diff --git a/src/macro/MacroBison.yy b/src/macro/MacroBison.yy index 868379b84e954b03fc34cf33bcbf6680ad742436..14f62226fb56c84f3f92eea908e0eb51263a4a5a 100644 --- a/src/macro/MacroBison.yy +++ b/src/macro/MacroBison.yy @@ -82,7 +82,7 @@ class MacroDriver; %precedence UMINUS UPLUS EXCLAMATION %precedence LBRACKET -%type <vector<string>> func_args +%type <vector<string>> comma_name %type <MacroValuePtr> expr %type <vector<MacroValuePtr>> comma_expr tuple_comma_expr %% @@ -103,6 +103,8 @@ statement : expr { driver.set_variable($2, $4); } | FOR NAME IN expr { TYPERR_CATCH(driver.init_loop($2, $4), @$); } + | FOR LPAREN comma_name RPAREN IN expr + { TYPERR_CATCH(driver.init_loop($3, $6), @$); } | IF expr { TYPERR_CATCH(driver.begin_if($2), @$); } | IFDEF NAME @@ -119,18 +121,18 @@ statement : expr { driver.printvars(@$, true); } | ECHOMACROVARS LPAREN SAVE RPAREN { out << driver.printvars(@$, false); } - | DEFINE NAME LPAREN func_args { driver.push_args_into_func_env($4); } RPAREN EQUAL expr + | DEFINE NAME LPAREN comma_name { driver.push_args_into_func_env($4); } RPAREN EQUAL expr { TYPERR_CATCH(driver.set_string_function($2, $4, $8), @$); driver.pop_func_env(); } ; -func_args : NAME - { $$ = vector<string>{$1}; } - | func_args COMMA NAME - { $1.push_back($3); $$ = $1; } - ; +comma_name : NAME + { $$ = vector<string>{$1}; } + | comma_name COMMA NAME + { $1.push_back($3); $$ = $1; } + ; expr : INTEGER { $$ = make_shared<IntMV>($1); } diff --git a/src/macro/MacroDriver.cc b/src/macro/MacroDriver.cc index 61f412c9431f818f3c5f1290da7ce13acf2e4667..0798ba5d21a341cf03be6c97ca59e042cec6cd03 100644 --- a/src/macro/MacroDriver.cc +++ b/src/macro/MacroDriver.cc @@ -205,18 +205,28 @@ MacroDriver::init_loop(const string &name, MacroValuePtr value) noexcept(false) auto mv = dynamic_pointer_cast<ArrayMV>(value); if (!mv) throw MacroValue::TypeError("Argument of @#for loop must be an array expression"); - loop_stack.emplace(name, move(mv), 0); + loop_stack.emplace(vector<string> {name}, move(mv), 0); } +void +MacroDriver::init_loop(const vector<string> &names, MacroValuePtr value) noexcept(false) +{ + auto mv = dynamic_pointer_cast<ArrayMV>(value); + if (!mv) + throw MacroValue::TypeError("Argument of @#for loop must be an array expression"); + loop_stack.emplace(names, move(mv), 0); +} + + bool -MacroDriver::iter_loop() +MacroDriver::iter_loop() noexcept(false) { if (loop_stack.empty()) throw "No loop on which to iterate!"; int &i = get<2>(loop_stack.top()); auto mv = get<1>(loop_stack.top()); - string &name = get<0>(loop_stack.top()); + vector<string> &names = get<0>(loop_stack.top()); if (i >= static_cast<int>(mv->values.size())) { @@ -225,7 +235,27 @@ MacroDriver::iter_loop() } else { - env[name] = mv->values[i++]; + if (names.size() == 1) + env[names.at(0)] = mv->values[i++]; + else + { + auto tmv = dynamic_pointer_cast<TupleMV>(mv->values[i++]); + if (!tmv) + throw MacroValue::TypeError("Argument of @#for loop must be an array expression of tuples"); + if (tmv->values.size() != names.size()) + { + cerr << "Error in for loop: tuple in array contains " << tmv->length() + << " elements while you are assigning to " << names.size() << " variables." + << endl; + exit(EXIT_FAILURE); + } + + for (auto &name: names) + { + auto idx = &name - &names[0]; + env[name] = tmv->values.at(idx); + } + } return true; } } diff --git a/src/macro/MacroDriver.hh b/src/macro/MacroDriver.hh index db05b06ee451925968dd4c4745f7984c4e518b0c..17d3411bae44618b37495953e01dae16f388dfb5 100644 --- a/src/macro/MacroDriver.hh +++ b/src/macro/MacroDriver.hh @@ -165,8 +165,10 @@ private: vector<env_t> func_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<tuple<string, shared_ptr<ArrayMV>, int>> loop_stack; + //! First element is loop variable name + //! Second is the array over which iteration is done + //! Third is subscript to be used by next call of iter_loop() (beginning with 0) */ + stack<tuple<vector<string>, shared_ptr<ArrayMV>, int>> loop_stack; public: //! Exception thrown when value of an unknown variable is requested class UnknownVariable @@ -229,10 +231,13 @@ public: //! Initiate a for loop /*! Does not set name = value[1]. You must call iter_loop() for that. */ void init_loop(const string &name, MacroValuePtr value) noexcept(false); + /*! Same as above but for looping over tuple array */ + void init_loop(const vector<string> &names, MacroValuePtr value) noexcept(false); //! 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(); + /*! 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() noexcept(false); //! Begins an @#if statement void begin_if(const MacroValuePtr &value) noexcept(false);