macroprocessor: allow looping over tuples. #5
parent
ca066ea398
commit
719630a53c
|
@ -82,7 +82,7 @@ class MacroDriver;
|
||||||
%precedence UMINUS UPLUS EXCLAMATION
|
%precedence UMINUS UPLUS EXCLAMATION
|
||||||
%precedence LBRACKET
|
%precedence LBRACKET
|
||||||
|
|
||||||
%type <vector<string>> func_args
|
%type <vector<string>> comma_name
|
||||||
%type <MacroValuePtr> expr
|
%type <MacroValuePtr> expr
|
||||||
%type <vector<MacroValuePtr>> comma_expr tuple_comma_expr
|
%type <vector<MacroValuePtr>> comma_expr tuple_comma_expr
|
||||||
%%
|
%%
|
||||||
|
@ -103,6 +103,8 @@ statement : expr
|
||||||
{ driver.set_variable($2, $4); }
|
{ driver.set_variable($2, $4); }
|
||||||
| FOR NAME IN expr
|
| FOR NAME IN expr
|
||||||
{ TYPERR_CATCH(driver.init_loop($2, $4), @$); }
|
{ TYPERR_CATCH(driver.init_loop($2, $4), @$); }
|
||||||
|
| FOR LPAREN comma_name RPAREN IN expr
|
||||||
|
{ TYPERR_CATCH(driver.init_loop($3, $6), @$); }
|
||||||
| IF expr
|
| IF expr
|
||||||
{ TYPERR_CATCH(driver.begin_if($2), @$); }
|
{ TYPERR_CATCH(driver.begin_if($2), @$); }
|
||||||
| IFDEF NAME
|
| IFDEF NAME
|
||||||
|
@ -119,18 +121,18 @@ statement : expr
|
||||||
{ driver.printvars(@$, true); }
|
{ driver.printvars(@$, true); }
|
||||||
| ECHOMACROVARS LPAREN SAVE RPAREN
|
| ECHOMACROVARS LPAREN SAVE RPAREN
|
||||||
{ out << driver.printvars(@$, false); }
|
{ 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), @$);
|
TYPERR_CATCH(driver.set_string_function($2, $4, $8), @$);
|
||||||
driver.pop_func_env();
|
driver.pop_func_env();
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
func_args : NAME
|
comma_name : NAME
|
||||||
{ $$ = vector<string>{$1}; }
|
{ $$ = vector<string>{$1}; }
|
||||||
| func_args COMMA NAME
|
| comma_name COMMA NAME
|
||||||
{ $1.push_back($3); $$ = $1; }
|
{ $1.push_back($3); $$ = $1; }
|
||||||
;
|
;
|
||||||
|
|
||||||
expr : INTEGER
|
expr : INTEGER
|
||||||
{ $$ = make_shared<IntMV>($1); }
|
{ $$ = 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);
|
auto mv = dynamic_pointer_cast<ArrayMV>(value);
|
||||||
if (!mv)
|
if (!mv)
|
||||||
throw MacroValue::TypeError("Argument of @#for loop must be an array expression");
|
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
|
bool
|
||||||
MacroDriver::iter_loop()
|
MacroDriver::iter_loop() noexcept(false)
|
||||||
{
|
{
|
||||||
if (loop_stack.empty())
|
if (loop_stack.empty())
|
||||||
throw "No loop on which to iterate!";
|
throw "No loop on which to iterate!";
|
||||||
|
|
||||||
int &i = get<2>(loop_stack.top());
|
int &i = get<2>(loop_stack.top());
|
||||||
auto mv = get<1>(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()))
|
if (i >= static_cast<int>(mv->values.size()))
|
||||||
{
|
{
|
||||||
|
@ -225,7 +235,27 @@ MacroDriver::iter_loop()
|
||||||
}
|
}
|
||||||
else
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -165,8 +165,10 @@ private:
|
||||||
vector<env_t> func_env;
|
vector<env_t> func_env;
|
||||||
|
|
||||||
//! Stack used to keep track of (possibly nested) loops
|
//! 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) */
|
//! First element is loop variable name
|
||||||
stack<tuple<string, shared_ptr<ArrayMV>, int>> loop_stack;
|
//! 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:
|
public:
|
||||||
//! Exception thrown when value of an unknown variable is requested
|
//! Exception thrown when value of an unknown variable is requested
|
||||||
class UnknownVariable
|
class UnknownVariable
|
||||||
|
@ -229,10 +231,13 @@ public:
|
||||||
//! Initiate a for loop
|
//! Initiate a for loop
|
||||||
/*! Does not set name = value[1]. You must call iter_loop() for that. */
|
/*! Does not set name = value[1]. You must call iter_loop() for that. */
|
||||||
void init_loop(const string &name, MacroValuePtr value) noexcept(false);
|
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
|
//! 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() */
|
/*! Returns false if iteration is no more possible (end of loop);
|
||||||
bool iter_loop();
|
in that case it destroys the pointer given to init_loop() */
|
||||||
|
bool iter_loop() noexcept(false);
|
||||||
|
|
||||||
//! Begins an @#if statement
|
//! Begins an @#if statement
|
||||||
void begin_if(const MacroValuePtr &value) noexcept(false);
|
void begin_if(const MacroValuePtr &value) noexcept(false);
|
||||||
|
|
Loading…
Reference in New Issue