How to correctly parse reserved words in the spirit of forcing

I am trying to parse the syntax sequence: <direction <type> <name>. For instance:

in float foo 

where the direction can be either in , out , or in_out . I managed to parse the correct text using the qi :: symbols class to convert direction keywords into an enumeration.

However, the problem occurs when I do not have the correct text. Take an example:

 int foo 

The symbol table parser will be excluding the "in" part of type "int", so the results will be as follows:

 direction: in type: t name: foo 

And no error was found. What is the best way to parse the reserved words in, out and in_out and make sure that they are followed by a non-identifier so that the β€œint” part of the previous text fails?

thanks

+6
source share
2 answers

In addition to the β€œmanual” approach suggested by Mike, you can

  • use convenience shell rule
  • use distinct parser in Spirit repository

1. Use a convenient wrapper

I just remembered, once I came up with this quick and dirty assistant:

 static const qi::rule<It, qi::unused_type(const char*)> kw = qi::lit(qi::_r1) >> !qi::alnum; 

What could you use (using +"lit" to decompose the ref-array into const char* ):

 stmt = kw(+"if") >> '(' >> expr >> ')' >> block >> -(kw(+"else") >> block) ; 

You can make it much more convenient.

 template <std::size_t N> static auto kw(char const (&keyword)[N]) -> qi::rule<Iterator> { // qi::lit has problems with char arrays, use pointer instead. return qi::lit(+keyword) >> !qi::alnum; } 

So you can

 kw_if = kw("if"); kw_then = kw("then"); kw_else = kw("else"); kw_and = kw("and"); kw_or = kw("or"); kw_not = kw("not"); 

2. Use the distinct directive from the Spirit repository

In addition to the β€œmanual” approach suggested by Mike, you can use the distinct parser directive from the Spirit repository:

 int main() { using namespace spirit_test; using namespace boost::spirit; { using namespace boost::spirit::ascii; qi::rule<char const*, space_type> r; r = distinct::keyword["description"] >> -lit(':') >> distinct::keyword["ident"]; BOOST_TEST(test("description ident", r, space)); BOOST_TEST(test("description:ident", r, space)); BOOST_TEST(test("description: ident", r, space)); BOOST_TEST(!test("descriptionident", r, space)); } return boost::report_errors(); } 
+5
source

You can use a parser and a predicate or not a predicate, depending on what you would like to express. Predicate analyzers simply check the following characters, but do not consume them.

This says that you expect a space (space or tab):

 rule = symbol_parser >> &qi::blank; 

This means that after that you do not want to have letters, numbers or underscores:

 rule = symbol_parser >> !(qi::alnum | qi::lit("_")); 
+4
source

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


All Articles