Ninja
lexer.cc
Go to the documentation of this file.
00001 /* Generated by re2c 0.13.5 */
00002 // Copyright 2011 Google Inc. All Rights Reserved.
00003 //
00004 // Licensed under the Apache License, Version 2.0 (the "License");
00005 // you may not use this file except in compliance with the License.
00006 // You may obtain a copy of the License at
00007 //
00008 //     http://www.apache.org/licenses/LICENSE-2.0
00009 //
00010 // Unless required by applicable law or agreed to in writing, software
00011 // distributed under the License is distributed on an "AS IS" BASIS,
00012 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013 // See the License for the specific language governing permissions and
00014 // limitations under the License.
00015 
00016 #include "lexer.h"
00017 
00018 #include <stdio.h>
00019 
00020 #include "eval_env.h"
00021 #include "util.h"
00022 
00023 bool Lexer::Error(const string& message, string* err) {
00024   // Compute line/column.
00025   int line = 1;
00026   const char* context = input_.str_;
00027   for (const char* p = input_.str_; p < last_token_; ++p) {
00028     if (*p == '\n') {
00029       ++line;
00030       context = p + 1;
00031     }
00032   }
00033   int col = last_token_ ? (int)(last_token_ - context) : 0;
00034 
00035   char buf[1024];
00036   snprintf(buf, sizeof(buf), "%s:%d: ", filename_.AsString().c_str(), line);
00037   *err = buf;
00038   *err += message + "\n";
00039 
00040   // Add some context to the message.
00041   const int kTruncateColumn = 72;
00042   if (col > 0 && col < kTruncateColumn) {
00043     int len;
00044     bool truncated = true;
00045     for (len = 0; len < kTruncateColumn; ++len) {
00046       if (context[len] == 0 || context[len] == '\n') {
00047         truncated = false;
00048         break;
00049       }
00050     }
00051     *err += string(context, len);
00052     if (truncated)
00053       *err += "...";
00054     *err += "\n";
00055     *err += string(col, ' ');
00056     *err += "^ near here";
00057   }
00058 
00059   return false;
00060 }
00061 
00062 Lexer::Lexer(const char* input) {
00063   Start("input", input);
00064 }
00065 
00066 void Lexer::Start(StringPiece filename, StringPiece input) {
00067   filename_ = filename;
00068   input_ = input;
00069   ofs_ = input_.str_;
00070   last_token_ = NULL;
00071 }
00072 
00073 const char* Lexer::TokenName(Token t) {
00074   switch (t) {
00075   case ERROR:    return "lexing error";
00076   case BUILD:    return "'build'";
00077   case COLON:    return "':'";
00078   case DEFAULT:  return "'default'";
00079   case EQUALS:   return "'='";
00080   case IDENT:    return "identifier";
00081   case INCLUDE:  return "'include'";
00082   case INDENT:   return "indent";
00083   case NEWLINE:  return "newline";
00084   case PIPE2:    return "'||'";
00085   case PIPE:     return "'|'";
00086   case POOL:     return "'pool'";
00087   case RULE:     return "'rule'";
00088   case SUBNINJA: return "'subninja'";
00089   case TEOF:     return "eof";
00090   }
00091   return NULL;  // not reached
00092 }
00093 
00094 const char* Lexer::TokenErrorHint(Token expected) {
00095   switch (expected) {
00096   case COLON:
00097     return " ($ also escapes ':')";
00098   default:
00099     return "";
00100   }
00101 }
00102 
00103 string Lexer::DescribeLastError() {
00104   if (last_token_) {
00105     switch (last_token_[0]) {
00106     case '\r':
00107       return "carriage returns are not allowed, use newlines";
00108     case '\t':
00109       return "tabs are not allowed, use spaces";
00110     }
00111   }
00112   return "lexing error";
00113 }
00114 
00115 void Lexer::UnreadToken() {
00116   ofs_ = last_token_;
00117 }
00118 
00119 Lexer::Token Lexer::ReadToken() {
00120   const char* p = ofs_;
00121   const char* q;
00122   const char* start;
00123   Lexer::Token token;
00124   for (;;) {
00125     start = p;
00126     
00127 {
00128   unsigned char yych;
00129   unsigned int yyaccept = 0;
00130   static const unsigned char yybm[] = {
00131       0,  64,  64,  64,  64,  64,  64,  64, 
00132      64,  64,   0,  64,  64,   0,  64,  64, 
00133      64,  64,  64,  64,  64,  64,  64,  64, 
00134      64,  64,  64,  64,  64,  64,  64,  64, 
00135     192,  64,  64,  64,  64,  64,  64,  64, 
00136      64,  64,  64,  64,  64,  96,  96,  64, 
00137      96,  96,  96,  96,  96,  96,  96,  96, 
00138      96,  96,  64,  64,  64,  64,  64,  64, 
00139      64,  96,  96,  96,  96,  96,  96,  96, 
00140      96,  96,  96,  96,  96,  96,  96,  96, 
00141      96,  96,  96,  96,  96,  96,  96,  96, 
00142      96,  96,  96,  64,  64,  64,  64,  96, 
00143      64,  96,  96,  96,  96,  96,  96,  96, 
00144      96,  96,  96,  96,  96,  96,  96,  96, 
00145      96,  96,  96,  96,  96,  96,  96,  96, 
00146      96,  96,  96,  64,  64,  64,  64,  64, 
00147      64,  64,  64,  64,  64,  64,  64,  64, 
00148      64,  64,  64,  64,  64,  64,  64,  64, 
00149      64,  64,  64,  64,  64,  64,  64,  64, 
00150      64,  64,  64,  64,  64,  64,  64,  64, 
00151      64,  64,  64,  64,  64,  64,  64,  64, 
00152      64,  64,  64,  64,  64,  64,  64,  64, 
00153      64,  64,  64,  64,  64,  64,  64,  64, 
00154      64,  64,  64,  64,  64,  64,  64,  64, 
00155      64,  64,  64,  64,  64,  64,  64,  64, 
00156      64,  64,  64,  64,  64,  64,  64,  64, 
00157      64,  64,  64,  64,  64,  64,  64,  64, 
00158      64,  64,  64,  64,  64,  64,  64,  64, 
00159      64,  64,  64,  64,  64,  64,  64,  64, 
00160      64,  64,  64,  64,  64,  64,  64,  64, 
00161      64,  64,  64,  64,  64,  64,  64,  64, 
00162      64,  64,  64,  64,  64,  64,  64,  64, 
00163   };
00164 
00165   yych = *p;
00166   if (yych <= '^') {
00167     if (yych <= ',') {
00168       if (yych <= 0x1F) {
00169         if (yych <= 0x00) goto yy22;
00170         if (yych == '\n') goto yy6;
00171         goto yy24;
00172       } else {
00173         if (yych <= ' ') goto yy2;
00174         if (yych == '#') goto yy4;
00175         goto yy24;
00176       }
00177     } else {
00178       if (yych <= ':') {
00179         if (yych == '/') goto yy24;
00180         if (yych <= '9') goto yy21;
00181         goto yy15;
00182       } else {
00183         if (yych <= '=') {
00184           if (yych <= '<') goto yy24;
00185           goto yy13;
00186         } else {
00187           if (yych <= '@') goto yy24;
00188           if (yych <= 'Z') goto yy21;
00189           goto yy24;
00190         }
00191       }
00192     }
00193   } else {
00194     if (yych <= 'i') {
00195       if (yych <= 'b') {
00196         if (yych == '`') goto yy24;
00197         if (yych <= 'a') goto yy21;
00198         goto yy8;
00199       } else {
00200         if (yych == 'd') goto yy12;
00201         if (yych <= 'h') goto yy21;
00202         goto yy19;
00203       }
00204     } else {
00205       if (yych <= 'r') {
00206         if (yych == 'p') goto yy10;
00207         if (yych <= 'q') goto yy21;
00208         goto yy11;
00209       } else {
00210         if (yych <= 'z') {
00211           if (yych <= 's') goto yy20;
00212           goto yy21;
00213         } else {
00214           if (yych == '|') goto yy17;
00215           goto yy24;
00216         }
00217       }
00218     }
00219   }
00220 yy2:
00221   yyaccept = 0;
00222   yych = *(q = ++p);
00223   goto yy70;
00224 yy3:
00225   { token = INDENT;   break; }
00226 yy4:
00227   yyaccept = 1;
00228   yych = *(q = ++p);
00229   if (yych <= 0x00) goto yy5;
00230   if (yych != '\r') goto yy65;
00231 yy5:
00232   { token = ERROR;    break; }
00233 yy6:
00234   ++p;
00235 yy7:
00236   { token = NEWLINE;  break; }
00237 yy8:
00238   ++p;
00239   if ((yych = *p) == 'u') goto yy59;
00240   goto yy26;
00241 yy9:
00242   { token = IDENT;    break; }
00243 yy10:
00244   yych = *++p;
00245   if (yych == 'o') goto yy55;
00246   goto yy26;
00247 yy11:
00248   yych = *++p;
00249   if (yych == 'u') goto yy51;
00250   goto yy26;
00251 yy12:
00252   yych = *++p;
00253   if (yych == 'e') goto yy44;
00254   goto yy26;
00255 yy13:
00256   ++p;
00257   { token = EQUALS;   break; }
00258 yy15:
00259   ++p;
00260   { token = COLON;    break; }
00261 yy17:
00262   ++p;
00263   if ((yych = *p) == '|') goto yy42;
00264   { token = PIPE;     break; }
00265 yy19:
00266   yych = *++p;
00267   if (yych == 'n') goto yy35;
00268   goto yy26;
00269 yy20:
00270   yych = *++p;
00271   if (yych == 'u') goto yy27;
00272   goto yy26;
00273 yy21:
00274   yych = *++p;
00275   goto yy26;
00276 yy22:
00277   ++p;
00278   { token = TEOF;     break; }
00279 yy24:
00280   yych = *++p;
00281   goto yy5;
00282 yy25:
00283   ++p;
00284   yych = *p;
00285 yy26:
00286   if (yybm[0+yych] & 32) {
00287     goto yy25;
00288   }
00289   goto yy9;
00290 yy27:
00291   yych = *++p;
00292   if (yych != 'b') goto yy26;
00293   yych = *++p;
00294   if (yych != 'n') goto yy26;
00295   yych = *++p;
00296   if (yych != 'i') goto yy26;
00297   yych = *++p;
00298   if (yych != 'n') goto yy26;
00299   yych = *++p;
00300   if (yych != 'j') goto yy26;
00301   yych = *++p;
00302   if (yych != 'a') goto yy26;
00303   ++p;
00304   if (yybm[0+(yych = *p)] & 32) {
00305     goto yy25;
00306   }
00307   { token = SUBNINJA; break; }
00308 yy35:
00309   yych = *++p;
00310   if (yych != 'c') goto yy26;
00311   yych = *++p;
00312   if (yych != 'l') goto yy26;
00313   yych = *++p;
00314   if (yych != 'u') goto yy26;
00315   yych = *++p;
00316   if (yych != 'd') goto yy26;
00317   yych = *++p;
00318   if (yych != 'e') goto yy26;
00319   ++p;
00320   if (yybm[0+(yych = *p)] & 32) {
00321     goto yy25;
00322   }
00323   { token = INCLUDE;  break; }
00324 yy42:
00325   ++p;
00326   { token = PIPE2;    break; }
00327 yy44:
00328   yych = *++p;
00329   if (yych != 'f') goto yy26;
00330   yych = *++p;
00331   if (yych != 'a') goto yy26;
00332   yych = *++p;
00333   if (yych != 'u') goto yy26;
00334   yych = *++p;
00335   if (yych != 'l') goto yy26;
00336   yych = *++p;
00337   if (yych != 't') goto yy26;
00338   ++p;
00339   if (yybm[0+(yych = *p)] & 32) {
00340     goto yy25;
00341   }
00342   { token = DEFAULT;  break; }
00343 yy51:
00344   yych = *++p;
00345   if (yych != 'l') goto yy26;
00346   yych = *++p;
00347   if (yych != 'e') goto yy26;
00348   ++p;
00349   if (yybm[0+(yych = *p)] & 32) {
00350     goto yy25;
00351   }
00352   { token = RULE;     break; }
00353 yy55:
00354   yych = *++p;
00355   if (yych != 'o') goto yy26;
00356   yych = *++p;
00357   if (yych != 'l') goto yy26;
00358   ++p;
00359   if (yybm[0+(yych = *p)] & 32) {
00360     goto yy25;
00361   }
00362   { token = POOL;     break; }
00363 yy59:
00364   yych = *++p;
00365   if (yych != 'i') goto yy26;
00366   yych = *++p;
00367   if (yych != 'l') goto yy26;
00368   yych = *++p;
00369   if (yych != 'd') goto yy26;
00370   ++p;
00371   if (yybm[0+(yych = *p)] & 32) {
00372     goto yy25;
00373   }
00374   { token = BUILD;    break; }
00375 yy64:
00376   ++p;
00377   yych = *p;
00378 yy65:
00379   if (yybm[0+yych] & 64) {
00380     goto yy64;
00381   }
00382   if (yych <= 0x00) goto yy66;
00383   if (yych <= '\f') goto yy67;
00384 yy66:
00385   p = q;
00386   if (yyaccept <= 0) {
00387     goto yy3;
00388   } else {
00389     goto yy5;
00390   }
00391 yy67:
00392   ++p;
00393   { continue; }
00394 yy69:
00395   yyaccept = 0;
00396   q = ++p;
00397   yych = *p;
00398 yy70:
00399   if (yybm[0+yych] & 128) {
00400     goto yy69;
00401   }
00402   if (yych == '\n') goto yy71;
00403   if (yych == '#') goto yy64;
00404   goto yy3;
00405 yy71:
00406   ++p;
00407   yych = *p;
00408   goto yy7;
00409 }
00410 
00411   }
00412 
00413   last_token_ = start;
00414   ofs_ = p;
00415   if (token != NEWLINE && token != TEOF)
00416     EatWhitespace();
00417   return token;
00418 }
00419 
00420 bool Lexer::PeekToken(Token token) {
00421   Token t = ReadToken();
00422   if (t == token)
00423     return true;
00424   UnreadToken();
00425   return false;
00426 }
00427 
00428 void Lexer::EatWhitespace() {
00429   const char* p = ofs_;
00430   for (;;) {
00431     ofs_ = p;
00432     
00433 {
00434   unsigned char yych;
00435   static const unsigned char yybm[] = {
00436       0,   0,   0,   0,   0,   0,   0,   0, 
00437       0,   0,   0,   0,   0,   0,   0,   0, 
00438       0,   0,   0,   0,   0,   0,   0,   0, 
00439       0,   0,   0,   0,   0,   0,   0,   0, 
00440     128,   0,   0,   0,   0,   0,   0,   0, 
00441       0,   0,   0,   0,   0,   0,   0,   0, 
00442       0,   0,   0,   0,   0,   0,   0,   0, 
00443       0,   0,   0,   0,   0,   0,   0,   0, 
00444       0,   0,   0,   0,   0,   0,   0,   0, 
00445       0,   0,   0,   0,   0,   0,   0,   0, 
00446       0,   0,   0,   0,   0,   0,   0,   0, 
00447       0,   0,   0,   0,   0,   0,   0,   0, 
00448       0,   0,   0,   0,   0,   0,   0,   0, 
00449       0,   0,   0,   0,   0,   0,   0,   0, 
00450       0,   0,   0,   0,   0,   0,   0,   0, 
00451       0,   0,   0,   0,   0,   0,   0,   0, 
00452       0,   0,   0,   0,   0,   0,   0,   0, 
00453       0,   0,   0,   0,   0,   0,   0,   0, 
00454       0,   0,   0,   0,   0,   0,   0,   0, 
00455       0,   0,   0,   0,   0,   0,   0,   0, 
00456       0,   0,   0,   0,   0,   0,   0,   0, 
00457       0,   0,   0,   0,   0,   0,   0,   0, 
00458       0,   0,   0,   0,   0,   0,   0,   0, 
00459       0,   0,   0,   0,   0,   0,   0,   0, 
00460       0,   0,   0,   0,   0,   0,   0,   0, 
00461       0,   0,   0,   0,   0,   0,   0,   0, 
00462       0,   0,   0,   0,   0,   0,   0,   0, 
00463       0,   0,   0,   0,   0,   0,   0,   0, 
00464       0,   0,   0,   0,   0,   0,   0,   0, 
00465       0,   0,   0,   0,   0,   0,   0,   0, 
00466       0,   0,   0,   0,   0,   0,   0,   0, 
00467       0,   0,   0,   0,   0,   0,   0,   0, 
00468   };
00469   yych = *p;
00470   if (yych <= ' ') {
00471     if (yych <= 0x00) goto yy78;
00472     if (yych <= 0x1F) goto yy80;
00473   } else {
00474     if (yych == '$') goto yy76;
00475     goto yy80;
00476   }
00477   ++p;
00478   yych = *p;
00479   goto yy84;
00480 yy75:
00481   { continue; }
00482 yy76:
00483   ++p;
00484   if ((yych = *p) == '\n') goto yy81;
00485 yy77:
00486   { break; }
00487 yy78:
00488   ++p;
00489   { break; }
00490 yy80:
00491   yych = *++p;
00492   goto yy77;
00493 yy81:
00494   ++p;
00495   { continue; }
00496 yy83:
00497   ++p;
00498   yych = *p;
00499 yy84:
00500   if (yybm[0+yych] & 128) {
00501     goto yy83;
00502   }
00503   goto yy75;
00504 }
00505 
00506   }
00507 }
00508 
00509 bool Lexer::ReadIdent(string* out) {
00510   const char* p = ofs_;
00511   for (;;) {
00512     const char* start = p;
00513     
00514 {
00515   unsigned char yych;
00516   static const unsigned char yybm[] = {
00517       0,   0,   0,   0,   0,   0,   0,   0, 
00518       0,   0,   0,   0,   0,   0,   0,   0, 
00519       0,   0,   0,   0,   0,   0,   0,   0, 
00520       0,   0,   0,   0,   0,   0,   0,   0, 
00521       0,   0,   0,   0,   0,   0,   0,   0, 
00522       0,   0,   0,   0,   0, 128, 128,   0, 
00523     128, 128, 128, 128, 128, 128, 128, 128, 
00524     128, 128,   0,   0,   0,   0,   0,   0, 
00525       0, 128, 128, 128, 128, 128, 128, 128, 
00526     128, 128, 128, 128, 128, 128, 128, 128, 
00527     128, 128, 128, 128, 128, 128, 128, 128, 
00528     128, 128, 128,   0,   0,   0,   0, 128, 
00529       0, 128, 128, 128, 128, 128, 128, 128, 
00530     128, 128, 128, 128, 128, 128, 128, 128, 
00531     128, 128, 128, 128, 128, 128, 128, 128, 
00532     128, 128, 128,   0,   0,   0,   0,   0, 
00533       0,   0,   0,   0,   0,   0,   0,   0, 
00534       0,   0,   0,   0,   0,   0,   0,   0, 
00535       0,   0,   0,   0,   0,   0,   0,   0, 
00536       0,   0,   0,   0,   0,   0,   0,   0, 
00537       0,   0,   0,   0,   0,   0,   0,   0, 
00538       0,   0,   0,   0,   0,   0,   0,   0, 
00539       0,   0,   0,   0,   0,   0,   0,   0, 
00540       0,   0,   0,   0,   0,   0,   0,   0, 
00541       0,   0,   0,   0,   0,   0,   0,   0, 
00542       0,   0,   0,   0,   0,   0,   0,   0, 
00543       0,   0,   0,   0,   0,   0,   0,   0, 
00544       0,   0,   0,   0,   0,   0,   0,   0, 
00545       0,   0,   0,   0,   0,   0,   0,   0, 
00546       0,   0,   0,   0,   0,   0,   0,   0, 
00547       0,   0,   0,   0,   0,   0,   0,   0, 
00548       0,   0,   0,   0,   0,   0,   0,   0, 
00549   };
00550   yych = *p;
00551   if (yych <= '@') {
00552     if (yych <= '.') {
00553       if (yych <= ',') goto yy89;
00554     } else {
00555       if (yych <= '/') goto yy89;
00556       if (yych >= ':') goto yy89;
00557     }
00558   } else {
00559     if (yych <= '_') {
00560       if (yych <= 'Z') goto yy87;
00561       if (yych <= '^') goto yy89;
00562     } else {
00563       if (yych <= '`') goto yy89;
00564       if (yych >= '{') goto yy89;
00565     }
00566   }
00567 yy87:
00568   ++p;
00569   yych = *p;
00570   goto yy92;
00571 yy88:
00572   {
00573       out->assign(start, p - start);
00574       break;
00575     }
00576 yy89:
00577   ++p;
00578   { return false; }
00579 yy91:
00580   ++p;
00581   yych = *p;
00582 yy92:
00583   if (yybm[0+yych] & 128) {
00584     goto yy91;
00585   }
00586   goto yy88;
00587 }
00588 
00589   }
00590   ofs_ = p;
00591   EatWhitespace();
00592   return true;
00593 }
00594 
00595 bool Lexer::ReadEvalString(EvalString* eval, bool path, string* err) {
00596   const char* p = ofs_;
00597   const char* q;
00598   const char* start;
00599   for (;;) {
00600     start = p;
00601     
00602 {
00603   unsigned char yych;
00604   static const unsigned char yybm[] = {
00605       0, 128, 128, 128, 128, 128, 128, 128, 
00606     128, 128,   0, 128, 128,   0, 128, 128, 
00607     128, 128, 128, 128, 128, 128, 128, 128, 
00608     128, 128, 128, 128, 128, 128, 128, 128, 
00609      16, 128, 128, 128,   0, 128, 128, 128, 
00610     128, 128, 128, 128, 128, 224, 160, 128, 
00611     224, 224, 224, 224, 224, 224, 224, 224, 
00612     224, 224,   0, 128, 128, 128, 128, 128, 
00613     128, 224, 224, 224, 224, 224, 224, 224, 
00614     224, 224, 224, 224, 224, 224, 224, 224, 
00615     224, 224, 224, 224, 224, 224, 224, 224, 
00616     224, 224, 224, 128, 128, 128, 128, 224, 
00617     128, 224, 224, 224, 224, 224, 224, 224, 
00618     224, 224, 224, 224, 224, 224, 224, 224, 
00619     224, 224, 224, 224, 224, 224, 224, 224, 
00620     224, 224, 224, 128,   0, 128, 128, 128, 
00621     128, 128, 128, 128, 128, 128, 128, 128, 
00622     128, 128, 128, 128, 128, 128, 128, 128, 
00623     128, 128, 128, 128, 128, 128, 128, 128, 
00624     128, 128, 128, 128, 128, 128, 128, 128, 
00625     128, 128, 128, 128, 128, 128, 128, 128, 
00626     128, 128, 128, 128, 128, 128, 128, 128, 
00627     128, 128, 128, 128, 128, 128, 128, 128, 
00628     128, 128, 128, 128, 128, 128, 128, 128, 
00629     128, 128, 128, 128, 128, 128, 128, 128, 
00630     128, 128, 128, 128, 128, 128, 128, 128, 
00631     128, 128, 128, 128, 128, 128, 128, 128, 
00632     128, 128, 128, 128, 128, 128, 128, 128, 
00633     128, 128, 128, 128, 128, 128, 128, 128, 
00634     128, 128, 128, 128, 128, 128, 128, 128, 
00635     128, 128, 128, 128, 128, 128, 128, 128, 
00636     128, 128, 128, 128, 128, 128, 128, 128, 
00637   };
00638   yych = *p;
00639   if (yych <= ' ') {
00640     if (yych <= '\n') {
00641       if (yych <= 0x00) goto yy101;
00642       if (yych >= '\n') goto yy97;
00643     } else {
00644       if (yych == '\r') goto yy103;
00645       if (yych >= ' ') goto yy97;
00646     }
00647   } else {
00648     if (yych <= '9') {
00649       if (yych == '$') goto yy99;
00650     } else {
00651       if (yych <= ':') goto yy97;
00652       if (yych == '|') goto yy97;
00653     }
00654   }
00655   ++p;
00656   yych = *p;
00657   goto yy126;
00658 yy96:
00659   {
00660       eval->AddText(StringPiece(start, p - start));
00661       continue;
00662     }
00663 yy97:
00664   ++p;
00665   {
00666       if (path) {
00667         p = start;
00668         break;
00669       } else {
00670         if (*start == '\n')
00671           break;
00672         eval->AddText(StringPiece(start, 1));
00673         continue;
00674       }
00675     }
00676 yy99:
00677   ++p;
00678   if ((yych = *p) <= '/') {
00679     if (yych <= ' ') {
00680       if (yych == '\n') goto yy115;
00681       if (yych <= 0x1F) goto yy104;
00682       goto yy106;
00683     } else {
00684       if (yych <= '$') {
00685         if (yych <= '#') goto yy104;
00686         goto yy108;
00687       } else {
00688         if (yych == '-') goto yy110;
00689         goto yy104;
00690       }
00691     }
00692   } else {
00693     if (yych <= '^') {
00694       if (yych <= ':') {
00695         if (yych <= '9') goto yy110;
00696         goto yy112;
00697       } else {
00698         if (yych <= '@') goto yy104;
00699         if (yych <= 'Z') goto yy110;
00700         goto yy104;
00701       }
00702     } else {
00703       if (yych <= '`') {
00704         if (yych <= '_') goto yy110;
00705         goto yy104;
00706       } else {
00707         if (yych <= 'z') goto yy110;
00708         if (yych <= '{') goto yy114;
00709         goto yy104;
00710       }
00711     }
00712   }
00713 yy100:
00714   {
00715       last_token_ = start;
00716       return Error(DescribeLastError(), err);
00717     }
00718 yy101:
00719   ++p;
00720   {
00721       last_token_ = start;
00722       return Error("unexpected EOF", err);
00723     }
00724 yy103:
00725   yych = *++p;
00726   goto yy100;
00727 yy104:
00728   ++p;
00729 yy105:
00730   {
00731       last_token_ = start;
00732       return Error("bad $-escape (literal $ must be written as $$)", err);
00733     }
00734 yy106:
00735   ++p;
00736   {
00737       eval->AddText(StringPiece(" ", 1));
00738       continue;
00739     }
00740 yy108:
00741   ++p;
00742   {
00743       eval->AddText(StringPiece("$", 1));
00744       continue;
00745     }
00746 yy110:
00747   ++p;
00748   yych = *p;
00749   goto yy124;
00750 yy111:
00751   {
00752       eval->AddSpecial(StringPiece(start + 1, p - start - 1));
00753       continue;
00754     }
00755 yy112:
00756   ++p;
00757   {
00758       eval->AddText(StringPiece(":", 1));
00759       continue;
00760     }
00761 yy114:
00762   yych = *(q = ++p);
00763   if (yybm[0+yych] & 32) {
00764     goto yy118;
00765   }
00766   goto yy105;
00767 yy115:
00768   ++p;
00769   yych = *p;
00770   if (yybm[0+yych] & 16) {
00771     goto yy115;
00772   }
00773   {
00774       continue;
00775     }
00776 yy118:
00777   ++p;
00778   yych = *p;
00779   if (yybm[0+yych] & 32) {
00780     goto yy118;
00781   }
00782   if (yych == '}') goto yy121;
00783   p = q;
00784   goto yy105;
00785 yy121:
00786   ++p;
00787   {
00788       eval->AddSpecial(StringPiece(start + 2, p - start - 3));
00789       continue;
00790     }
00791 yy123:
00792   ++p;
00793   yych = *p;
00794 yy124:
00795   if (yybm[0+yych] & 64) {
00796     goto yy123;
00797   }
00798   goto yy111;
00799 yy125:
00800   ++p;
00801   yych = *p;
00802 yy126:
00803   if (yybm[0+yych] & 128) {
00804     goto yy125;
00805   }
00806   goto yy96;
00807 }
00808 
00809   }
00810   last_token_ = start;
00811   ofs_ = p;
00812   if (path)
00813     EatWhitespace();
00814   // Non-path strings end in newlines, so there's no whitespace to eat.
00815   return true;
00816 }