Создание собственного дерева выражений в духе: ци (без Utree или Boost :: Variant)
Прежде всего, если гораздо проще использовать Boost Variant или Utree, то я с ними соглашаюсь и постараюсь решить свои проблемы с ними в другой теме. Тем не менее, я бы очень хотел иметь возможность построить дерево, как у меня ниже.
Фон, игнорируйте, если вы хотите перейти непосредственно к вопросу: я хотел бы иметь возможность построить дерево выражений, которое анализирует что-то вроде
"({a} == 0) && ({b} > 5)"
или стандартное математическое выражение
"(2 * a) + b"
Затем я определю, что такое a и b, прежде чем оценивать свое дерево, примерно так:
a = 10;
double val = myExpression->Evaluate();
Моя проблема возникает, когда я пытаюсь создать попытку анализа строки в моем дереве выражений. Я использую абстрактный классВыражение» который потом выводитПеременная ","Константа» а также "Binary» выражения (это также будет делать унарные, но это не должно влиять на мою проблему. У меня продолжают возникать проблемы с добавлением к дереву, используя мои правила, поэтому я явно делаю что-то не так. У меня с трудом складывается голова вокруг атрибутов.
Мое дерево выглядит следующим образом (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;
}
Теперь, если я создаю дерево вручную, все работает нормально, поэтому я не думаю, что есть проблема с его структурой.
Вот Grammar.h (Множество комментариев, где я пробовал разные вещи, я мог бы их удалить, но, возможно, стоит показать, что яЯ пробовал / где я хочу пойти с этим)
#include "Tree.h"
#include
#include
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 plus = BinaryExpression('+');
boost::phoenix::function minus = BinaryExpression('-');
template
struct ExpressionParser : qi::grammar
{
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
expression;
qi::rule
// eventually will deal with all these rules
equality_expr,
relational_expr,
logical_expr,
additive_expr,
multiplicative_expr,
primary_expr
;
qi::rule
constant
;
qi::rule
variable
;
qi::rule
string
;
};
Так что это действительно взломано, но, надеюсь, это покажет, чего я пытаюсь достичь. Любые советы или советы будут очень признательны. Есть ли пример, когда кто-то построил такое дерево без использования варианта или utree.
Также извините, если я нарушил соглашение, и для моего форматирования, я попытался сделать его максимально читабельным.