Merge pull request #59 from mbellew/eval_perf

Expression evaluation performance
This commit is contained in:
Mischa Spiegelmock
2018-05-12 08:55:41 +03:00
committed by GitHub
15 changed files with 459 additions and 308 deletions

View File

@ -450,7 +450,7 @@ CustomWave::~CustomWave()
// Comments: index is not passed, so we assume monotonic increment by 1 is ok here
int CustomWave::add_per_point_eqn(char * name, GenExpr * gen_expr)
int CustomWave::add_per_point_eqn(char * name, Expr * gen_expr)
{
PerPointEqn * per_point_eqn;

View File

@ -32,7 +32,7 @@
#define CUSTOM_WAVE_DEBUG 0
class CustomWave;
class GenExpr;
class Expr;
class PerPointEqn;
class Preset;
@ -115,7 +115,7 @@ public:
int per_frame_eqn_string_index;
int per_frame_init_eqn_string_index;
int add_per_point_eqn(char * name, GenExpr * gen_expr);
int add_per_point_eqn(char * name, Expr * gen_expr);
void evalCustomWaveInitConditions(Preset *preset);

View File

@ -69,25 +69,22 @@ public:
*infix_negative,
*infix_positive;
float eval_gen_expr(GenExpr * gen_expr);
inline GenExpr * opt_gen_expr(GenExpr * gen_expr, int ** param_list);
float eval_gen_expr(Expr * gen_expr);
inline Expr * opt_gen_expr(Expr * gen_expr, int ** param_list);
GenExpr * const_to_expr(float val);
GenExpr * param_to_expr(Param * param);
GenExpr * prefun_to_expr(float (*func_ptr)(), GenExpr ** expr_list, int num_args);
static TreeExpr * new_tree_expr(InfixOp * infix_op, GenExpr * gen_expr, TreeExpr * left, TreeExpr * right);
static GenExpr * new_gen_expr(int type, void * item);
static ValExpr * new_val_expr(int type, Term *term);
Expr * const_to_expr(float val);
Expr * param_to_expr(Param * param);
Expr * prefun_to_expr(float (*func_ptr)(), Expr ** expr_list, int num_args);
static TreeExpr * new_tree_expr(InfixOp * infix_op, Expr * gen_expr, TreeExpr * left, TreeExpr * right);
static Expr * new_gen_expr(int type, void * item);
static InfixOp * new_infix_op(int type, int precedence);
static int init_infix_ops();
static int destroy_infix_ops();
void reset_engine_vars();
GenExpr * clone_gen_expr(GenExpr * gen_expr);
TreeExpr * clone_tree_expr(TreeExpr * tree_expr);
ValExpr * clone_val_expr(ValExpr * val_expr);
PrefunExpr * clone_prefun_expr(PrefunExpr * prefun_expr);
};

View File

