aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--eval.cc17
-rw-r--r--parser.cc47
-rw-r--r--parser.h5
-rw-r--r--rule.cc76
-rw-r--r--rule.h15
-rw-r--r--strutil.cc1
6 files changed, 123 insertions, 38 deletions
diff --git a/eval.cc b/eval.cc
index 93357b3..16791fa 100644
--- a/eval.cc
+++ b/eval.cc
@@ -87,13 +87,18 @@ void Evaluator::EvalRule(const RuleAST* ast) {
if (expr->find_first_not_of(" \t\n;") == string::npos)
return;
- Rule* rule = new Rule;
- rule->loc = loc_;
- rule->Parse(*expr);
+ Rule* rule;
+ RuleVar rule_var;
+ ParseRule(loc_, *expr, &rule, &rule_var);
+
+ if (rule) {
+ LOG("Rule: %s", rule->DebugString().c_str());
+ rules_.push_back(rule);
+ last_rule_ = rule;
+ return;
+ }
- LOG("Rule: %s", rule->DebugString().c_str());
- rules_.push_back(rule);
- last_rule_ = rule;
+ CHECK(false);
}
void Evaluator::EvalCommand(const CommandAST* ast) {
diff --git a/parser.cc b/parser.cc
index 31347c6..d2f0098 100644
--- a/parser.cc
+++ b/parser.cc
@@ -186,27 +186,15 @@ class Parser {
void ParseAssign(StringPiece line, size_t sep) {
if (sep == 0)
Error("*** empty variable name ***");
- AssignOp op = AssignOp::EQ;
- size_t lhs_end = sep;
- switch (line[sep-1]) {
- case ':':
- lhs_end--;
- op = AssignOp::COLON_EQ;
- break;
- case '+':
- lhs_end--;
- op = AssignOp::PLUS_EQ;
- break;
- case '?':
- lhs_end--;
- op = AssignOp::QUESTION_EQ;
- break;
- }
+ StringPiece lhs;
+ StringPiece rhs;
+ AssignOp op;
+ ParseAssignStatement(line, sep, &lhs, &rhs, &op);
AssignAST* ast = new AssignAST();
ast->set_loc(loc_);
- ast->lhs = ParseExpr(TrimSpace(line.substr(0, lhs_end)), false);
- ast->rhs = ParseExpr(TrimSpace(line.substr(sep + 1)), false);
+ ast->lhs = ParseExpr(lhs, false);
+ ast->rhs = ParseExpr(rhs, false);
ast->op = op;
ast->directive = AssignDirective::NONE;
out_asts_->push_back(ast);
@@ -446,3 +434,26 @@ Parser::DirectiveMap* Parser::make_directives_;
Parser::DirectiveMap* Parser::else_if_directives_;
size_t Parser::shortest_directive_len_;
size_t Parser::longest_directive_len_;
+
+void ParseAssignStatement(StringPiece line, size_t sep,
+ StringPiece* lhs, StringPiece* rhs, AssignOp* op) {
+ CHECK(sep != 0);
+ *op = AssignOp::EQ;
+ size_t lhs_end = sep;
+ switch (line[sep-1]) {
+ case ':':
+ lhs_end--;
+ *op = AssignOp::COLON_EQ;
+ break;
+ case '+':
+ lhs_end--;
+ *op = AssignOp::PLUS_EQ;
+ break;
+ case '?':
+ lhs_end--;
+ *op = AssignOp::QUESTION_EQ;
+ break;
+ }
+ *lhs = TrimSpace(line.substr(0, lhs_end));
+ *rhs = TrimSpace(line.substr(sep + 1));
+}
diff --git a/parser.h b/parser.h
index f0a29bc..c7e2e23 100644
--- a/parser.h
+++ b/parser.h
@@ -3,17 +3,20 @@
#include <vector>
+#include "ast.h"
#include "loc.h"
#include "string_piece.h"
using namespace std;
-class AST;
class Makefile;
void Parse(Makefile* mk);
void Parse(StringPiece buf, const Loc& loc, vector<AST*>* out_asts);
+void ParseAssignStatement(StringPiece line, size_t sep,
+ StringPiece* lhs, StringPiece* rhs, AssignOp* op);
+
void InitParser();
void QuitParser();
diff --git a/rule.cc b/rule.cc
index 54280a3..6ddd55a 100644
--- a/rule.cc
+++ b/rule.cc
@@ -1,10 +1,13 @@
#include "rule.h"
#include "log.h"
+#include "parser.h"
#include "stringprintf.h"
#include "strutil.h"
#include "value.h"
+namespace {
+
// Strip leading sequences of './' from file names, so that ./file
// and file are considered to be the same file.
// From http://www.gnu.org/software/make/manual/make.html#Features
@@ -30,27 +33,42 @@ static void ParseInputs(Rule* r, StringPiece s) {
}
}
+bool IsPatternRule(StringPiece s) {
+ return s.find('%') != string::npos;
+}
+
+} // namespace
+
Rule::Rule()
: is_double_colon(false),
is_suffix_rule(false),
cmd_lineno(0) {
}
-void Rule::Parse(StringPiece line) {
+void ParseRule(Loc& loc, StringPiece line,
+ Rule** out_rule, RuleVar* rule_var) {
size_t index = line.find(':');
if (index == string::npos) {
- Error("*** missing separator.");
+ ERROR("%s:%d: *** missing separator.", LOCF(loc));
}
StringPiece first = line.substr(0, index);
- // TODO: isPattern?
- if (false) {
- } else {
- for (StringPiece tok : WordScanner(first)) {
- outputs.push_back(Intern(TrimLeadingCurdir(tok)));
+ vector<StringPiece> outputs;
+ for (StringPiece tok : WordScanner(first)) {
+ outputs.push_back(Intern(TrimLeadingCurdir(tok)));
+ }
+
+ CHECK(!outputs.empty());
+ const bool is_first_pattern = IsPatternRule(outputs[0]);
+ if (is_first_pattern) {
+ if (outputs.size() > 1) {
+ // TODO: Multiple output patterns are not supported yet.
+ ERROR("%s:%d: *** mixed implicit and normal rules: deprecated syntax",
+ LOCF(loc));
}
}
+ bool is_double_colon = false;
index++;
if (line.get(index) == ':') {
is_double_colon = true;
@@ -58,15 +76,53 @@ void Rule::Parse(StringPiece line) {
}
StringPiece rest = line.substr(index);
+ size_t equal_index = rest.find('=');
+ if (equal_index != string::npos) {
+ rule_var->outputs.swap(outputs);
+ ParseAssignStatement(rest, equal_index,
+ &rule_var->lhs, &rule_var->rhs, &rule_var->op);
+ *out_rule = NULL;
+ return;
+ }
- // TODO: TSV
- //if (
+ Rule* rule = new Rule();
+ *out_rule = rule;
+ rule->loc = loc;
+ rule->is_double_colon = is_double_colon;
+ if (is_first_pattern) {
+ rule->output_patterns.swap(outputs);
+ } else {
+ rule->outputs.swap(outputs);
+ }
index = rest.find(':');
if (index == string::npos) {
- ParseInputs(this, rest);
+ ParseInputs(rule, rest);
return;
}
+
+ if (is_first_pattern) {
+ ERROR("%s:%d: *** mixed implicit and normal rules: deprecated syntax",
+ LOCF(loc));
+ }
+
+ StringPiece second = rest.substr(0, index);
+ StringPiece third = rest.substr(index+1);
+
+ for (StringPiece tok : WordScanner(second)) {
+ rule->output_patterns.push_back(tok);
+ }
+
+ if (rule->output_patterns.empty()) {
+ ERROR("%s:%d: *** missing target pattern.", LOCF(loc));
+ }
+ if (rule->output_patterns.size() > 1) {
+ ERROR("%s:%d: *** multiple target patterns.", LOCF(loc));
+ }
+ if (!IsPatternRule(rule->output_patterns[0])) {
+ ERROR("%s:%d: *** target pattern contains no '%%'.", LOCF(loc));
+ }
+ ParseInputs(rule, third);
}
string Rule::DebugString() const {
diff --git a/rule.h b/rule.h
index 071ad48..6434281 100644
--- a/rule.h
+++ b/rule.h
@@ -3,25 +3,26 @@
#include <vector>
+#include "ast.h"
#include "loc.h"
#include "log.h"
#include "string_piece.h"
using namespace std;
+class Evaluator;
class Value;
class Rule {
public:
Rule();
- void Parse(StringPiece line);
string DebugString() const;
vector<StringPiece> outputs;
vector<StringPiece> inputs;
vector<StringPiece> order_only_inputs;
- vector<string> output_patterns;
+ vector<StringPiece> output_patterns;
bool is_double_colon;
bool is_suffix_rule;
vector<Value*> cmds;
@@ -34,4 +35,14 @@ class Rule {
}
};
+struct RuleVar {
+ vector<StringPiece> outputs;
+ StringPiece lhs;
+ StringPiece rhs;
+ AssignOp op;
+};
+
+// If |rule| is not NULL, rule_var is filled.
+void ParseRule(Loc& loc, StringPiece line, Rule** rule, RuleVar* rule_var);
+
#endif // RULE_H_
diff --git a/strutil.cc b/strutil.cc
index 03eeb49..dba86c2 100644
--- a/strutil.cc
+++ b/strutil.cc
@@ -290,7 +290,6 @@ void AbsPath(StringPiece s, string* o) {
(*o)[j] = c;
j++;
}
- LOG("%zu => %zu", prev_start, j);
prev_start = j;
}
o->resize(j);