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
23using namespace std;
24
25bool 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
64Lexer::Lexer(const char* input) {
65 Start("input", input);
66}
67
68void Lexer::Start(StringPiece filename, StringPiece input) {
69 filename_ = filename;
70 input_ = input;
71 ofs_ = input_.str_;
72 last_token_ = NULL;
73}
74
75const 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
97const char* Lexer::TokenErrorHint(Token expected) {
98 switch (expected) {
99 case COLON:
100 return " ($ also escapes ':')";
101 default:
102 return "";
103 }
104}
105
106string 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
116void Lexer::UnreadToken() {
117 ofs_ = last_token_;
118}
119
120Lexer::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 }
223yy2:
224 ++p;
225 { token = TEOF; break; }
226yy4:
227 ++p;
228yy5:
229 { token = ERROR; break; }
230yy6:
231 ++p;
232 { token = NEWLINE; break; }
233yy8:
234 yych = *++p;
235 if (yych == '\n') goto yy28;
236 goto yy5;
237yy9:
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 }
249yy11:
250 { token = INDENT; break; }
251yy12:
252 yyaccept = 1;
253 yych = *(q = ++p);
254 if (yych <= 0x00) goto yy5;
255 goto yy33;
256yy13:
257 yych = *++p;
258yy14:
259 if (yybm[0+yych] & 64) {
260 goto yy13;
261 }
262 { token = IDENT; break; }
263yy16:
264 ++p;
265 { token = COLON; break; }
266yy18:
267 ++p;
268 { token = EQUALS; break; }
269yy20:
270 yych = *++p;
271 if (yych == 'u') goto yy36;
272 goto yy14;
273yy21:
274 yych = *++p;
275 if (yych == 'e') goto yy37;
276 goto yy14;
277yy22:
278 yych = *++p;
279 if (yych == 'n') goto yy38;
280 goto yy14;
281yy23:
282 yych = *++p;
283 if (yych == 'o') goto yy39;
284 goto yy14;
285yy24:
286 yych = *++p;
287 if (yych == 'u') goto yy40;
288 goto yy14;
289yy25:
290 yych = *++p;
291 if (yych == 'u') goto yy41;
292 goto yy14;
293yy26:
294 yych = *++p;
295 if (yych == '@') goto yy42;
296 if (yych == '|') goto yy44;
297 { token = PIPE; break; }
298yy28:
299 ++p;
300 { token = NEWLINE; break; }
301yy30:
302 yych = *++p;
303 if (yych == '\n') goto yy28;
304yy31:
305 p = q;
306 if (yyaccept == 0) {
307 goto yy11;
308 } else {
309 goto yy5;
310 }
311yy32:
312 yych = *++p;
313yy33:
314 if (yybm[0+yych] & 128) {
315 goto yy32;
316 }
317 if (yych <= 0x00) goto yy31;
318 ++p;
319 { continue; }
320yy36:
321 yych = *++p;
322 if (yych == 'i') goto yy46;
323 goto yy14;
324yy37:
325 yych = *++p;
326 if (yych == 'f') goto yy47;
327 goto yy14;
328yy38:
329 yych = *++p;
330 if (yych == 'c') goto yy48;
331 goto yy14;
332yy39:
333 yych = *++p;
334 if (yych == 'o') goto yy49;
335 goto yy14;
336yy40:
337 yych = *++p;
338 if (yych == 'l') goto yy50;
339 goto yy14;
340yy41:
341 yych = *++p;
342 if (yych == 'b') goto yy51;
343 goto yy14;
344yy42:
345 ++p;
346 { token = PIPEAT; break; }
347yy44:
348 ++p;
349 { token = PIPE2; break; }
350yy46:
351 yych = *++p;
352 if (yych == 'l') goto yy52;
353 goto yy14;
354yy47:
355 yych = *++p;
356 if (yych == 'a') goto yy53;
357 goto yy14;
358yy48:
359 yych = *++p;
360 if (yych == 'l') goto yy54;
361 goto yy14;
362yy49:
363 yych = *++p;
364 if (yych == 'l') goto yy55;
365 goto yy14;
366yy50:
367 yych = *++p;
368 if (yych == 'e') goto yy57;
369 goto yy14;
370yy51:
371 yych = *++p;
372 if (yych == 'n') goto yy59;
373 goto yy14;
374yy52:
375 yych = *++p;
376 if (yych == 'd') goto yy60;
377 goto yy14;
378yy53:
379 yych = *++p;
380 if (yych == 'u') goto yy62;
381 goto yy14;
382yy54:
383 yych = *++p;
384 if (yych == 'u') goto yy63;
385 goto yy14;
386yy55:
387 yych = *++p;
388 if (yybm[0+yych] & 64) {
389 goto yy13;
390 }
391 { token = POOL; break; }
392yy57:
393 yych = *++p;
394 if (yybm[0+yych] & 64) {
395 goto yy13;
396 }
397 { token = RULE; break; }
398yy59:
399 yych = *++p;
400 if (yych == 'i') goto yy64;
401 goto yy14;
402yy60:
403 yych = *++p;
404 if (yybm[0+yych] & 64) {
405 goto yy13;
406 }
407 { token = BUILD; break; }
408yy62:
409 yych = *++p;
410 if (yych == 'l') goto yy65;
411 goto yy14;
412yy63:
413 yych = *++p;
414 if (yych == 'd') goto yy66;
415 goto yy14;
416yy64:
417 yych = *++p;
418 if (yych == 'n') goto yy67;
419 goto yy14;
420yy65:
421 yych = *++p;
422 if (yych == 't') goto yy68;
423 goto yy14;
424yy66:
425 yych = *++p;
426 if (yych == 'e') goto yy70;
427 goto yy14;
428yy67:
429 yych = *++p;
430 if (yych == 'j') goto yy72;
431 goto yy14;
432yy68:
433 yych = *++p;
434 if (yybm[0+yych] & 64) {
435 goto yy13;
436 }
437 { token = DEFAULT; break; }
438yy70:
439 yych = *++p;
440 if (yybm[0+yych] & 64) {
441 goto yy13;
442 }
443 { token = INCLUDE; break; }
444yy72:
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
463bool Lexer::PeekToken(Token token) {
464 Token t = ReadToken();
465 if (t == token)
466 return true;
467 UnreadToken();
468 return false;
469}
470
471void 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;
520yy77:
521 ++p;
522 { break; }
523yy79:
524 ++p;
525yy80:
526 { break; }
527yy81:
528 yych = *++p;
529 if (yybm[0+yych] & 128) {
530 goto yy81;
531 }
532 { continue; }
533yy84:
534 yych = *(q = ++p);
535 if (yych == '\n') goto yy85;
536 if (yych == '\r') goto yy87;
537 goto yy80;
538yy85:
539 ++p;
540 { continue; }
541yy87:
542 yych = *++p;
543 if (yych == '\n') goto yy89;
544 p = q;
545 goto yy80;
546yy89:
547 ++p;
548 { continue; }
549}
550
551 }
552}
553
554bool 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 }
605yy95:
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
623bool 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 }
679yy100:
680 ++p;
681 {
682 last_token_ = start;
683 return Error("unexpected EOF", err);
684 }
685yy102:
686 yych = *++p;
687 if (yybm[0+yych] & 16) {
688 goto yy102;
689 }
690 {
691 eval->AddText(StringPiece(start, p - start));
692 continue;
693 }
694yy105:
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 }
707yy107:
708 yych = *++p;
709 if (yych == '\n') goto yy110;
710 {
711 last_token_ = start;
712 return Error(DescribeLastError(), err);
713 }
714yy109:
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 }
739yy110:
740 ++p;
741 {
742 if (path)
743 p = start;
744 break;
745 }
746yy112:
747 ++p;
748yy113:
749 {
750 last_token_ = start;
751 return Error("bad $-escape (literal $ must be written as $$)", err);
752 }
753yy114:
754 yych = *++p;
755 if (yybm[0+yych] & 32) {
756 goto yy114;
757 }
758 {
759 continue;
760 }
761yy117:
762 yych = *++p;
763 if (yych == '\n') goto yy128;
764 goto yy113;
765yy118:
766 ++p;
767 {
768 eval->AddText(StringPiece(" ", 1));
769 continue;
770 }
771yy120:
772 ++p;
773 {
774 eval->AddText(StringPiece("$", 1));
775 continue;
776 }
777yy122:
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 }
786yy125:
787 ++p;
788 {
789 eval->AddText(StringPiece(":", 1));
790 continue;
791 }
792yy127:
793 yych = *(q = ++p);
794 if (yybm[0+yych] & 128) {
795 goto yy131;
796 }
797 goto yy113;
798yy128:
799 yych = *++p;
800 if (yych == ' ') goto yy128;
801 {
802 continue;
803 }
804yy131:
805 yych = *++p;
806 if (yybm[0+yych] & 128) {
807 goto yy131;
808 }
809 if (yych == '}') goto yy134;
810 p = q;
811 goto yy113;
812yy134:
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