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