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