2008-02-03 11:28:36 +01:00
/*
2012-01-03 17:34:06 +01:00
* Copyright ( C ) 2008 - 2012 Dynare Team
2008-02-03 11:28:36 +01:00
*
* 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/>.
*/
# ifndef _MACRO_DRIVER_HH
# define _MACRO_DRIVER_HH
# ifdef _PARSING_DRIVER_HH
# error Impossible to include both ParsingDriver.hh and MacroDriver.hh
# endif
# include <string>
# include <iostream>
# include <stack>
2008-02-15 18:31:40 +01:00
# include <map>
2008-02-29 17:21:01 +01:00
# include <set>
2008-02-03 11:28:36 +01:00
2008-02-15 18:31:40 +01:00
# include "MacroValue.hh"
2009-02-27 15:29:08 +01:00
# include "MacroBison.hh"
2008-02-03 11:28:36 +01:00
using namespace std ;
// Declare MacroFlexLexer class
# ifndef __FLEX_LEXER_H
# define yyFlexLexer MacroFlexLexer
2009-09-21 12:00:47 +02:00
# include <FlexLexer.h>
2008-02-03 11:28:36 +01:00
# undef yyFlexLexer
# endif
//! The lexer class
/*! Actually it was necessary to subclass the MacroFlexLexer class generated by Flex,
2009-01-23 11:59:37 +01:00
since the prototype for MacroFlexLexer : : yylex ( ) was not convenient .
2008-02-03 11:28:36 +01:00
*/
class MacroFlex : public MacroFlexLexer
{
2008-03-07 16:58:35 +01:00
private :
2008-02-29 17:21:01 +01:00
//! Used to backup all the information related to a given scanning context
class ScanContext
{
public :
2008-08-25 18:45:39 +02:00
istream * input ;
2008-02-29 17:21:01 +01:00
struct yy_buffer_state * buffer ;
const Macro : : parser : : location_type yylloc ;
2009-02-05 16:54:09 +01:00
const bool is_for_context ;
2008-02-29 17:21:01 +01:00
const string for_body ;
const Macro : : parser : : location_type for_body_loc ;
2008-08-25 18:45:39 +02:00
ScanContext ( istream * input_arg , struct yy_buffer_state * buffer_arg ,
2009-02-05 16:54:09 +01:00
Macro : : parser : : location_type & yylloc_arg , bool is_for_context_arg ,
const string & for_body_arg ,
2008-02-29 17:21:01 +01:00
Macro : : parser : : location_type & for_body_loc_arg ) :
2009-02-05 16:54:09 +01:00
input ( input_arg ) , buffer ( buffer_arg ) , yylloc ( yylloc_arg ) , is_for_context ( is_for_context_arg ) ,
2009-12-16 18:13:23 +01:00
for_body ( for_body_arg ) , for_body_loc ( for_body_loc_arg )
{
}
2008-02-29 17:21:01 +01:00
} ;
2008-03-07 16:58:35 +01:00
2008-02-29 17:21:01 +01:00
//! The stack used to keep track of nested scanning contexts
stack < ScanContext > context_stack ;
//! Input stream used for initialization of current scanning context
/*! Kept for deletion at end of current scanning buffer */
2008-08-25 18:45:39 +02:00
istream * input ;
2008-02-29 17:21:01 +01:00
2009-01-21 14:45:44 +01:00
//! Should we omit the @#line statements ?
const bool no_line_macro ;
2009-02-05 16:54:09 +01:00
//! True iff current context is the body of a loop
bool is_for_context ;
//! If current context is the body of a loop, contains the string of the loop body
2008-02-29 17:21:01 +01:00
string for_body ;
//! If current context is the body of a loop, contains the location of the beginning of the body
Macro : : parser : : location_type for_body_loc ;
//! Temporary variable used in FOR_BODY mode
string for_body_tmp ;
//! Temporary variable used in FOR_BODY mode
Macro : : parser : : location_type for_body_loc_tmp ;
2008-12-09 17:13:03 +01:00
//! Temporary variable used in FOR_BODY mode. Keeps track of the location of the @#for statement, for reporting messages
Macro : : parser : : location_type for_stmt_loc_tmp ;
2008-04-10 10:16:54 +02:00
//! Temporary variable used in FOR_BODY mode. Keeps track of number of nested @#for/@#endfor
2008-02-29 17:21:01 +01:00
int nested_for_nb ;
//! Set to true while parsing a FOR statement (only the statement, not the loop body)
bool reading_for_statement ;
2008-04-10 10:16:54 +02:00
//! Temporary variable used in THEN_BODY and ELSE_BODY modes. Keeps track of number of nested @#if
2008-03-07 16:58:35 +01:00
int nested_if_nb ;
//! Temporary variable used in THEN_BODY mode
string then_body_tmp ;
//! Temporary variable used in THEN_BODY mode
Macro : : parser : : location_type then_body_loc_tmp ;
2008-12-09 17:13:03 +01:00
//! Temporary variable used in THEN_BODY mode. Keeps track of the location of the @#if statement, for reporting messages
Macro : : parser : : location_type if_stmt_loc_tmp ;
2008-03-07 16:58:35 +01:00
//! Temporary variable used in ELSE_BODY mode
string else_body_tmp ;
//! Temporary variable used in ELSE_BODY mode
Macro : : parser : : location_type else_body_loc_tmp ;
//! Set to true while parsing an IF statement (only the statement, not the body)
bool reading_if_statement ;
2008-04-10 10:16:54 +02:00
//! Output the @#line declaration
2008-03-07 16:58:35 +01:00
void output_line ( Macro : : parser : : location_type * yylloc ) const ;
//! Save current scanning context
void save_context ( Macro : : parser : : location_type * yylloc ) ;
//! Restore last scanning context
void restore_context ( Macro : : parser : : location_type * yylloc ) ;
//! Saves current scanning context and create a new context with content of filename
/*! Filename must be a newly allocated string which will be deleted by the lexer */
void create_include_context ( string * filename , Macro : : parser : : location_type * yylloc ,
MacroDriver & driver ) ;
//! Saves current scanning context and create a new context based on the "then" body
void create_then_context ( Macro : : parser : : location_type * yylloc ) ;
//! Saves current scanning context and create a new context based on the "else" body
void create_else_context ( Macro : : parser : : location_type * yylloc ) ;
2008-02-29 17:21:01 +01:00
2009-02-06 16:47:26 +01:00
//! Initialise a new flex buffer with the loop body
void new_loop_body_buffer ( Macro : : parser : : location_type * yylloc ) ;
2008-02-03 11:28:36 +01:00
public :
2009-12-16 18:13:23 +01:00
MacroFlex ( istream * in , ostream * out , bool no_line_macro_arg ) ;
2008-02-03 11:28:36 +01:00
//! The main lexing function
Macro : : parser : : token_type lex ( Macro : : parser : : semantic_type * yylval ,
Macro : : parser : : location_type * yylloc ,
MacroDriver & driver ) ;
} ;
//! Implements the macro expansion using a Flex scanner and a Bison parser
class MacroDriver
{
2008-02-29 17:21:01 +01:00
friend class MacroValue ;
2008-02-22 13:03:38 +01:00
private :
2008-03-07 16:58:35 +01:00
//! Stores all created macro values
2008-02-29 17:21:01 +01:00
set < const MacroValue * > values ;
2008-02-22 13:03:38 +01:00
//! Environment: maps macro variables to their values
2008-02-29 17:21:01 +01:00
map < string , const MacroValue * > env ;
2008-02-22 13:03:38 +01:00
2008-02-29 17:21:01 +01:00
//! Stack used to keep track of (possibly nested) loops
//! First element is loop variable name, second is the array over which iteration is done, and third is subscript to be used by next call of iter_loop() (beginning with 0) */
stack < pair < string , pair < const MacroValue * , int > > > loop_stack ;
2008-02-03 11:28:36 +01:00
public :
2008-02-22 13:03:38 +01:00
//! Exception thrown when value of an unknown variable is requested
class UnknownVariable
{
public :
const string name ;
2009-12-16 18:13:23 +01:00
UnknownVariable ( const string & name_arg ) : name ( name_arg )
{
}
2008-02-22 13:03:38 +01:00
} ;
2008-02-03 11:28:36 +01:00
//! Constructor
2008-03-28 18:38:10 +01:00
MacroDriver ( ) ;
2008-02-03 11:28:36 +01:00
//! Destructor
virtual ~ MacroDriver ( ) ;
//! Starts parsing a file, returns output in out
2009-01-21 14:45:44 +01:00
/*! \param no_line_macro should we omit the @#line statements ? */
2011-03-29 15:53:10 +02:00
void parse ( const string & f , ostream & out , bool debug , bool no_line_macro , map < string , string > defines ) ;
2008-02-03 11:28:36 +01:00
//! Name of main file being parsed
string file ;
//! Reference to the lexer
class MacroFlex * lexer ;
2008-04-10 10:16:54 +02:00
//! Used to store the value of the last @#if condition
2008-03-07 16:58:35 +01:00
bool last_if ;
2008-02-03 11:28:36 +01:00
//! Error handler
2008-02-22 13:03:38 +01:00
void error ( const Macro : : parser : : location_type & l , const string & m ) const ;
//! Set a variable
2008-02-29 17:21:01 +01:00
void set_variable ( const string & name , const MacroValue * value ) ;
2008-02-22 13:03:38 +01:00
//! Get a variable
/*! Returns a newly allocated value (clone of the value stored in environment). */
2008-02-29 17:21:01 +01:00
const MacroValue * get_variable ( const string & name ) const throw ( UnknownVariable ) ;
//! Initiate a for loop
/*! Does not set name = value[1]. You must call iter_loop() for that. */
void init_loop ( const string & name , const MacroValue * value ) throw ( MacroValue : : TypeError ) ;
//! Iterate innermost loop
/*! Returns false if iteration is no more possible (end of loop); in that case it destroys the pointer given to init_loop() */
bool iter_loop ( ) ;
2008-03-07 16:58:35 +01:00
2008-04-10 10:16:54 +02:00
//! Begins an @#if statement
2008-03-07 16:58:35 +01:00
void begin_if ( const MacroValue * value ) throw ( MacroValue : : TypeError ) ;
2012-01-02 18:08:14 +01:00
//! Begins an @#ifdef statement
void begin_ifdef ( const string & name ) ;
2012-06-26 15:12:31 +02:00
//! Begins an @#ifndef statement
void begin_ifndef ( const string & name ) ;
2008-04-10 10:16:54 +02:00
//! Executes @#echo directive
2008-03-07 16:58:35 +01:00
void echo ( const Macro : : parser : : location_type & l , const MacroValue * value ) const throw ( MacroValue : : TypeError ) ;
2008-04-10 10:16:54 +02:00
//! Executes @#error directive
2008-03-07 16:58:35 +01:00
void error ( const Macro : : parser : : location_type & l , const MacroValue * value ) const throw ( MacroValue : : TypeError ) ;
2008-02-03 11:28:36 +01:00
} ;
# endif // ! MACRO_DRIVER_HH