Как создать собственный парсер, похожий на double_ в Boost.Spirit? - PullRequest
0 голосов
/ 18 января 2012

Я пытаюсь узнать, как работает Boost.Spirit . К сожалению, документация для меня слишком лаконична, и я не могу понять, как она на самом деле работает.

Итак, давайте перейдем к моей проблеме. Я пытаюсь написать парсер для типа std::complex, который будет работать так же, как встроенные парсеры, например int_ или double_. Я хочу, чтобы он разбирал комплексное число в разных формах, таких как 1.2+2i, 3-i*4, 5*i и т. Д. И, если честно, я застрял и не знаю, что делать. Я пробовал этот подход:

typedef std::complex<double> Complex;

struct complex_parser : qi::grammar<Iterator, Complex(), ascii::space_type>
{
    complex_parser() : complex_parser::base_type(value)
    {
        real = (
            double_[_val = _1]
        );

        imaginary = (
            ( double_[_val = Complex(0.0, _1)] >> -(lit('*')) >> 'i' )
          | ( 'i' >> -(lit('*')) >> double_[_val = Complex(0.0, _1)] )
        );

        value = (
            imaginary[_val = _1]
          | real[_val = _1] >> -('+' >> imaginary[_val += _1])
          | real[_val = _1] >> -('-' >> imaginary[_val -= _1])
        );
    }

    qi::rule<Iterator, Complex(), ascii::space_type> value;
    qi::rule<Iterator, double(), ascii::space_type> real;
    qi::rule<Iterator, double(), ascii::space_type> imaginary;
};

Но это не работает. Даже не компилируется, потому что когда imaginary анализируется, заполнитель _1 не является double типом:

ошибка C2665: 'std :: complex :: complex': ни одна из 6 перегрузок не может преобразовать все типы аргументов [...] при попытке сопоставить список аргументов '(double, const boost :: spirit :: _1_type) '

Но почему? Я дал imaginary правило (а также real) double() параметр вместо Complex(). Разве это не должно сделать заполнитель double -эквивалентного типа? Если нет, то зачем вообще устанавливать тип в правилах? И как правильно их использовать?

1 Ответ

1 голос
/ 18 января 2012

Вы можете использовать boost :: phoenix :: construct .

#define BOOST_SPIRIT_USE_PHOENIX_V3

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

namespace qi = boost::spirit::qi;
using namespace boost::spirit::qi;
namespace phx = boost::phoenix;

typedef std::complex<double> Complex;
typedef std::string::iterator Iterator;

struct complex_parser : qi::grammar<Iterator, Complex(), ascii::space_type>
{
    complex_parser() : complex_parser::base_type(value)
    {
        real = (
            double_[_val = _1]
        );

        imaginary = (
            ( double_[_val = phx::construct<Complex>(0.0, _1)] >> -(lit('*')) >> 'i' )
          | ( 'i' >> -(lit('*')) >> double_[_val = phx::construct<Complex>(0.0, _1)] )
        );

        value = (
            imaginary[_val = _1]
          | real[_val = _1] >> -('+' >> imaginary[_val += _1])
          | real[_val = _1] >> -('-' >> imaginary[_val -= _1])
        );
    }

    qi::rule<Iterator, Complex(), ascii::space_type> value;
    qi::rule<Iterator, double(), ascii::space_type> real;
    qi::rule<Iterator, Complex(), ascii::space_type> imaginary;
};
...