Erstellen eines benutzerdefinierten Ausdrucksbaums in Spirit: Qi (ohne Utree oder Boost :: Variant)

Erstens, wenn es mit Boost Variant oder Utree viel einfacher ist, werde ich mich mit ihnen abfinden und versuchen, meine Probleme mit ihnen in einem anderen Thema zu lösen. Ich würde jedoch sehr gerne in der Lage sein, einen Baum zu bauen, wie ich ihn unten habe.

Hintergrund, ignorieren Sie, wenn Sie direkt zum Thema gehen möchten: Ich möchte in der Lage sein, einen Ausdrucksbaum zu erstellen, der so etwas wie analysiert

"({a} == 0) && ({b} > 5)"

oder ein mathematischer Standardausdruck

"(2 * a) + b"

Ich werde dann definieren, was a und b sind, bevor ich meinen Baum bewerte, ungefähr so:

a = 10;
double val = myExpression->Evaluate();

Mein Problem entsteht, wenn ich versuche, den Versuch, die Zeichenfolge in meinem Ausdrucksbaum zu analysieren, zu erstellen. Ich verwende eine abstrakte Klasse "Ausdruck", die dann die Ausdrücke "Variable", "Konstante" und "Binär" ableitet (dies ist auch unärgerlich, hat jedoch keine Auswirkungen auf mein Problem. Ich habe weiterhin Probleme, dem Baum mithilfe meiner Regeln etwas hinzuzufügen Also mache ich offensichtlich etwas falsch. Es fällt mir schwer, meinen Kopf um die Attribute zu wickeln.

Mein Baum sieht wie folgt aus (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;
}

Wenn ich den Baum jetzt manuell baue, funktioniert alles einwandfrei, sodass ich nicht denke, dass es ein Problem mit der Art und Weise gibt, wie er aufgebaut ist.

Hier ist Grammatik.h (Viele Kommentare von wo ich verschiedene Dinge ausprobiert habe, ich könnte sie entfernen, aber ich kann es wert sein zu zeigen, was ich ausprobiert habe / wohin ich damit gehen möchte)

#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
        ;
};

Das ist also eine wirklich gehackte Sache, aber hoffentlich zeigt sie, was ich erreichen will. Für Ratschläge oder Tipps wäre ich sehr dankbar. Gibt es ein Beispiel, in dem jemand einen Baum wie diesen erstellt hat, ohne variant oder utree zu verwenden?

Es tut mir auch leid, wenn ich gegen die Konvention verstoßen habe, und ich habe versucht, sie für meine Formatierung so lesbar wie möglich zu machen.

Antworten auf die Frage(1)

Ihre Antwort auf die Frage