[C++] Parse include directives
diff --git a/ast.cc b/ast.cc
index b755ce9..79cea85 100644
--- a/ast.cc
+++ b/ast.cc
@@ -41,6 +41,11 @@
                       expr->DebugString().c_str(), LOCF(loc()));
 }
 
+string IncludeAST::DebugString() const {
+  return StringPrintf("IncludeAST(%s, loc=%s:%d)",
+                      expr->DebugString().c_str(), LOCF(loc()));
+}
+
 RuleAST::~RuleAST() {
   delete expr;
   delete after_term;
@@ -66,3 +71,11 @@
 void CommandAST::Eval(Evaluator* ev) const {
   ev->EvalCommand(this);
 }
+
+IncludeAST::~IncludeAST() {
+  delete expr;
+}
+
+void IncludeAST::Eval(Evaluator* ev) const {
+  ev->EvalInclude(this);
+}
diff --git a/ast.h b/ast.h
index 8c0ceea..99c8ae5 100644
--- a/ast.h
+++ b/ast.h
@@ -2,6 +2,7 @@
 #define AST_H_
 
 #include <string>
+#include <vector>
 
 #include "loc.h"
 #include "string_piece.h"
@@ -24,6 +25,13 @@
   EXPORT,
 };
 
+enum struct CondOp {
+  IFEQ,
+  IFNEQ,
+  IFDEF,
+  IFNDEF,
+};
+
 struct AST {
  public:
   virtual ~AST();
@@ -79,4 +87,40 @@
   virtual string DebugString() const;
 };
 
+struct IfAST : public AST {
+  CondOp op;
+  Value* lhs;
+  Value* rhs;
+  vector<AST*> true_stmts;
+  vector<AST*> false_stmts;
+
+  virtual ~IfAST();
+
+  virtual void Eval(Evaluator* ev) const;
+
+  virtual string DebugString() const;
+};
+
+struct IncludeAST : public AST {
+  Value* expr;
+  char op;  // '-' or 0.
+
+  virtual ~IncludeAST();
+
+  virtual void Eval(Evaluator* ev) const;
+
+  virtual string DebugString() const;
+};
+
+struct ExportAST : public AST {
+  Value* expr;
+  bool is_export;
+
+  virtual ~ExportAST();
+
+  virtual void Eval(Evaluator* ev) const;
+
+  virtual string DebugString() const;
+};
+
 #endif  // AST_H_
diff --git a/eval.cc b/eval.cc
index b8d2fe6..56c9623 100644
--- a/eval.cc
+++ b/eval.cc
@@ -105,6 +105,18 @@
   LOG("Command: %s", ast->expr->DebugString().c_str());
 }
 
