blob: a48331028833d4b156d50fc6da6020ea3f01839e [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"
26#include "string_piece.h"
Shinichiro Hamaji810fd032015-06-17 04:38:03 +090027#include "strutil.h"
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090028#include "value.h"
29
30enum struct ParserState {
31 NOT_AFTER_RULE = 0,
32 AFTER_RULE,
33 MAYBE_AFTER_RULE,
34};
35
36class Parser {
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +090037 struct IfState {
38 IfAST* ast;
39 bool is_in_else;
40 int num_nest;
41 };
42
Shinichiro Hamaji6cb1c252015-06-17 16:22:51 +090043 typedef void (Parser::*DirectiveHandler)(
44 StringPiece line, StringPiece directive);
45 typedef unordered_map<StringPiece, DirectiveHandler> DirectiveMap;
46
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090047 public:
48 Parser(StringPiece buf, const char* filename, vector<AST*>* asts)
49 : buf_(buf),
50 state_(ParserState::NOT_AFTER_RULE),
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +090051 asts_(asts),
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090052 out_asts_(asts),
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +090053 num_if_nest_(0),
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090054 loc_(filename, 0),
55 fixed_lineno_(false) {
56 }
57
Shinichiro Hamaji80456fb2015-06-18 14:56:10 +090058 Parser(StringPiece buf, const Loc& loc, vector<AST*>* asts)
59 : buf_(buf),
60 state_(ParserState::NOT_AFTER_RULE),
61 asts_(asts),
62 out_asts_(asts),
63 num_if_nest_(0),
64 loc_(loc),
65 fixed_lineno_(true) {
66 }
67
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090068 ~Parser() {
69 }
70
71 void Parse() {
72 l_ = 0;
73
74 for (l_ = 0; l_ < buf_.size();) {
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090075 size_t lf_cnt = 0;
76 size_t e = FindEndOfLine(&lf_cnt);
Shinichiro Hamaji8ee8c372015-06-16 16:19:40 +090077 if (!fixed_lineno_)
Shinichiro Hamajib3af68b2015-06-24 20:47:57 +090078 loc_.lineno++;
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090079 StringPiece line(buf_.data() + l_, e - l_);
Shinichiro Hamaji420f7752015-06-26 04:02:02 +090080 orig_line_with_directives_ = line;
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090081 ParseLine(line);
Shinichiro Hamajib3af68b2015-06-24 20:47:57 +090082 if (!fixed_lineno_)
83 loc_.lineno += lf_cnt - 1;
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090084 if (e == buf_.size())
85 break;
86
87 l_ = e + 1;
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090088 }
89 }
90
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +090091 static void Init() {
Shinichiro Hamaji6cb1c252015-06-17 16:22:51 +090092 make_directives_ = new DirectiveMap;
Shinichiro Hamaji14b8bea2015-06-17 03:14:28 +090093 (*make_directives_)["include"] = &Parser::ParseInclude;
94 (*make_directives_)["-include"] = &Parser::ParseInclude;
95 (*make_directives_)["sinclude"] = &Parser::ParseInclude;
Shinichiro Hamaji810fd032015-06-17 04:38:03 +090096 (*make_directives_)["define"] = &Parser::ParseDefine;
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +090097 (*make_directives_)["ifdef"] = &Parser::ParseIfdef;
98 (*make_directives_)["ifndef"] = &Parser::ParseIfdef;
Shinichiro Hamajid146f4c2015-06-17 17:51:24 +090099 (*make_directives_)["ifeq"] = &Parser::ParseIfeq;
100 (*make_directives_)["ifneq"] = &Parser::ParseIfeq;
Shinichiro Hamaji6cb1c252015-06-17 16:22:51 +0900101 (*make_directives_)["else"] = &Parser::ParseElse;
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900102 (*make_directives_)["endif"] = &Parser::ParseEndif;
Shinichiro Hamaji420f7752015-06-26 04:02:02 +0900103 (*make_directives_)["override"] = &Parser::ParseOverride;
104 (*make_directives_)["export"] = &Parser::ParseExport;
105 (*make_directives_)["unexport"] = &Parser::ParseUnexport;
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900106
Shinichiro Hamaji6cb1c252015-06-17 16:22:51 +0900107 else_if_directives_ = new DirectiveMap;
108 (*else_if_directives_)["ifdef"] = &Parser::ParseIfdef;
109 (*else_if_directives_)["ifndef"] = &Parser::ParseIfdef;
Shinichiro Hamaji6aeab2a2015-06-26 09:12:01 +0900110 (*else_if_directives_)["ifeq"] = &Parser::ParseIfeq;
111 (*else_if_directives_)["ifneq"] = &Parser::ParseIfeq;
Shinichiro Hamaji6cb1c252015-06-17 16:22:51 +0900112
Shinichiro Hamaji420f7752015-06-26 04:02:02 +0900113 assign_directives_ = new DirectiveMap;
114 (*assign_directives_)["define"] = &Parser::ParseDefine;
115 (*assign_directives_)["export"] = &Parser::ParseExport;
116 (*assign_directives_)["override"] = &Parser::ParseOverride;
117
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900118 shortest_directive_len_ = 9999;
119 longest_directive_len_ = 0;
120 for (auto p : *make_directives_) {
121 size_t len = p.first.size();
122 shortest_directive_len_ = min(len, shortest_directive_len_);
123 longest_directive_len_ = max(len, longest_directive_len_);
124 }
125 }
126
127 static void Quit() {
128 delete make_directives_;
129 }
130
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900131 private:
132 void Error(const string& msg) {
Shinichiro Hamaji8ee8c372015-06-16 16:19:40 +0900133 ERROR("%s:%d: %s", LOCF(loc_), msg.c_str());
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900134 }
135
136 size_t FindEndOfLine(size_t* lf_cnt) {
Shinichiro Hamaji14bb2792015-06-25 18:24:11 +0900137 return ::FindEndOfLine(buf_, l_, lf_cnt);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900138 }
139
Shinichiro Hamaji36b326f2015-06-26 08:56:13 +0900140 Value* ParseExpr(StringPiece s, ParseExprOpt opt = ParseExprOpt::NORMAL) {
141 return ::ParseExpr(loc_, s, opt);
142 }
143
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900144 void ParseLine(StringPiece line) {
145 if (line.empty() || (line.size() == 1 && line[0] == '\r'))
146 return;
147
Shinichiro Hamaji810fd032015-06-17 04:38:03 +0900148 if (!define_name_.empty()) {
149 ParseInsideDefine(line);
150 return;
151 }
152
Shinichiro Hamaji420f7752015-06-26 04:02:02 +0900153 current_directive_ = AssignDirective::NONE;
154
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900155 if (line[0] == '\t' && state_ != ParserState::NOT_AFTER_RULE) {
156 CommandAST* ast = new CommandAST();
Shinichiro Hamaji861bd642015-06-19 16:59:13 +0900157 ast->set_loc(loc_);
Shinichiro Hamaji66bd7bc2015-06-19 16:54:06 +0900158 ast->expr = ParseExpr(line.substr(1), ParseExprOpt::COMMAND);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900159 out_asts_->push_back(ast);
160 return;
161 }
162
Shinichiro Hamaji32750622015-06-17 14:57:33 +0900163 line = TrimLeftSpace(line);
Shinichiro Hamajid4e81932015-06-17 04:40:45 +0900164
165 if (line[0] == '#')
166 return;
167
Shinichiro Hamaji6cb1c252015-06-17 16:22:51 +0900168 if (HandleDirective(line, make_directives_)) {
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900169 return;
170 }
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900171
Shinichiro Hamaji420f7752015-06-26 04:02:02 +0900172 ParseRuleOrAssign(line);
173 }
174
175 void ParseRuleOrAssign(StringPiece line) {
Shinichiro Hamaji76ff9832015-06-18 17:11:22 +0900176 size_t sep = FindTwoOutsideParen(line, ':', '=');
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900177 if (sep == string::npos) {
Shinichiro Hamaji14b8bea2015-06-17 03:14:28 +0900178 ParseRule(line, sep);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900179 } else if (line[sep] == '=') {
Shinichiro Hamaji14b8bea2015-06-17 03:14:28 +0900180 ParseAssign(line, sep);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900181 } else if (line.get(sep+1) == '=') {
Shinichiro Hamaji14b8bea2015-06-17 03:14:28 +0900182 ParseAssign(line, sep+1);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900183 } else if (line[sep] == ':') {
Shinichiro Hamaji14b8bea2015-06-17 03:14:28 +0900184 ParseRule(line, sep);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900185 } else {
186 CHECK(false);
187 }
188 }
189
Shinichiro Hamaji14b8bea2015-06-17 03:14:28 +0900190 void ParseRule(StringPiece line, size_t sep) {
Shinichiro Hamaji420f7752015-06-26 04:02:02 +0900191 if (current_directive_ != AssignDirective::NONE) {
Shinichiro Hamaji45a0c762015-06-26 06:47:10 +0900192 if (IsInExport())
193 return;
Shinichiro Hamaji420f7752015-06-26 04:02:02 +0900194 if (sep != string::npos) {
195 sep += orig_line_with_directives_.size() - line.size();
196 }
197 line = orig_line_with_directives_;
Shinichiro Hamajidf066c32015-06-26 09:09:26 +0900198 }
199
Shinichiro Hamaji6aeab2a2015-06-26 09:12:01 +0900200 line = TrimLeftSpace(line);
Shinichiro Hamajidf066c32015-06-26 09:09:26 +0900201 if (line.empty())
202 return;
203
204 if (orig_line_with_directives_[0] == '\t') {
Shinichiro Hamaji2bed7702015-06-26 07:56:28 +0900205 Error("*** commands commence before first target.");
Shinichiro Hamaji420f7752015-06-26 04:02:02 +0900206 }
207
Shinichiro Hamaji76ff9832015-06-18 17:11:22 +0900208 const bool is_rule = sep != string::npos && line[sep] == ':';
Shinichiro Hamaji810fd032015-06-17 04:38:03 +0900209 RuleAST* ast = new RuleAST();
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900210 ast->set_loc(loc_);
211
Shinichiro Hamaji76ff9832015-06-18 17:11:22 +0900212 size_t found = FindTwoOutsideParen(line.substr(sep + 1), '=', ';');
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900213 if (found != string::npos) {
214 found += sep + 1;
215 ast->term = line[found];
Shinichiro Hamaji66bd7bc2015-06-19 16:54:06 +0900216 ParseExprOpt opt =
217 ast->term == ';' ? ParseExprOpt::COMMAND : ParseExprOpt::NORMAL;
218 ast->after_term = ParseExpr(TrimLeftSpace(line.substr(found + 1)), opt);
219 ast->expr = ParseExpr(TrimSpace(line.substr(0, found)));
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900220 } else {
221 ast->term = 0;
222 ast->after_term = NULL;
Shinichiro Hamajidf066c32015-06-26 09:09:26 +0900223 ast->expr = ParseExpr(line);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900224 }
225 out_asts_->push_back(ast);
226 state_ = is_rule ? ParserState::AFTER_RULE : ParserState::MAYBE_AFTER_RULE;
227 }
228
Shinichiro Hamaji14b8bea2015-06-17 03:14:28 +0900229 void ParseAssign(StringPiece line, size_t sep) {
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900230 if (sep == 0)
231 Error("*** empty variable name ***");
Shinichiro Hamaji9b16bda2015-06-19 14:25:17 +0900232 StringPiece lhs;
233 StringPiece rhs;
234 AssignOp op;
235 ParseAssignStatement(line, sep, &lhs, &rhs, &op);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900236
Shinichiro Hamaji810fd032015-06-17 04:38:03 +0900237 AssignAST* ast = new AssignAST();
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900238 ast->set_loc(loc_);
Shinichiro Hamaji66bd7bc2015-06-19 16:54:06 +0900239 ast->lhs = ParseExpr(lhs);
240 ast->rhs = ParseExpr(rhs);
Shinichiro Hamaji81699be2015-06-22 18:07:38 +0900241 ast->orig_rhs = rhs;
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900242 ast->op = op;
Shinichiro Hamaji420f7752015-06-26 04:02:02 +0900243 ast->directive = current_directive_;
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900244 out_asts_->push_back(ast);
245 state_ = ParserState::NOT_AFTER_RULE;
246 }
247
Shinichiro Hamaji14b8bea2015-06-17 03:14:28 +0900248 void ParseInclude(StringPiece line, StringPiece directive) {
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900249 IncludeAST* ast = new IncludeAST();
Shinichiro Hamaji861bd642015-06-19 16:59:13 +0900250 ast->set_loc(loc_);
Shinichiro Hamaji66bd7bc2015-06-19 16:54:06 +0900251 ast->expr = ParseExpr(line);
Shinichiro Hamajiefad2dd2015-06-17 03:08:02 +0900252 ast->should_exist = directive[0] == 'i';
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900253 out_asts_->push_back(ast);
Shinichiro Hamajiff4584d2015-06-24 17:45:14 +0900254 state_ = ParserState::NOT_AFTER_RULE;
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900255 }
256
Shinichiro Hamaji810fd032015-06-17 04:38:03 +0900257 void ParseDefine(StringPiece line, StringPiece) {
258 if (line.empty()) {
259 Error("*** empty variable name.");
260 }
261 define_name_ = line;
262 define_start_ = 0;
263 define_start_line_ = loc_.lineno;
Shinichiro Hamajiff4584d2015-06-24 17:45:14 +0900264 state_ = ParserState::NOT_AFTER_RULE;
Shinichiro Hamaji810fd032015-06-17 04:38:03 +0900265 }
266
267 void ParseInsideDefine(StringPiece line) {
Shinichiro Hamaji5562caf2015-06-17 17:08:40 +0900268 line = TrimLeftSpace(line);
269 if (GetDirective(line) != "endef") {
Shinichiro Hamaji810fd032015-06-17 04:38:03 +0900270 if (define_start_ == 0)
271 define_start_ = l_;
272 return;
273 }
274
Shinichiro Hamaji5562caf2015-06-17 17:08:40 +0900275 StringPiece rest = TrimRightSpace(RemoveComment(TrimLeftSpace(
276 line.substr(sizeof("endef")))));
277 if (!rest.empty()) {
278 WARN("%s:%d: extraneous text after `endef' directive", LOCF(loc_));
279 }
280
Shinichiro Hamaji810fd032015-06-17 04:38:03 +0900281 AssignAST* ast = new AssignAST();
282 ast->set_loc(Loc(loc_.filename, define_start_line_));
Shinichiro Hamaji66bd7bc2015-06-19 16:54:06 +0900283 ast->lhs = ParseExpr(define_name_);
Shinichiro Hamaji810fd032015-06-17 04:38:03 +0900284 StringPiece rhs;
285 if (define_start_)
Shinichiro Hamajia4d0ecb2015-06-24 22:08:30 +0900286 rhs = buf_.substr(define_start_, l_ - define_start_ - 1);
Shinichiro Hamaji66bd7bc2015-06-19 16:54:06 +0900287 ast->rhs = ParseExpr(rhs, ParseExprOpt::DEFINE);
Shinichiro Hamaji81699be2015-06-22 18:07:38 +0900288 ast->orig_rhs = rhs;
Shinichiro Hamaji810fd032015-06-17 04:38:03 +0900289 ast->op = AssignOp::EQ;
Shinichiro Hamaji420f7752015-06-26 04:02:02 +0900290 ast->directive = current_directive_;
Shinichiro Hamaji810fd032015-06-17 04:38:03 +0900291 out_asts_->push_back(ast);
292 define_name_.clear();
293 }
294
Shinichiro Hamajid146f4c2015-06-17 17:51:24 +0900295 void EnterIf(IfAST* ast) {
296 IfState* st = new IfState();
297 st->ast = ast;
298 st->is_in_else = false;
299 st->num_nest = num_if_nest_;
300 if_stack_.push(st);
301 out_asts_ = &ast->true_asts;
302 }
303
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900304 void ParseIfdef(StringPiece line, StringPiece directive) {
305 IfAST* ast = new IfAST();
306 ast->set_loc(loc_);
307 ast->op = directive[2] == 'n' ? CondOp::IFNDEF : CondOp::IFDEF;
Shinichiro Hamaji66bd7bc2015-06-19 16:54:06 +0900308 ast->lhs = ParseExpr(line);
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900309 ast->rhs = NULL;
310 out_asts_->push_back(ast);
Shinichiro Hamajid146f4c2015-06-17 17:51:24 +0900311 EnterIf(ast);
312 }
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900313
Shinichiro Hamajid146f4c2015-06-17 17:51:24 +0900314 bool ParseIfEqCond(StringPiece s, IfAST* ast) {
315 if (s.empty()) {
316 return false;
317 }
318
319 if (s[0] == '(' && s[s.size() - 1] == ')') {
320 s = s.substr(1, s.size() - 2);
321 char terms[] = {',', '\0'};
322 size_t n;
Shinichiro Hamaji36b326f2015-06-26 08:56:13 +0900323 ast->lhs = ParseExprImpl(loc_, s, terms, ParseExprOpt::NORMAL, &n, true);
Shinichiro Hamajid146f4c2015-06-17 17:51:24 +0900324 if (s[n] != ',')
325 return false;
326 s = TrimLeftSpace(s.substr(n+1));
Shinichiro Hamaji36b326f2015-06-26 08:56:13 +0900327 ast->rhs = ParseExprImpl(loc_, s, NULL, ParseExprOpt::NORMAL, &n);
Shinichiro Hamajiadeea692015-06-17 17:57:31 +0900328 s = TrimLeftSpace(s.substr(n));
Shinichiro Hamajid146f4c2015-06-17 17:51:24 +0900329 } else {
330 for (int i = 0; i < 2; i++) {
331 if (s.empty())
332 return false;
333 char quote = s[0];
334 if (quote != '\'' && quote != '"')
335 return false;
336 size_t end = s.find(quote, 1);
337 if (end == string::npos)
338 return false;
Shinichiro Hamaji66bd7bc2015-06-19 16:54:06 +0900339 Value* v = ParseExpr(s.substr(1, end - 1), ParseExprOpt::NORMAL);
Shinichiro Hamajid146f4c2015-06-17 17:51:24 +0900340 if (i == 0)
341 ast->lhs = v;
342 else
343 ast->rhs = v;
344 s = TrimLeftSpace(s.substr(end+1));
345 }
Shinichiro Hamajid146f4c2015-06-17 17:51:24 +0900346 }
Shinichiro Hamajiadeea692015-06-17 17:57:31 +0900347 if (!s.empty()) {
348 Error("extraneous text after `ifeq' directive");
349 }
350 return true;
Shinichiro Hamajid146f4c2015-06-17 17:51:24 +0900351 }
352
353 void ParseIfeq(StringPiece line, StringPiece directive) {
354 IfAST* ast = new IfAST();
355 ast->set_loc(loc_);
356 ast->op = directive[2] == 'n' ? CondOp::IFNEQ : CondOp::IFEQ;
357
358 if (!ParseIfEqCond(line, ast)) {
359 Error("*** invalid syntax in conditional.");
360 }
361
362 out_asts_->push_back(ast);
363 EnterIf(ast);
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900364 }
365
Shinichiro Hamaji6cb1c252015-06-17 16:22:51 +0900366 void ParseElse(StringPiece line, StringPiece) {
367 CheckIfStack("else");
368 IfState* st = if_stack_.top();
369 if (st->is_in_else)
370 Error("*** only one `else' per conditional.");
371 st->is_in_else = true;
372 out_asts_ = &st->ast->false_asts;
373
374 StringPiece next_if = TrimLeftSpace(line);
375 if (next_if.empty())
376 return;
377
378 num_if_nest_ = st->num_nest + 1;
379 if (!HandleDirective(next_if, else_if_directives_)) {
380 WARN("%s:%d: extraneous text after `else' directive", LOCF(loc_));
381 }
382 num_if_nest_ = 0;
383 }
384
385 void ParseEndif(StringPiece line, StringPiece) {
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900386 CheckIfStack("endif");
Shinichiro Hamaji6cb1c252015-06-17 16:22:51 +0900387 if (!line.empty())
388 Error("extraneous text after `endif` directive");
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900389 IfState st = *if_stack_.top();
390 for (int t = 0; t <= st.num_nest; t++) {
391 delete if_stack_.top();
392 if_stack_.pop();
393 if (if_stack_.empty()) {
394 out_asts_ = asts_;
395 } else {
396 IfState* st = if_stack_.top();
397 if (st->is_in_else)
Shinichiro Hamaji2847f092015-06-17 15:48:37 +0900398 out_asts_ = &st->ast->false_asts;
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900399 else
Shinichiro Hamaji2847f092015-06-17 15:48:37 +0900400 out_asts_ = &st->ast->true_asts;
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900401 }
402 }
403 }
404
Shinichiro Hamaji45a0c762015-06-26 06:47:10 +0900405 bool IsInExport() const {
406 return (static_cast<int>(current_directive_) &
407 static_cast<int>(AssignDirective::EXPORT));
408 }
409
410 void CreateExport(StringPiece line, bool is_export) {
411 ExportAST* ast = new ExportAST;
412 ast->set_loc(loc_);
413 ast->expr = ParseExpr(line);
414 ast->is_export = is_export;
415 out_asts_->push_back(ast);
416 }
417
418 void ParseOverride(StringPiece line, StringPiece) {
Shinichiro Hamaji420f7752015-06-26 04:02:02 +0900419 current_directive_ =
420 static_cast<AssignDirective>(
421 (static_cast<int>(current_directive_) |
422 static_cast<int>(AssignDirective::OVERRIDE)));
423 if (HandleDirective(line, assign_directives_))
424 return;
Shinichiro Hamaji45a0c762015-06-26 06:47:10 +0900425 if (IsInExport()) {
426 CreateExport(line, true);
427 }
Shinichiro Hamaji420f7752015-06-26 04:02:02 +0900428 ParseRuleOrAssign(line);
429 }
430
431 void ParseExport(StringPiece line, StringPiece) {
Shinichiro Hamaji45a0c762015-06-26 06:47:10 +0900432 current_directive_ =
433 static_cast<AssignDirective>(
434 (static_cast<int>(current_directive_) |
435 static_cast<int>(AssignDirective::EXPORT)));
436 if (HandleDirective(line, assign_directives_))
437 return;
438 CreateExport(line, true);
439 ParseRuleOrAssign(line);
Shinichiro Hamaji420f7752015-06-26 04:02:02 +0900440 }
441
442 void ParseUnexport(StringPiece line, StringPiece) {
Shinichiro Hamaji45a0c762015-06-26 06:47:10 +0900443 CreateExport(line, false);
Shinichiro Hamaji420f7752015-06-26 04:02:02 +0900444 }
445
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900446 void CheckIfStack(const char* keyword) {
447 if (if_stack_.empty()) {
448 Error(StringPrintf("*** extraneous `%s'.", keyword));
449 }
450 }
451
Shinichiro Hamaji5562caf2015-06-17 17:08:40 +0900452 StringPiece RemoveComment(StringPiece line) {
Shinichiro Hamajieafd0522015-06-18 16:46:02 +0900453 size_t i = FindOutsideParen(line, '#');
454 if (i == string::npos)
455 return line;
456 return line.substr(0, i);
Shinichiro Hamaji5562caf2015-06-17 17:08:40 +0900457 }
458
459 StringPiece GetDirective(StringPiece line) {
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900460 if (line.size() < shortest_directive_len_)
Shinichiro Hamaji5562caf2015-06-17 17:08:40 +0900461 return StringPiece();
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900462 StringPiece prefix = line.substr(0, longest_directive_len_ + 1);
Shinichiro Hamaji5562caf2015-06-17 17:08:40 +0900463 size_t space_index = prefix.find_first_of(" \t#");
464 return prefix.substr(0, space_index);
465 }
466
467 bool HandleDirective(StringPiece line, const DirectiveMap* directive_map) {
468 StringPiece directive = GetDirective(line);
Shinichiro Hamaji6cb1c252015-06-17 16:22:51 +0900469 auto found = directive_map->find(directive);
470 if (found == directive_map->end())
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900471 return false;
472
Shinichiro Hamaji5562caf2015-06-17 17:08:40 +0900473 StringPiece rest = TrimRightSpace(RemoveComment(TrimLeftSpace(
Shinichiro Hamajid146f4c2015-06-17 17:51:24 +0900474 line.substr(directive.size()))));
Shinichiro Hamaji810fd032015-06-17 04:38:03 +0900475 (this->*found->second)(rest, directive);
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900476 return true;
477 }
478
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900479 StringPiece buf_;
480 size_t l_;
481 ParserState state_;
482
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900483 vector<AST*>* asts_;
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900484 vector<AST*>* out_asts_;
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900485
Shinichiro Hamaji810fd032015-06-17 04:38:03 +0900486 StringPiece define_name_;
487 size_t define_start_;
488 int define_start_line_;
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900489
Shinichiro Hamaji420f7752015-06-26 04:02:02 +0900490 StringPiece orig_line_with_directives_;
491 AssignDirective current_directive_;
492
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900493 int num_if_nest_;
494 stack<IfState*> if_stack_;
495
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900496 Loc loc_;
497 bool fixed_lineno_;
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900498
Shinichiro Hamaji6cb1c252015-06-17 16:22:51 +0900499 static DirectiveMap* make_directives_;
500 static DirectiveMap* else_if_directives_;
Shinichiro Hamaji420f7752015-06-26 04:02:02 +0900501 static DirectiveMap* assign_directives_;
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900502 static size_t shortest_directive_len_;
503 static size_t longest_directive_len_;
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900504};
505
506void Parse(Makefile* mk) {
507 Parser parser(StringPiece(mk->buf(), mk->len()),
508 mk->filename().c_str(),
509 mk->mutable_asts());
510 parser.Parse();
511}
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900512
Shinichiro Hamaji80456fb2015-06-18 14:56:10 +0900513void Parse(StringPiece buf, const Loc& loc, vector<AST*>* out_asts) {
514 Parser parser(buf, loc, out_asts);
515 parser.Parse();
516}
517
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900518void InitParser() {
519 Parser::Init();
520}
521
522void QuitParser() {
523 Parser::Quit();
524}
525
Shinichiro Hamaji6cb1c252015-06-17 16:22:51 +0900526Parser::DirectiveMap* Parser::make_directives_;
527Parser::DirectiveMap* Parser::else_if_directives_;
Shinichiro Hamaji420f7752015-06-26 04:02:02 +0900528Parser::DirectiveMap* Parser::assign_directives_;
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900529size_t Parser::shortest_directive_len_;
530size_t Parser::longest_directive_len_;
Shinichiro Hamaji9b16bda2015-06-19 14:25:17 +0900531
532void ParseAssignStatement(StringPiece line, size_t sep,
533 StringPiece* lhs, StringPiece* rhs, AssignOp* op) {
534 CHECK(sep != 0);
535 *op = AssignOp::EQ;
536 size_t lhs_end = sep;
537 switch (line[sep-1]) {
538 case ':':
539 lhs_end--;
540 *op = AssignOp::COLON_EQ;
541 break;
542 case '+':
543 lhs_end--;
544 *op = AssignOp::PLUS_EQ;
545 break;
546 case '?':
547 lhs_end--;
548 *op = AssignOp::QUESTION_EQ;
549 break;
550 }
551 *lhs = TrimSpace(line.substr(0, lhs_end));
552 *rhs = TrimSpace(line.substr(sep + 1));
553}