Merge changes Iaa05196d,I8bd4f4de,I721e1ff9 into tizen
[platform/upstream/ninja.git] / src / depfile_parser.cc
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
19 DepfileParser::DepfileParser(DepfileParserOptions options)
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;
233           } else if (options_.depfile_distinct_target_lines_action_ ==
234                      kDepfileDistinctTargetLinesActionError) {
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 }