Skip to content
Snippets Groups Projects
Select Git revision
  • 4ad7de7bb939d11d8dd0e033d15a524557ef5916
  • master default protected
  • python-visitor
  • python-codegen
  • 6.x protected
  • julia protected
  • llvm-15
  • 5.x protected
  • 4.6 protected
  • uop
  • rework_pac
  • aux_vars_fix
  • julia-7.0.0
  • julia-6.4.0
  • julia-6.3.0
  • julia-6.2.0
16 results

MacroDriver.hh

Blame
  • MacroDriver.hh 7.58 KiB
    /*
     * Copyright (C) 2008 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 "MacroBison.hh"
    #include "MacroValue.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 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, const string &for_body_arg,
                    Macro::parser::location_type &for_body_loc_arg) :
          input(input_arg), buffer(buffer_arg), yylloc(yylloc_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;
    
      //! If current context is the body of a loop, contains the string of the loop body. Empty otherwise.
      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);
    
      //! Iterates over the loop body
      /*! If loop is terminated, return false and do nothing.
          Otherwise, set loop variable to its new value (through driver.iter_loop()),
          and initialise a new scanning context with the loop body */
      bool iter_loop(MacroDriver &driver, Macro::parser::location_type *yylloc);
    public:
      MacroFlex(istream* in = 0, ostream* out = 0);
    
      //! 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
      void parse(const string &f, ostream &out, bool debug);
    
      //! 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