MacroDriver.hh 7.58 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/*
 * 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>
30
#include <map>
31
#include <set>
32
33

#include "MacroBison.hh"
34
#include "MacroValue.hh"
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50

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
{
sebastien's avatar
sebastien committed
51
private:
52
53
54
55
  //! Used to backup all the information related to a given scanning context
  class ScanContext
  {
  public:
sebastien's avatar
sebastien committed
56
    istream *input;
57
58
59
60
    struct yy_buffer_state *buffer;
    const Macro::parser::location_type yylloc;
    const string for_body;
    const Macro::parser::location_type for_body_loc;
sebastien's avatar
sebastien committed
61
    ScanContext(istream *input_arg, struct yy_buffer_state *buffer_arg,
62
63
64
65
66
                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) { }
  };
sebastien's avatar
sebastien committed
67

68
69
70
71
72
  //! 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 */
sebastien's avatar
sebastien committed
73
  istream *input;
74
75
76
77
78
79
80
81
82
83

  //! 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;
84
85
  //! 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;
86
  //! Temporary variable used in FOR_BODY mode. Keeps track of number of nested @#for/@#endfor
87
88
89
90
  int nested_for_nb;
  //! Set to true while parsing a FOR statement (only the statement, not the loop body)
  bool reading_for_statement;

91
  //! Temporary variable used in THEN_BODY and ELSE_BODY modes. Keeps track of number of nested @#if
sebastien's avatar
sebastien committed
92
93
94
95
96
  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;
97
98
  //! 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;
sebastien's avatar
sebastien committed
99
100
101
102
103
104
105
  //! 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;

106
  //! Output the @#line declaration
sebastien's avatar
sebastien committed
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
  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);
125
126
127
128
129
130

  //! 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);
131
public:
sebastien's avatar
sebastien committed
132
  MacroFlex(istream* in = 0, ostream* out = 0);
133
134
135
136
137
138
139
140
141
142

  //! 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
{
143
  friend class MacroValue;
144
private:
sebastien's avatar
sebastien committed
145
  //! Stores all created macro values
146
147
  set<const MacroValue *> values;

148
  //! Environment: maps macro variables to their values
149
  map<string, const MacroValue *> env;
150

151
152
153
  //! 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;
154
public:
155
156
157
158
159
160
161
162
  //! Exception thrown when value of an unknown variable is requested
  class UnknownVariable
  {
  public:
    const string name;
    UnknownVariable(const string &name_arg) : name(name_arg) {}
  };

163
  //! Constructor
164
  MacroDriver();
165
166
167
168
  //! Destructor
  virtual ~MacroDriver();

  //! Starts parsing a file, returns output in out
169
  void parse(const string &f, ostream &out, bool debug);
170
171
172
173
174
175
176

  //! Name of main file being parsed
  string file;

  //! Reference to the lexer
  class MacroFlex *lexer;

177
  //! Used to store the value of the last @#if condition
sebastien's avatar
sebastien committed
178
179
  bool last_if;

180
  //! Error handler
181
182
183
  void error(const Macro::parser::location_type &l, const string &m) const;

  //! Set a variable
184
  void set_variable(const string &name, const MacroValue *value);
185
186
187

  //! Get a variable
  /*! Returns a newly allocated value (clone of the value stored in environment). */
188
189
190
191
192
193
194
195
196
  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();
sebastien's avatar
sebastien committed
197

198
  //! Begins an @#if statement
sebastien's avatar
sebastien committed
199
200
  void begin_if(const MacroValue *value) throw (MacroValue::TypeError);

201
  //! Executes @#echo directive
sebastien's avatar
sebastien committed
202
203
  void echo(const Macro::parser::location_type &l, const MacroValue *value) const throw (MacroValue::TypeError);

204
  //! Executes @#error directive
sebastien's avatar
sebastien committed
205
  void error(const Macro::parser::location_type &l, const MacroValue *value) const throw (MacroValue::TypeError);
206
207
208
};

#endif // ! MACRO_DRIVER_HH