Note that there are some explanatory texts on larger screens.

plurals
  1. PODynamically combine Boost.Spirit.Qi rules at runtime (arbitrary number of alternatives)
    primarykey
    data
    text
    <p>I was wondering whether there is a way in Boost.Spirit.Qi to dynamically combine an arbitrary number of rules at runtime. The inner workings of Boost.Spirit are still a bit of a mystery to me, but since rules are implemented as objects it seems feasible. My motivation is to make certain parts of my grammar easily extendable.</p> <p>Consider the following contrived example:</p> <pre><code>namespace qi = boost::spirit::qi; namespace px = boost::phoenix; typedef std::string::const_iterator iterator_t; template&lt;typename Expr&gt; inline bool parse_full(const std::string&amp; input, const Expr&amp; expr) { iterator_t first(input.begin()), last(input.end()); bool result = qi::phrase_parse(first, last, expr, boost::spirit::ascii::space); return first == input.end() &amp;&amp; result; } void no_op() {} int main(int argc, char *argv[]) { int attr = -1; // "Static" version - Works fine! /* qi::rule&lt;iterator_t, void(int&amp;)&gt; grammar; qi::rule&lt;iterator_t, void(int&amp;)&gt; ruleA = qi::char_('a')[qi::_r1 = px::val(0)]; qi::rule&lt;iterator_t, void(int&amp;)&gt; ruleB = qi::char_('b')[qi::_r1 = px::val(1)]; qi::rule&lt;iterator_t, void(int&amp;)&gt; ruleC = qi::char_('c')[qi::_r1 = px::val(2)]; grammar = ruleA(qi::_r1) | //[no_op] ruleB(qi::_r1) | //[no_op] ruleC(qi::_r1); //[no_op] */ // "Dynamic" version - Does not compile! :( std::vector&lt;qi::rule&lt;iterator_t, void(int&amp;)&gt;&gt; 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&lt;qi::rule&lt;iterator_t, void(int&amp;)&gt;&gt;::iterator i(rules.begin()), last(rules.end()); qi::rule&lt;iterator_t, void(int&amp;)&gt; grammar; grammar = (*i)(qi::_r1); for(++i; i!=last; ++i) { grammar = grammar.copy() | (*i)(qi::_r1); } // Tests if(parse_full("a", grammar(px::ref(attr)))) std::cout &lt;&lt; attr &lt;&lt; std::endl; if(parse_full("b", grammar(px::ref(attr)))) std::cout &lt;&lt; attr &lt;&lt; std::endl; if(parse_full("c", grammar(px::ref(attr)))) std::cout &lt;&lt; attr &lt;&lt; std::endl; std::cin.ignore(std::numeric_limits&lt;std::streamsize&gt;::max(), '\n'); return 0; } </code></pre> <p>The error given by Visual Studio 2010 is:</p> <pre><code>error C2440: 'initializing' : cannot convert from 'boost::fusion::void_' to 'int &amp;' </code></pre> <p>My suspicion is that this is caused by not passing the inherited attribute to <code>grammar.copy()</code>. Unfortunately, I couldn't find an easy way of doing this, so I opted for a workaround. As a result, I have one last version (and I would already like to thank anyone who stuck around until now!). This one actually seems to work:</p> <pre><code> // "Dynamic" version - Kind of works! :-/ std::vector&lt;qi::rule&lt;iterator_t, void(int&amp;)&gt;&gt; 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&lt;qi::rule&lt;iterator_t, void(int&amp;)&gt;&gt;::iterator i(rules.begin()), last(rules.end()); qi::rule&lt;iterator_t, int()&gt; temp; temp = (*i)(qi::_val); //[no_op] for(++i; i!=last; ++i) { temp = temp.copy() | (*i)(qi::_val); //[no_op] } qi::rule&lt;iterator_t, void(int&amp;)&gt; grammar; grammar = temp[qi::_r1 = qi::_1]; </code></pre> <p>However, once I attach a simple semantic action (such as "[no_op]"), the behavior becomes really weird. Rather than printing 0,1,2 as before, it 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?</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload