Verified Commit 8ebd2a17 authored by Houtan Bastani's avatar Houtan Bastani
Browse files

macro processor: support `@#elseif` directive

parent 75b000a0
......@@ -210,37 +210,37 @@ For::interpret(ostream &output, bool no_line_macro)
void
If::interpret(ostream &output, bool no_line_macro)
{
RealPtr dp;
BoolPtr bp;
try
{
dp = dynamic_pointer_cast<Real>(condition->eval());
bp = dynamic_pointer_cast<Bool>(condition->eval());
if (!bp && !dp)
error(StackTrace("@#if", "The condition must evaluate to a boolean or a double", location));
}
catch (StackTrace &ex)
{
ex.push("@#if", location);
error(ex);
}
catch (exception &e)
{
error(StackTrace("@#if", e.what(), location));
}
if ((bp && *bp) || (dp && *dp))
loopIf(output, no_line_macro);
else
loopElse(output, no_line_macro);
for (auto & it : expr_and_body)
try
{
RealPtr dp = dynamic_pointer_cast<Real>(it.first->eval());
BoolPtr bp = dynamic_pointer_cast<Bool>(it.first->eval());
if (!bp && !dp)
error(StackTrace("@#if",
"The condition must evaluate to a boolean or a double", location));
if ((bp && *bp) || (dp && *dp))
{
interpretBody(it.second, output, no_line_macro);
break;
}
}
catch (StackTrace &ex)
{
ex.push("@#if", location);
error(ex);
}
catch (exception &e)
{
error(StackTrace("@#if", e.what(), location));
}
printEndLineInfo(output, no_line_macro);
}
void
If::loopIf(ostream &output, bool no_line_macro)
If::interpretBody(const vector<DirectivePtr> &body, ostream &output, bool no_line_macro)
{
bool printLine = !no_line_macro;
for (auto & statement : if_statements)
for (auto & statement : body)
{
if (printLine)
{
......@@ -252,41 +252,33 @@ If::loopIf(ostream &output, bool no_line_macro)
}
void
If::loopElse(ostream &output, bool no_line_macro)
Ifdef::interpret(ostream &output, bool no_line_macro)
{
bool printLine = !no_line_macro;
for (auto & statement : else_statements)
for (auto & it : expr_and_body)
{
if (printLine)
VariablePtr vp = dynamic_pointer_cast<Variable>(it.first);
if (dynamic_pointer_cast<BaseType>(it.first)
|| (vp && env.isVariableDefined(vp->getName())))
{
statement->printLineInfo(output, no_line_macro);
printLine = false;
interpretBody(it.second, output, no_line_macro);
break;
}
statement->interpret(output, no_line_macro);
}
}
void
Ifdef::interpret(ostream &output, bool no_line_macro)
{
BaseTypePtr btnp = dynamic_pointer_cast<BaseType>(condition);
VariablePtr vp = dynamic_pointer_cast<Variable>(condition);
if (btnp || (vp && env.isVariableDefined(vp->getName())))
loopIf(output, no_line_macro);
else
loopElse(output, no_line_macro);
printEndLineInfo(output, no_line_macro);
}
void
Ifndef::interpret(ostream &output, bool no_line_macro)
{
BaseTypePtr btnp = dynamic_pointer_cast<BaseType>(condition);
VariablePtr vp = dynamic_pointer_cast<Variable>(condition);
if (!(btnp || (vp && env.isVariableDefined(vp->getName()))))
loopIf(output, no_line_macro);
else
loopElse(output, no_line_macro);
for (auto & it : expr_and_body)
{
VariablePtr vp = dynamic_pointer_cast<Variable>(it.first);
if (!(dynamic_pointer_cast<BaseType>(it.first)
|| (vp && env.isVariableDefined(vp->getName()))))
{
interpretBody(it.second, output, no_line_macro);
break;
}
}
printEndLineInfo(output, no_line_macro);
}
......@@ -163,39 +163,23 @@ namespace macro
class If : public Directive
{
protected:
const ExpressionPtr condition;
const vector<DirectivePtr> if_statements;
const vector<DirectivePtr> else_statements;
const vector<pair<ExpressionPtr, vector<DirectivePtr>>> expr_and_body;
public:
If(ExpressionPtr condition_arg,
vector<DirectivePtr> if_statements_arg,
If(vector<pair<ExpressionPtr, vector<DirectivePtr>>> expr_and_body_arg,
Environment &env_arg, Tokenizer::location location_arg) :
Directive(env_arg, move(location_arg)), condition{move(condition_arg)}, if_statements{move(if_statements_arg)} { }
If(ExpressionPtr condition_arg,
vector<DirectivePtr> if_statements_arg,
vector<DirectivePtr> else_statements_arg,
Environment &env_arg, Tokenizer::location location_arg) :
Directive(env_arg, move(location_arg)),
condition{move(condition_arg)}, if_statements{move(if_statements_arg)}, else_statements{move(else_statements_arg)} { }
Directive(env_arg, move(location_arg)), expr_and_body{move(expr_and_body_arg)} { }
void interpret(ostream &output, bool no_line_macro) override;
protected:
void loopIf(ostream &output, bool no_line_macro);
void loopElse(ostream &output, bool no_line_macro);
void interpretBody(const vector<DirectivePtr> &body, ostream &output, bool no_line_macro);
};
class Ifdef : public If
{
public:
Ifdef(ExpressionPtr condition_arg,
vector<DirectivePtr> if_statements_arg,
Environment &env_arg, Tokenizer::location location_arg) :
If(move(condition_arg), move(if_statements_arg), env_arg, move(location_arg)) { }
Ifdef(ExpressionPtr condition_arg,
vector<DirectivePtr> if_statements_arg,
vector<DirectivePtr> else_statements_arg,
Ifdef(vector<pair<ExpressionPtr, vector<DirectivePtr>>> expr_and_body_arg,
Environment &env_arg, Tokenizer::location location_arg) :
If(move(condition_arg), move(if_statements_arg), move(else_statements_arg), env_arg, move(location_arg)) { }
If(move(expr_and_body_arg), env_arg, move(location_arg)) { }
void interpret(ostream &output, bool no_line_macro) override;
};
......@@ -203,15 +187,9 @@ namespace macro
class Ifndef : public If
{
public:
Ifndef(ExpressionPtr condition_arg,
vector<DirectivePtr> if_statements_arg,
Environment &env_arg, Tokenizer::location location_arg) :
If(move(condition_arg), move(if_statements_arg), env_arg, move(location_arg)) { }
Ifndef(ExpressionPtr condition_arg,
vector<DirectivePtr> if_statements_arg,
vector<DirectivePtr> else_statements_arg,
Ifndef(vector<pair<ExpressionPtr, vector<DirectivePtr>>> expr_and_body_arg,
Environment &env_arg, Tokenizer::location location_arg) :
If(move(condition_arg), move(if_statements_arg), move(else_statements_arg), env_arg, move(location_arg)) { }
If(move(expr_and_body_arg), env_arg, move(location_arg)) { }
void interpret(ostream &output, bool no_line_macro) override;
};
}
......
......@@ -56,7 +56,7 @@ using namespace macro;
}
%token FOR ENDFOR IF IFDEF IFNDEF ELSE ENDIF TRUE FALSE
%token FOR ENDFOR IF IFDEF IFNDEF ELSEIF ELSE ENDIF TRUE FALSE
%token INCLUDE INCLUDEPATH DEFINE EQUAL D_ECHO ERROR
%token COMMA LPAREN RPAREN LBRACKET RBRACKET WHEN
%token BEGIN_EVAL END_EVAL ECHOMACROVARS SAVE
......@@ -91,6 +91,8 @@ using namespace macro;
%type <DirectivePtr> statement
%type <DirectivePtr> directive directive_one_line directive_multiline for if ifdef ifndef text eval
%type <vector<pair<ExpressionPtr, vector<DirectivePtr>>>> if_list if_list1
%type <pair<ExpressionPtr, vector<DirectivePtr>>> elseif else
%type <ExpressionPtr> primary_expr oper_expr colon_expr expr
%type <FunctionPtr> function
%type <VariablePtr> symbol
......@@ -176,63 +178,78 @@ comma_name : NAME
{ $1.emplace_back(make_shared<Variable>($3, driver.env, @3)); $$ = $1; }
;
if_begin : IF { driver.pushContext(); }
;
if : if_begin expr EOL statements ENDIF
{
auto ifContext = driver.popContext();
ifContext.emplace_back(make_shared<TextNode>("\n", driver.env, @5));
$$ = make_shared<If>($2, ifContext, driver.env, @$);
}
| if_begin expr EOL statements ELSE EOL { driver.pushContext(); } statements ENDIF
{
auto elseContext = driver.popContext();
elseContext.emplace_back(make_shared<TextNode>("\n", driver.env, @9));
auto ifContext = driver.popContext();
ifContext.emplace_back(make_shared<TextNode>("\n", driver.env, @5));
$$ = make_shared<If>($2, ifContext, elseContext, driver.env, @$);
}
if : IF { driver.pushContext(); } if_list ENDIF
{ $$ = make_shared<If>($3, driver.env, @$); }
;
ifdef_begin : IFDEF { driver.pushContext(); }
;
ifdef : ifdef_begin expr EOL statements ENDIF
{
auto ifContext = driver.popContext();
ifContext.emplace_back(make_shared<TextNode>("\n", driver.env, @5));
$$ = make_shared<Ifdef>($2, ifContext, driver.env, @$);
}
| ifdef_begin expr EOL statements ELSE EOL { driver.pushContext(); } statements ENDIF
{
auto elseContext = driver.popContext();
elseContext.emplace_back(make_shared<TextNode>("\n", driver.env, @9));
auto ifContext = driver.popContext();
ifContext.emplace_back(make_shared<TextNode>("\n", driver.env, @5));
$$ = make_shared<Ifdef>($2, ifContext, elseContext, driver.env, @$);
}
ifdef : IFDEF { driver.pushContext(); } if_list ENDIF
{ $$ = make_shared<Ifdef>($3, driver.env, @$); }
;
ifndef_begin : IFNDEF { driver.pushContext(); }
;
ifndef : IFNDEF { driver.pushContext(); } if_list ENDIF
{ $$ = make_shared<Ifndef>($3, driver.env, @$); }
;
if_list : if_list1
| if_list1 else
{
$1.emplace_back($2);
$$ = $1;
}
;
if_list1 : expr EOL
{
auto context = driver.popContext();
context.emplace_back(make_shared<TextNode>("\n", driver.env, @2));
$$ = vector<pair<ExpressionPtr, vector<DirectivePtr>>> { make_pair($1, context) };
}
| expr EOL statements
{
auto context = driver.popContext();
context.emplace_back(make_shared<TextNode>("\n", driver.env, @3));
$$ = vector<pair<ExpressionPtr, vector<DirectivePtr>>> { make_pair($1, context) };
}
| if_list1 elseif
{
$1.emplace_back($2);
$$ = $1;
}
;
elseif_begin : ELSEIF { driver.pushContext(); } ;
ifndef : ifndef_begin expr EOL statements ENDIF
elseif : elseif_begin expr EOL
{
auto ifContext = driver.popContext();
ifContext.emplace_back(make_shared<TextNode>("\n", driver.env, @5));
$$ = make_shared<Ifndef>($2, ifContext, driver.env, @$);
auto context = driver.popContext();
context.emplace_back(make_shared<TextNode>("\n", driver.env, @3));
$$ = make_pair($2, context);
}
| ifndef_begin expr EOL statements ELSE EOL { driver.pushContext(); } statements ENDIF
| elseif_begin expr EOL statements
{
auto elseContext = driver.popContext();
elseContext.emplace_back(make_shared<TextNode>("\n", driver.env, @9));
auto ifContext = driver.popContext();
ifContext.emplace_back(make_shared<TextNode>("\n", driver.env, @5));
$$ = make_shared<Ifndef>($2, ifContext, elseContext, driver.env, @$);
auto context = driver.popContext();
context.emplace_back(make_shared<TextNode>("\n", driver.env, @4));
$$ = make_pair($2, context);
}
;
else_begin : ELSE { driver.pushContext(); } ;
else : else_begin EOL
{
auto context = driver.popContext();
context.emplace_back(make_shared<TextNode>("\n", driver.env, @2));
$$ = make_pair(make_shared<Bool>(true, driver.env, @1), context);
}
| else_begin EOL statements
{
auto context = driver.popContext();
context.emplace_back(make_shared<TextNode>("\n", driver.env, @3));
$$ = make_pair(make_shared<Bool>(true, driver.env, @1), context);
}
;
text : TEXT
{ $$ = make_shared<TextNode>($1, driver.env, @$); }
| EOL
......
......@@ -72,6 +72,7 @@ CONT \\\\{SPC}*
<directive>if { BEGIN(expr); return token::IF; }
<directive>ifdef { BEGIN(expr); return token::IFDEF; }
<directive>ifndef { BEGIN(expr); return token::IFNDEF; }
<directive>elseif { BEGIN(expr); return token::ELSEIF; }
<directive>else { BEGIN(end_line); return token::ELSE; }
<directive>endif { BEGIN(end_line); return token::ENDIF; }
<directive>for { BEGIN(expr); return token::FOR; }
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment