Используйте указатель как синтезированный атрибут в анализаторе буст-спирита

Я хочу написать анализатор духа для дерева объектов, которые я не могу изменить. Чтобы упростить код, я могу использовать пример Expression:

class Expr
{
public:
virtual ~Expr() = 0;
};
Expr::~Expr() {}

class Plus : public Expr
{
public:
Plus (Expr* e1, Expr* e2) : _e1(e1), _e2(e2) {}
~Plus () {}
private:
Expr* _e1;
Expr* _e2;
};

class Num : public Expr
{
public:
Num(double n) : _n(n) {}
private:
double _n;
};

Я проверил документацию и нашел полезную BOOST_ADAPT_STRUCT, но используя
правило, объявленное как:

qi::rule<Iterator, Expr()> r;

Я нарежу объект, когда правило вернет, например, объект Plus.
Итак, я пытаюсь так:

template <typename Iterator>
struct ExprParser : qi::grammar<Iterator, Expr*(), ascii::space_type>
{

ExprParser()
: ExprParser::base_type (start, "expr")
{
expr = qi::double_    [ qi::_val = phoenix::new_<Num>(::_1) ]
| '('
>> expr
>> '+'
>> expr
>> ')'      [ qi::_val = phoenix::new_<Plus>(::_1, ::_2) ]
;

start %= expr;
}

qi::rule<Iterator, Expr*(), ascii::space_type> expr;
qi::rule<Iterator, Expr*(), ascii::space_type> start;
};

Но я получаю ошибку компиляции в присвоении внутри семантических действий. Что я делаю неправильно?

Ответ Сехе хорош! Там где пропущены круглые скобки и неправильное использование заполнителей. Но как насчет утечек памяти при возникновении ошибки синтаксического анализа?

2

Решение

Как указано в документации

в разделе «Важно» вам необходимо использовать заполнители ци с Phoenix. Я проверил исправленный код. Вы можете увидеть это в прямом эфире http://liveworkspace.org/code/48dbfb55a0b7cbd4783b2f9f9a66d6d1.

Обратите внимание, что для компиляции второго семантического действия потребовались дополнительные скобки:

#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>

namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
namespace phoenix = boost::phoenix;

class Expr
{
public:
virtual ~Expr() = 0;
};
Expr::~Expr() {}

class Plus : public Expr
{
public:
Plus (Expr* e1, Expr* e2) : _e1(e1), _e2(e2) {}
~Plus () {}
private:
Expr* _e1;
Expr* _e2;
};

class Num : public Expr
{
public:
Num(double n) : _n(n) {}
private:
double _n;
};

template <typename Iterator>
struct ExprParser : qi::grammar<Iterator, Expr*(), ascii::space_type>
{

ExprParser()
: ExprParser::base_type (start, "expr")
{
expr = qi::double_     [ qi::_val = phoenix::new_<Num>(qi::_1) ]
| ('('
>> expr
>> '+'
>> expr
>> ')')      [ qi::_val = phoenix::new_<Plus>(qi::_1, qi::_2) ]
;

start %= expr;
}

qi::rule<Iterator, Expr*(), ascii::space_type> expr;
qi::rule<Iterator, Expr*(), ascii::space_type> start;
};

int main(int argc, const char *argv[])
{
char input[] = "3.14 + 39";
ExprParser<const char*> p;

const char *f = std::begin(input);
const char *l = std::end(input);
qi::phrase_parse(f, l, p, ascii::space);
}
4

Другие решения

Других решений пока нет …