1 // 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 15 // +build ignore 16 17 #include "parser.h" 18 19 #include <stack> 20 #include <unordered_map> 21 22 #include "expr.h" 23 #include "file.h" 24 #include "loc.h" 25 #include "log.h" 26 #include "stats.h" 27 #include "stmt.h" 28 #include "string_piece.h" 29 #include "strutil.h" 30 31 enum struct ParserState { 32 NOT_AFTER_RULE = 0, 33 AFTER_RULE, 34 MAYBE_AFTER_RULE, 35 }; 36 37 class Parser { 38 struct IfState { 39 IfStmt* stmt; 40 bool is_in_else; 41 int num_nest; 42 }; 43 44 typedef void (Parser::*DirectiveHandler)( 45 StringPiece line, StringPiece directive); 46 typedef unordered_map<StringPiece, DirectiveHandler> DirectiveMap; 47 48 public: 49 Parser(StringPiece buf, const char* filename, vector<Stmt*>* stmts) 50 : buf_(buf), 51 state_(ParserState::NOT_AFTER_RULE), 52 stmts_(stmts), 53 out_stmts_(stmts), 54 num_if_nest_(0), 55 loc_(filename, 0), 56 fixed_lineno_(false) { 57 } 58 59 Parser(StringPiece buf, const Loc& loc, vector<Stmt*>* stmts) 60 : buf_(buf), 61 state_(ParserState::NOT_AFTER_RULE), 62 stmts_(stmts), 63 out_stmts_(stmts), 64 num_if_nest_(0), 65 loc_(loc), 66 fixed_lineno_(true) { 67 } 68 69 ~Parser() { 70 } 71 72 void Parse() { 73 l_ = 0; 74 75 for (l_ = 0; l_ < buf_.size();) { 76 size_t lf_cnt = 0; 77 size_t e = FindEndOfLine(&lf_cnt); 78 if (!fixed_lineno_) 79 loc_.lineno++; 80 StringPiece line(buf_.data() + l_, e - l_); 81 orig_line_with_directives_ = line; 82 ParseLine(line); 83 if (!fixed_lineno_) 84 loc_.lineno += lf_cnt - 1; 85 if (e == buf_.size()) 86 break; 87 88 l_ = e + 1; 89 } 90 } 91 92 static void Init() { 93 make_directives_ = new DirectiveMap; 94 (*make_directives_)["include"] = &Parser::ParseInclude; 95 (*make_directives_)["-include"] = &Parser::ParseInclude; 96 (*make_directives_)["sinclude"] = &Parser::ParseInclude; 97 (*make_directives_)["define"] = &Parser::ParseDefine; 98 (*make_directives_)["ifdef"] = &Parser::ParseIfdef; 99 (*make_directives_)["ifndef"] = &Parser::ParseIfdef; 100 (*make_directives_)["ifeq"] = &Parser::ParseIfeq; 101 (*make_directives_)["ifneq"] = &Parser::ParseIfeq; 102 (*make_directives_)["else"] = &Parser::ParseElse; 103 (*make_directives_)["endif"] = &Parser::ParseEndif; 104 (*make_directives_)["override"] = &Parser::ParseOverride; 105 (*make_directives_)["export"] = &Parser::ParseExport; 106 (*make_directives_)["unexport"] = &Parser::ParseUnexport; 107 108 else_if_directives_ = new DirectiveMap; 109 (*else_if_directives_)["ifdef"] = &Parser::ParseIfdef; 110 (*else_if_directives_)["ifndef"] = &Parser::ParseIfdef; 111 (*else_if_directives_)["ifeq"] = &Parser::ParseIfeq; 112 (*else_if_directives_)["ifneq"] = &Parser::ParseIfeq; 113 114 assign_directives_ = new DirectiveMap; 115 (*assign_directives_)["define"] = &Parser::ParseDefine; 116 (*assign_directives_)["export"] = &Parser::ParseExport; 117 (*assign_directives_)["override"] = &Parser::ParseOverride; 118 119 shortest_directive_len_ = 9999; 120 longest_directive_len_ = 0; 121 for (auto p : *make_directives_) { 122 size_t len = p.first.size(); 123 shortest_directive_len_ = min(len, shortest_directive_len_); 124 longest_directive_len_ = max(len, longest_directive_len_); 125 } 126 } 127 128 static void Quit() { 129 delete make_directives_; 130 } 131 132 void set_state(ParserState st) { state_ = st; } 133 134 static vector<ParseErrorStmt*> parse_errors; 135 136 private: 137 void Error(const string& msg) { 138 ParseErrorStmt* stmt = new ParseErrorStmt(); 139 stmt->set_loc(loc_); 140 stmt->msg = msg; 141 out_stmts_->push_back(stmt); 142 parse_errors.push_back(stmt); 143 } 144 145 size_t FindEndOfLine(size_t* lf_cnt) { 146 return ::FindEndOfLine(buf_, l_, lf_cnt); 147 } 148 149 Value* ParseExpr(StringPiece s, ParseExprOpt opt = ParseExprOpt::NORMAL) { 150 return ::ParseExpr(loc_, s, opt); 151 } 152 153 void ParseLine(StringPiece line) { 154 if (!define_name_.empty()) { 155 ParseInsideDefine(line); 156 return; 157 } 158 159 if (line.empty() || (line.size() == 1 && line[0] == '\r')) 160 return; 161 162 current_directive_ = AssignDirective::NONE; 163 164 if (line[0] == '\t' && state_ != ParserState::NOT_AFTER_RULE) { 165 CommandStmt* stmt = new CommandStmt(); 166 stmt->set_loc(loc_); 167 stmt->expr = ParseExpr(line.substr(1), ParseExprOpt::COMMAND); 168 stmt->orig = line; 169 out_stmts_->push_back(stmt); 170 return; 171 } 172 173 line = TrimLeftSpace(line); 174 175 if (line[0] == '#') 176 return; 177 178 if (HandleDirective(line, make_directives_)) { 179 return; 180 } 181 182 ParseRuleOrAssign(line); 183 } 184 185 void ParseRuleOrAssign(StringPiece line) { 186 size_t sep = FindThreeOutsideParen(line, ':', '=', ';'); 187 if (sep == string::npos || line[sep] == ';') { 188 ParseRule(line, string::npos); 189 } else if (line[sep] == '=') { 190 ParseAssign(line, sep); 191 } else if (line.get(sep+1) == '=') { 192 ParseAssign(line, sep+1); 193 } else if (line[sep] == ':') { 194 ParseRule(line, sep); 195 } else { 196 CHECK(false); 197 } 198 } 199 200 void ParseRule(StringPiece line, size_t sep) { 201 if (current_directive_ != AssignDirective::NONE) { 202 if (IsInExport()) 203 return; 204 if (sep != string::npos) { 205 sep += orig_line_with_directives_.size() - line.size(); 206 } 207 line = orig_line_with_directives_; 208 } 209 210 line = TrimLeftSpace(line); 211 if (line.empty()) 212 return; 213 214 if (orig_line_with_directives_[0] == '\t') { 215 Error("*** commands commence before first target."); 216 return; 217 } 218 219 const bool is_rule = sep != string::npos && line[sep] == ':'; 220 RuleStmt* stmt = new RuleStmt(); 221 stmt->set_loc(loc_); 222 223 size_t found = FindTwoOutsideParen(line.substr(sep + 1), '=', ';'); 224 if (found != string::npos) { 225 found += sep + 1; 226 stmt->term = line[found]; 227 ParseExprOpt opt = 228 stmt->term == ';' ? ParseExprOpt::COMMAND : ParseExprOpt::NORMAL; 229 stmt->after_term = ParseExpr(TrimLeftSpace(line.substr(found + 1)), opt); 230 stmt->expr = ParseExpr(TrimSpace(line.substr(0, found))); 231 } else { 232 stmt->term = 0; 233 stmt->after_term = NULL; 234 stmt->expr = ParseExpr(line); 235 } 236 out_stmts_->push_back(stmt); 237 state_ = is_rule ? ParserState::AFTER_RULE : ParserState::MAYBE_AFTER_RULE; 238 } 239 240 void ParseAssign(StringPiece line, size_t sep) { 241 if (sep == 0) { 242 Error("*** empty variable name ***"); 243 return; 244 } 245 StringPiece lhs; 246 StringPiece rhs; 247 AssignOp op; 248 ParseAssignStatement(line, sep, &lhs, &rhs, &op); 249 250 AssignStmt* stmt = new AssignStmt(); 251 stmt->set_loc(loc_); 252 stmt->lhs = ParseExpr(lhs); 253 stmt->rhs = ParseExpr(rhs); 254 stmt->orig_rhs = rhs; 255 stmt->op = op; 256 stmt->directive = current_directive_; 257 out_stmts_->push_back(stmt); 258 state_ = ParserState::NOT_AFTER_RULE; 259 } 260 261 void ParseInclude(StringPiece line, StringPiece directive) { 262 IncludeStmt* stmt = new IncludeStmt(); 263 stmt->set_loc(loc_); 264 stmt->expr = ParseExpr(line); 265 stmt->should_exist = directive[0] == 'i'; 266 out_stmts_->push_back(stmt); 267 state_ = ParserState::NOT_AFTER_RULE; 268 } 269 270 void ParseDefine(StringPiece line, StringPiece) { 271 if (line.empty()) { 272 Error("*** empty variable name."); 273 return; 274 } 275 define_name_ = line; 276 define_start_ = 0; 277 define_start_line_ = loc_.lineno; 278 state_ = ParserState::NOT_AFTER_RULE; 279 } 280 281 void ParseInsideDefine(StringPiece line) { 282 line = TrimLeftSpace(line); 283 if (GetDirective(line) != "endef") { 284 if (define_start_ == 0) 285 define_start_ = l_; 286 return; 287 } 288 289 StringPiece rest = TrimRightSpace(RemoveComment(TrimLeftSpace( 290 line.substr(sizeof("endef"))))); 291 if (!rest.empty()) { 292 WARN("%s:%d: extraneous text after `endef' directive", LOCF(loc_)); 293 } 294 295 AssignStmt* stmt = new AssignStmt(); 296 stmt->set_loc(Loc(loc_.filename, define_start_line_)); 297 stmt->lhs = ParseExpr(define_name_); 298 StringPiece rhs; 299 if (define_start_) 300 rhs = buf_.substr(define_start_, l_ - define_start_ - 1); 301 stmt->rhs = ParseExpr(rhs, ParseExprOpt::DEFINE); 302 stmt->orig_rhs = rhs; 303 stmt->op = AssignOp::EQ; 304 stmt->directive = current_directive_; 305 out_stmts_->push_back(stmt); 306 define_name_.clear(); 307 } 308 309 void EnterIf(IfStmt* stmt) { 310 IfState* st = new IfState(); 311 st->stmt = stmt; 312 st->is_in_else = false; 313 st->num_nest = num_if_nest_; 314 if_stack_.push(st); 315 out_stmts_ = &stmt->true_stmts; 316 } 317 318 void ParseIfdef(StringPiece line, StringPiece directive) { 319 IfStmt* stmt = new IfStmt(); 320 stmt->set_loc(loc_); 321 stmt->op = directive[2] == 'n' ? CondOp::IFNDEF : CondOp::IFDEF; 322 stmt->lhs = ParseExpr(line); 323 stmt->rhs = NULL; 324 out_stmts_->push_back(stmt); 325 EnterIf(stmt); 326 } 327 328 bool ParseIfEqCond(StringPiece s, IfStmt* stmt) { 329 if (s.empty()) { 330 return false; 331 } 332 333 if (s[0] == '(' && s[s.size() - 1] == ')') { 334 s = s.substr(1, s.size() - 2); 335 char terms[] = {',', '\0'}; 336 size_t n; 337 stmt->lhs = ParseExprImpl(loc_, s, terms, ParseExprOpt::NORMAL, &n, true); 338 if (s[n] != ',') 339 return false; 340 s = TrimLeftSpace(s.substr(n+1)); 341 stmt->rhs = ParseExprImpl(loc_, s, NULL, ParseExprOpt::NORMAL, &n); 342 s = TrimLeftSpace(s.substr(n)); 343 } else { 344 for (int i = 0; i < 2; i++) { 345 if (s.empty()) 346 return false; 347 char quote = s[0]; 348 if (quote != '\'' && quote != '"') 349 return false; 350 size_t end = s.find(quote, 1); 351 if (end == string::npos) 352 return false; 353 Value* v = ParseExpr(s.substr(1, end - 1), ParseExprOpt::NORMAL); 354 if (i == 0) 355 stmt->lhs = v; 356 else 357 stmt->rhs = v; 358 s = TrimLeftSpace(s.substr(end+1)); 359 } 360 } 361 if (!s.empty()) { 362 WARN("%s:%d: extraneous text after `ifeq' directive", LOCF(loc_)); 363 return true; 364 } 365 return true; 366 } 367 368 void ParseIfeq(StringPiece line, StringPiece directive) { 369 IfStmt* stmt = new IfStmt(); 370 stmt->set_loc(loc_); 371 stmt->op = directive[2] == 'n' ? CondOp::IFNEQ : CondOp::IFEQ; 372 373 if (!ParseIfEqCond(line, stmt)) { 374 Error("*** invalid syntax in conditional."); 375 return; 376 } 377 378 out_stmts_->push_back(stmt); 379 EnterIf(stmt); 380 } 381 382 void ParseElse(StringPiece line, StringPiece) { 383 if (!CheckIfStack("else")) 384 return; 385 IfState* st = if_stack_.top(); 386 if (st->is_in_else) { 387 Error("*** only one `else' per conditional."); 388 return; 389 } 390 st->is_in_else = true; 391 out_stmts_ = &st->stmt->false_stmts; 392 393 StringPiece next_if = TrimLeftSpace(line); 394 if (next_if.empty()) 395 return; 396 397 num_if_nest_ = st->num_nest + 1; 398 if (!HandleDirective(next_if, else_if_directives_)) { 399 WARN("%s:%d: extraneous text after `else' directive", LOCF(loc_)); 400 } 401 num_if_nest_ = 0; 402 } 403 404 void ParseEndif(StringPiece line, StringPiece) { 405 if (!CheckIfStack("endif")) 406 return; 407 if (!line.empty()) { 408 Error("extraneous text after `endif` directive"); 409 return; 410 } 411 IfState st = *if_stack_.top(); 412 for (int t = 0; t <= st.num_nest; t++) { 413 delete if_stack_.top(); 414 if_stack_.pop(); 415 if (if_stack_.empty()) { 416 out_stmts_ = stmts_; 417 } else { 418 IfState* st = if_stack_.top(); 419 if (st->is_in_else) 420 out_stmts_ = &st->stmt->false_stmts; 421 else 422 out_stmts_ = &st->stmt->true_stmts; 423 } 424 } 425 } 426 427 bool IsInExport() const { 428 return (static_cast<int>(current_directive_) & 429 static_cast<int>(AssignDirective::EXPORT)); 430 } 431 432 void CreateExport(StringPiece line, bool is_export) { 433 ExportStmt* stmt = new ExportStmt; 434 stmt->set_loc(loc_); 435 stmt->expr = ParseExpr(line); 436 stmt->is_export = is_export; 437 out_stmts_->push_back(stmt); 438 } 439 440 void ParseOverride(StringPiece line, StringPiece) { 441 current_directive_ = 442 static_cast<AssignDirective>( 443 (static_cast<int>(current_directive_) | 444 static_cast<int>(AssignDirective::OVERRIDE))); 445 if (HandleDirective(line, assign_directives_)) 446 return; 447 if (IsInExport()) { 448 CreateExport(line, true); 449 } 450 ParseRuleOrAssign(line); 451 } 452 453 void ParseExport(StringPiece line, StringPiece) { 454 current_directive_ = 455 static_cast<AssignDirective>( 456 (static_cast<int>(current_directive_) | 457 static_cast<int>(AssignDirective::EXPORT))); 458 if (HandleDirective(line, assign_directives_)) 459 return; 460 CreateExport(line, true); 461 ParseRuleOrAssign(line); 462 } 463 464 void ParseUnexport(StringPiece line, StringPiece) { 465 CreateExport(line, false); 466 } 467 468 bool CheckIfStack(const char* keyword) { 469 if (if_stack_.empty()) { 470 Error(StringPrintf("*** extraneous `%s'.", keyword)); 471 return false; 472 } 473 return true; 474 } 475 476 StringPiece RemoveComment(StringPiece line) { 477 size_t i = FindOutsideParen(line, '#'); 478 if (i == string::npos) 479 return line; 480 return line.substr(0, i); 481 } 482 483 StringPiece GetDirective(StringPiece line) { 484 if (line.size() < shortest_directive_len_) 485 return StringPiece(); 486 StringPiece prefix = line.substr(0, longest_directive_len_ + 1); 487 size_t space_index = prefix.find_first_of(" \t#"); 488 return prefix.substr(0, space_index); 489 } 490 491 bool HandleDirective(StringPiece line, const DirectiveMap* directive_map) { 492 StringPiece directive = GetDirective(line); 493 auto found = directive_map->find(directive); 494 if (found == directive_map->end()) 495 return false; 496 497 StringPiece rest = TrimRightSpace(RemoveComment(TrimLeftSpace( 498 line.substr(directive.size())))); 499 (this->*found->second)(rest, directive); 500 return true; 501 } 502 503 StringPiece buf_; 504 size_t l_; 505 ParserState state_; 506 507 vector<Stmt*>* stmts_; 508 vector<Stmt*>* out_stmts_; 509 510 StringPiece define_name_; 511 size_t define_start_; 512 int define_start_line_; 513 514 StringPiece orig_line_with_directives_; 515 AssignDirective current_directive_; 516 517 int num_if_nest_; 518 stack<IfState*> if_stack_; 519 520 Loc loc_; 521 bool fixed_lineno_; 522 523 static DirectiveMap* make_directives_; 524 static DirectiveMap* else_if_directives_; 525 static DirectiveMap* assign_directives_; 526 static size_t shortest_directive_len_; 527 static size_t longest_directive_len_; 528 }; 529 530 void Parse(Makefile* mk) { 531 COLLECT_STATS("parse file time"); 532 Parser parser(StringPiece(mk->buf()), 533 mk->filename().c_str(), 534 mk->mutable_stmts()); 535 parser.Parse(); 536 } 537 538 void Parse(StringPiece buf, const Loc& loc, vector<Stmt*>* out_stmts) { 539 COLLECT_STATS("parse eval time"); 540 Parser parser(buf, loc, out_stmts); 541 parser.Parse(); 542 } 543 544 void ParseNotAfterRule(StringPiece buf, const Loc& loc, 545 vector<Stmt*>* out_stmts) { 546 Parser parser(buf, loc, out_stmts); 547 parser.set_state(ParserState::NOT_AFTER_RULE); 548 parser.Parse(); 549 } 550 551 void InitParser() { 552 Parser::Init(); 553 } 554 555 void QuitParser() { 556 Parser::Quit(); 557 } 558 559 Parser::DirectiveMap* Parser::make_directives_; 560 Parser::DirectiveMap* Parser::else_if_directives_; 561 Parser::DirectiveMap* Parser::assign_directives_; 562 size_t Parser::shortest_directive_len_; 563 size_t Parser::longest_directive_len_; 564 vector<ParseErrorStmt*> Parser::parse_errors; 565 566 void ParseAssignStatement(StringPiece line, size_t sep, 567 StringPiece* lhs, StringPiece* rhs, AssignOp* op) { 568 CHECK(sep != 0); 569 *op = AssignOp::EQ; 570 size_t lhs_end = sep; 571 switch (line[sep-1]) { 572 case ':': 573 lhs_end--; 574 *op = AssignOp::COLON_EQ; 575 break; 576 case '+': 577 lhs_end--; 578 *op = AssignOp::PLUS_EQ; 579 break; 580 case '?': 581 lhs_end--; 582 *op = AssignOp::QUESTION_EQ; 583 break; 584 } 585 *lhs = TrimSpace(line.substr(0, lhs_end)); 586 *rhs = TrimLeftSpace(line.substr(sep + 1)); 587 } 588 589 const vector<ParseErrorStmt*>& GetParseErrors() { 590 return Parser::parse_errors; 591 } 592