diff --git a/doc/dynare.texi b/doc/dynare.texi index 173daac21d1aa6894b078051091de5df0d565624..f38c1bb288c565e286a30410f5134d2a6cfc7401 100644 --- a/doc/dynare.texi +++ b/doc/dynare.texi @@ -6558,8 +6558,8 @@ line. The main directives are: @item @code{@@#define}, for defining a macro-processor variable, @item -@code{@@#if}, @code{@@#ifdef}, @code{@@#else}, @code{@@#endif} for -conditional statements, +@code{@@#if}, @code{@@#ifdef}, @code{@@#ifndef}, @code{@@#else}, +@code{@@#endif} for conditional statements, @item @code{@@#for}, @code{@@#endfor} for constructing loops. @end itemize @@ -6702,10 +6702,11 @@ end; @deffn {Macro directive} @@#if @var{MACRO_EXPRESSION} @deffnx {Macro directive} @@#ifdef @var{MACRO_VARIABLE} +@deffnx {Macro directive} @@#ifndef @var{MACRO_VARIABLE} @deffnx {Macro directive} @@#else @deffnx {Macro directive} @@#endif Conditional inclusion of some part of the @file{.mod} file. -The lines between @code{@@#if} or @code{@@#ifdef} and the next +The lines between @code{@@#if}, @code{@@#ifdef} or @code{@@#ifndef} and the next @code{@@#else} or @code{@@#endif} is executed only if the condition evaluates to a non-null integer. The @code{@@#else} branch is optional and, if present, is only evaluated if the condition evaluates to @@ -6744,6 +6745,21 @@ model; end; @end example +Choose between two alternative monetary policy rules using a +macro-variable. As @code{linear_mon_pol} was not previously defined in +this example, the first equation will be chosen: + +@example +model; +@@#ifndef linear_mon_pol + i = w*i(-1) + (1-w)*i_ss + w2*(pie-piestar); +@@#else + i = i(-1)^w * i_ss^(1-w) * (pie/piestar)^w2; +@@#endif +... +end; +@end example + @end deffn @deffn {Macro directive} @@#for @var{MACRO_VARIABLE} in @var{MACRO_EXPRESSION} diff --git a/preprocessor/macro/MacroBison.yy b/preprocessor/macro/MacroBison.yy index 13a06a06a840078d201608c8acfb18dc90c8b0d6..a7dc4fc5cefd9d3de778164cbc64080fde132fb4 100644 --- a/preprocessor/macro/MacroBison.yy +++ b/preprocessor/macro/MacroBison.yy @@ -79,7 +79,7 @@ class MacroDriver; %} -%token DEFINE LINE FOR IN IF ELSE ENDIF ECHO_DIR ERROR IFDEF +%token DEFINE LINE FOR IN IF ELSE ENDIF ECHO_DIR ERROR IFDEF IFNDEF %token LPAREN RPAREN LBRACKET RBRACKET EQUAL EOL %token <int_val> INTEGER @@ -119,6 +119,8 @@ statement : expr { TYPERR_CATCH(driver.begin_if($2), @$); } | IFDEF NAME { TYPERR_CATCH(driver.begin_ifdef(*$2), @$); delete $2; } + | IFNDEF NAME + { TYPERR_CATCH(driver.begin_ifndef(*$2), @$); delete $2; } | ECHO_DIR expr { TYPERR_CATCH(driver.echo(@$, $2), @$); } | ERROR expr diff --git a/preprocessor/macro/MacroDriver.cc b/preprocessor/macro/MacroDriver.cc index a7c900bd193f1d1defd4ade23e59e8d1a6bffeb7..746fd12e334b6ea14ac9ead4744d9fb14fbabc87 100644 --- a/preprocessor/macro/MacroDriver.cc +++ b/preprocessor/macro/MacroDriver.cc @@ -178,6 +178,20 @@ MacroDriver::begin_ifdef(const string &name) } } +void +MacroDriver::begin_ifndef(const string &name) +{ + try + { + get_variable(name); + begin_if(new IntMV(*this, 0)); + } + catch (UnknownVariable &) + { + begin_if(new IntMV(*this, 1)); + } +} + void MacroDriver::echo(const Macro::parser::location_type &l, const MacroValue *value) const throw (MacroValue::TypeError) { diff --git a/preprocessor/macro/MacroDriver.hh b/preprocessor/macro/MacroDriver.hh index fb21543b9184f63c32ac58bc478ce5b01a2dac49..0945a32960b4cfe1a8c5f3d03a9db72bc2e24e18 100644 --- a/preprocessor/macro/MacroDriver.hh +++ b/preprocessor/macro/MacroDriver.hh @@ -211,6 +211,9 @@ public: //! Begins an @#ifdef statement void begin_ifdef(const string &name); + //! Begins an @#ifndef statement + void begin_ifndef(const string &name); + //! Executes @#echo directive void echo(const Macro::parser::location_type &l, const MacroValue *value) const throw (MacroValue::TypeError); diff --git a/preprocessor/macro/MacroFlex.ll b/preprocessor/macro/MacroFlex.ll index 590f60ac49210680112a988610841bb0bc23494a..7e3e5dbaea557812b79665c000cc1ab4c0222e15 100644 --- a/preprocessor/macro/MacroFlex.ll +++ b/preprocessor/macro/MacroFlex.ll @@ -165,10 +165,11 @@ CONT \\\\ <STMT>endfor { driver.error(*yylloc, "@#endfor is not matched by a @#for statement"); } <STMT>ifdef { reading_if_statement = true; return token::IFDEF; } +<STMT>ifndef { reading_if_statement = true; return token::IFNDEF; } <STMT>if { reading_if_statement = true; return token::IF; } -<STMT>else { driver.error(*yylloc, "@#else is not matched by an @#if/@#ifdef statement"); } -<STMT>endif { driver.error(*yylloc, "@#endif is not matched by an @#if/@#ifdef statement"); } +<STMT>else { driver.error(*yylloc, "@#else is not matched by an @#if/@#ifdef/@#ifndef statement"); } +<STMT>endif { driver.error(*yylloc, "@#endif is not matched by an @#if/@#ifdef/@#ifndef statement"); } <STMT>echo { return token::ECHO_DIR; } <STMT>error { return token::ERROR; } @@ -225,7 +226,7 @@ CONT \\\\ yylloc->step(); } <THEN_BODY>. { then_body_tmp.append(yytext); yylloc->step(); } -<THEN_BODY><<EOF>> { driver.error(if_stmt_loc_tmp, "@#if/@#ifdef not matched by an @#endif (unexpected end of file)"); } +<THEN_BODY><<EOF>> { driver.error(if_stmt_loc_tmp, "@#if/@#ifdef/@#ifndef not matched by an @#endif (unexpected end of file)"); } <THEN_BODY>^{SPC}*@#{SPC}*else{SPC}*(\/\/.*)?{EOL} { yylloc->lines(1); yylloc->step(); @@ -267,7 +268,7 @@ CONT \\\\ yylloc->step(); } <ELSE_BODY>. { else_body_tmp.append(yytext); yylloc->step(); } -<ELSE_BODY><<EOF>> { driver.error(if_stmt_loc_tmp, "@#if/@#ifdef not matched by an @#endif (unexpected end of file)"); } +<ELSE_BODY><<EOF>> { driver.error(if_stmt_loc_tmp, "@#if/@#ifdef/@#ifndef not matched by an @#endif (unexpected end of file)"); } <ELSE_BODY>^{SPC}*@#{SPC}*endif{SPC}*(\/\/.*)?{EOL} { yylloc->lines(1);