Simple implementation of tail-recursion elimination.

master
Torsten Paul 2014-11-26 22:53:10 +01:00
parent 2e8d93d5be
commit a820487032
5 changed files with 78 additions and 4 deletions

View File

@ -121,6 +121,13 @@ void Context::set_constant(const std::string &name, const Value &value)
set_constant(name, ValuePtr(value));
}
void Context::apply_variables(const Context &other)
{
for (ValueMap::const_iterator it = other.variables.begin();it != other.variables.end();it++) {
set_variable((*it).first, (*it).second);
}
}
ValuePtr Context::lookup_variable(const std::string &name, bool silent) const
{
if (!this->ctx_stack) {

View File

@ -26,6 +26,7 @@ public:
void set_constant(const std::string &name, const ValuePtr &value);
void set_constant(const std::string &name, const Value &value);
void apply_variables(const Context &other);
ValuePtr lookup_variable(const std::string &name, bool silent = false) const;
bool has_local_variable(const std::string &name) const;

View File

@ -84,6 +84,11 @@ std::string AbstractFunction::dump(const std::string &indent, const std::string
return dump.str();
}
Function::Function(const char *name, AssignmentList &definition_arguments, Expression *expr)
: name(name), definition_arguments(definition_arguments), expr(expr)
{
}
Function::~Function()
{
delete expr;
@ -113,6 +118,66 @@ std::string Function::dump(const std::string &indent, const std::string &name) c
return dump.str();
}
class FunctionTailRecursion : public Function
{
private:
bool invert;
ExpressionFunctionCall *call; // memory owned by the main expression
Expression *endexpr; // memory owned by the main expression
public:
FunctionTailRecursion(const char *name, AssignmentList &definition_arguments, Expression *expr, ExpressionFunctionCall *call, Expression *endexpr, bool invert);
virtual ~FunctionTailRecursion();
virtual ValuePtr evaluate(const Context *ctx, const EvalContext *evalctx) const;
};
FunctionTailRecursion::FunctionTailRecursion(const char *name, AssignmentList &definition_arguments, Expression *expr, ExpressionFunctionCall *call, Expression *endexpr, bool invert)
: Function(name, definition_arguments, expr), invert(invert), call(call), endexpr(endexpr)
{
}
FunctionTailRecursion::~FunctionTailRecursion()
{
}
ValuePtr FunctionTailRecursion::evaluate(const Context *ctx, const EvalContext *evalctx) const
{
if (!expr) return ValuePtr::undefined;
Context c(ctx);
c.setVariables(definition_arguments, evalctx);
EvalContext ec(&c, call->call_arguments);
while (invert ^ expr->first->evaluate(&c)) {
Context tmp;
tmp.setVariables(definition_arguments, &ec);
c.apply_variables(tmp);
}
ValuePtr result = endexpr->evaluate(&c);
return result;
}
Function * Function::create(const char *name, AssignmentList &definition_arguments, Expression *expr)
{
if (dynamic_cast<ExpressionTernary *>(expr)) {
ExpressionFunctionCall *f1 = dynamic_cast<ExpressionFunctionCall *>(expr->second);
ExpressionFunctionCall *f2 = dynamic_cast<ExpressionFunctionCall *>(expr->third);
if (f1 && !f2) {
if (name == f1->funcname) {
return new FunctionTailRecursion(name, definition_arguments, expr, f1, expr->third, false);
}
} else if (f2 && !f1) {
if (name == f2->funcname) {
return new FunctionTailRecursion(name, definition_arguments, expr, f2, expr->second, true);
}
}
}
return new Function(name, definition_arguments, expr);
}
BuiltinFunction::~BuiltinFunction()
{
}

View File

@ -38,13 +38,16 @@ public:
class Function : public AbstractFunction
{
public:
std::string name;
AssignmentList definition_arguments;
Expression *expr;
Function() { }
Function(const char *name, AssignmentList &definition_arguments, Expression *expr);
virtual ~Function();
virtual ValuePtr evaluate(const Context *ctx, const EvalContext *evalctx) const;
virtual std::string dump(const std::string &indent, const std::string &name) const;
static Function * create(const char *name, AssignmentList &definition_arguments, Expression *expr);
};

View File

@ -166,9 +166,7 @@ statement:
}
| TOK_FUNCTION TOK_ID '(' arguments_decl optional_commas ')' '=' expr
{
Function *func = new Function();
func->definition_arguments = *$4;
func->expr = $8;
Function *func = Function::create($2, *$4, $8);
scope_stack.top()->functions[$2] = func;
free($2);
delete $4;