Ninja
depfile_parser.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 "depfile_parser.h"
00017 
00018 // A note on backslashes in Makefiles, from reading the docs:
00019 // Backslash-newline is the line continuation character.
00020 // Backslash-# escapes a # (otherwise meaningful as a comment start).
00021 // Backslash-% escapes a % (otherwise meaningful as a special).
00022 // Finally, quoting the GNU manual, "Backslashes that are not in danger
00023 // of quoting ‘%’ characters go unmolested."
00024 // How do you end a line with a backslash?  The netbsd Make docs suggest
00025 // reading the result of a shell command echoing a backslash!
00026 //
00027 // Rather than implement all of above, we do a simpler thing here:
00028 // Backslashes escape a set of characters (see "escapes" defined below),
00029 // otherwise they are passed through verbatim.
00030 // If anyone actually has depfiles that rely on the more complicated
00031 // behavior we can adjust this.
00032 bool DepfileParser::Parse(string* content, string* err) {
00033   // in: current parser input point.
00034   // end: end of input.
00035   // parsing_targets: whether we are parsing targets or dependencies.
00036   char* in = &(*content)[0];
00037   char* end = in + content->size();
00038   bool parsing_targets = true;
00039   while (in < end) {
00040     // out: current output point (typically same as in, but can fall behind
00041     // as we de-escape backslashes).
00042     char* out = in;
00043     // filename: start of the current parsed filename.
00044     char* filename = out;
00045     for (;;) {
00046       // start: beginning of the current parsed span.
00047       const char* start = in;
00048       
00049     {
00050       char yych;
00051       static const unsigned char yybm[] = {
00052           0,   0,   0,   0,   0,   0,   0,   0, 
00053           0,   0,   0,   0,   0,   0,   0,   0, 
00054           0,   0,   0,   0,   0,   0,   0,   0, 
00055           0,   0,   0,   0,   0,   0,   0,   0, 
00056           0, 128, 128, 128, 128, 128, 128, 128, 
00057         128, 128, 128, 128, 128, 128, 128, 128, 
00058         128, 128, 128, 128, 128, 128, 128, 128, 
00059         128, 128, 128, 128, 128, 128,   0,   0, 
00060         128, 128, 128, 128, 128, 128, 128, 128, 
00061         128, 128, 128, 128, 128, 128, 128, 128, 
00062         128, 128, 128, 128, 128, 128, 128, 128, 
00063         128, 128, 128,   0,   0,   0,   0, 128, 
00064           0, 128, 128, 128, 128, 128, 128, 128, 
00065         128, 128, 128, 128, 128, 128, 128, 128, 
00066         128, 128, 128, 128, 128, 128, 128, 128, 
00067         128, 128, 128,   0,   0,   0, 128,   0, 
00068           0,   0,   0,   0,   0,   0,   0,   0, 
00069           0,   0,   0,   0,   0,   0,   0,   0, 
00070           0,   0,   0,   0,   0,   0,   0,   0, 
00071           0,   0,   0,   0,   0,   0,   0,   0, 
00072           0,   0,   0,   0,   0,   0,   0,   0, 
00073           0,   0,   0,   0,   0,   0,   0,   0, 
00074           0,   0,   0,   0,   0,   0,   0,   0, 
00075           0,   0,   0,   0,   0,   0,   0,   0, 
00076           0,   0,   0,   0,   0,   0,   0,   0, 
00077           0,   0,   0,   0,   0,   0,   0,   0, 
00078           0,   0,   0,   0,   0,   0,   0,   0, 
00079           0,   0,   0,   0,   0,   0,   0,   0, 
00080           0,   0,   0,   0,   0,   0,   0,   0, 
00081           0,   0,   0,   0,   0,   0,   0,   0, 
00082           0,   0,   0,   0,   0,   0,   0,   0, 
00083           0,   0,   0,   0,   0,   0,   0,   0, 
00084       };
00085 
00086       yych = *in;
00087       if (yych <= '[') {
00088         if (yych <= '$') {
00089           if (yych <= 0x00) goto yy7;
00090           if (yych <= ' ') goto yy9;
00091           if (yych <= '#') goto yy6;
00092           goto yy4;
00093         } else {
00094           if (yych <= '=') goto yy6;
00095           if (yych <= '?') goto yy9;
00096           if (yych <= 'Z') goto yy6;
00097           goto yy9;
00098         }
00099       } else {
00100         if (yych <= '`') {
00101           if (yych <= '\\') goto yy2;
00102           if (yych == '_') goto yy6;
00103           goto yy9;
00104         } else {
00105           if (yych <= 'z') goto yy6;
00106           if (yych == '~') goto yy6;
00107           goto yy9;
00108         }
00109       }
00110 yy2:
00111       ++in;
00112       if ((yych = *in) <= '#') {
00113         if (yych <= '\n') {
00114           if (yych <= 0x00) goto yy3;
00115           if (yych <= '\t') goto yy14;
00116         } else {
00117           if (yych == ' ') goto yy16;
00118           if (yych <= '"') goto yy14;
00119           goto yy16;
00120         }
00121       } else {
00122         if (yych <= 'Z') {
00123           if (yych == '*') goto yy16;
00124           goto yy14;
00125         } else {
00126           if (yych <= '\\') goto yy16;
00127           if (yych == '|') goto yy16;
00128           goto yy14;
00129         }
00130       }
00131 yy3:
00132       {
00133         // For any other character (e.g. whitespace), swallow it here,
00134         // allowing the outer logic to loop around again.
00135         break;
00136       }
00137 yy4:
00138       ++in;
00139       if ((yych = *in) == '$') goto yy12;
00140       goto yy11;
00141 yy5:
00142       {
00143         // Got a span of plain text.
00144         int len = (int)(in - start);
00145         // Need to shift it over if we're overwriting backslashes.
00146         if (out < start)
00147           memmove(out, start, len);
00148         out += len;
00149         continue;
00150       }
00151 yy6:
00152       yych = *++in;
00153       goto yy11;
00154 yy7:
00155       ++in;
00156       {
00157         break;
00158       }
00159 yy9:
00160       yych = *++in;
00161       goto yy3;
00162 yy10:
00163       ++in;
00164       yych = *in;
00165 yy11:
00166       if (yybm[0+yych] & 128) {
00167         goto yy10;
00168       }
00169       goto yy5;
00170 yy12:
00171       ++in;
00172       if (yybm[0+(yych = *in)] & 128) {
00173         goto yy10;
00174       }
00175       {
00176         // De-escape dollar character.
00177         *out++ = '$';
00178         continue;
00179       }
00180 yy14:
00181       ++in;
00182       {
00183         // Let backslash before other characters through verbatim.
00184         *out++ = '\\';
00185         *out++ = yych;
00186         continue;
00187       }
00188 yy16:
00189       ++in;
00190       {
00191         // De-escape backslashed character.
00192         *out++ = yych;
00193         continue;
00194       }
00195     }
00196 
00197     }
00198 
00199     int len = (int)(out - filename);
00200     const bool is_target = parsing_targets;
00201     if (len > 0 && filename[len - 1] == ':') {
00202       len--;  // Strip off trailing colon, if any.
00203       parsing_targets = false;
00204     }
00205 
00206     if (len == 0)
00207       continue;
00208 
00209     if (!is_target) {
00210       ins_.push_back(StringPiece(filename, len));
00211     } else if (!out_.str_) {
00212       out_ = StringPiece(filename, len);
00213     } else if (out_ != StringPiece(filename, len)) {
00214       *err = "depfile has multiple output paths.";
00215       return false;
00216     }
00217   }
00218   return true;
00219 }