我正在开发一个测试项目,理想情况是将来构建一个更大的项目(希望构建我自己的脚本语言以获得乐趣),使用我的自定义类将表达式解析为树结构。
我的预期结果是Expression
可以被评估,但实际结果是一个具有空AbstractExpression
指针的表达式。
表达类
注意:State
是我计划用来保存评估所需的变量和其他信息的结构
class AbstractExpression
{
public:
AbstractExpression()
{
}
virtual double const Evaluate(State &state) = 0;
virtual ~AbstractExpression() {}
};
class BinaryExpression : public AbstractExpression
{
public:
typedef double(*OperatorFunction)(double, double);
BinaryExpression(char op, AbstractExpression *leftOperand, AbstractExpression *rightOperand)
{
this->left = leftOperand;
this->right = rightOperand;
this->operatorFunction = GetFunction(std::string(1, op));
}
BinaryExpression(std::string op, AbstractExpression *leftOperand, AbstractExpression *rightOperand)
{
this->left = leftOperand;
this->right = rightOperand;
this->operatorFunction = GetFunction(op);
}
~BinaryExpression()
{
delete this->left;
delete this->right;
}
double const Evaluate(State &state)
{
return this->operatorFunction(this->left->Evaluate(state), this->right->Evaluate(state));
}
private:
AbstractExpression *left;
AbstractExpression *right;
OperatorFunction operatorFunction;
static double Add(double left, double right) { return left + right; }
//<... A bunch of definitions like the above ...>
static double NoOp(double left, double right) { return 0; }
static BinaryExpression::OperatorFunction GetFunction(std::string op)
{
if (op.compare("+") == 0)
{
return &Add;
}
//<... Lost of else if statements ...>
else
{
return &NoOp;
}
}
};
class ConstantExpression : public AbstractExpression
{
public:
ConstantExpression(double value)
{
this->value = value;
}
ConstantExpression()
{
this->value = 0;
}
double const Evaluate(State &state)
{
return this->value;
}
private:
double value;
};
class Expression : public AbstractExpression
{
private:
AbstractExpression *expression;
public:
Expression()
{
}
Expression(AbstractExpression *expression)
{
this->expression = expression;
}
~Expression()
{
//delete this->expression;
}
double const Evaluate(State &state)
{
return this->expression->Evaluate(state);
}
};
分析器
namespace Test
{
template <typename Iterator>
struct StatementGrammar : qi::grammar < Iterator, Expression(), ascii::space_type >
{
StatementGrammar() : StatementGrammar::base_type(expression)
{
expression =
constant[qi::_val = phoenix::construct<Expression>(qi::_1)]
;
constant =
qi::double_[qi::_val = &(phoenix::construct<ConstantExpression>(qi::_1))]
;
}
qi::rule < Iterator, Expression(), ascii::space_type > expression;
//qi::rule < Iterator, BinaryExpression*(), ascii::space_type> binaryExpression;
qi::rule < Iterator, ConstantExpression*(), ascii::space_type> constant;
};
}
下面是我用来调用解析器的代码:
std::string string;
Expression exp;
std::getline(std::cin, string);
using boost::spirit::ascii::space;
typedef std::string::const_iterator iterator_type;
Test::StatementGrammar<iterator_type> grammar;
std::string::const_iterator iter = string.begin();
std::string::const_iterator end = string.end();
bool result = qi::phrase_parse(iter, end, grammar, space, epx);
if (result)
{
State s;
double foo = exp.Evaluate(s);
}
else
{
std::cout << "No Match!" << std::endl;
}
return 0;
我主要是一个C#开发人员(读:我是C ++ / Boost noob)请纠正我在C ++中做错的事情(我需要了解我的错误在哪里!)。
答案 0 :(得分:1)
在这一行:
qi::double_[qi::_val = &(phoenix::construct<ConstantExpression>(qi::_1))]
phoenix::construct
构建一个临时ConstantExpression
,其地址稍后与运营商&
一起使用。通常采用临时地址会导致编译错误,但很可能这种语言功能在phoenix实现中丢失了。你可能想做的是:
qi::double_[qi::_val = phoenix::new_<ConstantExpression>(qi::_1)]
作为旁注,Expression
应该实现对包装表达式的某种引用计数,以便在完成时调用delete
。理想情况下,你不需要在这里重新计算,因为移动语义/唯一所有权就足够了,但我不相信Spirit v2适用于移动语义。