Skip to content
This repository was archived by the owner on Jun 15, 2023. It is now read-only.

Commit 8a0c960

Browse files
committed
switch the core ninja parser to use re2c for the lexer
- Delete the old "Tokenizer" code. - Write separate tests for the lexer distinct from the parser. - Switch the parser to use the new code. - New lexer error output has file:line numbers so e.g. Emacs can jump your editor to the syntax error. - The EvalEnv ($-interpolation) code is now part of the lexer as well.
1 parent ad7d9f4 commit 8a0c960

15 files changed

+1510
-771
lines changed

configure.py

+5-3
Original file line numberDiff line numberDiff line change
@@ -151,12 +151,13 @@ def binary(name):
151151
objs += cxx('browse', order_only=built('browse_py.h'))
152152
n.newline()
153153

154-
n.comment('the depfile parser is generated using re2c.')
154+
n.comment('the depfile parser and ninja lexers are generated using re2c.')
155155
n.rule('re2c',
156156
command='re2c -b -i --no-generation-date -o $out $in',
157157
description='RE2C $out')
158-
# Generate the .cc file in the source directory so we can check it in.
158+
# Generate the .cc files in the source directory so we can check them in.
159159
n.build(src('depfile_parser.cc'), 're2c', src('depfile_parser.in.cc'))
160+
n.build(src('lexer.cc'), 're2c', src('lexer.in.cc'))
160161
n.newline()
161162

162163
n.comment('Core source files all build into ninja library.')
@@ -169,6 +170,7 @@ def binary(name):
169170
'eval_env',
170171
'graph',
171172
'graphviz',
173+
'lexer',
172174
'parsers',
173175
'state',
174176
'util']:
@@ -219,8 +221,8 @@ def binary(name):
219221
'depfile_parser_test',
220222
'disk_interface_test',
221223
'edit_distance_test',
222-
'eval_env_test',
223224
'graph_test',
225+
'lexer_test',
224226
'parsers_test',
225227
'state_test',
226228
'subprocess_test',

src/eval_env.cc

+22-58
Original file line numberDiff line numberDiff line change
@@ -27,64 +27,6 @@ void BindingEnv::AddBinding(const string& key, const string& val) {
2727
bindings_[key] = val;
2828
}
2929

30-
bool EvalString::Parse(const string& input, string* err, size_t* err_index) {
31-
unparsed_ = input;
32-
33-
string::size_type start, end;
34-
start = 0;
35-
do {
36-
end = input.find('$', start);
37-
if (end == string::npos) {
38-
end = input.size();
39-
break;
40-
}
41-
if (end > start)
42-
parsed_.push_back(make_pair(input.substr(start, end - start), RAW));
43-
start = end + 1;
44-
if (start < input.size() && input[start] == '{') {
45-
++start;
46-
for (end = start + 1; end < input.size(); ++end) {
47-
if (input[end] == '}')
48-
break;
49-
}
50-
if (end >= input.size()) {
51-
*err = "expected closing curly after ${";
52-
if (err_index)
53-
*err_index = end;
54-
return false;
55-
}
56-
parsed_.push_back(make_pair(input.substr(start, end - start), SPECIAL));
57-
++end;
58-
} else if (start < input.size() && input[start] == '$') {
59-
parsed_.push_back(make_pair("$", RAW));
60-
end = start + 1;
61-
} else if (start < input.size() && input[start] == ' ') {
62-
parsed_.push_back(make_pair(" ", RAW));
63-
end = start + 1;
64-
} else {
65-
for (end = start; end < input.size(); ++end) {
66-
char c = input[end];
67-
if (!(('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') ||
68-
('0' <= c && c <= '9') || c == '_')) {
69-
break;
70-
}
71-
}
72-
if (end == start) {
73-
*err = "expected variable after $";
74-
if (err_index)
75-
*err_index = start;
76-
return false;
77-
}
78-
parsed_.push_back(make_pair(input.substr(start, end - start), SPECIAL));
79-
}
80-
start = end;
81-
} while (end < input.size());
82-
if (end > start)
83-
parsed_.push_back(make_pair(input.substr(start, end - start), RAW));
84-
85-
return true;
86-
}
87-
8830
string EvalString::Evaluate(Env* env) const {
8931
string result;
9032
for (TokenList::const_iterator i = parsed_.begin(); i != parsed_.end(); ++i) {
@@ -95,3 +37,25 @@ string EvalString::Evaluate(Env* env) const {
9537
}
9638
return result;
9739
}
40+
41+
void EvalString::Add(TokenType type, StringPiece text) {
42+
// Add it to the end of an existing RAW token if possible.
43+
if (type == RAW && !parsed_.empty() && parsed_.back().second == RAW) {
44+
parsed_.back().first.append(text.str_, text.len_);
45+
} else {
46+
parsed_.push_back(make_pair(text.AsString(), type));
47+
}
48+
}
49+
50+
string EvalString::Serialize() const {
51+
string result;
52+
for (TokenList::const_iterator i = parsed_.begin();
53+
i != parsed_.end(); ++i) {
54+
result.append("[");
55+
if (i->second == SPECIAL)
56+
result.append("$");
57+
result.append(i->first);
58+
result.append("]");
59+
}
60+
return result;
61+
}

src/eval_env.h

+10-4
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
#include <vector>
2121
using namespace std;
2222

23+
#include "string_piece.h"
24+
2325
/// An interface for a scope for variable (e.g. "$foo") lookups.
2426
struct Env {
2527
virtual ~Env() {}
@@ -41,14 +43,18 @@ struct BindingEnv : public Env {
4143
/// A tokenized string that contains variable references.
4244
/// Can be evaluated relative to an Env.
4345
struct EvalString {
44-
bool Parse(const string& input, string* err, size_t* err_index=NULL);
4546
string Evaluate(Env* env) const;
4647

47-
const string& unparsed() const { return unparsed_; }
48-
bool empty() const { return unparsed_.empty(); }
48+
void Clear() { parsed_.clear(); }
49+
bool empty() const { return parsed_.empty(); }
4950

50-
string unparsed_;
5151
enum TokenType { RAW, SPECIAL };
52+
void Add(TokenType type, StringPiece text);
53+
54+
/// Construct a human-readable representation of the parsed state,
55+
/// for use in tests.
56+
string Serialize() const;
57+
5258
typedef vector<pair<string, TokenType> > TokenList;
5359
TokenList parsed_;
5460
};

src/eval_env_test.cc

-101
This file was deleted.

src/graph.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -109,10 +109,10 @@ struct Rule {
109109
const EvalString& description() const { return description_; }
110110
const EvalString& depfile() const { return depfile_; }
111111

112-
private:
112+
// TODO: private:
113+
113114
// Allow the parsers to reach into this object and fill out its fields.
114115
friend class ManifestParser;
115-
friend class ParserTest;
116116

117117
string name_;
118118

0 commit comments

Comments
 (0)