diff options
author | Shinichiro Hamaji <shinichiro.hamaji@gmail.com> | 2015-06-17 15:33:11 +0900 |
---|---|---|
committer | Shinichiro Hamaji <shinichiro.hamaji@gmail.com> | 2015-06-18 11:25:44 +0900 |
commit | 7e256dfc39efc5f1614686a85fb5c9da6480abb9 (patch) | |
tree | eb30790d43ac6081d9332ac0dfe92ce5960082e5 | |
parent | 32750621508da5e68f53bf14f944ad524627eb50 (diff) | |
download | android_build_kati-7e256dfc39efc5f1614686a85fb5c9da6480abb9.tar.gz android_build_kati-7e256dfc39efc5f1614686a85fb5c9da6480abb9.tar.bz2 android_build_kati-7e256dfc39efc5f1614686a85fb5c9da6480abb9.zip |
[C++] Implement ifdef
-rw-r--r-- | ast.cc | 24 | ||||
-rw-r--r-- | eval.cc | 29 | ||||
-rw-r--r-- | parser.cc | 56 |
3 files changed, 108 insertions, 1 deletions
@@ -41,6 +41,21 @@ string CommandAST::DebugString() const { expr->DebugString().c_str(), LOCF(loc())); } +string IfAST::DebugString() const { + const char* opstr = "???"; + switch (op) { + case CondOp::IFEQ: opstr = "ifeq"; break; + case CondOp::IFNEQ: opstr = "ifneq"; break; + case CondOp::IFDEF: opstr = "ifdef"; break; + case CondOp::IFNDEF: opstr = "ifndef"; break; + } + return StringPrintf("IfAST(op=%s, lhs=%s, rhs=%s loc=%s:%d)", + opstr, + lhs->DebugString().c_str(), + rhs->DebugString().c_str(), + LOCF(loc())); +} + string IncludeAST::DebugString() const { return StringPrintf("IncludeAST(%s, loc=%s:%d)", expr->DebugString().c_str(), LOCF(loc())); @@ -72,6 +87,15 @@ void CommandAST::Eval(Evaluator* ev) const { ev->EvalCommand(this); } +IfAST::~IfAST() { + delete lhs; + delete rhs; +} + +void IfAST::Eval(Evaluator* ev) const { + ev->EvalIf(this); +} + IncludeAST::~IncludeAST() { delete expr; } @@ -106,7 +106,34 @@ void Evaluator::EvalCommand(const CommandAST* ast) { } void Evaluator::EvalIf(const IfAST* ast) { - ERROR("TODO"); + bool is_true; + StringPiece lhs = Intern(*ast->lhs->Eval(this)); + switch (ast->op) { + case CondOp::IFDEF: + case CondOp::IFNDEF: { + Var* v = LookupVarInCurrentScope(lhs); + shared_ptr<string> s = v->Eval(this); + is_true = s->empty() == (ast->op == CondOp::IFNDEF); + break; + } + case CondOp::IFEQ: + case CondOp::IFNEQ: { + ERROR("TODO"); + break; + } + default: + CHECK(false); + } + + const vector<AST*>* asts; + if (is_true) { + asts = &ast->true_stmts; + } else { + asts = &ast->false_stmts; + } + for (AST* a : *asts) { + a->Eval(this); + } } void Evaluator::EvalInclude(const IncludeAST* ast) { @@ -1,5 +1,6 @@ #include "parser.h" +#include <stack> #include <unordered_map> #include "ast.h" @@ -17,11 +18,19 @@ enum struct ParserState { }; class Parser { + struct IfState { + IfAST* ast; + bool is_in_else; + int num_nest; + }; + public: Parser(StringPiece buf, const char* filename, vector<AST*>* asts) : buf_(buf), state_(ParserState::NOT_AFTER_RULE), + asts_(asts), out_asts_(asts), + num_if_nest_(0), loc_(filename, 0), fixed_lineno_(false) { } @@ -52,6 +61,9 @@ class Parser { (*make_directives_)["-include"] = &Parser::ParseInclude; (*make_directives_)["sinclude"] = &Parser::ParseInclude; (*make_directives_)["define"] = &Parser::ParseDefine; + (*make_directives_)["ifdef"] = &Parser::ParseIfdef; + (*make_directives_)["ifndef"] = &Parser::ParseIfdef; + (*make_directives_)["endif"] = &Parser::ParseEndif; shortest_directive_len_ = 9999; longest_directive_len_ = 0; @@ -216,6 +228,45 @@ class Parser { define_name_.clear(); } + void ParseIfdef(StringPiece line, StringPiece directive) { + IfAST* ast = new IfAST(); + ast->set_loc(loc_); + ast->op = directive[2] == 'n' ? CondOp::IFNDEF : CondOp::IFDEF; + ast->lhs = ParseExpr(line, false); + ast->rhs = NULL; + out_asts_->push_back(ast); + + IfState* st = new IfState(); + st->ast = ast; + st->is_in_else = false; + st->num_nest = num_if_nest_; + out_asts_ = &ast->true_stmts; + } + + void ParseEndif(StringPiece, StringPiece) { + CheckIfStack("endif"); + IfState st = *if_stack_.top(); + for (int t = 0; t <= st.num_nest; t++) { + delete if_stack_.top(); + if_stack_.pop(); + if (if_stack_.empty()) { + out_asts_ = asts_; + } else { + IfState* st = if_stack_.top(); + if (st->is_in_else) + out_asts_ = &st->ast->false_stmts; + else + out_asts_ = &st->ast->true_stmts; + } + } + } + + void CheckIfStack(const char* keyword) { + if (if_stack_.empty()) { + Error(StringPrintf("*** extraneous `%s'.", keyword)); + } + } + bool HandleDirective(StringPiece line) { if (line.size() < shortest_directive_len_) return false; @@ -237,11 +288,16 @@ class Parser { size_t l_; ParserState state_; + vector<AST*>* asts_; vector<AST*>* out_asts_; + StringPiece define_name_; size_t define_start_; int define_start_line_; + int num_if_nest_; + stack<IfState*> if_stack_; + Loc loc_; bool fixed_lineno_; |