fart/parser/nodes.cc
Josh Holtrop 654be9058d added function calls to scene files
git-svn-id: svn://anubis/fart/trunk@361 7f9b0f55-74a9-4bce-be96-3c2cd072584d
2010-10-07 18:53:42 +00:00

267 lines
5.8 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;
default:
cerr << "Error: BinOpNode created with op '" << m_op << "'" << endl;
exit(-3);
}
return new NumberNode(r);
}
NodeRef BoolExpressionNode::evaluate()
{
double o, t;
double r = 0;
if (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();
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()));
}