macroprocessor: allow looping over tuples. #5
parent
ca066ea398
commit
719630a53c
|
@ -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,16 +121,16 @@ 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
|
||||
comma_name : NAME
|
||||
{ $$ = vector<string>{$1}; }
|
||||
| func_args COMMA NAME
|
||||
| comma_name COMMA NAME
|
||||
{ $1.push_back($3); $$ = $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);
|
||||
|
|
Loading…
Reference in New Issue