parser.cc revision efad2dd288a5b5466c23b2dd7f275c25910e987a
1#include "parser.h" 2 3#include <unordered_map> 4 5#include "ast.h" 6#include "file.h" 7#include "loc.h" 8#include "log.h" 9#include "string_piece.h" 10#include "value.h" 11 12enum struct ParserState { 13 NOT_AFTER_RULE = 0, 14 AFTER_RULE, 15 MAYBE_AFTER_RULE, 16}; 17 18class Parser { 19 public: 20 Parser(StringPiece buf, const char* filename, vector<AST*>* asts) 21 : buf_(buf), 22 state_(ParserState::NOT_AFTER_RULE), 23 out_asts_(asts), 24 loc_(filename, 0), 25 fixed_lineno_(false) { 26 } 27 28 ~Parser() { 29 } 30 31 void Parse() { 32 l_ = 0; 33 34 for (l_ = 0; l_ < buf_.size();) { 35 size_t lf_cnt = 0; 36 size_t e = FindEndOfLine(&lf_cnt); 37 if (!fixed_lineno_) 38 loc_.lineno += lf_cnt; 39 StringPiece line(buf_.data() + l_, e - l_); 40 ParseLine(line); 41 if (e == buf_.size()) 42 break; 43 44 l_ = e + 1; 45 } 46 } 47 48 static void Init() { 49 make_directives_ = new unordered_map<StringPiece, DirectiveHandler>; 50 (*make_directives_)["include"] = &Parser::ParseIncludeAST; 51 (*make_directives_)["-include"] = &Parser::ParseIncludeAST; 52 (*make_directives_)["sinclude"] = &Parser::ParseIncludeAST; 53 54 shortest_directive_len_ = 9999; 55 longest_directive_len_ = 0; 56 for (auto p : *make_directives_) { 57 size_t len = p.first.size(); 58 shortest_directive_len_ = min(len, shortest_directive_len_); 59 longest_directive_len_ = max(len, longest_directive_len_); 60 } 61 } 62 63 static void Quit() { 64 delete make_directives_; 65 } 66 67 private: 68 void Error(const string& msg) { 69 ERROR("%s:%d: %s", LOCF(loc_), msg.c_str()); 70 } 71 72 size_t FindEndOfLine(size_t* lf_cnt) { 73 size_t e = l_; 74 bool prev_backslash = false; 75 for (; e < buf_.size(); e++) { 76 char c = buf_[e]; 77 if (c == '\\') { 78 prev_backslash = !prev_backslash; 79 } else if (c == '\n') { 80 ++*lf_cnt; 81 if (!prev_backslash) { 82 return e; 83 } 84 } else if (c != '\r') { 85 prev_backslash = false; 86 } 87 } 88 return e; 89 } 90 91 void ParseLine(StringPiece line) { 92 if (line.empty() || (line.size() == 1 && line[0] == '\r')) 93 return; 94 95 if (line[0] == '\t' && state_ != ParserState::NOT_AFTER_RULE) { 96 CommandAST* ast = new CommandAST(); 97 ast->expr = ParseExpr(line.substr(1), true); 98 out_asts_->push_back(ast); 99 return; 100 } 101 102 line = line.StripLeftSpaces(); 103 if (HandleDirective(line)) { 104 return; 105 } 106 107 size_t sep = line.find_first_of(STRING_PIECE("=:")); 108 if (sep == string::npos) { 109 ParseRuleAST(line, sep); 110 } else if (line[sep] == '=') { 111 ParseAssignAST(line, sep); 112 } else if (line.get(sep+1) == '=') { 113 ParseAssignAST(line, sep+1); 114 } else if (line[sep] == ':') { 115 ParseRuleAST(line, sep); 116 } else { 117 CHECK(false); 118 } 119 } 120 121 void ParseRuleAST(StringPiece line, size_t sep) { 122 const bool is_rule = line.find(':') != string::npos; 123 RuleAST* ast = new RuleAST; 124 ast->set_loc(loc_); 125 126 size_t found = line.substr(sep + 1).find_first_of("=;"); 127 if (found != string::npos) { 128 found += sep + 1; 129 ast->term = line[found]; 130 ast->after_term = ParseExpr(line.substr(found + 1).StripLeftSpaces(), 131 ast->term == ';'); 132 ast->expr = ParseExpr(line.substr(0, found).StripSpaces(), false); 133 } else { 134 ast->term = 0; 135 ast->after_term = NULL; 136 ast->expr = ParseExpr(line.StripSpaces(), false); 137 } 138 out_asts_->push_back(ast); 139 state_ = is_rule ? ParserState::AFTER_RULE : ParserState::MAYBE_AFTER_RULE; 140 } 141 142 void ParseAssignAST(StringPiece line, size_t sep) { 143 if (sep == 0) 144 Error("*** empty variable name ***"); 145 AssignOp op = AssignOp::EQ; 146 size_t lhs_end = sep; 147 switch (line[sep-1]) { 148 case ':': 149 lhs_end--; 150 op = AssignOp::COLON_EQ; 151 break; 152 case '+': 153 lhs_end--; 154 op = AssignOp::PLUS_EQ; 155 break; 156 case '?': 157 lhs_end--; 158 op = AssignOp::QUESTION_EQ; 159 break; 160 } 161 162 AssignAST* ast = new AssignAST; 163 ast->set_loc(loc_); 164 ast->lhs = ParseExpr(line.substr(0, lhs_end).StripSpaces(), false); 165 ast->rhs = ParseExpr(line.substr(sep + 1).StripLeftSpaces(), false); 166 ast->op = op; 167 ast->directive = AssignDirective::NONE; 168 out_asts_->push_back(ast); 169 state_ = ParserState::NOT_AFTER_RULE; 170 } 171 172 void ParseIncludeAST(StringPiece line, StringPiece directive) { 173 IncludeAST* ast = new IncludeAST(); 174 ast->expr = ParseExpr(line, false); 175 ast->should_exist = directive[0] == 'i'; 176 out_asts_->push_back(ast); 177 } 178 179 bool HandleDirective(StringPiece line) { 180 if (line.size() < shortest_directive_len_) 181 return false; 182 StringPiece prefix = line.substr(0, longest_directive_len_ + 1); 183 size_t space_index = prefix.find(' '); 184 if (space_index == string::npos) 185 return false; 186 StringPiece directive = prefix.substr(0, space_index); 187 auto found = make_directives_->find(directive); 188 if (found == make_directives_->end()) 189 return false; 190 191 (this->*found->second)(line.substr(directive.size() + 1), directive); 192 return true; 193 } 194 195 StringPiece buf_; 196 size_t l_; 197 ParserState state_; 198 199 vector<AST*>* out_asts_; 200 201 Loc loc_; 202 bool fixed_lineno_; 203 204 typedef void (Parser::*DirectiveHandler)( 205 StringPiece line, StringPiece directive); 206 static unordered_map<StringPiece, DirectiveHandler>* make_directives_; 207 static size_t shortest_directive_len_; 208 static size_t longest_directive_len_; 209}; 210 211void Parse(Makefile* mk) { 212 Parser parser(StringPiece(mk->buf(), mk->len()), 213 mk->filename().c_str(), 214 mk->mutable_asts()); 215 parser.Parse(); 216} 217 218void InitParser() { 219 Parser::Init(); 220} 221 222void QuitParser() { 223 Parser::Quit(); 224} 225 226unordered_map<StringPiece, Parser::DirectiveHandler>* Parser::make_directives_; 227size_t Parser::shortest_directive_len_; 228size_t Parser::longest_directive_len_; 229