blob: ccb88de37813741392d7b5cc98cee7f88156b6da [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
Shinichiro Hamaji80456fb2015-06-18 14:56:10 +090042 Parser(StringPiece buf, const Loc& loc, vector<AST*>* asts)
43 : buf_(buf),
44 state_(ParserState::NOT_AFTER_RULE),
45 asts_(asts),
46 out_asts_(asts),
47 num_if_nest_(0),
48 loc_(loc),
49 fixed_lineno_(true) {
50 }
51
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090052 ~Parser() {
53 }
54
55 void Parse() {
56 l_ = 0;
57
58 for (l_ = 0; l_ < buf_.size();) {
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090059 size_t lf_cnt = 0;
60 size_t e = FindEndOfLine(&lf_cnt);
Shinichiro Hamaji8ee8c372015-06-16 16:19:40 +090061 if (!fixed_lineno_)
62 loc_.lineno += lf_cnt;
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090063 StringPiece line(buf_.data() + l_, e - l_);
64 ParseLine(line);
65 if (e == buf_.size())
66 break;
67
68 l_ = e + 1;
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090069 }
70 }
71
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +090072 static void Init() {
Shinichiro Hamaji6cb1c252015-06-17 16:22:51 +090073 make_directives_ = new DirectiveMap;
Shinichiro Hamaji14b8bea2015-06-17 03:14:28 +090074 (*make_directives_)["include"] = &Parser::ParseInclude;
75 (*make_directives_)["-include"] = &Parser::ParseInclude;
76 (*make_directives_)["sinclude"] = &Parser::ParseInclude;
Shinichiro Hamaji810fd032015-06-17 04:38:03 +090077 (*make_directives_)["define"] = &Parser::ParseDefine;
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +090078 (*make_directives_)["ifdef"] = &Parser::ParseIfdef;
79 (*make_directives_)["ifndef"] = &Parser::ParseIfdef;
Shinichiro Hamajid146f4c2015-06-17 17:51:24 +090080 (*make_directives_)["ifeq"] = &Parser::ParseIfeq;
81 (*make_directives_)["ifneq"] = &Parser::ParseIfeq;
Shinichiro Hamaji6cb1c252015-06-17 16:22:51 +090082 (*make_directives_)["else"] = &Parser::ParseElse;
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +090083 (*make_directives_)["endif"] = &Parser::ParseEndif;
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +090084
Shinichiro Hamaji6cb1c252015-06-17 16:22:51 +090085 else_if_directives_ = new DirectiveMap;
86 (*else_if_directives_)["ifdef"] = &Parser::ParseIfdef;
87 (*else_if_directives_)["ifndef"] = &Parser::ParseIfdef;
88
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +090089 shortest_directive_len_ = 9999;
90 longest_directive_len_ = 0;
91 for (auto p : *make_directives_) {
92 size_t len = p.first.size();
93 shortest_directive_len_ = min(len, shortest_directive_len_);
94 longest_directive_len_ = max(len, longest_directive_len_);
95 }
96 }
97
98 static void Quit() {
99 delete make_directives_;
100 }
101
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900102 private:
103 void Error(const string& msg) {
Shinichiro Hamaji8ee8c372015-06-16 16:19:40 +0900104 ERROR("%s:%d: %s", LOCF(loc_), msg.c_str());
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900105 }
106
107 size_t FindEndOfLine(size_t* lf_cnt) {
108 size_t e = l_;
109 bool prev_backslash = false;
110 for (; e < buf_.size(); e++) {
111 char c = buf_[e];
112 if (c == '\\') {
113 prev_backslash = !prev_backslash;
114 } else if (c == '\n') {
115 ++*lf_cnt;
116 if (!prev_backslash) {
117 return e;
118 }
119 } else if (c != '\r') {
120 prev_backslash = false;
121 }
122 }
123 return e;
124 }
125
126 void ParseLine(StringPiece line) {
127 if (line.empty() || (line.size() == 1 && line[0] == '\r'))
128 return;
129
Shinichiro Hamaji810fd032015-06-17 04:38:03 +0900130 if (!define_name_.empty()) {
131 ParseInsideDefine(line);
132 return;
133 }
134
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900135 if (line[0] == '\t' && state_ != ParserState::NOT_AFTER_RULE) {
136 CommandAST* ast = new CommandAST();
Shinichiro Hamaji861bd642015-06-19 16:59:13 +0900137 ast->set_loc(loc_);
Shinichiro Hamaji66bd7bc2015-06-19 16:54:06 +0900138 ast->expr = ParseExpr(line.substr(1), ParseExprOpt::COMMAND);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900139 out_asts_->push_back(ast);
140 return;
141 }
142
Shinichiro Hamaji32750622015-06-17 14:57:33 +0900143 line = TrimLeftSpace(line);
Shinichiro Hamajid4e81932015-06-17 04:40:45 +0900144
145 if (line[0] == '#')
146 return;
147
Shinichiro Hamaji6cb1c252015-06-17 16:22:51 +0900148 if (HandleDirective(line, make_directives_)) {
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900149 return;
150 }
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900151
Shinichiro Hamaji76ff9832015-06-18 17:11:22 +0900152 size_t sep = FindTwoOutsideParen(line, ':', '=');
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900153 if (sep == string::npos) {
Shinichiro Hamaji14b8bea2015-06-17 03:14:28 +0900154 ParseRule(line, sep);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900155 } else if (line[sep] == '=') {
Shinichiro Hamaji14b8bea2015-06-17 03:14:28 +0900156 ParseAssign(line, sep);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900157 } else if (line.get(sep+1) == '=') {
Shinichiro Hamaji14b8bea2015-06-17 03:14:28 +0900158 ParseAssign(line, sep+1);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900159 } else if (line[sep] == ':') {
Shinichiro Hamaji14b8bea2015-06-17 03:14:28 +0900160 ParseRule(line, sep);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900161 } else {
162 CHECK(false);
163 }
164 }
165
Shinichiro Hamaji14b8bea2015-06-17 03:14:28 +0900166 void ParseRule(StringPiece line, size_t sep) {
Shinichiro Hamaji76ff9832015-06-18 17:11:22 +0900167 const bool is_rule = sep != string::npos && line[sep] == ':';
Shinichiro Hamaji810fd032015-06-17 04:38:03 +0900168 RuleAST* ast = new RuleAST();
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900169 ast->set_loc(loc_);
170
Shinichiro Hamaji76ff9832015-06-18 17:11:22 +0900171 size_t found = FindTwoOutsideParen(line.substr(sep + 1), '=', ';');
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900172 if (found != string::npos) {
173 found += sep + 1;
174 ast->term = line[found];
Shinichiro Hamaji66bd7bc2015-06-19 16:54:06 +0900175 ParseExprOpt opt =
176 ast->term == ';' ? ParseExprOpt::COMMAND : ParseExprOpt::NORMAL;
177 ast->after_term = ParseExpr(TrimLeftSpace(line.substr(found + 1)), opt);
178 ast->expr = ParseExpr(TrimSpace(line.substr(0, found)));
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900179 } else {
180 ast->term = 0;
181 ast->after_term = NULL;
Shinichiro Hamaji66bd7bc2015-06-19 16:54:06 +0900182 ast->expr = ParseExpr(TrimSpace(line));
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900183 }
184 out_asts_->push_back(ast);
185 state_ = is_rule ? ParserState::AFTER_RULE : ParserState::MAYBE_AFTER_RULE;
186 }
187
Shinichiro Hamaji14b8bea2015-06-17 03:14:28 +0900188 void ParseAssign(StringPiece line, size_t sep) {
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900189 if (sep == 0)
190 Error("*** empty variable name ***");
Shinichiro Hamaji9b16bda2015-06-19 14:25:17 +0900191 StringPiece lhs;
192 StringPiece rhs;
193 AssignOp op;
194 ParseAssignStatement(line, sep, &lhs, &rhs, &op);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900195
Shinichiro Hamaji810fd032015-06-17 04:38:03 +0900196 AssignAST* ast = new AssignAST();
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900197 ast->set_loc(loc_);
Shinichiro Hamaji66bd7bc2015-06-19 16:54:06 +0900198 ast->lhs = ParseExpr(lhs);
199 ast->rhs = ParseExpr(rhs);
Shinichiro Hamaji81699be2015-06-22 18:07:38 +0900200 ast->orig_rhs = rhs;
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900201 ast->op = op;
202 ast->directive = AssignDirective::NONE;
203 out_asts_->push_back(ast);
204 state_ = ParserState::NOT_AFTER_RULE;
205 }
206
Shinichiro Hamaji14b8bea2015-06-17 03:14:28 +0900207 void ParseInclude(StringPiece line, StringPiece directive) {
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900208 IncludeAST* ast = new IncludeAST();
Shinichiro Hamaji861bd642015-06-19 16:59:13 +0900209 ast->set_loc(loc_);
Shinichiro Hamaji66bd7bc2015-06-19 16:54:06 +0900210 ast->expr = ParseExpr(line);
Shinichiro Hamajiefad2dd2015-06-17 03:08:02 +0900211 ast->should_exist = directive[0] == 'i';
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900212 out_asts_->push_back(ast);
213 }
214
Shinichiro Hamaji810fd032015-06-17 04:38:03 +0900215 void ParseDefine(StringPiece line, StringPiece) {
216 if (line.empty()) {
217 Error("*** empty variable name.");
218 }
219 define_name_ = line;
220 define_start_ = 0;
221 define_start_line_ = loc_.lineno;
222 }
223
224 void ParseInsideDefine(StringPiece line) {
Shinichiro Hamaji5562caf2015-06-17 17:08:40 +0900225 line = TrimLeftSpace(line);
226 if (GetDirective(line) != "endef") {
Shinichiro Hamaji810fd032015-06-17 04:38:03 +0900227 if (define_start_ == 0)
228 define_start_ = l_;
229 return;
230 }
231
Shinichiro Hamaji5562caf2015-06-17 17:08:40 +0900232 StringPiece rest = TrimRightSpace(RemoveComment(TrimLeftSpace(
233 line.substr(sizeof("endef")))));
234 if (!rest.empty()) {
235 WARN("%s:%d: extraneous text after `endef' directive", LOCF(loc_));
236 }
237
Shinichiro Hamaji810fd032015-06-17 04:38:03 +0900238 AssignAST* ast = new AssignAST();
239 ast->set_loc(Loc(loc_.filename, define_start_line_));
Shinichiro Hamaji66bd7bc2015-06-19 16:54:06 +0900240 ast->lhs = ParseExpr(define_name_);
Shinichiro Hamaji810fd032015-06-17 04:38:03 +0900241 StringPiece rhs;
242 if (define_start_)
Shinichiro Hamaji32750622015-06-17 14:57:33 +0900243 rhs = TrimRightSpace(buf_.substr(define_start_, l_ - define_start_));
Shinichiro Hamaji66bd7bc2015-06-19 16:54:06 +0900244 ast->rhs = ParseExpr(rhs, ParseExprOpt::DEFINE);
Shinichiro Hamaji81699be2015-06-22 18:07:38 +0900245 ast->orig_rhs = rhs;
Shinichiro Hamaji810fd032015-06-17 04:38:03 +0900246 ast->op = AssignOp::EQ;
247 ast->directive = AssignDirective::NONE;
248 out_asts_->push_back(ast);
249 define_name_.clear();
250 }
251
Shinichiro Hamajid146f4c2015-06-17 17:51:24 +0900252 void EnterIf(IfAST* ast) {
253 IfState* st = new IfState();
254 st->ast = ast;
255 st->is_in_else = false;
256 st->num_nest = num_if_nest_;
257 if_stack_.push(st);
258 out_asts_ = &ast->true_asts;
259 }
260
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900261 void ParseIfdef(StringPiece line, StringPiece directive) {
262 IfAST* ast = new IfAST();
263 ast->set_loc(loc_);
264 ast->op = directive[2] == 'n' ? CondOp::IFNDEF : CondOp::IFDEF;
Shinichiro Hamaji66bd7bc2015-06-19 16:54:06 +0900265 ast->lhs = ParseExpr(line);
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900266 ast->rhs = NULL;
267 out_asts_->push_back(ast);
Shinichiro Hamajid146f4c2015-06-17 17:51:24 +0900268 EnterIf(ast);
269 }
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900270
Shinichiro Hamajid146f4c2015-06-17 17:51:24 +0900271 bool ParseIfEqCond(StringPiece s, IfAST* ast) {
272 if (s.empty()) {
273 return false;
274 }
275
276 if (s[0] == '(' && s[s.size() - 1] == ')') {
277 s = s.substr(1, s.size() - 2);
278 char terms[] = {',', '\0'};
279 size_t n;
Shinichiro Hamaji66bd7bc2015-06-19 16:54:06 +0900280 ast->lhs = ParseExprImpl(s, terms, ParseExprOpt::NORMAL, &n, true);
Shinichiro Hamajid146f4c2015-06-17 17:51:24 +0900281 if (s[n] != ',')
282 return false;
283 s = TrimLeftSpace(s.substr(n+1));
Shinichiro Hamaji66bd7bc2015-06-19 16:54:06 +0900284 ast->rhs = ParseExprImpl(s, NULL, ParseExprOpt::NORMAL, &n);
Shinichiro Hamajiadeea692015-06-17 17:57:31 +0900285 s = TrimLeftSpace(s.substr(n));
Shinichiro Hamajid146f4c2015-06-17 17:51:24 +0900286 } else {
287 for (int i = 0; i < 2; i++) {
288 if (s.empty())
289 return false;
290 char quote = s[0];
291 if (quote != '\'' && quote != '"')
292 return false;
293 size_t end = s.find(quote, 1);
294 if (end == string::npos)
295 return false;
Shinichiro Hamaji66bd7bc2015-06-19 16:54:06 +0900296 Value* v = ParseExpr(s.substr(1, end - 1), ParseExprOpt::NORMAL);
Shinichiro Hamajid146f4c2015-06-17 17:51:24 +0900297 if (i == 0)
298 ast->lhs = v;
299 else
300 ast->rhs = v;
301 s = TrimLeftSpace(s.substr(end+1));
302 }
Shinichiro Hamajid146f4c2015-06-17 17:51:24 +0900303 }
Shinichiro Hamajiadeea692015-06-17 17:57:31 +0900304 if (!s.empty()) {
305 Error("extraneous text after `ifeq' directive");
306 }
307 return true;
Shinichiro Hamajid146f4c2015-06-17 17:51:24 +0900308 }
309
310 void ParseIfeq(StringPiece line, StringPiece directive) {
311 IfAST* ast = new IfAST();
312 ast->set_loc(loc_);
313 ast->op = directive[2] == 'n' ? CondOp::IFNEQ : CondOp::IFEQ;
314
315 if (!ParseIfEqCond(line, ast)) {
316 Error("*** invalid syntax in conditional.");
317 }
318
319 out_asts_->push_back(ast);
320 EnterIf(ast);
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900321 }
322
Shinichiro Hamaji6cb1c252015-06-17 16:22:51 +0900323 void ParseElse(StringPiece line, StringPiece) {
324 CheckIfStack("else");
325 IfState* st = if_stack_.top();
326 if (st->is_in_else)
327 Error("*** only one `else' per conditional.");
328 st->is_in_else = true;
329 out_asts_ = &st->ast->false_asts;
330
331 StringPiece next_if = TrimLeftSpace(line);
332 if (next_if.empty())
333 return;
334
335 num_if_nest_ = st->num_nest + 1;
336 if (!HandleDirective(next_if, else_if_directives_)) {
337 WARN("%s:%d: extraneous text after `else' directive", LOCF(loc_));
338 }
339 num_if_nest_ = 0;
340 }
341
342 void ParseEndif(StringPiece line, StringPiece) {
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900343 CheckIfStack("endif");
Shinichiro Hamaji6cb1c252015-06-17 16:22:51 +0900344 if (!line.empty())
345 Error("extraneous text after `endif` directive");
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900346 IfState st = *if_stack_.top();
347 for (int t = 0; t <= st.num_nest; t++) {
348 delete if_stack_.top();
349 if_stack_.pop();
350 if (if_stack_.empty()) {
351 out_asts_ = asts_;
352 } else {
353 IfState* st = if_stack_.top();
354 if (st->is_in_else)
Shinichiro Hamaji2847f092015-06-17 15:48:37 +0900355 out_asts_ = &st->ast->false_asts;
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900356 else
Shinichiro Hamaji2847f092015-06-17 15:48:37 +0900357 out_asts_ = &st->ast->true_asts;
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900358 }
359 }
360 }
361
362 void CheckIfStack(const char* keyword) {
363 if (if_stack_.empty()) {
364 Error(StringPrintf("*** extraneous `%s'.", keyword));
365 }
366 }
367
Shinichiro Hamaji5562caf2015-06-17 17:08:40 +0900368 StringPiece RemoveComment(StringPiece line) {
Shinichiro Hamajieafd0522015-06-18 16:46:02 +0900369 size_t i = FindOutsideParen(line, '#');
370 if (i == string::npos)
371 return line;
372 return line.substr(0, i);
Shinichiro Hamaji5562caf2015-06-17 17:08:40 +0900373 }
374
375 StringPiece GetDirective(StringPiece line) {
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900376 if (line.size() < shortest_directive_len_)
Shinichiro Hamaji5562caf2015-06-17 17:08:40 +0900377 return StringPiece();
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900378 StringPiece prefix = line.substr(0, longest_directive_len_ + 1);
Shinichiro Hamaji5562caf2015-06-17 17:08:40 +0900379 size_t space_index = prefix.find_first_of(" \t#");
380 return prefix.substr(0, space_index);
381 }
382
383 bool HandleDirective(StringPiece line, const DirectiveMap* directive_map) {
384 StringPiece directive = GetDirective(line);
Shinichiro Hamaji6cb1c252015-06-17 16:22:51 +0900385 auto found = directive_map->find(directive);
386 if (found == directive_map->end())
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900387 return false;
388
Shinichiro Hamaji5562caf2015-06-17 17:08:40 +0900389 StringPiece rest = TrimRightSpace(RemoveComment(TrimLeftSpace(
Shinichiro Hamajid146f4c2015-06-17 17:51:24 +0900390 line.substr(directive.size()))));
Shinichiro Hamaji810fd032015-06-17 04:38:03 +0900391 (this->*found->second)(rest, directive);
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900392 return true;
393 }
394
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900395 StringPiece buf_;
396 size_t l_;
397 ParserState state_;
398
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900399 vector<AST*>* asts_;
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900400 vector<AST*>* out_asts_;
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900401
Shinichiro Hamaji810fd032015-06-17 04:38:03 +0900402 StringPiece define_name_;
403 size_t define_start_;
404 int define_start_line_;
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900405
Shinichiro Hamaji7e256df2015-06-17 15:33:11 +0900406 int num_if_nest_;
407 stack<IfState*> if_stack_;
408
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900409 Loc loc_;
410 bool fixed_lineno_;
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900411
Shinichiro Hamaji6cb1c252015-06-17 16:22:51 +0900412 static DirectiveMap* make_directives_;
413 static DirectiveMap* else_if_directives_;
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900414 static size_t shortest_directive_len_;
415 static size_t longest_directive_len_;
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900416};
417
418void Parse(Makefile* mk) {
419 Parser parser(StringPiece(mk->buf(), mk->len()),
420 mk->filename().c_str(),
421 mk->mutable_asts());
422 parser.Parse();
423}
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900424
Shinichiro Hamaji80456fb2015-06-18 14:56:10 +0900425void Parse(StringPiece buf, const Loc& loc, vector<AST*>* out_asts) {
426 Parser parser(buf, loc, out_asts);
427 parser.Parse();
428}
429
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900430void InitParser() {
431 Parser::Init();
432}
433
434void QuitParser() {
435 Parser::Quit();
436}
437
Shinichiro Hamaji6cb1c252015-06-17 16:22:51 +0900438Parser::DirectiveMap* Parser::make_directives_;
439Parser::DirectiveMap* Parser::else_if_directives_;
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900440size_t Parser::shortest_directive_len_;
441size_t Parser::longest_directive_len_;
Shinichiro Hamaji9b16bda2015-06-19 14:25:17 +0900442
443void ParseAssignStatement(StringPiece line, size_t sep,
444 StringPiece* lhs, StringPiece* rhs, AssignOp* op) {
445 CHECK(sep != 0);
446 *op = AssignOp::EQ;
447 size_t lhs_end = sep;
448 switch (line[sep-1]) {
449 case ':':
450 lhs_end--;
451 *op = AssignOp::COLON_EQ;
452 break;
453 case '+':
454 lhs_end--;
455 *op = AssignOp::PLUS_EQ;
456 break;
457 case '?':
458 lhs_end--;
459 *op = AssignOp::QUESTION_EQ;
460 break;
461 }
462 *lhs = TrimSpace(line.substr(0, lhs_end));
463 *rhs = TrimSpace(line.substr(sep + 1));
464}