From 719630a53c5bff534078b3df4610bc6dede0d03c Mon Sep 17 00:00:00 2001 From: Houtan Bastani Date: Wed, 8 Aug 2018 17:17:35 +0200 Subject: [PATCH] macroprocessor: allow looping over tuples. #5 --- src/macro/MacroBison.yy | 16 +++++++++------- src/macro/MacroDriver.cc | 38 ++++++++++++++++++++++++++++++++++---- src/macro/MacroDriver.hh | 13 +++++++++---- 3 files changed, 52 insertions(+), 15 deletions(-) diff --git a/src/macro/MacroBison.yy b/src/macro/MacroBison.yy index 868379b8..14f62226 100644 --- a/src/macro/MacroBison.yy +++ b/src/macro/MacroBison.yy @@ -82,7 +82,7 @@ class MacroDriver; %precedence UMINUS UPLUS EXCLAMATION %precedence LBRACKET -%type > func_args +%type > comma_name %type expr %type > 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{$1}; } - | func_args COMMA NAME - { $1.push_back($3); $$ = $1; } - ; +comma_name : NAME + { $$ = vector{$1}; } + | comma_name COMMA NAME + { $1.push_back($3); $$ = $1; } + ; expr : INTEGER { $$ = make_shared($1); } diff --git a/src/macro/MacroDriver.cc b/src/macro/MacroDriver.cc index 61f412c9..0798ba5d 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(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 {name}, move(mv), 0); } +void +MacroDriver::init_loop(const vector &names, MacroValuePtr value) noexcept(false) +{ + auto mv = dynamic_pointer_cast(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 &names = get<0>(loop_stack.top()); if (i >= static_cast(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(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 db05b06e..17d3411b 100644 --- a/src/macro/MacroDriver.hh +++ b/src/macro/MacroDriver.hh @@ -165,8 +165,10 @@ private: vector 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, 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, shared_ptr, 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 &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);