Commit 719630a5 authored by Houtan Bastani's avatar Houtan Bastani

macroprocessor: allow looping over tuples. #5

parent ca066ea3
......@@ -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); }
......
......@@ -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;
}
}
......
......@@ -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);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment