Henri Menke
Henri Menke

Reputation: 10939

Templating Spirit X3 parser

In Boost Spirit QI it was easy to template the parser so that it could be instantiated for various attribute types. It is unclear to me how to do this with X3. Consider this stripped down version of the 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";
    }
}

I'd like to template the parser on the attribute type which is currently hardcoded as unsigned. My first guess was to replace

namespace parser {
// ...
}

with

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

which is obviously too naïve. How to do this correctly?

Upvotes: 0

Views: 246

Answers (1)

sehe
sehe

Reputation: 392833

In X3 there's not so much pain in combining parsers dynamically. So I'd write your sample as:

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); })];
}

See it Live On Coliru

Upvotes: 1

Related Questions