219 lines
7.8 KiB
C++
219 lines
7.8 KiB
C++
/*
|
|
* Copyright (C) 2008-2009 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/>.
|
|
*/
|
|
|
|
#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>
|
|
#include <map>
|
|
#include <set>
|
|
|
|
#include "MacroValue.hh"
|
|
#include "MacroBison.hh"
|
|
|
|
using namespace std;
|
|
|
|
// Declare MacroFlexLexer class
|
|
#ifndef __FLEX_LEXER_H
|
|
# define yyFlexLexer MacroFlexLexer
|
|
# include <FlexLexer.h>
|
|
# undef yyFlexLexer
|
|
#endif
|
|
|
|
//! The lexer class
|
|
/*! Actually it was necessary to subclass the MacroFlexLexer class generated by Flex,
|
|
since the prototype for MacroFlexLexer::yylex() was not convenient.
|
|
*/
|
|
class MacroFlex : public MacroFlexLexer
|
|
{
|
|
private:
|
|
//! Used to backup all the information related to a given scanning context
|
|
class ScanContext
|
|
{
|
|
public:
|
|
istream *input;
|
|
struct yy_buffer_state *buffer;
|
|
const Macro::parser::location_type yylloc;
|
|
const bool is_for_context;
|
|
const string for_body;
|
|
const Macro::parser::location_type for_body_loc;
|
|
ScanContext(istream *input_arg, struct yy_buffer_state *buffer_arg,
|
|
Macro::parser::location_type &yylloc_arg, bool is_for_context_arg,
|
|
const string &for_body_arg,
|
|
Macro::parser::location_type &for_body_loc_arg) :
|
|
input(input_arg), buffer(buffer_arg), yylloc(yylloc_arg), is_for_context(is_for_context_arg),
|
|
for_body(for_body_arg), for_body_loc(for_body_loc_arg)
|
|
{
|
|
}
|
|
};
|
|
|
|
//! 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 */
|
|
istream *input;
|
|
|
|
//! Should we omit the @#line statements ?
|
|
const bool no_line_macro;
|
|
|
|
//! 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
|
|
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;
|
|
//! 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;
|
|
//! Temporary variable used in FOR_BODY mode. Keeps track of number of nested @#for/@#endfor
|
|
int nested_for_nb;
|
|
//! Set to true while parsing a FOR statement (only the statement, not the loop body)
|
|
bool reading_for_statement;
|
|
|
|
//! Temporary variable used in THEN_BODY and ELSE_BODY modes. Keeps track of number of nested @#if
|
|
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;
|
|
//! 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;
|
|
//! 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;
|
|
|
|
//! Output the @#line declaration
|
|
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);
|
|
|
|
//! Initialise a new flex buffer with the loop body
|
|
void new_loop_body_buffer(Macro::parser::location_type *yylloc);
|
|
|
|
public:
|
|
MacroFlex(istream *in, ostream *out, bool no_line_macro_arg);
|
|
|
|
//! 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
|
|
{
|
|
friend class MacroValue;
|
|
private:
|
|
//! Stores all created macro values
|
|
set<const MacroValue *> values;
|
|
|
|
//! Environment: maps macro variables to their values
|
|
map<string, const MacroValue *> env;
|
|
|
|
//! 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;
|
|
public:
|
|
//! Exception thrown when value of an unknown variable is requested
|
|
class UnknownVariable
|
|
{
|
|
public:
|
|
const string name;
|
|
UnknownVariable(const string &name_arg) : name(name_arg)
|
|
{
|
|
}
|
|
};
|
|
|
|
//! Constructor
|
|
MacroDriver();
|
|
//! Destructor
|
|
virtual ~MacroDriver();
|
|
|
|
//! Starts parsing a file, returns output in out
|
|
/*! \param no_line_macro should we omit the @#line statements ? */
|
|
void parse(const string &f, ostream &out, bool debug, bool no_line_macro, map<string,string> defines);
|
|
|
|
//! Name of main file being parsed
|
|
string file;
|
|
|
|
//! Reference to the lexer
|
|
class MacroFlex *lexer;
|
|
|
|
//! Used to store the value of the last @#if condition
|
|
bool last_if;
|
|
|
|
//! Error handler
|
|
void error(const Macro::parser::location_type &l, const string &m) const;
|
|
|
|
//! Set a variable
|
|
void set_variable(const string &name, const MacroValue *value);
|
|
|
|
//! Get a variable
|
|
/*! Returns a newly allocated value (clone of the value stored in environment). */
|
|
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();
|
|
|
|
//! Begins an @#if statement
|
|
void begin_if(const MacroValue *value) throw (MacroValue::TypeError);
|
|
|
|
//! Executes @#echo directive
|
|
void echo(const Macro::parser::location_type &l, const MacroValue *value) const throw (MacroValue::TypeError);
|
|
|
|
//! Executes @#error directive
|
|
void error(const Macro::parser::location_type &l, const MacroValue *value) const throw (MacroValue::TypeError);
|
|
};
|
|
|
|
#endif // ! MACRO_DRIVER_HH
|