diff options
-rw-r--r-- | eval.cc | 17 | ||||
-rw-r--r-- | parser.cc | 47 | ||||
-rw-r--r-- | parser.h | 5 | ||||
-rw-r--r-- | rule.cc | 76 | ||||
-rw-r--r-- | rule.h | 15 | ||||
-rw-r--r-- | strutil.cc | 1 |
6 files changed, 123 insertions, 38 deletions
@@ -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) { @@ -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)); +} @@ -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(); @@ -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 { @@ -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_ @@ -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); |