1 // Copyright 2011 Google Inc. All Rights Reserved.
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
7 // http://www.apache.org/licenses/LICENSE-2.0
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
22 bool Lexer::Error(const string& message, string* err) {
23 // Compute line/column.
25 const char* context = input_.str_;
26 for (const char* p = input_.str_; p < last_token_; ++p) {
32 int col = last_token_ ? (int)(last_token_ - context) : 0;
35 snprintf(buf, sizeof(buf), "%s:%d: ", filename_.AsString().c_str(), line);
37 *err += message + "\n";
39 // Add some context to the message.
40 const int kTruncateColumn = 72;
41 if (col > 0 && col < kTruncateColumn) {
43 bool truncated = true;
44 for (len = 0; len < kTruncateColumn; ++len) {
45 if (context[len] == 0 || context[len] == '\n') {
50 *err += string(context, len);
54 *err += string(col, ' ');
55 *err += "^ near here";
61 Lexer::Lexer(const char* input) {
62 Start("input", input);
65 void Lexer::Start(StringPiece filename, StringPiece input) {
72 const char* Lexer::TokenName(Token t) {
74 case ERROR: return "lexing error";
75 case BUILD: return "'build'";
76 case COLON: return "':'";
77 case DEFAULT: return "'default'";
78 case EQUALS: return "'='";
79 case IDENT: return "identifier";
80 case INCLUDE: return "'include'";
81 case INDENT: return "indent";
82 case NEWLINE: return "newline";
83 case PIPE2: return "'||'";
84 case PIPE: return "'|'";
85 case POOL: return "'pool'";
86 case RULE: return "'rule'";
87 case SUBNINJA: return "'subninja'";
88 case TEOF: return "eof";
90 return NULL; // not reached
93 const char* Lexer::TokenErrorHint(Token expected) {
96 return " ($ also escapes ':')";
102 string Lexer::DescribeLastError() {
104 switch (last_token_[0]) {
106 return "tabs are not allowed, use spaces";
109 return "lexing error";
112 void Lexer::UnreadToken() {
116 Lexer::Token Lexer::ReadToken() {
117 const char* p = ofs_;
124 re2c:define:YYCTYPE = "unsigned char";
125 re2c:define:YYCURSOR = p;
126 re2c:define:YYMARKER = q;
127 re2c:yyfill:enable = 0;
130 simple_varname = [a-zA-Z0-9_-]+;
131 varname = [a-zA-Z0-9_.-]+;
133 [ ]*"#"[^\000\n]*"\n" { continue; }
134 [ ]*"\r\n" { token = NEWLINE; break; }
135 [ ]*"\n" { token = NEWLINE; break; }
136 [ ]+ { token = INDENT; break; }
137 "build" { token = BUILD; break; }
138 "pool" { token = POOL; break; }
139 "rule" { token = RULE; break; }
140 "default" { token = DEFAULT; break; }
141 "=" { token = EQUALS; break; }
142 ":" { token = COLON; break; }
143 "||" { token = PIPE2; break; }
144 "|" { token = PIPE; break; }
145 "include" { token = INCLUDE; break; }
146 "subninja" { token = SUBNINJA; break; }
147 varname { token = IDENT; break; }
148 nul { token = TEOF; break; }
149 [^] { token = ERROR; break; }
155 if (token != NEWLINE && token != TEOF)
160 bool Lexer::PeekToken(Token token) {
161 Token t = ReadToken();
168 void Lexer::EatWhitespace() {
169 const char* p = ofs_;
175 "$\r\n" { continue; }
183 bool Lexer::ReadIdent(string* out) {
184 const char* p = ofs_;
186 const char* start = p;
189 out->assign(start, p - start);
192 [^] { return false; }
200 bool Lexer::ReadEvalString(EvalString* eval, bool path, string* err) {
201 const char* p = ofs_;
208 eval->AddText(StringPiece(start, p - start));
223 eval->AddText(StringPiece(start, 1));
228 eval->AddText(StringPiece("$", 1));
232 eval->AddText(StringPiece(" ", 1));
242 eval->AddSpecial(StringPiece(start + 2, p - start - 3));
246 eval->AddSpecial(StringPiece(start + 1, p - start - 1));
250 eval->AddText(StringPiece(":", 1));
255 return Error("bad $-escape (literal $ must be written as $$)", err);
259 return Error("unexpected EOF", err);
263 return Error(DescribeLastError(), err);
271 // Non-path strings end in newlines, so there's no whitespace to eat.