blob: 2816e2827d2828318575ef71a326f666fb8ccb34 [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 Hamaji6cb1c252015-06-17 16:22:51 +090070 (*make_directives_)["else"] = &Parser::ParseElse;
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +090071 (*make_directives_)["endif"] = &Parser::ParseEndif;
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +090072
Shinichiro Hamaji6cb1c252015-06-17 16:22:51 +090073 else_if_directives_ = new DirectiveMap;
74 (*else_if_directives_)["ifdef"] = &Parser::ParseIfdef;
75 (*else_if_directives_)["ifndef"] = &Parser::ParseIfdef;
76
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +090077 shortest_directive_len_ = 9999;
78 longest_directive_len_ = 0;
79 for (auto p : *make_directives_) {
80 size_t len = p.first.size();
81 shortest_directive_len_ = min(len, shortest_directive_len_);
82 longest_directive_len_ = max(len, longest_directive_len_);
83 }
84 }
85
86 static void Quit() {
87 delete make_directives_;
88 }
89
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090090 private:
91 void Error(const string& msg) {
Shinichiro Hamaji8ee8c372015-06-16 16:19:40 +090092 ERROR("%s:%d: %s", LOCF(loc_), msg.c_str());
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090093 }
94
95 size_t FindEndOfLine(size_t* lf_cnt) {
96 size_t e = l_;
97 bool prev_backslash = false;
98 for (; e < buf_.size(); e++) {
99 char c = buf_[e];
100 if (c == '\\') {
101 prev_backslash = !prev_backslash;
102 } else if (c == '\n') {
103 ++*lf_cnt;
104 if (!prev_backslash) {
105 return e;
106 }
107 } else if (c != '\r') {
108 prev_backslash = false;
109 }
110 }
111 return e;
112 }
113
114 void ParseLine(StringPiece line) {
115 if (line.empty() || (line.size() == 1 && line[0] == '\r'))
116 return;
117
Shinichiro Hamaji810fd032015-06-17 04:38:03 +0900118 if (!define_name_.empty()) {
119 ParseInsideDefine(line);
120 return;
121 }
122
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900123 if (line[0] == '\t' && state_ != ParserState::NOT_AFTER_RULE) {
124 CommandAST* ast = new CommandAST();
125 ast->expr = ParseExpr(line.substr(1), true);
126 out_asts_->push_back(ast);
127 return;
128 }
129
Shinichiro Hamaji32750622015-06-17 14:57:33 +0900130 line = TrimLeftSpace(line);
Shinichiro Hamajid4e81932015-06-17 04:40:45 +0900131
132 if (line[0] == '#')
133 return;
134
Shinichiro Hamaji6cb1c252015-06-17 16:22:51 +0900135 if (HandleDirective(line, make_directives_)) {
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900136 return;
137 }
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900138
139 size_t sep = line.find_first_of(STRING_PIECE("=:"));
140 if (sep == string::npos) {
Shinichiro Hamaji14b8bea2015-06-17 03:14:28 +0900141 ParseRule(line, sep);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900142 } else if (line[sep] == '=') {
Shinichiro Hamaji14b8bea2015-06-17 03:14:28 +0900143 ParseAssign(line, sep);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900144 } else if (line.get(sep+1) == '=') {
Shinichiro Hamaji14b8bea2015-06-17 03:14:28 +0900145 ParseAssign(line, sep+1);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900146 } else if (line[sep] == ':') {
Shinichiro Hamaji14b8bea2015-06-17 03:14:28 +0900147 ParseRule(line, sep);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900148 } else {
149 CHECK(false);
150 }
151 }
152
Shinichiro Hamaji14b8bea2015-06-17 03:14:28 +0900153 void ParseRule(StringPiece line, size_t sep) {
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900154 const bool is_rule = line.find(':') != string::npos;
Shinichiro Hamaji810fd032015-06-17 04:38:03 +0900155 RuleAST* ast = new RuleAST();
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900156 ast->set_loc(loc_);
157
158 size_t found = line.substr(sep + 1).find_first_of("=;");
159 if (found != string::npos) {
160 found += sep + 1;
161 ast->term = line[found];
Shinichiro Hamaji32750622015-06-17 14:57:33 +0900162 ast->after_term = ParseExpr(TrimLeftSpace(line.substr(found + 1)),
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900163 ast->term == ';');
Shinichiro Hamaji32750622015-06-17 14:57:33 +0900164 ast->expr = ParseExpr(TrimSpace(line.substr(0, found)), false);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900165 } else {
166 ast->term = 0;
167 ast->after_term = NULL;
Shinichiro Hamaji32750622015-06-17 14:57:33 +0900168 ast->expr = ParseExpr(TrimSpace(line), false);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900169 }
170 out_asts_->push_back(ast);
171 state_ = is_rule ? ParserState::AFTER_RULE : ParserState::MAYBE_AFTER_RULE;
172 }
173
Shinichiro Hamaji14b8bea2015-06-17 03:14:28 +0900174 void ParseAssign(StringPiece line, size_t sep) {
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900175 if (sep == 0)
176 Error("*** empty variable name ***");
177 AssignOp op = AssignOp::EQ;
178 size_t lhs_end = sep;
179 switch (line[sep-1]) {
180 case ':':
181 lhs_end--;
182 op = AssignOp::COLON_EQ;
183 break;
184 case '+':
185 lhs_end--;
186 op = AssignOp::PLUS_EQ;
187 break;
188 case '?':
189 lhs_end--;
190 op = AssignOp::QUESTION_EQ;
191 break;
192 }
193
Shinichiro Hamaji810fd032015-06-17 04:38:03 +0900194 AssignAST* ast = new AssignAST();
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900195 ast->set_loc(loc_);
Shinichiro Hamaji32750622015-06-17 14:57:33 +0900196 ast->lhs = ParseExpr(TrimSpace(line.substr(0, lhs_end)), false);
197 ast->rhs = ParseExpr(TrimSpace(line.substr(sep + 1)), false);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900198 ast->op = op;
199 ast->directive = AssignDirective::NONE;
200 out_asts_->push_back(ast);
201 state_ = ParserState::NOT_AFTER_RULE;
202 }
203
Shinichiro Hamaji14b8bea2015-06-17 03:14:28 +0900204 void ParseInclude(StringPiece line, StringPiece directive) {
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900205 IncludeAST* ast = new IncludeAST();
206 ast->expr = ParseExpr(line, false);
Shinichiro Hamajiefad2dd2015-06-17 03:08:02 +0900207 ast->should_exist = directive[0] == 'i';
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900208 out_asts_->push_back(ast);
209 }
210
Shinichiro Hamaji810fd032015-06-17 04:38:03 +0900211 void ParseDefine(StringPiece line, StringPiece) {
212 if (line.empty()) {
213 Error("*** empty variable name.");
214 }
215 define_name_ = line;
216 define_start_ = 0;
217 define_start_line_ = loc_.lineno;
218 }
219
220 void ParseInsideDefine(StringPiece line) {
Shinichiro Hamaji32750622015-06-17 14:57:33 +0900221 if (TrimLeftSpace(line) != "endef") {
Shinichiro Hamaji810fd032015-06-17 04:38:03 +0900222 if (define_start_ == 0)
223 define_start_ = l_;
224 return;
225 }
226
227 AssignAST* ast = new AssignAST();
228 ast->set_loc(Loc(loc_.filename, define_start_line_));
229 ast->lhs = ParseExpr(define_name_, false);
230 StringPiece rhs;
231 if (define_start_)
Shinichiro Hamaji32750622015-06-17 14:57:33 +0900232 rhs = TrimRightSpace(buf_.substr(define_start_, l_ - define_start_));
Shinichiro Hamaji810fd032015-06-17 04:38:03 +0900233 ast->rhs = ParseExpr(rhs, false);
234 ast->op = AssignOp::EQ;
235 ast->directive = AssignDirective::NONE;
236 out_asts_->push_back(ast);
237 define_name_.clear();
238 }
239
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900240 void ParseIfdef(StringPiece line, StringPiece directive) {
241 IfAST* ast = new IfAST();
242 ast->set_loc(loc_);
243 ast->op = directive[2] == 'n' ? CondOp::IFNDEF : CondOp::IFDEF;
244 ast->lhs = ParseExpr(line, false);
245 ast->rhs = NULL;
246 out_asts_->push_back(ast);
247
248 IfState* st = new IfState();
249 st->ast = ast;
250 st->is_in_else = false;
251 st->num_nest = num_if_nest_;
Shinichiro Hamaji6cb1c252015-06-17 16:22:51 +0900252 if_stack_.push(st);
Shinichiro Hamaji2847f092015-06-17 15:48:37 +0900253 out_asts_ = &ast->true_asts;
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900254 }
255
Shinichiro Hamaji6cb1c252015-06-17 16:22:51 +0900256 void ParseElse(StringPiece line, StringPiece) {
257 CheckIfStack("else");
258 IfState* st = if_stack_.top();
259 if (st->is_in_else)
260 Error("*** only one `else' per conditional.");
261 st->is_in_else = true;
262 out_asts_ = &st->ast->false_asts;
263
264 StringPiece next_if = TrimLeftSpace(line);
265 if (next_if.empty())
266 return;
267
268 num_if_nest_ = st->num_nest + 1;
269 if (!HandleDirective(next_if, else_if_directives_)) {
270 WARN("%s:%d: extraneous text after `else' directive", LOCF(loc_));
271 }
272 num_if_nest_ = 0;
273 }
274
275 void ParseEndif(StringPiece line, StringPiece) {
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900276 CheckIfStack("endif");
Shinichiro Hamaji6cb1c252015-06-17 16:22:51 +0900277 if (!line.empty())
278 Error("extraneous text after `endif` directive");
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900279 IfState st = *if_stack_.top();
280 for (int t = 0; t <= st.num_nest; t++) {
281 delete if_stack_.top();
282 if_stack_.pop();
283 if (if_stack_.empty()) {
284 out_asts_ = asts_;
285 } else {
286 IfState* st = if_stack_.top();
287 if (st->is_in_else)
Shinichiro Hamaji2847f092015-06-17 15:48:37 +0900288 out_asts_ = &st->ast->false_asts;
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900289 else
Shinichiro Hamaji2847f092015-06-17 15:48:37 +0900290 out_asts_ = &st->ast->true_asts;
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900291 }
292 }
293 }
294
295 void CheckIfStack(const char* keyword) {
296 if (if_stack_.empty()) {
297 Error(StringPrintf("*** extraneous `%s'.", keyword));
298 }
299 }
300
Shinichiro Hamaji6cb1c252015-06-17 16:22:51 +0900301 bool HandleDirective(StringPiece line, const DirectiveMap* directive_map) {
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900302 if (line.size() < shortest_directive_len_)
303 return false;
304 StringPiece prefix = line.substr(0, longest_directive_len_ + 1);
305 size_t space_index = prefix.find(' ');
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900306 StringPiece directive = prefix.substr(0, space_index);
Shinichiro Hamaji6cb1c252015-06-17 16:22:51 +0900307 auto found = directive_map->find(directive);
308 if (found == directive_map->end())
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900309 return false;
310
Shinichiro Hamaji32750622015-06-17 14:57:33 +0900311 StringPiece rest = TrimLeftSpace(line.substr(directive.size() + 1));
Shinichiro Hamaji810fd032015-06-17 04:38:03 +0900312 (this->*found->second)(rest, directive);
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900313 return true;
314 }
315
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900316 StringPiece buf_;
317 size_t l_;
318 ParserState state_;
319
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900320 vector<AST*>* asts_;
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900321 vector<AST*>* out_asts_;
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900322
Shinichiro Hamaji810fd032015-06-17 04:38:03 +0900323 StringPiece define_name_;
324 size_t define_start_;
325 int define_start_line_;
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900326
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900327 int num_if_nest_;
328 stack<IfState*> if_stack_;
329
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900330 Loc loc_;
331 bool fixed_lineno_;
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900332
Shinichiro Hamaji6cb1c252015-06-17 16:22:51 +0900333 static DirectiveMap* make_directives_;
334 static DirectiveMap* else_if_directives_;
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900335 static size_t shortest_directive_len_;
336 static size_t longest_directive_len_;
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900337};
338
339void Parse(Makefile* mk) {
340 Parser parser(StringPiece(mk->buf(), mk->len()),
341 mk->filename().c_str(),
342 mk->mutable_asts());
343 parser.Parse();
344}
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900345
346void InitParser() {
347 Parser::Init();
348}
349
350void QuitParser() {
351 Parser::Quit();
352}
353
Shinichiro Hamaji6cb1c252015-06-17 16:22:51 +0900354Parser::DirectiveMap* Parser::make_directives_;
355Parser::DirectiveMap* Parser::else_if_directives_;
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900356size_t Parser::shortest_directive_len_;
357size_t Parser::longest_directive_len_;