From 98f96190038b3ad6bcd2c1b55fc925df9017b7bb Mon Sep 17 00:00:00 2001 From: sebastien Date: Fri, 29 Feb 2008 16:21:01 +0000 Subject: [PATCH] v4 preprocessor/macro: added @for loops git-svn-id: https://www.dynare.org/svn/dynare/dynare_v4@1724 ac1d8469-bf42-47a9-8791-bf33cf982152 --- preprocessor/macro/MacroBison.yy | 70 +++++----- preprocessor/macro/MacroDriver.cc | 69 +++++++++- preprocessor/macro/MacroDriver.hh | 76 +++++++++-- preprocessor/macro/MacroFlex.ll | 147 ++++++++++++++------ preprocessor/macro/MacroValue.cc | 184 ++++++++++++------------- preprocessor/macro/MacroValue.hh | 216 +++++++++++++----------------- 6 files changed, 454 insertions(+), 308 deletions(-) diff --git a/preprocessor/macro/MacroBison.yy b/preprocessor/macro/MacroBison.yy index d27e96b9c..e61bb5e9a 100644 --- a/preprocessor/macro/MacroBison.yy +++ b/preprocessor/macro/MacroBison.yy @@ -51,7 +51,7 @@ class MacroDriver; { string *string_val; int int_val; - MacroValue *mv; + const MacroValue *mv; }; %{ @@ -64,9 +64,9 @@ class MacroDriver; #undef yylex #define yylex driver.lexer->lex -#define TYPERR_CATCH(st, loc) try \ +#define TYPERR_CATCH(statement, loc) try \ { \ - st; \ + statement; \ } \ catch(MacroValue::TypeError &e) \ { \ @@ -75,7 +75,7 @@ class MacroDriver; %} -%token DEFINE LINE +%token DEFINE LINE FOR IN %token LPAREN RPAREN LBRACKET RBRACKET EQUAL EOL %token INTEGER @@ -98,24 +98,30 @@ class MacroDriver; %start statement_list_or_nothing; statement_list_or_nothing : /* empty */ - | statement_list; + | statement_list + ; statement_list : statement EOL - | statement_list statement EOL; + | statement_list statement EOL + ; statement : expr - { *driver.out_stream << $1->toString(); delete $1; } + { *driver.out_stream << $1->toString(); } | DEFINE NAME EQUAL expr { driver.set_variable(*$2, $4); delete $2; } + | FOR NAME IN expr + { TYPERR_CATCH(driver.init_loop(*$2, $4), @$); delete $2; } | LINE STRING INTEGER /* Ignore @line declarations */ + ; expr : INTEGER - { $$ = new IntMV($1); } + { $$ = new IntMV(driver, $1); } | STRING - { $$ = new StringMV(*$1); delete $1; } + { $$ = new StringMV(driver, *$1); delete $1; } | NAME - { try + { + try { $$ = driver.get_variable(*$1); } @@ -123,56 +129,58 @@ expr : INTEGER { error(@$, "Unknown variable: " + e.name); } - delete $1; } + delete $1; + } | LPAREN expr RPAREN { $$ = $2; } | expr PLUS expr - { TYPERR_CATCH($$ = *$1 + *$3, @$); delete $1; delete $3; } + { TYPERR_CATCH($$ = *$1 + *$3, @$); } | expr MINUS expr - { TYPERR_CATCH($$ = *$1 - *$3, @$); delete $1; delete $3; } + { TYPERR_CATCH($$ = *$1 - *$3, @$); } | expr TIMES expr - { TYPERR_CATCH($$ = *$1 * *$3, @$); delete $1; delete $3; } + { TYPERR_CATCH($$ = *$1 * *$3, @$); } | expr DIVIDE expr - { TYPERR_CATCH($$ = *$1 / *$3, @$); delete $1; delete $3; } + { TYPERR_CATCH($$ = *$1 / *$3, @$); } | expr LESS expr - { TYPERR_CATCH($$ = *$1 < *$3, @$); delete $1; delete $3; } + { TYPERR_CATCH($$ = *$1 < *$3, @$); } | expr GREATER expr - { TYPERR_CATCH($$ = *$1 > *$3, @$); delete $1; delete $3; } + { TYPERR_CATCH($$ = *$1 > *$3, @$); } | expr LESS_EQUAL expr - { TYPERR_CATCH($$ = *$1 <= *$3, @$); delete $1; delete $3; } + { TYPERR_CATCH($$ = *$1 <= *$3, @$); } | expr GREATER_EQUAL expr - { TYPERR_CATCH($$ = *$1 >= *$3, @$); delete $1; delete $3; } + { TYPERR_CATCH($$ = *$1 >= *$3, @$); } | expr EQUAL_EQUAL expr - { TYPERR_CATCH($$ = *$1 == *$3, @$); delete $1; delete $3; } + { TYPERR_CATCH($$ = *$1 == *$3, @$); } | expr EXCLAMATION_EQUAL expr - { TYPERR_CATCH($$ = *$1 != *$3, @$); delete $1; delete $3; } + { TYPERR_CATCH($$ = *$1 != *$3, @$); } | expr LOGICAL_OR expr - { TYPERR_CATCH($$ = *$1 || *$3, @$); delete $1; delete $3; } + { TYPERR_CATCH($$ = *$1 || *$3, @$); } | expr LOGICAL_AND expr - { TYPERR_CATCH($$ = *$1 && *$3, @$); delete $1; delete $3; } + { TYPERR_CATCH($$ = *$1 && *$3, @$); } | MINUS expr %prec UMINUS - { TYPERR_CATCH($$ = -*$2, @$); delete $2;} + { TYPERR_CATCH($$ = -*$2, @$); } | PLUS expr %prec UPLUS - { TYPERR_CATCH($$ = +(*$2), @$); delete $2; } + { TYPERR_CATCH($$ = +(*$2), @$); } | EXCLAMATION expr - { TYPERR_CATCH($$ = !*$2, @$); delete $2; } + { TYPERR_CATCH($$ = !*$2, @$); } | expr LBRACKET array_expr RBRACKET - { TYPERR_CATCH($$ = (*$1)[*$3], @$) + { + TYPERR_CATCH($$ = (*$1)[*$3], @$) catch(MacroValue::OutOfBoundsError) { error(@$, "Index out of bounds"); } - delete $1; delete $3; } + } | LBRACKET array_expr RBRACKET { $$ = $2; } | expr COLON expr - { TYPERR_CATCH($$ = IntMV::new_range(*$1, *$3), @$); delete $1; delete $3; } + { TYPERR_CATCH($$ = IntMV::new_range(driver, $1, $3), @$); } ; array_expr : expr - { $$ = $1->toArray(); delete $1; } + { $$ = $1->toArray(); } | array_expr COMMA expr - { TYPERR_CATCH($$ = $3->append(*$1), @$); delete $1; delete $3; } + { TYPERR_CATCH($$ = $3->append($1), @$); } ; %% diff --git a/preprocessor/macro/MacroDriver.cc b/preprocessor/macro/MacroDriver.cc index 7041e9261..0b27a4ed4 100644 --- a/preprocessor/macro/MacroDriver.cc +++ b/preprocessor/macro/MacroDriver.cc @@ -28,9 +28,9 @@ MacroDriver::MacroDriver() : trace_scanning(false), trace_parsing(false) MacroDriver::~MacroDriver() { - for(map::iterator it = env.begin(); - it != env.end(); it++) - delete it->second; + for(set::iterator it = values.begin(); + it != values.end(); it++) + delete *it; } void @@ -40,6 +40,11 @@ MacroDriver::parse(const string &f, ostream &out) out_stream = &out; ifstream in(f.c_str(), ios::binary); + if (in.fail()) + { + cerr << "ERROR: Could not open file: " << f << endl; + exit(-1); + } lexer = new MacroFlex(&in, &out); lexer->set_debug(trace_scanning); @@ -58,16 +63,66 @@ MacroDriver::error(const Macro::parser::location_type &l, const string &m) const } void -MacroDriver::set_variable(const string &name, MacroValue *value) +MacroDriver::set_variable(const string &name, const MacroValue *value) { env[name] = value; } -MacroValue * +const MacroValue * MacroDriver::get_variable(const string &name) const throw (UnknownVariable) { - map::const_iterator it = env.find(name); + map::const_iterator it = env.find(name); if (it == env.end()) throw UnknownVariable(name); - return (it->second)->clone(); + return it->second; +} + +void +MacroDriver::init_loop(const string &name, const MacroValue *value) throw (MacroValue::TypeError) +{ + const ArrayMV *mv1 = dynamic_cast *>(value); + const ArrayMV *mv2 = dynamic_cast *>(value); + if (!mv1 && !mv2) + throw MacroValue::TypeError("Argument of @for loop must be an array expression"); + loop_stack.push(make_pair(name, make_pair(value, 0))); +} + +bool +MacroDriver::iter_loop() +{ + if (loop_stack.empty()) + throw "No loop on which to iterate!"; + + int &i = loop_stack.top().second.second; + const MacroValue *mv = loop_stack.top().second.first; + string name = loop_stack.top().first; + + const ArrayMV *mv1 = dynamic_cast *>(mv); + if (mv1) + { + if (i >= (int) mv1->values.size()) + { + loop_stack.pop(); + return false; + } + else + { + env[name] = new IntMV(*this, mv1->values[i++]); + return true; + } + } + else + { + const ArrayMV *mv2 = dynamic_cast *>(mv); + if (i >= (int) mv2->values.size()) + { + loop_stack.pop(); + return false; + } + else + { + env[name] = new StringMV(*this, mv2->values[i++]); + return true; + } + } } diff --git a/preprocessor/macro/MacroDriver.hh b/preprocessor/macro/MacroDriver.hh index cc48d2f3e..ac12de958 100644 --- a/preprocessor/macro/MacroDriver.hh +++ b/preprocessor/macro/MacroDriver.hh @@ -28,6 +28,7 @@ #include #include #include +#include #include "MacroBison.hh" #include "MacroValue.hh" @@ -47,14 +48,51 @@ using namespace std; */ class MacroFlex : public MacroFlexLexer { + //! 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) { } + }; private: - //! The stack used to handle (possibly nested) includes - /*! Keeps track of buffer state and associated location, as they were just before switching to - included file. - Note that we could have used yypush_buffer_state() and yypop_buffer_state() - instead of a stack for buffer states, but those functions do not exist in Flex 2.5.4 */ - stack > include_stack; + //! The stack used to keep track of nested scanning contexts + stack 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 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; + + //! Output the @line declaration + void output_line(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); @@ -67,10 +105,16 @@ public: //! Implements the macro expansion using a Flex scanner and a Bison parser class MacroDriver { + friend class MacroValue; private: - //! Environment: maps macro variables to their values - map env; + set values; + //! Environment: maps macro variables to their values + map 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 > > loop_stack; public: //! Exception thrown when value of an unknown variable is requested class UnknownVariable @@ -88,9 +132,6 @@ public: //! Starts parsing a file, returns output in out void parse(const string &f, ostream &out); - //! Pointer to keep track of the input file stream currently scanned - ifstream *ifs; - //! Name of main file being parsed string file; @@ -113,12 +154,19 @@ public: void error(const Macro::parser::location_type &l, const string &m) const; //! Set a variable - /*! Pointer *value must not be altered nor deleted afterwards, since it is kept by this class */ - void set_variable(const string &name, MacroValue *value); + void set_variable(const string &name, const MacroValue *value); //! Get a variable /*! Returns a newly allocated value (clone of the value stored in environment). */ - MacroValue *get_variable(const string &name) const throw (UnknownVariable); + 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(); }; #endif // ! MACRO_DRIVER_HH diff --git a/preprocessor/macro/MacroFlex.ll b/preprocessor/macro/MacroFlex.ll index d1205acb7..b4989c8ea 100644 --- a/preprocessor/macro/MacroFlex.ll +++ b/preprocessor/macro/MacroFlex.ll @@ -47,9 +47,8 @@ typedef Macro::parser::token token; %option case-insensitive noyywrap nounput batch debug never-interactive -%x INCLUDE -%x END_INCLUDE %x MACRO +%x FOR_BODY %{ // Increments location counter for every token read @@ -62,43 +61,54 @@ typedef Macro::parser::token token; yylloc->step(); %} -^@include[ \t]+\" BEGIN(INCLUDE); - -[^\"\r\n]* { - driver.ifs = new ifstream(yytext, ios::binary); - if (driver.ifs->fail()) - driver.error(*yylloc, "Could not open " + string(yytext)); - // Save old buffer state and location - /* We don't use yypush_buffer_state(), since it doesn't exist in - Flex 2.5.4 (see Flex 2.5.33 info file - section 11 - for code - example with yypush_buffer_state()) */ +^@include[ \t]+\"[^\"\r\n]*\"[ \t]*(\r)?\n { + yylloc->lines(1); yylloc->step(); - include_stack.push(make_pair(YY_CURRENT_BUFFER, *yylloc)); + // Save old buffer state and location + context_stack.push(ScanContext(input, YY_CURRENT_BUFFER, *yylloc, for_body, for_body_loc)); + // Get filename + string *filename = new string(yytext); + int dblq_idx1 = filename->find('"'); + int dblq_idx2 = filename->find('"', dblq_idx1 + 1); + filename->erase(dblq_idx2); + filename->erase(0, dblq_idx1 + 1); + // Open new file + input = new ifstream(filename->c_str(), ios::binary); + if (input->fail()) + driver.error(*yylloc, "Could not open " + *filename); // Reset location - yylloc->begin.filename = yylloc->end.filename = new string(yytext); + yylloc->begin.filename = yylloc->end.filename = filename; yylloc->begin.line = yylloc->end.line = 1; yylloc->begin.column = yylloc->end.column = 0; + // We are not in a loop body + for_body.erase(); // Output @line information - *yyout << "@line \"" << *yylloc->begin.filename << "\" 1" << endl; + output_line(yylloc); // Switch to new buffer - yy_switch_to_buffer(yy_create_buffer(driver.ifs, YY_BUF_SIZE)); + yy_switch_to_buffer(yy_create_buffer(input, YY_BUF_SIZE)); BEGIN(INITIAL); } -\"[^\r\n]*(\r)?\n { - yylloc->lines(1); - yylloc->step(); - *yyout << "@line \"" << *yylloc->begin.filename << "\" " - << yylloc->begin.line << endl; - BEGIN(INITIAL); - } - @ { BEGIN(MACRO); } - [ \t\r\f]+ { yylloc->step(); } @ { BEGIN(INITIAL); return token::EOL; } -\n { BEGIN(INITIAL); yylloc->lines(1); yylloc->step(); *yyout << endl; return token::EOL; } +\n { + yylloc->lines(1); + yylloc->step(); + if (reading_for_statement) + { + reading_for_statement = false; + for_body_tmp.erase(); + for_body_loc_tmp = *yylloc; + nested_for_nb = 0; + BEGIN(FOR_BODY); + } + else + BEGIN(INITIAL); + *yyout << endl; + return token::EOL; + } [0-9]+ { yylval->int_val = atoi(yytext); @@ -133,31 +143,68 @@ typedef Macro::parser::token token; line { return token::LINE; } define { return token::DEFINE; } +for { reading_for_statement = true; return token::FOR; } +in { return token::IN; } +endfor { driver.error(*yylloc, "@endfor is not matched by a @for statement"); } [A-Za-z_][A-Za-z0-9_]* { yylval->string_val = new string(yytext); return token::NAME; } +<> { driver.error(*yylloc, "Unexpected end of file while parsing a macro expression"); } -<> { +[\n]+ { yylloc->lines(yyleng); yylloc->step(); for_body_tmp.append(yytext); } +@for { nested_for_nb++; for_body_tmp.append(yytext); } +. { for_body_tmp.append(yytext); } +<> { driver.error(*yylloc, "Unexpected end of file: @for loop not matched by an @endfor"); } +@endfor[ \t]*(\r)?\n { + if (nested_for_nb) + { + nested_for_nb--; + for_body_tmp.append(yytext); + } + else + { + yylloc->lines(1); + yylloc->step(); + // Save old buffer state and location + context_stack.push(ScanContext(input, YY_CURRENT_BUFFER, *yylloc, for_body, for_body_loc)); + + for_body = for_body_tmp; + for_body_loc = for_body_loc_tmp; + + iter_loop(driver, yylloc); + + BEGIN(INITIAL); + } + } + +<> { // Quit lexer if end of main file - if (include_stack.empty()) + if (context_stack.empty()) { yyterminate(); } - // Else restore old flex buffer - /* We don't use yypop_buffer_state(), since it doesn't exist in - Flex 2.5.4 (see Flex 2.5.33 info file - section 11 - for code - example with yypop_buffer_state()) */ + // Else clean current scanning context yy_delete_buffer(YY_CURRENT_BUFFER); - yy_switch_to_buffer(include_stack.top().first); - // And restore old location + delete input; delete yylloc->begin.filename; - *yylloc = include_stack.top().second; - // Remove top of stack - include_stack.pop(); - BEGIN(END_INCLUDE); + + // If we are not in a loop body, or if the loop has terminated, pop a context + if (for_body.empty() || !iter_loop(driver, yylloc)) + { + // Restore old context + input = context_stack.top().input; + yy_switch_to_buffer(context_stack.top().buffer); + *yylloc = context_stack.top().yylloc; + for_body = context_stack.top().for_body; + for_body_loc = context_stack.top().for_body_loc; + // Remove top of stack + context_stack.pop(); + // Dump @line instruction + output_line(yylloc); + } } /* Ignore \r, because under Cygwin, outputting \n automatically adds another \r */ @@ -171,10 +218,32 @@ typedef Macro::parser::token token; %% MacroFlex::MacroFlex(istream* in, ostream* out) - : MacroFlexLexer(in, out) + : MacroFlexLexer(in, out), input(in), reading_for_statement(false) { } +void +MacroFlex::output_line(Macro::parser::location_type *yylloc) +{ + *yyout << endl << "@line \"" << *yylloc->begin.filename << "\" " + << yylloc->begin.line << endl; +} + +bool +MacroFlex::iter_loop(MacroDriver &driver, Macro::parser::location_type *yylloc) +{ + if (!driver.iter_loop()) + return false; + + input = new stringstream(for_body); + *yylloc = for_body_loc; + yylloc->begin.filename = yylloc->end.filename = new string(*for_body_loc.begin.filename); + output_line(yylloc); + yy_switch_to_buffer(yy_create_buffer(input, YY_BUF_SIZE)); + + return true; +} + /* This implementation of MacroFlexLexer::yylex() is required to fill the * vtable of the class MacroFlexLexer. We define the scanner's main yylex * function via YY_DECL to reside in the MacroFlex class instead. */ diff --git a/preprocessor/macro/MacroValue.cc b/preprocessor/macro/MacroValue.cc index d94659220..d3dcce6a7 100644 --- a/preprocessor/macro/MacroValue.cc +++ b/preprocessor/macro/MacroValue.cc @@ -17,109 +17,114 @@ * along with Dynare. If not, see . */ -#include "MacroValue.hh" +#include "MacroDriver.hh" + +MacroValue::MacroValue(MacroDriver &driver_arg) : driver(driver_arg) +{ + driver.values.insert(this); +} MacroValue::~MacroValue() { } -MacroValue * +const MacroValue * MacroValue::operator+() const throw (TypeError) { throw TypeError("Unary operator + does not exist for this type"); } -MacroValue * +const MacroValue * MacroValue::operator-(const MacroValue &mv) const throw (TypeError) { throw TypeError("Operator - does not exist for this type"); } -MacroValue * +const MacroValue * MacroValue::operator-() const throw (TypeError) { throw TypeError("Unary operator - does not exist for this type"); } -MacroValue * +const MacroValue * MacroValue::operator*(const MacroValue &mv) const throw (TypeError) { throw TypeError("Operator * does not exist for this type"); } -MacroValue * +const MacroValue * MacroValue::operator/(const MacroValue &mv) const throw (TypeError) { throw TypeError("Operator / does not exist for this type"); } -MacroValue * +const MacroValue * MacroValue::operator<(const MacroValue &mv) const throw (TypeError) { throw TypeError("Operator < does not exist for this type"); } -MacroValue * +const MacroValue * MacroValue::operator>(const MacroValue &mv) const throw (TypeError) { throw TypeError("Operator > does not exist for this type"); } -MacroValue * +const MacroValue * MacroValue::operator<=(const MacroValue &mv) const throw (TypeError) { throw TypeError("Operator <= does not exist for this type"); } -MacroValue * +const MacroValue * MacroValue::operator>=(const MacroValue &mv) const throw (TypeError) { throw TypeError("Operator >= does not exist for this type"); } -MacroValue * +const MacroValue * MacroValue::operator&&(const MacroValue &mv) const throw (TypeError) { throw TypeError("Operator && does not exist for this type"); } -MacroValue * +const MacroValue * MacroValue::operator||(const MacroValue &mv) const throw (TypeError) { throw TypeError("Operator || does not exist for this type"); } -MacroValue * +const MacroValue * MacroValue::operator!() const throw (TypeError) { throw TypeError("Operator ! does not exist for this type"); } -MacroValue * +const MacroValue * MacroValue::operator[](const MacroValue &mv) const throw (TypeError, OutOfBoundsError) { throw TypeError("Operator [] does not exist for this type"); } -MacroValue * -MacroValue::append(const MacroValue &mv) const throw (TypeError) +const MacroValue * +MacroValue::append(const MacroValue *mv) const throw (TypeError) { throw TypeError("Cannot append an array at the end of another one. Should use concatenation."); } -MacroValue * -MacroValue::new_base_value(int i) +const MacroValue * +MacroValue::new_base_value(MacroDriver &driver, int i) { - return new IntMV(i); + return new IntMV(driver, i); } -MacroValue * -MacroValue::new_base_value(const string &s) +const MacroValue * +MacroValue::new_base_value(MacroDriver &driver, const string &s) { - return new StringMV(s); + return new StringMV(driver, s); } -IntMV::IntMV(int value_arg) : value(value_arg) +IntMV::IntMV(MacroDriver &driver, int value_arg) : MacroValue(driver), value(value_arg) { } @@ -127,132 +132,132 @@ IntMV::~IntMV() { } -MacroValue * +const MacroValue * IntMV::operator+(const MacroValue &mv) const throw (TypeError) { const IntMV *mv2 = dynamic_cast(&mv); if (mv2 == NULL) throw TypeError("Type mismatch for operands of + operator"); - return new IntMV(value + mv2->value); + return new IntMV(driver, value + mv2->value); } -MacroValue * +const MacroValue * IntMV::operator+() const throw (TypeError) { - return clone(); + return this; } -MacroValue * +const MacroValue * IntMV::operator-(const MacroValue &mv) const throw (TypeError) { const IntMV *mv2 = dynamic_cast(&mv); if (mv2 == NULL) throw TypeError("Type mismatch for operands of - operator"); - return new IntMV(value - mv2->value); + return new IntMV(driver, value - mv2->value); } -MacroValue * +const MacroValue * IntMV::operator-() const throw (TypeError) { - return new IntMV(-value); + return new IntMV(driver, -value); } -MacroValue * +const MacroValue * IntMV::operator*(const MacroValue &mv) const throw (TypeError) { const IntMV *mv2 = dynamic_cast(&mv); if (mv2 == NULL) throw TypeError("Type mismatch for operands of * operator"); - return new IntMV(value * mv2->value); + return new IntMV(driver, value * mv2->value); } -MacroValue * +const MacroValue * IntMV::operator/(const MacroValue &mv) const throw (TypeError) { const IntMV *mv2 = dynamic_cast(&mv); if (mv2 == NULL) throw TypeError("Type mismatch for operands of / operator"); - return new IntMV(value / mv2->value); + return new IntMV(driver, value / mv2->value); } -MacroValue * +const MacroValue * IntMV::operator<(const MacroValue &mv) const throw (TypeError) { const IntMV *mv2 = dynamic_cast(&mv); if (mv2 == NULL) throw TypeError("Type mismatch for operands of < operator"); - return new IntMV(value < mv2->value); + return new IntMV(driver, value < mv2->value); } -MacroValue * +const MacroValue * IntMV::operator>(const MacroValue &mv) const throw (TypeError) { const IntMV *mv2 = dynamic_cast(&mv); if (mv2 == NULL) throw TypeError("Type mismatch for operands of > operator"); - return new IntMV(value > mv2->value); + return new IntMV(driver, value > mv2->value); } -MacroValue * +const MacroValue * IntMV::operator<=(const MacroValue &mv) const throw (TypeError) { const IntMV *mv2 = dynamic_cast(&mv); if (mv2 == NULL) throw TypeError("Type mismatch for operands of <= operator"); - return new IntMV(value <= mv2->value); + return new IntMV(driver, value <= mv2->value); } -MacroValue * +const MacroValue * IntMV::operator>=(const MacroValue &mv) const throw (TypeError) { const IntMV *mv2 = dynamic_cast(&mv); if (mv2 == NULL) throw TypeError("Type mismatch for operands of >= operator"); - return new IntMV(value >= mv2->value); + return new IntMV(driver, value >= mv2->value); } -MacroValue * +const MacroValue * IntMV::operator==(const MacroValue &mv) const throw (TypeError) { const IntMV *mv2 = dynamic_cast(&mv); if (mv2 == NULL) - return new IntMV(0); + return new IntMV(driver, 0); else - return new IntMV(value == mv2->value); + return new IntMV(driver, value == mv2->value); } -MacroValue * +const MacroValue * IntMV::operator!=(const MacroValue &mv) const throw (TypeError) { const IntMV *mv2 = dynamic_cast(&mv); if (mv2 == NULL) - return new IntMV(1); + return new IntMV(driver, 1); else - return new IntMV(value != mv2->value); + return new IntMV(driver, value != mv2->value); } -MacroValue * +const MacroValue * IntMV::operator&&(const MacroValue &mv) const throw (TypeError) { const IntMV *mv2 = dynamic_cast(&mv); if (mv2 == NULL) throw TypeError("Type mismatch for operands of && operator"); - return new IntMV(value && mv2->value); + return new IntMV(driver, value && mv2->value); } -MacroValue * +const MacroValue * IntMV::operator||(const MacroValue &mv) const throw (TypeError) { const IntMV *mv2 = dynamic_cast(&mv); if (mv2 == NULL) throw TypeError("Type mismatch for operands of || operator"); - return new IntMV(value || mv2->value); + return new IntMV(driver, value || mv2->value); } -MacroValue * +const MacroValue * IntMV::operator!() const throw (TypeError) { - return new IntMV(!value); + return new IntMV(driver, !value); } string @@ -263,37 +268,31 @@ IntMV::toString() const return ss.str(); } -MacroValue * -IntMV::clone() const -{ - return new IntMV(value); -} - -MacroValue * +const MacroValue * IntMV::toArray() const { vector v; v.push_back(value); - return new ArrayMV(v); + return new ArrayMV(driver, v); } -MacroValue * -IntMV::append(const MacroValue &array) const throw (TypeError) +const MacroValue * +IntMV::append(const MacroValue *array) const throw (TypeError) { - const ArrayMV *array2 = dynamic_cast *>(&array); + const ArrayMV *array2 = dynamic_cast *>(array); if (array2 == NULL) throw TypeError("Type mismatch for append operation"); vector v(array2->values); v.push_back(value); - return new ArrayMV(v); + return new ArrayMV(driver, v); } -MacroValue * -IntMV::new_range(const MacroValue &mv1, const MacroValue &mv2) throw (TypeError) +const MacroValue * +IntMV::new_range(MacroDriver &driver, const MacroValue *mv1, const MacroValue *mv2) throw (TypeError) { - const IntMV *mv1i = dynamic_cast(&mv1); - const IntMV *mv2i = dynamic_cast(&mv2); + const IntMV *mv1i = dynamic_cast(mv1); + const IntMV *mv2i = dynamic_cast(mv2); if (mv1i == NULL || mv2i == NULL) throw TypeError("Arguments of range operator (:) must be integers"); @@ -309,10 +308,11 @@ IntMV::new_range(const MacroValue &mv1, const MacroValue &mv2) throw (TypeError) } for(; v1 <= v2; v1++) result.push_back(v1); - return new ArrayMV(result); + return new ArrayMV(driver, result); } -StringMV::StringMV(const string &value_arg) : value(value_arg) +StringMV::StringMV(MacroDriver &driver, const string &value_arg) + : MacroValue(driver), value(value_arg) { } @@ -320,36 +320,36 @@ StringMV::~StringMV() { } -MacroValue * +const MacroValue * StringMV::operator+(const MacroValue &mv) const throw (TypeError) { const StringMV *mv2 = dynamic_cast(&mv); if (mv2 == NULL) throw TypeError("Type mismatch for operands of + operator"); - return new StringMV(value + mv2->value); + return new StringMV(driver, value + mv2->value); } -MacroValue * +const MacroValue * StringMV::operator==(const MacroValue &mv) const throw (TypeError) { const StringMV *mv2 = dynamic_cast(&mv); if (mv2 == NULL) - return new IntMV(0); + return new IntMV(driver, 0); else - return new IntMV(value == mv2->value); + return new IntMV(driver, value == mv2->value); } -MacroValue * +const MacroValue * StringMV::operator!=(const MacroValue &mv) const throw (TypeError) { const StringMV *mv2 = dynamic_cast(&mv); if (mv2 == NULL) - return new IntMV(1); + return new IntMV(driver, 1); else - return new IntMV(value != mv2->value); + return new IntMV(driver, value != mv2->value); } -MacroValue * +const MacroValue * StringMV::operator[](const MacroValue &mv) const throw (TypeError, OutOfBoundsError) { const ArrayMV *mv2 = dynamic_cast *>(&mv); @@ -364,7 +364,7 @@ StringMV::operator[](const MacroValue &mv) const throw (TypeError, OutOfBoundsEr char c = value.at(*it - 1); result.append(&c); } - return new StringMV(result); + return new StringMV(driver, result); } string @@ -373,28 +373,22 @@ StringMV::toString() const return value; } -MacroValue * -StringMV::clone() const -{ - return new StringMV(value); -} - -MacroValue * +const MacroValue * StringMV::toArray() const { vector v; v.push_back(value); - return new ArrayMV(v); + return new ArrayMV(driver, v); } -MacroValue * -StringMV::append(const MacroValue &array) const throw (TypeError) +const MacroValue * +StringMV::append(const MacroValue *array) const throw (TypeError) { - const ArrayMV *array2 = dynamic_cast *>(&array); + const ArrayMV *array2 = dynamic_cast *>(array); if (array2 == NULL) throw TypeError("Type mismatch for append operation"); vector v(array2->values); v.push_back(value); - return new ArrayMV(v); + return new ArrayMV(driver, v); } diff --git a/preprocessor/macro/MacroValue.hh b/preprocessor/macro/MacroValue.hh index 82e730890..2ecf2572b 100644 --- a/preprocessor/macro/MacroValue.hh +++ b/preprocessor/macro/MacroValue.hh @@ -26,9 +26,14 @@ using namespace std; #include #include +class MacroDriver; + //! Base class for representing values in macro language class MacroValue { +protected: + //! Reference to enclosing MacroDriver + MacroDriver &driver; public: //! Exception thrown when type error occurs in macro language class TypeError @@ -41,72 +46,59 @@ public: class OutOfBoundsError { }; + MacroValue(MacroDriver &driver_arg); virtual ~MacroValue(); //! Applies + operator - /*! Returns a newly allocated value */ - virtual MacroValue *operator+(const MacroValue &mv) const throw (TypeError) = 0; + virtual const MacroValue *operator+(const MacroValue &mv) const throw (TypeError) = 0; //! Applies unary + operator - /*! Returns a newly allocated value */ - virtual MacroValue *operator+() const throw (TypeError); + virtual const MacroValue *operator+() const throw (TypeError); //! Applies - operator - /*! Returns a newly allocated value */ - virtual MacroValue *operator-(const MacroValue &mv) const throw (TypeError); + virtual const MacroValue *operator-(const MacroValue &mv) const throw (TypeError); //! Applies unary - operator - /*! Returns a newly allocated value */ - virtual MacroValue *operator-() const throw (TypeError); + virtual const MacroValue *operator-() const throw (TypeError); //! Applies * operator - /*! Returns a newly allocated value */ - virtual MacroValue *operator*(const MacroValue &mv) const throw (TypeError); + virtual const MacroValue *operator*(const MacroValue &mv) const throw (TypeError); //! Applies / operator - /*! Returns a newly allocated value */ - virtual MacroValue *operator/(const MacroValue &mv) const throw (TypeError); + virtual const MacroValue *operator/(const MacroValue &mv) const throw (TypeError); //! Less comparison - /*! Returns a newly allocated IntMV, equal to 0 or 1 */ - virtual MacroValue *operator<(const MacroValue &mv) const throw (TypeError); + /*! Returns an IntMV, equal to 0 or 1 */ + virtual const MacroValue *operator<(const MacroValue &mv) const throw (TypeError); //! Greater comparision - /*! Returns a newly allocated IntMV, equal to 0 or 1 */ - virtual MacroValue *operator>(const MacroValue &mv) const throw (TypeError); + /*! Returns an IntMV, equal to 0 or 1 */ + virtual const MacroValue *operator>(const MacroValue &mv) const throw (TypeError); //! Less or equal comparison - /*! Returns a newly allocated IntMV, equal to 0 or 1 */ - virtual MacroValue *operator<=(const MacroValue &mv) const throw (TypeError); + /*! Returns an IntMV, equal to 0 or 1 */ + virtual const MacroValue *operator<=(const MacroValue &mv) const throw (TypeError); //! Greater or equal comparison - /*! Returns a newly allocated IntMV, equal to 0 or 1 */ - virtual MacroValue *operator>=(const MacroValue &mv) const throw (TypeError); + /*! Returns an IntMV, equal to 0 or 1 */ + virtual const MacroValue *operator>=(const MacroValue &mv) const throw (TypeError); //! Equal comparison - /*! Returns a newly allocated IntMV, equal to 0 or 1 */ - virtual MacroValue *operator==(const MacroValue &mv) const throw (TypeError) = 0; + /*! Returns an IntMV, equal to 0 or 1 */ + virtual const MacroValue *operator==(const MacroValue &mv) const throw (TypeError) = 0; //! Not equal comparison - /*! Returns a newly allocated IntMV, equal to 0 or 1 */ - virtual MacroValue *operator!=(const MacroValue &mv) const throw (TypeError) = 0; + /*! Returns an IntMV, equal to 0 or 1 */ + virtual const MacroValue *operator!=(const MacroValue &mv) const throw (TypeError) = 0; //! Applies && operator - /*! Returns a newly allocated value */ - virtual MacroValue *operator&&(const MacroValue &mv) const throw (TypeError); + virtual const MacroValue *operator&&(const MacroValue &mv) const throw (TypeError); //! Applies || operator - /*! Returns a newly allocated value */ - virtual MacroValue *operator||(const MacroValue &mv) const throw (TypeError); + virtual const MacroValue *operator||(const MacroValue &mv) const throw (TypeError); //! Applies unary ! operator - /*! Returns a newly allocated value */ - virtual MacroValue *operator!() const throw (TypeError); + virtual const MacroValue *operator!() const throw (TypeError); //! Applies [] operator - /*! Returns a newly allocated value */ - virtual MacroValue *operator[](const MacroValue &mv) const throw (TypeError, OutOfBoundsError); + virtual const MacroValue *operator[](const MacroValue &mv) const throw (TypeError, OutOfBoundsError); //! Converts value to string virtual string toString() const = 0; - //! Clones value - /*! Returns a newly allocated value */ - virtual MacroValue *clone() const = 0; //! Converts value to array form - /*! Returns a newly allocated array value */ - virtual MacroValue *toArray() const = 0; + virtual const MacroValue *toArray() const = 0; //! Appends value at the end of an array - /*! The first argument must be an array. Returns a newly allocated array. */ - virtual MacroValue *append(const MacroValue &array) const throw (TypeError); + /*! The first argument must be an array. */ + virtual const MacroValue *append(const MacroValue *array) const throw (TypeError); //! Returns a new IntMV /*! Necessary for ArrayMV::operator[] (template issue) */ - static MacroValue *new_base_value(int i); + static const MacroValue *new_base_value(MacroDriver &driver, int i); //! Returns a new StringMV /*! Necessary for ArrayMV::operator[] (template issue) */ - static MacroValue *new_base_value(const string &s); + static const MacroValue *new_base_value(MacroDriver &driver, const string &s); }; //! Represents an integer value in macro language @@ -115,57 +107,48 @@ class IntMV : public MacroValue friend class StringMV; private: //! Underlying integer value - int value; + const int value; public: - IntMV(int value_arg); + IntMV(MacroDriver &driver, int value_arg); virtual ~IntMV(); //! Computes arithmetic addition - /*! Returns a newly allocated value */ - virtual MacroValue *operator+(const MacroValue &mv) const throw (TypeError); + virtual const MacroValue *operator+(const MacroValue &mv) const throw (TypeError); //! Unary plus - /*! Returns a clone of itself */ - virtual MacroValue *operator+() const throw (TypeError); + /*! Returns itself */ + virtual const MacroValue *operator+() const throw (TypeError); //! Computes arithmetic substraction - /*! Returns a newly allocated value */ - virtual MacroValue *operator-(const MacroValue &mv) const throw (TypeError); + virtual const MacroValue *operator-(const MacroValue &mv) const throw (TypeError); //! Computes opposite - /*! Returns a newly allocated value */ - virtual MacroValue *operator-() const throw (TypeError); + virtual const MacroValue *operator-() const throw (TypeError); //! Computes arithmetic multiplication - /*! Returns a newly allocated value */ - virtual MacroValue *operator*(const MacroValue &mv) const throw (TypeError); + virtual const MacroValue *operator*(const MacroValue &mv) const throw (TypeError); //! Computes arithmetic division - /*! Returns a newly allocated value */ - virtual MacroValue *operator/(const MacroValue &mv) const throw (TypeError); - virtual MacroValue *operator<(const MacroValue &mv) const throw (TypeError); - virtual MacroValue *operator>(const MacroValue &mv) const throw (TypeError); - virtual MacroValue *operator<=(const MacroValue &mv) const throw (TypeError); - virtual MacroValue *operator>=(const MacroValue &mv) const throw (TypeError); - virtual MacroValue *operator==(const MacroValue &mv) const throw (TypeError); - virtual MacroValue *operator!=(const MacroValue &mv) const throw (TypeError); + virtual const MacroValue *operator/(const MacroValue &mv) const throw (TypeError); + virtual const MacroValue *operator<(const MacroValue &mv) const throw (TypeError); + virtual const MacroValue *operator>(const MacroValue &mv) const throw (TypeError); + virtual const MacroValue *operator<=(const MacroValue &mv) const throw (TypeError); + virtual const MacroValue *operator>=(const MacroValue &mv) const throw (TypeError); + virtual const MacroValue *operator==(const MacroValue &mv) const throw (TypeError); + virtual const MacroValue *operator!=(const MacroValue &mv) const throw (TypeError); //! Computes logical and - /*! Returns a newly allocated value */ - virtual MacroValue *operator&&(const MacroValue &mv) const throw (TypeError); + virtual const MacroValue *operator&&(const MacroValue &mv) const throw (TypeError); //! Computes logical or - /*! Returns a newly allocated value */ - virtual MacroValue *operator||(const MacroValue &mv) const throw (TypeError); + virtual const MacroValue *operator||(const MacroValue &mv) const throw (TypeError); //! Computes logical negation - /*! Returns a newly allocated value */ - virtual MacroValue *operator!() const throw (TypeError); + virtual const MacroValue *operator!() const throw (TypeError); virtual string toString() const; - virtual MacroValue *clone() const; //! Converts value to array form - /*! Returns a newly allocated integer array containing a single value */ - virtual MacroValue *toArray() const; + /*! Returns an integer array containing a single value */ + virtual const MacroValue *toArray() const; //! Appends value at the end of an array - /*! The first argument must be an integer array. Returns a newly allocated integer array. */ - virtual MacroValue *append(const MacroValue &array) const throw (TypeError); + /*! The first argument must be an integer array. */ + virtual const MacroValue *append(const MacroValue *array) const throw (TypeError); //! Creates a integer range /*! Arguments must be of type IntMV. - Returns a newly allocated integer array containing all integers between mv1 and mv2. + Returns an integer array containing all integers between mv1 and mv2. If mv2 < mv1, constructs the range in decreasing order. */ - static MacroValue *new_range(const MacroValue &mv1, const MacroValue &mv2) throw (TypeError); + static const MacroValue *new_range(MacroDriver &driver, const MacroValue *mv1, const MacroValue *mv2) throw (TypeError); }; //! Represents a string value in macro language @@ -173,28 +156,25 @@ class StringMV : public MacroValue { private: //! Underlying string value - string value; + const string value; public: - StringMV(const string &value_arg); + StringMV(MacroDriver &driver, const string &value_arg); virtual ~StringMV(); //! Computes string concatenation - /*! Returns a newly allocated value */ - virtual MacroValue *operator+(const MacroValue &mv) const throw (TypeError); - virtual MacroValue *operator==(const MacroValue &mv) const throw (TypeError); - virtual MacroValue *operator!=(const MacroValue &mv) const throw (TypeError); + virtual const MacroValue *operator+(const MacroValue &mv) const throw (TypeError); + virtual const MacroValue *operator==(const MacroValue &mv) const throw (TypeError); + virtual const MacroValue *operator!=(const MacroValue &mv) const throw (TypeError); //! Subscripting operator - /*! Argument must be an ArrayMV. Indexes begin at 1. - Returns a newly allocated string. */ - virtual MacroValue *operator[](const MacroValue &mv) const throw (TypeError, OutOfBoundsError); + /*! Argument must be an ArrayMV. Indexes begin at 1. Returns a StringMV. */ + virtual const MacroValue *operator[](const MacroValue &mv) const throw (TypeError, OutOfBoundsError); //! Returns underlying string value virtual string toString() const; - virtual MacroValue *clone() const; //! Converts value to array form - /*! Returns a newly allocated string array containing a single value */ - virtual MacroValue *toArray() const; + /*! Returns a string array containing a single value */ + virtual const MacroValue *toArray() const; //! Appends value at the end of an array - /*! The first argument must be a string array. Returns a newly allocated string array. */ - virtual MacroValue *append(const MacroValue &array) const throw (TypeError); + /*! The first argument must be a string array. Returns a string array. */ + virtual const MacroValue *append(const MacroValue *array) const throw (TypeError); }; //! Represents an array in macro language @@ -205,32 +185,31 @@ class ArrayMV : public MacroValue friend class IntMV; friend class StringMV; friend class ArrayMV; // Necessary for operator[] to access values of integer array when subscripting a string array + friend class MacroDriver; private: //! Underlying vector - vector values; + const vector values; public: - ArrayMV(const vector &values_arg); + ArrayMV(MacroDriver &driver, const vector &values_arg); virtual ~ArrayMV(); //! Computes array concatenation - /*! Both array must be of same type - Returns a newly allocated array */ - virtual MacroValue *operator+(const MacroValue &mv) const throw (TypeError); - virtual MacroValue *operator==(const MacroValue &mv) const throw (TypeError); - virtual MacroValue *operator!=(const MacroValue &mv) const throw (TypeError); + /*! Both array must be of same type */ + virtual const MacroValue *operator+(const MacroValue &mv) const throw (TypeError); + virtual const MacroValue *operator==(const MacroValue &mv) const throw (TypeError); + virtual const MacroValue *operator!=(const MacroValue &mv) const throw (TypeError); //! Subscripting operator /*! Argument must be an ArrayMV. Indexes begin at 1. - If argument is a one-element array, returns a newly-allocated IntMV or String. - Otherwise returns a newly allocated array. */ - virtual MacroValue *operator[](const MacroValue &mv) const throw (TypeError, OutOfBoundsError); + If argument is a one-element array, returns an IntMV or StringMV. + Otherwise returns an array. */ + virtual const MacroValue *operator[](const MacroValue &mv) const throw (TypeError, OutOfBoundsError); //! Returns a string containing the concatenation of string representations of elements virtual string toString() const; - virtual MacroValue *clone() const; - //! Returns a clone of itself - virtual MacroValue *toArray() const; + //! Returns itself + virtual const MacroValue *toArray() const; }; template -ArrayMV::ArrayMV(const vector &values_arg) : values(values_arg) +ArrayMV::ArrayMV(MacroDriver &driver, const vector &values_arg) : MacroValue(driver), values(values_arg) { if (values.size() == 0) throw "Empty arrays forbidden"; @@ -242,7 +221,7 @@ ArrayMV::~ArrayMV() } template -MacroValue * +const MacroValue * ArrayMV::operator+(const MacroValue &mv) const throw (TypeError) { const ArrayMV *mv2 = dynamic_cast *>(&mv); @@ -251,33 +230,33 @@ ArrayMV::operator+(const MacroValue &mv) const throw (TypeError) vector values_copy(values); values_copy.insert(values_copy.end(), mv2->values.begin(), mv2->values.end()); - return new ArrayMV(values_copy); + return new ArrayMV(driver, values_copy); } template -MacroValue * +const MacroValue * ArrayMV::operator==(const MacroValue &mv) const throw (TypeError) { const ArrayMV *mv2 = dynamic_cast *>(&mv); if (mv2 == NULL) - return new IntMV(0); + return new IntMV(driver, 0); else - return new IntMV(values == mv2->values); + return new IntMV(driver, values == mv2->values); } template -MacroValue * +const MacroValue * ArrayMV::operator!=(const MacroValue &mv) const throw (TypeError) { const ArrayMV *mv2 = dynamic_cast *>(&mv); if (mv2 == NULL) - return new IntMV(1); + return new IntMV(driver, 1); else - return new IntMV(values != mv2->values); + return new IntMV(driver, values != mv2->values); } template -MacroValue * +const MacroValue * ArrayMV::operator[](const MacroValue &mv) const throw (TypeError, OutOfBoundsError) { const ArrayMV *mv2 = dynamic_cast *>(&mv); @@ -293,9 +272,9 @@ ArrayMV::operator[](const MacroValue &mv) const throw (TypeError, OutOfBounds } if (result.size() > 1) - return new ArrayMV(result); + return new ArrayMV(driver, result); else - return MacroValue::new_base_value(result[0]); + return MacroValue::new_base_value(driver, result[0]); } template @@ -310,17 +289,10 @@ ArrayMV::toString() const } template -MacroValue * -ArrayMV::clone() const -{ - return new ArrayMV(values); -} - -template -MacroValue * +const MacroValue * ArrayMV::toArray() const { - return clone(); + return this; } #endif