parser.cc revision 810fd03ef36afedeef832c5e78171b9e26a97e00
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 "strutil.h" 11#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();) { 36 size_t lf_cnt = 0; 37 size_t e = FindEndOfLine(&lf_cnt); 38 if (!fixed_lineno_) 39 loc_.lineno += lf_cnt; 40 StringPiece line(buf_.data() + l_, e - l_); 41 ParseLine(line); 42 if (e == buf_.size()) 43 break; 44 45 l_ = e + 1; 46 } 47 } 48 49 static void Init() { 50 make_directives_ = new unordered_map<StringPiece, DirectiveHandler>; 51 (*make_directives_)["include"] = &Parser::ParseInclude; 52 (*make_directives_)["-include"] = &Parser::ParseInclude; 53 (*make_directives_)["sinclude"] = &Parser::ParseInclude; 54 (*make_directives_)["define"] = &Parser::ParseDefine; 55 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 69 private: 70 void Error(const string& msg) { 71 ERROR("%s:%d: %s", LOCF(loc_), msg.c_str()); 72 } 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 97 if (!define_name_.empty()) { 98 ParseInsideDefine(line); 99 return; 100 } 101 102 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 109 line = line.StripLeftSpaces(); 110 111 if (line[0] == '#') 112 return; 113 114 if (HandleDirective(line)) { 115 return; 116 } 117 118 size_t sep = line.find_first_of(STRING_PIECE("=:")); 119 if (sep == string::npos) { 120 ParseRule(line, sep); 121 } else if (line[sep] == '=') { 122 ParseAssign(line, sep); 123 } else if (line.get(sep+1) == '=') { 124 ParseAssign(line, sep+1); 125 } else if (line[sep] == ':') { 126 ParseRule(line, sep); 127 } else { 128 CHECK(false); 129 } 130 } 131 132 void ParseRule(StringPiece line, size_t sep) { 133 const bool is_rule = line.find(':') != string::npos; 134 RuleAST* ast = new RuleAST(); 135 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]; 141 ast->after_term = ParseExpr(line.substr(found + 1).StripLeftSpaces(), 142 ast->term == ';'); 143 ast->expr = ParseExpr(line.substr(0, found).StripSpaces(), false); 144 } else { 145 ast->term = 0; 146 ast->after_term = NULL; 147 ast->expr = ParseExpr(line.StripSpaces(), false); 148 } 149 out_asts_->push_back(ast); 150 state_ = is_rule ? ParserState::AFTER_RULE : ParserState::MAYBE_AFTER_RULE; 151 } 152 153 void ParseAssign(StringPiece line, size_t sep) { 154 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 173 AssignAST* ast = new AssignAST(); 174 ast->set_loc(loc_); 175 ast->lhs = ParseExpr(line.substr(0, lhs_end).StripSpaces(), false); 176 ast->rhs = ParseExpr(line.substr(sep + 1).StripLeftSpaces(), false); 177 ast->op = op; 178 ast->directive = AssignDirective::NONE; 179 out_asts_->push_back(ast); 180 state_ = ParserState::NOT_AFTER_RULE; 181 } 182 183 void ParseInclude(StringPiece line, StringPiece directive) { 184 IncludeAST* ast = new IncludeAST(); 185 ast->expr = ParseExpr(line, false); 186 ast->should_exist = directive[0] == 'i'; 187 out_asts_->push_back(ast); 188 } 189 190 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) { 200 if (line.StripLeftSpaces() != "endef") { 201 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_) 211 rhs = buf_.substr(define_start_, l_ - define_start_).StripRightSpaces(); 212 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 219 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 231 StringPiece rest = line.substr(directive.size() + 1).StripLeftSpaces(); 232 (this->*found->second)(rest, directive); 233 return true; 234 } 235 236 StringPiece buf_; 237 size_t l_; 238 ParserState state_; 239 240 vector<AST*>* out_asts_; 241 StringPiece define_name_; 242 size_t define_start_; 243 int define_start_line_; 244 245 Loc loc_; 246 bool fixed_lineno_; 247 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_; 253}; 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} 261 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_; 273