aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShinichiro Hamaji <shinichiro.hamaji@gmail.com>2015-06-17 15:33:11 +0900
committerShinichiro Hamaji <shinichiro.hamaji@gmail.com>2015-06-18 11:25:44 +0900
commit7e256dfc39efc5f1614686a85fb5c9da6480abb9 (patch)
treeeb30790d43ac6081d9332ac0dfe92ce5960082e5
parent32750621508da5e68f53bf14f944ad524627eb50 (diff)
downloadandroid_build_kati-7e256dfc39efc5f1614686a85fb5c9da6480abb9.tar.gz
android_build_kati-7e256dfc39efc5f1614686a85fb5c9da6480abb9.tar.bz2
android_build_kati-7e256dfc39efc5f1614686a85fb5c9da6480abb9.zip
[C++] Implement ifdef
-rw-r--r--ast.cc24
-rw-r--r--eval.cc29
-rw-r--r--parser.cc56
3 files changed, 108 insertions, 1 deletions
diff --git a/ast.cc b/ast.cc
index 79cea85..31a6ef4 100644
--- a/ast.cc
+++ b/ast.cc
@@ -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;
}
diff --git a/eval.cc b/eval.cc
index 56c9623..62b6aa0 100644
--- a/eval.cc
+++ b/eval.cc
@@ -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) {
diff --git a/parser.cc b/parser.cc
index 00339c0..2bd0169 100644
--- a/parser.cc
+++ b/parser.cc
@@ -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_;