aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShinichiro Hamaji <shinichiro.hamaji@gmail.com>2015-06-17 17:51:24 +0900
committerShinichiro Hamaji <shinichiro.hamaji@gmail.com>2015-06-18 11:25:44 +0900
commitd146f4c482adb0c51bfc1bef101361845f74407c (patch)
treebf2f649f66ce5ddbdb3fafbed6fbf12163c4b5a1
parenteb2b3d0a6a18e2eff96ba64abf5604011c2fbf2d (diff)
downloadkati-d146f4c482adb0c51bfc1bef101361845f74407c.tar.gz
[C++] Implement ifeq
-rw-r--r--eval.cc8
-rw-r--r--parser.cc68
-rw-r--r--value.cc21
-rw-r--r--value.h4
4 files changed, 83 insertions, 18 deletions
diff --git a/eval.cc b/eval.cc
index 0da8712..ff30049 100644
--- a/eval.cc
+++ b/eval.cc
@@ -107,18 +107,20 @@ void Evaluator::EvalCommand(const CommandAST* ast) {
void Evaluator::EvalIf(const IfAST* ast) {
bool is_true;
- StringPiece lhs = Intern(*ast->lhs->Eval(this));
switch (ast->op) {
case CondOp::IFDEF:
case CondOp::IFNDEF: {
+ StringPiece lhs = Intern(*ast->lhs->Eval(this));
Var* v = LookupVarInCurrentScope(lhs);
shared_ptr<string> s = v->Eval(this);
- is_true = s->empty() == (ast->op == CondOp::IFNDEF);
+ is_true = (s->empty() == (ast->op == CondOp::IFNDEF));
break;
}
case CondOp::IFEQ:
case CondOp::IFNEQ: {
- ERROR("TODO");
+ shared_ptr<string> lhs = ast->lhs->Eval(this);
+ shared_ptr<string> rhs = ast->rhs->Eval(this);
+ is_true = ((*lhs == *rhs) == (ast->op == CondOp::IFEQ));
break;
}
default:
diff --git a/parser.cc b/parser.cc
index 0266f35..a8d01ba 100644
--- a/parser.cc
+++ b/parser.cc
@@ -67,6 +67,8 @@ class Parser {
(*make_directives_)["define"] = &Parser::ParseDefine;
(*make_directives_)["ifdef"] = &Parser::ParseIfdef;
(*make_directives_)["ifndef"] = &Parser::ParseIfdef;
+ (*make_directives_)["ifeq"] = &Parser::ParseIfeq;
+ (*make_directives_)["ifneq"] = &Parser::ParseIfeq;
(*make_directives_)["else"] = &Parser::ParseElse;
(*make_directives_)["endif"] = &Parser::ParseEndif;
@@ -244,6 +246,15 @@ class Parser {
define_name_.clear();
}
+ void EnterIf(IfAST* ast) {
+ IfState* st = new IfState();
+ st->ast = ast;
+ st->is_in_else = false;
+ st->num_nest = num_if_nest_;
+ if_stack_.push(st);
+ out_asts_ = &ast->true_asts;
+ }
+
void ParseIfdef(StringPiece line, StringPiece directive) {
IfAST* ast = new IfAST();
ast->set_loc(loc_);
@@ -251,13 +262,56 @@ class Parser {
ast->lhs = ParseExpr(line, false);
ast->rhs = NULL;
out_asts_->push_back(ast);
+ EnterIf(ast);
+ }
- IfState* st = new IfState();
- st->ast = ast;
- st->is_in_else = false;
- st->num_nest = num_if_nest_;
- if_stack_.push(st);
- out_asts_ = &ast->true_asts;
+ bool ParseIfEqCond(StringPiece s, IfAST* ast) {
+ if (s.empty()) {
+ return false;
+ }
+
+ if (s[0] == '(' && s[s.size() - 1] == ')') {
+ s = s.substr(1, s.size() - 2);
+ char terms[] = {',', '\0'};
+ size_t n;
+ ast->lhs = ParseExprImpl(s, terms, false, &n, true);
+ if (s[n] != ',')
+ return false;
+ s = TrimLeftSpace(s.substr(n+1));
+ ast->rhs = ParseExprImpl(s, NULL, false, &n);
+ return TrimSpace(s.substr(n)) == "";
+ } else {
+ for (int i = 0; i < 2; i++) {
+ if (s.empty())
+ return false;
+ char quote = s[0];
+ if (quote != '\'' && quote != '"')
+ return false;
+ size_t end = s.find(quote, 1);
+ if (end == string::npos)
+ return false;
+ Value* v = ParseExpr(s.substr(1, end - 1), false);
+ if (i == 0)
+ ast->lhs = v;
+ else
+ ast->rhs = v;
+ s = TrimLeftSpace(s.substr(end+1));
+ }
+ return s.empty();
+ }
+ }
+
+ void ParseIfeq(StringPiece line, StringPiece directive) {
+ IfAST* ast = new IfAST();
+ ast->set_loc(loc_);
+ ast->op = directive[2] == 'n' ? CondOp::IFNEQ : CondOp::IFEQ;
+
+ if (!ParseIfEqCond(line, ast)) {
+ Error("*** invalid syntax in conditional.");
+ }
+
+ out_asts_->push_back(ast);
+ EnterIf(ast);
}
void ParseElse(StringPiece line, StringPiece) {
@@ -350,7 +404,7 @@ class Parser {
return false;
StringPiece rest = TrimRightSpace(RemoveComment(TrimLeftSpace(
- line.substr(directive.size() + 1))));
+ line.substr(directive.size()))));
(this->*found->second)(rest, directive);
return true;
}
diff --git a/value.cc b/value.cc
index d762bcf..fa4577f 100644
--- a/value.cc
+++ b/value.cc
@@ -223,9 +223,6 @@ static size_t SkipSpaces(StringPiece s, const char* terms) {
return s.size();
}
-static Value* ParseExprImpl(StringPiece s, const char* terms, bool is_command,
- size_t* index_out);
-
Value* ParseFunc(Func* f, StringPiece s, size_t i, char* terms,
size_t* index_out) {
terms[1] = ',';
@@ -332,8 +329,8 @@ Value* ParseDollar(StringPiece s, size_t* index_out) {
}
}
-static Value* ParseExprImpl(StringPiece s, const char* terms, bool is_command,
- size_t* index_out) {
+Value* ParseExprImpl(StringPiece s, const char* terms, bool is_command,
+ size_t* index_out, bool trim_right_space) {
// TODO: A faulty optimization.
#if 0
char specials[] = "$(){}\\\n";
@@ -433,8 +430,13 @@ static Value* ParseExprImpl(StringPiece s, const char* terms, bool is_command,
}
}
- if (i > b)
- r->AddValue(new Literal(s.substr(b, i-b)));
+ if (i > b) {
+ StringPiece rest = s.substr(b, i-b);
+ if (trim_right_space)
+ rest = TrimRightSpace(rest);
+ if (!rest.empty())
+ r->AddValue(new Literal(rest));
+ }
*index_out = i;
return r->Compact();
}
@@ -444,6 +446,11 @@ Value* ParseExpr(StringPiece s, bool is_command) {
return ParseExprImpl(s, NULL, is_command, &n);
}
+Value* ParseExprUntilComma(StringPiece s, size_t* index_out) {
+ char terms[] = {',', '\0'};
+ return ParseExprImpl(s, terms, false, index_out);
+}
+
string JoinValues(const vector<Value*> vals, const char* sep) {
vector<string> val_strs;
for (Value* v : vals) {
diff --git a/value.h b/value.h
index 3b3e324..55037dc 100644
--- a/value.h
+++ b/value.h
@@ -34,7 +34,9 @@ class Value : public Evaluable {
virtual string DebugString_() const = 0;
};
-Value* ParseExpr(StringPiece s, bool is_command);
+Value* ParseExprImpl(StringPiece s, const char* terms, bool is_command,
+ size_t* index_out, bool trim_right_space = false);
+Value* ParseExpr(StringPiece s, bool is_command = false);
string JoinValues(const vector<Value*> vals, const char* sep);