Boost::Spirit::Qi Auto-rules and conditional actions
This is probably a pathetically easy question, especially since I've been successfully using QI to parse simple structures for a while now, and probably should already know the answer, but 开发者_如何学编程it eludes me regardless...
Let's say we have a container like:
struct GenderTally
{
std::vector<std::string> males;
std::vector<std::string> females;
};
and an input file like
m:Steve;
f:Dora;
f:Martha;
m:Joe;
...
With objects of a specific category appearing in any order and not all objects might come up.
I'll skip the Fusion adaptation here, but it would be two vectors of strings.
My problem is, constructing a grammar that fills a conditional container like that. So far I have worked around this problem by parsing the input multiple times, each time with a specialized grammar. In this example that would be a male and female one.
In the QI mini-XML tutorial, I have gotten the impression that auto rules take away semantic actions, but admittedly, I'm a rookie and still intimidated by hardcore (template) magic APIs like QI use. So, even though I know it's bad, bad form...I'd be utterly grateful to get a real practical example here, since I am experiencing some major deer in headlight blockage. edit: Wouldn't have to be exactly for this struct, just...a practical example of a grammar that uses auto rules, and puts things into appropriate buckets.
What I'd do in your case is this:
BOOST_FUSION_ADAPT_STRUCT(
GenderTally,
(std::vector<std::string>, males)
(std::vector<std::string>, females)
);
rule<Iterator, std::string()> r = +alnum;
rule<Iterator, GenderTally()> g =
*( ("f:" >> r)[phx::push_back(at_c<0>(_val), _1)]
| ("m:" >> r)[phx::push_back(at_c<1>(_val), _1)]
);
not nice, but still the easiest way to deal with what you have.
If you had a different data structure, like
struct Gender {
char gender;
std::string name;
};
typedef std::vector<Gender> GenderTally;
BOOST_FUSION_ADAPT_STRUCT(
Gender,
(char, gender)
(std::string, name)
);
you could write it differently:
rule<Iterator, std::string()> r = +alnum;
rule<Iterator, GenderTally()> g = *(char_('f') >> ':' >> r | char_('m') >> ':' >> r);
But this code might work with SVN trunk only as we have a lot of fixes to attribute handling committed only recently.
The disadvantage is that you need a separate postprocessing step to sort out the males and females.
精彩评论