【问题标题】:How to create own parser similar to double_ in Boost.Spirit?如何在Boost.Spirit中创建类似于double_的自己的解析器?
【发布时间】:2012-01-18 10:04:16
【问题描述】:

我尝试了解Boost.Spirit 的工作原理。不幸的是,文档对我来说太简洁了,我无法弄清楚它是如何工作的。

那么,让我们来解决我的问题。我尝试为std::complex 类型编写解析器,它的工作方式与内置解析器相同,例如int_double_。我希望它解析不同形式的复数,例如1.2+2i3-i*45*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 规则(以及realdouble() 参数,而不是Complex()。它不应该使占位符成为double-equivalent 类型吗?如果不是,那为什么还要在规则中设置类型?以及如何正确使用它们?

【问题讨论】:

    标签: c++ boost-spirit


    【解决方案1】:

    您可以使用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;
    };
    

    【讨论】:

    • 所以让我正确理解:事情是关于惰性评估,对吧?也就是说,如果没有 phoenix::construct 的惰性求值,编译器不知道 _1 占位符是什么类型?
    • _1 是一个特殊的值和类型。 _1 是替换任何类型的值。 _1 对目标类型一无所知。 (对不起,我的英语不好。)
    • 要更好地了解 boost::spirit 和 boost::phoenix 的内部结构,请查看这个优秀的系列。 cpp-next.com/archive/2010/08/expressive-c-introduction
    猜你喜欢
    • 1970-01-01
    • 2011-10-16
    • 2013-12-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-24
    相关资源
    最近更新 更多