Ninja
depfile_parser.cc
Go to the documentation of this file.
1 /* Generated by re2c 1.1.1 */
2 // Copyright 2011 Google Inc. All Rights Reserved.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 
16 #include "depfile_parser.h"
17 #include "util.h"
18 
20  : options_(options)
21 {
22 }
23 
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!
32 //
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.
40  // end: end of input.
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;
49  while (in < end) {
50  bool have_newline = false;
51  // out: current output point (typically same as in, but can fall behind
52  // as we de-escape backslashes).
53  char* out = in;
54  // filename: start of the current parsed filename.
55  char* filename = out;
56  for (;;) {
57  // start: beginning of the current parsed span.
58  const char* start = in;
59  char* yymarker = NULL;
60 
61  {
62  unsigned char yych;
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,
96  };
97  yych = *in;
98  if (yybm[0+yych] & 128) {
99  goto yy9;
100  }
101  if (yych <= '\r') {
102  if (yych <= '\t') {
103  if (yych >= 0x01) goto yy4;
104  } else {
105  if (yych <= '\n') goto yy6;
106  if (yych <= '\f') goto yy4;
107  goto yy8;
108  }
109  } else {
110  if (yych <= '$') {
111  if (yych <= '#') goto yy4;
112  goto yy12;
113  } else {
114  if (yych == '\\') goto yy13;
115  goto yy4;
116  }
117  }
118  ++in;
119  {
120  break;
121  }
122 yy4:
123  ++in;
124 yy5:
125  {
126  // For any other character (e.g. whitespace), swallow it here,
127  // allowing the outer logic to loop around again.
128  break;
129  }
130 yy6:
131  ++in;
132  {
133  // A newline ends the current file name and the current rule.
134  have_newline = true;
135  break;
136  }
137 yy8:
138  yych = *++in;
139  if (yych == '\n') goto yy6;
140  goto yy5;
141 yy9:
142  yych = *++in;
143  if (yybm[0+yych] & 128) {
144  goto yy9;
145  }
146  {
147  // Got a span of plain text.
148  int len = (int)(in - start);
149  // Need to shift it over if we're overwriting backslashes.
150  if (out < start)
151  memmove(out, start, len);
152  out += len;
153  continue;
154  }
155 yy12:
156  yych = *++in;
157  if (yych == '$') goto yy14;
158  goto yy5;
159 yy13:
160  yych = *(yymarker = ++in);
161  if (yych <= '"') {
162  if (yych <= '\f') {
163  if (yych <= 0x00) goto yy5;
164  if (yych == '\n') goto yy18;
165  goto yy16;
166  } else {
167  if (yych <= '\r') goto yy20;
168  if (yych == ' ') goto yy22;
169  goto yy16;
170  }
171  } else {
172  if (yych <= 'Z') {
173  if (yych <= '#') goto yy22;
174  if (yych == '*') goto yy22;
175  goto yy16;
176  } else {
177  if (yych <= ']') goto yy22;
178  if (yych == '|') goto yy22;
179  goto yy16;
180  }
181  }
182 yy14:
183  ++in;
184  {
185  // De-escape dollar character.
186  *out++ = '$';
187  continue;
188  }
189 yy16:
190  ++in;
191  {
192  // Let backslash before other characters through verbatim.
193  *out++ = '\\';
194  *out++ = yych;
195  continue;
196  }
197 yy18:
198  ++in;
199  {
200  // A line continuation ends the current file name.
201  break;
202  }
203 yy20:
204  yych = *++in;
205  if (yych == '\n') goto yy18;
206  in = yymarker;
207  goto yy5;
208 yy22:
209  ++in;
210  {
211  // De-escape backslashed character.
212  *out++ = yych;
213  continue;
214  }
215  }
216 
217  }
218 
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;
224  have_target = true;
225  }
226 
227  if (len > 0) {
228  if (is_dependency) {
229  if (have_secondary_target_on_this_rule) {
230  if (!have_newline_since_primary_target) {
231  *err = "depfile has multiple output paths";
232  return false;
235  *err =
236  "depfile has multiple output paths (on separate lines)"
237  " [-w depfilemulti=err]";
238  return false;
239  } else {
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]");
244  }
245  continue;
246  }
247  }
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;
253  }
254  }
255 
256  if (have_newline) {
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;
260  if (have_target) {
261  have_newline_since_primary_target = true;
262  }
263  }
264  }
265  if (!have_target) {
266  *err = "expected ':' in depfile";
267  return false;
268  }
269  return true;
270 }
const char * str_
Definition: string_piece.h:67
StringPiece represents a slice of a string whose memory is managed externally.
Definition: string_piece.h:27
bool Parse(string *content, string *err)
Parse an input file.
DepfileParserOptions options_
DepfileDistinctTargetLinesAction depfile_distinct_target_lines_action_
vector< StringPiece > ins_
StringPiece out_
DepfileParser(DepfileParserOptions options=DepfileParserOptions())
void Warning(const char *msg,...)
Log a warning message.
Definition: util.cc:75