First of all, if it is much easier using either Boost Variant or Utree, then I will settle with them, and i will try to solve my issues with them in another topic. However, i would very much like to be able to build a tree like i have below.
Background, ignore if you would like to go straight to the issue: I would like to be able to build an expression tree which parses something like
"({a} == 0) && ({b} > 5)" or a standard mathmatic expression
"(2 * a) + b" I will then define what a and b are before i evaluate my tree, something like this:
a = 10; double val = myExpression->Evaluate(); My issue comes from when i try to build the try to parse the string into my Expression Tree. I am using an abstract class "Expression" which then derives "Variable", "Constant" and "Binary" expressions (it will also do unary, but it shouldnt effect my problem. I keep having problems with adding to the tree using my rules, so im clearly doing something wrong. Im having a hard time wrapping my head around the attributes.
My Tree is as follows (Tree.h):
class BinaryExpression; typedef double (*func)(double, double); class Expression { public: virtual double Evaluate() = 0; }; class BinaryExpression : public Expression { private: Expression* lhs; Expression* rhs; func method; double Evaluate(); public: BinaryExpression(void); BinaryExpression(char op, Expression* lhs, Expression* rhs); BinaryExpression(char op); void operator()(Expression* lhs, Expression* rhs); }; class ConstantExpression : public Expression { private: double value; public: ConstantExpression(void); ConstantExpression(char op); ConstantExpression(double val); double Evaluate(); }; // Require as many types as there are fields in expression? static double a; static double b; class VariableExpression : public Expression { private: char op; public: VariableExpression(char op); double Evaluate(); }; BOOST_FUSION_ADAPT_STRUCT( BinaryExpression, (Expression*, lhs) (Expression*, rhs) (func, method) ) BOOST_FUSION_ADAPT_STRUCT( VariableExpression, (char, op) ) BOOST_FUSION_ADAPT_STRUCT( ConstantExpression, (double, op) ) Tree.cpp
typedef double (*func)(double, double); ///////////////////////////////////////////////////////////////////////////// // BINARY EXPRESSION //////////////////////////////////////////////////////////////////////////// BinaryExpression::BinaryExpression(void) {} BinaryExpression::BinaryExpression(char op, Expression* lhs, Expression* rhs) { this->lhs = lhs; this->rhs = rhs; // Example, methods are held in another header if (op == '+') method = Add; else if (op == '-') method = Subtract; } double BinaryExpression::Evaluate() { return method(lhs->Evaluate(), rhs->Evaluate()); } BinaryExpression::BinaryExpression(char op) { if (op == '+') method = Add; else if (op == '-') method = Subtract; } void BinaryExpression::operator()(Expression* lhs, Expression* rhs) { this->lhs = lhs; this->rhs = rhs; } ///////////////////////////////////////////////////////////////////////////// // CONSTANT EXPRESSION //////////////////////////////////////////////////////////////////////////// ConstantExpression::ConstantExpression() {} ConstantExpression::ConstantExpression(char op) { this->value = op - 48; } ConstantExpression::ConstantExpression(double val) { value = val; } double ConstantExpression::Evaluate() { return value; } ///////////////////////////////////////////////////////////////////////////// // VARIABLE EXPRESSION //////////////////////////////////////////////////////////////////////////// VariableExpression::VariableExpression(char op) { this->op = op; } double VariableExpression::Evaluate() { // a and b are defined in the header, and are used to fill in the variables we want to evaluate if (op == 'a') return a; if (op == 'b') return b; return 0; } Now if i build the tree manually it all works fine, so i dont think theres an issue with the way it is structured.
Here is Grammar.h (Lots of comments from where i tried various things, i could remove them, but i may be worth showing what i've tried / where i want to go with it)
#include "Tree.h" #include <boost/spirit/include/qi.hpp> #include <boost/spirit/include/phoenix_function.hpp> namespace qi = boost::spirit::qi; namespace ascii = boost::spirit::ascii; qi::_1_type _1; qi::_2_type _2; // Pass functions to boost boost::phoenix::function<BinaryExpression> plus = BinaryExpression('+'); boost::phoenix::function<BinaryExpression> minus = BinaryExpression('-'); template <typename Iterator> struct ExpressionParser : qi::grammar<Iterator, BinaryExpression(), ascii::space_type> { ExpressionParser() : ExpressionParser::base_type(expression) { qi::_3_type _3; qi::_4_type _4; qi::char_type char_; qi::uint_type uint_; qi::_val_type _val; qi::raw_type raw; qi::lexeme_type lexeme; qi::alpha_type alpha; qi::alnum_type alnum; qi::bool_type bool_; qi::double_type double_; expression = //? additive_expr [_val = _1] ; //equality_expr = // relational_expr >> // *(lit("==") > relational_expr) [/*Semantice action to add to tree*/] // ; additive_expr = primary_expr >> ( '+' > primary_expr) [plus(_val, _1)] | ( '-' > primary_expr) [minus(_val, _1)] ; // Also tried "_val = plus(_1, _2)" primary_expr = constant [_val = _1] | variable [_val = _1] //| '(' > expression > ')' [_val = _1] ; string %= '{' >> *(char_ - '}') >> '}' ; // Returns ConstantExpression constant = double_ [_val = _1]; // Returns VariableExpression variable = char_ [_val = _1] ; } // constant expression = double // variable expression = string qi::rule<Iterator, BinaryExpression(), ascii::space_type> expression; qi::rule<Iterator, BinaryExpression(), ascii::space_type> // eventually will deal with all these rules equality_expr, relational_expr, logical_expr, additive_expr, multiplicative_expr, primary_expr ; qi::rule<Iterator, ConstantExpression(), ascii::space_type> constant ; qi::rule<Iterator, VariableExpression(), ascii::space_type> variable ; qi::rule<Iterator, std::string(), ascii::space_type> string ; }; So this is a really hacked apart, but hopefully it will show what im trying to achieve. Any advice or tips would be really appreciated. Is there an example where someone has built a tree like this without using variant or utree.
Also sorry if ive broken convention, and for my formatting, i tried to make it as readable as possible.