--- /dev/null
+/* -*-c++-*-
+ *
+ * Copyright (C) 2006-2007 Mathias Froehlich
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <simgear_config.h>
+#endif
+
+#include "SGExpression.hxx"
+
+#include <string>
+#include <sstream>
+#include <simgear/props/props.hxx>
+
+template<typename T>
+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;
+}
+
+template<>
+static 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;
+
+ 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;
+}
+
+template<typename T>
+static bool
+SGReadValueFromContent(const SGPropertyNode *node, T& value)
+{
+ if (!node)
+ return false;
+ return SGReadValueFromString(node->getStringValue(), value);
+}
+
+template<typename T>
+static SGExpression<T>*
+SGReadIExpression(SGPropertyNode *inputRoot, const SGPropertyNode *expression);
+
+template<typename T>
+static bool
+SGReadNaryOperands(SGNaryExpression<T>* nary,
+ SGPropertyNode *inputRoot, const SGPropertyNode *expression)
+{
+ for (unsigned i = 0; i < expression->nChildren(); ++i) {
+ SGExpression<T>* inputExpression;
+ inputExpression = SGReadIExpression<T>(inputRoot, expression->getChild(i));
+ if (!inputExpression)
+ return false;
+ nary->addOperand(inputExpression);
+ }
+}
+
+// template<typename T>
+// static SGExpression<T>*
+// SGReadBExpression(SGPropertyNode *inputRoot, const SGPropertyNode *expression)
+// {
+// 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<T>(value);
+// }
+
+// return 0;
+// }
+
+template<typename T>
+static SGExpression<T>*
+SGReadIExpression(SGPropertyNode *inputRoot, const SGPropertyNode *expression)
+{
+ 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<T>(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<T>(inputNode);
+ }
+
+ if (name == "abs" || name == "fabs") {
+ if (expression->nChildren() != 1) {
+ SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
+ return 0;
+ }
+ SGSharedPtr<SGExpression<T> > inputExpression;
+ inputExpression = SGReadIExpression<T>(inputRoot, expression->getChild(0));
+ if (!inputExpression) {
+ SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
+ return 0;
+ }
+ return new SGAbsExpression<T>(inputExpression);
+ }
+
+ if (name == "sqr") {
+ if (expression->nChildren() != 1) {
+ SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
+ return 0;
+ }
+ SGSharedPtr<SGExpression<T> > inputExpression;
+ inputExpression = SGReadIExpression<T>(inputRoot, expression->getChild(0));
+ if (!inputExpression) {
+ SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
+ return 0;
+ }
+ return new SGSqrExpression<T>(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<T>::min(SGLimits<T>::min(), -SGLimits<T>::max());
+
+ const SGPropertyNode* maxProperty = expression->getChild("clipMax");
+ T clipMax;
+ if (!SGReadValueFromContent(maxProperty, clipMax))
+ clipMin = SGLimits<T>::max();
+
+ SGSharedPtr<SGExpression<T> > inputExpression;
+ for (unsigned i = 0; !inputExpression && i < expression->nChildren(); ++i)
+ inputExpression = SGReadIExpression<T>(inputRoot, expression->getChild(i));
+ if (!inputExpression) {
+ SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
+ return 0;
+ }
+ return new SGClipExpression<T>(inputExpression, clipMin, clipMax);
+ }
+
+ if (name == "div") {
+ if (expression->nChildren() != 2) {
+ SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
+ return 0;
+ }
+ SGSharedPtr<SGExpression<T> > inputExpressions[2] = {
+ SGReadIExpression<T>(inputRoot, expression->getChild(0)),
+ SGReadIExpression<T>(inputRoot, expression->getChild(1))
+ };
+ if (!inputExpressions[0] || !inputExpressions[1]) {
+ SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
+ return 0;
+ }
+ return new SGDivExpression<T>(inputExpressions[0], inputExpressions[1]);
+ }
+ if (name == "mod") {
+ if (expression->nChildren() != 2) {
+ SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
+ return 0;
+ }
+ SGSharedPtr<SGExpression<T> > inputExpressions[2] = {
+ SGReadIExpression<T>(inputRoot, expression->getChild(0)),
+ SGReadIExpression<T>(inputRoot, expression->getChild(1))
+ };
+ if (!inputExpressions[0] || !inputExpressions[1]) {
+ SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
+ return 0;
+ }
+ return new SGModExpression<T>(inputExpressions[0], inputExpressions[1]);
+ }
+
+ if (name == "sum") {
+ if (expression->nChildren() < 1) {
+ SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
+ return 0;
+ }
+ SGSumExpression<T>* output = new SGSumExpression<T>;
+ 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<T>* output = new SGProductExpression<T>;
+ 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<T>* output = new SGMinExpression<T>;
+ 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<T>* output = new SGMaxExpression<T>;
+ if (!SGReadNaryOperands(output, inputRoot, expression)) {
+ delete output;
+ SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
+ return 0;
+ }
+ return output;
+ }
+
+ return 0;
+}
+
+
+template<typename T>
+static SGExpression<T>*
+SGReadFExpression(SGPropertyNode *inputRoot, const SGPropertyNode *expression)
+{
+ SGExpression<T>* r = SGReadIExpression<T>(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<SGExpression<T> > inputExpression;
+ inputExpression = SGReadFExpression<T>(inputRoot, expression->getChild(0));
+ if (!inputExpression) {
+ SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
+ return 0;
+ }
+ return new SGACosExpression<T>(inputExpression);
+ }
+
+ if (name == "asin") {
+ if (expression->nChildren() != 1) {
+ SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
+ return 0;
+ }
+ SGSharedPtr<SGExpression<T> > inputExpression;
+ inputExpression = SGReadFExpression<T>(inputRoot, expression->getChild(0));
+ if (!inputExpression) {
+ SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
+ return 0;
+ }
+ return new SGASinExpression<T>(inputExpression);
+ }
+
+ if (name == "atan") {
+ if (expression->nChildren() != 1) {
+ SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
+ return 0;
+ }
+ SGSharedPtr<SGExpression<T> > inputExpression;
+ inputExpression = SGReadFExpression<T>(inputRoot, expression->getChild(0));
+ if (!inputExpression) {
+ SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
+ return 0;
+ }
+ return new SGATanExpression<T>(inputExpression);
+ }
+
+ if (name == "ceil") {
+ if (expression->nChildren() != 1) {
+ SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
+ return 0;
+ }
+ SGSharedPtr<SGExpression<T> > inputExpression;
+ inputExpression = SGReadFExpression<T>(inputRoot, expression->getChild(0));
+ if (!inputExpression) {
+ SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
+ return 0;
+ }
+ return new SGCeilExpression<T>(inputExpression);
+ }
+
+ if (name == "cos") {
+ if (expression->nChildren() != 1) {
+ SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
+ return 0;
+ }
+ SGSharedPtr<SGExpression<T> > inputExpression;
+ inputExpression = SGReadFExpression<T>(inputRoot, expression->getChild(0));
+ if (!inputExpression) {
+ SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
+ return 0;
+ }
+ return new SGCosExpression<T>(inputExpression);
+ }
+
+ if (name == "cosh") {
+ if (expression->nChildren() != 1) {
+ SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
+ return 0;
+ }
+ SGSharedPtr<SGExpression<T> > inputExpression;
+ inputExpression = SGReadFExpression<T>(inputRoot, expression->getChild(0));
+ if (!inputExpression) {
+ SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
+ return 0;
+ }
+ return new SGCoshExpression<T>(inputExpression);
+ }
+
+ if (name == "deg2rad") {
+ if (expression->nChildren() != 1) {
+ SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
+ return 0;
+ }
+ SGSharedPtr<SGExpression<T> > inputExpression;
+ inputExpression = SGReadFExpression<T>(inputRoot, expression->getChild(0));
+ if (!inputExpression) {
+ SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
+ return 0;
+ }
+ return new SGScaleExpression<T>(inputExpression, SGMisc<T>::pi()/180);
+ }
+
+ if (name == "exp") {
+ if (expression->nChildren() != 1) {
+ SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
+ return 0;
+ }
+ SGSharedPtr<SGExpression<T> > inputExpression;
+ inputExpression = SGReadFExpression<T>(inputRoot, expression->getChild(0));
+ if (!inputExpression) {
+ SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
+ return 0;
+ }
+ return new SGExpExpression<T>(inputExpression);
+ }
+
+ if (name == "floor") {
+ if (expression->nChildren() != 1) {
+ SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
+ return 0;
+ }
+ SGSharedPtr<SGExpression<T> > inputExpression;
+ inputExpression = SGReadFExpression<T>(inputRoot, expression->getChild(0));
+ if (!inputExpression) {
+ SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
+ return 0;
+ }
+ return new SGFloorExpression<T>(inputExpression);
+ }
+
+ if (name == "log") {
+ if (expression->nChildren() != 1) {
+ SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
+ return 0;
+ }
+ SGSharedPtr<SGExpression<T> > inputExpression;
+ inputExpression = SGReadFExpression<T>(inputRoot, expression->getChild(0));
+ if (!inputExpression) {
+ SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
+ return 0;
+ }
+ return new SGLogExpression<T>(inputExpression);
+ }
+
+ if (name == "log10") {
+ if (expression->nChildren() != 1) {
+ SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
+ return 0;
+ }
+ SGSharedPtr<SGExpression<T> > inputExpression;
+ inputExpression = SGReadFExpression<T>(inputRoot, expression->getChild(0));
+ if (!inputExpression) {
+ SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
+ return 0;
+ }
+ return new SGLog10Expression<T>(inputExpression);
+ }
+
+ if (name == "rad2deg") {
+ if (expression->nChildren() != 1) {
+ SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
+ return 0;
+ }
+ SGSharedPtr<SGExpression<T> > inputExpression;
+ inputExpression = SGReadFExpression<T>(inputRoot, expression->getChild(0));
+ if (!inputExpression) {
+ SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
+ return 0;
+ }
+ return new SGScaleExpression<T>(inputExpression, 180/SGMisc<T>::pi());
+ }
+
+ if (name == "sin") {
+ if (expression->nChildren() != 1) {
+ SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
+ return 0;
+ }
+ SGSharedPtr<SGExpression<T> > inputExpression;
+ inputExpression = SGReadFExpression<T>(inputRoot, expression->getChild(0));
+ if (!inputExpression) {
+ SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
+ return 0;
+ }
+ return new SGSinExpression<T>(inputExpression);
+ }
+
+ if (name == "sinh") {
+ if (expression->nChildren() != 1) {
+ SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
+ return 0;
+ }
+ SGSharedPtr<SGExpression<T> > inputExpression;
+ inputExpression = SGReadFExpression<T>(inputRoot, expression->getChild(0));
+ if (!inputExpression) {
+ SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
+ return 0;
+ }
+ return new SGSinhExpression<T>(inputExpression);
+ }
+
+ if (name == "sqrt") {
+ if (expression->nChildren() != 1) {
+ SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
+ return 0;
+ }
+ SGSharedPtr<SGExpression<T> > inputExpression;
+ inputExpression = SGReadFExpression<T>(inputRoot, expression->getChild(0));
+ if (!inputExpression) {
+ SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
+ return 0;
+ }
+ return new SGSqrtExpression<T>(inputExpression);
+ }
+
+ if (name == "tan") {
+ if (expression->nChildren() != 1) {
+ SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
+ return 0;
+ }
+ SGSharedPtr<SGExpression<T> > inputExpression;
+ inputExpression = SGReadFExpression<T>(inputRoot, expression->getChild(0));
+ if (!inputExpression) {
+ SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
+ return 0;
+ }
+ return new SGTanExpression<T>(inputExpression);
+ }
+
+ if (name == "tanh") {
+ if (expression->nChildren() != 1) {
+ SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
+ return 0;
+ }
+ SGSharedPtr<SGExpression<T> > inputExpression;
+ inputExpression = SGReadFExpression<T>(inputRoot, expression->getChild(0));
+ if (!inputExpression) {
+ SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
+ return 0;
+ }
+ return new SGTanhExpression<T>(inputExpression);
+ }
+
+// if (name == "table") {
+// }
+// if (name == "step") {
+// }
+// if (name == "condition") {
+// }
+
+ if (name == "atan2") {
+ if (expression->nChildren() != 2) {
+ SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
+ return 0;
+ }
+ SGSharedPtr<SGExpression<T> > inputExpressions[2] = {
+ SGReadFExpression<T>(inputRoot, expression->getChild(0)),
+ SGReadFExpression<T>(inputRoot, expression->getChild(1))
+ };
+ if (!inputExpressions[0] || !inputExpressions[1]) {
+ SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
+ return 0;
+ }
+ return new SGAtan2Expression<T>(inputExpressions[0], inputExpressions[1]);
+ }
+ if (name == "div") {
+ if (expression->nChildren() != 2) {
+ SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
+ return 0;
+ }
+ SGSharedPtr<SGExpression<T> > inputExpressions[2] = {
+ SGReadFExpression<T>(inputRoot, expression->getChild(0)),
+ SGReadFExpression<T>(inputRoot, expression->getChild(1))
+ };
+ if (!inputExpressions[0] || !inputExpressions[1]) {
+ SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
+ return 0;
+ }
+ return new SGDivExpression<T>(inputExpressions[0], inputExpressions[1]);
+ }
+ if (name == "mod") {
+ if (expression->nChildren() != 2) {
+ SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
+ return 0;
+ }
+ SGSharedPtr<SGExpression<T> > inputExpressions[2] = {
+ SGReadFExpression<T>(inputRoot, expression->getChild(0)),
+ SGReadFExpression<T>(inputRoot, expression->getChild(1))
+ };
+ if (!inputExpressions[0] || !inputExpressions[1]) {
+ SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
+ return 0;
+ }
+ return new SGModExpression<T>(inputExpressions[0], inputExpressions[1]);
+ }
+ if (name == "pow") {
+ if (expression->nChildren() != 2) {
+ SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
+ return 0;
+ }
+ SGSharedPtr<SGExpression<T> > inputExpressions[2] = {
+ SGReadIExpression<T>(inputRoot, expression->getChild(0)),
+ SGReadIExpression<T>(inputRoot, expression->getChild(1))
+ };
+ if (!inputExpressions[0] || !inputExpressions[1]) {
+ SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.");
+ return 0;
+ }
+ return new SGPowExpression<T>(inputExpressions[0], inputExpressions[1]);
+ }
+
+ return 0;
+}
+
+SGExpression<int>*
+SGReadIntExpression(SGPropertyNode *inputRoot,
+ const SGPropertyNode *configNode)
+{ return SGReadIExpression<int>(inputRoot, configNode); }
+
+SGExpression<float>*
+SGReadFloatExpression(SGPropertyNode *inputRoot,
+ const SGPropertyNode *configNode)
+{ return SGReadFExpression<float>(inputRoot, configNode); }
+
+SGExpression<double>*
+SGReadDoubleExpression(SGPropertyNode *inputRoot,
+ const SGPropertyNode *configNode)
+{ return SGReadFExpression<double>(inputRoot, configNode); }
+
+// SGExpression<bool>*
+// SGReadBoolExpression(SGPropertyNode *inputRoot,
+// const SGPropertyNode *configNode)
+// { return SGReadBExpression<bool>(inputRoot, configNode); }
--- /dev/null
+/* -*-c++-*-
+ *
+ * Copyright (C) 2006-2007 Mathias Froehlich
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ */
+
+#ifndef _SG_EXPRESSION_HXX
+#define _SG_EXPRESSION_HXX 1
+
+#include <simgear/props/condition.hxx>
+#include <simgear/props/props.hxx>
+#include <simgear/math/interpolater.hxx>
+#include <simgear/math/SGMath.hxx>
+#include <simgear/scene/model/persparam.hxx>
+
+/// Expression tree implementation.
+
+template<typename T>
+class SGExpression : public SGReferenced {
+public:
+ virtual ~SGExpression() {}
+ virtual void eval(T&) const = 0;
+
+ T getValue() const
+ { T value; eval(value); return value; }
+
+ virtual bool isConst() const { return false; }
+ virtual SGExpression* simplify();
+};
+
+/// Constant value expression
+template<typename T>
+class SGConstExpression : public SGExpression<T> {
+public:
+ SGConstExpression(const T& value = T()) : _value(value)
+ { }
+ void setValue(const T& value)
+ { _value = value; }
+ const T& getValue() const
+ { return _value; }
+ virtual void eval(T& value) const
+ { value = _value; }
+ virtual bool isConst() const { return true; }
+private:
+ T _value;
+};
+
+template<typename T>
+SGExpression<T>*
+SGExpression<T>::simplify()
+{
+ if (isConst())
+ return new SGConstExpression<T>(getValue());
+ return this;
+}
+
+template<typename T>
+class SGUnaryExpression : public SGExpression<T> {
+public:
+ const SGExpression<T>* getOperand() const
+ { return _expression; }
+ SGExpression<T>* getOperand()
+ { return _expression; }
+ void setOperand(SGExpression<T>* expression)
+ {
+ if (!expression)
+ expression = new SGConstExpression<T>(T());
+ _expression = expression;
+ }
+ virtual bool isConst() const
+ { return getOperand()->isConst(); }
+ virtual SGExpression<T>* simplify()
+ {
+ _expression = _expression->simplify();
+ return SGExpression<T>::simplify();
+ }
+
+protected:
+ SGUnaryExpression(SGExpression<T>* expression = 0)
+ { setOperand(expression); }
+
+private:
+ SGSharedPtr<SGExpression<T> > _expression;
+};
+
+template<typename T>
+class SGBinaryExpression : public SGExpression<T> {
+public:
+ const SGExpression<T>* getOperand(unsigned i) const
+ { return _expressions[i]; }
+ SGExpression<T>* getOperand(unsigned i)
+ { return _expressions[i]; }
+ void setOperand(unsigned i, SGExpression<T>* expression)
+ {
+ if (!expression)
+ expression = new SGConstExpression<T>(T());
+ if (2 <= i)
+ i = 0;
+ _expressions[i] = expression;
+ }
+
+ virtual bool isConst() const
+ { return getOperand(0)->isConst() && getOperand(1)->isConst(); }
+ virtual SGExpression<T>* simplify()
+ {
+ _expressions[0] = _expressions[0]->simplify();
+ _expressions[1] = _expressions[1]->simplify();
+ return SGExpression<T>::simplify();
+ }
+
+protected:
+ SGBinaryExpression(SGExpression<T>* expr0, SGExpression<T>* expr1)
+ { setOperand(0, expr0); setOperand(1, expr1); }
+
+private:
+ SGSharedPtr<SGExpression<T> > _expressions[2];
+};
+
+template<typename T>
+class SGNaryExpression : public SGExpression<T> {
+public:
+ unsigned getNumOperands() const
+ { return _expressions.size(); }
+ const SGExpression<T>* getOperand(unsigned i) const
+ { return _expressions[i]; }
+ SGExpression<T>* getOperand(unsigned i)
+ { return _expressions[i]; }
+ unsigned addOperand(SGExpression<T>* expression)
+ {
+ if (!expression)
+ return ~unsigned(0);
+ _expressions.push_back(expression);
+ return _expressions.size() - 1;
+ }
+
+ virtual bool isConst() const
+ {
+ for (unsigned i = 0; i < _expressions.size(); ++i)
+ if (!_expressions[i]->isConst())
+ return false;
+ return true;
+ }
+ virtual SGExpression<T>* simplify()
+ {
+ for (unsigned i = 0; i < _expressions.size(); ++i)
+ _expressions[i] = _expressions[i]->simplify();
+ return SGExpression<T>::simplify();
+ }
+
+protected:
+ SGNaryExpression()
+ { }
+ SGNaryExpression(SGExpression<T>* expr0, SGExpression<T>* expr1)
+ { addOperand(expr0); addOperand(expr1); }
+
+private:
+ std::vector<SGSharedPtr<SGExpression<T> > > _expressions;
+};
+
+
+
+
+template<typename T>
+class SGPropertyExpression : public SGExpression<T> {
+public:
+ SGPropertyExpression(const SGPropertyNode* prop) : _prop(prop)
+ { }
+ void setPropertyNode(const SGPropertyNode* prop)
+ { _prop = prop; }
+ virtual void eval(T& value) const
+ { doEval(value); }
+private:
+ void doEval(float& value) const
+ { if (_prop) value = _prop->getFloatValue(); }
+ void doEval(double& value) const
+ { if (_prop) value = _prop->getDoubleValue(); }
+ void doEval(int& value) const
+ { if (_prop) value = _prop->getIntValue(); }
+ void doEval(long& value) const
+ { if (_prop) value = _prop->getLongValue(); }
+ void doEval(bool& value) const
+ { if (_prop) value = _prop->getBoolValue(); }
+ SGSharedPtr<const SGPropertyNode> _prop;
+};
+
+template<typename T>
+class SGAbsExpression : public SGUnaryExpression<T> {
+public:
+ SGAbsExpression(SGExpression<T>* expr = 0)
+ : SGUnaryExpression<T>(expr)
+ { }
+
+ virtual void eval(T& value) const
+ { value = getOperand()->getValue(); if (value <= 0) value = -value; }
+
+ using SGUnaryExpression<T>::getOperand;
+};
+
+template<typename T>
+class SGACosExpression : public SGUnaryExpression<T> {
+public:
+ SGACosExpression(SGExpression<T>* expr = 0)
+ : SGUnaryExpression<T>(expr)
+ { }
+
+ virtual void eval(T& value) const
+ { value = acos(SGMisc<T>::clip(getOperand()->getValue(), -1, 1)); }
+
+ using SGUnaryExpression<T>::getOperand;
+};
+
+template<typename T>
+class SGASinExpression : public SGUnaryExpression<T> {
+public:
+ SGASinExpression(SGExpression<T>* expr = 0)
+ : SGUnaryExpression<T>(expr)
+ { }
+
+ virtual void eval(T& value) const
+ { value = asin(SGMisc<T>::clip(getOperand()->getValue(), -1, 1)); }
+
+ using SGUnaryExpression<T>::getOperand;
+};
+
+template<typename T>
+class SGATanExpression : public SGUnaryExpression<T> {
+public:
+ SGATanExpression(SGExpression<T>* expr = 0)
+ : SGUnaryExpression<T>(expr)
+ { }
+
+ virtual void eval(T& value) const
+ { value = atan(getOperand()->getValue()); }
+
+ using SGUnaryExpression<T>::getOperand;
+};
+
+template<typename T>
+class SGCeilExpression : public SGUnaryExpression<T> {
+public:
+ SGCeilExpression(SGExpression<T>* expr = 0)
+ : SGUnaryExpression<T>(expr)
+ { }
+
+ virtual void eval(T& value) const
+ { value = ceil(getOperand()->getValue()); }
+
+ using SGUnaryExpression<T>::getOperand;
+};
+
+template<typename T>
+class SGCosExpression : public SGUnaryExpression<T> {
+public:
+ SGCosExpression(SGExpression<T>* expr = 0)
+ : SGUnaryExpression<T>(expr)
+ { }
+
+ virtual void eval(T& value) const
+ { value = cos(getOperand()->getValue()); }
+
+ using SGUnaryExpression<T>::getOperand;
+};
+
+template<typename T>
+class SGCoshExpression : public SGUnaryExpression<T> {
+public:
+ SGCoshExpression(SGExpression<T>* expr = 0)
+ : SGUnaryExpression<T>(expr)
+ { }
+
+ virtual void eval(T& value) const
+ { value = cosh(getOperand()->getValue()); }
+
+ using SGUnaryExpression<T>::getOperand;
+};
+
+template<typename T>
+class SGExpExpression : public SGUnaryExpression<T> {
+public:
+ SGExpExpression(SGExpression<T>* expr = 0)
+ : SGUnaryExpression<T>(expr)
+ { }
+
+ virtual void eval(T& value) const
+ { value = exp(getOperand()->getValue()); }
+
+ using SGUnaryExpression<T>::getOperand;
+};
+
+template<typename T>
+class SGFloorExpression : public SGUnaryExpression<T> {
+public:
+ SGFloorExpression(SGExpression<T>* expr = 0)
+ : SGUnaryExpression<T>(expr)
+ { }
+
+ virtual void eval(T& value) const
+ { value = floor(getOperand()->getValue()); }
+
+ using SGUnaryExpression<T>::getOperand;
+};
+
+template<typename T>
+class SGLogExpression : public SGUnaryExpression<T> {
+public:
+ SGLogExpression(SGExpression<T>* expr = 0)
+ : SGUnaryExpression<T>(expr)
+ { }
+
+ virtual void eval(T& value) const
+ { value = log(getOperand()->getValue()); }
+
+ using SGUnaryExpression<T>::getOperand;
+};
+
+template<typename T>
+class SGLog10Expression : public SGUnaryExpression<T> {
+public:
+ SGLog10Expression(SGExpression<T>* expr = 0)
+ : SGUnaryExpression<T>(expr)
+ { }
+
+ virtual void eval(T& value) const
+ { value = log10(getOperand()->getValue()); }
+
+ using SGUnaryExpression<T>::getOperand;
+};
+
+template<typename T>
+class SGSinExpression : public SGUnaryExpression<T> {
+public:
+ SGSinExpression(SGExpression<T>* expr = 0)
+ : SGUnaryExpression<T>(expr)
+ { }
+
+ virtual void eval(T& value) const
+ { value = sin(getOperand()->getValue()); }
+
+ using SGUnaryExpression<T>::getOperand;
+};
+
+template<typename T>
+class SGSinhExpression : public SGUnaryExpression<T> {
+public:
+ SGSinhExpression(SGExpression<T>* expr = 0)
+ : SGUnaryExpression<T>(expr)
+ { }
+
+ virtual void eval(T& value) const
+ { value = sinh(getOperand()->getValue()); }
+
+ using SGUnaryExpression<T>::getOperand;
+};
+
+template<typename T>
+class SGSqrExpression : public SGUnaryExpression<T> {
+public:
+ SGSqrExpression(SGExpression<T>* expr = 0)
+ : SGUnaryExpression<T>(expr)
+ { }
+
+ virtual void eval(T& value) const
+ { value = getOperand()->getValue(); value = value*value; }
+
+ using SGUnaryExpression<T>::getOperand;
+};
+
+template<typename T>
+class SGSqrtExpression : public SGUnaryExpression<T> {
+public:
+ SGSqrtExpression(SGExpression<T>* expr = 0)
+ : SGUnaryExpression<T>(expr)
+ { }
+
+ virtual void eval(T& value) const
+ { value = sqrt(getOperand()->getValue()); }
+
+ using SGUnaryExpression<T>::getOperand;
+};
+
+template<typename T>
+class SGTanExpression : public SGUnaryExpression<T> {
+public:
+ SGTanExpression(SGExpression<T>* expr = 0)
+ : SGUnaryExpression<T>(expr)
+ { }
+
+ virtual void eval(T& value) const
+ { value = tan(getOperand()->getValue()); }
+
+ using SGUnaryExpression<T>::getOperand;
+};
+
+template<typename T>
+class SGTanhExpression : public SGUnaryExpression<T> {
+public:
+ SGTanhExpression(SGExpression<T>* expr = 0)
+ : SGUnaryExpression<T>(expr)
+ { }
+
+ virtual void eval(T& value) const
+ { value = tanh(getOperand()->getValue()); }
+
+ using SGUnaryExpression<T>::getOperand;
+};
+
+template<typename T>
+class SGScaleExpression : public SGUnaryExpression<T> {
+public:
+ SGScaleExpression(SGExpression<T>* expr = 0, const T& scale = T(1))
+ : SGUnaryExpression<T>(expr), _scale(scale)
+ { }
+ void setScale(const T& scale)
+ { _scale = scale; }
+ const T& getScale() const
+ { return _scale; }
+
+ virtual void eval(T& value) const
+ { value = _scale * getOperand()->getValue(); }
+
+ virtual SGExpression<T>* simplify()
+ {
+ if (_scale == 1)
+ return getOperand()->simplify();
+ return SGUnaryExpression<T>::simplify();
+ }
+
+ using SGUnaryExpression<T>::getOperand;
+private:
+ T _scale;
+};
+
+template<typename T>
+class SGBiasExpression : public SGUnaryExpression<T> {
+public:
+ SGBiasExpression(SGExpression<T>* expr = 0, const T& bias = T(0))
+ : SGUnaryExpression<T>(expr), _bias(bias)
+ { }
+
+ void setBias(const T& bias)
+ { _bias = bias; }
+ const T& getBias() const
+ { return _bias; }
+
+ virtual void eval(T& value) const
+ { value = _bias + getOperand()->getValue(); }
+
+ virtual SGExpression<T>* simplify()
+ {
+ if (_bias == 0)
+ return getOperand()->simplify();
+ return SGUnaryExpression<T>::simplify();
+ }
+
+ using SGUnaryExpression<T>::getOperand;
+private:
+ T _bias;
+};
+
+template<typename T>
+class SGInterpTableExpression : public SGUnaryExpression<T> {
+public:
+ SGInterpTableExpression(SGExpression<T>* expr,
+ const SGInterpTable* interpTable) :
+ SGUnaryExpression<T>(expr),
+ _interpTable(interpTable)
+ { }
+
+ virtual void eval(T& value) const
+ {
+ if (_interpTable)
+ value = _interpTable->interpolate(getOperand()->getValue());
+ }
+
+ using SGUnaryExpression<T>::getOperand;
+private:
+ SGSharedPtr<SGInterpTable const> _interpTable;
+};
+
+template<typename T>
+class SGClipExpression : public SGUnaryExpression<T> {
+public:
+ SGClipExpression(SGExpression<T>* expr)
+ : SGUnaryExpression<T>(expr),
+ _clipMin(SGMisc<T>::min(-SGLimits<T>::max(), SGLimits<T>::min())),
+ _clipMax(SGLimits<T>::max())
+ { }
+ SGClipExpression(SGExpression<T>* expr,
+ const T& clipMin, const T& clipMax)
+ : SGUnaryExpression<T>(expr),
+ _clipMin(clipMin),
+ _clipMax(clipMax)
+ { }
+
+ void setClipMin(const T& clipMin)
+ { _clipMin = clipMin; }
+ const T& getClipMin() const
+ { return _clipMin; }
+
+ void setClipMax(const T& clipMax)
+ { _clipMax = clipMax; }
+ const T& getClipMax() const
+ { return _clipMax; }
+
+ virtual void eval(T& value) const
+ {
+ value = SGMisc<T>::clip(getOperand()->getValue(), _clipMin, _clipMax);
+ }
+
+ virtual SGExpression<T>* simplify()
+ {
+ if (_clipMin <= SGMisc<T>::min(-SGLimits<T>::max(), SGLimits<T>::min()) &&
+ _clipMax >= SGLimits<T>::max())
+ return getOperand()->simplify();
+ return SGUnaryExpression<T>::simplify();
+ }
+
+ using SGUnaryExpression<T>::getOperand;
+private:
+ T _clipMin;
+ T _clipMax;
+};
+
+template<typename T>
+class SGStepExpression : public SGUnaryExpression<T> {
+public:
+ SGStepExpression(SGExpression<T>* expr = 0,
+ const T& step = T(1), const T& scroll = T(0))
+ : SGUnaryExpression<T>(expr), _step(step), _scroll(scroll)
+ { }
+
+ void setStep(const T& step)
+ { _step = step; }
+ const T& getStep() const
+ { return _step; }
+
+ void setScroll(const T& scroll)
+ { _scroll = scroll; }
+ const T& getScroll() const
+ { return _scroll; }
+
+ virtual void eval(T& value) const
+ { value = apply_mods(getOperand()->getValue()); }
+
+ using SGUnaryExpression<T>::getOperand;
+
+private:
+ T apply_mods(T property) const
+ {
+ T modprop;
+ if (_step > 0) {
+ T scrollval = 0;
+ if(_scroll > 0) {
+ // calculate scroll amount (for odometer like movement)
+ T remainder = _step - fmod(fabs(property), _step);
+ if (remainder < _scroll) {
+ scrollval = (_scroll - remainder) / _scroll * _step;
+ }
+ }
+ // apply stepping of input value
+ if(property > 0)
+ modprop = ((floor(property/_step) * _step) + scrollval);
+ else
+ modprop = ((ceil(property/_step) * _step) + scrollval);
+ } else {
+ modprop = property;
+ }
+ return modprop;
+ }
+
+ T _step;
+ T _scroll;
+};
+
+template<typename T>
+class SGEnableExpression : public SGUnaryExpression<T> {
+public:
+ SGEnableExpression(SGExpression<T>* expr = 0,
+ SGCondition* enable = 0,
+ const T& disabledValue = T(0))
+ : SGUnaryExpression<T>(expr),
+ _enable(enable),
+ _disabledValue(disabledValue)
+ { }
+
+ const T& getDisabledValue() const
+ { return _disabledValue; }
+ void setDisabledValue(const T& disabledValue)
+ { _disabledValue = disabledValue; }
+
+ virtual void eval(T& value) const
+ {
+ if (_enable->test())
+ value = getOperand()->getValue();
+ else
+ value = _disabledValue;
+ }
+
+ virtual SGExpression<T>* simplify()
+ {
+ if (!_enable)
+ return getOperand()->simplify();
+ return SGUnaryExpression<T>::simplify();
+ }
+
+ using SGUnaryExpression<T>::getOperand;
+private:
+ SGSharedPtr<SGCondition> _enable;
+ T _disabledValue;
+};
+
+template<typename T>
+class SGAtan2Expression : public SGBinaryExpression<T> {
+public:
+ SGAtan2Expression(SGExpression<T>* expr0, SGExpression<T>* expr1)
+ : SGBinaryExpression<T>(expr0, expr1)
+ { }
+ virtual void eval(T& value) const
+ { value = atan2(getOperand(0)->getValue(), getOperand(1)->getValue()); }
+ using SGBinaryExpression<T>::getOperand;
+};
+
+template<typename T>
+class SGDivExpression : public SGBinaryExpression<T> {
+public:
+ SGDivExpression(SGExpression<T>* expr0, SGExpression<T>* expr1)
+ : SGBinaryExpression<T>(expr0, expr1)
+ { }
+ virtual void eval(T& value) const
+ { value = getOperand(0)->getValue() / getOperand(1)->getValue(); }
+ using SGBinaryExpression<T>::getOperand;
+};
+
+template<typename T>
+class SGModExpression : public SGBinaryExpression<T> {
+public:
+ SGModExpression(SGExpression<T>* expr0, SGExpression<T>* expr1)
+ : SGBinaryExpression<T>(expr0, expr1)
+ { }
+ virtual void eval(T& value) const
+ { value = mod(getOperand(0)->getValue(), getOperand(1)->getValue()); }
+ using SGBinaryExpression<T>::getOperand;
+private:
+ int mod(const int& v0, const int& v1) const
+ { return v0 % v1; }
+ float mod(const float& v0, const float& v1) const
+ { return fmod(v0, v1); }
+ double mod(const double& v0, const double& v1) const
+ { return fmod(v0, v1); }
+};
+
+template<typename T>
+class SGPowExpression : public SGBinaryExpression<T> {
+public:
+ SGPowExpression(SGExpression<T>* expr0, SGExpression<T>* expr1)
+ : SGBinaryExpression<T>(expr0, expr1)
+ { }
+ virtual void eval(T& value) const
+ { value = pow(getOperand(0)->getValue(), getOperand(1)->getValue()); }
+ using SGBinaryExpression<T>::getOperand;
+};
+
+template<typename T>
+class SGSumExpression : public SGNaryExpression<T> {
+public:
+ SGSumExpression()
+ { }
+ SGSumExpression(SGExpression<T>* expr0, SGExpression<T>* expr1)
+ : SGNaryExpression<T>(expr0, expr1)
+ { }
+ virtual void eval(T& value) const
+ {
+ value = T(0);
+ unsigned sz = SGNaryExpression<T>::getNumOperands();
+ for (unsigned i = 0; i < sz; ++i)
+ value += getOperand(i)->getValue();
+ }
+ using SGNaryExpression<T>::getValue;
+ using SGNaryExpression<T>::getOperand;
+};
+
+template<typename T>
+class SGProductExpression : public SGNaryExpression<T> {
+public:
+ SGProductExpression()
+ { }
+ SGProductExpression(SGExpression<T>* expr0, SGExpression<T>* expr1)
+ : SGNaryExpression<T>(expr0, expr1)
+ { }
+ virtual void eval(T& value) const
+ {
+ value = T(1);
+ unsigned sz = SGNaryExpression<T>::getNumOperands();
+ for (unsigned i = 0; i < sz; ++i)
+ value *= getOperand(i)->getValue();
+ }
+ using SGNaryExpression<T>::getValue;
+ using SGNaryExpression<T>::getOperand;
+};
+
+template<typename T>
+class SGMinExpression : public SGNaryExpression<T> {
+public:
+ SGMinExpression()
+ { }
+ SGMinExpression(SGExpression<T>* expr0, SGExpression<T>* expr1)
+ : SGNaryExpression<T>(expr0, expr1)
+ { }
+ virtual void eval(T& value) const
+ {
+ unsigned sz = SGNaryExpression<T>::getNumOperands();
+ if (sz < 1)
+ return;
+
+ value = getOperand(0)->getValue();
+ for (unsigned i = 1; i < sz; ++i)
+ value = SGMisc<T>::min(value, getOperand(i)->getValue());
+ }
+ using SGNaryExpression<T>::getOperand;
+};
+
+template<typename T>
+class SGMaxExpression : public SGNaryExpression<T> {
+public:
+ SGMaxExpression()
+ { }
+ SGMaxExpression(SGExpression<T>* expr0, SGExpression<T>* expr1)
+ : SGNaryExpression<T>(expr0, expr1)
+ { }
+ virtual void eval(T& value) const
+ {
+ unsigned sz = SGNaryExpression<T>::getNumOperands();
+ if (sz < 1)
+ return;
+
+ value = getOperand(0)->getValue();
+ for (unsigned i = 1; i < sz; ++i)
+ value = SGMisc<T>::max(value, getOperand(i)->getValue());
+ }
+ using SGNaryExpression<T>::getOperand;
+};
+
+typedef SGExpression<int> SGExpressioni;
+typedef SGExpression<float> SGExpressionf;
+typedef SGExpression<double> SGExpressiond;
+typedef SGExpression<bool> SGExpressionb;
+
+/**
+ * Global function to make an expression out of properties.
+
+ <clip>
+ <clipMin>0</clipMin>
+ <clipMax>79</clipMax>
+ <abs>
+ <sum>
+ <rad2deg>
+ <property>sim/model/whatever-rad</property>
+ </rad2deg>
+ <property>sim/model/someother-deg</property>
+ <value>-90</value>
+ </sum>
+ </abs>
+ <clip>
+
+will evaluate to an expression:
+
+SGMisc<T>::clip(abs(deg2rad*sim/model/whatever-rad + sim/model/someother-deg - 90), clipMin, clipMax);
+
+ */
+SGExpression<int>*
+SGReadIntExpression(SGPropertyNode *inputRoot,
+ const SGPropertyNode *configNode);
+
+SGExpression<float>*
+SGReadFloatExpression(SGPropertyNode *inputRoot,
+ const SGPropertyNode *configNode);
+
+SGExpression<double>*
+SGReadDoubleExpression(SGPropertyNode *inputRoot,
+ const SGPropertyNode *configNode);
+
+SGExpression<bool>*
+SGReadBoolExpression(SGPropertyNode *inputRoot,
+ const SGPropertyNode *configNode);
+
+#endif // _SG_EXPRESSION_HXX