preprocessor/src/macro/MacroBison.yy

215 lines
5.9 KiB
Plaintext

/*
* Copyright (C) 2008-2017 Dynare Team
*
* This file is part of Dynare.
*
* Dynare is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Dynare is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Dynare. If not, see <http://www.gnu.org/licenses/>.
*/
%skeleton "lalr1.cc"
%require "2.5"
%defines
%code top {
class MacroDriver;
}
%name-prefix "Macro"
%parse-param { MacroDriver &driver }
%parse-param { ostream &out }
%lex-param { MacroDriver &driver }
%locations
%initial-action
{
// Initialize the location filenames
@$.begin.filename = @$.end.filename = &driver.file;
};
%debug
%error-verbose
%code requires {
#include "MacroValue.hh"
}
%union
{
string *string_val;
int int_val;
const MacroValue *mv;
};
%code {
#include <cstdlib> // Pour atoi()
#include "MacroDriver.hh"
/* this "connects" the bison parser in the driver to the flex scanner class
* object. it defines the yylex() function call to pull the next token from the
* current lexer object of the driver context. */
#undef yylex
#define yylex driver.lexer->lex
#define TYPERR_CATCH(statement, loc) try \
{ \
statement; \
} \
catch(MacroValue::TypeError &e) \
{ \
driver.error(loc, e.message); \
}
}
%token DEFINE LINE FOR IN IF ELSE ENDIF ECHO_DIR ERROR IFDEF IFNDEF
%token LPAREN RPAREN LBRACKET RBRACKET EQUAL EOL LENGTH ECHOMACROVARS SAVE
%token <int_val> INTEGER
%token <string_val> NAME STRING
%left COMMA
%left LOGICAL_OR
%left LOGICAL_AND
%left LESS GREATER LESS_EQUAL GREATER_EQUAL EQUAL_EQUAL EXCLAMATION_EQUAL
%nonassoc IN
%nonassoc COLON
%left PLUS MINUS
%left TIMES DIVIDE
%left UMINUS UPLUS EXCLAMATION
%left LBRACKET
%type <mv> expr array_expr
%%
%start statement_list_or_nothing;
statement_list_or_nothing : /* empty */
| statement_list
;
statement_list : statement EOL
| statement_list statement EOL
;
statement : expr
{ out << $1->toString(); }
| DEFINE NAME EQUAL expr
{ driver.set_variable(*$2, $4); delete $2; }
| FOR NAME IN expr
{ TYPERR_CATCH(driver.init_loop(*$2, $4), @$); delete $2; }
| IF 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
{ TYPERR_CATCH(driver.error(@$, $2), @$); }
| LINE STRING INTEGER
/* Ignore @#line declarations */
| ECHOMACROVARS
{ driver.printvars(@$, true); }
| ECHOMACROVARS LPAREN SAVE RPAREN
{ out << driver.printvars(@$, false); }
;
expr : INTEGER
{ $$ = new IntMV(driver, $1); }
| STRING
{ $$ = new StringMV(driver, *$1); delete $1; }
| NAME
{
try
{
$$ = driver.get_variable(*$1);
}
catch(MacroDriver::UnknownVariable(&e))
{
error(@$, "Unknown variable: " + e.name);
}
delete $1;
}
| LENGTH LPAREN array_expr RPAREN
{ TYPERR_CATCH($$ = $3->length(), @$); }
| LPAREN expr RPAREN
{ $$ = $2; }
| expr PLUS expr
{ TYPERR_CATCH($$ = *$1 + *$3, @$); }
| expr MINUS expr
{ TYPERR_CATCH($$ = *$1 - *$3, @$); }
| expr TIMES expr
{ TYPERR_CATCH($$ = *$1 * *$3, @$); }
| expr DIVIDE expr
{
if (dynamic_cast<const IntMV *>($3) != NULL
&& ((IntMV *)$3)->get_int_value() == 0)
driver.error(@$, "Division by zero");
TYPERR_CATCH($$ = *$1 / *$3, @$);
}
| expr LESS expr
{ TYPERR_CATCH($$ = *$1 < *$3, @$); }
| expr GREATER expr
{ TYPERR_CATCH($$ = *$1 > *$3, @$); }
| expr LESS_EQUAL expr
{ TYPERR_CATCH($$ = *$1 <= *$3, @$); }
| expr GREATER_EQUAL expr
{ TYPERR_CATCH($$ = *$1 >= *$3, @$); }
| expr EQUAL_EQUAL expr
{ TYPERR_CATCH($$ = *$1 == *$3, @$); }
| expr EXCLAMATION_EQUAL expr
{ TYPERR_CATCH($$ = *$1 != *$3, @$); }
| expr LOGICAL_OR expr
{ TYPERR_CATCH($$ = *$1 || *$3, @$); }
| expr LOGICAL_AND expr
{ TYPERR_CATCH($$ = *$1 && *$3, @$); }
| MINUS expr %prec UMINUS
{ TYPERR_CATCH($$ = -*$2, @$); }
| PLUS expr %prec UPLUS
{ TYPERR_CATCH($$ = +(*$2), @$); }
| EXCLAMATION expr
{ TYPERR_CATCH($$ = !*$2, @$); }
| expr LBRACKET array_expr RBRACKET
{
TYPERR_CATCH($$ = (*$1)[*$3], @$)
catch(MacroValue::OutOfBoundsError)
{
error(@$, "Index out of bounds");
}
}
| LBRACKET array_expr RBRACKET
{ $$ = $2; }
| expr COLON expr
{ TYPERR_CATCH($$ = IntMV::new_range(driver, $1, $3), @$); }
| expr IN expr
{ TYPERR_CATCH($$ = $1->in($3), @$); }
;
array_expr : expr
{ $$ = $1->toArray(); }
| array_expr COMMA expr
{ TYPERR_CATCH($$ = $3->append($1), @$); }
;
%%
void
Macro::parser::error(const Macro::parser::location_type &l,
const string &m)
{
driver.error(l, m);
}