summaryrefslogtreecommitdiffstats
path: root/src/parsers.h
blob: bdc88d2e6c84376ca0b33d29db15516abd4b7b36 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
// Copyright 2011 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef NINJA_PARSERS_H_
#define NINJA_PARSERS_H_

#include <string>
#include <vector>
#include <limits>

using namespace std;

struct BindingEnv;

/// A single parsed token in an input stream.
struct Token {
  enum Type {
    NONE,
    UNKNOWN,
    IDENT,
    NEWLINE,
    EQUALS,
    COLON,
    PIPE,
    PIPE2,
    INDENT,
    OUTDENT,
    TEOF
  };
  explicit Token(Type type) : type_(type) {}

  void Clear() { type_ = NONE; }
  string AsString() const;

  Type type_;
  const char* pos_;
  const char* end_;
};

/// Processes an input stream into Tokens.
struct Tokenizer {
  Tokenizer()
    : makefile_flavor_(false),
      token_(Token::NONE),
      last_indent_(0), cur_indent_(-1) {}

  /// Tokenization differs slightly between ninja files and Makefiles.
  /// By default we tokenize as ninja files; calling this changes to
  /// Makefile-style tokenization.
  void SetMakefileFlavor() {
    makefile_flavor_ = true;
  }

  void Start(const char* start, const char* end);
  /// Report an error at a particular location.
  bool ErrorAt(const char* pos, const string& message, string* err);
  /// Report an error with a location pointing at the current token.
  bool Error(const string& message, string* err) {
    return ErrorAt(token_.pos_, message, err);
  }
  /// Call Error() with "expected foo, got bar".
  bool ErrorExpected(const string& expected, string* err);

  const Token& token() const { return token_; }

  void SkipWhitespace(bool newline=false);
  bool Newline(string* err);
  bool ExpectToken(Token::Type expected, string* err);
  bool ExpectIdent(const char* expected, string* err);
  bool ReadIdent(string* out);
  bool ReadToNewline(string* text, string* err,
                     size_t max_length=std::numeric_limits<size_t>::max());

  Token::Type PeekToken();
  void ConsumeToken();

  bool makefile_flavor_;

  const char* start_;  /// Start of the input.
  const char* cur_;    /// Current position within the input.
  const char* end_;    /// End of the input.

  const char* cur_line_;  /// Start of current line.
  Token token_;
  int last_indent_, cur_indent_;
};

/// Parses simple Makefiles as generated by gcc.
struct MakefileParser {
  MakefileParser();
  bool Parse(const string& input, string* err);

  Tokenizer tokenizer_;
  string out_;
  vector<string> ins_;
};

struct EvalString;
struct State;

/// Parses .ninja files.
struct ManifestParser {
  struct FileReader {
    virtual ~FileReader() {}
    virtual bool ReadFile(const string& path, string* content, string* err) = 0;
  };

  ManifestParser(State* state, FileReader* file_reader);

  bool Load(const string& filename, string* err);
  bool Parse(const string& input, string* err);

  bool ParseRule(string* err);
  /// Parse a key=val statement, expanding $vars in the value with the
  /// current env.
  bool ParseLet(string* key, string* val, string* err);
  bool ParseEdge(string* err);
  bool ParseDefaults(string* err);

  /// Parse either a 'subninja' or 'include' line.
  bool ParseFileInclude(string* err);


  /// Parse the "key=" half of a key=val statement.
  bool ParseLetKey(string* key, string* err);
  /// Parse the val half of a key=val statement, writing and parsing
  /// output into an EvalString (ready for expansion).
  bool ParseLetValue(EvalString* eval, string* err);

  State* state_;
  BindingEnv* env_;
  FileReader* file_reader_;
  Tokenizer tokenizer_;
};

#endif  // NINJA_PARSERS_H_