Remove accidental changes
authorScott Graham <scottmg@chromium.org>
Mon, 10 Aug 2015 04:27:39 +0000 (21:27 -0700)
committerScott Graham <scottmg@chromium.org>
Mon, 10 Aug 2015 04:27:39 +0000 (21:27 -0700)
src/depfile_parser.cc
src/lexer.cc

index c5bc291..7268f31 100644 (file)
-/* Generated by re2c 0.13.5 */\r
-// Copyright 2011 Google Inc. All Rights Reserved.\r
-//\r
-// Licensed under the Apache License, Version 2.0 (the "License");\r
-// you may not use this file except in compliance with the License.\r
-// You may obtain a copy of the License at\r
-//\r
-//     http://www.apache.org/licenses/LICENSE-2.0\r
-//\r
-// Unless required by applicable law or agreed to in writing, software\r
-// distributed under the License is distributed on an "AS IS" BASIS,\r
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
-// See the License for the specific language governing permissions and\r
-// limitations under the License.\r
-\r
-#include "depfile_parser.h"\r
-\r
-// A note on backslashes in Makefiles, from reading the docs:\r
-// Backslash-newline is the line continuation character.\r
-// Backslash-# escapes a # (otherwise meaningful as a comment start).\r
-// Backslash-% escapes a % (otherwise meaningful as a special).\r
-// Finally, quoting the GNU manual, "Backslashes that are not in danger\r
-// of quoting ‘%’ characters go unmolested."\r
-// How do you end a line with a backslash?  The netbsd Make docs suggest\r
-// reading the result of a shell command echoing a backslash!\r
-//\r
-// Rather than implement all of above, we do a simpler thing here:\r
-// Backslashes escape a set of characters (see "escapes" defined below),\r
-// otherwise they are passed through verbatim.\r
-// If anyone actually has depfiles that rely on the more complicated\r
-// behavior we can adjust this.\r
-bool DepfileParser::Parse(string* content, string* err) {\r
-  // in: current parser input point.\r
-  // end: end of input.\r
-  // parsing_targets: whether we are parsing targets or dependencies.\r
-  char* in = &(*content)[0];\r
-  char* end = in + content->size();\r
-  bool parsing_targets = true;\r
-  while (in < end) {\r
-    // out: current output point (typically same as in, but can fall behind\r
-    // as we de-escape backslashes).\r
-    char* out = in;\r
-    // filename: start of the current parsed filename.\r
-    char* filename = out;\r
-    for (;;) {\r
-      // start: beginning of the current parsed span.\r
-      const char* start = in;\r
-      \r
-    {\r
-      char yych;\r
-      static const unsigned char yybm[] = {\r
-          0,   0,   0,   0,   0,   0,   0,   0, \r
-          0,   0,   0,   0,   0,   0,   0,   0, \r
-          0,   0,   0,   0,   0,   0,   0,   0, \r
-          0,   0,   0,   0,   0,   0,   0,   0, \r
-          0, 128,   0,   0,   0,   0,   0,   0, \r
-        128, 128,   0, 128, 128, 128, 128, 128, \r
-        128, 128, 128, 128, 128, 128, 128, 128, \r
-        128, 128, 128,   0,   0, 128,   0,   0, \r
-        128, 128, 128, 128, 128, 128, 128, 128, \r
-        128, 128, 128, 128, 128, 128, 128, 128, \r
-        128, 128, 128, 128, 128, 128, 128, 128, \r
-        128, 128, 128,   0,   0,   0,   0, 128, \r
-          0, 128, 128, 128, 128, 128, 128, 128, \r
-        128, 128, 128, 128, 128, 128, 128, 128, \r
-        128, 128, 128, 128, 128, 128, 128, 128, \r
-        128, 128, 128, 128,   0, 128, 128,   0, \r
-          0,   0,   0,   0,   0,   0,   0,   0, \r
-          0,   0,   0,   0,   0,   0,   0,   0, \r
-          0,   0,   0,   0,   0,   0,   0,   0, \r
-          0,   0,   0,   0,   0,   0,   0,   0, \r
-          0,   0,   0,   0,   0,   0,   0,   0, \r
-          0,   0,   0,   0,   0,   0,   0,   0, \r
-          0,   0,   0,   0,   0,   0,   0,   0, \r
-          0,   0,   0,   0,   0,   0,   0,   0, \r
-          0,   0,   0,   0,   0,   0,   0,   0, \r
-          0,   0,   0,   0,   0,   0,   0,   0, \r
-          0,   0,   0,   0,   0,   0,   0,   0, \r
-          0,   0,   0,   0,   0,   0,   0,   0, \r
-          0,   0,   0,   0,   0,   0,   0,   0, \r
-          0,   0,   0,   0,   0,   0,   0,   0, \r
-          0,   0,   0,   0,   0,   0,   0,   0, \r
-          0,   0,   0,   0,   0,   0,   0,   0, \r
-      };\r
-\r
-      yych = *in;\r
-      if (yych <= '=') {\r
-        if (yych <= '$') {\r
-          if (yych <= ' ') {\r
-            if (yych <= 0x00) goto yy7;\r
-            goto yy9;\r
-          } else {\r
-            if (yych <= '!') goto yy5;\r
-            if (yych <= '#') goto yy9;\r
-            goto yy4;\r
-          }\r
-        } else {\r
-          if (yych <= '*') {\r
-            if (yych <= '\'') goto yy9;\r
-            if (yych <= ')') goto yy5;\r
-            goto yy9;\r
-          } else {\r
-            if (yych <= ':') goto yy5;\r
-            if (yych <= '<') goto yy9;\r
-            goto yy5;\r
-          }\r
-        }\r
-      } else {\r
-        if (yych <= '^') {\r
-          if (yych <= 'Z') {\r
-            if (yych <= '?') goto yy9;\r
-            goto yy5;\r
-          } else {\r
-            if (yych != '\\') goto yy9;\r
-          }\r
-        } else {\r
-          if (yych <= '{') {\r
-            if (yych == '`') goto yy9;\r
-            goto yy5;\r
-          } else {\r
-            if (yych <= '|') goto yy9;\r
-            if (yych <= '~') goto yy5;\r
-            goto yy9;\r
-          }\r
-        }\r
-      }\r
-      ++in;\r
-      if ((yych = *in) <= '"') {\r
-        if (yych <= '\f') {\r
-          if (yych <= 0x00) goto yy3;\r
-          if (yych != '\n') goto yy14;\r
-        } else {\r
-          if (yych <= '\r') goto yy3;\r
-          if (yych == ' ') goto yy16;\r
-          goto yy14;\r
-        }\r
-      } else {\r
-        if (yych <= 'Z') {\r
-          if (yych <= '#') goto yy16;\r
-          if (yych == '*') goto yy16;\r
-          goto yy14;\r
-        } else {\r
-          if (yych <= '\\') goto yy16;\r
-          if (yych == '|') goto yy16;\r
-          goto yy14;\r
-        }\r
-      }\r
-yy3:\r
-      {\r
-        // For any other character (e.g. whitespace), swallow it here,\r
-        // allowing the outer logic to loop around again.\r
-        break;\r
-      }\r
-yy4:\r
-      yych = *++in;\r
-      if (yych == '$') goto yy12;\r
-      goto yy3;\r
-yy5:\r
-      ++in;\r
-      yych = *in;\r
-      goto yy11;\r
-yy6:\r
-      {\r
-        // Got a span of plain text.\r
-        int len = (int)(in - start);\r
-        // Need to shift it over if we're overwriting backslashes.\r
-        if (out < start)\r
-          memmove(out, start, len);\r
-        out += len;\r
-        continue;\r
-      }\r
-yy7:\r
-      ++in;\r
-      {\r
-        break;\r
-      }\r
-yy9:\r
-      yych = *++in;\r
-      goto yy3;\r
-yy10:\r
-      ++in;\r
-      yych = *in;\r
-yy11:\r
-      if (yybm[0+yych] & 128) {\r
-        goto yy10;\r
-      }\r
-      goto yy6;\r
-yy12:\r
-      ++in;\r
-      {\r
-        // De-escape dollar character.\r
-        *out++ = '$';\r
-        continue;\r
-      }\r
-yy14:\r
-      ++in;\r
-      {\r
-        // Let backslash before other characters through verbatim.\r
-        *out++ = '\\';\r
-        *out++ = yych;\r
-        continue;\r
-      }\r
-yy16:\r
-      ++in;\r
-      {\r
-        // De-escape backslashed character.\r
-        *out++ = yych;\r
-        continue;\r
-      }\r
-    }\r
-\r
-    }\r
-\r
-    int len = (int)(out - filename);\r
-    const bool is_target = parsing_targets;\r
-    if (len > 0 && filename[len - 1] == ':') {\r
-      len--;  // Strip off trailing colon, if any.\r
-      parsing_targets = false;\r
-    }\r
-\r
-    if (len == 0)\r
-      continue;\r
-\r
-    if (!is_target) {\r
-      ins_.push_back(StringPiece(filename, len));\r
-    } else if (!out_.str_) {\r
-      out_ = StringPiece(filename, len);\r
-    } else if (out_ != StringPiece(filename, len)) {\r
-      *err = "depfile has multiple output paths";\r
-      return false;\r
-    }\r
-  }\r
-  if (parsing_targets) {\r
-    *err = "expected ':' in depfile";\r
-    return false;\r
-  }\r
-  return true;\r
-}\r
+/* Generated by re2c 0.13.5 */
+// Copyright 2011 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "depfile_parser.h"
+
+// A note on backslashes in Makefiles, from reading the docs:
+// Backslash-newline is the line continuation character.
+// Backslash-# escapes a # (otherwise meaningful as a comment start).
+// Backslash-% escapes a % (otherwise meaningful as a special).
+// Finally, quoting the GNU manual, "Backslashes that are not in danger
+// of quoting ‘%’ characters go unmolested."
+// How do you end a line with a backslash?  The netbsd Make docs suggest
+// reading the result of a shell command echoing a backslash!
+//
+// Rather than implement all of above, we do a simpler thing here:
+// Backslashes escape a set of characters (see "escapes" defined below),
+// otherwise they are passed through verbatim.
+// If anyone actually has depfiles that rely on the more complicated
+// behavior we can adjust this.
+bool DepfileParser::Parse(string* content, string* err) {
+  // in: current parser input point.
+  // end: end of input.
+  // parsing_targets: whether we are parsing targets or dependencies.
+  char* in = &(*content)[0];
+  char* end = in + content->size();
+  bool parsing_targets = true;
+  while (in < end) {
+    // out: current output point (typically same as in, but can fall behind
+    // as we de-escape backslashes).
+    char* out = in;
+    // filename: start of the current parsed filename.
+    char* filename = out;
+    for (;;) {
+      // start: beginning of the current parsed span.
+      const char* start = in;
+      
+    {
+      char yych;
+      static const unsigned char yybm[] = {
+          0,   0,   0,   0,   0,   0,   0,   0, 
+          0,   0,   0,   0,   0,   0,   0,   0, 
+          0,   0,   0,   0,   0,   0,   0,   0, 
+          0,   0,   0,   0,   0,   0,   0,   0, 
+          0, 128,   0,   0,   0,   0,   0,   0, 
+        128, 128,   0, 128, 128, 128, 128, 128, 
+        128, 128, 128, 128, 128, 128, 128, 128, 
+        128, 128, 128,   0,   0, 128,   0,   0, 
+        128, 128, 128, 128, 128, 128, 128, 128, 
+        128, 128, 128, 128, 128, 128, 128, 128, 
+        128, 128, 128, 128, 128, 128, 128, 128, 
+        128, 128, 128,   0,   0,   0,   0, 128, 
+          0, 128, 128, 128, 128, 128, 128, 128, 
+        128, 128, 128, 128, 128, 128, 128, 128, 
+        128, 128, 128, 128, 128, 128, 128, 128, 
+        128, 128, 128, 128,   0, 128, 128,   0, 
+          0,   0,   0,   0,   0,   0,   0,   0, 
+          0,   0,   0,   0,   0,   0,   0,   0, 
+          0,   0,   0,   0,   0,   0,   0,   0, 
+          0,   0,   0,   0,   0,   0,   0,   0, 
+          0,   0,   0,   0,   0,   0,   0,   0, 
+          0,   0,   0,   0,   0,   0,   0,   0, 
+          0,   0,   0,   0,   0,   0,   0,   0, 
+          0,   0,   0,   0,   0,   0,   0,   0, 
+          0,   0,   0,   0,   0,   0,   0,   0, 
+          0,   0,   0,   0,   0,   0,   0,   0, 
+          0,   0,   0,   0,   0,   0,   0,   0, 
+          0,   0,   0,   0,   0,   0,   0,   0, 
+          0,   0,   0,   0,   0,   0,   0,   0, 
+          0,   0,   0,   0,   0,   0,   0,   0, 
+          0,   0,   0,   0,   0,   0,   0,   0, 
+          0,   0,   0,   0,   0,   0,   0,   0, 
+      };
+
+      yych = *in;
+      if (yych <= '=') {
+        if (yych <= '$') {
+          if (yych <= ' ') {
+            if (yych <= 0x00) goto yy7;
+            goto yy9;
+          } else {
+            if (yych <= '!') goto yy5;
+            if (yych <= '#') goto yy9;
+            goto yy4;
+          }
+        } else {
+          if (yych <= '*') {
+            if (yych <= '\'') goto yy9;
+            if (yych <= ')') goto yy5;
+            goto yy9;
+          } else {
+            if (yych <= ':') goto yy5;
+            if (yych <= '<') goto yy9;
+            goto yy5;
+          }
+        }
+      } else {
+        if (yych <= '^') {
+          if (yych <= 'Z') {
+            if (yych <= '?') goto yy9;
+            goto yy5;
+          } else {
+            if (yych != '\\') goto yy9;
+          }
+        } else {
+          if (yych <= '{') {
+            if (yych == '`') goto yy9;
+            goto yy5;
+          } else {
+            if (yych <= '|') goto yy9;
+            if (yych <= '~') goto yy5;
+            goto yy9;
+          }
+        }
+      }
+      ++in;
+      if ((yych = *in) <= '"') {
+        if (yych <= '\f') {
+          if (yych <= 0x00) goto yy3;
+          if (yych != '\n') goto yy14;
+        } else {
+          if (yych <= '\r') goto yy3;
+          if (yych == ' ') goto yy16;
+          goto yy14;
+        }
+      } else {
+        if (yych <= 'Z') {
+          if (yych <= '#') goto yy16;
+          if (yych == '*') goto yy16;
+          goto yy14;
+        } else {
+          if (yych <= '\\') goto yy16;
+          if (yych == '|') goto yy16;
+          goto yy14;
+        }
+      }
+yy3:
+      {
+        // For any other character (e.g. whitespace), swallow it here,
+        // allowing the outer logic to loop around again.
+        break;
+      }
+yy4:
+      yych = *++in;
+      if (yych == '$') goto yy12;
+      goto yy3;
+yy5:
+      ++in;
+      yych = *in;
+      goto yy11;
+yy6:
+      {
+        // Got a span of plain text.
+        int len = (int)(in - start);
+        // Need to shift it over if we're overwriting backslashes.
+        if (out < start)
+          memmove(out, start, len);
+        out += len;
+        continue;
+      }
+yy7:
+      ++in;
+      {
+        break;
+      }
+yy9:
+      yych = *++in;
+      goto yy3;
+yy10:
+      ++in;
+      yych = *in;
+yy11:
+      if (yybm[0+yych] & 128) {
+        goto yy10;
+      }
+      goto yy6;
+yy12:
+      ++in;
+      {
+        // De-escape dollar character.
+        *out++ = '$';
+        continue;
+      }
+yy14:
+      ++in;
+      {
+        // Let backslash before other characters through verbatim.
+        *out++ = '\\';
+        *out++ = yych;
+        continue;
+      }
+yy16:
+      ++in;
+      {
+        // De-escape backslashed character.
+        *out++ = yych;
+        continue;
+      }
+    }
+
+    }
+
+    int len = (int)(out - filename);
+    const bool is_target = parsing_targets;
+    if (len > 0 && filename[len - 1] == ':') {
+      len--;  // Strip off trailing colon, if any.
+      parsing_targets = false;
+    }
+
+    if (len == 0)
+      continue;
+
+    if (!is_target) {
+      ins_.push_back(StringPiece(filename, len));
+    } else if (!out_.str_) {
+      out_ = StringPiece(filename, len);
+    } else if (out_ != StringPiece(filename, len)) {
+      *err = "depfile has multiple output paths";
+      return false;
+    }
+  }
+  if (parsing_targets) {
+    *err = "expected ':' in depfile";
+    return false;
+  }
+  return true;
+}
index 81264bd..37b8678 100644 (file)
-/* Generated by re2c 0.13.5 */\r
-// Copyright 2011 Google Inc. All Rights Reserved.\r
-//\r
-// Licensed under the Apache License, Version 2.0 (the "License");\r
-// you may not use this file except in compliance with the License.\r
-// You may obtain a copy of the License at\r
-//\r
-//     http://www.apache.org/licenses/LICENSE-2.0\r
-//\r
-// Unless required by applicable law or agreed to in writing, software\r
-// distributed under the License is distributed on an "AS IS" BASIS,\r
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
-// See the License for the specific language governing permissions and\r
-// limitations under the License.\r
-\r
-#include "lexer.h"\r
-\r
-#include <stdio.h>\r
-\r
-#include "eval_env.h"\r
-#include "util.h"\r
-\r
-bool Lexer::Error(const string& message, string* err) {\r
-  // Compute line/column.\r
-  int line = 1;\r
-  const char* context = input_.str_;\r
-  for (const char* p = input_.str_; p < last_token_; ++p) {\r
-    if (*p == '\n') {\r
-      ++line;\r
-      context = p + 1;\r
-    }\r
-  }\r
-  int col = last_token_ ? (int)(last_token_ - context) : 0;\r
-\r
-  char buf[1024];\r
-  snprintf(buf, sizeof(buf), "%s:%d: ", filename_.AsString().c_str(), line);\r
-  *err = buf;\r
-  *err += message + "\n";\r
-\r
-  // Add some context to the message.\r
-  const int kTruncateColumn = 72;\r
-  if (col > 0 && col < kTruncateColumn) {\r
-    int len;\r
-    bool truncated = true;\r
-    for (len = 0; len < kTruncateColumn; ++len) {\r
-      if (context[len] == 0 || context[len] == '\n') {\r
-        truncated = false;\r
-        break;\r
-      }\r
-    }\r
-    *err += string(context, len);\r
-    if (truncated)\r
-      *err += "...";\r
-    *err += "\n";\r
-    *err += string(col, ' ');\r
-    *err += "^ near here";\r
-  }\r
-\r
-  return false;\r
-}\r
-\r
-Lexer::Lexer(const char* input) {\r
-  Start("input", input);\r
-}\r
-\r
-void Lexer::Start(StringPiece filename, StringPiece input) {\r
-  filename_ = filename;\r
-  input_ = input;\r
-  ofs_ = input_.str_;\r
-  last_token_ = NULL;\r
-}\r
-\r
-const char* Lexer::TokenName(Token t) {\r
-  switch (t) {\r
-  case ERROR:    return "lexing error";\r
-  case BUILD:    return "'build'";\r
-  case COLON:    return "':'";\r
-  case DEFAULT:  return "'default'";\r
-  case EQUALS:   return "'='";\r
-  case IDENT:    return "identifier";\r
-  case INCLUDE:  return "'include'";\r
-  case INDENT:   return "indent";\r
-  case NEWLINE:  return "newline";\r
-  case PIPE2:    return "'||'";\r
-  case PIPE:     return "'|'";\r
-  case POOL:     return "'pool'";\r
-  case RULE:     return "'rule'";\r
-  case SUBNINJA: return "'subninja'";\r
-  case TEOF:     return "eof";\r
-  }\r
-  return NULL;  // not reached\r
-}\r
-\r
-const char* Lexer::TokenErrorHint(Token expected) {\r
-  switch (expected) {\r
-  case COLON:\r
-    return " ($ also escapes ':')";\r
-  default:\r
-    return "";\r
-  }\r
-}\r
-\r
-string Lexer::DescribeLastError() {\r
-  if (last_token_) {\r
-    switch (last_token_[0]) {\r
-    case '\t':\r
-      return "tabs are not allowed, use spaces";\r
-    }\r
-  }\r
-  return "lexing error";\r
-}\r
-\r
-void Lexer::UnreadToken() {\r
-  ofs_ = last_token_;\r
-}\r
-\r
-Lexer::Token Lexer::ReadToken() {\r
-  const char* p = ofs_;\r
-  const char* q;\r
-  const char* start;\r
-  Lexer::Token token;\r
-  for (;;) {\r
-    start = p;\r
-    \r
-{\r
-       unsigned char yych;\r
-       unsigned int yyaccept = 0;\r
-       static const unsigned char yybm[] = {\r
-                 0,  64,  64,  64,  64,  64,  64,  64, \r
-                64,  64,   0,  64,  64,  64,  64,  64, \r
-                64,  64,  64,  64,  64,  64,  64,  64, \r
-                64,  64,  64,  64,  64,  64,  64,  64, \r
-               192,  64,  64,  64,  64,  64,  64,  64, \r
-                64,  64,  64,  64,  64,  96,  96,  64, \r
-                96,  96,  96,  96,  96,  96,  96,  96, \r
-                96,  96,  64,  64,  64,  64,  64,  64, \r
-                64,  96,  96,  96,  96,  96,  96,  96, \r
-                96,  96,  96,  96,  96,  96,  96,  96, \r
-                96,  96,  96,  96,  96,  96,  96,  96, \r
-                96,  96,  96,  64,  64,  64,  64,  96, \r
-                64,  96,  96,  96,  96,  96,  96,  96, \r
-                96,  96,  96,  96,  96,  96,  96,  96, \r
-                96,  96,  96,  96,  96,  96,  96,  96, \r
-                96,  96,  96,  64,  64,  64,  64,  64, \r
-                64,  64,  64,  64,  64,  64,  64,  64, \r
-                64,  64,  64,  64,  64,  64,  64,  64, \r
-                64,  64,  64,  64,  64,  64,  64,  64, \r
-                64,  64,  64,  64,  64,  64,  64,  64, \r
-                64,  64,  64,  64,  64,  64,  64,  64, \r
-                64,  64,  64,  64,  64,  64,  64,  64, \r
-                64,  64,  64,  64,  64,  64,  64,  64, \r
-                64,  64,  64,  64,  64,  64,  64,  64, \r
-                64,  64,  64,  64,  64,  64,  64,  64, \r
-                64,  64,  64,  64,  64,  64,  64,  64, \r
-                64,  64,  64,  64,  64,  64,  64,  64, \r
-                64,  64,  64,  64,  64,  64,  64,  64, \r
-                64,  64,  64,  64,  64,  64,  64,  64, \r
-                64,  64,  64,  64,  64,  64,  64,  64, \r
-                64,  64,  64,  64,  64,  64,  64,  64, \r
-                64,  64,  64,  64,  64,  64,  64,  64, \r
-       };\r
-\r
-       yych = *p;\r
-       if (yych <= 'Z') {\r
-               if (yych <= '#') {\r
-                       if (yych <= '\f') {\r
-                               if (yych <= 0x00) goto yy23;\r
-                               if (yych == '\n') goto yy7;\r
-                               goto yy25;\r
-                       } else {\r
-                               if (yych <= 0x1F) {\r
-                                       if (yych <= '\r') goto yy6;\r
-                                       goto yy25;\r
-                               } else {\r
-                                       if (yych <= ' ') goto yy2;\r
-                                       if (yych <= '"') goto yy25;\r
-                                       goto yy4;\r
-                               }\r
-                       }\r
-               } else {\r
-                       if (yych <= '9') {\r
-                               if (yych <= ',') goto yy25;\r
-                               if (yych == '/') goto yy25;\r
-                               goto yy22;\r
-                       } else {\r
-                               if (yych <= '<') {\r
-                                       if (yych <= ':') goto yy16;\r
-                                       goto yy25;\r
-                               } else {\r
-                                       if (yych <= '=') goto yy14;\r
-                                       if (yych <= '@') goto yy25;\r
-                                       goto yy22;\r
-                               }\r
-                       }\r
-               }\r
-       } else {\r
-               if (yych <= 'i') {\r
-                       if (yych <= 'a') {\r
-                               if (yych == '_') goto yy22;\r
-                               if (yych <= '`') goto yy25;\r
-                               goto yy22;\r
-                       } else {\r
-                               if (yych <= 'c') {\r
-                                       if (yych <= 'b') goto yy9;\r
-                                       goto yy22;\r
-                               } else {\r
-                                       if (yych <= 'd') goto yy13;\r
-                                       if (yych <= 'h') goto yy22;\r
-                                       goto yy20;\r
-                               }\r
-                       }\r
-               } else {\r
-                       if (yych <= 'r') {\r
-                               if (yych == 'p') goto yy11;\r
-                               if (yych <= 'q') goto yy22;\r
-                               goto yy12;\r
-                       } else {\r
-                               if (yych <= 'z') {\r
-                                       if (yych <= 's') goto yy21;\r
-                                       goto yy22;\r
-                               } else {\r
-                                       if (yych == '|') goto yy18;\r
-                                       goto yy25;\r
-                               }\r
-                       }\r
-               }\r
-       }\r
-yy2:\r
-       yyaccept = 0;\r
-       yych = *(q = ++p);\r
-       goto yy73;\r
-yy3:\r
-       { token = INDENT;   break; }\r
-yy4:\r
-       yyaccept = 1;\r
-       yych = *(q = ++p);\r
-       if (yych >= 0x01) goto yy68;\r
-yy5:\r
-       { token = ERROR;    break; }\r
-yy6:\r
-       yych = *++p;\r
-       if (yych == '\n') goto yy65;\r
-       goto yy5;\r
-yy7:\r
-       ++p;\r
-yy8:\r
-       { token = NEWLINE;  break; }\r
-yy9:\r
-       ++p;\r
-       if ((yych = *p) == 'u') goto yy60;\r
-       goto yy27;\r
-yy10:\r
-       { token = IDENT;    break; }\r
-yy11:\r
-       yych = *++p;\r
-       if (yych == 'o') goto yy56;\r
-       goto yy27;\r
-yy12:\r
-       yych = *++p;\r
-       if (yych == 'u') goto yy52;\r
-       goto yy27;\r
-yy13:\r
-       yych = *++p;\r
-       if (yych == 'e') goto yy45;\r
-       goto yy27;\r
-yy14:\r
-       ++p;\r
-       { token = EQUALS;   break; }\r
-yy16:\r
-       ++p;\r
-       { token = COLON;    break; }\r
-yy18:\r
-       ++p;\r
-       if ((yych = *p) == '|') goto yy43;\r
-       { token = PIPE;     break; }\r
-yy20:\r
-       yych = *++p;\r
-       if (yych == 'n') goto yy36;\r
-       goto yy27;\r
-yy21:\r
-       yych = *++p;\r
-       if (yych == 'u') goto yy28;\r
-       goto yy27;\r
-yy22:\r
-       yych = *++p;\r
-       goto yy27;\r
-yy23:\r
-       ++p;\r
-       { token = TEOF;     break; }\r
-yy25:\r
-       yych = *++p;\r
-       goto yy5;\r
-yy26:\r
-       ++p;\r
-       yych = *p;\r
-yy27:\r
-       if (yybm[0+yych] & 32) {\r
-               goto yy26;\r
-       }\r
-       goto yy10;\r
-yy28:\r
-       yych = *++p;\r
-       if (yych != 'b') goto yy27;\r
-       yych = *++p;\r
-       if (yych != 'n') goto yy27;\r
-       yych = *++p;\r
-       if (yych != 'i') goto yy27;\r
-       yych = *++p;\r
-       if (yych != 'n') goto yy27;\r
-       yych = *++p;\r
-       if (yych != 'j') goto yy27;\r
-       yych = *++p;\r
-       if (yych != 'a') goto yy27;\r
-       ++p;\r
-       if (yybm[0+(yych = *p)] & 32) {\r
-               goto yy26;\r
-       }\r
-       { token = SUBNINJA; break; }\r
-yy36:\r
-       yych = *++p;\r
-       if (yych != 'c') goto yy27;\r
-       yych = *++p;\r
-       if (yych != 'l') goto yy27;\r
-       yych = *++p;\r
-       if (yych != 'u') goto yy27;\r
-       yych = *++p;\r
-       if (yych != 'd') goto yy27;\r
-       yych = *++p;\r
-       if (yych != 'e') goto yy27;\r
-       ++p;\r
-       if (yybm[0+(yych = *p)] & 32) {\r
-               goto yy26;\r
-       }\r
-       { token = INCLUDE;  break; }\r
-yy43:\r
-       ++p;\r
-       { token = PIPE2;    break; }\r
-yy45:\r
-       yych = *++p;\r
-       if (yych != 'f') goto yy27;\r
-       yych = *++p;\r
-       if (yych != 'a') goto yy27;\r
-       yych = *++p;\r
-       if (yych != 'u') goto yy27;\r
-       yych = *++p;\r
-       if (yych != 'l') goto yy27;\r
-       yych = *++p;\r
-       if (yych != 't') goto yy27;\r
-       ++p;\r
-       if (yybm[0+(yych = *p)] & 32) {\r
-               goto yy26;\r
-       }\r
-       { token = DEFAULT;  break; }\r
-yy52:\r
-       yych = *++p;\r
-       if (yych != 'l') goto yy27;\r
-       yych = *++p;\r
-       if (yych != 'e') goto yy27;\r
-       ++p;\r
-       if (yybm[0+(yych = *p)] & 32) {\r
-               goto yy26;\r
-       }\r
-       { token = RULE;     break; }\r
-yy56:\r
-       yych = *++p;\r
-       if (yych != 'o') goto yy27;\r
-       yych = *++p;\r
-       if (yych != 'l') goto yy27;\r
-       ++p;\r
-       if (yybm[0+(yych = *p)] & 32) {\r
-               goto yy26;\r
-       }\r
-       { token = POOL;     break; }\r
-yy60:\r
-       yych = *++p;\r
-       if (yych != 'i') goto yy27;\r
-       yych = *++p;\r
-       if (yych != 'l') goto yy27;\r
-       yych = *++p;\r
-       if (yych != 'd') goto yy27;\r
-       ++p;\r
-       if (yybm[0+(yych = *p)] & 32) {\r
-               goto yy26;\r
-       }\r
-       { token = BUILD;    break; }\r
-yy65:\r
-       ++p;\r
-       { token = NEWLINE;  break; }\r
-yy67:\r
-       ++p;\r
-       yych = *p;\r
-yy68:\r
-       if (yybm[0+yych] & 64) {\r
-               goto yy67;\r
-       }\r
-       if (yych >= 0x01) goto yy70;\r
-yy69:\r
-       p = q;\r
-       if (yyaccept <= 0) {\r
-               goto yy3;\r
-       } else {\r
-               goto yy5;\r
-       }\r
-yy70:\r
-       ++p;\r
-       { continue; }\r
-yy72:\r
-       yyaccept = 0;\r
-       q = ++p;\r
-       yych = *p;\r
-yy73:\r
-       if (yybm[0+yych] & 128) {\r
-               goto yy72;\r
-       }\r
-       if (yych <= '\f') {\r
-               if (yych != '\n') goto yy3;\r
-       } else {\r
-               if (yych <= '\r') goto yy75;\r
-               if (yych == '#') goto yy67;\r
-               goto yy3;\r
-       }\r
-       yych = *++p;\r
-       goto yy8;\r
-yy75:\r
-       ++p;\r
-       if ((yych = *p) == '\n') goto yy65;\r
-       goto yy69;\r
-}\r
-\r
-  }\r
-\r
-  last_token_ = start;\r
-  ofs_ = p;\r
-  if (token != NEWLINE && token != TEOF)\r
-    EatWhitespace();\r
-  return token;\r
-}\r
-\r
-bool Lexer::PeekToken(Token token) {\r
-  Token t = ReadToken();\r
-  if (t == token)\r
-    return true;\r
-  UnreadToken();\r
-  return false;\r
-}\r
-\r
-void Lexer::EatWhitespace() {\r
-  const char* p = ofs_;\r
-  const char* q;\r
-  for (;;) {\r
-    ofs_ = p;\r
-    \r
-{\r
-       unsigned char yych;\r
-       static const unsigned char yybm[] = {\r
-                 0,   0,   0,   0,   0,   0,   0,   0, \r
-                 0,   0,   0,   0,   0,   0,   0,   0, \r
-                 0,   0,   0,   0,   0,   0,   0,   0, \r
-                 0,   0,   0,   0,   0,   0,   0,   0, \r
-               128,   0,   0,   0,   0,   0,   0,   0, \r
-                 0,   0,   0,   0,   0,   0,   0,   0, \r
-                 0,   0,   0,   0,   0,   0,   0,   0, \r
-                 0,   0,   0,   0,   0,   0,   0,   0, \r
-                 0,   0,   0,   0,   0,   0,   0,   0, \r
-                 0,   0,   0,   0,   0,   0,   0,   0, \r
-                 0,   0,   0,   0,   0,   0,   0,   0, \r
-                 0,   0,   0,   0,   0,   0,   0,   0, \r
-                 0,   0,   0,   0,   0,   0,   0,   0, \r
-                 0,   0,   0,   0,   0,   0,   0,   0, \r
-                 0,   0,   0,   0,   0,   0,   0,   0, \r
-                 0,   0,   0,   0,   0,   0,   0,   0, \r
-                 0,   0,   0,   0,   0,   0,   0,   0, \r
-                 0,   0,   0,   0,   0,   0,   0,   0, \r
-                 0,   0,   0,   0,   0,   0,   0,   0, \r
-                 0,   0,   0,   0,   0,   0,   0,   0, \r
-                 0,   0,   0,   0,   0,   0,   0,   0, \r
-                 0,   0,   0,   0,   0,   0,   0,   0, \r
-                 0,   0,   0,   0,   0,   0,   0,   0, \r
-                 0,   0,   0,   0,   0,   0,   0,   0, \r
-                 0,   0,   0,   0,   0,   0,   0,   0, \r
-                 0,   0,   0,   0,   0,   0,   0,   0, \r
-                 0,   0,   0,   0,   0,   0,   0,   0, \r
-                 0,   0,   0,   0,   0,   0,   0,   0, \r
-                 0,   0,   0,   0,   0,   0,   0,   0, \r
-                 0,   0,   0,   0,   0,   0,   0,   0, \r
-                 0,   0,   0,   0,   0,   0,   0,   0, \r
-                 0,   0,   0,   0,   0,   0,   0,   0, \r
-       };\r
-       yych = *p;\r
-       if (yych <= ' ') {\r
-               if (yych <= 0x00) goto yy82;\r
-               if (yych <= 0x1F) goto yy84;\r
-       } else {\r
-               if (yych == '$') goto yy80;\r
-               goto yy84;\r
-       }\r
-       ++p;\r
-       yych = *p;\r
-       goto yy92;\r
-yy79:\r
-       { continue; }\r
-yy80:\r
-       yych = *(q = ++p);\r
-       if (yych == '\n') goto yy85;\r
-       if (yych == '\r') goto yy87;\r
-yy81:\r
-       { break; }\r
-yy82:\r
-       ++p;\r
-       { break; }\r
-yy84:\r
-       yych = *++p;\r
-       goto yy81;\r
-yy85:\r
-       ++p;\r
-       { continue; }\r
-yy87:\r
-       yych = *++p;\r
-       if (yych == '\n') goto yy89;\r
-       p = q;\r
-       goto yy81;\r
-yy89:\r
-       ++p;\r
-       { continue; }\r
-yy91:\r
-       ++p;\r
-       yych = *p;\r
-yy92:\r
-       if (yybm[0+yych] & 128) {\r
-               goto yy91;\r
-       }\r
-       goto yy79;\r
-}\r
-\r
-  }\r
-}\r
-\r
-bool Lexer::ReadIdent(string* out) {\r
-  const char* p = ofs_;\r
-  for (;;) {\r
-    const char* start = p;\r
-    \r
-{\r
-       unsigned char yych;\r
-       static const unsigned char yybm[] = {\r
-                 0,   0,   0,   0,   0,   0,   0,   0, \r
-                 0,   0,   0,   0,   0,   0,   0,   0, \r
-                 0,   0,   0,   0,   0,   0,   0,   0, \r
-                 0,   0,   0,   0,   0,   0,   0,   0, \r
-                 0,   0,   0,   0,   0,   0,   0,   0, \r
-                 0,   0,   0,   0,   0, 128, 128,   0, \r
-               128, 128, 128, 128, 128, 128, 128, 128, \r
-               128, 128,   0,   0,   0,   0,   0,   0, \r
-                 0, 128, 128, 128, 128, 128, 128, 128, \r
-               128, 128, 128, 128, 128, 128, 128, 128, \r
-               128, 128, 128, 128, 128, 128, 128, 128, \r
-               128, 128, 128,   0,   0,   0,   0, 128, \r
-                 0, 128, 128, 128, 128, 128, 128, 128, \r
-               128, 128, 128, 128, 128, 128, 128, 128, \r
-               128, 128, 128, 128, 128, 128, 128, 128, \r
-               128, 128, 128,   0,   0,   0,   0,   0, \r
-                 0,   0,   0,   0,   0,   0,   0,   0, \r
-                 0,   0,   0,   0,   0,   0,   0,   0, \r
-                 0,   0,   0,   0,   0,   0,   0,   0, \r
-                 0,   0,   0,   0,   0,   0,   0,   0, \r
-                 0,   0,   0,   0,   0,   0,   0,   0, \r
-                 0,   0,   0,   0,   0,   0,   0,   0, \r
-                 0,   0,   0,   0,   0,   0,   0,   0, \r
-                 0,   0,   0,   0,   0,   0,   0,   0, \r
-                 0,   0,   0,   0,   0,   0,   0,   0, \r
-                 0,   0,   0,   0,   0,   0,   0,   0, \r
-                 0,   0,   0,   0,   0,   0,   0,   0, \r
-                 0,   0,   0,   0,   0,   0,   0,   0, \r
-                 0,   0,   0,   0,   0,   0,   0,   0, \r
-                 0,   0,   0,   0,   0,   0,   0,   0, \r
-                 0,   0,   0,   0,   0,   0,   0,   0, \r
-                 0,   0,   0,   0,   0,   0,   0,   0, \r
-       };\r
-       yych = *p;\r
-       if (yych <= '@') {\r
-               if (yych <= '.') {\r
-                       if (yych <= ',') goto yy97;\r
-               } else {\r
-                       if (yych <= '/') goto yy97;\r
-                       if (yych >= ':') goto yy97;\r
-               }\r
-       } else {\r
-               if (yych <= '_') {\r
-                       if (yych <= 'Z') goto yy95;\r
-                       if (yych <= '^') goto yy97;\r
-               } else {\r
-                       if (yych <= '`') goto yy97;\r
-                       if (yych >= '{') goto yy97;\r
-               }\r
-       }\r
-yy95:\r
-       ++p;\r
-       yych = *p;\r
-       goto yy100;\r
-yy96:\r
-       {\r
-      out->assign(start, p - start);\r
-      break;\r
-    }\r
-yy97:\r
-       ++p;\r
-       { return false; }\r
-yy99:\r
-       ++p;\r
-       yych = *p;\r
-yy100:\r
-       if (yybm[0+yych] & 128) {\r
-               goto yy99;\r
-       }\r
-       goto yy96;\r
-}\r
-\r
-  }\r
-  ofs_ = p;\r
-  EatWhitespace();\r
-  return true;\r
-}\r
-\r
-bool Lexer::ReadEvalString(EvalString* eval, bool path, string* err) {\r
-  const char* p = ofs_;\r
-  const char* q;\r
-  const char* start;\r
-  for (;;) {\r
-    start = p;\r
-    \r
-{\r
-       unsigned char yych;\r
-       static const unsigned char yybm[] = {\r
-                 0, 128, 128, 128, 128, 128, 128, 128, \r
-               128, 128,   0, 128, 128,   0, 128, 128, \r
-               128, 128, 128, 128, 128, 128, 128, 128, \r
-               128, 128, 128, 128, 128, 128, 128, 128, \r
-                16, 128, 128, 128,   0, 128, 128, 128, \r
-               128, 128, 128, 128, 128, 224, 160, 128, \r
-               224, 224, 224, 224, 224, 224, 224, 224, \r
-               224, 224,   0, 128, 128, 128, 128, 128, \r
-               128, 224, 224, 224, 224, 224, 224, 224, \r
-               224, 224, 224, 224, 224, 224, 224, 224, \r
-               224, 224, 224, 224, 224, 224, 224, 224, \r
-               224, 224, 224, 128, 128, 128, 128, 224, \r
-               128, 224, 224, 224, 224, 224, 224, 224, \r
-               224, 224, 224, 224, 224, 224, 224, 224, \r
-               224, 224, 224, 224, 224, 224, 224, 224, \r
-               224, 224, 224, 128,   0, 128, 128, 128, \r
-               128, 128, 128, 128, 128, 128, 128, 128, \r
-               128, 128, 128, 128, 128, 128, 128, 128, \r
-               128, 128, 128, 128, 128, 128, 128, 128, \r
-               128, 128, 128, 128, 128, 128, 128, 128, \r
-               128, 128, 128, 128, 128, 128, 128, 128, \r
-               128, 128, 128, 128, 128, 128, 128, 128, \r
-               128, 128, 128, 128, 128, 128, 128, 128, \r
-               128, 128, 128, 128, 128, 128, 128, 128, \r
-               128, 128, 128, 128, 128, 128, 128, 128, \r
-               128, 128, 128, 128, 128, 128, 128, 128, \r
-               128, 128, 128, 128, 128, 128, 128, 128, \r
-               128, 128, 128, 128, 128, 128, 128, 128, \r
-               128, 128, 128, 128, 128, 128, 128, 128, \r
-               128, 128, 128, 128, 128, 128, 128, 128, \r
-               128, 128, 128, 128, 128, 128, 128, 128, \r
-               128, 128, 128, 128, 128, 128, 128, 128, \r
-       };\r
-       yych = *p;\r
-       if (yych <= ' ') {\r
-               if (yych <= '\n') {\r
-                       if (yych <= 0x00) goto yy110;\r
-                       if (yych >= '\n') goto yy107;\r
-               } else {\r
-                       if (yych == '\r') goto yy105;\r
-                       if (yych >= ' ') goto yy107;\r
-               }\r
-       } else {\r
-               if (yych <= '9') {\r
-                       if (yych == '$') goto yy109;\r
-               } else {\r
-                       if (yych <= ':') goto yy107;\r
-                       if (yych == '|') goto yy107;\r
-               }\r
-       }\r
-       ++p;\r
-       yych = *p;\r
-       goto yy140;\r
-yy104:\r
-       {\r
-      eval->AddText(StringPiece(start, p - start));\r
-      continue;\r
-    }\r
-yy105:\r
-       ++p;\r
-       if ((yych = *p) == '\n') goto yy137;\r
-       {\r
-      last_token_ = start;\r
-      return Error(DescribeLastError(), err);\r
-    }\r
-yy107:\r
-       ++p;\r
-       {\r
-      if (path) {\r
-        p = start;\r
-        break;\r
-      } else {\r
-        if (*start == '\n')\r
-          break;\r
-        eval->AddText(StringPiece(start, 1));\r
-        continue;\r
-      }\r
-    }\r
-yy109:\r
-       yych = *++p;\r
-       if (yych <= '-') {\r
-               if (yych <= 0x1F) {\r
-                       if (yych <= '\n') {\r
-                               if (yych <= '\t') goto yy112;\r
-                               goto yy124;\r
-                       } else {\r
-                               if (yych == '\r') goto yy114;\r
-                               goto yy112;\r
-                       }\r
-               } else {\r
-                       if (yych <= '#') {\r
-                               if (yych <= ' ') goto yy115;\r
-                               goto yy112;\r
-                       } else {\r
-                               if (yych <= '$') goto yy117;\r
-                               if (yych <= ',') goto yy112;\r
-                               goto yy119;\r
-                       }\r
-               }\r
-       } else {\r
-               if (yych <= 'Z') {\r
-                       if (yych <= '9') {\r
-                               if (yych <= '/') goto yy112;\r
-                               goto yy119;\r
-                       } else {\r
-                               if (yych <= ':') goto yy121;\r
-                               if (yych <= '@') goto yy112;\r
-                               goto yy119;\r
-                       }\r
-               } else {\r
-                       if (yych <= '`') {\r
-                               if (yych == '_') goto yy119;\r
-                               goto yy112;\r
-                       } else {\r
-                               if (yych <= 'z') goto yy119;\r
-                               if (yych <= '{') goto yy123;\r
-                               goto yy112;\r
-                       }\r
-               }\r
-       }\r
-yy110:\r
-       ++p;\r
-       {\r
-      last_token_ = start;\r
-      return Error("unexpected EOF", err);\r
-    }\r
-yy112:\r
-       ++p;\r
-yy113:\r
-       {\r
-      last_token_ = start;\r
-      return Error("bad $-escape (literal $ must be written as $$)", err);\r
-    }\r
-yy114:\r
-       yych = *++p;\r
-       if (yych == '\n') goto yy134;\r
-       goto yy113;\r
-yy115:\r
-       ++p;\r
-       {\r
-      eval->AddText(StringPiece(" ", 1));\r
-      continue;\r
-    }\r
-yy117:\r
-       ++p;\r
-       {\r
-      eval->AddText(StringPiece("$", 1));\r
-      continue;\r
-    }\r
-yy119:\r
-       ++p;\r
-       yych = *p;\r
-       goto yy133;\r
-yy120:\r
-       {\r
-      eval->AddSpecial(StringPiece(start + 1, p - start - 1));\r
-      continue;\r
-    }\r
-yy121:\r
-       ++p;\r
-       {\r
-      eval->AddText(StringPiece(":", 1));\r
-      continue;\r
-    }\r
-yy123:\r
-       yych = *(q = ++p);\r
-       if (yybm[0+yych] & 32) {\r
-               goto yy127;\r
-       }\r
-       goto yy113;\r
-yy124:\r
-       ++p;\r
-       yych = *p;\r
-       if (yybm[0+yych] & 16) {\r
-               goto yy124;\r
-       }\r
-       {\r
-      continue;\r
-    }\r
-yy127:\r
-       ++p;\r
-       yych = *p;\r
-       if (yybm[0+yych] & 32) {\r
-               goto yy127;\r
-       }\r
-       if (yych == '}') goto yy130;\r
-       p = q;\r
-       goto yy113;\r
-yy130:\r
-       ++p;\r
-       {\r
-      eval->AddSpecial(StringPiece(start + 2, p - start - 3));\r
-      continue;\r
-    }\r
-yy132:\r
-       ++p;\r
-       yych = *p;\r
-yy133:\r
-       if (yybm[0+yych] & 64) {\r
-               goto yy132;\r
-       }\r
-       goto yy120;\r
-yy134:\r
-       ++p;\r
-       yych = *p;\r
-       if (yych == ' ') goto yy134;\r
-       {\r
-      continue;\r
-    }\r
-yy137:\r
-       ++p;\r
-       {\r
-      if (path)\r
-        p = start;\r
-      break;\r
-    }\r
-yy139:\r
-       ++p;\r
-       yych = *p;\r
-yy140:\r
-       if (yybm[0+yych] & 128) {\r
-               goto yy139;\r
-       }\r
-       goto yy104;\r
-}\r
-\r
-  }\r
-  last_token_ = start;\r
-  ofs_ = p;\r
-  if (path)\r
-    EatWhitespace();\r
-  // Non-path strings end in newlines, so there's no whitespace to eat.\r
-  return true;\r
-}\r
+/* Generated by re2c 0.13.5 */
+// Copyright 2011 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "lexer.h"
+
+#include <stdio.h>
+
+#include "eval_env.h"
+#include "util.h"
+
+bool Lexer::Error(const string& message, string* err) {
+  // Compute line/column.
+  int line = 1;
+  const char* context = input_.str_;
+  for (const char* p = input_.str_; p < last_token_; ++p) {
+    if (*p == '\n') {
+      ++line;
+      context = p + 1;
+    }
+  }
+  int col = last_token_ ? (int)(last_token_ - context) : 0;
+
+  char buf[1024];
+  snprintf(buf, sizeof(buf), "%s:%d: ", filename_.AsString().c_str(), line);
+  *err = buf;
+  *err += message + "\n";
+
+  // Add some context to the message.
+  const int kTruncateColumn = 72;
+  if (col > 0 && col < kTruncateColumn) {
+    int len;
+    bool truncated = true;
+    for (len = 0; len < kTruncateColumn; ++len) {
+      if (context[len] == 0 || context[len] == '\n') {
+        truncated = false;
+        break;
+      }
+    }
+    *err += string(context, len);
+    if (truncated)
+      *err += "...";
+    *err += "\n";
+    *err += string(col, ' ');
+    *err += "^ near here";
+  }
+
+  return false;
+}
+
+Lexer::Lexer(const char* input) {
+  Start("input", input);
+}
+
+void Lexer::Start(StringPiece filename, StringPiece input) {
+  filename_ = filename;
+  input_ = input;
+  ofs_ = input_.str_;
+  last_token_ = NULL;
+}
+
+const char* Lexer::TokenName(Token t) {
+  switch (t) {
+  case ERROR:    return "lexing error";
+  case BUILD:    return "'build'";
+  case COLON:    return "':'";
+  case DEFAULT:  return "'default'";
+  case EQUALS:   return "'='";
+  case IDENT:    return "identifier";
+  case INCLUDE:  return "'include'";
+  case INDENT:   return "indent";
+  case NEWLINE:  return "newline";
+  case PIPE2:    return "'||'";
+  case PIPE:     return "'|'";
+  case POOL:     return "'pool'";
+  case RULE:     return "'rule'";
+  case SUBNINJA: return "'subninja'";
+  case TEOF:     return "eof";
+  }
+  return NULL;  // not reached
+}
+
+const char* Lexer::TokenErrorHint(Token expected) {
+  switch (expected) {
+  case COLON:
+    return " ($ also escapes ':')";
+  default:
+    return "";
+  }
+}
+
+string Lexer::DescribeLastError() {
+  if (last_token_) {
+    switch (last_token_[0]) {
+    case '\t':
+      return "tabs are not allowed, use spaces";
+    }
+  }
+  return "lexing error";
+}
+
+void Lexer::UnreadToken() {
+  ofs_ = last_token_;
+}
+
+Lexer::Token Lexer::ReadToken() {
+  const char* p = ofs_;
+  const char* q;
+  const char* start;
+  Lexer::Token token;
+  for (;;) {
+    start = p;
+    
+{
+       unsigned char yych;
+       unsigned int yyaccept = 0;
+       static const unsigned char yybm[] = {
+                 0,  64,  64,  64,  64,  64,  64,  64, 
+                64,  64,   0,  64,  64,  64,  64,  64, 
+                64,  64,  64,  64,  64,  64,  64,  64, 
+                64,  64,  64,  64,  64,  64,  64,  64, 
+               192,  64,  64,  64,  64,  64,  64,  64, 
+                64,  64,  64,  64,  64,  96,  96,  64, 
+                96,  96,  96,  96,  96,  96,  96,  96, 
+                96,  96,  64,  64,  64,  64,  64,  64, 
+                64,  96,  96,  96,  96,  96,  96,  96, 
+                96,  96,  96,  96,  96,  96,  96,  96, 
+                96,  96,  96,  96,  96,  96,  96,  96, 
+                96,  96,  96,  64,  64,  64,  64,  96, 
+                64,  96,  96,  96,  96,  96,  96,  96, 
+                96,  96,  96,  96,  96,  96,  96,  96, 
+                96,  96,  96,  96,  96,  96,  96,  96, 
+                96,  96,  96,  64,  64,  64,  64,  64, 
+                64,  64,  64,  64,  64,  64,  64,  64, 
+                64,  64,  64,  64,  64,  64,  64,  64, 
+                64,  64,  64,  64,  64,  64,  64,  64, 
+                64,  64,  64,  64,  64,  64,  64,  64, 
+                64,  64,  64,  64,  64,  64,  64,  64, 
+                64,  64,  64,  64,  64,  64,  64,  64, 
+                64,  64,  64,  64,  64,  64,  64,  64, 
+                64,  64,  64,  64,  64,  64,  64,  64, 
+                64,  64,  64,  64,  64,  64,  64,  64, 
+                64,  64,  64,  64,  64,  64,  64,  64, 
+                64,  64,  64,  64,  64,  64,  64,  64, 
+                64,  64,  64,  64,  64,  64,  64,  64, 
+                64,  64,  64,  64,  64,  64,  64,  64, 
+                64,  64,  64,  64,  64,  64,  64,  64, 
+                64,  64,  64,  64,  64,  64,  64,  64, 
+                64,  64,  64,  64,  64,  64,  64,  64, 
+       };
+
+       yych = *p;
+       if (yych <= 'Z') {
+               if (yych <= '#') {
+                       if (yych <= '\f') {
+                               if (yych <= 0x00) goto yy23;
+                               if (yych == '\n') goto yy7;
+                               goto yy25;
+                       } else {
+                               if (yych <= 0x1F) {
+                                       if (yych <= '\r') goto yy6;
+                                       goto yy25;
+                               } else {
+                                       if (yych <= ' ') goto yy2;
+                                       if (yych <= '"') goto yy25;
+                                       goto yy4;
+                               }
+                       }
+               } else {
+                       if (yych <= '9') {
+                               if (yych <= ',') goto yy25;
+                               if (yych == '/') goto yy25;
+                               goto yy22;
+                       } else {
+                               if (yych <= '<') {
+                                       if (yych <= ':') goto yy16;
+                                       goto yy25;
+                               } else {
+                                       if (yych <= '=') goto yy14;
+                                       if (yych <= '@') goto yy25;
+                                       goto yy22;
+                               }
+                       }
+               }
+       } else {
+               if (yych <= 'i') {
+                       if (yych <= 'a') {
+                               if (yych == '_') goto yy22;
+                               if (yych <= '`') goto yy25;
+                               goto yy22;
+                       } else {
+                               if (yych <= 'c') {
+                                       if (yych <= 'b') goto yy9;
+                                       goto yy22;
+                               } else {
+                                       if (yych <= 'd') goto yy13;
+                                       if (yych <= 'h') goto yy22;
+                                       goto yy20;
+                               }
+                       }
+               } else {
+                       if (yych <= 'r') {
+                               if (yych == 'p') goto yy11;
+                               if (yych <= 'q') goto yy22;
+                               goto yy12;
+                       } else {
+                               if (yych <= 'z') {
+                                       if (yych <= 's') goto yy21;
+                                       goto yy22;
+                               } else {
+                                       if (yych == '|') goto yy18;
+                                       goto yy25;
+                               }
+                       }
+               }
+       }
+yy2:
+       yyaccept = 0;
+       yych = *(q = ++p);
+       goto yy73;
+yy3:
+       { token = INDENT;   break; }
+yy4:
+       yyaccept = 1;
+       yych = *(q = ++p);
+       if (yych >= 0x01) goto yy68;
+yy5:
+       { token = ERROR;    break; }
+yy6:
+       yych = *++p;
+       if (yych == '\n') goto yy65;
+       goto yy5;
+yy7:
+       ++p;
+yy8:
+       { token = NEWLINE;  break; }
+yy9:
+       ++p;
+       if ((yych = *p) == 'u') goto yy60;
+       goto yy27;
+yy10:
+       { token = IDENT;    break; }
+yy11:
+       yych = *++p;
+       if (yych == 'o') goto yy56;
+       goto yy27;
+yy12:
+       yych = *++p;
+       if (yych == 'u') goto yy52;
+       goto yy27;
+yy13:
+       yych = *++p;
+       if (yych == 'e') goto yy45;
+       goto yy27;
+yy14:
+       ++p;
+       { token = EQUALS;   break; }
+yy16:
+       ++p;
+       { token = COLON;    break; }
+yy18:
+       ++p;
+       if ((yych = *p) == '|') goto yy43;
+       { token = PIPE;     break; }
+yy20:
+       yych = *++p;
+       if (yych == 'n') goto yy36;
+       goto yy27;
+yy21:
+       yych = *++p;
+       if (yych == 'u') goto yy28;
+       goto yy27;
+yy22:
+       yych = *++p;
+       goto yy27;
+yy23:
+       ++p;
+       { token = TEOF;     break; }
+yy25:
+       yych = *++p;
+       goto yy5;
+yy26:
+       ++p;
+       yych = *p;
+yy27:
+       if (yybm[0+yych] & 32) {
+               goto yy26;
+       }
+       goto yy10;
+yy28:
+       yych = *++p;
+       if (yych != 'b') goto yy27;
+       yych = *++p;
+       if (yych != 'n') goto yy27;
+       yych = *++p;
+       if (yych != 'i') goto yy27;
+       yych = *++p;
+       if (yych != 'n') goto yy27;
+       yych = *++p;
+       if (yych != 'j') goto yy27;
+       yych = *++p;
+       if (yych != 'a') goto yy27;
+       ++p;
+       if (yybm[0+(yych = *p)] & 32) {
+               goto yy26;
+       }
+       { token = SUBNINJA; break; }
+yy36:
+       yych = *++p;
+       if (yych != 'c') goto yy27;
+       yych = *++p;
+       if (yych != 'l') goto yy27;
+       yych = *++p;
+       if (yych != 'u') goto yy27;
+       yych = *++p;
+       if (yych != 'd') goto yy27;
+       yych = *++p;
+       if (yych != 'e') goto yy27;
+       ++p;
+       if (yybm[0+(yych = *p)] & 32) {
+               goto yy26;
+       }
+       { token = INCLUDE;  break; }
+yy43:
+       ++p;
+       { token = PIPE2;    break; }
+yy45:
+       yych = *++p;
+       if (yych != 'f') goto yy27;
+       yych = *++p;
+       if (yych != 'a') goto yy27;
+       yych = *++p;
+       if (yych != 'u') goto yy27;
+       yych = *++p;
+       if (yych != 'l') goto yy27;
+       yych = *++p;
+       if (yych != 't') goto yy27;
+       ++p;
+       if (yybm[0+(yych = *p)] & 32) {
+               goto yy26;
+       }
+       { token = DEFAULT;  break; }
+yy52:
+       yych = *++p;
+       if (yych != 'l') goto yy27;
+       yych = *++p;
+       if (yych != 'e') goto yy27;
+       ++p;
+       if (yybm[0+(yych = *p)] & 32) {
+               goto yy26;
+       }
+       { token = RULE;     break; }
+yy56:
+       yych = *++p;
+       if (yych != 'o') goto yy27;
+       yych = *++p;
+       if (yych != 'l') goto yy27;
+       ++p;
+       if (yybm[0+(yych = *p)] & 32) {
+               goto yy26;
+       }
+       { token = POOL;     break; }
+yy60:
+       yych = *++p;
+       if (yych != 'i') goto yy27;
+       yych = *++p;
+       if (yych != 'l') goto yy27;
+       yych = *++p;
+       if (yych != 'd') goto yy27;
+       ++p;
+       if (yybm[0+(yych = *p)] & 32) {
+               goto yy26;
+       }
+       { token = BUILD;    break; }
+yy65:
+       ++p;
+       { token = NEWLINE;  break; }
+yy67:
+       ++p;
+       yych = *p;
+yy68:
+       if (yybm[0+yych] & 64) {
+               goto yy67;
+       }
+       if (yych >= 0x01) goto yy70;
+yy69:
+       p = q;
+       if (yyaccept <= 0) {
+               goto yy3;
+       } else {
+               goto yy5;
+       }
+yy70:
+       ++p;
+       { continue; }
+yy72:
+       yyaccept = 0;
+       q = ++p;
+       yych = *p;
+yy73:
+       if (yybm[0+yych] & 128) {
+               goto yy72;
+       }
+       if (yych <= '\f') {
+               if (yych != '\n') goto yy3;
+       } else {
+               if (yych <= '\r') goto yy75;
+               if (yych == '#') goto yy67;
+               goto yy3;
+       }
+       yych = *++p;
+       goto yy8;
+yy75:
+       ++p;
+       if ((yych = *p) == '\n') goto yy65;
+       goto yy69;
+}
+
+  }
+
+  last_token_ = start;
+  ofs_ = p;
+  if (token != NEWLINE && token != TEOF)
+    EatWhitespace();
+  return token;
+}
+
+bool Lexer::PeekToken(Token token) {
+  Token t = ReadToken();
+  if (t == token)
+    return true;
+  UnreadToken();
+  return false;
+}
+
+void Lexer::EatWhitespace() {
+  const char* p = ofs_;
+  const char* q;
+  for (;;) {
+    ofs_ = p;
+    
+{
+       unsigned char yych;
+       static const unsigned char yybm[] = {
+                 0,   0,   0,   0,   0,   0,   0,   0, 
+                 0,   0,   0,   0,   0,   0,   0,   0, 
+                 0,   0,   0,   0,   0,   0,   0,   0, 
+                 0,   0,   0,   0,   0,   0,   0,   0, 
+               128,   0,   0,   0,   0,   0,   0,   0, 
+                 0,   0,   0,   0,   0,   0,   0,   0, 
+                 0,   0,   0,   0,   0,   0,   0,   0, 
+                 0,   0,   0,   0,   0,   0,   0,   0, 
+                 0,   0,   0,   0,   0,   0,   0,   0, 
+                 0,   0,   0,   0,   0,   0,   0,   0, 
+                 0,   0,   0,   0,   0,   0,   0,   0, 
+                 0,   0,   0,   0,   0,   0,   0,   0, 
+                 0,   0,   0,   0,   0,   0,   0,   0, 
+                 0,   0,   0,   0,   0,   0,   0,   0, 
+                 0,   0,   0,   0,   0,   0,   0,   0, 
+                 0,   0,   0,   0,   0,   0,   0,   0, 
+                 0,   0,   0,   0,   0,   0,   0,   0, 
+                 0,   0,   0,   0,   0,   0,   0,   0, 
+                 0,   0,   0,   0,   0,   0,   0,   0, 
+                 0,   0,   0,   0,   0,   0,   0,   0, 
+                 0,   0,   0,   0,   0,   0,   0,   0, 
+                 0,   0,   0,   0,   0,   0,   0,   0, 
+                 0,   0,   0,   0,   0,   0,   0,   0, 
+                 0,   0,   0,   0,   0,   0,   0,   0, 
+                 0,   0,   0,   0,   0,   0,   0,   0, 
+                 0,   0,   0,   0,   0,   0,   0,   0, 
+                 0,   0,   0,   0,   0,   0,   0,   0, 
+                 0,   0,   0,   0,   0,   0,   0,   0, 
+                 0,   0,   0,   0,   0,   0,   0,   0, 
+                 0,   0,   0,   0,   0,   0,   0,   0, 
+                 0,   0,   0,   0,   0,   0,   0,   0, 
+                 0,   0,   0,   0,   0,   0,   0,   0, 
+       };
+       yych = *p;
+       if (yych <= ' ') {
+               if (yych <= 0x00) goto yy82;
+               if (yych <= 0x1F) goto yy84;
+       } else {
+               if (yych == '$') goto yy80;
+               goto yy84;
+       }
+       ++p;
+       yych = *p;
+       goto yy92;
+yy79:
+       { continue; }
+yy80:
+       yych = *(q = ++p);
+       if (yych == '\n') goto yy85;
+       if (yych == '\r') goto yy87;
+yy81:
+       { break; }
+yy82:
+       ++p;
+       { break; }
+yy84:
+       yych = *++p;
+       goto yy81;
+yy85:
+       ++p;
+       { continue; }
+yy87:
+       yych = *++p;
+       if (yych == '\n') goto yy89;
+       p = q;
+       goto yy81;
+yy89:
+       ++p;
+       { continue; }
+yy91:
+       ++p;
+       yych = *p;
+yy92:
+       if (yybm[0+yych] & 128) {
+               goto yy91;
+       }
+       goto yy79;
+}
+
+  }
+}
+
+bool Lexer::ReadIdent(string* out) {
+  const char* p = ofs_;
+  for (;;) {
+    const char* start = p;
+    
+{
+       unsigned char yych;
+       static const unsigned char yybm[] = {
+                 0,   0,   0,   0,   0,   0,   0,   0, 
+                 0,   0,   0,   0,   0,   0,   0,   0, 
+                 0,   0,   0,   0,   0,   0,   0,   0, 
+                 0,   0,   0,   0,   0,   0,   0,   0, 
+                 0,   0,   0,   0,   0,   0,   0,   0, 
+                 0,   0,   0,   0,   0, 128, 128,   0, 
+               128, 128, 128, 128, 128, 128, 128, 128, 
+               128, 128,   0,   0,   0,   0,   0,   0, 
+                 0, 128, 128, 128, 128, 128, 128, 128, 
+               128, 128, 128, 128, 128, 128, 128, 128, 
+               128, 128, 128, 128, 128, 128, 128, 128, 
+               128, 128, 128,   0,   0,   0,   0, 128, 
+                 0, 128, 128, 128, 128, 128, 128, 128, 
+               128, 128, 128, 128, 128, 128, 128, 128, 
+               128, 128, 128, 128, 128, 128, 128, 128, 
+               128, 128, 128,   0,   0,   0,   0,   0, 
+                 0,   0,   0,   0,   0,   0,   0,   0, 
+                 0,   0,   0,   0,   0,   0,   0,   0, 
+                 0,   0,   0,   0,   0,   0,   0,   0, 
+                 0,   0,   0,   0,   0,   0,   0,   0, 
+                 0,   0,   0,   0,   0,   0,   0,   0, 
+                 0,   0,   0,   0,   0,   0,   0,   0, 
+                 0,   0,   0,   0,   0,   0,   0,   0, 
+                 0,   0,   0,   0,   0,   0,   0,   0, 
+                 0,   0,   0,   0,   0,   0,   0,   0, 
+                 0,   0,   0,   0,   0,   0,   0,   0, 
+                 0,   0,   0,   0,   0,   0,   0,   0, 
+                 0,   0,   0,   0,   0,   0,   0,   0, 
+                 0,   0,   0,   0,   0,   0,   0,   0, 
+                 0,   0,   0,   0,   0,   0,   0,   0, 
+                 0,   0,   0,   0,   0,   0,   0,   0, 
+                 0,   0,   0,   0,   0,   0,   0,   0, 
+       };
+       yych = *p;
+       if (yych <= '@') {
+               if (yych <= '.') {
+                       if (yych <= ',') goto yy97;
+               } else {
+                       if (yych <= '/') goto yy97;
+                       if (yych >= ':') goto yy97;
+               }
+       } else {
+               if (yych <= '_') {
+                       if (yych <= 'Z') goto yy95;
+                       if (yych <= '^') goto yy97;
+               } else {
+                       if (yych <= '`') goto yy97;
+                       if (yych >= '{') goto yy97;
+               }
+       }
+yy95:
+       ++p;
+       yych = *p;
+       goto yy100;
+yy96:
+       {
+      out->assign(start, p - start);
+      break;
+    }
+yy97:
+       ++p;
+       { return false; }
+yy99:
+       ++p;
+       yych = *p;
+yy100:
+       if (yybm[0+yych] & 128) {
+               goto yy99;
+       }
+       goto yy96;
+}
+
+  }
+  ofs_ = p;
+  EatWhitespace();
+  return true;
+}
+
+bool Lexer::ReadEvalString(EvalString* eval, bool path, string* err) {
+  const char* p = ofs_;
+  const char* q;
+  const char* start;
+  for (;;) {
+    start = p;
+    
+{
+       unsigned char yych;
+       static const unsigned char yybm[] = {
+                 0, 128, 128, 128, 128, 128, 128, 128, 
+               128, 128,   0, 128, 128,   0, 128, 128, 
+               128, 128, 128, 128, 128, 128, 128, 128, 
+               128, 128, 128, 128, 128, 128, 128, 128, 
+                16, 128, 128, 128,   0, 128, 128, 128, 
+               128, 128, 128, 128, 128, 224, 160, 128, 
+               224, 224, 224, 224, 224, 224, 224, 224, 
+               224, 224,   0, 128, 128, 128, 128, 128, 
+               128, 224, 224, 224, 224, 224, 224, 224, 
+               224, 224, 224, 224, 224, 224, 224, 224, 
+               224, 224, 224, 224, 224, 224, 224, 224, 
+               224, 224, 224, 128, 128, 128, 128, 224, 
+               128, 224, 224, 224, 224, 224, 224, 224, 
+               224, 224, 224, 224, 224, 224, 224, 224, 
+               224, 224, 224, 224, 224, 224, 224, 224, 
+               224, 224, 224, 128,   0, 128, 128, 128, 
+               128, 128, 128, 128, 128, 128, 128, 128, 
+               128, 128, 128, 128, 128, 128, 128, 128, 
+               128, 128, 128, 128, 128, 128, 128, 128, 
+               128, 128, 128, 128, 128, 128, 128, 128, 
+               128, 128, 128, 128, 128, 128, 128, 128, 
+               128, 128, 128, 128, 128, 128, 128, 128, 
+               128, 128, 128, 128, 128, 128, 128, 128, 
+               128, 128, 128, 128, 128, 128, 128, 128, 
+               128, 128, 128, 128, 128, 128, 128, 128, 
+               128, 128, 128, 128, 128, 128, 128, 128, 
+               128, 128, 128, 128, 128, 128, 128, 128, 
+               128, 128, 128, 128, 128, 128, 128, 128, 
+               128, 128, 128, 128, 128, 128, 128, 128, 
+               128, 128, 128, 128, 128, 128, 128, 128, 
+               128, 128, 128, 128, 128, 128, 128, 128, 
+               128, 128, 128, 128, 128, 128, 128, 128, 
+       };
+       yych = *p;
+       if (yych <= ' ') {
+               if (yych <= '\n') {
+                       if (yych <= 0x00) goto yy110;
+                       if (yych >= '\n') goto yy107;
+               } else {
+                       if (yych == '\r') goto yy105;
+                       if (yych >= ' ') goto yy107;
+               }
+       } else {
+               if (yych <= '9') {
+                       if (yych == '$') goto yy109;
+               } else {
+                       if (yych <= ':') goto yy107;
+                       if (yych == '|') goto yy107;
+               }
+       }
+       ++p;
+       yych = *p;
+       goto yy140;
+yy104:
+       {
+      eval->AddText(StringPiece(start, p - start));
+      continue;
+    }
+yy105:
+       ++p;
+       if ((yych = *p) == '\n') goto yy137;
+       {
+      last_token_ = start;
+      return Error(DescribeLastError(), err);
+    }
+yy107:
+       ++p;
+       {
+      if (path) {
+        p = start;
+        break;
+      } else {
+        if (*start == '\n')
+          break;
+        eval->AddText(StringPiece(start, 1));
+        continue;
+      }
+    }
+yy109:
+       yych = *++p;
+       if (yych <= '-') {
+               if (yych <= 0x1F) {
+                       if (yych <= '\n') {
+                               if (yych <= '\t') goto yy112;
+                               goto yy124;
+                       } else {
+                               if (yych == '\r') goto yy114;
+                               goto yy112;
+                       }
+               } else {
+                       if (yych <= '#') {
+                               if (yych <= ' ') goto yy115;
+                               goto yy112;
+                       } else {
+                               if (yych <= '$') goto yy117;
+                               if (yych <= ',') goto yy112;
+                               goto yy119;
+                       }
+               }
+       } else {
+               if (yych <= 'Z') {
+                       if (yych <= '9') {
+                               if (yych <= '/') goto yy112;
+                               goto yy119;
+                       } else {
+                               if (yych <= ':') goto yy121;
+                               if (yych <= '@') goto yy112;
+                               goto yy119;
+                       }
+               } else {
+                       if (yych <= '`') {
+                               if (yych == '_') goto yy119;
+                               goto yy112;
+                       } else {
+                               if (yych <= 'z') goto yy119;
+                               if (yych <= '{') goto yy123;
+                               goto yy112;
+                       }
+               }
+       }
+yy110:
+       ++p;
+       {
+      last_token_ = start;
+      return Error("unexpected EOF", err);
+    }
+yy112:
+       ++p;
+yy113:
+       {
+      last_token_ = start;
+      return Error("bad $-escape (literal $ must be written as $$)", err);
+    }
+yy114:
+       yych = *++p;
+       if (yych == '\n') goto yy134;
+       goto yy113;
+yy115:
+       ++p;
+       {
+      eval->AddText(StringPiece(" ", 1));
+      continue;
+    }
+yy117:
+       ++p;
+       {
+      eval->AddText(StringPiece("$", 1));
+      continue;
+    }
+yy119:
+       ++p;
+       yych = *p;
+       goto yy133;
+yy120:
+       {
+      eval->AddSpecial(StringPiece(start + 1, p - start - 1));
+      continue;
+    }
+yy121:
+       ++p;
+       {
+      eval->AddText(StringPiece(":", 1));
+      continue;
+    }
+yy123:
+       yych = *(q = ++p);
+       if (yybm[0+yych] & 32) {
+               goto yy127;
+       }
+       goto yy113;
+yy124:
+       ++p;
+       yych = *p;
+       if (yybm[0+yych] & 16) {
+               goto yy124;
+       }
+       {
+      continue;
+    }
+yy127:
+       ++p;
+       yych = *p;
+       if (yybm[0+yych] & 32) {
+               goto yy127;
+       }
+       if (yych == '}') goto yy130;
+       p = q;
+       goto yy113;
+yy130:
+       ++p;
+       {
+      eval->AddSpecial(StringPiece(start + 2, p - start - 3));
+      continue;
+    }
+yy132:
+       ++p;
+       yych = *p;
+yy133:
+       if (yybm[0+yych] & 64) {
+               goto yy132;
+       }
+       goto yy120;
+yy134:
+       ++p;
+       yych = *p;
+       if (yych == ' ') goto yy134;
+       {
+      continue;
+    }
+yy137:
+       ++p;
+       {
+      if (path)
+        p = start;
+      break;
+    }
+yy139:
+       ++p;
+       yych = *p;
+yy140:
+       if (yybm[0+yych] & 128) {
+               goto yy139;
+       }
+       goto yy104;
+}
+
+  }
+  last_token_ = start;
+  ofs_ = p;
+  if (path)
+    EatWhitespace();
+  // Non-path strings end in newlines, so there's no whitespace to eat.
+  return true;
+}