1 /* Generated by re2c 1.1.1 */
2 // Copyright 2011 Google Inc. All Rights Reserved.
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
8 // http://www.apache.org/licenses/LICENSE-2.0
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
16 #include "depfile_parser.h"
19 DepfileParser::DepfileParser(DepfileParserOptions options)
24 // A note on backslashes in Makefiles, from reading the docs:
25 // Backslash-newline is the line continuation character.
26 // Backslash-# escapes a # (otherwise meaningful as a comment start).
27 // Backslash-% escapes a % (otherwise meaningful as a special).
28 // Finally, quoting the GNU manual, "Backslashes that are not in danger
29 // of quoting ‘%’ characters go unmolested."
30 // How do you end a line with a backslash? The netbsd Make docs suggest
31 // reading the result of a shell command echoing a backslash!
33 // Rather than implement all of above, we do a simpler thing here:
34 // Backslashes escape a set of characters (see "escapes" defined below),
35 // otherwise they are passed through verbatim.
36 // If anyone actually has depfiles that rely on the more complicated
37 // behavior we can adjust this.
38 bool DepfileParser::Parse(string* content, string* err) {
39 // in: current parser input point.
41 // parsing_targets: whether we are parsing targets or dependencies.
42 char* in = &(*content)[0];
43 char* end = in + content->size();
44 bool have_target = false;
45 bool have_secondary_target_on_this_rule = false;
46 bool have_newline_since_primary_target = false;
47 bool warned_distinct_target_lines = false;
48 bool parsing_targets = true;
50 bool have_newline = false;
51 // out: current output point (typically same as in, but can fall behind
52 // as we de-escape backslashes).
54 // filename: start of the current parsed filename.
57 // start: beginning of the current parsed span.
58 const char* start = in;
59 char* yymarker = NULL;
63 static const unsigned char yybm[] = {
64 0, 0, 0, 0, 0, 0, 0, 0,
65 0, 0, 0, 0, 0, 0, 0, 0,
66 0, 0, 0, 0, 0, 0, 0, 0,
67 0, 0, 0, 0, 0, 0, 0, 0,
68 0, 128, 0, 0, 0, 128, 0, 0,
69 128, 128, 0, 128, 128, 128, 128, 128,
70 128, 128, 128, 128, 128, 128, 128, 128,
71 128, 128, 128, 0, 0, 128, 0, 0,
72 128, 128, 128, 128, 128, 128, 128, 128,
73 128, 128, 128, 128, 128, 128, 128, 128,
74 128, 128, 128, 128, 128, 128, 128, 128,
75 128, 128, 128, 0, 0, 0, 0, 128,
76 0, 128, 128, 128, 128, 128, 128, 128,
77 128, 128, 128, 128, 128, 128, 128, 128,
78 128, 128, 128, 128, 128, 128, 128, 128,
79 128, 128, 128, 128, 0, 128, 128, 0,
80 128, 128, 128, 128, 128, 128, 128, 128,
81 128, 128, 128, 128, 128, 128, 128, 128,
82 128, 128, 128, 128, 128, 128, 128, 128,
83 128, 128, 128, 128, 128, 128, 128, 128,
84 128, 128, 128, 128, 128, 128, 128, 128,
85 128, 128, 128, 128, 128, 128, 128, 128,
86 128, 128, 128, 128, 128, 128, 128, 128,
87 128, 128, 128, 128, 128, 128, 128, 128,
88 128, 128, 128, 128, 128, 128, 128, 128,
89 128, 128, 128, 128, 128, 128, 128, 128,
90 128, 128, 128, 128, 128, 128, 128, 128,
91 128, 128, 128, 128, 128, 128, 128, 128,
92 128, 128, 128, 128, 128, 128, 128, 128,
93 128, 128, 128, 128, 128, 128, 128, 128,
94 128, 128, 128, 128, 128, 128, 128, 128,
95 128, 128, 128, 128, 128, 128, 128, 128,
98 if (yybm[0+yych] & 128) {
103 if (yych >= 0x01) goto yy4;
105 if (yych <= '\n') goto yy6;
106 if (yych <= '\f') goto yy4;
111 if (yych <= '#') goto yy4;
114 if (yych == '\\') goto yy13;
126 // For any other character (e.g. whitespace), swallow it here,
127 // allowing the outer logic to loop around again.
133 // A newline ends the current file name and the current rule.
139 if (yych == '\n') goto yy6;
143 if (yybm[0+yych] & 128) {
147 // Got a span of plain text.
148 int len = (int)(in - start);
149 // Need to shift it over if we're overwriting backslashes.
151 memmove(out, start, len);
157 if (yych == '$') goto yy14;
160 yych = *(yymarker = ++in);
163 if (yych <= 0x00) goto yy5;
164 if (yych == '\n') goto yy18;
167 if (yych <= '\r') goto yy20;
168 if (yych == ' ') goto yy22;
173 if (yych <= '#') goto yy22;
174 if (yych == '*') goto yy22;
177 if (yych <= ']') goto yy22;
178 if (yych == '|') goto yy22;
185 // De-escape dollar character.
192 // Let backslash before other characters through verbatim.
200 // A line continuation ends the current file name.
205 if (yych == '\n') goto yy18;
211 // De-escape backslashed character.
219 int len = (int)(out - filename);
220 const bool is_dependency = !parsing_targets;
221 if (len > 0 && filename[len - 1] == ':') {
222 len--; // Strip off trailing colon, if any.
223 parsing_targets = false;
229 if (have_secondary_target_on_this_rule) {
230 if (!have_newline_since_primary_target) {
231 *err = "depfile has multiple output paths";
233 } else if (options_.depfile_distinct_target_lines_action_ ==
234 kDepfileDistinctTargetLinesActionError) {
236 "depfile has multiple output paths (on separate lines)"
237 " [-w depfilemulti=err]";
240 if (!warned_distinct_target_lines) {
241 warned_distinct_target_lines = true;
242 Warning("depfile has multiple output paths (on separate lines); "
243 "continuing anyway [-w depfilemulti=warn]");
248 ins_.push_back(StringPiece(filename, len));
249 } else if (!out_.str_) {
250 out_ = StringPiece(filename, len);
251 } else if (out_ != StringPiece(filename, len)) {
252 have_secondary_target_on_this_rule = true;
257 // A newline ends a rule so the next filename will be a new target.
258 parsing_targets = true;
259 have_secondary_target_on_this_rule = false;
261 have_newline_since_primary_target = true;
266 *err = "expected ':' in depfile";