blob: 9ddd8cc03680cc3a6cad05fd3c32be73db8698d2 [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;
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
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090066 private:
67 void Error(const string& msg) {
Shinichiro Hamaji8ee8c372015-06-16 16:19:40 +090068 ERROR("%s:%d: %s", LOCF(loc_), msg.c_str());
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090069 }
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
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900101 line = line.StripLeftSpaces();
102 if (HandleDirective(line)) {
103 return;
104 }
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900105
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
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900171 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
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900194 StringPiece buf_;
195 size_t l_;
196 ParserState state_;
197
198 vector<AST*>* out_asts_;
199
200 Loc loc_;
201 bool fixed_lineno_;
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900202
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_;
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900208};
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}
Shinichiro Hamaji42b625f2015-06-16 23:07:21 +0900216
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_;