blob: 8e012ab26b54592da28eeeffa92b81ac828db8a3 [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 Hamaji776ca302015-06-06 03:52:48 +090027 public:
28 Parser(StringPiece buf, const char* filename, vector<AST*>* asts)
29 : buf_(buf),
30 state_(ParserState::NOT_AFTER_RULE),
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +090031 asts_(asts),
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090032 out_asts_(asts),
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +090033 num_if_nest_(0),
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090034 loc_(filename, 0),
35 fixed_lineno_(false) {
36 }
37
38 ~Parser() {
39 }
40
41 void Parse() {
42 l_ = 0;
43
44 for (l_ = 0; l_ < buf_.size();) {
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090045 size_t lf_cnt = 0;
46 size_t e = FindEndOfLine(&lf_cnt);
Shinichiro Hamaji8ee8c372015-06-16 16:19:40 +090047 if (!fixed_lineno_)
48 loc_.lineno += lf_cnt;
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090049 StringPiece line(buf_.data() + l_, e - l_);
50 ParseLine(line);
51 if (e == buf_.size())
52 break;
53
54 l_ = e + 1;
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090055 }
56 }
57
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +090058 static void Init() {
59 make_directives_ = new unordered_map<StringPiece, DirectiveHandler>;
Shinichiro Hamaji14b8bea2015-06-17 03:14:28 +090060 (*make_directives_)["include"] = &Parser::ParseInclude;
61 (*make_directives_)["-include"] = &Parser::ParseInclude;
62 (*make_directives_)["sinclude"] = &Parser::ParseInclude;
Shinichiro Hamaji810fd032015-06-17 04:38:03 +090063 (*make_directives_)["define"] = &Parser::ParseDefine;
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +090064 (*make_directives_)["ifdef"] = &Parser::ParseIfdef;
65 (*make_directives_)["ifndef"] = &Parser::ParseIfdef;
66 (*make_directives_)["endif"] = &Parser::ParseEndif;
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +090067
68 shortest_directive_len_ = 9999;
69 longest_directive_len_ = 0;
70 for (auto p : *make_directives_) {
71 size_t len = p.first.size();
72 shortest_directive_len_ = min(len, shortest_directive_len_);
73 longest_directive_len_ = max(len, longest_directive_len_);
74 }
75 }
76
77 static void Quit() {
78 delete make_directives_;
79 }
80
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090081 private:
82 void Error(const string& msg) {
Shinichiro Hamaji8ee8c372015-06-16 16:19:40 +090083 ERROR("%s:%d: %s", LOCF(loc_), msg.c_str());
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090084 }
85
86 size_t FindEndOfLine(size_t* lf_cnt) {
87 size_t e = l_;
88 bool prev_backslash = false;
89 for (; e < buf_.size(); e++) {
90 char c = buf_[e];
91 if (c == '\\') {
92 prev_backslash = !prev_backslash;
93 } else if (c == '\n') {
94 ++*lf_cnt;
95 if (!prev_backslash) {
96 return e;
97 }
98 } else if (c != '\r') {
99 prev_backslash = false;
100 }
101 }
102 return e;
103 }
104
105 void ParseLine(StringPiece line) {
106 if (line.empty() || (line.size() == 1 && line[0] == '\r'))
107 return;
108
Shinichiro Hamaji810fd032015-06-17 04:38:03 +0900109 if (!define_name_.empty()) {
110 ParseInsideDefine(line);
111 return;
112 }
113
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900114 if (line[0] == '\t' && state_ != ParserState::NOT_AFTER_RULE) {
115 CommandAST* ast = new CommandAST();
116 ast->expr = ParseExpr(line.substr(1), true);
117 out_asts_->push_back(ast);
118 return;
119 }
120
Shinichiro Hamaji32750622015-06-17 14:57:33 +0900121 line = TrimLeftSpace(line);
Shinichiro Hamajid4e81932015-06-17 04:40:45 +0900122
123 if (line[0] == '#')
124 return;
125
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900126 if (HandleDirective(line)) {
127 return;
128 }
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900129
130 size_t sep = line.find_first_of(STRING_PIECE("=:"));
131 if (sep == string::npos) {
Shinichiro Hamaji14b8bea2015-06-17 03:14:28 +0900132 ParseRule(line, sep);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900133 } else if (line[sep] == '=') {
Shinichiro Hamaji14b8bea2015-06-17 03:14:28 +0900134 ParseAssign(line, sep);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900135 } else if (line.get(sep+1) == '=') {
Shinichiro Hamaji14b8bea2015-06-17 03:14:28 +0900136 ParseAssign(line, sep+1);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900137 } else if (line[sep] == ':') {
Shinichiro Hamaji14b8bea2015-06-17 03:14:28 +0900138 ParseRule(line, sep);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900139 } else {
140 CHECK(false);
141 }
142 }
143
Shinichiro Hamaji14b8bea2015-06-17 03:14:28 +0900144 void ParseRule(StringPiece line, size_t sep) {
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900145 const bool is_rule = line.find(':') != string::npos;
Shinichiro Hamaji810fd032015-06-17 04:38:03 +0900146 RuleAST* ast = new RuleAST();
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900147 ast->set_loc(loc_);
148
149 size_t found = line.substr(sep + 1).find_first_of("=;");
150 if (found != string::npos) {
151 found += sep + 1;
152 ast->term = line[found];
Shinichiro Hamaji32750622015-06-17 14:57:33 +0900153 ast->after_term = ParseExpr(TrimLeftSpace(line.substr(found + 1)),
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900154 ast->term == ';');
Shinichiro Hamaji32750622015-06-17 14:57:33 +0900155 ast->expr = ParseExpr(TrimSpace(line.substr(0, found)), false);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900156 } else {
157 ast->term = 0;
158 ast->after_term = NULL;
Shinichiro Hamaji32750622015-06-17 14:57:33 +0900159 ast->expr = ParseExpr(TrimSpace(line), false);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900160 }
161 out_asts_->push_back(ast);
162 state_ = is_rule ? ParserState::AFTER_RULE : ParserState::MAYBE_AFTER_RULE;
163 }
164
Shinichiro Hamaji14b8bea2015-06-17 03:14:28 +0900165 void ParseAssign(StringPiece line, size_t sep) {
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900166 if (sep == 0)
167 Error("*** empty variable name ***");
168 AssignOp op = AssignOp::EQ;
169 size_t lhs_end = sep;
170 switch (line[sep-1]) {
171 case ':':
172 lhs_end--;
173 op = AssignOp::COLON_EQ;
174 break;
175 case '+':
176 lhs_end--;
177 op = AssignOp::PLUS_EQ;
178 break;
179 case '?':
180 lhs_end--;
181 op = AssignOp::QUESTION_EQ;
182 break;
183 }
184
Shinichiro Hamaji810fd032015-06-17 04:38:03 +0900185 AssignAST* ast = new AssignAST();
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900186 ast->set_loc(loc_);
Shinichiro Hamaji32750622015-06-17 14:57:33 +0900187 ast->lhs = ParseExpr(TrimSpace(line.substr(0, lhs_end)), false);
188 ast->rhs = ParseExpr(TrimSpace(line.substr(sep + 1)), false);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900189 ast->op = op;
190 ast->directive = AssignDirective::NONE;
191 out_asts_->push_back(ast);
192 state_ = ParserState::NOT_AFTER_RULE;
193 }
194
Shinichiro Hamaji14b8bea2015-06-17 03:14:28 +0900195 void ParseInclude(StringPiece line, StringPiece directive) {
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900196 IncludeAST* ast = new IncludeAST();
197 ast->expr = ParseExpr(line, false);
Shinichiro Hamajiefad2dd2015-06-17 03:08:02 +0900198 ast->should_exist = directive[0] == 'i';
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900199 out_asts_->push_back(ast);
200 }
201
Shinichiro Hamaji810fd032015-06-17 04:38:03 +0900202 void ParseDefine(StringPiece line, StringPiece) {
203 if (line.empty()) {
204 Error("*** empty variable name.");
205 }
206 define_name_ = line;
207 define_start_ = 0;
208 define_start_line_ = loc_.lineno;
209 }
210
211 void ParseInsideDefine(StringPiece line) {
Shinichiro Hamaji32750622015-06-17 14:57:33 +0900212 if (TrimLeftSpace(line) != "endef") {
Shinichiro Hamaji810fd032015-06-17 04:38:03 +0900213 if (define_start_ == 0)
214 define_start_ = l_;
215 return;
216 }
217
218 AssignAST* ast = new AssignAST();
219 ast->set_loc(Loc(loc_.filename, define_start_line_));
220 ast->lhs = ParseExpr(define_name_, false);
221 StringPiece rhs;
222 if (define_start_)
Shinichiro Hamaji32750622015-06-17 14:57:33 +0900223 rhs = TrimRightSpace(buf_.substr(define_start_, l_ - define_start_));
Shinichiro Hamaji810fd032015-06-17 04:38:03 +0900224 ast->rhs = ParseExpr(rhs, false);
225 ast->op = AssignOp::EQ;
226 ast->directive = AssignDirective::NONE;
227 out_asts_->push_back(ast);
228 define_name_.clear();
229 }
230
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900231 void ParseIfdef(StringPiece line, StringPiece directive) {
232 IfAST* ast = new IfAST();
233 ast->set_loc(loc_);
234 ast->op = directive[2] == 'n' ? CondOp::IFNDEF : CondOp::IFDEF;
235 ast->lhs = ParseExpr(line, false);
236 ast->rhs = NULL;
237 out_asts_->push_back(ast);
238
239 IfState* st = new IfState();
240 st->ast = ast;
241 st->is_in_else = false;
242 st->num_nest = num_if_nest_;
Shinichiro Hamaji2847f092015-06-17 15:48:37 +0900243 out_asts_ = &ast->true_asts;
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900244 }
245
246 void ParseEndif(StringPiece, StringPiece) {
247 CheckIfStack("endif");
248 IfState st = *if_stack_.top();
249 for (int t = 0; t <= st.num_nest; t++) {
250 delete if_stack_.top();
251 if_stack_.pop();
252 if (if_stack_.empty()) {
253 out_asts_ = asts_;
254 } else {
255 IfState* st = if_stack_.top();
256 if (st->is_in_else)
Shinichiro Hamaji2847f092015-06-17 15:48:37 +0900257 out_asts_ = &st->ast->false_asts;
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900258 else
Shinichiro Hamaji2847f092015-06-17 15:48:37 +0900259 out_asts_ = &st->ast->true_asts;
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900260 }
261 }
262 }
263
264 void CheckIfStack(const char* keyword) {
265 if (if_stack_.empty()) {
266 Error(StringPrintf("*** extraneous `%s'.", keyword));
267 }
268 }
269
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900270 bool HandleDirective(StringPiece line) {
271 if (line.size() < shortest_directive_len_)
272 return false;
273 StringPiece prefix = line.substr(0, longest_directive_len_ + 1);
274 size_t space_index = prefix.find(' ');
275 if (space_index == string::npos)
276 return false;
277 StringPiece directive = prefix.substr(0, space_index);
278 auto found = make_directives_->find(directive);
279 if (found == make_directives_->end())
280 return false;
281
Shinichiro Hamaji32750622015-06-17 14:57:33 +0900282 StringPiece rest = TrimLeftSpace(line.substr(directive.size() + 1));
Shinichiro Hamaji810fd032015-06-17 04:38:03 +0900283 (this->*found->second)(rest, directive);
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900284 return true;
285 }
286
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900287 StringPiece buf_;
288 size_t l_;
289 ParserState state_;
290
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900291 vector<AST*>* asts_;
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900292 vector<AST*>* out_asts_;
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900293
Shinichiro Hamaji810fd032015-06-17 04:38:03 +0900294 StringPiece define_name_;
295 size_t define_start_;
296 int define_start_line_;
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900297
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900298 int num_if_nest_;
299 stack<IfState*> if_stack_;
300
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900301 Loc loc_;
302 bool fixed_lineno_;
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900303
304 typedef void (Parser::*DirectiveHandler)(
305 StringPiece line, StringPiece directive);
306 static unordered_map<StringPiece, DirectiveHandler>* make_directives_;
307 static size_t shortest_directive_len_;
308 static size_t longest_directive_len_;
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900309};
310
311void Parse(Makefile* mk) {
312 Parser parser(StringPiece(mk->buf(), mk->len()),
313 mk->filename().c_str(),
314 mk->mutable_asts());
315 parser.Parse();
316}
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900317
318void InitParser() {
319 Parser::Init();
320}
321
322void QuitParser() {
323 Parser::Quit();
324}
325
326unordered_map<StringPiece, Parser::DirectiveHandler>* Parser::make_directives_;
327size_t Parser::shortest_directive_len_;
328size_t Parser::longest_directive_len_;