284 lines
6.2 KiB
C++
284 lines
6.2 KiB
C++
|
|
#include <stdlib.h>
|
|
#include <math.h>
|
|
|
|
#include <vector>
|
|
#include <iostream>
|
|
#include <typeinfo>
|
|
#include <map>
|
|
|
|
#include "nodes.h"
|
|
|
|
using namespace std;
|
|
|
|
typedef NodeRef (*Function)(NodeRef args);
|
|
|
|
NodeRef CosFunction(NodeRef args);
|
|
NodeRef SinFunction(NodeRef args);
|
|
NodeRef SqrtFunction(NodeRef args);
|
|
NodeRef AbsFunction(NodeRef args);
|
|
|
|
static const struct {
|
|
const char * fn_name;
|
|
Function fn;
|
|
} functions[] = {
|
|
{"cos", CosFunction},
|
|
{"sin", SinFunction},
|
|
{"sqrt", SqrtFunction},
|
|
{"abs", AbsFunction}
|
|
};
|
|
|
|
class FunctionMap : public map<string, Function>
|
|
{
|
|
public:
|
|
FunctionMap()
|
|
{
|
|
for (unsigned int i = 0;
|
|
i < sizeof(functions)/sizeof(functions[0]);
|
|
i++)
|
|
{
|
|
(*this)[functions[i].fn_name] = functions[i].fn;
|
|
}
|
|
}
|
|
bool contains(const string & key)
|
|
{
|
|
return find(key) != end();
|
|
}
|
|
};
|
|
|
|
static FunctionMap function_map;
|
|
|
|
void Node::evaluateChildren(refptr<Node> parent)
|
|
{
|
|
/* recursively evaluate all children nodes */
|
|
for (std::vector< refptr<Node> >::iterator it = m_children.begin();
|
|
it != m_children.end();
|
|
it++)
|
|
{
|
|
refptr<Node> evaluated = (*it)->evaluate();
|
|
if ( ! evaluated.isNull() )
|
|
{
|
|
if (typeid(*evaluated) == typeid(EvaluatePropagateNode))
|
|
{
|
|
for (vector<NodeRef>::iterator it2
|
|
= evaluated->getChildren().begin();
|
|
it2 != evaluated->getChildren().end();
|
|
it2++)
|
|
{
|
|
parent->addChild(*it2);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
(*it)->evaluateChildren(evaluated);
|
|
parent->addChild(evaluated);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Node::addChildren(NodeRef other)
|
|
{
|
|
if (other.isNull())
|
|
return;
|
|
|
|
for (vector<NodeRef>::const_iterator it = other->m_children.begin();
|
|
it != other->m_children.end();
|
|
it++)
|
|
{
|
|
addChild(*it);
|
|
}
|
|
}
|
|
|
|
Node::~Node()
|
|
{
|
|
}
|
|
|
|
NodeRef BinOpNode::evaluate()
|
|
{
|
|
double o = one->evaluate()->getNumber();
|
|
double t = two->evaluate()->getNumber();
|
|
double r = 0.0;
|
|
switch (m_op)
|
|
{
|
|
case '*':
|
|
r = o * t;
|
|
break;
|
|
case '/':
|
|
r = o / t;
|
|
break;
|
|
case '+':
|
|
r = o + t;
|
|
break;
|
|
case '-':
|
|
r = o - t;
|
|
break;
|
|
case '%':
|
|
r = (int) o % (int) t;
|
|
break;
|
|
case '^':
|
|
r = pow(o, t);
|
|
break;
|
|
default:
|
|
cerr << "Error: BinOpNode created with op '" << m_op << "'" << endl;
|
|
exit(-3);
|
|
}
|
|
return new NumberNode(r);
|
|
}
|
|
|
|
NodeRef BoolExpressionNode::evaluate()
|
|
{
|
|
double o = 0, t = 0;
|
|
double r = 0;
|
|
if (m_op != '!' && m_op != '&' && m_op != '|')
|
|
{
|
|
o = one->evaluate()->getNumber();
|
|
t = two->evaluate()->getNumber();
|
|
}
|
|
switch (m_op)
|
|
{
|
|
case '<':
|
|
r = o < t ? 1 : 0;
|
|
break;
|
|
case 'l':
|
|
r = o <= t ? 1 : 0;
|
|
break;
|
|
case '>':
|
|
r = o > t ? 1 : 0;
|
|
break;
|
|
case 'g':
|
|
r = o >= t ? 1 : 0;
|
|
break;
|
|
case '=':
|
|
r = o == t ? 1 : 0;
|
|
break;
|
|
case 'n':
|
|
r = o != t ? 1 : 0;
|
|
break;
|
|
case '&':
|
|
r = one->evaluate()->getInteger();
|
|
if (r != 0)
|
|
{
|
|
r = two->evaluate()->getInteger();
|
|
}
|
|
break;
|
|
case '|':
|
|
r = one->evaluate()->getInteger();
|
|
if (r == 0)
|
|
{
|
|
r = two->evaluate()->getInteger();
|
|
}
|
|
break;
|
|
case '!':
|
|
r = ! one->evaluate()->getInteger();
|
|
break;
|
|
case 'T':
|
|
r = 1;
|
|
break;
|
|
}
|
|
return new NumberNode(r);
|
|
}
|
|
|
|
NodeRef ForNode::evaluate()
|
|
{
|
|
NodeRef eval = new EvaluatePropagateNode();
|
|
|
|
if (!m_nodes[0].isNull())
|
|
{
|
|
m_nodes[0]->evaluate();
|
|
}
|
|
|
|
while (m_nodes[1]->evaluate()->getInteger() != 0)
|
|
{
|
|
evaluateChildren(eval);
|
|
|
|
if (!m_nodes[2].isNull())
|
|
{
|
|
m_nodes[2]->evaluate();
|
|
}
|
|
}
|
|
|
|
return eval;
|
|
}
|
|
|
|
NodeRef IfNode::evaluate()
|
|
{
|
|
NodeRef eval = new EvaluatePropagateNode();
|
|
|
|
int if_val = m_test_expr->evaluate()->getInteger();
|
|
|
|
if (if_val != 0)
|
|
{
|
|
evaluateChildren(eval);
|
|
}
|
|
else if ( ! m_elses.isNull() )
|
|
{
|
|
return m_elses->evaluate();
|
|
}
|
|
|
|
return eval;
|
|
}
|
|
|
|
NodeRef ElseNode::evaluate()
|
|
{
|
|
NodeRef eval = new EvaluatePropagateNode();
|
|
evaluateChildren(eval);
|
|
return eval;
|
|
}
|
|
|
|
NodeRef FunctionCallNode::evaluate()
|
|
{
|
|
if (function_map.contains(m_name->getString()))
|
|
{
|
|
return function_map[m_name->getString()](m_parameters);
|
|
}
|
|
cerr << "Error: no function \"" << m_name->getString() << "\" defined!"
|
|
<< endl;
|
|
exit(4);
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
* Scene file functions *
|
|
*************************************************************************/
|
|
NodeRef CosFunction(NodeRef args)
|
|
{
|
|
if (args->getChildren().size() != 1)
|
|
{
|
|
cerr << "Error: cos function requires 1 argument" << endl;
|
|
exit(4);
|
|
}
|
|
return new NumberNode(cos(args->getChildren()[0]->evaluate()->getNumber()));
|
|
}
|
|
|
|
NodeRef SinFunction(NodeRef args)
|
|
{
|
|
if (args->getChildren().size() != 1)
|
|
{
|
|
cerr << "Error: sin function requires 1 argument" << endl;
|
|
exit(4);
|
|
}
|
|
return new NumberNode(sin(args->getChildren()[0]->evaluate()->getNumber()));
|
|
}
|
|
|
|
NodeRef SqrtFunction(NodeRef args)
|
|
{
|
|
if (args->getChildren().size() != 1)
|
|
{
|
|
cerr << "Error: sqrt function requires 1 argument" << endl;
|
|
exit(4);
|
|
}
|
|
return new NumberNode(sqrt(args->getChildren()[0]->evaluate()->getNumber()));
|
|
}
|
|
|
|
NodeRef AbsFunction(NodeRef args)
|
|
{
|
|
if (args->getChildren().size() != 1)
|
|
{
|
|
cerr << "Error: abs function requires 1 argument" << endl;
|
|
exit(4);
|
|
}
|
|
return new NumberNode(fabs(args->getChildren()[0]->evaluate()->getNumber()));
|
|
}
|
|
|