blob: 00339c0650a178936d91dbffefe9bbfb215bbbf4 [file] [log] [blame]
Shinichiro Hamaji776ca302015-06-06 03:52:48 +09001#include "parser.h"
2
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +09003#include <unordered_map>
4
Shinichiro Hamaji776ca302015-06-06 03:52:48 +09005#include "ast.h"
6#include "file.h"
7#include "loc.h"
8#include "log.h"
9#include "string_piece.h"
Shinichiro Hamaji810fd032015-06-17 04:38:03 +090010#include "strutil.h"
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090011#include "value.h"
12
13enum struct ParserState {
14 NOT_AFTER_RULE = 0,
15 AFTER_RULE,
16 MAYBE_AFTER_RULE,
17};
18
19class Parser {
20 public:
21 Parser(StringPiece buf, const char* filename, vector<AST*>* asts)
22 : buf_(buf),
23 state_(ParserState::NOT_AFTER_RULE),
24 out_asts_(asts),
25 loc_(filename, 0),
26 fixed_lineno_(false) {
27 }
28
29 ~Parser() {
30 }
31
32 void Parse() {
33 l_ = 0;
34
35 for (l_ = 0; l_ < buf_.size();) {
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090036 size_t lf_cnt = 0;
37 size_t e = FindEndOfLine(&lf_cnt);
Shinichiro Hamaji8ee8c372015-06-16 16:19:40 +090038 if (!fixed_lineno_)
39 loc_.lineno += lf_cnt;
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090040 StringPiece line(buf_.data() + l_, e - l_);
41 ParseLine(line);
42 if (e == buf_.size())
43 break;
44
45 l_ = e + 1;
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090046 }
47 }
48
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +090049 static void Init() {
50 make_directives_ = new unordered_map<StringPiece, DirectiveHandler>;
Shinichiro Hamaji14b8bea2015-06-17 03:14:28 +090051 (*make_directives_)["include"] = &Parser::ParseInclude;
52 (*make_directives_)["-include"] = &Parser::ParseInclude;
53 (*make_directives_)["sinclude"] = &Parser::ParseInclude;
Shinichiro Hamaji810fd032015-06-17 04:38:03 +090054 (*make_directives_)["define"] = &Parser::ParseDefine;
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +090055
56 shortest_directive_len_ = 9999;
57 longest_directive_len_ = 0;
58 for (auto p : *make_directives_) {
59 size_t len = p.first.size();
60 shortest_directive_len_ = min(len, shortest_directive_len_);
61 longest_directive_len_ = max(len, longest_directive_len_);
62 }
63 }
64
65 static void Quit() {
66 delete make_directives_;
67 }
68
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090069 private:
70 void Error(const string& msg) {
Shinichiro Hamaji8ee8c372015-06-16 16:19:40 +090071 ERROR("%s:%d: %s", LOCF(loc_), msg.c_str());
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090072 }
73
74 size_t FindEndOfLine(size_t* lf_cnt) {
75 size_t e = l_;
76 bool prev_backslash = false;
77 for (; e < buf_.size(); e++) {
78 char c = buf_[e];
79 if (c == '\\') {
80 prev_backslash = !prev_backslash;
81 } else if (c == '\n') {
82 ++*lf_cnt;
83 if (!prev_backslash) {
84 return e;
85 }
86 } else if (c != '\r') {
87 prev_backslash = false;
88 }
89 }
90 return e;
91 }
92
93 void ParseLine(StringPiece line) {
94 if (line.empty() || (line.size() == 1 && line[0] == '\r'))
95 return;
96
Shinichiro Hamaji810fd032015-06-17 04:38:03 +090097 if (!define_name_.empty()) {
98 ParseInsideDefine(line);
99 return;
100 }
101
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900102 if (line[0] == '\t' && state_ != ParserState::NOT_AFTER_RULE) {
103 CommandAST* ast = new CommandAST();
104 ast->expr = ParseExpr(line.substr(1), true);
105 out_asts_->push_back(ast);
106 return;
107 }
108
Shinichiro Hamaji32750622015-06-17 14:57:33 +0900109 line = TrimLeftSpace(line);
Shinichiro Hamajid4e81932015-06-17 04:40:45 +0900110
111 if (line[0] == '#')
112 return;
113
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900114 if (HandleDirective(line)) {
115 return;
116 }
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900117
118 size_t sep = line.find_first_of(STRING_PIECE("=:"));
119 if (sep == string::npos) {
Shinichiro Hamaji14b8bea2015-06-17 03:14:28 +0900120 ParseRule(line, sep);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900121 } else if (line[sep] == '=') {
Shinichiro Hamaji14b8bea2015-06-17 03:14:28 +0900122 ParseAssign(line, sep);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900123 } else if (line.get(sep+1) == '=') {
Shinichiro Hamaji14b8bea2015-06-17 03:14:28 +0900124 ParseAssign(line, sep+1);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900125 } else if (line[sep] == ':') {
Shinichiro Hamaji14b8bea2015-06-17 03:14:28 +0900126 ParseRule(line, sep);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900127 } else {
128 CHECK(false);
129 }
130 }
131
Shinichiro Hamaji14b8bea2015-06-17 03:14:28 +0900132 void ParseRule(StringPiece line, size_t sep) {
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900133 const bool is_rule = line.find(':') != string::npos;
Shinichiro Hamaji810fd032015-06-17 04:38:03 +0900134 RuleAST* ast = new RuleAST();
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900135 ast->set_loc(loc_);
136
137 size_t found = line.substr(sep + 1).find_first_of("=;");
138 if (found != string::npos) {
139 found += sep + 1;
140 ast->term = line[found];
Shinichiro Hamaji32750622015-06-17 14:57:33 +0900141 ast->after_term = ParseExpr(TrimLeftSpace(line.substr(found + 1)),
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900142 ast->term == ';');
Shinichiro Hamaji32750622015-06-17 14:57:33 +0900143 ast->expr = ParseExpr(TrimSpace(line.substr(0, found)), false);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900144 } else {
145 ast->term = 0;
146 ast->after_term = NULL;
Shinichiro Hamaji32750622015-06-17 14:57:33 +0900147 ast->expr = ParseExpr(TrimSpace(line), false);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900148 }
149 out_asts_->push_back(ast);
150 state_ = is_rule ? ParserState::AFTER_RULE : ParserState::MAYBE_AFTER_RULE;
151 }
152
Shinichiro Hamaji14b8bea2015-06-17 03:14:28 +0900153 void ParseAssign(StringPiece line, size_t sep) {
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900154 if (sep == 0)
155 Error("*** empty variable name ***");
156 AssignOp op = AssignOp::EQ;
157 size_t lhs_end = sep;
158 switch (line[sep-1]) {
159 case ':':
160 lhs_end--;
161 op = AssignOp::COLON_EQ;
162 break;
163 case '+':
164 lhs_end--;
165 op = AssignOp::PLUS_EQ;
166 break;
167 case '?':
168 lhs_end--;
169 op = AssignOp::QUESTION_EQ;
170 break;
171 }
172
Shinichiro Hamaji810fd032015-06-17 04:38:03 +0900173 AssignAST* ast = new AssignAST();
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900174 ast->set_loc(loc_);
Shinichiro Hamaji32750622015-06-17 14:57:33 +0900175 ast->lhs = ParseExpr(TrimSpace(line.substr(0, lhs_end)), false);
176 ast->rhs = ParseExpr(TrimSpace(line.substr(sep + 1)), false);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900177 ast->op = op;
178 ast->directive = AssignDirective::NONE;
179 out_asts_->push_back(ast);
180 state_ = ParserState::NOT_AFTER_RULE;
181 }
182
Shinichiro Hamaji14b8bea2015-06-17 03:14:28 +0900183 void ParseInclude(StringPiece line, StringPiece directive) {
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900184 IncludeAST* ast = new IncludeAST();
185 ast->expr = ParseExpr(line, false);
Shinichiro Hamajiefad2dd2015-06-17 03:08:02 +0900186 ast->should_exist = directive[0] == 'i';
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900187 out_asts_->push_back(ast);
188 }
189
Shinichiro Hamaji810fd032015-06-17 04:38:03 +0900190 void ParseDefine(StringPiece line, StringPiece) {
191 if (line.empty()) {
192 Error("*** empty variable name.");
193 }
194 define_name_ = line;
195 define_start_ = 0;
196 define_start_line_ = loc_.lineno;
197 }
198
199 void ParseInsideDefine(StringPiece line) {
Shinichiro Hamaji32750622015-06-17 14:57:33 +0900200 if (TrimLeftSpace(line) != "endef") {
Shinichiro Hamaji810fd032015-06-17 04:38:03 +0900201 if (define_start_ == 0)
202 define_start_ = l_;
203 return;
204 }
205
206 AssignAST* ast = new AssignAST();
207 ast->set_loc(Loc(loc_.filename, define_start_line_));
208 ast->lhs = ParseExpr(define_name_, false);
209 StringPiece rhs;
210 if (define_start_)
Shinichiro Hamaji32750622015-06-17 14:57:33 +0900211 rhs = TrimRightSpace(buf_.substr(define_start_, l_ - define_start_));
Shinichiro Hamaji810fd032015-06-17 04:38:03 +0900212 ast->rhs = ParseExpr(rhs, false);
213 ast->op = AssignOp::EQ;
214 ast->directive = AssignDirective::NONE;
215 out_asts_->push_back(ast);
216 define_name_.clear();
217 }
218
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900219 bool HandleDirective(StringPiece line) {
220 if (line.size() < shortest_directive_len_)
221 return false;
222 StringPiece prefix = line.substr(0, longest_directive_len_ + 1);
223 size_t space_index = prefix.find(' ');
224 if (space_index == string::npos)
225 return false;
226 StringPiece directive = prefix.substr(0, space_index);
227 auto found = make_directives_->find(directive);
228 if (found == make_directives_->end())
229 return false;
230
Shinichiro Hamaji32750622015-06-17 14:57:33 +0900231 StringPiece rest = TrimLeftSpace(line.substr(directive.size() + 1));
Shinichiro Hamaji810fd032015-06-17 04:38:03 +0900232 (this->*found->second)(rest, directive);
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900233 return true;
234 }
235
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900236 StringPiece buf_;
237 size_t l_;
238 ParserState state_;
239
240 vector<AST*>* out_asts_;
Shinichiro Hamaji810fd032015-06-17 04:38:03 +0900241 StringPiece define_name_;
242 size_t define_start_;
243 int define_start_line_;
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900244
245 Loc loc_;
246 bool fixed_lineno_;
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900247
248 typedef void (Parser::*DirectiveHandler)(
249 StringPiece line, StringPiece directive);
250 static unordered_map<StringPiece, DirectiveHandler>* make_directives_;
251 static size_t shortest_directive_len_;
252 static size_t longest_directive_len_;
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900253};
254
255void Parse(Makefile* mk) {
256 Parser parser(StringPiece(mk->buf(), mk->len()),
257 mk->filename().c_str(),
258 mk->mutable_asts());
259 parser.Parse();
260}
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900261
262void InitParser() {
263 Parser::Init();
264}
265
266void QuitParser() {
267 Parser::Quit();
268}
269
270unordered_map<StringPiece, Parser::DirectiveHandler>* Parser::make_directives_;
271size_t Parser::shortest_directive_len_;
272size_t Parser::longest_directive_len_;