使用自定义表达式类提升Spirit Expression Expression解析器

时间:2015-04-14 23:25:40

标签: c++ boost boost-spirit boost-spirit-qi

我正在开发一个测试项目,理想情况是将来构建一个更大的项目(希望构建我自己的脚本语言以获得乐趣),使用我的自定义类将表达式解析为树结构。

我的预期结果是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 ++中做错的事情(我需要了解我的错误在哪里!)。

1 个答案:

答案 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适用于移动语义。