[C++] Implement ifeq
diff --git a/eval.cc b/eval.cc
index 0da8712..ff30049 100644
--- a/eval.cc
+++ b/eval.cc
@@ -107,18 +107,20 @@
 
 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 @@
     (*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 @@
     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 @@
     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 @@
       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 @@
   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 @@
   }
 }
 
-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 @@
     }
   }
 
-  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 @@
   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 @@
   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);