jay1189947
jay1189947

Reputation: 221

Compound Attribute generation in Boost::Spirit parse rule

I have the following parsing rule:

filter = (input >> (qi::repeat(0,2)[char_(';') >> input]))

input is a rule that returns a std::vector<int>, vector that I will just call vec for short.

The question is: What compound attribute would the filter rule return?

I tried:

fusion::vector <vec,std::vector <fusion::vector <char,vec> > >

But it fails and I don't know why.

Upvotes: 2

Views: 245

Answers (1)

sehe
sehe

Reputation: 392979

The attribute types resulting of the parser expressions are quite well-documented. But that can be disorienting and timeconsuming.

Here's a trick: send in a sentinel to detect the attribute type:

struct Sniffer
{
    typedef void result_type;

    template <typename T>
    void operator()(T const&) const { std::cout << typeid(T).name() << "\n"; }
};

then using the folliing parser expression

 (input >> (qi::repeat(0,2)[qi::char_(';') >> input])) [ Sniffer() ]

will dump:

N5boost6fusion7vector2ISt6vectorIsSaIsEES2_INS1_IcS4_EESaIS5_EEEE

which c++filt -1 will tell you represents:

boost::fusion::vector2<
    std::vector<short, std::allocator<short> >, 
    std::vector<boost::fusion::vector2<char, std::vector<short, std::allocator<short> > >, 
                std::allocator<boost::fusion::vector2<char, std::vector<short, std::allocator<short> > > 
            > > 
 >

See it live on Coliru: http://coliru.stacked-crooked.com/view?id=3e767990571f8d0917aae745bccfa520-5c1d29aa57205c65cfb2587775d52d22

boost::fusion::vector2<std::vector<short, std::allocator<short> >, std::vector<std::vector<short, std::allocator<short> >, std::allocator<std::vector<short, std::allocator<short> > > > >

It might be so surprisingly complicated, in part, because char_(";") could have been ';' (or more explicitely lit(';')). Constrast with this (Coliru):

boost::fusion::vector2<
    std::vector<short, ... >, 
    std::vector<std::vector<short, std::allocator<short> >, ... > >

This should answer your question.

Sidenotes: parsing things

Don't underestimate automatic attribute propagation in Spirit. Frequently, you don't have to bother with the exact exposed types of attributes. Instead, rely on the (many) attribute transformations that Spirit uses to assign them to your supplied attribute references.

I trust you know the list-operator (%) in spirit? I'll show you how you can use it without further ado:

vector<vector<short>> data;

qi::parse(f, l, qi::short_ % ',' % ';', data);

Now, if you need to enforce the fact that it may be 1-3 elements, you might employ an eps with a Phoenix action to assert the maximum size:

const string x = "1,2,3;2,3,4;3,4,5";
auto f(begin(x)), l(end(x));

if (qi::parse(f, l, 
        (qi::eps(phx::size(qi::_val) < 2) > (qi::short_ % ',')) % ';'
        , data))
{
    cout << karma::format(karma::short_ % ',' % ';', data) << "\n";
}
cout << "remaining unparsed: '" << std::string(f,l) << "'\n";

Prints:

1,2,3;2,3,4
remaining unparsed: ';3,4,5'

Upvotes: 5

Related Questions