如何在提升精神中正确解析保留字

时间:2013-11-21 20:23:59

标签: parsing boost boost-spirit boost-spirit-qi

我正在尝试解析一系列语法:<方向> <类型> <名称>。例如:

in float foo

其中方向可以是 out in_out 。我已成功通过使用qi :: symbols类将方向关键字转换为枚举来解析正确的文本。

然而,问题显示我没有正确的文字。举个例子:

int foo

符号表解析器除了'int'类型的'in'部分外,结果将是:

direction: in
type: t
name: foo

未检测到错误。能够解析in,out和in_out保留字并确保它们后跟非标识符字符以便前一文本的“int”部分失败的最佳方法是什么?

由于

2 个答案:

答案 0 :(得分:5)

除了迈克建议的“手动”方法,你可以

  1. 使用便利包装规则
  2. 使用Spirit Repository中的distinct解析器
  3. 1。使用便利包装

    我记得,我曾经想过这个快速而又肮脏的帮手:

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

    您可以使用(使用+"lit"将数组-ref转换为const char*):

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

    你可以使它更方便

    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;
    }
    

    所以你可以

    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。使用Spirit Repository

    中的distinct指令

    除了Mike建议的“手动”方法之外,您还可以使用Spirit Repository中的distinct解析器指令:

    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();
    }
    

答案 1 :(得分:3)

您可以使用and predicate或not谓词解析器,具体取决于您要表达的内容。谓词解析器只检查下一个符号但不消耗它们。

这就是说,您希望之后有空白(空格或制表符):

rule = symbol_parser >> &qi::blank;

这就是说,之后你不想要一个字母,数字或下划线:

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