diff --git a/src/macro/Directives.cc b/src/macro/Directives.cc index ee5e6b7b3f93d93a71b0819b5328f84ccd066ae4..9880beceeb2e20003bb8868495b4aebb50b20397 100644 --- a/src/macro/Directives.cc +++ b/src/macro/Directives.cc @@ -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); } - diff --git a/src/macro/Directives.hh b/src/macro/Directives.hh index 9e8f131053720fe7d3279fd1101a329f7ab120cd..58d4d5463dcde9132cb1339fee8c6557afc31ab2 100644 --- a/src/macro/Directives.hh +++ b/src/macro/Directives.hh @@ -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; }; } diff --git a/src/macro/Parser.yy b/src/macro/Parser.yy index 6bde33d2d924d012eff9297f1461d842f37d4981..2de754cf61c40d02d09282c8f354199db3dab50b 100644 --- a/src/macro/Parser.yy +++ b/src/macro/Parser.yy @@ -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 diff --git a/src/macro/Tokenizer.ll b/src/macro/Tokenizer.ll index 5ec1ffe53dab8d1e3a1e4293c9b59754233f928d..941b30d742e54486996d219ccbd27e682b367744 100644 --- a/src/macro/Tokenizer.ll +++ b/src/macro/Tokenizer.ll @@ -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; }