Reputation: 221
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
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.
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