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; }