• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Generated by re2c */
2 // Copyright 2011 Google Inc. All Rights Reserved.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //     http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 
16 #include "lexer.h"
17 
18 #include <stdio.h>
19 
20 #include "eval_env.h"
21 #include "util.h"
22 
23 using namespace std;
24 
Error(const string & message,string * err)25 bool Lexer::Error(const string& message, string* err) {
26   // Compute line/column.
27   int line = 1;
28   const char* line_start = input_.str_;
29   for (const char* p = input_.str_; p < last_token_; ++p) {
30     if (*p == '\n') {
31       ++line;
32       line_start = p + 1;
33     }
34   }
35   int col = last_token_ ? (int)(last_token_ - line_start) : 0;
36 
37   char buf[1024];
38   snprintf(buf, sizeof(buf), "%s:%d: ", filename_.AsString().c_str(), line);
39   *err = buf;
40   *err += message + "\n";
41 
42   // Add some context to the message.
43   const int kTruncateColumn = 72;
44   if (col > 0 && col < kTruncateColumn) {
45     int len;
46     bool truncated = true;
47     for (len = 0; len < kTruncateColumn; ++len) {
48       if (line_start[len] == 0 || line_start[len] == '\n') {
49         truncated = false;
50         break;
51       }
52     }
53     *err += string(line_start, len);
54     if (truncated)
55       *err += "...";
56     *err += "\n";
57     *err += string(col, ' ');
58     *err += "^ near here";
59   }
60 
61   return false;
62 }
63 
Lexer(const char * input)64 Lexer::Lexer(const char* input) {
65   Start("input", input);
66 }
67 
Start(StringPiece filename,StringPiece input)68 void Lexer::Start(StringPiece filename, StringPiece input) {
69   filename_ = filename;
70   input_ = input;
71   ofs_ = input_.str_;
72   last_token_ = NULL;
73 }
74 
TokenName(Token t)75 const char* Lexer::TokenName(Token t) {
76   switch (t) {
77   case ERROR:    return "lexing error";
78   case BUILD:    return "'build'";
79   case COLON:    return "':'";
80   case DEFAULT:  return "'default'";
81   case EQUALS:   return "'='";
82   case IDENT:    return "identifier";
83   case INCLUDE:  return "'include'";
84   case INDENT:   return "indent";
85   case NEWLINE:  return "newline";
86   case PIPE2:    return "'||'";
87   case PIPE:     return "'|'";
88   case PIPEAT:   return "'|@'";
89   case POOL:     return "'pool'";
90   case RULE:     return "'rule'";
91   case SUBNINJA: return "'subninja'";
92   case TEOF:     return "eof";
93   }
94   return NULL;  // not reached
95 }
96 
TokenErrorHint(Token expected)97 const char* Lexer::TokenErrorHint(Token expected) {
98   switch (expected) {
99   case COLON:
100     return " ($ also escapes ':')";
101   default:
102     return "";
103   }
104 }
105 
DescribeLastError()106 string Lexer::DescribeLastError() {
107   if (last_token_) {
108     switch (last_token_[0]) {
109     case '\t':
110       return "tabs are not allowed, use spaces";
111     }
112   }
113   return "lexing error";
114 }
115 
UnreadToken()116 void Lexer::UnreadToken() {
117   ofs_ = last_token_;
118 }
119 
ReadToken()120 Lexer::Token Lexer::ReadToken() {
121   const char* p = ofs_;
122   const char* q;
123   const char* start;
124   Lexer::Token token;
125   for (;;) {
126     start = p;
127 
128 {
129 	unsigned char yych;
130 	unsigned int yyaccept = 0;
131 	static const unsigned char yybm[] = {
132 		  0, 128, 128, 128, 128, 128, 128, 128,
133 		128, 128,   0, 128, 128, 128, 128, 128,
134 		128, 128, 128, 128, 128, 128, 128, 128,
135 		128, 128, 128, 128, 128, 128, 128, 128,
136 		160, 128, 128, 128, 128, 128, 128, 128,
137 		128, 128, 128, 128, 128, 192, 192, 128,
138 		192, 192, 192, 192, 192, 192, 192, 192,
139 		192, 192, 128, 128, 128, 128, 128, 128,
140 		128, 192, 192, 192, 192, 192, 192, 192,
141 		192, 192, 192, 192, 192, 192, 192, 192,
142 		192, 192, 192, 192, 192, 192, 192, 192,
143 		192, 192, 192, 128, 128, 128, 128, 192,
144 		128, 192, 192, 192, 192, 192, 192, 192,
145 		192, 192, 192, 192, 192, 192, 192, 192,
146 		192, 192, 192, 192, 192, 192, 192, 192,
147 		192, 192, 192, 128, 128, 128, 128, 128,
148 		128, 128, 128, 128, 128, 128, 128, 128,
149 		128, 128, 128, 128, 128, 128, 128, 128,
150 		128, 128, 128, 128, 128, 128, 128, 128,
151 		128, 128, 128, 128, 128, 128, 128, 128,
152 		128, 128, 128, 128, 128, 128, 128, 128,
153 		128, 128, 128, 128, 128, 128, 128, 128,
154 		128, 128, 128, 128, 128, 128, 128, 128,
155 		128, 128, 128, 128, 128, 128, 128, 128,
156 		128, 128, 128, 128, 128, 128, 128, 128,
157 		128, 128, 128, 128, 128, 128, 128, 128,
158 		128, 128, 128, 128, 128, 128, 128, 128,
159 		128, 128, 128, 128, 128, 128, 128, 128,
160 		128, 128, 128, 128, 128, 128, 128, 128,
161 		128, 128, 128, 128, 128, 128, 128, 128,
162 		128, 128, 128, 128, 128, 128, 128, 128,
163 		128, 128, 128, 128, 128, 128, 128, 128,
164 	};
165 	yych = *p;
166 	if (yybm[0+yych] & 32) {
167 		goto yy9;
168 	}
169 	if (yych <= '^') {
170 		if (yych <= ',') {
171 			if (yych <= '\f') {
172 				if (yych <= 0x00) goto yy2;
173 				if (yych == '\n') goto yy6;
174 				goto yy4;
175 			} else {
176 				if (yych <= '\r') goto yy8;
177 				if (yych == '#') goto yy12;
178 				goto yy4;
179 			}
180 		} else {
181 			if (yych <= ':') {
182 				if (yych == '/') goto yy4;
183 				if (yych <= '9') goto yy13;
184 				goto yy16;
185 			} else {
186 				if (yych <= '=') {
187 					if (yych <= '<') goto yy4;
188 					goto yy18;
189 				} else {
190 					if (yych <= '@') goto yy4;
191 					if (yych <= 'Z') goto yy13;
192 					goto yy4;
193 				}
194 			}
195 		}
196 	} else {
197 		if (yych <= 'i') {
198 			if (yych <= 'b') {
199 				if (yych == '`') goto yy4;
200 				if (yych <= 'a') goto yy13;
201 				goto yy20;
202 			} else {
203 				if (yych == 'd') goto yy21;
204 				if (yych <= 'h') goto yy13;
205 				goto yy22;
206 			}
207 		} else {
208 			if (yych <= 'r') {
209 				if (yych == 'p') goto yy23;
210 				if (yych <= 'q') goto yy13;
211 				goto yy24;
212 			} else {
213 				if (yych <= 'z') {
214 					if (yych <= 's') goto yy25;
215 					goto yy13;
216 				} else {
217 					if (yych == '|') goto yy26;
218 					goto yy4;
219 				}
220 			}
221 		}
222 	}
223 yy2:
224 	++p;
225 	{ token = TEOF;     break; }
226 yy4:
227 	++p;
228 yy5:
229 	{ token = ERROR;    break; }
230 yy6:
231 	++p;
232 	{ token = NEWLINE;  break; }
233 yy8:
234 	yych = *++p;
235 	if (yych == '\n') goto yy28;
236 	goto yy5;
237 yy9:
238 	yyaccept = 0;
239 	yych = *(q = ++p);
240 	if (yybm[0+yych] & 32) {
241 		goto yy9;
242 	}
243 	if (yych <= '\f') {
244 		if (yych == '\n') goto yy6;
245 	} else {
246 		if (yych <= '\r') goto yy30;
247 		if (yych == '#') goto yy32;
248 	}
249 yy11:
250 	{ token = INDENT;   break; }
251 yy12:
252 	yyaccept = 1;
253 	yych = *(q = ++p);
254 	if (yych <= 0x00) goto yy5;
255 	goto yy33;
256 yy13:
257 	yych = *++p;
258 yy14:
259 	if (yybm[0+yych] & 64) {
260 		goto yy13;
261 	}
262 	{ token = IDENT;    break; }
263 yy16:
264 	++p;
265 	{ token = COLON;    break; }
266 yy18:
267 	++p;
268 	{ token = EQUALS;   break; }
269 yy20:
270 	yych = *++p;
271 	if (yych == 'u') goto yy36;
272 	goto yy14;
273 yy21:
274 	yych = *++p;
275 	if (yych == 'e') goto yy37;
276 	goto yy14;
277 yy22:
278 	yych = *++p;
279 	if (yych == 'n') goto yy38;
280 	goto yy14;
281 yy23:
282 	yych = *++p;
283 	if (yych == 'o') goto yy39;
284 	goto yy14;
285 yy24:
286 	yych = *++p;
287 	if (yych == 'u') goto yy40;
288 	goto yy14;
289 yy25:
290 	yych = *++p;
291 	if (yych == 'u') goto yy41;
292 	goto yy14;
293 yy26:
294 	yych = *++p;
295 	if (yych == '@') goto yy42;
296 	if (yych == '|') goto yy44;
297 	{ token = PIPE;     break; }
298 yy28:
299 	++p;
300 	{ token = NEWLINE;  break; }
301 yy30:
302 	yych = *++p;
303 	if (yych == '\n') goto yy28;
304 yy31:
305 	p = q;
306 	if (yyaccept == 0) {
307 		goto yy11;
308 	} else {
309 		goto yy5;
310 	}
311 yy32:
312 	yych = *++p;
313 yy33:
314 	if (yybm[0+yych] & 128) {
315 		goto yy32;
316 	}
317 	if (yych <= 0x00) goto yy31;
318 	++p;
319 	{ continue; }
320 yy36:
321 	yych = *++p;
322 	if (yych == 'i') goto yy46;
323 	goto yy14;
324 yy37:
325 	yych = *++p;
326 	if (yych == 'f') goto yy47;
327 	goto yy14;
328 yy38:
329 	yych = *++p;
330 	if (yych == 'c') goto yy48;
331 	goto yy14;
332 yy39:
333 	yych = *++p;
334 	if (yych == 'o') goto yy49;
335 	goto yy14;
336 yy40:
337 	yych = *++p;
338 	if (yych == 'l') goto yy50;
339 	goto yy14;
340 yy41:
341 	yych = *++p;
342 	if (yych == 'b') goto yy51;
343 	goto yy14;
344 yy42:
345 	++p;
346 	{ token = PIPEAT;   break; }
347 yy44:
348 	++p;
349 	{ token = PIPE2;    break; }
350 yy46:
351 	yych = *++p;
352 	if (yych == 'l') goto yy52;
353 	goto yy14;
354 yy47:
355 	yych = *++p;
356 	if (yych == 'a') goto yy53;
357 	goto yy14;
358 yy48:
359 	yych = *++p;
360 	if (yych == 'l') goto yy54;
361 	goto yy14;
362 yy49:
363 	yych = *++p;
364 	if (yych == 'l') goto yy55;
365 	goto yy14;
366 yy50:
367 	yych = *++p;
368 	if (yych == 'e') goto yy57;
369 	goto yy14;
370 yy51:
371 	yych = *++p;
372 	if (yych == 'n') goto yy59;
373 	goto yy14;
374 yy52:
375 	yych = *++p;
376 	if (yych == 'd') goto yy60;
377 	goto yy14;
378 yy53:
379 	yych = *++p;
380 	if (yych == 'u') goto yy62;
381 	goto yy14;
382 yy54:
383 	yych = *++p;
384 	if (yych == 'u') goto yy63;
385 	goto yy14;
386 yy55:
387 	yych = *++p;
388 	if (yybm[0+yych] & 64) {
389 		goto yy13;
390 	}
391 	{ token = POOL;     break; }
392 yy57:
393 	yych = *++p;
394 	if (yybm[0+yych] & 64) {
395 		goto yy13;
396 	}
397 	{ token = RULE;     break; }
398 yy59:
399 	yych = *++p;
400 	if (yych == 'i') goto yy64;
401 	goto yy14;
402 yy60:
403 	yych = *++p;
404 	if (yybm[0+yych] & 64) {
405 		goto yy13;
406 	}
407 	{ token = BUILD;    break; }
408 yy62:
409 	yych = *++p;
410 	if (yych == 'l') goto yy65;
411 	goto yy14;
412 yy63:
413 	yych = *++p;
414 	if (yych == 'd') goto yy66;
415 	goto yy14;
416 yy64:
417 	yych = *++p;
418 	if (yych == 'n') goto yy67;
419 	goto yy14;
420 yy65:
421 	yych = *++p;
422 	if (yych == 't') goto yy68;
423 	goto yy14;
424 yy66:
425 	yych = *++p;
426 	if (yych == 'e') goto yy70;
427 	goto yy14;
428 yy67:
429 	yych = *++p;
430 	if (yych == 'j') goto yy72;
431 	goto yy14;
432 yy68:
433 	yych = *++p;
434 	if (yybm[0+yych] & 64) {
435 		goto yy13;
436 	}
437 	{ token = DEFAULT;  break; }
438 yy70:
439 	yych = *++p;
440 	if (yybm[0+yych] & 64) {
441 		goto yy13;
442 	}
443 	{ token = INCLUDE;  break; }
444 yy72:
445 	yych = *++p;
446 	if (yych != 'a') goto yy14;
447 	yych = *++p;
448 	if (yybm[0+yych] & 64) {
449 		goto yy13;
450 	}
451 	{ token = SUBNINJA; break; }
452 }
453 
454   }
455 
456   last_token_ = start;
457   ofs_ = p;
458   if (token != NEWLINE && token != TEOF)
459     EatWhitespace();
460   return token;
461 }
462 
PeekToken(Token token)463 bool Lexer::PeekToken(Token token) {
464   Token t = ReadToken();
465   if (t == token)
466     return true;
467   UnreadToken();
468   return false;
469 }
470 
EatWhitespace()471 void Lexer::EatWhitespace() {
472   const char* p = ofs_;
473   const char* q;
474   for (;;) {
475     ofs_ = p;
476 
477 {
478 	unsigned char yych;
479 	static const unsigned char yybm[] = {
480 		  0,   0,   0,   0,   0,   0,   0,   0,
481 		  0,   0,   0,   0,   0,   0,   0,   0,
482 		  0,   0,   0,   0,   0,   0,   0,   0,
483 		  0,   0,   0,   0,   0,   0,   0,   0,
484 		128,   0,   0,   0,   0,   0,   0,   0,
485 		  0,   0,   0,   0,   0,   0,   0,   0,
486 		  0,   0,   0,   0,   0,   0,   0,   0,
487 		  0,   0,   0,   0,   0,   0,   0,   0,
488 		  0,   0,   0,   0,   0,   0,   0,   0,
489 		  0,   0,   0,   0,   0,   0,   0,   0,
490 		  0,   0,   0,   0,   0,   0,   0,   0,
491 		  0,   0,   0,   0,   0,   0,   0,   0,
492 		  0,   0,   0,   0,   0,   0,   0,   0,
493 		  0,   0,   0,   0,   0,   0,   0,   0,
494 		  0,   0,   0,   0,   0,   0,   0,   0,
495 		  0,   0,   0,   0,   0,   0,   0,   0,
496 		  0,   0,   0,   0,   0,   0,   0,   0,
497 		  0,   0,   0,   0,   0,   0,   0,   0,
498 		  0,   0,   0,   0,   0,   0,   0,   0,
499 		  0,   0,   0,   0,   0,   0,   0,   0,
500 		  0,   0,   0,   0,   0,   0,   0,   0,
501 		  0,   0,   0,   0,   0,   0,   0,   0,
502 		  0,   0,   0,   0,   0,   0,   0,   0,
503 		  0,   0,   0,   0,   0,   0,   0,   0,
504 		  0,   0,   0,   0,   0,   0,   0,   0,
505 		  0,   0,   0,   0,   0,   0,   0,   0,
506 		  0,   0,   0,   0,   0,   0,   0,   0,
507 		  0,   0,   0,   0,   0,   0,   0,   0,
508 		  0,   0,   0,   0,   0,   0,   0,   0,
509 		  0,   0,   0,   0,   0,   0,   0,   0,
510 		  0,   0,   0,   0,   0,   0,   0,   0,
511 		  0,   0,   0,   0,   0,   0,   0,   0,
512 	};
513 	yych = *p;
514 	if (yybm[0+yych] & 128) {
515 		goto yy81;
516 	}
517 	if (yych <= 0x00) goto yy77;
518 	if (yych == '$') goto yy84;
519 	goto yy79;
520 yy77:
521 	++p;
522 	{ break; }
523 yy79:
524 	++p;
525 yy80:
526 	{ break; }
527 yy81:
528 	yych = *++p;
529 	if (yybm[0+yych] & 128) {
530 		goto yy81;
531 	}
532 	{ continue; }
533 yy84:
534 	yych = *(q = ++p);
535 	if (yych == '\n') goto yy85;
536 	if (yych == '\r') goto yy87;
537 	goto yy80;
538 yy85:
539 	++p;
540 	{ continue; }
541 yy87:
542 	yych = *++p;
543 	if (yych == '\n') goto yy89;
544 	p = q;
545 	goto yy80;
546 yy89:
547 	++p;
548 	{ continue; }
549 }
550 
551   }
552 }
553 
ReadIdent(string * out)554 bool Lexer::ReadIdent(string* out) {
555   const char* p = ofs_;
556   const char* start;
557   for (;;) {
558     start = p;
559 
560 {
561 	unsigned char yych;
562 	static const unsigned char yybm[] = {
563 		  0,   0,   0,   0,   0,   0,   0,   0,
564 		  0,   0,   0,   0,   0,   0,   0,   0,
565 		  0,   0,   0,   0,   0,   0,   0,   0,
566 		  0,   0,   0,   0,   0,   0,   0,   0,
567 		  0,   0,   0,   0,   0,   0,   0,   0,
568 		  0,   0,   0,   0,   0, 128, 128,   0,
569 		128, 128, 128, 128, 128, 128, 128, 128,
570 		128, 128,   0,   0,   0,   0,   0,   0,
571 		  0, 128, 128, 128, 128, 128, 128, 128,
572 		128, 128, 128, 128, 128, 128, 128, 128,
573 		128, 128, 128, 128, 128, 128, 128, 128,
574 		128, 128, 128,   0,   0,   0,   0, 128,
575 		  0, 128, 128, 128, 128, 128, 128, 128,
576 		128, 128, 128, 128, 128, 128, 128, 128,
577 		128, 128, 128, 128, 128, 128, 128, 128,
578 		128, 128, 128,   0,   0,   0,   0,   0,
579 		  0,   0,   0,   0,   0,   0,   0,   0,
580 		  0,   0,   0,   0,   0,   0,   0,   0,
581 		  0,   0,   0,   0,   0,   0,   0,   0,
582 		  0,   0,   0,   0,   0,   0,   0,   0,
583 		  0,   0,   0,   0,   0,   0,   0,   0,
584 		  0,   0,   0,   0,   0,   0,   0,   0,
585 		  0,   0,   0,   0,   0,   0,   0,   0,
586 		  0,   0,   0,   0,   0,   0,   0,   0,
587 		  0,   0,   0,   0,   0,   0,   0,   0,
588 		  0,   0,   0,   0,   0,   0,   0,   0,
589 		  0,   0,   0,   0,   0,   0,   0,   0,
590 		  0,   0,   0,   0,   0,   0,   0,   0,
591 		  0,   0,   0,   0,   0,   0,   0,   0,
592 		  0,   0,   0,   0,   0,   0,   0,   0,
593 		  0,   0,   0,   0,   0,   0,   0,   0,
594 		  0,   0,   0,   0,   0,   0,   0,   0,
595 	};
596 	yych = *p;
597 	if (yybm[0+yych] & 128) {
598 		goto yy95;
599 	}
600 	++p;
601 	{
602       last_token_ = start;
603       return false;
604     }
605 yy95:
606 	yych = *++p;
607 	if (yybm[0+yych] & 128) {
608 		goto yy95;
609 	}
610 	{
611       out->assign(start, p - start);
612       break;
613     }
614 }
615 
616   }
617   last_token_ = start;
618   ofs_ = p;
619   EatWhitespace();
620   return true;
621 }
622 
ReadEvalString(EvalString * eval,bool path,string * err)623 bool Lexer::ReadEvalString(EvalString* eval, bool path, string* err) {
624   const char* p = ofs_;
625   const char* q;
626   const char* start;
627   for (;;) {
628     start = p;
629 
630 {
631 	unsigned char yych;
632 	static const unsigned char yybm[] = {
633 		  0,  16,  16,  16,  16,  16,  16,  16,
634 		 16,  16,   0,  16,  16,   0,  16,  16,
635 		 16,  16,  16,  16,  16,  16,  16,  16,
636 		 16,  16,  16,  16,  16,  16,  16,  16,
637 		 32,  16,  16,  16,   0,  16,  16,  16,
638 		 16,  16,  16,  16,  16, 208, 144,  16,
639 		208, 208, 208, 208, 208, 208, 208, 208,
640 		208, 208,   0,  16,  16,  16,  16,  16,
641 		 16, 208, 208, 208, 208, 208, 208, 208,
642 		208, 208, 208, 208, 208, 208, 208, 208,
643 		208, 208, 208, 208, 208, 208, 208, 208,
644 		208, 208, 208,  16,  16,  16,  16, 208,
645 		 16, 208, 208, 208, 208, 208, 208, 208,
646 		208, 208, 208, 208, 208, 208, 208, 208,
647 		208, 208, 208, 208, 208, 208, 208, 208,
648 		208, 208, 208,  16,   0,  16,  16,  16,
649 		 16,  16,  16,  16,  16,  16,  16,  16,
650 		 16,  16,  16,  16,  16,  16,  16,  16,
651 		 16,  16,  16,  16,  16,  16,  16,  16,
652 		 16,  16,  16,  16,  16,  16,  16,  16,
653 		 16,  16,  16,  16,  16,  16,  16,  16,
654 		 16,  16,  16,  16,  16,  16,  16,  16,
655 		 16,  16,  16,  16,  16,  16,  16,  16,
656 		 16,  16,  16,  16,  16,  16,  16,  16,
657 		 16,  16,  16,  16,  16,  16,  16,  16,
658 		 16,  16,  16,  16,  16,  16,  16,  16,
659 		 16,  16,  16,  16,  16,  16,  16,  16,
660 		 16,  16,  16,  16,  16,  16,  16,  16,
661 		 16,  16,  16,  16,  16,  16,  16,  16,
662 		 16,  16,  16,  16,  16,  16,  16,  16,
663 		 16,  16,  16,  16,  16,  16,  16,  16,
664 		 16,  16,  16,  16,  16,  16,  16,  16,
665 	};
666 	yych = *p;
667 	if (yybm[0+yych] & 16) {
668 		goto yy102;
669 	}
670 	if (yych <= '\r') {
671 		if (yych <= 0x00) goto yy100;
672 		if (yych <= '\n') goto yy105;
673 		goto yy107;
674 	} else {
675 		if (yych <= ' ') goto yy105;
676 		if (yych <= '$') goto yy109;
677 		goto yy105;
678 	}
679 yy100:
680 	++p;
681 	{
682       last_token_ = start;
683       return Error("unexpected EOF", err);
684     }
685 yy102:
686 	yych = *++p;
687 	if (yybm[0+yych] & 16) {
688 		goto yy102;
689 	}
690 	{
691       eval->AddText(StringPiece(start, p - start));
692       continue;
693     }
694 yy105:
695 	++p;
696 	{
697       if (path) {
698         p = start;
699         break;
700       } else {
701         if (*start == '\n')
702           break;
703         eval->AddText(StringPiece(start, 1));
704         continue;
705       }
706     }
707 yy107:
708 	yych = *++p;
709 	if (yych == '\n') goto yy110;
710 	{
711       last_token_ = start;
712       return Error(DescribeLastError(), err);
713     }
714 yy109:
715 	yych = *++p;
716 	if (yybm[0+yych] & 64) {
717 		goto yy122;
718 	}
719 	if (yych <= ' ') {
720 		if (yych <= '\f') {
721 			if (yych == '\n') goto yy114;
722 			goto yy112;
723 		} else {
724 			if (yych <= '\r') goto yy117;
725 			if (yych <= 0x1F) goto yy112;
726 			goto yy118;
727 		}
728 	} else {
729 		if (yych <= '/') {
730 			if (yych == '$') goto yy120;
731 			goto yy112;
732 		} else {
733 			if (yych <= ':') goto yy125;
734 			if (yych <= '`') goto yy112;
735 			if (yych <= '{') goto yy127;
736 			goto yy112;
737 		}
738 	}
739 yy110:
740 	++p;
741 	{
742       if (path)
743         p = start;
744       break;
745     }
746 yy112:
747 	++p;
748 yy113:
749 	{
750       last_token_ = start;
751       return Error("bad $-escape (literal $ must be written as $$)", err);
752     }
753 yy114:
754 	yych = *++p;
755 	if (yybm[0+yych] & 32) {
756 		goto yy114;
757 	}
758 	{
759       continue;
760     }
761 yy117:
762 	yych = *++p;
763 	if (yych == '\n') goto yy128;
764 	goto yy113;
765 yy118:
766 	++p;
767 	{
768       eval->AddText(StringPiece(" ", 1));
769       continue;
770     }
771 yy120:
772 	++p;
773 	{
774       eval->AddText(StringPiece("$", 1));
775       continue;
776     }
777 yy122:
778 	yych = *++p;
779 	if (yybm[0+yych] & 64) {
780 		goto yy122;
781 	}
782 	{
783       eval->AddSpecial(StringPiece(start + 1, p - start - 1));
784       continue;
785     }
786 yy125:
787 	++p;
788 	{
789       eval->AddText(StringPiece(":", 1));
790       continue;
791     }
792 yy127:
793 	yych = *(q = ++p);
794 	if (yybm[0+yych] & 128) {
795 		goto yy131;
796 	}
797 	goto yy113;
798 yy128:
799 	yych = *++p;
800 	if (yych == ' ') goto yy128;
801 	{
802       continue;
803     }
804 yy131:
805 	yych = *++p;
806 	if (yybm[0+yych] & 128) {
807 		goto yy131;
808 	}
809 	if (yych == '}') goto yy134;
810 	p = q;
811 	goto yy113;
812 yy134:
813 	++p;
814 	{
815       eval->AddSpecial(StringPiece(start + 2, p - start - 3));
816       continue;
817     }
818 }
819 
820   }
821   last_token_ = start;
822   ofs_ = p;
823   if (path)
824     EatWhitespace();
825   // Non-path strings end in newlines, so there's no whitespace to eat.
826   return true;
827 }
828