From 03b9303f229c605c72a1f8f74ee0a8e752770e65 Mon Sep 17 00:00:00 2001 From: timoore Date: Wed, 15 Jul 2009 23:10:06 +0000 Subject: [PATCH] Overhaul of SGExpression Polymorphic additions to expressions: Add an expression base class with a method for dynamically determining the type of an expression. Add variables, predicates and boolian expressions. Support for parsing trees of expressions --- simgear/scene/model/animation.cxx | 4 +- simgear/structure/SGExpression.cxx | 1288 +++++++++++++++++----------- simgear/structure/SGExpression.hxx | 546 ++++++++++-- 3 files changed, 1249 insertions(+), 589 deletions(-) diff --git a/simgear/scene/model/animation.cxx b/simgear/scene/model/animation.cxx index 10b1b66d..7218fc06 100644 --- a/simgear/scene/model/animation.cxx +++ b/simgear/scene/model/animation.cxx @@ -150,11 +150,11 @@ public: void setOffset(double offset) { _offset = offset; } - virtual void eval(double& value) const + virtual void eval(double& value, const simgear::expression::Binding* b) const { _offset.shuffle(); _scale.shuffle(); - value = _offset + _scale*getOperand()->getValue(); + value = _offset + _scale*getOperand()->getValue(b); } virtual bool isConst() const { return false; } diff --git a/simgear/structure/SGExpression.cxx b/simgear/structure/SGExpression.cxx index 395831f9..4c746d88 100644 --- a/simgear/structure/SGExpression.cxx +++ b/simgear/structure/SGExpression.cxx @@ -24,65 +24,104 @@ #endif #include "SGExpression.hxx" +#include "Singleton.hxx" +#include +#include +#include +#include #include #include +#include + #include +using namespace std; + +namespace simgear +{ +template +const expression::Value evalValue(const Expression* exp, + const expression::Binding* b) +{ + T val; + static_cast*>(exp)->eval(val, b); + return expression::Value(val); +} + +const expression::Value eval(const Expression* exp, + const expression::Binding* b) +{ + using namespace expression; + switch (exp->getType()) { + case BOOL: + return evalValue(exp, b); + case INT: + return evalValue(exp, b); + case FLOAT: + return evalValue(exp, b); + case DOUBLE: + return evalValue(exp, b); + default: + throw "invalid type."; + } +} +} + template static bool SGReadValueFromString(const char* str, T& value) { - if (!str) { - SG_LOG(SG_IO, SG_ALERT, "Cannot read string content."); - return false; - } - std::stringstream s; - s.str(std::string(str)); - s >> value; - if (s.fail()) { - SG_LOG(SG_IO, SG_ALERT, "Cannot read string content."); - return false; - } - return true; + if (!str) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read string content."); + return false; + } + std::stringstream s; + s.str(std::string(str)); + s >> value; + if (s.fail()) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read string content."); + return false; + } + return true; } template<> bool SGReadValueFromString(const char* str, bool& value) { - if (!str) { - SG_LOG(SG_IO, SG_ALERT, "Cannot read string content."); - return false; - } - std::stringstream s; - s.str(std::string(str)); - s >> value; - if (!s.fail()) - return true; + if (!str) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read string content."); + return false; + } + std::stringstream s; + s.str(std::string(str)); + s >> value; + if (!s.fail()) + return true; - std::string stdstr; - if (!SGReadValueFromString(str, stdstr)) - return false; + std::string stdstr; + if (!SGReadValueFromString(str, stdstr)) + return false; - if (stdstr == "true" || stdstr == "True" || stdstr == "TRUE") { - value = true; - return true; - } - if (stdstr == "false" || stdstr == "False" || stdstr == "FALSE") { - value = true; - return true; - } - return false; + if (stdstr == "true" || stdstr == "True" || stdstr == "TRUE") { + value = true; + return true; + } + if (stdstr == "false" || stdstr == "False" || stdstr == "FALSE") { + value = true; + return true; + } + return false; } template static bool SGReadValueFromContent(const SGPropertyNode *node, T& value) { - if (!node) - return false; - return SGReadValueFromString(node->getStringValue(), value); + if (!node) + return false; + return SGReadValueFromString(node->getStringValue(), value); } template @@ -94,14 +133,14 @@ static bool SGReadNaryOperands(SGNaryExpression* nary, SGPropertyNode *inputRoot, const SGPropertyNode *expression) { - for (int i = 0; i < expression->nChildren(); ++i) { - SGExpression* inputExpression; - inputExpression = SGReadIExpression(inputRoot, expression->getChild(i)); - if (!inputExpression) - return false; - nary->addOperand(inputExpression); - } - return true; + for (int i = 0; i < expression->nChildren(); ++i) { + SGExpression* inputExpression; + inputExpression = SGReadIExpression(inputRoot, expression->getChild(i)); + if (!inputExpression) + return false; + nary->addOperand(inputExpression); + } + return true; } // template @@ -128,172 +167,172 @@ template static SGExpression* SGReadIExpression(SGPropertyNode *inputRoot, const SGPropertyNode *expression) { - if (!expression) - return 0; + if (!expression) + return 0; + + std::string name = expression->getName(); + if (name == "value") { + T value; + if (!SGReadValueFromContent(expression, value)) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"value\" expression."); + return 0; + } + return new SGConstExpression(value); + } + + if (name == "property") { + if (!inputRoot) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.\n" + "No inputRoot argument given!"); + return 0; + } + if (!expression->getStringValue()) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + SGPropertyNode* inputNode; + inputNode = inputRoot->getNode(expression->getStringValue(), true); + return new SGPropertyExpression(inputNode); + } + + if (name == "abs" || name == "fabs") { + if (expression->nChildren() != 1) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + SGSharedPtr > inputExpression; + inputExpression = SGReadIExpression(inputRoot, expression->getChild(0)); + if (!inputExpression) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + return new SGAbsExpression(inputExpression); + } + + if (name == "sqr") { + if (expression->nChildren() != 1) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + SGSharedPtr > inputExpression; + inputExpression = SGReadIExpression(inputRoot, expression->getChild(0)); + if (!inputExpression) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + return new SGSqrExpression(inputExpression); + } + + if (name == "clip") { + if (expression->nChildren() != 3) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + const SGPropertyNode* minProperty = expression->getChild("clipMin"); + T clipMin; + if (!SGReadValueFromContent(minProperty, clipMin)) + clipMin = SGMisc::min(SGLimits::min(), -SGLimits::max()); + + const SGPropertyNode* maxProperty = expression->getChild("clipMax"); + T clipMax; + if (!SGReadValueFromContent(maxProperty, clipMax)) + clipMin = SGLimits::max(); + + SGSharedPtr > inputExpression; + for (int i = 0; !inputExpression && i < expression->nChildren(); ++i) + inputExpression = SGReadIExpression(inputRoot, expression->getChild(i)); + if (!inputExpression) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + return new SGClipExpression(inputExpression, clipMin, clipMax); + } + + if (name == "div") { + if (expression->nChildren() != 2) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + SGSharedPtr > inputExpressions[2] = { + SGReadIExpression(inputRoot, expression->getChild(0)), + SGReadIExpression(inputRoot, expression->getChild(1)) + }; + if (!inputExpressions[0] || !inputExpressions[1]) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + return new SGDivExpression(inputExpressions[0], inputExpressions[1]); + } + if (name == "mod") { + if (expression->nChildren() != 2) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + SGSharedPtr > inputExpressions[2] = { + SGReadIExpression(inputRoot, expression->getChild(0)), + SGReadIExpression(inputRoot, expression->getChild(1)) + }; + if (!inputExpressions[0] || !inputExpressions[1]) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + return new SGModExpression(inputExpressions[0], inputExpressions[1]); + } + + if (name == "sum") { + if (expression->nChildren() < 1) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + SGSumExpression* output = new SGSumExpression; + if (!SGReadNaryOperands(output, inputRoot, expression)) { + delete output; + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + return output; + } + if (name == "prod" || name == "product") { + if (expression->nChildren() < 1) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + SGProductExpression* output = new SGProductExpression; + if (!SGReadNaryOperands(output, inputRoot, expression)) { + delete output; + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + return output; + } + if (name == "min") { + if (expression->nChildren() < 1) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + SGMinExpression* output = new SGMinExpression; + if (!SGReadNaryOperands(output, inputRoot, expression)) { + delete output; + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + return output; + } + if (name == "max") { + if (expression->nChildren() < 1) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + SGMaxExpression* output = new SGMaxExpression; + if (!SGReadNaryOperands(output, inputRoot, expression)) { + delete output; + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + return output; + } - std::string name = expression->getName(); - if (name == "value") { - T value; - if (!SGReadValueFromContent(expression, value)) { - SG_LOG(SG_IO, SG_ALERT, "Cannot read \"value\" expression."); - return 0; - } - return new SGConstExpression(value); - } - - if (name == "property") { - if (!inputRoot) { - SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.\n" - "No inputRoot argument given!"); - return 0; - } - if (!expression->getStringValue()) { - SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); - return 0; - } - SGPropertyNode* inputNode; - inputNode = inputRoot->getNode(expression->getStringValue(), true); - return new SGPropertyExpression(inputNode); - } - - if (name == "abs" || name == "fabs") { - if (expression->nChildren() != 1) { - SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); - return 0; - } - SGSharedPtr > inputExpression; - inputExpression = SGReadIExpression(inputRoot, expression->getChild(0)); - if (!inputExpression) { - SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); - return 0; - } - return new SGAbsExpression(inputExpression); - } - - if (name == "sqr") { - if (expression->nChildren() != 1) { - SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); - return 0; - } - SGSharedPtr > inputExpression; - inputExpression = SGReadIExpression(inputRoot, expression->getChild(0)); - if (!inputExpression) { - SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); - return 0; - } - return new SGSqrExpression(inputExpression); - } - - if (name == "clip") { - if (expression->nChildren() != 3) { - SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); - return 0; - } - const SGPropertyNode* minProperty = expression->getChild("clipMin"); - T clipMin; - if (!SGReadValueFromContent(minProperty, clipMin)) - clipMin = SGMisc::min(SGLimits::min(), -SGLimits::max()); - - const SGPropertyNode* maxProperty = expression->getChild("clipMax"); - T clipMax; - if (!SGReadValueFromContent(maxProperty, clipMax)) - clipMin = SGLimits::max(); - - SGSharedPtr > inputExpression; - for (int i = 0; !inputExpression && i < expression->nChildren(); ++i) - inputExpression = SGReadIExpression(inputRoot, expression->getChild(i)); - if (!inputExpression) { - SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); - return 0; - } - return new SGClipExpression(inputExpression, clipMin, clipMax); - } - - if (name == "div") { - if (expression->nChildren() != 2) { - SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); - return 0; - } - SGSharedPtr > inputExpressions[2] = { - SGReadIExpression(inputRoot, expression->getChild(0)), - SGReadIExpression(inputRoot, expression->getChild(1)) - }; - if (!inputExpressions[0] || !inputExpressions[1]) { - SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); - return 0; - } - return new SGDivExpression(inputExpressions[0], inputExpressions[1]); - } - if (name == "mod") { - if (expression->nChildren() != 2) { - SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); - return 0; - } - SGSharedPtr > inputExpressions[2] = { - SGReadIExpression(inputRoot, expression->getChild(0)), - SGReadIExpression(inputRoot, expression->getChild(1)) - }; - if (!inputExpressions[0] || !inputExpressions[1]) { - SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); - return 0; - } - return new SGModExpression(inputExpressions[0], inputExpressions[1]); - } - - if (name == "sum") { - if (expression->nChildren() < 1) { - SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); - return 0; - } - SGSumExpression* output = new SGSumExpression; - if (!SGReadNaryOperands(output, inputRoot, expression)) { - delete output; - SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); - return 0; - } - return output; - } - if (name == "prod" || name == "product") { - if (expression->nChildren() < 1) { - SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); - return 0; - } - SGProductExpression* output = new SGProductExpression; - if (!SGReadNaryOperands(output, inputRoot, expression)) { - delete output; - SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); - return 0; - } - return output; - } - if (name == "min") { - if (expression->nChildren() < 1) { - SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); - return 0; - } - SGMinExpression* output = new SGMinExpression; - if (!SGReadNaryOperands(output, inputRoot, expression)) { - delete output; - SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); - return 0; - } - return output; - } - if (name == "max") { - if (expression->nChildren() < 1) { - SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); - return 0; - } - SGMaxExpression* output = new SGMaxExpression; - if (!SGReadNaryOperands(output, inputRoot, expression)) { - delete output; - SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); - return 0; - } - return output; - } - - return 0; + return 0; } @@ -301,251 +340,251 @@ template static SGExpression* SGReadFExpression(SGPropertyNode *inputRoot, const SGPropertyNode *expression) { - SGExpression* r = SGReadIExpression(inputRoot, expression); - if (r) - return r; - - if (!expression) - return 0; - - std::string name = expression->getName(); - if (name == "acos") { - if (expression->nChildren() != 1) { - SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); - return 0; - } - SGSharedPtr > inputExpression; - inputExpression = SGReadFExpression(inputRoot, expression->getChild(0)); - if (!inputExpression) { - SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); - return 0; - } - return new SGACosExpression(inputExpression); - } - - if (name == "asin") { - if (expression->nChildren() != 1) { - SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); - return 0; - } - SGSharedPtr > inputExpression; - inputExpression = SGReadFExpression(inputRoot, expression->getChild(0)); - if (!inputExpression) { - SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); - return 0; - } - return new SGASinExpression(inputExpression); - } - - if (name == "atan") { - if (expression->nChildren() != 1) { - SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); - return 0; - } - SGSharedPtr > inputExpression; - inputExpression = SGReadFExpression(inputRoot, expression->getChild(0)); - if (!inputExpression) { - SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); - return 0; - } - return new SGATanExpression(inputExpression); - } - - if (name == "ceil") { - if (expression->nChildren() != 1) { - SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); - return 0; - } - SGSharedPtr > inputExpression; - inputExpression = SGReadFExpression(inputRoot, expression->getChild(0)); - if (!inputExpression) { - SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); - return 0; - } - return new SGCeilExpression(inputExpression); - } - - if (name == "cos") { - if (expression->nChildren() != 1) { - SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); - return 0; - } - SGSharedPtr > inputExpression; - inputExpression = SGReadFExpression(inputRoot, expression->getChild(0)); - if (!inputExpression) { - SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); - return 0; - } - return new SGCosExpression(inputExpression); - } - - if (name == "cosh") { - if (expression->nChildren() != 1) { - SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); - return 0; - } - SGSharedPtr > inputExpression; - inputExpression = SGReadFExpression(inputRoot, expression->getChild(0)); - if (!inputExpression) { - SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); - return 0; - } - return new SGCoshExpression(inputExpression); - } - - if (name == "deg2rad") { - if (expression->nChildren() != 1) { - SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); - return 0; - } - SGSharedPtr > inputExpression; - inputExpression = SGReadFExpression(inputRoot, expression->getChild(0)); - if (!inputExpression) { - SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); - return 0; - } - return new SGScaleExpression(inputExpression, SGMisc::pi()/180); - } - - if (name == "exp") { - if (expression->nChildren() != 1) { - SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); - return 0; - } - SGSharedPtr > inputExpression; - inputExpression = SGReadFExpression(inputRoot, expression->getChild(0)); - if (!inputExpression) { - SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); - return 0; - } - return new SGExpExpression(inputExpression); - } - - if (name == "floor") { - if (expression->nChildren() != 1) { - SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); - return 0; - } - SGSharedPtr > inputExpression; - inputExpression = SGReadFExpression(inputRoot, expression->getChild(0)); - if (!inputExpression) { - SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); - return 0; - } - return new SGFloorExpression(inputExpression); - } - - if (name == "log") { - if (expression->nChildren() != 1) { - SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); - return 0; - } - SGSharedPtr > inputExpression; - inputExpression = SGReadFExpression(inputRoot, expression->getChild(0)); - if (!inputExpression) { - SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); - return 0; - } - return new SGLogExpression(inputExpression); - } - - if (name == "log10") { - if (expression->nChildren() != 1) { - SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); - return 0; - } - SGSharedPtr > inputExpression; - inputExpression = SGReadFExpression(inputRoot, expression->getChild(0)); - if (!inputExpression) { - SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); - return 0; - } - return new SGLog10Expression(inputExpression); - } - - if (name == "rad2deg") { - if (expression->nChildren() != 1) { - SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); - return 0; - } - SGSharedPtr > inputExpression; - inputExpression = SGReadFExpression(inputRoot, expression->getChild(0)); - if (!inputExpression) { - SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); - return 0; - } - return new SGScaleExpression(inputExpression, 180/SGMisc::pi()); - } - - if (name == "sin") { - if (expression->nChildren() != 1) { - SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); - return 0; - } - SGSharedPtr > inputExpression; - inputExpression = SGReadFExpression(inputRoot, expression->getChild(0)); - if (!inputExpression) { - SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); - return 0; - } - return new SGSinExpression(inputExpression); - } - - if (name == "sinh") { - if (expression->nChildren() != 1) { - SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); - return 0; - } - SGSharedPtr > inputExpression; - inputExpression = SGReadFExpression(inputRoot, expression->getChild(0)); - if (!inputExpression) { - SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); - return 0; - } - return new SGSinhExpression(inputExpression); - } - - if (name == "sqrt") { - if (expression->nChildren() != 1) { - SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); - return 0; - } - SGSharedPtr > inputExpression; - inputExpression = SGReadFExpression(inputRoot, expression->getChild(0)); - if (!inputExpression) { - SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); - return 0; - } - return new SGSqrtExpression(inputExpression); - } - - if (name == "tan") { - if (expression->nChildren() != 1) { - SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); - return 0; - } - SGSharedPtr > inputExpression; - inputExpression = SGReadFExpression(inputRoot, expression->getChild(0)); - if (!inputExpression) { - SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); - return 0; - } - return new SGTanExpression(inputExpression); - } - - if (name == "tanh") { - if (expression->nChildren() != 1) { - SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); - return 0; - } - SGSharedPtr > inputExpression; - inputExpression = SGReadFExpression(inputRoot, expression->getChild(0)); - if (!inputExpression) { - SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); - return 0; - } - return new SGTanhExpression(inputExpression); - } + SGExpression* r = SGReadIExpression(inputRoot, expression); + if (r) + return r; + + if (!expression) + return 0; + + std::string name = expression->getName(); + if (name == "acos") { + if (expression->nChildren() != 1) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + SGSharedPtr > inputExpression; + inputExpression = SGReadFExpression(inputRoot, expression->getChild(0)); + if (!inputExpression) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + return new SGACosExpression(inputExpression); + } + + if (name == "asin") { + if (expression->nChildren() != 1) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + SGSharedPtr > inputExpression; + inputExpression = SGReadFExpression(inputRoot, expression->getChild(0)); + if (!inputExpression) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + return new SGASinExpression(inputExpression); + } + + if (name == "atan") { + if (expression->nChildren() != 1) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + SGSharedPtr > inputExpression; + inputExpression = SGReadFExpression(inputRoot, expression->getChild(0)); + if (!inputExpression) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + return new SGATanExpression(inputExpression); + } + + if (name == "ceil") { + if (expression->nChildren() != 1) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + SGSharedPtr > inputExpression; + inputExpression = SGReadFExpression(inputRoot, expression->getChild(0)); + if (!inputExpression) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + return new SGCeilExpression(inputExpression); + } + + if (name == "cos") { + if (expression->nChildren() != 1) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + SGSharedPtr > inputExpression; + inputExpression = SGReadFExpression(inputRoot, expression->getChild(0)); + if (!inputExpression) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + return new SGCosExpression(inputExpression); + } + + if (name == "cosh") { + if (expression->nChildren() != 1) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + SGSharedPtr > inputExpression; + inputExpression = SGReadFExpression(inputRoot, expression->getChild(0)); + if (!inputExpression) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + return new SGCoshExpression(inputExpression); + } + + if (name == "deg2rad") { + if (expression->nChildren() != 1) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + SGSharedPtr > inputExpression; + inputExpression = SGReadFExpression(inputRoot, expression->getChild(0)); + if (!inputExpression) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + return new SGScaleExpression(inputExpression, SGMisc::pi()/180); + } + + if (name == "exp") { + if (expression->nChildren() != 1) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + SGSharedPtr > inputExpression; + inputExpression = SGReadFExpression(inputRoot, expression->getChild(0)); + if (!inputExpression) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + return new SGExpExpression(inputExpression); + } + + if (name == "floor") { + if (expression->nChildren() != 1) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + SGSharedPtr > inputExpression; + inputExpression = SGReadFExpression(inputRoot, expression->getChild(0)); + if (!inputExpression) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + return new SGFloorExpression(inputExpression); + } + + if (name == "log") { + if (expression->nChildren() != 1) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + SGSharedPtr > inputExpression; + inputExpression = SGReadFExpression(inputRoot, expression->getChild(0)); + if (!inputExpression) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + return new SGLogExpression(inputExpression); + } + + if (name == "log10") { + if (expression->nChildren() != 1) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + SGSharedPtr > inputExpression; + inputExpression = SGReadFExpression(inputRoot, expression->getChild(0)); + if (!inputExpression) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + return new SGLog10Expression(inputExpression); + } + + if (name == "rad2deg") { + if (expression->nChildren() != 1) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + SGSharedPtr > inputExpression; + inputExpression = SGReadFExpression(inputRoot, expression->getChild(0)); + if (!inputExpression) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + return new SGScaleExpression(inputExpression, 180/SGMisc::pi()); + } + + if (name == "sin") { + if (expression->nChildren() != 1) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + SGSharedPtr > inputExpression; + inputExpression = SGReadFExpression(inputRoot, expression->getChild(0)); + if (!inputExpression) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + return new SGSinExpression(inputExpression); + } + + if (name == "sinh") { + if (expression->nChildren() != 1) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + SGSharedPtr > inputExpression; + inputExpression = SGReadFExpression(inputRoot, expression->getChild(0)); + if (!inputExpression) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + return new SGSinhExpression(inputExpression); + } + + if (name == "sqrt") { + if (expression->nChildren() != 1) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + SGSharedPtr > inputExpression; + inputExpression = SGReadFExpression(inputRoot, expression->getChild(0)); + if (!inputExpression) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + return new SGSqrtExpression(inputExpression); + } + + if (name == "tan") { + if (expression->nChildren() != 1) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + SGSharedPtr > inputExpression; + inputExpression = SGReadFExpression(inputRoot, expression->getChild(0)); + if (!inputExpression) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + return new SGTanExpression(inputExpression); + } + + if (name == "tanh") { + if (expression->nChildren() != 1) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + SGSharedPtr > inputExpression; + inputExpression = SGReadFExpression(inputRoot, expression->getChild(0)); + if (!inputExpression) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + return new SGTanhExpression(inputExpression); + } // if (name == "table") { // } @@ -554,68 +593,68 @@ SGReadFExpression(SGPropertyNode *inputRoot, const SGPropertyNode *expression) // if (name == "condition") { // } - if (name == "atan2") { - if (expression->nChildren() != 2) { - SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); - return 0; - } - SGSharedPtr > inputExpressions[2] = { - SGReadFExpression(inputRoot, expression->getChild(0)), - SGReadFExpression(inputRoot, expression->getChild(1)) - }; - if (!inputExpressions[0] || !inputExpressions[1]) { - SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); - return 0; - } - return new SGAtan2Expression(inputExpressions[0], inputExpressions[1]); - } - if (name == "div") { - if (expression->nChildren() != 2) { - SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); - return 0; - } - SGSharedPtr > inputExpressions[2] = { - SGReadFExpression(inputRoot, expression->getChild(0)), - SGReadFExpression(inputRoot, expression->getChild(1)) - }; - if (!inputExpressions[0] || !inputExpressions[1]) { - SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); - return 0; - } - return new SGDivExpression(inputExpressions[0], inputExpressions[1]); - } - if (name == "mod") { - if (expression->nChildren() != 2) { - SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); - return 0; - } - SGSharedPtr > inputExpressions[2] = { - SGReadFExpression(inputRoot, expression->getChild(0)), - SGReadFExpression(inputRoot, expression->getChild(1)) - }; - if (!inputExpressions[0] || !inputExpressions[1]) { - SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); - return 0; - } - return new SGModExpression(inputExpressions[0], inputExpressions[1]); - } - if (name == "pow") { - if (expression->nChildren() != 2) { - SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); - return 0; - } - SGSharedPtr > inputExpressions[2] = { - SGReadIExpression(inputRoot, expression->getChild(0)), - SGReadIExpression(inputRoot, expression->getChild(1)) - }; - if (!inputExpressions[0] || !inputExpressions[1]) { - SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); - return 0; - } - return new SGPowExpression(inputExpressions[0], inputExpressions[1]); - } - - return 0; + if (name == "atan2") { + if (expression->nChildren() != 2) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + SGSharedPtr > inputExpressions[2] = { + SGReadFExpression(inputRoot, expression->getChild(0)), + SGReadFExpression(inputRoot, expression->getChild(1)) + }; + if (!inputExpressions[0] || !inputExpressions[1]) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + return new SGAtan2Expression(inputExpressions[0], inputExpressions[1]); + } + if (name == "div") { + if (expression->nChildren() != 2) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + SGSharedPtr > inputExpressions[2] = { + SGReadFExpression(inputRoot, expression->getChild(0)), + SGReadFExpression(inputRoot, expression->getChild(1)) + }; + if (!inputExpressions[0] || !inputExpressions[1]) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + return new SGDivExpression(inputExpressions[0], inputExpressions[1]); + } + if (name == "mod") { + if (expression->nChildren() != 2) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + SGSharedPtr > inputExpressions[2] = { + SGReadFExpression(inputRoot, expression->getChild(0)), + SGReadFExpression(inputRoot, expression->getChild(1)) + }; + if (!inputExpressions[0] || !inputExpressions[1]) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + return new SGModExpression(inputExpressions[0], inputExpressions[1]); + } + if (name == "pow") { + if (expression->nChildren() != 2) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + SGSharedPtr > inputExpressions[2] = { + SGReadIExpression(inputRoot, expression->getChild(0)), + SGReadIExpression(inputRoot, expression->getChild(1)) + }; + if (!inputExpressions[0] || !inputExpressions[1]) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + return new SGPowExpression(inputExpressions[0], inputExpressions[1]); + } + + return 0; } SGExpression* @@ -637,3 +676,220 @@ SGReadDoubleExpression(SGPropertyNode *inputRoot, // SGReadBoolExpression(SGPropertyNode *inputRoot, // const SGPropertyNode *configNode) // { return SGReadBExpression(inputRoot, configNode); } + +namespace simgear +{ +namespace expression +{ + +class Parser { +public: + void addParser(const std::string& name, exp_parser parser) + { + _parserTable.insert(std::make_pair(name, parser)); + } + Expression* read(const SGPropertyNode* exp) + { + ParserMap::iterator itr = _parserTable.find(exp->getName()); + if (itr == _parserTable.end()) + throw ParseError(string("unknown expression ") + exp->getName()); + exp_parser parser = itr->second; + return (*parser)(exp, this); + } + // XXX vector of SGSharedPtr? + bool readChildren(const SGPropertyNode* exp, + vector& result); +protected: + typedef std::map ParserMap; + ParserMap _parserTable; +}; + +class ExpressionParser : public Parser, public Singleton +{ +}; + +void addExpParser(const string& token, exp_parser parsefn) +{ + ExpressionParser::instance()->addParser(token, parsefn); +} + +Expression* read(const SGPropertyNode* exp, Parser* parser) +{ + if (!parser) + parser = ExpressionParser::instance(); + return parser->read(exp); +} + +bool Parser::readChildren(const SGPropertyNode* exp, + vector& result) +{ + for (int i = 0; i < exp->nChildren(); ++i) + result.push_back(read(exp->getChild(i))); + return true; +} + +Expression* valueParser(const SGPropertyNode* exp, Parser* parser) +{ + switch (exp->getType()) { + case props::BOOL: + return new SGConstExpression(getValue(exp)); + case props::INT: + return new SGConstExpression(getValue(exp)); + case props::FLOAT: + return new SGConstExpression(getValue(exp)); + case props::DOUBLE: + return new SGConstExpression(getValue(exp)); + default: + return 0; + } +} + +ExpParserRegistrar valueRegistrar("value", valueParser); + +template +inline Expression* makeConvert(Expression* e) +{ + return new ConvertExpression(static_cast*>(e)); +} + +Type promoteAndConvert(vector& exps, Type minType = BOOL) +{ + vector::iterator maxElem + = max_element(exps.begin(), exps.end()); + Type maxType = (*maxElem)->getType(); + Type resultType = minType < maxType ? maxType : minType; + for (vector::iterator itr = exps.begin(), end = exps.end(); + itr != end; + ++itr) { + if ((*itr)->getType() != resultType) { + switch ((*itr)->getType()) { + case BOOL: + switch (resultType) { + case INT: + *itr = makeConvert(*itr); + break; + case FLOAT: + *itr = makeConvert(*itr); + break; + case DOUBLE: + *itr = makeConvert(*itr); + break; + default: + break; + } + break; + case INT: + switch (resultType) { + case FLOAT: + *itr = makeConvert(*itr); + break; + case DOUBLE: + *itr = makeConvert(*itr); + break; + default: + break; + } + break; + case FLOAT: + *itr = makeConvert(*itr); + break; + default: + break; + } + } + } + return resultType; +} + +template class Expr> +Expression* makeTypedOperandExp(Type operandType, vector children) +{ + switch (operandType) { + case BOOL: + { + Expr *expr = new Expr(); + expr->addOperands(children.begin(), children.end()); + return expr; + } + case INT: + { + Expr *expr = new Expr(); + expr->addOperands(children.begin(), children.end()); + return expr; + } + case FLOAT: + { + Expr *expr = new Expr(); + expr->addOperands(children.begin(), children.end()); + return expr; + } + case DOUBLE: + { + Expr *expr = new Expr(); + expr->addOperands(children.begin(), children.end()); + return expr; + } + default: + return 0; + } +} + +template class PredExp> +Expression* predParser(const SGPropertyNode* exp, Parser* parser) +{ + vector children; + parser->readChildren(exp, children); + Type operandType = promoteAndConvert(children); + return makeTypedOperandExp(operandType, children); +} + +ExpParserRegistrar equalRegistrar("equal", predParser); +ExpParserRegistrar lessRegistrar("less", predParser); +ExpParserRegistrar leRegistrar("less-equal", predParser); + +template +Expression* logicopParser(const SGPropertyNode* exp, Parser* parser) +{ + using namespace boost; + vector children; + parser->readChildren(exp, children); + vector::iterator notBool = + find_if(children.begin(), children.end(), + bind(&Expression::getType, _1) != BOOL); + if (notBool != children.end()) + throw("non boolean operand to logical expression"); + Logicop *expr = new Logicop; + expr->addOperands(children.begin(), children.end()); + return expr; +} + +ExpParserRegistrar andRegistrar("and", logicopParser); +ExpParserRegistrar orRegistrar("or", logicopParser); + + +int BindingLayout::addBinding(const string& name, Type type) +{ + //XXX error checkint + int result = bindings.size(); + bindings.push_back(VariableBinding(name, type, bindings.size())); + return result; +} + +bool BindingLayout::findBinding(const std::string& name, + VariableBinding& result) const +{ + using namespace std; + using namespace boost; + vector::const_iterator itr + = find_if(bindings.begin(), bindings.end(), + bind(&VariableBinding::name, _1) == name); + if (itr != bindings.end()) { + result = *itr; + return true; + } else { + return false; + } +} +} +} diff --git a/simgear/structure/SGExpression.hxx b/simgear/structure/SGExpression.hxx index c3e3bac5..82dd8bbd 100644 --- a/simgear/structure/SGExpression.hxx +++ b/simgear/structure/SGExpression.hxx @@ -22,25 +22,115 @@ #ifndef _SG_EXPRESSION_HXX #define _SG_EXPRESSION_HXX 1 +#include +#include + #include #include #include #include #include +#include /// Expression tree implementation. +namespace simgear +{ + namespace expression + { + enum Type { + BOOL = 0, + INT, + FLOAT, + DOUBLE + }; + template struct TypeTraits; + template<> struct TypeTraits { + static const Type typeTag = BOOL; + }; + template<> struct TypeTraits { + static const Type typeTag = INT; + }; + template<> struct TypeTraits { + static const Type typeTag = FLOAT; + }; + template<> struct TypeTraits { + static const Type typeTag = DOUBLE; + }; + + struct Value + { + Type typeTag; + union { + bool boolVal; + int intVal; + float floatVal; + double doubleVal; + } val; + + Value() : typeTag(DOUBLE) + { + val.doubleVal = 0.0; + } + + Value(bool val_) : typeTag(BOOL) + { + val.boolVal = val_; + } + + Value(int val_) : typeTag(INT) + { + val.intVal = val_; + } + + Value(float val_) : typeTag(FLOAT) + { + val.floatVal = val_; + } + + Value(double val_) : typeTag(DOUBLE) + { + val.doubleVal = val_; + } + + }; + + class Binding; + } + + class Expression : public SGReferenced + { + public: + virtual ~Expression() {} + virtual expression::Type getType() const = 0; + }; + + const expression::Value eval(const Expression* exp, + const expression::Binding* binding = 0); + +} + template -class SGExpression : public SGReferenced { +class SGExpression : public simgear::Expression { public: virtual ~SGExpression() {} - virtual void eval(T&) const = 0; + typedef T result_type; + typedef T operand_type; + virtual void eval(T&, const simgear::expression::Binding*) const = 0; - T getValue() const - { T value; eval(value); return value; } + T getValue(const simgear::expression::Binding* binding = 0) const + { T value; eval(value, binding); return value; } virtual bool isConst() const { return false; } virtual SGExpression* simplify(); + virtual simgear::expression::Type getType() const + { + return simgear::expression::TypeTraits::typeTag; + } + virtual simgear::expression::Type getOperandType() const + { + return simgear::expression::TypeTraits::typeTag; + } }; /// Constant value expression @@ -51,9 +141,9 @@ public: { } void setValue(const T& value) { _value = value; } - const T& getValue() const + const T& getValue(const simgear::expression::Binding* binding = 0) const { return _value; } - virtual void eval(T& value) const + virtual void eval(T& value, const simgear::expression::Binding*) const { value = _value; } virtual bool isConst() const { return true; } private: @@ -148,6 +238,15 @@ public: return _expressions.size() - 1; } + template + void addOperands(Iter begin, Iter end) + { + for (Iter iter = begin; iter != end; ++iter) + { + addOperand(static_cast< ::SGExpression*>(*iter)); + } + } + virtual bool isConst() const { for (unsigned i = 0; i < _expressions.size(); ++i) @@ -182,7 +281,7 @@ public: { } void setPropertyNode(const SGPropertyNode* prop) { _prop = prop; } - virtual void eval(T& value) const + virtual void eval(T& value, const simgear::expression::Binding*) const { doEval(value); } private: void doEval(float& value) const @@ -205,8 +304,8 @@ public: : SGUnaryExpression(expr) { } - virtual void eval(T& value) const - { value = getOperand()->getValue(); if (value <= 0) value = -value; } + virtual void eval(T& value, const simgear::expression::Binding* b) const + { value = getOperand()->getValue(b); if (value <= 0) value = -value; } using SGUnaryExpression::getOperand; }; @@ -218,8 +317,8 @@ public: : SGUnaryExpression(expr) { } - virtual void eval(T& value) const - { value = acos(SGMisc::clip(getOperand()->getValue(), -1, 1)); } + virtual void eval(T& value, const simgear::expression::Binding* b) const + { value = acos(SGMisc::clip(getOperand()->getValue(b), -1, 1)); } using SGUnaryExpression::getOperand; }; @@ -231,8 +330,8 @@ public: : SGUnaryExpression(expr) { } - virtual void eval(T& value) const - { value = asin(SGMisc::clip(getOperand()->getValue(), -1, 1)); } + virtual void eval(T& value, const simgear::expression::Binding* b) const + { value = asin(SGMisc::clip(getOperand()->getValue(b), -1, 1)); } using SGUnaryExpression::getOperand; }; @@ -244,8 +343,8 @@ public: : SGUnaryExpression(expr) { } - virtual void eval(T& value) const - { value = atan(getOperand()->getValue()); } + virtual void eval(T& value, const simgear::expression::Binding* b) const + { value = atan(getOperand()->getValue(b)); } using SGUnaryExpression::getOperand; }; @@ -257,8 +356,8 @@ public: : SGUnaryExpression(expr) { } - virtual void eval(T& value) const - { value = ceil(getOperand()->getValue()); } + virtual void eval(T& value, const simgear::expression::Binding* b) const + { value = ceil(getOperand()->getValue(b)); } using SGUnaryExpression::getOperand; }; @@ -270,8 +369,8 @@ public: : SGUnaryExpression(expr) { } - virtual void eval(T& value) const - { value = cos(getOperand()->getValue()); } + virtual void eval(T& value, const simgear::expression::Binding* b) const + { value = cos(getOperand()->getValue(b)); } using SGUnaryExpression::getOperand; }; @@ -283,8 +382,8 @@ public: : SGUnaryExpression(expr) { } - virtual void eval(T& value) const - { value = cosh(getOperand()->getValue()); } + virtual void eval(T& value, const simgear::expression::Binding* b) const + { value = cosh(getOperand()->getValue(b)); } using SGUnaryExpression::getOperand; }; @@ -296,8 +395,8 @@ public: : SGUnaryExpression(expr) { } - virtual void eval(T& value) const - { value = exp(getOperand()->getValue()); } + virtual void eval(T& value, const simgear::expression::Binding* b) const + { value = exp(getOperand()->getValue(b)); } using SGUnaryExpression::getOperand; }; @@ -309,8 +408,8 @@ public: : SGUnaryExpression(expr) { } - virtual void eval(T& value) const - { value = floor(getOperand()->getValue()); } + virtual void eval(T& value, const simgear::expression::Binding* b) const + { value = floor(getOperand()->getValue(b)); } using SGUnaryExpression::getOperand; }; @@ -322,8 +421,8 @@ public: : SGUnaryExpression(expr) { } - virtual void eval(T& value) const - { value = log(getOperand()->getValue()); } + virtual void eval(T& value, const simgear::expression::Binding* b) const + { value = log(getOperand()->getValue(b)); } using SGUnaryExpression::getOperand; }; @@ -335,8 +434,8 @@ public: : SGUnaryExpression(expr) { } - virtual void eval(T& value) const - { value = log10(getOperand()->getValue()); } + virtual void eval(T& value, const simgear::expression::Binding* b) const + { value = log10(getOperand()->getValue(b)); } using SGUnaryExpression::getOperand; }; @@ -348,8 +447,8 @@ public: : SGUnaryExpression(expr) { } - virtual void eval(T& value) const - { value = sin(getOperand()->getValue()); } + virtual void eval(T& value, const simgear::expression::Binding* b) const + { value = sin(getOperand()->getValue(b)); } using SGUnaryExpression::getOperand; }; @@ -361,8 +460,8 @@ public: : SGUnaryExpression(expr) { } - virtual void eval(T& value) const - { value = sinh(getOperand()->getValue()); } + virtual void eval(T& value, const simgear::expression::Binding* b) const + { value = sinh(getOperand()->getValue(b)); } using SGUnaryExpression::getOperand; }; @@ -374,8 +473,8 @@ public: : SGUnaryExpression(expr) { } - virtual void eval(T& value) const - { value = getOperand()->getValue(); value = value*value; } + virtual void eval(T& value, const simgear::expression::Binding* b) const + { value = getOperand()->getValue(b); value = value*value; } using SGUnaryExpression::getOperand; }; @@ -387,8 +486,8 @@ public: : SGUnaryExpression(expr) { } - virtual void eval(T& value) const - { value = sqrt(getOperand()->getValue()); } + virtual void eval(T& value, const simgear::expression::Binding* b) const + { value = sqrt(getOperand()->getValue(b)); } using SGUnaryExpression::getOperand; }; @@ -400,8 +499,8 @@ public: : SGUnaryExpression(expr) { } - virtual void eval(T& value) const - { value = tan(getOperand()->getValue()); } + virtual void eval(T& value, const simgear::expression::Binding* b) const + { value = tan(getOperand()->getValue(b)); } using SGUnaryExpression::getOperand; }; @@ -413,8 +512,8 @@ public: : SGUnaryExpression(expr) { } - virtual void eval(T& value) const - { value = tanh(getOperand()->getValue()); } + virtual void eval(T& value, const simgear::expression::Binding* b) const + { value = tanh(getOperand()->getValue(b)); } using SGUnaryExpression::getOperand; }; @@ -430,8 +529,8 @@ public: const T& getScale() const { return _scale; } - virtual void eval(T& value) const - { value = _scale * getOperand()->getValue(); } + virtual void eval(T& value, const simgear::expression::Binding* b) const + { value = _scale * getOperand()->getValue(b); } virtual SGExpression* simplify() { @@ -457,8 +556,8 @@ public: const T& getBias() const { return _bias; } - virtual void eval(T& value) const - { value = _bias + getOperand()->getValue(); } + virtual void eval(T& value, const simgear::expression::Binding* b) const + { value = _bias + getOperand()->getValue(b); } virtual SGExpression* simplify() { @@ -481,10 +580,10 @@ public: _interpTable(interpTable) { } - virtual void eval(T& value) const + virtual void eval(T& value, const simgear::expression::Binding* b) const { if (_interpTable) - value = _interpTable->interpolate(getOperand()->getValue()); + value = _interpTable->interpolate(getOperand()->getValue(b)); } using SGUnaryExpression::getOperand; @@ -517,9 +616,9 @@ public: const T& getClipMax() const { return _clipMax; } - virtual void eval(T& value) const + virtual void eval(T& value, const simgear::expression::Binding* b) const { - value = SGMisc::clip(getOperand()->getValue(), _clipMin, _clipMax); + value = SGMisc::clip(getOperand()->getValue(b), _clipMin, _clipMax); } virtual SGExpression* simplify() @@ -554,8 +653,8 @@ public: const T& getScroll() const { return _scroll; } - virtual void eval(T& value) const - { value = apply_mods(getOperand()->getValue()); } + virtual void eval(T& value, const simgear::expression::Binding* b) const + { value = apply_mods(getOperand()->getValue(b)); } using SGUnaryExpression::getOperand; @@ -603,10 +702,10 @@ public: void setDisabledValue(const T& disabledValue) { _disabledValue = disabledValue; } - virtual void eval(T& value) const + virtual void eval(T& value, const simgear::expression::Binding* b) const { if (_enable->test()) - value = getOperand()->getValue(); + value = getOperand()->getValue(b); else value = _disabledValue; } @@ -630,8 +729,8 @@ public: SGAtan2Expression(SGExpression* expr0, SGExpression* expr1) : SGBinaryExpression(expr0, expr1) { } - virtual void eval(T& value) const - { value = atan2(getOperand(0)->getValue(), getOperand(1)->getValue()); } + virtual void eval(T& value, const simgear::expression::Binding* b) const + { value = atan2(getOperand(0)->getValue(b), getOperand(1)->getValue(b)); } using SGBinaryExpression::getOperand; }; @@ -641,8 +740,8 @@ public: SGDivExpression(SGExpression* expr0, SGExpression* expr1) : SGBinaryExpression(expr0, expr1) { } - virtual void eval(T& value) const - { value = getOperand(0)->getValue() / getOperand(1)->getValue(); } + virtual void eval(T& value, const simgear::expression::Binding* b) const + { value = getOperand(0)->getValue(b) / getOperand(1)->getValue(b); } using SGBinaryExpression::getOperand; }; @@ -652,8 +751,8 @@ public: SGModExpression(SGExpression* expr0, SGExpression* expr1) : SGBinaryExpression(expr0, expr1) { } - virtual void eval(T& value) const - { value = mod(getOperand(0)->getValue(), getOperand(1)->getValue()); } + virtual void eval(T& value, const simgear::expression::Binding* b) const + { value = mod(getOperand(0)->getValue(b), getOperand(1)->getValue(b)); } using SGBinaryExpression::getOperand; private: int mod(const int& v0, const int& v1) const @@ -670,8 +769,8 @@ public: SGPowExpression(SGExpression* expr0, SGExpression* expr1) : SGBinaryExpression(expr0, expr1) { } - virtual void eval(T& value) const - { value = pow(getOperand(0)->getValue(), getOperand(1)->getValue()); } + virtual void eval(T& value, const simgear::expression::Binding* b) const + { value = pow(getOperand(0)->getValue(b), getOperand(1)->getValue(b)); } using SGBinaryExpression::getOperand; }; @@ -683,12 +782,12 @@ public: SGSumExpression(SGExpression* expr0, SGExpression* expr1) : SGNaryExpression(expr0, expr1) { } - virtual void eval(T& value) const + virtual void eval(T& value, const simgear::expression::Binding* b) const { value = T(0); unsigned sz = SGNaryExpression::getNumOperands(); for (unsigned i = 0; i < sz; ++i) - value += getOperand(i)->getValue(); + value += getOperand(i)->getValue(b); } using SGNaryExpression::getValue; using SGNaryExpression::getOperand; @@ -702,12 +801,12 @@ public: SGProductExpression(SGExpression* expr0, SGExpression* expr1) : SGNaryExpression(expr0, expr1) { } - virtual void eval(T& value) const + virtual void eval(T& value, const simgear::expression::Binding* b) const { value = T(1); unsigned sz = SGNaryExpression::getNumOperands(); for (unsigned i = 0; i < sz; ++i) - value *= getOperand(i)->getValue(); + value *= getOperand(i)->getValue(b); } using SGNaryExpression::getValue; using SGNaryExpression::getOperand; @@ -721,15 +820,15 @@ public: SGMinExpression(SGExpression* expr0, SGExpression* expr1) : SGNaryExpression(expr0, expr1) { } - virtual void eval(T& value) const + virtual void eval(T& value, const simgear::expression::Binding* b) const { unsigned sz = SGNaryExpression::getNumOperands(); if (sz < 1) return; - value = getOperand(0)->getValue(); + value = getOperand(0)->getValue(b); for (unsigned i = 1; i < sz; ++i) - value = SGMisc::min(value, getOperand(i)->getValue()); + value = SGMisc::min(value, getOperand(i)->getValue(b)); } using SGNaryExpression::getOperand; }; @@ -742,15 +841,15 @@ public: SGMaxExpression(SGExpression* expr0, SGExpression* expr1) : SGNaryExpression(expr0, expr1) { } - virtual void eval(T& value) const + virtual void eval(T& value, const simgear::expression::Binding* b) const { unsigned sz = SGNaryExpression::getNumOperands(); if (sz < 1) return; - value = getOperand(0)->getValue(); + value = getOperand(0)->getValue(b); for (unsigned i = 1; i < sz; ++i) - value = SGMisc::max(value, getOperand(i)->getValue()); + value = SGMisc::max(value, getOperand(i)->getValue(b)); } using SGNaryExpression::getOperand; }; @@ -798,4 +897,309 @@ SGExpression* SGReadBoolExpression(SGPropertyNode *inputRoot, const SGPropertyNode *configNode); +namespace simgear +{ + namespace expression + { + class Parser; + /** + * Function that parses a property tree, producing an expression. + */ + typedef Expression* (*exp_parser)(const SGPropertyNode* exp, + Parser* parser); + void addExpParser(const std::string&, exp_parser); + Expression* read(const SGPropertyNode* exp, Parser* parser = 0); + /** + * Constructor for registering parser functions. + */ + struct ExpParserRegistrar + { + ExpParserRegistrar(const std::string& token, exp_parser parser) + { + addExpParser(token, parser); + } + }; + + struct ParseError : public sg_exception + { + ParseError(const string& message = std::string()) + : sg_exception(message) {} + }; + + // Support for binding variables around an expression. + class Binding + { + public: + virtual ~Binding() {} + const virtual Value* getBindings() const = 0; + virtual Value* getBindings() = 0; + }; + + class VariableLengthBinding : public Binding + { + public: + const Value* getBindings() const + { + if (_bindings.empty()) + return 0; + else + return &_bindings[0]; + } + Value* getBindings() + { + if (_bindings.empty()) + return 0; + else + return &_bindings[0]; + } + std::vector _bindings; + }; + + template class FixedLengthBinding : public Binding + { + public: + Value* getBindings() + { + return &_bindings[0]; + } + const Value* getBindings() const + { + return &_bindings[0]; + } + Value _bindings[Size]; + }; + + struct VariableBinding + { + VariableBinding() : type(expression::DOUBLE), location(-1) {} + + VariableBinding(const std::string& name_, expression::Type type_, + int location_) + : name(name_), type(type_), location(location_) + { + } + std::string name; + expression::Type type; + int location; + }; + + class BindingLayout + { + public: + int addBinding(const std::string& name, expression::Type type); + bool findBinding(const string& name, VariableBinding& result) const; + protected: + std::vector bindings; + }; + } + + /** + * Access a variable definition. Use a location from a BindingLayout. + */ + template + class VariableExpression : public ::SGExpression { + public: + VariableExpression(int location) : _location(location) {} + virtual ~VariableExpression() {} + virtual void eval(T& value, const simgear::expression::Binding* b) const + { + const expression::Value* values = b->getBindings(); + value = *reinterpret_cast(&values[_location].val); + } + protected: + int _location; + + }; + + /** + * An n-ary expression where the types of the argument aren't the + * same as the return type. + */ + template + class GeneralNaryExpression : public ::SGExpression { + public: + typedef OpType operand_type; + unsigned getNumOperands() const + { return _expressions.size(); } + const ::SGExpression* getOperand(unsigned i) const + { return _expressions[i]; } + ::SGExpression* getOperand(unsigned i) + { return _expressions[i]; } + unsigned addOperand(::SGExpression* expression) + { + if (!expression) + return ~unsigned(0); + _expressions.push_back(expression); + return _expressions.size() - 1; + } + + template + void addOperands(Iter begin, Iter end) + { + for (Iter iter = begin; iter != end; ++iter) + { + addOperand(static_cast< ::SGExpression*>(*iter)); + } + } + + virtual bool isConst() const + { + for (unsigned i = 0; i < _expressions.size(); ++i) + if (!_expressions[i]->isConst()) + return false; + return true; + } + virtual ::SGExpression* simplify() + { + for (unsigned i = 0; i < _expressions.size(); ++i) + _expressions[i] = _expressions[i]->simplify(); + return SGExpression::simplify(); + } + + simgear::expression::Type getOperandType() const + { + return simgear::expression::TypeTraits::typeTag; + } + + protected: + GeneralNaryExpression() + { } + GeneralNaryExpression(::SGExpression* expr0, + ::SGExpression* expr1) + { addOperand(expr0); addOperand(expr1); } + + std::vector > > _expressions; + }; + + /** + * A predicate that wraps, for example the STL template predicate + * expressions like std::equal_to. + */ + template class Pred> + class PredicateExpression : public GeneralNaryExpression { + public: + PredicateExpression() + { + } + PredicateExpression(::SGExpression* expr0, + ::SGExpression* expr1) + : GeneralNaryExpression(expr0, expr1) + { + } + virtual void eval(bool& value, const simgear::expression::Binding* b) const + { + unsigned sz = this->getNumOperands(); + if (sz != 2) + return; + value = _pred(this->getOperand(0)->getValue(b), + this->getOperand(1)->getValue(b)); + } + protected: + Pred _pred; + }; + + template class Pred, typename OpType> + PredicateExpression* + makePredicate(SGExpression* op1, SGExpression* op2) + { + return new PredicateExpression(op1, op2); + } + + template + class EqualToExpression : public PredicateExpression + { + public: + EqualToExpression() {} + EqualToExpression(::SGExpression* expr0, + ::SGExpression* expr1) + : PredicateExpression(expr0, expr1) + { + } + }; + + template + class LessExpression : public PredicateExpression + { + public: + LessExpression() {} + LessExpression(::SGExpression* expr0, ::SGExpression* expr1) + : PredicateExpression(expr0, expr1) + { + } + }; + + template + class LessEqualExpression + : public PredicateExpression + { + public: + LessEqualExpression() {} + LessEqualExpression(::SGExpression* expr0, + ::SGExpression* expr1) + : PredicateExpression(expr0, expr1) + { + } + }; + + class NotExpression : public ::SGUnaryExpression + { + public: + NotExpression(::SGExpression* expr = 0) + : ::SGUnaryExpression(expr) + { + } + void eval(bool& value, const expression::Binding* b) const + { + value = !getOperand()->getValue(b); + } + }; + + class OrExpression : public ::SGNaryExpression + { + public: + void eval(bool& value, const expression::Binding* b) const + { + value = false; + for (int i = 0; i < getNumOperands(); ++i) { + value = value || getOperand(i)->getValue(b); + if (value) + return; + } + } + }; + + class AndExpression : public ::SGNaryExpression + { + public: + void eval(bool& value, const expression::Binding* b) const + { + value = true; + for (int i = 0; i < getNumOperands(); ++i) { + value = value && getOperand(i)->getValue(b); + if (!value) + return; + } + } + }; + + /** + * Convert an operand from OpType to T. + */ + template + class ConvertExpression : public GeneralNaryExpression + { + public: + ConvertExpression() {} + ConvertExpression(::SGExpression* expr0) + { + addOperand(expr0); + } + virtual void eval(T& value, const simgear::expression::Binding* b) const + { + typename ConvertExpression::operand_type result; + this->_expressions.at(0)->eval(result, b); + value = result; + } + }; +} #endif // _SG_EXPRESSION_HXX -- 2.39.5