blob: 670a42df473e486dfe75f4584a07af2543ec8b29 [file] [log] [blame]
Shinichiro Hamaji776ca302015-06-06 03:52:48 +09001#include "parser.h"
2
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +09003#include <stack>
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +09004#include <unordered_map>
5
Shinichiro Hamaji776ca302015-06-06 03:52:48 +09006#include "ast.h"
7#include "file.h"
8#include "loc.h"
9#include "log.h"
10#include "string_piece.h"
Shinichiro Hamaji810fd032015-06-17 04:38:03 +090011#include "strutil.h"
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090012#include "value.h"
13
14enum struct ParserState {
15 NOT_AFTER_RULE = 0,
16 AFTER_RULE,
17 MAYBE_AFTER_RULE,
18};
19
20class Parser {
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +090021 struct IfState {
22 IfAST* ast;
23 bool is_in_else;
24 int num_nest;
25 };
26
Shinichiro Hamaji6cb1c252015-06-17 16:22:51 +090027 typedef void (Parser::*DirectiveHandler)(
28 StringPiece line, StringPiece directive);
29 typedef unordered_map<StringPiece, DirectiveHandler> DirectiveMap;
30
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090031 public:
32 Parser(StringPiece buf, const char* filename, vector<AST*>* asts)
33 : buf_(buf),
34 state_(ParserState::NOT_AFTER_RULE),
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +090035 asts_(asts),
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090036 out_asts_(asts),
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +090037 num_if_nest_(0),
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090038 loc_(filename, 0),
39 fixed_lineno_(false) {
40 }
41
42 ~Parser() {
43 }
44
45 void Parse() {
46 l_ = 0;
47
48 for (l_ = 0; l_ < buf_.size();) {
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090049 size_t lf_cnt = 0;
50 size_t e = FindEndOfLine(&lf_cnt);
Shinichiro Hamaji8ee8c372015-06-16 16:19:40 +090051 if (!fixed_lineno_)
52 loc_.lineno += lf_cnt;
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090053 StringPiece line(buf_.data() + l_, e - l_);
54 ParseLine(line);
55 if (e == buf_.size())
56 break;
57
58 l_ = e + 1;
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090059 }
60 }
61
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +090062 static void Init() {
Shinichiro Hamaji6cb1c252015-06-17 16:22:51 +090063 make_directives_ = new DirectiveMap;
Shinichiro Hamaji14b8bea2015-06-17 03:14:28 +090064 (*make_directives_)["include"] = &Parser::ParseInclude;
65 (*make_directives_)["-include"] = &Parser::ParseInclude;
66 (*make_directives_)["sinclude"] = &Parser::ParseInclude;
Shinichiro Hamaji810fd032015-06-17 04:38:03 +090067 (*make_directives_)["define"] = &Parser::ParseDefine;
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +090068 (*make_directives_)["ifdef"] = &Parser::ParseIfdef;
69 (*make_directives_)["ifndef"] = &Parser::ParseIfdef;
Shinichiro Hamajid146f4c2015-06-17 17:51:24 +090070 (*make_directives_)["ifeq"] = &Parser::ParseIfeq;
71 (*make_directives_)["ifneq"] = &Parser::ParseIfeq;
Shinichiro Hamaji6cb1c252015-06-17 16:22:51 +090072 (*make_directives_)["else"] = &Parser::ParseElse;
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +090073 (*make_directives_)["endif"] = &Parser::ParseEndif;
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +090074
Shinichiro Hamaji6cb1c252015-06-17 16:22:51 +090075 else_if_directives_ = new DirectiveMap;
76 (*else_if_directives_)["ifdef"] = &Parser::ParseIfdef;
77 (*else_if_directives_)["ifndef"] = &Parser::ParseIfdef;
78
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +090079 shortest_directive_len_ = 9999;
80 longest_directive_len_ = 0;
81 for (auto p : *make_directives_) {
82 size_t len = p.first.size();
83 shortest_directive_len_ = min(len, shortest_directive_len_);
84 longest_directive_len_ = max(len, longest_directive_len_);
85 }
86 }
87
88 static void Quit() {
89 delete make_directives_;
90 }
91
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090092 private:
93 void Error(const string& msg) {
Shinichiro Hamaji8ee8c372015-06-16 16:19:40 +090094 ERROR("%s:%d: %s", LOCF(loc_), msg.c_str());
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090095 }
96
97 size_t FindEndOfLine(size_t* lf_cnt) {
98 size_t e = l_;
99 bool prev_backslash = false;
100 for (; e < buf_.size(); e++) {
101 char c = buf_[e];
102 if (c == '\\') {
103 prev_backslash = !prev_backslash;
104 } else if (c == '\n') {
105 ++*lf_cnt;
106 if (!prev_backslash) {
107 return e;
108 }
109 } else if (c != '\r') {
110 prev_backslash = false;
111 }
112 }
113 return e;
114 }
115
116 void ParseLine(StringPiece line) {
117 if (line.empty() || (line.size() == 1 && line[0] == '\r'))
118 return;
119
Shinichiro Hamaji810fd032015-06-17 04:38:03 +0900120 if (!define_name_.empty()) {
121 ParseInsideDefine(line);
122 return;
123 }
124
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900125 if (line[0] == '\t' && state_ != ParserState::NOT_AFTER_RULE) {
126 CommandAST* ast = new CommandAST();
127 ast->expr = ParseExpr(line.substr(1), true);
128 out_asts_->push_back(ast);
129 return;
130 }
131
Shinichiro Hamaji32750622015-06-17 14:57:33 +0900132 line = TrimLeftSpace(line);
Shinichiro Hamajid4e81932015-06-17 04:40:45 +0900133
134 if (line[0] == '#')
135 return;
136
Shinichiro Hamaji6cb1c252015-06-17 16:22:51 +0900137 if (HandleDirective(line, make_directives_)) {
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900138 return;
139 }
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900140
141 size_t sep = line.find_first_of(STRING_PIECE("=:"));
142 if (sep == string::npos) {
Shinichiro Hamaji14b8bea2015-06-17 03:14:28 +0900143 ParseRule(line, sep);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900144 } else if (line[sep] == '=') {
Shinichiro Hamaji14b8bea2015-06-17 03:14:28 +0900145 ParseAssign(line, sep);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900146 } else if (line.get(sep+1) == '=') {
Shinichiro Hamaji14b8bea2015-06-17 03:14:28 +0900147 ParseAssign(line, sep+1);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900148 } else if (line[sep] == ':') {
Shinichiro Hamaji14b8bea2015-06-17 03:14:28 +0900149 ParseRule(line, sep);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900150 } else {
151 CHECK(false);
152 }
153 }
154
Shinichiro Hamaji14b8bea2015-06-17 03:14:28 +0900155 void ParseRule(StringPiece line, size_t sep) {
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900156 const bool is_rule = line.find(':') != string::npos;
Shinichiro Hamaji810fd032015-06-17 04:38:03 +0900157 RuleAST* ast = new RuleAST();
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900158 ast->set_loc(loc_);
159
160 size_t found = line.substr(sep + 1).find_first_of("=;");
161 if (found != string::npos) {
162 found += sep + 1;
163 ast->term = line[found];
Shinichiro Hamaji32750622015-06-17 14:57:33 +0900164 ast->after_term = ParseExpr(TrimLeftSpace(line.substr(found + 1)),
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900165 ast->term == ';');
Shinichiro Hamaji32750622015-06-17 14:57:33 +0900166 ast->expr = ParseExpr(TrimSpace(line.substr(0, found)), false);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900167 } else {
168 ast->term = 0;
169 ast->after_term = NULL;
Shinichiro Hamaji32750622015-06-17 14:57:33 +0900170 ast->expr = ParseExpr(TrimSpace(line), false);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900171 }
172 out_asts_->push_back(ast);
173 state_ = is_rule ? ParserState::AFTER_RULE : ParserState::MAYBE_AFTER_RULE;
174 }
175
Shinichiro Hamaji14b8bea2015-06-17 03:14:28 +0900176 void ParseAssign(StringPiece line, size_t sep) {
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900177 if (sep == 0)
178 Error("*** empty variable name ***");
179 AssignOp op = AssignOp::EQ;
180 size_t lhs_end = sep;
181 switch (line[sep-1]) {
182 case ':':
183 lhs_end--;
184 op = AssignOp::COLON_EQ;
185 break;
186 case '+':
187 lhs_end--;
188 op = AssignOp::PLUS_EQ;
189 break;
190 case '?':
191 lhs_end--;
192 op = AssignOp::QUESTION_EQ;
193 break;
194 }
195
Shinichiro Hamaji810fd032015-06-17 04:38:03 +0900196 AssignAST* ast = new AssignAST();
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900197 ast->set_loc(loc_);
Shinichiro Hamaji32750622015-06-17 14:57:33 +0900198 ast->lhs = ParseExpr(TrimSpace(line.substr(0, lhs_end)), false);
199 ast->rhs = ParseExpr(TrimSpace(line.substr(sep + 1)), false);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900200 ast->op = op;
201 ast->directive = AssignDirective::NONE;
202 out_asts_->push_back(ast);
203 state_ = ParserState::NOT_AFTER_RULE;
204 }
205
Shinichiro Hamaji14b8bea2015-06-17 03:14:28 +0900206 void ParseInclude(StringPiece line, StringPiece directive) {
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900207 IncludeAST* ast = new IncludeAST();
208 ast->expr = ParseExpr(line, false);
Shinichiro Hamajiefad2dd2015-06-17 03:08:02 +0900209 ast->should_exist = directive[0] == 'i';
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900210 out_asts_->push_back(ast);
211 }
212
Shinichiro Hamaji810fd032015-06-17 04:38:03 +0900213 void ParseDefine(StringPiece line, StringPiece) {
214 if (line.empty()) {
215 Error("*** empty variable name.");
216 }
217 define_name_ = line;
218 define_start_ = 0;
219 define_start_line_ = loc_.lineno;
220 }
221
222 void ParseInsideDefine(StringPiece line) {
Shinichiro Hamaji5562caf2015-06-17 17:08:40 +0900223 line = TrimLeftSpace(line);
224 if (GetDirective(line) != "endef") {
Shinichiro Hamaji810fd032015-06-17 04:38:03 +0900225 if (define_start_ == 0)
226 define_start_ = l_;
227 return;
228 }
229
Shinichiro Hamaji5562caf2015-06-17 17:08:40 +0900230 StringPiece rest = TrimRightSpace(RemoveComment(TrimLeftSpace(
231 line.substr(sizeof("endef")))));
232 if (!rest.empty()) {
233 WARN("%s:%d: extraneous text after `endef' directive", LOCF(loc_));
234 }
235
Shinichiro Hamaji810fd032015-06-17 04:38:03 +0900236 AssignAST* ast = new AssignAST();
237 ast->set_loc(Loc(loc_.filename, define_start_line_));
238 ast->lhs = ParseExpr(define_name_, false);
239 StringPiece rhs;
240 if (define_start_)
Shinichiro Hamaji32750622015-06-17 14:57:33 +0900241 rhs = TrimRightSpace(buf_.substr(define_start_, l_ - define_start_));
Shinichiro Hamaji810fd032015-06-17 04:38:03 +0900242 ast->rhs = ParseExpr(rhs, false);
243 ast->op = AssignOp::EQ;
244 ast->directive = AssignDirective::NONE;
245 out_asts_->push_back(ast);
246 define_name_.clear();
247 }
248
Shinichiro Hamajid146f4c2015-06-17 17:51:24 +0900249 void EnterIf(IfAST* ast) {
250 IfState* st = new IfState();
251 st->ast = ast;
252 st->is_in_else = false;
253 st->num_nest = num_if_nest_;
254 if_stack_.push(st);
255 out_asts_ = &ast->true_asts;
256 }
257
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900258 void ParseIfdef(StringPiece line, StringPiece directive) {
259 IfAST* ast = new IfAST();
260 ast->set_loc(loc_);
261 ast->op = directive[2] == 'n' ? CondOp::IFNDEF : CondOp::IFDEF;
262 ast->lhs = ParseExpr(line, false);
263 ast->rhs = NULL;
264 out_asts_->push_back(ast);
Shinichiro Hamajid146f4c2015-06-17 17:51:24 +0900265 EnterIf(ast);
266 }
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900267
Shinichiro Hamajid146f4c2015-06-17 17:51:24 +0900268 bool ParseIfEqCond(StringPiece s, IfAST* ast) {
269 if (s.empty()) {
270 return false;
271 }
272
273 if (s[0] == '(' && s[s.size() - 1] == ')') {
274 s = s.substr(1, s.size() - 2);
275 char terms[] = {',', '\0'};
276 size_t n;
277 ast->lhs = ParseExprImpl(s, terms, false, &n, true);
278 if (s[n] != ',')
279 return false;
280 s = TrimLeftSpace(s.substr(n+1));
281 ast->rhs = ParseExprImpl(s, NULL, false, &n);
Shinichiro Hamajiadeea692015-06-17 17:57:31 +0900282 s = TrimLeftSpace(s.substr(n));
Shinichiro Hamajid146f4c2015-06-17 17:51:24 +0900283 } else {
284 for (int i = 0; i < 2; i++) {
285 if (s.empty())
286 return false;
287 char quote = s[0];
288 if (quote != '\'' && quote != '"')
289 return false;
290 size_t end = s.find(quote, 1);
291 if (end == string::npos)
292 return false;
293 Value* v = ParseExpr(s.substr(1, end - 1), false);
294 if (i == 0)
295 ast->lhs = v;
296 else
297 ast->rhs = v;
298 s = TrimLeftSpace(s.substr(end+1));
299 }
Shinichiro Hamajid146f4c2015-06-17 17:51:24 +0900300 }
Shinichiro Hamajiadeea692015-06-17 17:57:31 +0900301 if (!s.empty()) {
302 Error("extraneous text after `ifeq' directive");
303 }
304 return true;
Shinichiro Hamajid146f4c2015-06-17 17:51:24 +0900305 }
306
307 void ParseIfeq(StringPiece line, StringPiece directive) {
308 IfAST* ast = new IfAST();
309 ast->set_loc(loc_);
310 ast->op = directive[2] == 'n' ? CondOp::IFNEQ : CondOp::IFEQ;
311
312 if (!ParseIfEqCond(line, ast)) {
313 Error("*** invalid syntax in conditional.");
314 }
315
316 out_asts_->push_back(ast);
317 EnterIf(ast);
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900318 }
319
Shinichiro Hamaji6cb1c252015-06-17 16:22:51 +0900320 void ParseElse(StringPiece line, StringPiece) {
321 CheckIfStack("else");
322 IfState* st = if_stack_.top();
323 if (st->is_in_else)
324 Error("*** only one `else' per conditional.");
325 st->is_in_else = true;
326 out_asts_ = &st->ast->false_asts;
327
328 StringPiece next_if = TrimLeftSpace(line);
329 if (next_if.empty())
330 return;
331
332 num_if_nest_ = st->num_nest + 1;
333 if (!HandleDirective(next_if, else_if_directives_)) {
334 WARN("%s:%d: extraneous text after `else' directive", LOCF(loc_));
335 }
336 num_if_nest_ = 0;
337 }
338
339 void ParseEndif(StringPiece line, StringPiece) {
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900340 CheckIfStack("endif");
Shinichiro Hamaji6cb1c252015-06-17 16:22:51 +0900341 if (!line.empty())
342 Error("extraneous text after `endif` directive");
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900343 IfState st = *if_stack_.top();
344 for (int t = 0; t <= st.num_nest; t++) {
345 delete if_stack_.top();
346 if_stack_.pop();
347 if (if_stack_.empty()) {
348 out_asts_ = asts_;
349 } else {
350 IfState* st = if_stack_.top();
351 if (st->is_in_else)
Shinichiro Hamaji2847f092015-06-17 15:48:37 +0900352 out_asts_ = &st->ast->false_asts;
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900353 else
Shinichiro Hamaji2847f092015-06-17 15:48:37 +0900354 out_asts_ = &st->ast->true_asts;
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900355 }
356 }
357 }
358
359 void CheckIfStack(const char* keyword) {
360 if (if_stack_.empty()) {
361 Error(StringPrintf("*** extraneous `%s'.", keyword));
362 }
363 }
364
Shinichiro Hamaji5562caf2015-06-17 17:08:40 +0900365 StringPiece RemoveComment(StringPiece line) {
366 bool prev_backslash = false;
367 stack<char> paren_stack;
368 for (size_t i = 0; i < line.size(); i++) {
369 char c = line[i];
370 switch (c) {
371 case '(':
372 paren_stack.push(')');
373 break;
374 case '{':
375 paren_stack.push('}');
376 break;
377
378 case ')':
379 case '}':
380 if (!paren_stack.empty() && c == paren_stack.top()) {
381 paren_stack.pop();
382 }
383 break;
384
385 case '#':
386 if (paren_stack.empty() && !prev_backslash)
387 return line.substr(0, i);
388
389 }
390 prev_backslash = c == '\\' && !prev_backslash;
391 }
392 return line;
393 }
394
395 StringPiece GetDirective(StringPiece line) {
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900396 if (line.size() < shortest_directive_len_)
Shinichiro Hamaji5562caf2015-06-17 17:08:40 +0900397 return StringPiece();
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900398 StringPiece prefix = line.substr(0, longest_directive_len_ + 1);
Shinichiro Hamaji5562caf2015-06-17 17:08:40 +0900399 size_t space_index = prefix.find_first_of(" \t#");
400 return prefix.substr(0, space_index);
401 }
402
403 bool HandleDirective(StringPiece line, const DirectiveMap* directive_map) {
404 StringPiece directive = GetDirective(line);
Shinichiro Hamaji6cb1c252015-06-17 16:22:51 +0900405 auto found = directive_map->find(directive);
406 if (found == directive_map->end())
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900407 return false;
408
Shinichiro Hamaji5562caf2015-06-17 17:08:40 +0900409 StringPiece rest = TrimRightSpace(RemoveComment(TrimLeftSpace(
Shinichiro Hamajid146f4c2015-06-17 17:51:24 +0900410 line.substr(directive.size()))));
Shinichiro Hamaji810fd032015-06-17 04:38:03 +0900411 (this->*found->second)(rest, directive);
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900412 return true;
413 }
414
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900415 StringPiece buf_;
416 size_t l_;
417 ParserState state_;
418
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900419 vector<AST*>* asts_;
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900420 vector<AST*>* out_asts_;
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900421
Shinichiro Hamaji810fd032015-06-17 04:38:03 +0900422 StringPiece define_name_;
423 size_t define_start_;
424 int define_start_line_;
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900425
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900426 int num_if_nest_;
427 stack<IfState*> if_stack_;
428
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900429 Loc loc_;
430 bool fixed_lineno_;
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900431
Shinichiro Hamaji6cb1c252015-06-17 16:22:51 +0900432 static DirectiveMap* make_directives_;
433 static DirectiveMap* else_if_directives_;
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900434 static size_t shortest_directive_len_;
435 static size_t longest_directive_len_;
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900436};
437
438void Parse(Makefile* mk) {
439 Parser parser(StringPiece(mk->buf(), mk->len()),
440 mk->filename().c_str(),
441 mk->mutable_asts());
442 parser.Parse();
443}
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900444
445void InitParser() {
446 Parser::Init();
447}
448
449void QuitParser() {
450 Parser::Quit();
451}
452
Shinichiro Hamaji6cb1c252015-06-17 16:22:51 +0900453Parser::DirectiveMap* Parser::make_directives_;
454Parser::DirectiveMap* Parser::else_if_directives_;
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900455size_t Parser::shortest_directive_len_;
456size_t Parser::longest_directive_len_;