]> git.mxchange.org Git - simgear.git/commitdiff
Modified Files:
authorfrohlich <frohlich>
Wed, 26 Dec 2007 19:10:40 +0000 (19:10 +0000)
committerfrohlich <frohlich>
Wed, 26 Dec 2007 19:10:40 +0000 (19:10 +0000)
Makefile.am
Added Files:
SGExpression.cxx SGExpression.hxx: Add not yet complete but already
usable expression tree. Will be used with the panel code.

simgear/structure/Makefile.am
simgear/structure/SGExpression.cxx [new file with mode: 0644]
simgear/structure/SGExpression.hxx [new file with mode: 0644]

index 15a31033c9a7774bd1235addee746c0e89322a0c..e538cfda0c1f4d806d2baa4a41d0ad5f43ff18ca 100644 (file)
@@ -10,6 +10,7 @@ include_HEADERS = \
        subsystem_mgr.hxx \
        SGAtomic.hxx \
        SGBinding.hxx \
+       SGExpression.hxx \
        SGReferenced.hxx \
        SGSharedPtr.hxx \
        SGSmplhist.hxx \
@@ -22,6 +23,7 @@ libsgstructure_a_SOURCES = \
        subsystem_mgr.cxx \
        SGAtomic.cxx \
        SGBinding.cxx \
+       SGExpression.cxx \
        SGSmplhist.cxx \
        SGSmplstat.cxx
 
diff --git a/simgear/structure/SGExpression.cxx b/simgear/structure/SGExpression.cxx
new file mode 100644 (file)
index 0000000..b042cb9
--- /dev/null
@@ -0,0 +1,638 @@
+/* -*-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); }
diff --git a/simgear/structure/SGExpression.hxx b/simgear/structure/SGExpression.hxx
new file mode 100644 (file)
index 0000000..c3e3bac
--- /dev/null
@@ -0,0 +1,801 @@
+/* -*-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