@ -27,40 +27,16 @@
#include <iostream>
#include "Eval.hpp"
float GenExpr::eval_gen_expr ( int mesh_i, int mesh_j )
{
float l;
if (item == 0)
return EVAL_ERROR;
switch ( this->type )
{ /* N.B. this code is responsible for 75% of all CPU time. making it faster will help a lot. */
case VAL_T:
return ( ( ValExpr* ) item )->eval_val_expr ( mesh_i, mesh_j );
case PREFUN_T:
l = ( ( PrefunExpr * ) item )->eval_prefun_expr ( mesh_i, mesh_j );
//if (EVAL_DEBUG) DWRITE( "eval_gen_expr: prefix function return value: %f\n", l);
return l;
case TREE_T:
return ( ( TreeExpr* ) ( item ) )->eval_tree_expr ( mesh_i, mesh_j );
default:
return EVAL_ERROR;
}
}
/* Evaluates functions in prefix form */
float PrefunExpr::eval_prefun_expr ( int mesh_i, int mesh_j )
float PrefunExpr::eval ( int mesh_i, int mesh_j )
{
assert ( func_ptr );
float arg_list_stk[10];
float * arg_list;
float * argp;
GenExpr **expr_listp = expr_list;
Expr **expr_listp = expr_list;
if (this->num_args > 10) {
@ -77,7 +53,7 @@ float PrefunExpr::eval_prefun_expr ( int mesh_i, int mesh_j )
/* Evaluate each argument before calling the function itself */
for ( int i = 0; i < num_args; i++ )
{
*(argp++) = (*(expr_listp++))->eval_gen_expr ( mesh_i, mesh_j );
*(argp++) = (*(expr_listp++))->eval ( mesh_i, mesh_j );
//printf("numargs %x", arg_list[i]);
}
/* Now we call the function, passing a list of
@ -92,102 +68,243 @@ float PrefunExpr::eval_prefun_expr ( int mesh_i, int mesh_j )
}
/* Evaluates a value expression */
float ValExpr::eval_val_expr ( int mesh_i, int mesh_j )
class PrefunExprOne : public PrefunExpr
{
/* Value is a constant, return the float value */
if ( type == CONSTANT_TERM_T )
float eval ( int mesh_i, int mesh_j )
{
return ( term.constant );
float val = expr_list[0]->eval ( mesh_i, mesh_j );
return (func_ptr)(&val);
}
};
/* Value is variable, dereference it */
if ( type == PARAM_TERM_T )
class ConstantExpr : public Expr
{
float constant;
public:
ConstantExpr( float value ) : Expr(CONSTANT), constant(value) {}
ConstantExpr( int type, Term *term ) : Expr(CONSTANT), constant(term->constant) {}
bool isConstant()
{
switch ( term.param->type )
{
return true;
}
float eval(int mesh_i, int mesh_j )
{
return constant;
}
std::ostream &to_string(std::ostream &out)
{
out << constant; return out;
}
};
case P_TYPE_BOOL:
class ParameterExpr : public Expr
{
protected:
Term term;
public:
ParameterExpr( int _type, Term *_term ) : Expr(PARAMETER), term(*_term) {}
float eval(int mesh_i, int mesh_j );
std::ostream& to_string(std::ostream& out)
{
out << term.param->name;
return out;
}
};
class BoolParameterExpr : public ParameterExpr
{
public:
BoolParameterExpr( int _type, Term *_term ) : ParameterExpr(_type,_term) {}
float eval ( int mesh_i, int mesh_j ) { return ( float ) ( * ( ( bool* ) ( term.param->engine_val ) ) ); }
};
class IntParameterExpr : public ParameterExpr
{
public:
IntParameterExpr( int _type, Term *_term ) : ParameterExpr(_type,_term) {}
float eval ( int mesh_i, int mesh_j ) { return ( float ) ( * ( ( int* ) ( term.param->engine_val ) ) ); }
};
class FloatParameterExpr : public ParameterExpr
{
public:
FloatParameterExpr( int _type, Term *_term ) : ParameterExpr(_type,_term) {}
float eval ( int mesh_i, int mesh_j ) { return ( * ( ( float* ) ( term.param->engine_val ) ) ); }
};
return ( float ) ( * ( ( bool* ) ( term.param->engine_val ) ) );
case P_TYPE_INT:
/* Evaluates a value expression */
float ParameterExpr::eval ( int mesh_i, int mesh_j )
{
switch ( term.param->type )
{
case P_TYPE_BOOL:
return ( float ) ( * ( ( bool* ) ( term.param->engine_val ) ) );
case P_TYPE_INT:
return ( float ) ( * ( ( int* ) ( term.param->engine_val ) ) );
case P_TYPE_DOUBLE:
if ( term.param->matrix_flag | ( term.param->flags & P_FLAG_ALWAYS_MATRIX ) )
{
/* Sanity check the matrix is there... */
assert ( term.param->matrix != NULL );
return ( float ) ( * ( ( int* ) ( term.param->engine_val ) ) );
case P_TYPE_DOUBLE:
if ( term.param->matrix_flag | ( term.param->flags & P_FLAG_ALWAYS_MATRIX ) )
/// @slow boolean check could be expensive in this critical (and common) step of evaluation
if ( mesh_i >= 0 )
{
/* Sanity check the matrix is there... */
assert ( term.param->matrix != NULL );
/// @slow boolean check could be expensive in this critical (and common) step of evaluation
if ( mesh_i >= 0 )
if ( mesh_j >= 0 )
{
if ( mesh_j >= 0 )
{
return ( ( ( float** ) term.param->matrix ) [mesh_i][mesh_j] );
}
else
{
return ( ( ( float* ) term.param->matrix ) [mesh_i] );
}
return ( ( ( float** ) term.param->matrix ) [mesh_i][mesh_j] );
}
else
{
return ( ( ( float* ) term.param->matrix ) [mesh_i] );
}
//assert(mesh_i >=0);
}
//std::cout << term.param->name << ": " << (*((float*)term.param->engine_val)) << std::endl;
return * ( ( float* ) ( term.param->engine_val ) );
default:
return EVAL_ERROR;
}
//assert(mesh_i >=0);
}
//std::cout << term.param->name << ": " << (*((float*)term.param->engine_val)) << std::endl;
return * ( ( float* ) ( term.param->engine_val ) );
default:
return EVAL_ERROR;
}
/* Unknown type, return failure */
return PROJECTM_FAILURE;
}
class MultAndAddExpr : public Expr
{
Expr *a, *b, *c;
public:
MultAndAddExpr(Expr *_a, Expr *_b, Expr *_c) : Expr(OTHER),
a(_a), b(_b), c(_c)
{
}
float eval(int mesh_i, int mesh_j)
{
float a_value = a->eval(mesh_i,mesh_j);
float b_value = b->eval(mesh_i,mesh_j);
float c_value = c->eval(mesh_i,mesh_j);
return a_value * b_value + c_value;
}
std::ostream &to_string(std::ostream &out)
{
out << "(" << a << " * " << b << ") + " << c;
return out;
}
};
std::ostream &TreeExpr::to_string(std::ostream &out)
{
if (NULL == infix_op)
{
out << gen_expr;
}
else
{
out << "(" << left << " ";
switch ( infix_op->type )
{
case INFIX_ADD:
out << "+"; break;
case INFIX_MINUS:
out << "-"; break;
case INFIX_MULT:
out << "*"; break;
case INFIX_MOD:
out << "%"; break;
case INFIX_OR:
out << "|"; break;
case INFIX_AND:
out << "&"; break;
case INFIX_DIV:
out << "/"; break;
default:
out << "infix_op_ERROR"; break;
}
out << " " << right << ")";
}
return out;
}
/* NOTE: Parser.cpp directly manipulates TreeExpr, so it is easier to optimizer AFTER parsing
* than while building up the tree initially
*/
Expr *TreeExpr::optimize()
{
if (infix_op == NULL)
{
Expr *opt = gen_expr->optimize();
if (opt != gen_expr)
delete gen_expr;
gen_expr = NULL;
return opt;
}
if (left != NULL)
{
Expr *l = left->optimize();
if (l != left)
delete left;
left = l;
}
if (right != NULL)
{
Expr *r = right->optimize();
if (r != right)
delete right;
right = r;
}
if (left == NULL)
{
Expr *opt = right;
right = NULL;
return opt;
}
if (right == NULL)
{
Expr *opt = left;
left = NULL;
return opt;
}
if (left->isConstant() && right->isConstant())
return Expr::const_to_expr(eval(-1, -1));
// this is gratuitious, but a*b+c is super common, so as proof-of-concept, let's make a special Expr
if (infix_op->type == INFIX_ADD &&
((left->clazz == TREE && ((TreeExpr *)left)->infix_op->type == INFIX_MULT) ||
(right->clazz == TREE && ((TreeExpr *)right)->infix_op->type == INFIX_MULT)))
{
Expr *a, *b, *c;
if (left->clazz == TREE && ((TreeExpr *)left)->infix_op->type == INFIX_MULT)
{
a = ((TreeExpr *)left)->left;
b = ((TreeExpr *)left)->right;
c = right;
((TreeExpr *)left)->left = NULL;
((TreeExpr *)left)->right = NULL;
right = NULL;
}
else
{
a = ((TreeExpr *)right)->left;
b = ((TreeExpr *)right)->right;
c = left;
((TreeExpr *)right)->left = NULL;
((TreeExpr *)right)->right = NULL;
left = NULL;
}
return new MultAndAddExpr(a,b,c);
}
return this;
}
/* Evaluates an expression tree */
float TreeExpr::eval_tree_expr ( int mesh_i, int mesh_j )
float TreeExpr::eval ( int mesh_i, int mesh_j )
{
float left_arg, right_arg;
/* A leaf node, evaluate the general expression. If the expression is null as well, return zero */
if ( infix_op == NULL )
{
if ( gen_expr == NULL )
return 0;
else
return gen_expr->eval_gen_expr ( mesh_i, mesh_j );
}
/* Otherwise, this node is an infix operator. Evaluate
accordingly */
/* Safe guard in case the user gave a partially written expression */
if (left == NULL) {
if (infix_op == Eval::infix_mult)
left_arg = 1;
else
left_arg = 0;
}
else
left_arg = left->eval_tree_expr ( mesh_i, mesh_j );
/* Safe guard in case the user gave a partially written expression */
if (right == NULL) {
if (infix_op == Eval::infix_mult)
right_arg = 1;
else
right_arg = 0;
}
else
right_arg = right->eval_tree_expr ( mesh_i, mesh_j );
/* shouldn't be null if we've called optimize() */
assert(NULL != infix_op);
left_arg = left->eval ( mesh_i, mesh_j );
right_arg = right->eval ( mesh_i, mesh_j );
switch ( infix_op->type )
{
@ -221,34 +338,16 @@ float TreeExpr::eval_tree_expr ( int mesh_i, int mesh_j )
}
/* Converts a float value to a general expression */
GenExpr * GenExpr::const_to_expr ( float val )
Expr * Expr::const_to_expr ( float val )
{
GenExpr * gen_expr;
ValExpr * val_expr;
Term term;
term.constant = val;
if ( ( val_expr = new ValExpr ( CONSTANT_TERM_T, &term ) ) == NULL )
return NULL;
gen_expr = new GenExpr ( VAL_T, ( void* ) val_expr );
if ( gen_expr == NULL )
{
delete val_expr;
}
return gen_expr;
return new ConstantExpr( CONSTANT_TERM_T, &term );
}
/* Converts a regular parameter to an expression */
GenExpr * GenExpr::param_to_expr ( Param * param )
Expr * Expr::param_to_expr ( Param * param )
{
GenExpr * gen_expr = NULL;
ValExpr * val_expr = NULL;
Term term;
if ( param == NULL )
@ -267,87 +366,93 @@ GenExpr * GenExpr::param_to_expr ( Param * param )
making the parser handle the case where parameters are essentially per pixel equation
substitutions */
term.param = param;
if ( ( val_expr = new ValExpr ( PARAM_TERM_T, &term ) ) == NULL )
return NULL;
if ( ( gen_expr = new GenExpr ( VAL_T, ( void* ) val_expr ) ) == NULL )
switch ( param->type )
{
delete val_expr;
return NULL;
case P_TYPE_BOOL:
return new BoolParameterExpr( PARAM_TERM_T, &term );
case P_TYPE_INT:
return new IntParameterExpr( PARAM_TERM_T, &term );
case P_TYPE_DOUBLE:
// TODO are these flags constant??? can I check them now?
if ( param->matrix_flag | ( param->flags & P_FLAG_ALWAYS_MATRIX ) )
return new ParameterExpr( PARAM_TERM_T, &term );
return new FloatParameterExpr( PARAM_TERM_T, &term );
}
return gen_expr;
return NULL;
}
/* Converts a prefix function to an expression */
GenExpr * GenExpr::prefun_to_expr ( float ( *func_ptr ) ( void * ), GenExpr ** expr_list, int num_args )
Expr * Expr::prefun_to_expr ( float ( *func_ptr ) ( void * ), Expr ** expr_list, int num_args )
{
GenExpr * gen_expr;
PrefunExpr * prefun_expr;
prefun_expr = new PrefunExpr();
if ( prefun_expr == NULL )
return NULL;
if (num_args == 1)
prefun_expr = new PrefunExprOne();
else
prefun_expr = new PrefunExpr();
prefun_expr->num_args = num_args;
prefun_expr->func_ptr = ( float ( * ) ( void* ) ) func_ptr;
prefun_expr->expr_list = expr_list;
gen_expr = new GenExpr ( PREFUN_T, ( void* ) prefun_expr );
if ( gen_expr == NULL )
delete prefun_expr;
return gen_expr;
return prefun_expr;
}
/* Creates a new tree expression */
TreeExpr::TreeExpr ( InfixOp * _infix_op, GenExpr * _gen_expr, TreeExpr * _left, TreeExpr * _right ) :
TreeExpr::TreeExpr ( InfixOp * _infix_op, Expr * _gen_expr, TreeExpr * _left, TreeExpr * _right ) :
Expr( TREE ),
infix_op ( _infix_op ), gen_expr ( _gen_expr ),
left ( _left ), right ( _right ) {}
/* Creates a new value expression */
ValExpr::ValExpr ( int _type, Term * _term ) :type ( _type )
class TreeExprAdd : public TreeExpr
{
//val_expr->type = _type;
term.constant = _term->constant;
term.param = _term->param;
//return val_expr;
}
/* Creates a new general expression */
GenExpr::GenExpr ( int _type, void * _item ) :type ( _type ), item ( _item ) {}
/* Frees a general expression */
GenExpr::~GenExpr()
{
switch ( type )
public:
TreeExprAdd( InfixOp * _infix_op, Expr * _gen_expr, TreeExpr * _left, TreeExpr * _right ) :
TreeExpr( _infix_op, _gen_expr, _left, _right) {}
float eval( int mesh_i, int mesh_j)
{
case VAL_T:
delete ( ( ValExpr* ) item );
break;
case PREFUN_T:
delete ( ( PrefunExpr* ) item );
break;
case TREE_T:
delete ( ( TreeExpr* ) item );
break;
return left->eval(mesh_i, mesh_j) + right->eval(mesh_i, mesh_j);
}
};
class TreeExprMinus : public TreeExpr
{
public:
TreeExprMinus( InfixOp * _infix_op, Expr * _gen_expr, TreeExpr * _left, TreeExpr * _right ) :
TreeExpr( _infix_op, _gen_expr, _left, _right) {}
float eval( int mesh_i, int mesh_j)
{
return left->eval(mesh_i, mesh_j) - right->eval(mesh_i, mesh_j);
}
};
class TreeExprMult : public TreeExpr
{
public:
TreeExprMult( InfixOp * _infix_op, Expr * _gen_expr, TreeExpr * _left, TreeExpr * _right ) :
TreeExpr( _infix_op, _gen_expr, _left, _right) {}
float eval( int mesh_i, int mesh_j)
{
return left->eval(mesh_i, mesh_j) * right->eval(mesh_i, mesh_j);
}
};
TreeExpr * TreeExpr::create( InfixOp * _infix_op, Expr * _gen_expr, TreeExpr * _left, TreeExpr * _right )
{
if ( NULL != _infix_op )
{
if ( _infix_op->type == INFIX_ADD )
return new TreeExprAdd( _infix_op, _gen_expr, _left, _right);
if ( _infix_op->type == INFIX_MINUS )
return new TreeExprMinus( _infix_op, _gen_expr, _left, _right);
if ( _infix_op->type == INFIX_MULT )
return new TreeExprMult( _infix_op, _gen_expr, _left, _right);
}
return new TreeExpr( _infix_op, _gen_expr, _left, _right );
}
/* Frees a function in prefix notation */
PrefunExpr::~PrefunExpr()
{
int i;
/* Free every element in expression list */
@ -358,10 +463,6 @@ PrefunExpr::~PrefunExpr()
free ( expr_list );
}
/* Frees values of type VARIABLE and CONSTANT */
ValExpr::~ValExpr()
{}
/* Frees a tree expression */
TreeExpr::~TreeExpr()
{
@ -390,13 +491,41 @@ TreeExpr::~TreeExpr()
}
/* Initializes an infix operator */
InfixOp::InfixOp ( int type, int precedence )
InfixOp::InfixOp ( int _type, int _precedence )
{
this->type = type;
this->precedence = precedence;
this->type = _type;
this->precedence = _precedence;
}
PrefunExpr::PrefunExpr() : Expr(FUNCTION)
{
}
Expr *PrefunExpr::optimize()
{
bool constant_args = true;
for (int i=0 ; i < num_args ; i++)
{
Expr *orig = expr_list[i];
expr_list[i] = orig->optimize();
if (orig != expr_list[i])
delete orig;
constant_args &= expr_list[i]->isConstant();
}
// TODO most functions can be pre-evaluated if inputs are constant, but not all
return this;
}
PrefunExpr::PrefunExpr() {}
std::ostream& PrefunExpr::to_string(std::ostream& out)
{
char comma = ' ';
out << "<function>(";
for (int i=0 ; i < num_args ; i++)
{
out << comma;
out << expr_list[i];
comma = ',';
}
out << ")";
return out;
}

View File

@ -31,6 +31,7 @@
#include "dlldefs.h"
#include "CValue.hpp"
#include <iostream>
class Param;
@ -58,65 +59,79 @@ public:
Term() { this->constant = 0; this->param = 0; }
};
/* General Expression Type */
class GenExpr
{
public:
int type;
void * item;
~GenExpr();
GenExpr( int type, void *item );
float eval_gen_expr(int mesh_i, int mesh_j);
static GenExpr *const_to_expr( float val );
static GenExpr *param_to_expr( Param *param );
static GenExpr *prefun_to_expr( float (*func_ptr)(void *), GenExpr **expr_list, int num_args );
enum ExprClass
{
TREE, CONSTANT, PARAMETER, FUNCTION, OTHER
};
/* Value expression, contains a term union */
class ValExpr
class Expr
{
public:
int type;
Term term;
ExprClass clazz;
Expr(ExprClass c) : clazz(c) {};
virtual ~Expr() {};
virtual Expr *optimize() { return this; };
virtual bool isConstant() { return false; };
virtual float eval(int mesh_i, int mesh_j) = 0;
virtual std::ostream& to_string(std::ostream &out)
{
std::cout << "nyi"; return out;
}
~ValExpr();
ValExpr( int type, Term *term );
float eval_val_expr(int mesh_i, int mesh_j);
static Expr *const_to_expr( float val );
static Expr *param_to_expr( Param *param );
static Expr *prefun_to_expr( float (*func_ptr)(void *), Expr **expr_list, int num_args );
};
inline std::ostream& operator<<(std::ostream& out, Expr *expr)
{
if (NULL == expr)
out << "NULL";
else
expr->to_string(out);
return out;
}
/* A binary expression tree ordered by operator precedence */
class TreeExpr
class TreeExpr : public Expr
{
protected:
TreeExpr( InfixOp *infix_op, Expr *gen_expr,
TreeExpr *left, TreeExpr *right );
public:
static TreeExpr *create( InfixOp *infix_op, Expr *gen_expr,
TreeExpr *left, TreeExpr *right );
InfixOp * infix_op; /* null if leaf */
GenExpr * gen_expr;
TreeExpr *left, *right;
Expr * gen_expr;
// NOTE: before optimize() left and right will always be TreeExpr
Expr *left, *right;
// these are for type-safe access in Parser.cpp
TreeExpr *&leftTree() { return *(TreeExpr **)&left; };
TreeExpr *&rightTree() { return *(TreeExpr **)&right; };
~TreeExpr();
TreeExpr( InfixOp *infix_op, GenExpr *gen_expr,
TreeExpr *left, TreeExpr *right );
float eval_tree_expr(int mesh_i, int mesh_j);
Expr *optimize();
float eval(int mesh_i, int mesh_j);
std::ostream& to_string(std::ostream &out);
};
/* A function expression in prefix form */
class PrefunExpr
class PrefunExpr : public Expr
{
public:
float (*func_ptr)(void*);
int num_args;
GenExpr **expr_list;
Expr **expr_list;
PrefunExpr();
~PrefunExpr();
/* Evaluates functions in prefix form */
float eval_prefun_expr(int mesh_i, int mesh_j);
Expr *optimize();
float eval(int mesh_i, int mesh_j);
std::ostream& to_string(std::ostream &out);
};
#endif /** _EXPR_H */

View File

@ -103,7 +103,7 @@ MilkdropPreset::~MilkdropPreset()
/* Adds a per pixel equation according to its string name. This
will be used only by the parser */
int MilkdropPreset::add_per_pixel_eqn(char * name, GenExpr * gen_expr)
int MilkdropPreset::add_per_pixel_eqn(char * name, Expr * gen_expr)
{
PerPixelEqn * per_pixel_eqn = NULL;

View File

@ -95,7 +95,7 @@ public:
/// Used by parser
/// @bug refactor
int add_per_pixel_eqn( char *name, GenExpr *gen_expr );
int add_per_pixel_eqn( char *name, Expr *gen_expr );
/// Accessor method to retrieve the absolute file path of the loaded MilkdropPreset
/// \returns a file path string

View File

@ -251,15 +251,15 @@ token_t Parser::parseToken(std::istream & fs, char * string)
/* Parse input in the form of "exp, exp, exp, ...)"
Returns a general expression list */
GenExpr **Parser::parse_prefix_args(std::istream & fs, int num_args, MilkdropPreset * preset)
Expr **Parser::parse_prefix_args(std::istream & fs, int num_args, MilkdropPreset * preset)
{
int i, j;
GenExpr ** expr_list; /* List of arguments to function */
GenExpr * gen_expr;
Expr ** expr_list; /* List of arguments to function */
Expr * gen_expr;
/* Malloc the expression list */
expr_list = (GenExpr**)wipemalloc(sizeof(GenExpr*)*num_args);
expr_list = (Expr**)wipemalloc(sizeof(Expr*)*num_args);
/* Malloc failed */
if (expr_list == NULL)
@ -331,7 +331,7 @@ int Parser::parse_per_pixel_eqn(std::istream & fs, MilkdropPreset * preset, cha
char string[MAX_TOKEN_SIZE];
GenExpr * gen_expr;
Expr * gen_expr;
if (init_string != 0)
@ -715,19 +715,17 @@ int Parser::parse_line(std::istream & fs, MilkdropPreset * preset)
}
/* Parses a general expression, this function is the meat of the parser */
GenExpr * Parser::parse_gen_expr ( std::istream & fs, TreeExpr * tree_expr, MilkdropPreset * preset)
Expr * Parser::_parse_gen_expr ( std::istream & fs, TreeExpr * tree_expr, MilkdropPreset * preset)
{
int i;
char string[MAX_TOKEN_SIZE];
token_t token;
GenExpr * gen_expr;
Expr * gen_expr;
float val;
Param * param = NULL;
Func * func;
GenExpr ** expr_list;
Expr ** expr_list;
switch (token = parseToken(fs,string))
{
@ -759,7 +757,7 @@ GenExpr * Parser::parse_gen_expr ( std::istream & fs, TreeExpr * tree_expr, Mil
}
/* Convert function to expression */
if ((gen_expr = GenExpr::prefun_to_expr((float (*)(void *))func->func_ptr, expr_list, func->getNumArgs())) == NULL)
if ((gen_expr = Expr::prefun_to_expr((float (*)(void *))func->func_ptr, expr_list, func->getNumArgs())) == NULL)
{
if (PARSE_DEBUG) printf("parse_prefix_args: failed to convert prefix function to general expression (LINE %d) \n",
line_count);
@ -818,7 +816,7 @@ GenExpr * Parser::parse_gen_expr ( std::istream & fs, TreeExpr * tree_expr, Mil
if (PARSE_DEBUG) printf("parse_gen_expr: plus used as prefix (LINE %d)\n", line_count);
/* Treat prefix plus as implict 0 preceding operator */
gen_expr = GenExpr::const_to_expr(0);
gen_expr = Expr::const_to_expr(0);
return parse_infix_op(fs, tPositive, insert_gen_expr(gen_expr, &tree_expr), preset);
}
@ -829,7 +827,7 @@ GenExpr * Parser::parse_gen_expr ( std::istream & fs, TreeExpr * tree_expr, Mil
{
/* Use the negative infix operator, but first add an implicit zero to the operator tree */
gen_expr = GenExpr::const_to_expr(0);
gen_expr = Expr::const_to_expr(0);
//return parse_gen_expr(fs, insert_gen_expr(gen_expr, &tree_expr), preset);
return parse_infix_op(fs, tNegative, insert_gen_expr(gen_expr, &tree_expr), preset);
}
@ -863,7 +861,7 @@ GenExpr * Parser::parse_gen_expr ( std::istream & fs, TreeExpr * tree_expr, Mil
/* CASE 1: Check if string is a just a floating point number */
if (string_to_float(string, &val) != PROJECTM_PARSE_ERROR)
{
if ((gen_expr = GenExpr::const_to_expr(val)) == NULL)
if ((gen_expr = Expr::const_to_expr(val)) == NULL)
{
if (tree_expr)
delete tree_expr;
@ -898,7 +896,7 @@ GenExpr * Parser::parse_gen_expr ( std::istream & fs, TreeExpr * tree_expr, Mil
/* Convert parameter to an expression */
if ((gen_expr = GenExpr::param_to_expr(param)) == NULL)
if ((gen_expr = Expr::param_to_expr(param)) == NULL)
{
delete tree_expr;
return NULL;
@ -932,7 +930,7 @@ GenExpr * Parser::parse_gen_expr ( std::istream & fs, TreeExpr * tree_expr, Mil
}
/* Convert parameter to an expression */
if ((gen_expr = GenExpr::param_to_expr(param)) == NULL)
if ((gen_expr = Expr::param_to_expr(param)) == NULL)
{
delete tree_expr;
return NULL;
@ -955,7 +953,7 @@ GenExpr * Parser::parse_gen_expr ( std::istream & fs, TreeExpr * tree_expr, Mil
}
/* Convert parameter to an expression */
if ((gen_expr = GenExpr::param_to_expr(param)) == NULL)
if ((gen_expr = Expr::param_to_expr(param)) == NULL)
{
delete tree_expr;
return NULL;
@ -981,6 +979,17 @@ GenExpr * Parser::parse_gen_expr ( std::istream & fs, TreeExpr * tree_expr, Mil
}
Expr * Parser::parse_gen_expr ( std::istream & fs, TreeExpr * tree_expr, MilkdropPreset * preset)
{
Expr *gen_expr = _parse_gen_expr( fs, tree_expr, preset );
if (NULL == gen_expr)
return NULL;
//std::cout << gen_expr << std::endl;
Expr *opt = gen_expr->optimize();
//std::cout << opt << std::endl << std::endl;
return opt;
}
/* Inserts expressions into tree according to operator precedence.
If root is null, a new tree is created, with infix_op as only element */
@ -999,7 +1008,7 @@ TreeExpr * Parser::insert_infix_op(InfixOp * infix_op, TreeExpr **root)
if (*root == NULL)
{
new_root = new TreeExpr(infix_op, NULL, NULL, NULL);
new_root = TreeExpr::create(infix_op, NULL, NULL, NULL);
*root = new_root;
return new_root;
}
@ -1009,7 +1018,7 @@ TreeExpr * Parser::insert_infix_op(InfixOp * infix_op, TreeExpr **root)
if ((*root)->infix_op == NULL)
{
new_root = new TreeExpr(infix_op, NULL, *root, NULL);
new_root = TreeExpr::create(infix_op, NULL, *root, NULL);
(*root) = new_root;
return new_root;
}
@ -1020,7 +1029,7 @@ TreeExpr * Parser::insert_infix_op(InfixOp * infix_op, TreeExpr **root)
if (infix_op->precedence >= (*root)->infix_op->precedence)
{
new_root = new TreeExpr(infix_op, NULL, *root, NULL);
new_root = TreeExpr::create(infix_op, NULL, *root, NULL);
(*root) = new_root;
return new_root;
}
@ -1035,7 +1044,7 @@ TreeExpr * Parser::insert_infix_op(InfixOp * infix_op, TreeExpr **root)
}
TreeExpr * Parser::insert_gen_expr(GenExpr * gen_expr, TreeExpr ** root)
TreeExpr * Parser::insert_gen_expr(Expr * gen_expr, TreeExpr ** root)
{
TreeExpr * new_root;
@ -1053,7 +1062,7 @@ TreeExpr * Parser::insert_gen_expr(GenExpr * gen_expr, TreeExpr ** root)
if (*root == NULL)
{
new_root = new TreeExpr(NULL, gen_expr, NULL, NULL);
new_root = TreeExpr::create(NULL, gen_expr, NULL, NULL);
*root = new_root;
return new_root;
}
@ -1067,7 +1076,7 @@ TreeExpr * Parser::insert_gen_expr(GenExpr * gen_expr, TreeExpr ** root)
}
/* A recursive helper function to insert general expression elements into the operator tree */
int Parser::insert_gen_rec(GenExpr * gen_expr, TreeExpr * root)
int Parser::insert_gen_rec(Expr * gen_expr, TreeExpr * root)
{
/* Trivial Case: root is null */
@ -1085,7 +1094,7 @@ int Parser::insert_gen_rec(GenExpr * gen_expr, TreeExpr * root)
if ((root->left == NULL) && (root->infix_op != NULL))
{
root->left = new TreeExpr(NULL, gen_expr, NULL, NULL);
root->left = TreeExpr::create(NULL, gen_expr, NULL, NULL);
return PROJECTM_SUCCESS;
}
@ -1095,7 +1104,7 @@ int Parser::insert_gen_rec(GenExpr * gen_expr, TreeExpr * root)
if ((root->right == NULL) && (root->infix_op != NULL))
{
root->right = new TreeExpr(NULL, gen_expr, NULL, NULL);
root->right = TreeExpr::create(NULL, gen_expr, NULL, NULL);
return PROJECTM_SUCCESS;
}
@ -1103,8 +1112,8 @@ int Parser::insert_gen_rec(GenExpr * gen_expr, TreeExpr * root)
this succeeds then return. If it fails, try
recursing down to the right */
if (insert_gen_rec(gen_expr, root->left) == PROJECTM_FAILURE)
return insert_gen_rec(gen_expr, root->right);
if (insert_gen_rec(gen_expr, root->leftTree()) == PROJECTM_FAILURE)
return insert_gen_rec(gen_expr, root->rightTree());
/* Impossible for control flow to reach here, but in
the world of C programming, who knows... */
@ -1131,14 +1140,14 @@ int Parser::insert_infix_rec(InfixOp * infix_op, TreeExpr * root)
I don't think this will ever happen */
if (root->left == NULL)
{
root->left = new TreeExpr(infix_op, NULL, root->left, NULL);
root->left = TreeExpr::create(infix_op, NULL, root->leftTree(), NULL);
return PROJECTM_SUCCESS;
}
/* Right tree is empty, attach this operator to it */
if (root->right == NULL)
{
root->right = new TreeExpr(infix_op, NULL, root->right, NULL);
root->right = TreeExpr::create(infix_op, NULL, root->rightTree(), NULL);
return PROJECTM_SUCCESS;
}
@ -1149,29 +1158,29 @@ int Parser::insert_infix_rec(InfixOp * infix_op, TreeExpr * root)
then insert the expression here, attaching the old right branch
to the left of the new expression */
if (root->right->infix_op == NULL)
if (root->rightTree()->infix_op == NULL)
{
root->right = new TreeExpr(infix_op, NULL, root->right, NULL);
root->right = TreeExpr::create(infix_op, NULL, root->rightTree(), NULL);
return PROJECTM_SUCCESS;
}
/* Traverse deeper if the inserting operator precedence is less than the
the root's right operator precedence */
if (infix_op->precedence < root->right->infix_op->precedence)
return insert_infix_rec(infix_op, root->right);
if (infix_op->precedence < root->rightTree()->infix_op->precedence)
return insert_infix_rec(infix_op, root->rightTree());
/* Otherwise, insert the operator here */
root->right = new TreeExpr(infix_op, NULL, root->right, NULL);
root->right = TreeExpr::create(infix_op, NULL, root->rightTree(), NULL);
return PROJECTM_SUCCESS;
}
/* Parses an infix operator */
GenExpr * Parser::parse_infix_op(std::istream & fs, token_t token, TreeExpr * tree_expr, MilkdropPreset * preset)
Expr * Parser::parse_infix_op(std::istream & fs, token_t token, TreeExpr * tree_expr, MilkdropPreset * preset)
{
GenExpr * gen_expr;
Expr * gen_expr;
switch (token)
{
@ -1212,7 +1221,7 @@ GenExpr * Parser::parse_infix_op(std::istream & fs, token_t token, TreeExpr * t
case tRPr:
case tComma:
if (PARSE_DEBUG) printf("parse_infix_op: terminal found (LINE %d)\n", line_count);
gen_expr = new GenExpr(TREE_T, (void*)tree_expr);
gen_expr = tree_expr;
assert(gen_expr);
return gen_expr;
default:
@ -1358,7 +1367,7 @@ PerFrameEqn * Parser::parse_per_frame_eqn(std::istream & fs, int index, Milkdro
char string[MAX_TOKEN_SIZE];
Param * param;
PerFrameEqn * per_frame_eqn;
GenExpr * gen_expr;
Expr * gen_expr;
if (parseToken(fs, string) != tEq)
@ -1408,7 +1417,7 @@ PerFrameEqn * Parser::parse_implicit_per_frame_eqn(std::istream & fs, char * pa
Param * param;
PerFrameEqn * per_frame_eqn;
GenExpr * gen_expr;
Expr * gen_expr;
if (fs.fail())
return NULL;
@ -1558,7 +1567,7 @@ InitCond * Parser::parse_per_frame_init_eqn(std::istream & fs, MilkdropPreset *
Param * param = NULL;
CValue init_val;
InitCond * init_cond;
GenExpr * gen_expr;
Expr * gen_expr;
float val;
token_t token;
@ -1604,7 +1613,7 @@ InitCond * Parser::parse_per_frame_init_eqn(std::istream & fs, MilkdropPreset *
}
/* Compute initial condition value */
val = gen_expr->eval_gen_expr(-1,-1);
val = gen_expr->eval(-1,-1);
/* Free the general expression now that we are done with it */
delete gen_expr;
@ -2192,7 +2201,7 @@ int Parser::parse_wave_helper(std::istream & fs, MilkdropPreset * preset, int
{
Param * param;
GenExpr * gen_expr;
Expr * gen_expr;
char string[MAX_TOKEN_SIZE];
PerFrameEqn * per_frame_eqn;
CustomWave * custom_wave;
@ -2458,7 +2467,7 @@ int Parser::parse_shape_per_frame_eqn(std::istream & fs, CustomShape * custom_sh
{
Param * param;
GenExpr * gen_expr;
Expr * gen_expr;
PerFrameEqn * per_frame_eqn;
char string[MAX_TOKEN_SIZE];
@ -2520,7 +2529,7 @@ int Parser::parse_wave_per_frame_eqn(std::istream & fs, CustomWave * custom_wav
{
Param * param;
GenExpr * gen_expr;
Expr * gen_expr;
PerFrameEqn * per_frame_eqn;
char string[MAX_TOKEN_SIZE];

View File

@ -122,7 +122,7 @@ typedef enum {
class CustomShape;
class CustomWave;
class GenExpr;
class Expr;
class InfixOp;
class PerFrameEqn;
class MilkdropPreset;
@ -155,17 +155,17 @@ public:
static int parse_line( std::istream & fs, MilkdropPreset * preset );
static int get_string_prefix_len(char * string);
static TreeExpr * insert_gen_expr(GenExpr * gen_expr, TreeExpr ** root);
static TreeExpr * insert_gen_expr(Expr * gen_expr, TreeExpr ** root);
static TreeExpr * insert_infix_op(InfixOp * infix_op, TreeExpr ** root);
static token_t parseToken(std::istream & fs, char * string);
static GenExpr ** parse_prefix_args(std::istream & fs, int num_args, MilkdropPreset * preset);
static GenExpr * parse_infix_op(std::istream & fs, token_t token, TreeExpr * tree_expr, MilkdropPreset * preset);
static GenExpr * parse_sign_arg(std::istream & fs);
static Expr ** parse_prefix_args(std::istream & fs, int num_args, MilkdropPreset * preset);
static Expr * parse_infix_op(std::istream & fs, token_t token, TreeExpr * tree_expr, MilkdropPreset * preset);
static Expr * parse_sign_arg(std::istream & fs);
static int parse_float(std::istream & fs, float * float_ptr);
static int parse_int(std::istream & fs, int * int_ptr);
static int insert_gen_rec(GenExpr * gen_expr, TreeExpr * root);
static int insert_gen_rec(Expr * gen_expr, TreeExpr * root);
static int insert_infix_rec(InfixOp * infix_op, TreeExpr * root);
static GenExpr * parse_gen_expr(std::istream & fs, TreeExpr * tree_expr, MilkdropPreset * preset);
static Expr * parse_gen_expr(std::istream & fs, TreeExpr * tree_expr, MilkdropPreset * preset);
static PerFrameEqn * parse_implicit_per_frame_eqn(std::istream & fs, char * param_string, int index, MilkdropPreset * preset);
static InitCond * parse_per_frame_init_eqn(std::istream & fs, MilkdropPreset * preset, std::map<std::string,Param*> * database);
static int parse_wavecode_prefix(char * token, int * id, char ** var_string);
@ -186,6 +186,8 @@ public:
static int parse_shape_per_frame_eqn(std::istream & fs, CustomShape * custom_shape, MilkdropPreset * preset);
static int parse_wave_per_frame_eqn(std::istream & fs, CustomWave * custom_wave, MilkdropPreset * preset);
static bool wrapsToNextLine(const std::string & str);
private:
static Expr * _parse_gen_expr(std::istream & fs, TreeExpr * tree_expr, MilkdropPreset * preset);
};
#endif /** !_PARSER_H */

View File

@ -43,10 +43,10 @@ void PerFrameEqn::evaluate() {
fflush(stdout);
}
//*((float*)per_frame_eqn->param->engine_val) = eval_gen_expr(per_frame_eqn->gen_expr);
//*((float*)per_frame_eqn->param->engine_val) = eval(per_frame_eqn->gen_expr);
assert(gen_expr);
assert(param);
param->set_param(gen_expr->eval_gen_expr(-1,-1));
param->set_param(gen_expr->eval(-1,-1));
if (PER_FRAME_EQN_DEBUG) printf(" = %.4f\n", *((float*)param->engine_val));
@ -63,5 +63,5 @@ PerFrameEqn::~PerFrameEqn() {
}
/* Create a new per frame equation */
PerFrameEqn::PerFrameEqn(int _index, Param * _param, GenExpr * _gen_expr) :
PerFrameEqn::PerFrameEqn(int _index, Param * _param, Expr * _gen_expr) :
index(_index), param(_param), gen_expr(_gen_expr) {}

View File

@ -31,7 +31,7 @@
#define PER_FRAME_EQN_DEBUG 0
class GenExpr;
class Expr;
class Param;
class PerFrameEqn;
@ -39,9 +39,9 @@ class PerFrameEqn {
public:
int index; /* a unique id for each per frame eqn (generated by order in preset files) */
Param *param; /* parameter to be assigned a value */
GenExpr *gen_expr; /* expression that paremeter is equal to */
Expr *gen_expr; /* expression that paremeter is equal to */
PerFrameEqn(int index, Param * param, GenExpr * gen_expr);
PerFrameEqn(int index, Param * param, Expr * gen_expr);
~PerFrameEqn();
/// Evaluate the per frame equation

View File

@ -38,7 +38,7 @@
/* Evaluates a per pixel equation */
void PerPixelEqn::evaluate(int mesh_i, int mesh_j) {
GenExpr * eqn_ptr = 0;
Expr * eqn_ptr = 0;
eqn_ptr = this->gen_expr;
@ -47,13 +47,13 @@ void PerPixelEqn::evaluate(int mesh_i, int mesh_j) {
if (param_matrix == 0) {
assert(param->engine_val);
(*(float*)param->engine_val) = eqn_ptr->eval_gen_expr(mesh_i, mesh_j);
(*(float*)param->engine_val) = eqn_ptr->eval(mesh_i, mesh_j);
} else {
assert(!(eqn_ptr == NULL || param_matrix == NULL));
param_matrix[mesh_i][mesh_j] = eqn_ptr->eval_gen_expr(mesh_i, mesh_j);
param_matrix[mesh_i][mesh_j] = eqn_ptr->eval(mesh_i, mesh_j);
/* Now that this parameter has been referenced with a per
pixel equation, we let the evaluator know by setting
@ -64,7 +64,7 @@ void PerPixelEqn::evaluate(int mesh_i, int mesh_j) {
}
}
PerPixelEqn::PerPixelEqn(int _index, Param * _param, GenExpr * _gen_expr):index(_index), param(_param), gen_expr(_gen_expr) {
PerPixelEqn::PerPixelEqn(int _index, Param * _param, Expr * _gen_expr):index(_index), param(_param), gen_expr(_gen_expr) {
assert(index >= 0);
assert(param != 0);

View File

@ -43,7 +43,7 @@
#define WARP_OP 9
#define NUM_OPS 10 /* obviously, this number is dependent on the number of existing per pixel operations */
class GenExpr;
class Expr;
class Param;
class PerPixelEqn;
class Preset;
@ -53,13 +53,13 @@ public:
int index; /* used for splay tree ordering. */
int flags; /* primarily to specify if this variable is user-defined */
Param *param;
GenExpr *gen_expr;
Expr *gen_expr;
void evalPerPixelEqns( Preset *preset );
void evaluate(int mesh_i, int mesh_j);
virtual ~PerPixelEqn();
PerPixelEqn(int index, Param * param, GenExpr * gen_expr);
PerPixelEqn(int index, Param * param, Expr * gen_expr);
};

View File

@ -42,7 +42,7 @@ void PerPointEqn::evaluate(int i)
{
float * param_matrix;
GenExpr * eqn_ptr;
Expr * eqn_ptr;
// samples = CustomWave::interface_wave->samples;
@ -51,8 +51,7 @@ void PerPointEqn::evaluate(int i)
if (param->matrix == NULL)
{
assert(param->matrix_flag == false);
(*(float*)param->engine_val) = eqn_ptr->eval_gen_expr(i,-1);
(*(float*)param->engine_val) = eqn_ptr->eval(i,-1);
return;
}
@ -62,7 +61,7 @@ void PerPointEqn::evaluate(int i)
param_matrix = (float*)param->matrix;
// -1 is because per points only use one dimension
param_matrix[i] = eqn_ptr->eval_gen_expr(i, -1);
param_matrix[i] = eqn_ptr->eval(i, -1);
/* Now that this parameter has been referenced with a per
@ -76,7 +75,7 @@ void PerPointEqn::evaluate(int i)
}
PerPointEqn::PerPointEqn(int _index, Param * _param, GenExpr * _gen_expr, int _samples):
PerPointEqn::PerPointEqn(int _index, Param * _param, Expr * _gen_expr, int _samples):
index(_index),
samples(_samples),
param(_param),

View File

@ -30,7 +30,7 @@
#define _PER_POINT_EQN_H
class CustomWave;
class GenExpr;
class Expr;
class Param;
class PerPointEqn;
@ -39,10 +39,10 @@ public:
int index;
int samples; // the number of samples to iterate over
Param *param;
GenExpr * gen_expr;
Expr * gen_expr;
~PerPointEqn();
void evaluate(int i);
PerPointEqn( int index, Param *param, GenExpr *gen_expr, int samples);
PerPointEqn( int index, Param *param, Expr *gen_expr, int samples);
};