+void Evaluator::EvalIf(const IfAST* ast) {
+  ERROR("TODO");
+}
+
+void Evaluator::EvalInclude(const IncludeAST* ast) {
+  ERROR("TODO");
+}
+
+void Evaluator::EvalExport(const ExportAST* ast) {
+  ERROR("TODO");
+}
+
 Var* Evaluator::LookupVar(StringPiece name) {
   // TODO: TSV.
   Var* v = vars_->Lookup(name);
diff --git a/eval.h b/eval.h
index 51460a9..3c84c3f 100644
--- a/eval.h
+++ b/eval.h
@@ -11,6 +11,9 @@
 
 class AssignAST;
 class CommandAST;
+class ExportAST;
+class IfAST;
+class IncludeAST;
 class Makefile;
 class Rule;
 class RuleAST;
@@ -34,6 +37,9 @@
   void EvalAssign(const AssignAST* ast);
   void EvalRule(const RuleAST* ast);
   void EvalCommand(const CommandAST* ast);
+  void EvalIf(const IfAST* ast);
+  void EvalInclude(const IncludeAST* ast);
+  void EvalExport(const ExportAST* ast);
 
   Var* LookupVar(StringPiece name);
   // For target specific variables.
diff --git a/main.cc b/main.cc
index cdb06ee..a504154 100644
--- a/main.cc
+++ b/main.cc
@@ -10,6 +10,7 @@
 #include "fileutil.h"
 #include "func.h"
 #include "log.h"
+#include "parser.h"
 #include "string_piece.h"
 #include "strutil.h"
 #include "var.h"
@@ -34,6 +35,7 @@
   InitSymtab();
   InitFuncTable();
   InitDepNodePool();
+  InitParser();
 
   if (g_makefile == NULL) {
     if (Exists("GNUmakefile")) {
@@ -49,6 +51,7 @@
 }
 
 static void Quit() {
+  QuitParser();
   QuitDepNodePool();
   QuitFuncTable();
   QuitSymtab();
diff --git a/parser.cc b/parser.cc
index 8d872de..9ddd8cc 100644
--- a/parser.cc
+++ b/parser.cc
@@ -1,5 +1,7 @@
 #include "parser.h"
 
+#include <unordered_map>
+
 #include "ast.h"
 #include "file.h"
 #include "loc.h"
@@ -43,6 +45,24 @@
     }
   }
 
+  static void Init() {
+    make_directives_ = new unordered_map<StringPiece, DirectiveHandler>;
+    (*make_directives_)["include"] = &Parser::ParseIncludeAST;
+    (*make_directives_)["-include"] = &Parser::ParseIncludeAST;
+
+    shortest_directive_len_ = 9999;
+    longest_directive_len_ = 0;
+    for (auto p : *make_directives_) {
+      size_t len = p.first.size();
+      shortest_directive_len_ = min(len, shortest_directive_len_);
+      longest_directive_len_ = max(len, longest_directive_len_);
+    }
+  }
+
+  static void Quit() {
+    delete make_directives_;
+  }
+
  private:
   void Error(const string& msg) {
     ERROR("%s:%d: %s", LOCF(loc_), msg.c_str());
@@ -78,7 +98,10 @@
       return;
     }
 
-    // TODO: directive.
+    line = line.StripLeftSpaces();
+    if (HandleDirective(line)) {
+      return;
+    }
 
     size_t sep = line.find_first_of(STRING_PIECE("=:"));
     if (sep == string::npos) {
@@ -145,6 +168,29 @@
     state_ = ParserState::NOT_AFTER_RULE;
   }
 
+  void ParseIncludeAST(StringPiece line, StringPiece directive) {
+    IncludeAST* ast = new IncludeAST();
+    ast->expr = ParseExpr(line, false);
+    ast->op = directive[0] == '-' ? '-' : 0;
+    out_asts_->push_back(ast);
+  }
+
+  bool HandleDirective(StringPiece line) {
+    if (line.size() < shortest_directive_len_)
+      return false;
+    StringPiece prefix = line.substr(0, longest_directive_len_ + 1);
+    size_t space_index = prefix.find(' ');
+    if (space_index == string::npos)
+      return false;
+    StringPiece directive = prefix.substr(0, space_index);
+    auto found = make_directives_->find(directive);
+    if (found == make_directives_->end())
+      return false;
+
+    (this->*found->second)(line.substr(directive.size() + 1), directive);
+    return true;
+  }
+
   StringPiece buf_;
   size_t l_;
   ParserState state_;
@@ -153,6 +199,12 @@
 
   Loc loc_;
   bool fixed_lineno_;
+
+  typedef void (Parser::*DirectiveHandler)(
+      StringPiece line, StringPiece directive);
+  static unordered_map<StringPiece, DirectiveHandler>* make_directives_;
+  static size_t shortest_directive_len_;
+  static size_t longest_directive_len_;
 };
 
 void Parse(Makefile* mk) {
@@ -161,3 +213,15 @@
                 mk->mutable_asts());
   parser.Parse();
 }
+
+void InitParser() {
+  Parser::Init();
+}
+
+void QuitParser() {
+  Parser::Quit();
+}
+
+unordered_map<StringPiece, Parser::DirectiveHandler>* Parser::make_directives_;
+size_t Parser::shortest_directive_len_;
+size_t Parser::longest_directive_len_;
diff --git a/parser.h b/parser.h
index b82741b..92be36c 100644
--- a/parser.h
+++ b/parser.h
@@ -5,4 +5,7 @@
 
 void Parse(Makefile* mk);
 
+void InitParser();
+void QuitParser();
+
 #endif  // PARSER_H_