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