模板精神X3解析器

时间:2018-01-28 04:21:12

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

在Boost Spirit QI中,很容易对解析器进行模板化,以便可以针对各种属性类型进行实例化。我不清楚如何使用X3做到这一点。考虑roman numerals parser example

的这个精简版本
#include <iostream>
#include <iterator>
#include <string>

#include <boost/spirit/home/x3.hpp>

namespace parser {

namespace x3 = boost::spirit::x3;

struct numbers_ : x3::symbols<unsigned> {
    numbers_() {
        add
            ("I"    , 1)
            ("II"   , 2)
            ("III"  , 3)
            ("IV"   , 4)
            ("V"    , 5)
            ("VI"   , 6)
            ("VII"  , 7)
            ("VIII" , 8)
            ("IX"   , 9)
            ;
    }
} numbers;

x3::rule<class roman, unsigned> const roman = "roman";

auto init = [](auto &x) { x3::_val(x) = 0; };
auto add = [](auto &x) { x3::_val(x) += x3::_attr(x); };

auto const roman_def = x3::eps [init] >> numbers [add];

BOOST_SPIRIT_DEFINE(roman);

}

int main()
{
    std::string input = "V";
    auto iter = input.begin();
    auto end = input.end();
    unsigned result;

    bool r = parse(iter, end, parser::roman, result);

    if (r && iter == end) {
        std::cout << "Success :) Result = " << result << '\n';
    } else {
        std::cout << "Failed :(\n";
    }
}

我想在当前硬编码为unsigned的属性类型上模板化解析器。我的第一个猜测是替换

namespace parser {
// ...
}

template < typename int_t >
struct parser {
// ...
};

这显然太天真了。如何正确地做到这一点?

1 个答案:

答案 0 :(得分:1)

在X3中,动态组合解析器并没有那么大的痛苦。所以我把你的样本写成:

template <typename Attribute>
auto make_roman() {
    using namespace boost::spirit::x3;

    struct numbers_ : symbols<Attribute> {
        numbers_() { this-> add
            ("I", Attribute{1}) ("II", Attribute{2}) ("III", Attribute{3}) ("IV", Attribute{4})
            ("V", Attribute{5}) ("VI", Attribute{6}) ("VII", Attribute{7}) ("VIII", Attribute{8})
            ("IX", Attribute{9}) ;
        }
    } numbers;

    return rule<class roman, Attribute> {"roman"} = 
        eps        [([](auto &x) { _val(x) = 0; })] 
        >> numbers [([](auto &x) { _val(x) += _attr(x); })];
}

查看 Live On Coliru