blob: 40595cd9436a30cda8d76a33823c0ccb20703f9d [file] [log] [blame]
Shinichiro Hamaji1d545aa2015-06-23 15:29:13 +09001// Copyright 2015 Google Inc. All rights reserved
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +090015// +build ignore
16
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090017#include "parser.h"
18
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +090019#include <stack>
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +090020#include <unordered_map>
21
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090022#include "ast.h"
23#include "file.h"
24#include "loc.h"
25#include "log.h"
Shinichiro Hamaji6b1a11a2015-06-30 16:21:19 +090026#include "stats.h"
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090027#include "string_piece.h"
Shinichiro Hamaji810fd032015-06-17 04:38:03 +090028#include "strutil.h"
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090029#include "value.h"
30
31enum struct ParserState {
32 NOT_AFTER_RULE = 0,
33 AFTER_RULE,
34 MAYBE_AFTER_RULE,
35};
36
37class Parser {
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +090038 struct IfState {
39 IfAST* ast;
40 bool is_in_else;
41 int num_nest;
42 };
43
Shinichiro Hamaji6cb1c252015-06-17 16:22:51 +090044 typedef void (Parser::*DirectiveHandler)(
45 StringPiece line, StringPiece directive);
46 typedef unordered_map<StringPiece, DirectiveHandler> DirectiveMap;
47
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090048 public:
49 Parser(StringPiece buf, const char* filename, vector<AST*>* asts)
50 : buf_(buf),
51 state_(ParserState::NOT_AFTER_RULE),
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +090052 asts_(asts),
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090053 out_asts_(asts),
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +090054 num_if_nest_(0),
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090055 loc_(filename, 0),
56 fixed_lineno_(false) {
57 }
58
Shinichiro Hamaji80456fb2015-06-18 14:56:10 +090059 Parser(StringPiece buf, const Loc& loc, vector<AST*>* asts)
60 : buf_(buf),
61 state_(ParserState::NOT_AFTER_RULE),
62 asts_(asts),
63 out_asts_(asts),
64 num_if_nest_(0),
65 loc_(loc),
66 fixed_lineno_(true) {
67 }
68
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090069 ~Parser() {
70 }
71
72 void Parse() {
73 l_ = 0;
74
75 for (l_ = 0; l_ < buf_.size();) {
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090076 size_t lf_cnt = 0;
77 size_t e = FindEndOfLine(&lf_cnt);
Shinichiro Hamaji8ee8c372015-06-16 16:19:40 +090078 if (!fixed_lineno_)
Shinichiro Hamajib3af68b2015-06-24 20:47:57 +090079 loc_.lineno++;
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090080 StringPiece line(buf_.data() + l_, e - l_);
Shinichiro Hamaji420f7752015-06-26 04:02:02 +090081 orig_line_with_directives_ = line;
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090082 ParseLine(line);
Shinichiro Hamajib3af68b2015-06-24 20:47:57 +090083 if (!fixed_lineno_)
84 loc_.lineno += lf_cnt - 1;
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090085 if (e == buf_.size())
86 break;
87
88 l_ = e + 1;
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090089 }
90 }
91
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +090092 static void Init() {
Shinichiro Hamaji6cb1c252015-06-17 16:22:51 +090093 make_directives_ = new DirectiveMap;
Shinichiro Hamaji14b8bea2015-06-17 03:14:28 +090094 (*make_directives_)["include"] = &Parser::ParseInclude;
95 (*make_directives_)["-include"] = &Parser::ParseInclude;
96 (*make_directives_)["sinclude"] = &Parser::ParseInclude;
Shinichiro Hamaji810fd032015-06-17 04:38:03 +090097 (*make_directives_)["define"] = &Parser::ParseDefine;
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +090098 (*make_directives_)["ifdef"] = &Parser::ParseIfdef;
99 (*make_directives_)["ifndef"] = &Parser::ParseIfdef;
Shinichiro Hamajid146f4c2015-06-17 17:51:24 +0900100 (*make_directives_)["ifeq"] = &Parser::ParseIfeq;
101 (*make_directives_)["ifneq"] = &Parser::ParseIfeq;
Shinichiro Hamaji6cb1c252015-06-17 16:22:51 +0900102 (*make_directives_)["else"] = &Parser::ParseElse;
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900103 (*make_directives_)["endif"] = &Parser::ParseEndif;
Shinichiro Hamaji420f7752015-06-26 04:02:02 +0900104 (*make_directives_)["override"] = &Parser::ParseOverride;
105 (*make_directives_)["export"] = &Parser::ParseExport;
106 (*make_directives_)["unexport"] = &Parser::ParseUnexport;
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900107
Shinichiro Hamaji6cb1c252015-06-17 16:22:51 +0900108 else_if_directives_ = new DirectiveMap;
109 (*else_if_directives_)["ifdef"] = &Parser::ParseIfdef;
110 (*else_if_directives_)["ifndef"] = &Parser::ParseIfdef;
Shinichiro Hamaji6aeab2a2015-06-26 09:12:01 +0900111 (*else_if_directives_)["ifeq"] = &Parser::ParseIfeq;
112 (*else_if_directives_)["ifneq"] = &Parser::ParseIfeq;
Shinichiro Hamaji6cb1c252015-06-17 16:22:51 +0900113
Shinichiro Hamaji420f7752015-06-26 04:02:02 +0900114 assign_directives_ = new DirectiveMap;
115 (*assign_directives_)["define"] = &Parser::ParseDefine;
116 (*assign_directives_)["export"] = &Parser::ParseExport;
117 (*assign_directives_)["override"] = &Parser::ParseOverride;
118
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900119 shortest_directive_len_ = 9999;
120 longest_directive_len_ = 0;
121 for (auto p : *make_directives_) {
122 size_t len = p.first.size();
123 shortest_directive_len_ = min(len, shortest_directive_len_);
124 longest_directive_len_ = max(len, longest_directive_len_);
125 }
126 }
127
128 static void Quit() {
129 delete make_directives_;
130 }
131
Shinichiro Hamaji631a9f82015-07-05 14:18:15 +0900132 void set_state(ParserState st) { state_ = st; }
133
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900134 private:
135 void Error(const string& msg) {
Shinichiro Hamaji56227862015-08-05 16:53:37 +0900136 ParseErrorAST* ast = new ParseErrorAST();
137 ast->set_loc(loc_);
138 ast->msg = msg;
139 out_asts_->push_back(ast);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900140 }
141
142 size_t FindEndOfLine(size_t* lf_cnt) {
Shinichiro Hamaji14bb2792015-06-25 18:24:11 +0900143 return ::FindEndOfLine(buf_, l_, lf_cnt);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900144 }
145
Shinichiro Hamaji36b326f2015-06-26 08:56:13 +0900146 Value* ParseExpr(StringPiece s, ParseExprOpt opt = ParseExprOpt::NORMAL) {
147 return ::ParseExpr(loc_, s, opt);
148 }
149
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900150 void ParseLine(StringPiece line) {
Shinichiro Hamaji810fd032015-06-17 04:38:03 +0900151 if (!define_name_.empty()) {
152 ParseInsideDefine(line);
153 return;
154 }
155
Shinichiro Hamajic6ac0b92015-07-06 16:24:10 +0900156 if (line.empty() || (line.size() == 1 && line[0] == '\r'))
157 return;
158
Shinichiro Hamaji420f7752015-06-26 04:02:02 +0900159 current_directive_ = AssignDirective::NONE;
160
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900161 if (line[0] == '\t' && state_ != ParserState::NOT_AFTER_RULE) {
162 CommandAST* ast = new CommandAST();
Shinichiro Hamaji861bd642015-06-19 16:59:13 +0900163 ast->set_loc(loc_);
Shinichiro Hamaji66bd7bc2015-06-19 16:54:06 +0900164 ast->expr = ParseExpr(line.substr(1), ParseExprOpt::COMMAND);
Shinichiro Hamaji631a9f82015-07-05 14:18:15 +0900165 ast->orig = line;
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900166 out_asts_->push_back(ast);
167 return;
168 }
169
Shinichiro Hamaji32750622015-06-17 14:57:33 +0900170 line = TrimLeftSpace(line);
Shinichiro Hamajid4e81932015-06-17 04:40:45 +0900171
172 if (line[0] == '#')
173 return;
174
Shinichiro Hamaji6cb1c252015-06-17 16:22:51 +0900175 if (HandleDirective(line, make_directives_)) {
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900176 return;
177 }
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900178
Shinichiro Hamaji420f7752015-06-26 04:02:02 +0900179 ParseRuleOrAssign(line);
180 }
181
182 void ParseRuleOrAssign(StringPiece line) {
Shinichiro Hamaji415a9b12015-07-05 14:33:02 +0900183 size_t sep = FindThreeOutsideParen(line, ':', '=', ';');
184 if (sep == string::npos || line[sep] == ';') {
185 ParseRule(line, string::npos);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900186 } else if (line[sep] == '=') {
Shinichiro Hamaji14b8bea2015-06-17 03:14:28 +0900187 ParseAssign(line, sep);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900188 } else if (line.get(sep+1) == '=') {
Shinichiro Hamaji14b8bea2015-06-17 03:14:28 +0900189 ParseAssign(line, sep+1);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900190 } else if (line[sep] == ':') {
Shinichiro Hamaji14b8bea2015-06-17 03:14:28 +0900191 ParseRule(line, sep);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900192 } else {
193 CHECK(false);
194 }
195 }
196
Shinichiro Hamaji14b8bea2015-06-17 03:14:28 +0900197 void ParseRule(StringPiece line, size_t sep) {
Shinichiro Hamaji420f7752015-06-26 04:02:02 +0900198 if (current_directive_ != AssignDirective::NONE) {
Shinichiro Hamaji45a0c762015-06-26 06:47:10 +0900199 if (IsInExport())
200 return;
Shinichiro Hamaji420f7752015-06-26 04:02:02 +0900201 if (sep != string::npos) {
202 sep += orig_line_with_directives_.size() - line.size();
203 }
204 line = orig_line_with_directives_;
Shinichiro Hamajidf066c32015-06-26 09:09:26 +0900205 }
206
Shinichiro Hamaji6aeab2a2015-06-26 09:12:01 +0900207 line = TrimLeftSpace(line);
Shinichiro Hamajidf066c32015-06-26 09:09:26 +0900208 if (line.empty())
209 return;
210
211 if (orig_line_with_directives_[0] == '\t') {
Shinichiro Hamaji2bed7702015-06-26 07:56:28 +0900212 Error("*** commands commence before first target.");
Shinichiro Hamaji56227862015-08-05 16:53:37 +0900213 return;
Shinichiro Hamaji420f7752015-06-26 04:02:02 +0900214 }
215
Shinichiro Hamaji76ff9832015-06-18 17:11:22 +0900216 const bool is_rule = sep != string::npos && line[sep] == ':';
Shinichiro Hamaji810fd032015-06-17 04:38:03 +0900217 RuleAST* ast = new RuleAST();
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900218 ast->set_loc(loc_);
219
Shinichiro Hamaji76ff9832015-06-18 17:11:22 +0900220 size_t found = FindTwoOutsideParen(line.substr(sep + 1), '=', ';');
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900221 if (found != string::npos) {
222 found += sep + 1;
223 ast->term = line[found];
Shinichiro Hamaji66bd7bc2015-06-19 16:54:06 +0900224 ParseExprOpt opt =
225 ast->term == ';' ? ParseExprOpt::COMMAND : ParseExprOpt::NORMAL;
226 ast->after_term = ParseExpr(TrimLeftSpace(line.substr(found + 1)), opt);
227 ast->expr = ParseExpr(TrimSpace(line.substr(0, found)));
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900228 } else {
229 ast->term = 0;
230 ast->after_term = NULL;
Shinichiro Hamajidf066c32015-06-26 09:09:26 +0900231 ast->expr = ParseExpr(line);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900232 }
233 out_asts_->push_back(ast);
234 state_ = is_rule ? ParserState::AFTER_RULE : ParserState::MAYBE_AFTER_RULE;
235 }
236
Shinichiro Hamaji14b8bea2015-06-17 03:14:28 +0900237 void ParseAssign(StringPiece line, size_t sep) {
Shinichiro Hamaji56227862015-08-05 16:53:37 +0900238 if (sep == 0) {
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900239 Error("*** empty variable name ***");
Shinichiro Hamaji56227862015-08-05 16:53:37 +0900240 return;
241 }
Shinichiro Hamaji9b16bda2015-06-19 14:25:17 +0900242 StringPiece lhs;
243 StringPiece rhs;
244 AssignOp op;
245 ParseAssignStatement(line, sep, &lhs, &rhs, &op);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900246
Shinichiro Hamaji810fd032015-06-17 04:38:03 +0900247 AssignAST* ast = new AssignAST();
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900248 ast->set_loc(loc_);
Shinichiro Hamaji66bd7bc2015-06-19 16:54:06 +0900249 ast->lhs = ParseExpr(lhs);
250 ast->rhs = ParseExpr(rhs);
Shinichiro Hamaji81699be2015-06-22 18:07:38 +0900251 ast->orig_rhs = rhs;
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900252 ast->op = op;
Shinichiro Hamaji420f7752015-06-26 04:02:02 +0900253 ast->directive = current_directive_;
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900254 out_asts_->push_back(ast);
255 state_ = ParserState::NOT_AFTER_RULE;
256 }
257
Shinichiro Hamaji14b8bea2015-06-17 03:14:28 +0900258 void ParseInclude(StringPiece line, StringPiece directive) {
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900259 IncludeAST* ast = new IncludeAST();
Shinichiro Hamaji861bd642015-06-19 16:59:13 +0900260 ast->set_loc(loc_);
Shinichiro Hamaji66bd7bc2015-06-19 16:54:06 +0900261 ast->expr = ParseExpr(line);
Shinichiro Hamajiefad2dd2015-06-17 03:08:02 +0900262 ast->should_exist = directive[0] == 'i';
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900263 out_asts_->push_back(ast);
Shinichiro Hamajiff4584d2015-06-24 17:45:14 +0900264 state_ = ParserState::NOT_AFTER_RULE;
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900265 }
266
Shinichiro Hamaji810fd032015-06-17 04:38:03 +0900267 void ParseDefine(StringPiece line, StringPiece) {
268 if (line.empty()) {
269 Error("*** empty variable name.");
Shinichiro Hamaji56227862015-08-05 16:53:37 +0900270 return;
Shinichiro Hamaji810fd032015-06-17 04:38:03 +0900271 }
272 define_name_ = line;
273 define_start_ = 0;
274 define_start_line_ = loc_.lineno;
Shinichiro Hamajiff4584d2015-06-24 17:45:14 +0900275 state_ = ParserState::NOT_AFTER_RULE;
Shinichiro Hamaji810fd032015-06-17 04:38:03 +0900276 }
277
278 void ParseInsideDefine(StringPiece line) {
Shinichiro Hamaji5562caf2015-06-17 17:08:40 +0900279 line = TrimLeftSpace(line);
280 if (GetDirective(line) != "endef") {
Shinichiro Hamaji810fd032015-06-17 04:38:03 +0900281 if (define_start_ == 0)
282 define_start_ = l_;
283 return;
284 }
285
Shinichiro Hamaji5562caf2015-06-17 17:08:40 +0900286 StringPiece rest = TrimRightSpace(RemoveComment(TrimLeftSpace(
287 line.substr(sizeof("endef")))));
288 if (!rest.empty()) {
289 WARN("%s:%d: extraneous text after `endef' directive", LOCF(loc_));
290 }
291
Shinichiro Hamaji810fd032015-06-17 04:38:03 +0900292 AssignAST* ast = new AssignAST();
293 ast->set_loc(Loc(loc_.filename, define_start_line_));
Shinichiro Hamaji66bd7bc2015-06-19 16:54:06 +0900294 ast->lhs = ParseExpr(define_name_);
Shinichiro Hamaji810fd032015-06-17 04:38:03 +0900295 StringPiece rhs;
296 if (define_start_)
Shinichiro Hamajia4d0ecb2015-06-24 22:08:30 +0900297 rhs = buf_.substr(define_start_, l_ - define_start_ - 1);
Shinichiro Hamaji66bd7bc2015-06-19 16:54:06 +0900298 ast->rhs = ParseExpr(rhs, ParseExprOpt::DEFINE);
Shinichiro Hamaji81699be2015-06-22 18:07:38 +0900299 ast->orig_rhs = rhs;
Shinichiro Hamaji810fd032015-06-17 04:38:03 +0900300 ast->op = AssignOp::EQ;
Shinichiro Hamaji420f7752015-06-26 04:02:02 +0900301 ast->directive = current_directive_;
Shinichiro Hamaji810fd032015-06-17 04:38:03 +0900302 out_asts_->push_back(ast);
303 define_name_.clear();
304 }
305
Shinichiro Hamajid146f4c2015-06-17 17:51:24 +0900306 void EnterIf(IfAST* ast) {
307 IfState* st = new IfState();
308 st->ast = ast;
309 st->is_in_else = false;
310 st->num_nest = num_if_nest_;
311 if_stack_.push(st);
312 out_asts_ = &ast->true_asts;
313 }
314
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900315 void ParseIfdef(StringPiece line, StringPiece directive) {
316 IfAST* ast = new IfAST();
317 ast->set_loc(loc_);
318 ast->op = directive[2] == 'n' ? CondOp::IFNDEF : CondOp::IFDEF;
Shinichiro Hamaji66bd7bc2015-06-19 16:54:06 +0900319 ast->lhs = ParseExpr(line);
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900320 ast->rhs = NULL;
321 out_asts_->push_back(ast);
Shinichiro Hamajid146f4c2015-06-17 17:51:24 +0900322 EnterIf(ast);
323 }
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900324
Shinichiro Hamajid146f4c2015-06-17 17:51:24 +0900325 bool ParseIfEqCond(StringPiece s, IfAST* ast) {
326 if (s.empty()) {
327 return false;
328 }
329
330 if (s[0] == '(' && s[s.size() - 1] == ')') {
331 s = s.substr(1, s.size() - 2);
332 char terms[] = {',', '\0'};
333 size_t n;
Shinichiro Hamaji36b326f2015-06-26 08:56:13 +0900334 ast->lhs = ParseExprImpl(loc_, s, terms, ParseExprOpt::NORMAL, &n, true);
Shinichiro Hamajid146f4c2015-06-17 17:51:24 +0900335 if (s[n] != ',')
336 return false;
337 s = TrimLeftSpace(s.substr(n+1));
Shinichiro Hamaji36b326f2015-06-26 08:56:13 +0900338 ast->rhs = ParseExprImpl(loc_, s, NULL, ParseExprOpt::NORMAL, &n);
Shinichiro Hamajiadeea692015-06-17 17:57:31 +0900339 s = TrimLeftSpace(s.substr(n));
Shinichiro Hamajid146f4c2015-06-17 17:51:24 +0900340 } else {
341 for (int i = 0; i < 2; i++) {
342 if (s.empty())
343 return false;
344 char quote = s[0];
345 if (quote != '\'' && quote != '"')
346 return false;
347 size_t end = s.find(quote, 1);
348 if (end == string::npos)
349 return false;
Shinichiro Hamaji66bd7bc2015-06-19 16:54:06 +0900350 Value* v = ParseExpr(s.substr(1, end - 1), ParseExprOpt::NORMAL);
Shinichiro Hamajid146f4c2015-06-17 17:51:24 +0900351 if (i == 0)
352 ast->lhs = v;
353 else
354 ast->rhs = v;
355 s = TrimLeftSpace(s.substr(end+1));
356 }
Shinichiro Hamajid146f4c2015-06-17 17:51:24 +0900357 }
Shinichiro Hamajiadeea692015-06-17 17:57:31 +0900358 if (!s.empty()) {
359 Error("extraneous text after `ifeq' directive");
Shinichiro Hamaji56227862015-08-05 16:53:37 +0900360 return true;
Shinichiro Hamajiadeea692015-06-17 17:57:31 +0900361 }
362 return true;
Shinichiro Hamajid146f4c2015-06-17 17:51:24 +0900363 }
364
365 void ParseIfeq(StringPiece line, StringPiece directive) {
366 IfAST* ast = new IfAST();
367 ast->set_loc(loc_);
368 ast->op = directive[2] == 'n' ? CondOp::IFNEQ : CondOp::IFEQ;
369
370 if (!ParseIfEqCond(line, ast)) {
371 Error("*** invalid syntax in conditional.");
Shinichiro Hamaji56227862015-08-05 16:53:37 +0900372 return;
Shinichiro Hamajid146f4c2015-06-17 17:51:24 +0900373 }
374
375 out_asts_->push_back(ast);
376 EnterIf(ast);
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900377 }
378
Shinichiro Hamaji6cb1c252015-06-17 16:22:51 +0900379 void ParseElse(StringPiece line, StringPiece) {
Shinichiro Hamaji56227862015-08-05 16:53:37 +0900380 if (!CheckIfStack("else"))
381 return;
Shinichiro Hamaji6cb1c252015-06-17 16:22:51 +0900382 IfState* st = if_stack_.top();
Shinichiro Hamaji56227862015-08-05 16:53:37 +0900383 if (st->is_in_else) {
Shinichiro Hamaji6cb1c252015-06-17 16:22:51 +0900384 Error("*** only one `else' per conditional.");
Shinichiro Hamaji56227862015-08-05 16:53:37 +0900385 return;
386 }
Shinichiro Hamaji6cb1c252015-06-17 16:22:51 +0900387 st->is_in_else = true;
388 out_asts_ = &st->ast->false_asts;
389
390 StringPiece next_if = TrimLeftSpace(line);
391 if (next_if.empty())
392 return;
393
394 num_if_nest_ = st->num_nest + 1;
395 if (!HandleDirective(next_if, else_if_directives_)) {
396 WARN("%s:%d: extraneous text after `else' directive", LOCF(loc_));
397 }
398 num_if_nest_ = 0;
399 }
400
401 void ParseEndif(StringPiece line, StringPiece) {
Shinichiro Hamaji56227862015-08-05 16:53:37 +0900402 if (!CheckIfStack("endif"))
403 return;
404 if (!line.empty()) {
Shinichiro Hamaji6cb1c252015-06-17 16:22:51 +0900405 Error("extraneous text after `endif` directive");
Shinichiro Hamaji56227862015-08-05 16:53:37 +0900406 return;
407 }
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900408 IfState st = *if_stack_.top();
409 for (int t = 0; t <= st.num_nest; t++) {
410 delete if_stack_.top();
411 if_stack_.pop();
412 if (if_stack_.empty()) {
413 out_asts_ = asts_;
414 } else {
415 IfState* st = if_stack_.top();
416 if (st->is_in_else)
Shinichiro Hamaji2847f092015-06-17 15:48:37 +0900417 out_asts_ = &st->ast->false_asts;
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900418 else
Shinichiro Hamaji2847f092015-06-17 15:48:37 +0900419 out_asts_ = &st->ast->true_asts;
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900420 }
421 }
422 }
423
Shinichiro Hamaji45a0c762015-06-26 06:47:10 +0900424 bool IsInExport() const {
425 return (static_cast<int>(current_directive_) &
426 static_cast<int>(AssignDirective::EXPORT));
427 }
428
429 void CreateExport(StringPiece line, bool is_export) {
430 ExportAST* ast = new ExportAST;
431 ast->set_loc(loc_);
432 ast->expr = ParseExpr(line);
433 ast->is_export = is_export;
434 out_asts_->push_back(ast);
435 }
436
437 void ParseOverride(StringPiece line, StringPiece) {
Shinichiro Hamaji420f7752015-06-26 04:02:02 +0900438 current_directive_ =
439 static_cast<AssignDirective>(
440 (static_cast<int>(current_directive_) |
441 static_cast<int>(AssignDirective::OVERRIDE)));
442 if (HandleDirective(line, assign_directives_))
443 return;
Shinichiro Hamaji45a0c762015-06-26 06:47:10 +0900444 if (IsInExport()) {
445 CreateExport(line, true);
446 }
Shinichiro Hamaji420f7752015-06-26 04:02:02 +0900447 ParseRuleOrAssign(line);
448 }
449
450 void ParseExport(StringPiece line, StringPiece) {
Shinichiro Hamaji45a0c762015-06-26 06:47:10 +0900451 current_directive_ =
452 static_cast<AssignDirective>(
453 (static_cast<int>(current_directive_) |
454 static_cast<int>(AssignDirective::EXPORT)));
455 if (HandleDirective(line, assign_directives_))
456 return;
457 CreateExport(line, true);
458 ParseRuleOrAssign(line);
Shinichiro Hamaji420f7752015-06-26 04:02:02 +0900459 }
460
461 void ParseUnexport(StringPiece line, StringPiece) {
Shinichiro Hamaji45a0c762015-06-26 06:47:10 +0900462 CreateExport(line, false);
Shinichiro Hamaji420f7752015-06-26 04:02:02 +0900463 }
464
Shinichiro Hamaji56227862015-08-05 16:53:37 +0900465 bool CheckIfStack(const char* keyword) {
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900466 if (if_stack_.empty()) {
467 Error(StringPrintf("*** extraneous `%s'.", keyword));
Shinichiro Hamaji56227862015-08-05 16:53:37 +0900468 return false;
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900469 }
Shinichiro Hamaji56227862015-08-05 16:53:37 +0900470 return true;
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900471 }
472
Shinichiro Hamaji5562caf2015-06-17 17:08:40 +0900473 StringPiece RemoveComment(StringPiece line) {
Shinichiro Hamajieafd0522015-06-18 16:46:02 +0900474 size_t i = FindOutsideParen(line, '#');
475 if (i == string::npos)
476 return line;
477 return line.substr(0, i);
Shinichiro Hamaji5562caf2015-06-17 17:08:40 +0900478 }
479
480 StringPiece GetDirective(StringPiece line) {
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900481 if (line.size() < shortest_directive_len_)
Shinichiro Hamaji5562caf2015-06-17 17:08:40 +0900482 return StringPiece();
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900483 StringPiece prefix = line.substr(0, longest_directive_len_ + 1);
Shinichiro Hamaji5562caf2015-06-17 17:08:40 +0900484 size_t space_index = prefix.find_first_of(" \t#");
485 return prefix.substr(0, space_index);
486 }
487
488 bool HandleDirective(StringPiece line, const DirectiveMap* directive_map) {
489 StringPiece directive = GetDirective(line);
Shinichiro Hamaji6cb1c252015-06-17 16:22:51 +0900490 auto found = directive_map->find(directive);
491 if (found == directive_map->end())
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900492 return false;
493
Shinichiro Hamaji5562caf2015-06-17 17:08:40 +0900494 StringPiece rest = TrimRightSpace(RemoveComment(TrimLeftSpace(
Shinichiro Hamajid146f4c2015-06-17 17:51:24 +0900495 line.substr(directive.size()))));
Shinichiro Hamaji810fd032015-06-17 04:38:03 +0900496 (this->*found->second)(rest, directive);
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900497 return true;
498 }
499
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900500 StringPiece buf_;
501 size_t l_;
502 ParserState state_;
503
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900504 vector<AST*>* asts_;
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900505 vector<AST*>* out_asts_;
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900506
Shinichiro Hamaji810fd032015-06-17 04:38:03 +0900507 StringPiece define_name_;
508 size_t define_start_;
509 int define_start_line_;
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900510
Shinichiro Hamaji420f7752015-06-26 04:02:02 +0900511 StringPiece orig_line_with_directives_;
512 AssignDirective current_directive_;
513
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900514 int num_if_nest_;
515 stack<IfState*> if_stack_;
516
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900517 Loc loc_;
518 bool fixed_lineno_;
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900519
Shinichiro Hamaji6cb1c252015-06-17 16:22:51 +0900520 static DirectiveMap* make_directives_;
521 static DirectiveMap* else_if_directives_;
Shinichiro Hamaji420f7752015-06-26 04:02:02 +0900522 static DirectiveMap* assign_directives_;
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900523 static size_t shortest_directive_len_;
524 static size_t longest_directive_len_;
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900525};
526
527void Parse(Makefile* mk) {
Shinichiro Hamaji6b1a11a2015-06-30 16:21:19 +0900528 COLLECT_STATS("parse file time");
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900529 Parser parser(StringPiece(mk->buf(), mk->len()),
530 mk->filename().c_str(),
531 mk->mutable_asts());
532 parser.Parse();
533}
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900534
Shinichiro Hamaji80456fb2015-06-18 14:56:10 +0900535void Parse(StringPiece buf, const Loc& loc, vector<AST*>* out_asts) {
Shinichiro Hamaji6b1a11a2015-06-30 16:21:19 +0900536 COLLECT_STATS("parse eval time");
Shinichiro Hamaji80456fb2015-06-18 14:56:10 +0900537 Parser parser(buf, loc, out_asts);
538 parser.Parse();
539}
540
Shinichiro Hamaji631a9f82015-07-05 14:18:15 +0900541void ParseNotAfterRule(StringPiece buf, const Loc& loc,
542 vector<AST*>* out_asts) {
543 Parser parser(buf, loc, out_asts);
544 parser.set_state(ParserState::NOT_AFTER_RULE);
545 parser.Parse();
546}
547
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900548void InitParser() {
549 Parser::Init();
550}
551
552void QuitParser() {
553 Parser::Quit();
554}
555
Shinichiro Hamaji6cb1c252015-06-17 16:22:51 +0900556Parser::DirectiveMap* Parser::make_directives_;
557Parser::DirectiveMap* Parser::else_if_directives_;
Shinichiro Hamaji420f7752015-06-26 04:02:02 +0900558Parser::DirectiveMap* Parser::assign_directives_;
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900559size_t Parser::shortest_directive_len_;
560size_t Parser::longest_directive_len_;
Shinichiro Hamaji9b16bda2015-06-19 14:25:17 +0900561
562void ParseAssignStatement(StringPiece line, size_t sep,
563 StringPiece* lhs, StringPiece* rhs, AssignOp* op) {
564 CHECK(sep != 0);
565 *op = AssignOp::EQ;
566 size_t lhs_end = sep;
567 switch (line[sep-1]) {
568 case ':':
569 lhs_end--;
570 *op = AssignOp::COLON_EQ;
571 break;
572 case '+':
573 lhs_end--;
574 *op = AssignOp::PLUS_EQ;
575 break;
576 case '?':
577 lhs_end--;
578 *op = AssignOp::QUESTION_EQ;
579 break;
580 }
581 *lhs = TrimSpace(line.substr(0, lhs_end));
582 *rhs = TrimSpace(line.substr(sep + 1));
583}