Skip to content
Snippets Groups Projects
Verified Commit 8ebd2a17 authored by Houtan Bastani's avatar Houtan Bastani
Browse files

macro processor: support `@#elseif` directive

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