blob: 8d872de9032a4850c9d1010ad3b796bc769827eb [file] [log] [blame]
Shinichiro Hamaji776ca302015-06-06 03:52:48 +09001#include "parser.h"
2
3#include "ast.h"
4#include "file.h"
5#include "loc.h"
6#include "log.h"
7#include "string_piece.h"
8#include "value.h"
9
10enum struct ParserState {
11 NOT_AFTER_RULE = 0,
12 AFTER_RULE,
13 MAYBE_AFTER_RULE,
14};
15
16class Parser {
17 public:
18 Parser(StringPiece buf, const char* filename, vector<AST*>* asts)
19 : buf_(buf),
20 state_(ParserState::NOT_AFTER_RULE),
21 out_asts_(asts),
22 loc_(filename, 0),
23 fixed_lineno_(false) {
24 }
25
26 ~Parser() {
27 }
28
29 void Parse() {
30 l_ = 0;
31
32 for (l_ = 0; l_ < buf_.size();) {
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090033 size_t lf_cnt = 0;
34 size_t e = FindEndOfLine(&lf_cnt);
Shinichiro Hamaji8ee8c372015-06-16 16:19:40 +090035 if (!fixed_lineno_)
36 loc_.lineno += lf_cnt;
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090037 StringPiece line(buf_.data() + l_, e - l_);
38 ParseLine(line);
39 if (e == buf_.size())
40 break;
41
42 l_ = e + 1;
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090043 }
44 }
45
46 private:
47 void Error(const string& msg) {
Shinichiro Hamaji8ee8c372015-06-16 16:19:40 +090048 ERROR("%s:%d: %s", LOCF(loc_), msg.c_str());
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090049 }
50
51 size_t FindEndOfLine(size_t* lf_cnt) {
52 size_t e = l_;
53 bool prev_backslash = false;
54 for (; e < buf_.size(); e++) {
55 char c = buf_[e];
56 if (c == '\\') {
57 prev_backslash = !prev_backslash;
58 } else if (c == '\n') {
59 ++*lf_cnt;
60 if (!prev_backslash) {
61 return e;
62 }
63 } else if (c != '\r') {
64 prev_backslash = false;
65 }
66 }
67 return e;
68 }
69
70 void ParseLine(StringPiece line) {
71 if (line.empty() || (line.size() == 1 && line[0] == '\r'))
72 return;
73
74 if (line[0] == '\t' && state_ != ParserState::NOT_AFTER_RULE) {
75 CommandAST* ast = new CommandAST();
76 ast->expr = ParseExpr(line.substr(1), true);
77 out_asts_->push_back(ast);
78 return;
79 }
80
81 // TODO: directive.
82
83 size_t sep = line.find_first_of(STRING_PIECE("=:"));
84 if (sep == string::npos) {
85 ParseRuleAST(line, sep);
86 } else if (line[sep] == '=') {
87 ParseAssignAST(line, sep);
88 } else if (line.get(sep+1) == '=') {
89 ParseAssignAST(line, sep+1);
90 } else if (line[sep] == ':') {
91 ParseRuleAST(line, sep);
92 } else {
93 CHECK(false);
94 }
95 }
96
97 void ParseRuleAST(StringPiece line, size_t sep) {
98 const bool is_rule = line.find(':') != string::npos;
99 RuleAST* ast = new RuleAST;
100 ast->set_loc(loc_);
101
102 size_t found = line.substr(sep + 1).find_first_of("=;");
103 if (found != string::npos) {
104 found += sep + 1;
105 ast->term = line[found];
106 ast->after_term = ParseExpr(line.substr(found + 1).StripLeftSpaces(),
107 ast->term == ';');
108 ast->expr = ParseExpr(line.substr(0, found).StripSpaces(), false);
109 } else {
110 ast->term = 0;
111 ast->after_term = NULL;
112 ast->expr = ParseExpr(line.StripSpaces(), false);
113 }
114 out_asts_->push_back(ast);
115 state_ = is_rule ? ParserState::AFTER_RULE : ParserState::MAYBE_AFTER_RULE;
116 }
117
118 void ParseAssignAST(StringPiece line, size_t sep) {
119 if (sep == 0)
120 Error("*** empty variable name ***");
121 AssignOp op = AssignOp::EQ;
122 size_t lhs_end = sep;
123 switch (line[sep-1]) {
124 case ':':
125 lhs_end--;
126 op = AssignOp::COLON_EQ;
127 break;
128 case '+':
129 lhs_end--;
130 op = AssignOp::PLUS_EQ;
131 break;
132 case '?':
133 lhs_end--;
134 op = AssignOp::QUESTION_EQ;
135 break;
136 }
137
138 AssignAST* ast = new AssignAST;
139 ast->set_loc(loc_);
140 ast->lhs = ParseExpr(line.substr(0, lhs_end).StripSpaces(), false);
141 ast->rhs = ParseExpr(line.substr(sep + 1).StripLeftSpaces(), false);
142 ast->op = op;
143 ast->directive = AssignDirective::NONE;
144 out_asts_->push_back(ast);
145 state_ = ParserState::NOT_AFTER_RULE;
146 }
147
148 StringPiece buf_;
149 size_t l_;
150 ParserState state_;
151
152 vector<AST*>* out_asts_;
153
154 Loc loc_;
155 bool fixed_lineno_;
156};
157
158void Parse(Makefile* mk) {
159 Parser parser(StringPiece(mk->buf(), mk->len()),
160 mk->filename().c_str(),
161 mk->mutable_asts());
162 parser.Parse();
163}