C ++ Boost qi rule recursive construction

[It seems that my explanations and expectations are not entirely clear, so I added how much I would like to use the function at the end of the message]

I am currently working on grammars using boost qi. I had a loop construct for the rule because I needed to build it from the elements of the vector. I rewrote it with simple types, and it looks like this:

#include <string> // using boost 1.43.0 #include <boost/spirit/include/qi.hpp> #include <boost/spirit/include/qi_eps.hpp> #include <boost/spirit/include/phoenix.hpp> namespace bqi = boost::spirit::qi; typedef const char* Iterator; // function that you can find [here][1] template<typename P> void test_phrase_parser(char const* input, P const& p, bool full_match = true); int main() { // my working rule type: bqi::rule<Iterator, std::string()> myLoopBuiltRule; std::vector<std::string> v; std::vector<std::string>::const_iterator iv; v.push_back("abc"); v.push_back("def"); v.push_back("ghi"); v.push_back("jkl"); myLoopBuiltRule = (! bqi::eps); for(iv = v.begin() ; iv != v.end() ; iv++) { myLoopBuiltRule = myLoopBuiltRule.copy() [ bqi::_val = bqi::_1 ] | bqi::string(*iv) [ bqi::_val = bqi::_1 ] ; } debug(myLoopBuiltRule); char s[] = " abc "; test_phrase_parser(s, myLoopBuiltRule); } 

(It seems that it doesn’t want to be replaced by the corresponding hyperlink, so here is the address for searching for the function test_phrase_parser (): http://www.boost.org/doc/libs/1_43_0/libs/spirit/doc/html/spirit/qi/reference /basics.html )

Everything was for the best in the best of all worlds ... until I had to accept an argument in favor of this rule. Here is a new type of rule:

  // my not-anymore-working rule type: bqi::rule<Iterator, std::string(int*)> myLoopBuiltRule; 

The 'int *' type, for example, is for purposes only, my real pointer addresses a much more complex class ... but still a simple pointer.

I changed my "for" loop accordingly, that is:

  for(iv = v.begin() ; iv != v.end() ; iv++) { myLoopBuiltRule = myLoopBuiltRule.copy()(bqi::_r1) [ bqi::_val = bqi::_1 ] | bqi::string(*iv) [ bqi::_val = bqi::_1 ] ; } 

I had to add a new rule because test_phrase_parser () cannot guess which value should be assigned to the int pointer:

 bqi::rule<Iterator> myInitialRule; 

And change everything that followed the for loop:

 myInitialRule = myLoopBuiltRule((int*)NULL); debug(myLoopBuiltRule); char s[] = " abc "; test_phrase_parser(s, myInitialRule); 

Then everything crashed:

 /home/sylvain.darras/software/repository/software/external/include/boost/boost_1_43_0/boost/spirit/home/qi/nonterminal/rule.hpp:199: error: no matching function for call to 'assertion_failed(mpl_::failed************ (boost::spirit::qi::rule<Iterator, T1, T2, T3, T4>::operator=(const Expr&) 

Then I went crazy and tried:

 myLoopBuiltRule = myLoopBuiltRule.copy(bqi::_r1) [ bqi::_val = bqi::_1 ] | bqi::string(*iv) [ bqi::_val = bqi::_1 ] 

->

 error: no matching function for call to 'boost::spirit::qi::rule<const char*, std::string(int*), boost::fusion::unused_type, boost::fusion::unused_type, boost::fusion::unused_type>::copy(const boost::phoenix::actor<boost::spirit::attribute<1> >&)' 

Then I got angry and wrote:

 myLoopBuiltRule = myLoopBuiltRule(bqi::_r1) [ bqi::_val = bqi::_1 ] | bqi::string(*iv) [ bqi::_val = bqi::_1 ] 

What compiles, since it is completely syntactically correct, but which perfectly overflows the stacks, it happily, beautifully, recursively calls itself to death ...

Then I lost my mind and typed:

 myLoopBuiltRule = jf jhsgf jshdg fjsdgh fjsg jhsdg jhg sjfg jsgh df 

Which, as you probably expect, could not be compiled.

You assume that before writing the aforementioned novel, I checked on the Internet but did not find anything related to copying () and passing arguments at the same time. Has anyone already experienced this problem? Did I miss something?

Be sure that any help will be truly appreciated.

PS: Many thanks to hkaiser, who, not knowing about it, answered many of my problems: qi via google (but this one).


Additional Information:

The purpose of my analyzer is to read files written in a given language L. The purpose of my message is to spread my "context" (that is: definitions of variables and especially constant values, so I can evaluate expressions).

The number of processed types of variables is small, but it is associated with growth, so I save these types in the container class. I can use these managed types.

So, consider the pseudo-algorithm of what I would like to achieve:

 LTypeList myTypes; LTypeList::const_iterator iTypes; bqi::rule<Iterator, LType(LContext*)> myLoopBuiltRule; myLoopBuiltRule = (! bqi::eps); for(iTypes = myTypes.begin() ; iTypes != myTypes.end() ; iTypes++) { myLoopBuiltRule = myLoopBuiltRule.copy()(bqi::_r1) [ bqi::_val = bqi::_1 ] | iTypes->getRule()(bqi::_r1) [ bqi::_val = bqi::_1 ] } 

This is done during initialization, and then myLoopBuiltRule is used and reused with another LContext *, parsing several types. And since some L types can have boundaries that are integer expressions, and that these integer expressions can expose constants, I (I think I) need my inherited attribute to take my LContext and calculate the value of the expression.

I hope that I was more clear in my intentions.

+4
source share
1 answer

Note I just expanded my answer with a few info links. In this particular case, I have a hunch that you can just get away with the Nabialek trick and instead of replacing the inherited attribute with the corresponding qi::locals<> . If I have enough time, I can continue the demonstration later.

Problem Cautions

Please note that when copying proto expression trees and spirit parser expressions, in particular, there are problems with creating dangling links, since the internals should not live to the end of the full expressions contained. See BOOST_SPIRIT_AUTO on Zero to 60 MPH in 2 seconds!

Also see the answers, which also apply to on-the-fly build / layout rules (at run time):

Nabialek Trick

In general, I would strongly advise against combining rules at runtime. Instead, if you want to “add alternatives” to a rule at run time, you can always use qi::symbols<> . The trick is to save the rule in the symbol table and use qi::lazy to invoke the rule. In particular, it is called Nabialek Trick .

I have a toy command line argument parser that demonstrates how you can use this idiom to match a time-defined set of command line arguments:

qi::lazy limitations, what's next?

Unfortunately, qi::lazy does not support inherited arguments, for example,

You might be better off writing a custom parser component, as described here:

I will try to find some time to work out a pattern that later replaces the inherited qi :: locals arguments.

+2
source

Source: https://habr.com/ru/post/1489103/


All Articles