Boost logo

Boost :

Subject: [boost] [spirit][qi] Dynamically combine Boost.Spirit.Qi rules at runtime
From: Daniel F. (the.source_at_[hidden])
Date: 2011-05-07 16:37:42


Hi,

I recently tried to combine an arbitrary number of rules as alternatives
in Boost.Spirit.Qi. Since rules are implemented as objects it seemed
feasible to me. My motivation was to make certain parts of my grammar
easily extensible. Unfortunately, I ran into some problems, so I wrote a
simple program (see attachment for the complete code) demonstrating the
unexpected behavior. Here's the key part:

// "Dynamic" version - Does not compile! :(
/*
std::vector<rule_t> rules;

rules.push_back(qi::char_('a')[qi::_r1 = px::val(0)]);
rules.push_back(qi::char_('b')[qi::_r1 = px::val(1)]);
rules.push_back(qi::char_('c')[qi::_r1 = px::val(2)]);

std::vector<rule_t>::iterator i(rules.begin()), last(rules.end());

rule_t grammar;

grammar = (*i)(qi::_r1); //[no_op]

for(++i; i!=last; ++i)
{
        grammar = grammar.copy() | (*i)(qi::_r1); //[no_op]
}
*/

// "Dynamic" version - Kind of works! :-/

std::vector<rule_t> rules;

rules.push_back(qi::char_('a')[qi::_r1 = px::val(0)]);
rules.push_back(qi::char_('b')[qi::_r1 = px::val(1)]);
rules.push_back(qi::char_('c')[qi::_r1 = px::val(2)]);

std::vector<rule_t>::iterator i(rules.begin()), last(rules.end());

qi::rule<iterator_t, int()> temp;

temp = (*i)(qi::_val); //[no_op]

for(++i; i!=last; ++i)
{
        temp = temp.copy() | (*i)(qi::_val); //[no_op]
}

rule_t grammar;

grammar = temp[qi::_r1 = qi::_1];

Now, I suppose that the first version (commented out) doesn't compile,
because I'm not passing the inherited attribute down to grammar.copy().
I would love to know if there's a better way of doing this than the
workaround that is the second version.

The second version actually compiles and it seems to do the right thing.
However, once I attach a simple semantic action as indicated in the code
using comments (see "[no_op]"), the behavior becomes really weird.
Rather than printing 0,1,2 as before, the program prints 0,0,2. So I'm
wondering, is what I'm trying to accomplish resulting in undefined
behavior? Is this a bug? Or, quite possibly, am I just using something
(e.g. semantic actions?) the wrong way?

Thanks for reading,
Daniel




Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk