blob: 58ea3ba8f3c998ec6788b68c334e5b14656ce83d [file] [log] [blame]
Shinichiro Hamaji776ca302015-06-06 03:52:48 +09001#include "parser.h"
2
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +09003#include <unordered_map>
4
Shinichiro Hamaji776ca302015-06-06 03:52:48 +09005#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();) {
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090035 size_t lf_cnt = 0;
36 size_t e = FindEndOfLine(&lf_cnt);
Shinichiro Hamaji8ee8c372015-06-16 16:19:40 +090037 if (!fixed_lineno_)
38 loc_.lineno += lf_cnt;
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090039 StringPiece line(buf_.data() + l_, e - l_);
40 ParseLine(line);
41 if (e == buf_.size())
42 break;
43
44 l_ = e + 1;
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090045 }
46 }
47
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +090048 static void Init() {
49 make_directives_ = new unordered_map<StringPiece, DirectiveHandler>;
50 (*make_directives_)["include"] = &Parser::ParseIncludeAST;
51 (*make_directives_)["-include"] = &Parser::ParseIncludeAST;
Shinichiro Hamajiefad2dd2015-06-17 03:08:02 +090052 (*make_directives_)["sinclude"] = &Parser::ParseIncludeAST;
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +090053
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
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090067 private:
68 void Error(const string& msg) {
Shinichiro Hamaji8ee8c372015-06-16 16:19:40 +090069 ERROR("%s:%d: %s", LOCF(loc_), msg.c_str());
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090070 }
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
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900102 line = line.StripLeftSpaces();
103 if (HandleDirective(line)) {
104 return;
105 }
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900106
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
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900172 void ParseIncludeAST(StringPiece line, StringPiece directive) {
173 IncludeAST* ast = new IncludeAST();
174 ast->expr = ParseExpr(line, false);
Shinichiro Hamajiefad2dd2015-06-17 03:08:02 +0900175 ast->should_exist = directive[0] == 'i';
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900176 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
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900195 StringPiece buf_;
196 size_t l_;
197 ParserState state_;
198
199 vector<AST*>* out_asts_;
200
201 Loc loc_;
202 bool fixed_lineno_;
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900203
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_;
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900209};
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}
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900217
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_;