2

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.

jay1189947
  • 201
  • 1
  • 2
  • 9
  • Oh. Lol I somehow read `vec of short` instead of _for short_. Oh well, `s/short/int/` in my answer wlll do – sehe Jul 26 '13 at 08:37
  • See also [Detecting the parameter types in a Spirit semantic action](http://stackoverflow.com/a/9404955/85371) – sehe Jul 26 '13 at 09:33

1 Answers1

5

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'
sehe
  • 374,641
  • 47
  • 450
  • 633
  • First of all, thanks for the detailed and informative answer! The strange thing is that the attribute that your code suggests is the same as the one I tried! The only difference is that you are explicitly specifying a `fusion::vector2` and I was just naming it a `fusion::vector` that takes 2 template arguments. To my understanding, both should be equivalent. To sum it up, this works: `fusion::vector > >` while this doesn't: `fusion::vector > >` I don't know if it's a bug or what. – jay1189947 Jul 26 '13 at 13:25
  • Notice how I never had to specify a `fusion::vector2` in the first one, so I don't really know why I have to do it for the second (Bug maybe?). Your answer and attribute detector guided me in the right direction, so I'm voting your answer as correct, but I still don't know why I'm forced to use `fusion::vector2` in this case. – jay1189947 Jul 26 '13 at 13:42
  • @jay1189947 Hmm. I think the most important take-away is _this_: Notice how I never even specify **any** `fusion::*` type _at all_. In my opinion, `fusion` sequences are an implementation detail, that you should only deal with when writing customization points, or perhaps when adapting structs (BOOST_FUSION_ADAPT_STRUCT). – sehe Jul 26 '13 at 14:55
  • Also, note that container attributes have more 'magical' properties (like `*int_ >> ';' >> *int_` can be used with a rule that exposes only a single `std::vector`. But all this is getting a bit far afield. I suggest that experimenting a bit (and perhaps looking at the mechanics while doing so) is the best way to get intimate with the levels of convenience (and sometimes, surprise) that Boost Spirit has to offer. – sehe Jul 26 '13 at 14:56
  • The thing is that I'm working with more complex structures, so I can't use the default synthesized attributes and need to use the rule context to build the attributes myself through semantic actions. I have read the documentation thoroughly multiple times, so I know how compound attributes are synthesized, which is precisely why I'm so confused that my first example doesn't work (and that I still claim is a bug). Thanks again for your time and replies! – jay1189947 Jul 26 '13 at 15:59
  • @jay1189947 I can see your surprise. I'm not entirely convinced you should be meddling with this in your semantic actions. You'll interested in at least the following two articles: [BOOST_SPIRIT_ACTIONS_ALLOW_ATTR_COMPAT (Kaiser, Feb2011)](http://boost.2283326.n4.nabble.com/Re-Spirit-general-Attribute-compatibility-and-Semantic-actions-td3306863.html) which you can just enable. Also, consider using customization points to decouple the attribute handling from your grammar definition; Search [tag:boost-spirit] for "traits" or "customization points". – sehe Jul 26 '13 at 19:23
  • This way you can achieve a grammar without semantic actions: [Semantic Actions Are Evil?](http://stackoverflow.com/questions/8259440/boost-spirit-semantic-actions-are-evil). Finally, a link to the documentation section on customization points: http://www.boost.org/doc/libs/1_54_0/libs/spirit/doc/html/spirit/advanced/customize.html – sehe Jul 26 '13 at 19:25