#include #include #include #include #include #include #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 { 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 parent) { /* recursively evaluate all children nodes */ for (std::vector< refptr >::iterator it = m_children.begin(); it != m_children.end(); it++) { refptr evaluated = (*it)->evaluate(); if ( ! evaluated.isNull() ) { if (typeid(*evaluated) == typeid(EvaluatePropagateNode)) { for (vector::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::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())); }