blob: 526b8feffc1bdbd6ed2f864016274746983f9735 [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();) {
33 if (!fixed_lineno_)
34 ++loc_.lineno;
35 size_t lf_cnt = 0;
36 size_t e = FindEndOfLine(&lf_cnt);
37 StringPiece line(buf_.data() + l_, e - l_);
38 ParseLine(line);
39 if (e == buf_.size())
40 break;
41
42 l_ = e + 1;
43 loc_.lineno += lf_cnt;
44 }
45 }
46
47 private:
48 void Error(const string& msg) {
49 ERROR("%s:%d: %s", loc_.filename, loc_.lineno, msg.c_str());
50 }
51
52 size_t FindEndOfLine(size_t* lf_cnt) {
53 size_t e = l_;
54 bool prev_backslash = false;
55 for (; e < buf_.size(); e++) {
56 char c = buf_[e];
57 if (c == '\\') {
58 prev_backslash = !prev_backslash;
59 } else if (c == '\n') {
60 ++*lf_cnt;
61 if (!prev_backslash) {
62 return e;
63 }
64 } else if (c != '\r') {
65 prev_backslash = false;
66 }
67 }
68 return e;
69 }
70
71 void ParseLine(StringPiece line) {
72 if (line.empty() || (line.size() == 1 && line[0] == '\r'))
73 return;
74
75 if (line[0] == '\t' && state_ != ParserState::NOT_AFTER_RULE) {
76 CommandAST* ast = new CommandAST();
77 ast->expr = ParseExpr(line.substr(1), true);
78 out_asts_->push_back(ast);
79 return;
80 }
81
82 // TODO: directive.
83
84 size_t sep = line.find_first_of(STRING_PIECE("=:"));
85 if (sep == string::npos) {
86 ParseRuleAST(line, sep);
87 } else if (line[sep] == '=') {
88 ParseAssignAST(line, sep);
89 } else if (line.get(sep+1) == '=') {
90 ParseAssignAST(line, sep+1);
91 } else if (line[sep] == ':') {
92 ParseRuleAST(line, sep);
93 } else {
94 CHECK(false);
95 }
96 }
97
98 void ParseRuleAST(StringPiece line, size_t sep) {
99 const bool is_rule = line.find(':') != string::npos;
100 RuleAST* ast = new RuleAST;
101 ast->set_loc(loc_);
102
103 size_t found = line.substr(sep + 1).find_first_of("=;");
104 if (found != string::npos) {
105 found += sep + 1;
106 ast->term = line[found];
107 ast->after_term = ParseExpr(line.substr(found + 1).StripLeftSpaces(),
108 ast->term == ';');
109 ast->expr = ParseExpr(line.substr(0, found).StripSpaces(), false);
110 } else {
111 ast->term = 0;
112 ast->after_term = NULL;
113 ast->expr = ParseExpr(line.StripSpaces(), false);
114 }
115 out_asts_->push_back(ast);
116 state_ = is_rule ? ParserState::AFTER_RULE : ParserState::MAYBE_AFTER_RULE;
117 }
118
119 void ParseAssignAST(StringPiece line, size_t sep) {
120 if (sep == 0)
121 Error("*** empty variable name ***");
122 AssignOp op = AssignOp::EQ;
123 size_t lhs_end = sep;
124 switch (line[sep-1]) {
125 case ':':
126 lhs_end--;
127 op = AssignOp::COLON_EQ;
128 break;
129 case '+':
130 lhs_end--;
131 op = AssignOp::PLUS_EQ;
132 break;
133 case '?':
134 lhs_end--;
135 op = AssignOp::QUESTION_EQ;
136 break;
137 }
138
139 AssignAST* ast = new AssignAST;
140 ast->set_loc(loc_);
141 ast->lhs = ParseExpr(line.substr(0, lhs_end).StripSpaces(), false);
142 ast->rhs = ParseExpr(line.substr(sep + 1).StripLeftSpaces(), false);
143 ast->op = op;
144 ast->directive = AssignDirective::NONE;
145 out_asts_->push_back(ast);
146 state_ = ParserState::NOT_AFTER_RULE;
147 }
148
149 StringPiece buf_;
150 size_t l_;
151 ParserState state_;
152
153 vector<AST*>* out_asts_;
154
155 Loc loc_;
156 bool fixed_lineno_;
157};
158
159void Parse(Makefile* mk) {
160 Parser parser(StringPiece(mk->buf(), mk->len()),
161 mk->filename().c_str(),
162 mk->mutable_asts());
163 parser.Parse();
164}