How to parse reserved words correctly in boost spirit

巧了我就是萌 提交于 2019-11-27 09:43:41

In addition to the "manual" approach suggested by Mike you can

  1. use a convenience wrapper rule
  2. use the distinct parser direetive from the Spirit Repository

1. Use a convenience wrapper

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

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

Which you could use like (using +"lit" to decay the array-ref into const char*):

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

You can make it considerably 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();
}

You can use the and predicate or the not predicate parser, depending on what you would like to express. The predicate parsers just check the next symbols but don't consume them.

This says, you expect a blank (space or tab) afterwards:

rule = symbol_parser >> &qi::blank;

This says, you don't want to have a letter, number or underscore afterwards:

rule = symbol_parser >> !(qi::alnum | qi::lit("_"));
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!