+namespace simgear
+{
+ namespace expression
+ {
+ 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<Value> _bindings;
+ };
+
+ template<int Size> 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;
+ std::vector<VariableBinding> bindings;
+ };
+
+ class Parser {
+ public:
+ typedef Expression* (*exp_parser)(const SGPropertyNode* exp,
+ Parser* parser);
+ void addParser(const std::string& name, exp_parser parser)
+ {
+ getParserMap().insert(std::make_pair(name, parser));
+ }
+ Expression* read(const SGPropertyNode* exp)
+ {
+ ParserMap& map = getParserMap();
+ ParserMap::iterator itr = map.find(exp->getName());
+ if (itr == map.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,
+ std::vector<Expression*>& result);
+ /**
+ * Function that parses a property tree, producing an expression.
+ */
+ typedef std::map<const std::string, exp_parser> ParserMap;
+ virtual ParserMap& getParserMap() = 0;
+ /**
+ * After an expression is parsed, the binding layout may contain
+ * references that need to be bound during evaluation.
+ */
+ BindingLayout& getBindingLayout() { return _bindingLayout; }
+ protected:
+ BindingLayout _bindingLayout;
+ };
+
+ class ExpressionParser : public Parser
+ {
+ public:
+ ParserMap& getParserMap()
+ {
+ return ParserMapSingleton::instance()->_parserTable;
+ }
+ static void addExpParser(const std::string&, exp_parser);
+ protected:
+ struct ParserMapSingleton : public simgear::Singleton<ParserMapSingleton>
+ {
+ ParserMap _parserTable;
+ };
+ };
+
+ /**
+ * Constructor for registering parser functions.
+ */
+ struct ExpParserRegistrar
+ {
+ ExpParserRegistrar(const std::string& token, Parser::exp_parser parser)
+ {
+ ExpressionParser::addExpParser(token, parser);
+ }
+ };
+
+ }
+
+ /**
+ * Access a variable definition. Use a location from a BindingLayout.
+ */
+ template<typename T>
+ class VariableExpression : public ::SGExpression<T> {
+ 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<const T *>(&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<typename T, typename OpType>
+ class GeneralNaryExpression : public ::SGExpression<T> {
+ public:
+ typedef OpType operand_type;
+ unsigned getNumOperands() const
+ { return _expressions.size(); }
+ const ::SGExpression<OpType>* getOperand(unsigned i) const
+ { return _expressions[i]; }
+ ::SGExpression<OpType>* getOperand(unsigned i)
+ { return _expressions[i]; }
+ unsigned addOperand(::SGExpression<OpType>* expression)
+ {
+ if (!expression)
+ return ~unsigned(0);
+ _expressions.push_back(expression);
+ return _expressions.size() - 1;
+ }
+
+ template<typename Iter>
+ void addOperands(Iter begin, Iter end)
+ {
+ for (Iter iter = begin; iter != end; ++iter)
+ {
+ addOperand(static_cast< ::SGExpression<OpType>*>(*iter));
+ }
+ }
+
+ 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();
+ }
+
+ simgear::expression::Type getOperandType() const
+ {
+ return simgear::expression::TypeTraits<OpType>::typeTag;
+ }
+
+ protected:
+ GeneralNaryExpression()
+ { }
+ GeneralNaryExpression(::SGExpression<OpType>* expr0,
+ ::SGExpression<OpType>* expr1)
+ { addOperand(expr0); addOperand(expr1); }
+
+ std::vector<SGSharedPtr<SGExpression<OpType> > > _expressions;
+ };
+
+ /**
+ * A predicate that wraps, for example the STL template predicate
+ * expressions like std::equal_to.
+ */
+ template<typename OpType, template<typename PredOp> class Pred>
+ class PredicateExpression : public GeneralNaryExpression<bool, OpType> {
+ public:
+ PredicateExpression()
+ {
+ }
+ PredicateExpression(::SGExpression<OpType>* expr0,
+ ::SGExpression<OpType>* expr1)
+ : GeneralNaryExpression<bool, OpType>(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<OpType> _pred;
+ };
+
+ template<template<typename OT> class Pred, typename OpType>
+ PredicateExpression<OpType, Pred>*
+ makePredicate(SGExpression<OpType>* op1, SGExpression<OpType>* op2)
+ {
+ return new PredicateExpression<OpType, Pred>(op1, op2);
+ }
+
+ template<typename OpType>
+ class EqualToExpression : public PredicateExpression<OpType, std::equal_to>
+ {
+ public:
+ EqualToExpression() {}
+ EqualToExpression(::SGExpression<OpType>* expr0,
+ ::SGExpression<OpType>* expr1)
+ : PredicateExpression<OpType, std::equal_to>(expr0, expr1)
+ {
+ }
+ };
+
+ template<typename OpType>
+ class LessExpression : public PredicateExpression<OpType, std::less>
+ {
+ public:
+ LessExpression() {}
+ LessExpression(::SGExpression<OpType>* expr0, ::SGExpression<OpType>* expr1)
+ : PredicateExpression<OpType, std::less>(expr0, expr1)
+ {
+ }
+ };
+
+ template<typename OpType>
+ class LessEqualExpression
+ : public PredicateExpression<OpType, std::less_equal>
+ {
+ public:
+ LessEqualExpression() {}
+ LessEqualExpression(::SGExpression<OpType>* expr0,
+ ::SGExpression<OpType>* expr1)
+ : PredicateExpression<OpType, std::less_equal>(expr0, expr1)
+ {
+ }
+ };
+
+ class NotExpression : public ::SGUnaryExpression<bool>
+ {
+ public:
+ NotExpression(::SGExpression<bool>* expr = 0)
+ : ::SGUnaryExpression<bool>(expr)
+ {
+ }
+ void eval(bool& value, const expression::Binding* b) const
+ {
+ value = !getOperand()->getValue(b);
+ }
+ };
+
+ class OrExpression : public ::SGNaryExpression<bool>
+ {
+ public:
+ void eval(bool& value, const expression::Binding* b) const
+ {
+ value = false;
+ for (int i = 0; i < (int)getNumOperands(); ++i) {
+ value = value || getOperand(i)->getValue(b);
+ if (value)
+ return;
+ }
+ }
+ };
+
+ class AndExpression : public ::SGNaryExpression<bool>
+ {
+ public:
+ void eval(bool& value, const expression::Binding* b) const
+ {
+ value = true;
+ for (int i = 0; i < (int)getNumOperands(); ++i) {
+ value = value && getOperand(i)->getValue(b);
+ if (!value)
+ return;
+ }
+ }
+ };
+
+ /**
+ * Convert an operand from OpType to T.
+ */
+ template<typename T, typename OpType>
+ class ConvertExpression : public GeneralNaryExpression<T, OpType>
+ {
+ public:
+ ConvertExpression() {}
+ ConvertExpression(::SGExpression<OpType>* expr0)
+ {
+ this->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;
+ }
+ };
+}