[Boost.Spirit] Skippers for sub-grammars
Hello, I've decided to break up my parser into sub-grammars to improve both the readability and compile time. I'm now trying to specify a skip parser for one of the sub-grammars, but I don't know how to do it. I'm familiar with specifying a skip parser in the parse functions, but not in the grammar itself. Could somebody please provide an example? Thanks. #include <boost/spirit/include/qi.hpp> #include <string> #include <iostream> using namespace boost::spirit; using namespace boost::spirit::ascii; template<class Iterator> struct sub_grammar_skipper: qi::grammar<Iterator> { sub_grammar_skipper(): sub_grammar_skipper::base_type(start) { start = ( *((char_ - eol) - lit(':')) >> lit(':') >> *blank >> *(char_ - eol) >> eol ) ; } qi::rule<Iterator> start; }; template<class Iterator> struct sub_grammar: qi::grammar<Iterator> { sub_grammar(): sub_grammar::base_type(start) { string = ( *(char_ - eol) ) ; name %= ( lit("NAME:") >> *blank >> string >> eol ) ; start = ( name ) ; } qi::rule<Iterator, std::string()> string; qi::rule<Iterator, std::string()> name; qi::rule<Iterator> start; }; template<class Iterator> struct test_grammar: qi::grammar<Iterator/*, sub_grammar_skipper<Iterator> */> { test_grammar(): test_grammar::base_type(start) { start = ( sg >> int_ ) ; } sub_grammar<Iterator> sg; qi::rule<Iterator/*, sub_grammar_skipper<Iterator> */> start; }; int main() { std::string str("NAME: John\nBLAH: blah\n10"); typedef std::string::const_iterator iterator; iterator first = str.begin(); iterator last = str.end(); test_grammar<iterator> tg; bool r = parse(first, last, tg); if(r && first == last) { std::cout << "Success!\n"; } else { std::cerr << "Failed to parse at: " << std::string(first, last) << std::endl; return 1; } return 0; }
Vitaly Budovski wrote:
Hello,
I've decided to break up my parser into sub-grammars to improve both the readability and compile time. I'm now trying to specify a skip parser for one of the sub-grammars, but I don't know how to do it. I'm familiar with specifying a skip parser in the parse functions, but not in the grammar itself. Could somebody please provide an example? Thanks.
I believe you need to make it a template argument and pass it on to each of the rules in the sub-grammar. HTH Bill Somerville.
Hi! On Fri, Oct 22, 2010 at 10:50 AM, Vitaly Budovski <vbudovski+news@gmail.com<vbudovski%2Bnews@gmail.com>
wrote:
qi::rule<Iterator/*, sub_grammar_skipper<Iterator> */> start;
Change this line to: qi::rule<Iterator, void(), sub_grammar_skipper<Iterator> > start; This should work. void() is needed if you grammar has no attributes. If your grammar expands into smth. meaningful, than you must pass the type of the associated attribute, e.g. if you grammar outputs string, you will write the line like: qi::rule<Iterator, std::string(), sub_grammar_skipper<Iterator> > start; With kind regards, Ovanes
On 22 October 2010 21:10, Ovanes Markarian <om_boost@keywallet.com> wrote:
qi::rule<Iterator/*, sub_grammar_skipper<Iterator> */> start;
Change this line to: qi::rule<Iterator, void(), sub_grammar_skipper<Iterator> > start; This should work. void() is needed if you grammar has no attributes. If your grammar expands into smth. meaningful, than you must pass the type of the associated attribute, e.g. if you grammar outputs string, you will write the line like: qi::rule<Iterator, std::string(), sub_grammar_skipper<Iterator> > start; With kind regards, Ovanes
Hi, using struct sub_grammar: qi::grammar<Iterator, void(), sub_grammar_skipper<Iterator> > with or without the void() produces a compilation error in gcc: include/boost/spirit/home/qi/nonterminal/rule.hpp:280: error: no match for call to ‘(const boost::function<bool(__gnu_cxx::__normal_iterator<const char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> >
&, const __gnu_cxx::__normal_iterator<const char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > &, boost::spirit::context<boost::fusion::cons<boost::fusion::unused_type&, boost::fusion::nil>, boost::fusion::vector0<void> >&, const boost::spirit::qi::reference<const boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<const char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > , boost::fusion::unused_type, boost::fusion::unused_type, boost::fusion::unused_type, boost::fusion::unused_type> >&)>) (__gnu_cxx::__normal_iterator<const char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >&, const __gnu_cxx::__normal_iterator<const char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >&, boost::spirit::context<boost::fusion::cons<boost::fusion::unused_type&, boost::fusion::nil>, boost::fusion::vector0<void> >&, const boost::fusion::unused_type&)’ /usr/include/boost/function/function_template.hpp:1006: note: candidates are: R boost::function4<R, T1, T2, T3, T4>::operator()(T0, T1, T2, T3) const [with R = bool, T0 = __gnu_cxx::__normal_iterator<const char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >&, T1 = const __gnu_cxx::__normal_iterator<const char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >&, T2 = boost::spirit::context<boost::fusion::cons<boost::fusion::unused_type&, boost::fusion::nil>, boost::fusion::vector0<void> >&, T3 = const boost::spirit::qi::reference<const boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<const char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > , boost::fusion::unused_type, boost::fusion::unused_type, boost::fusion::unused_type, boost::fusion::unused_type> >&]
I've decided to break up my parser into sub-grammars to improve both the readability and compile time. I'm now trying to specify a skip parser for one of the sub-grammars, but I don't know how to do it. I'm familiar with specifying a skip parser in the parse functions, but not in the grammar itself. Could somebody please provide an example? Thanks.
You need to pass the skipper type to the subgrammar (see attached). Additionally you need to utilize phrase_parse() instead of parse to hand down a skipper instance. Regards Hartmut --------------- http://boost-spirit.com
On 22 October 2010 23:06, Hartmut Kaiser <hartmut.kaiser@gmail.com> wrote:
I've decided to break up my parser into sub-grammars to improve both the readability and compile time. I'm now trying to specify a skip parser for one of the sub-grammars, but I don't know how to do it. I'm familiar with specifying a skip parser in the parse functions, but not in the grammar itself. Could somebody please provide an example? Thanks.
You need to pass the skipper type to the subgrammar (see attached). Additionally you need to utilize phrase_parse() instead of parse to hand down a skipper instance.
Regards Hartmut --------------- http://boost-spirit.com
Hi Hartmut, Thank you very much for the reply. I do have another question though: Is it possible for the top level grammar to have its own skipper? If there are multiple sub-grammars, can they also have a different skipper each? If not, I guess I would have to put all the possible alternatives into the one skipper grammar, right? Regards, Vitaly
On Fri, Oct 22, 2010 at 6:58 AM, Vitaly Budovski <vbudovski+news@gmail.com> wrote:
On 22 October 2010 23:06, Hartmut Kaiser <hartmut.kaiser@gmail.com> wrote:
I've decided to break up my parser into sub-grammars to improve both the readability and compile time. I'm now trying to specify a skip parser for one of the sub-grammars, but I don't know how to do it. I'm familiar with specifying a skip parser in the parse functions, but not in the grammar itself. Could somebody please provide an example? Thanks.
You need to pass the skipper type to the subgrammar (see attached). Additionally you need to utilize phrase_parse() instead of parse to hand down a skipper instance.
Regards Hartmut --------------- http://boost-spirit.com
Hi Hartmut,
Thank you very much for the reply. I do have another question though: Is it possible for the top level grammar to have its own skipper? If there are multiple sub-grammars, can they also have a different skipper each? If not, I guess I would have to put all the possible alternatives into the one skipper grammar, right?
They can, that is what the skip()[] directive is for (see docs).
participants (5)
-
Bill Somerville
-
Hartmut Kaiser
-
Ovanes Markarian
-
OvermindDL1
-
Vitaly Budovski