1 /*
2  * Copyright © 2019-2020 Dynare Team
3  *
4  * This file is part of Dynare.
5  *
6  * Dynare is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * Dynare is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with Dynare.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #ifndef _MACRO_DRIVER_HH
21 #define _MACRO_DRIVER_HH
22 
23 #ifdef _PARSING_DRIVER_HH
24 # error Impossible to include both ../ParsingDriver.hh and Driver.hh
25 #endif
26 
27 #include "Parser.hh"
28 #include "Environment.hh"
29 #include "Expressions.hh"
30 
31 #include <stack>
32 
33 // Declare TokenizerFlexLexer class
34 #ifndef __FLEX_LEXER_H
35 # define yyFlexLexer TokenizerFlexLexer
36 # include <FlexLexer.h>
37 # undef yyFlexLexer
38 #endif
39 
40 namespace macro
41 {
42   /* The lexer class
43    * It was necessary to subclass the TokenizerFlexLexer class generated by Flex,
44    * since the prototype for TokenizerFlexLexer::yylex() was not convenient.
45    */
46   class TokenizerFlex : public TokenizerFlexLexer
47   {
48   public:
TokenizerFlex(istream * in)49     TokenizerFlex(istream *in) : TokenizerFlexLexer{in} { }
50     TokenizerFlex(const TokenizerFlex &) = delete;
51     TokenizerFlex(TokenizerFlex &&) = delete;
52     TokenizerFlex &operator=(const TokenizerFlex &) = delete;
53     TokenizerFlex &operator=(TokenizerFlex &&) = delete;
54 
55     //! The main lexing function
56     Tokenizer::parser::token_type lex(Tokenizer::parser::semantic_type *yylval,
57                                       Tokenizer::parser::location_type *yylloc,
58                                       macro::Driver &driver);
59   };
60 
61   //! Implements the macro expansion using a Flex scanner and a Bison parser
62   class Driver
63   {
64   public:
65     Environment &env;
66   private:
67     vector<DirectivePtr> statements;
68     stack<vector<DirectivePtr>> directive_stack;
69   public:
Driver(Environment & env_arg)70     Driver(Environment &env_arg) :
71       env{env_arg} { }
72     Driver(const Driver &) = delete;
73     Driver(Driver &&) = delete;
74     Driver &operator=(const Driver &) = delete;
75     Driver &operator=(Driver &&) = delete;
76 
77     //! Exception thrown when value of an unknown variable is requested
78     class UnknownVariable
79     {
80     public:
81       const string name;
UnknownVariable(string name_arg)82       explicit UnknownVariable(string name_arg) : name{move(name_arg)}
83       {
84       }
85     };
86 
87     //! Starts parsing a file, returns output in out
88     void parse(const string &file_arg, const string &basename_arg, istream &modfile,
89                ostream &output, bool debug, const vector<pair<string, string>> &defines,
90                vector<filesystem::path> &paths_arg);
91 
92     //! Name of main file being parsed
93     string file;
94 
95     //! Basename of main file being parsed
96     string basename;
97 
98     //! Reference to the lexer
99     unique_ptr<TokenizerFlex> lexer;
100 
101     //! Error handler
102     void error(const Tokenizer::parser::location_type &location, const string &message) const;
103 
104     inline bool
inContext() const105     inContext() const
106     {
107       return !directive_stack.empty();
108     }
109 
110     inline void
pushContext()111     pushContext()
112     {
113       directive_stack.emplace(vector<DirectivePtr>());
114     }
115 
116     inline void
pushContextTop(DirectivePtr statement)117     pushContextTop(DirectivePtr statement)
118     {
119       directive_stack.top().emplace_back(move(statement));
120     }
121 
122     inline void
pushStatements(DirectivePtr statement)123     pushStatements(DirectivePtr statement)
124     {
125       statements.emplace_back(move(statement));
126     }
127 
128     inline vector<DirectivePtr>
popContext()129     popContext()
130     {
131       auto top = move(directive_stack.top());
132       directive_stack.pop();
133       return top;
134     }
135   };
136 }
137 #endif
138