【问题标题】:Boost spirit take away keyword and ignore skipper提升精神带走关键字并忽略船长
【发布时间】:2018-05-05 18:57:42
【问题描述】:

这是使用表达式的语法的一小部分。

 prefix =
     (lit(L"not") >> prefix) 
    |(lit('-') >> prefix)
    | postfix
    ;

在后缀中的某种方式我有 name_pure 来获取标识符..

name_pure = lexeme[+(boost::spirit::standard_wide::alpha | '_') >> *(boost::spirit::standard_wide::alnum | '_')];

到目前为止一切都很好。可以写类似

a=not b

但是如果我开始像这样使用 not 作为名称前缀

a=not notvarname 

我从 AST 得到一个解析器输出,看起来像这样

a=not not varname

这意味着 not 用作前缀规则,而不是带有规则 Name_pureName

在我看来,船长似乎没有正确参与。

这是我的船长

 template<typename Iterator>
  struct eol_skipper : public qi::grammar<Iterator> {

    eol_skipper() : eol_skipper::base_type(skip) 
    {

      using qi::eol;
      using qi::lit;
      using qi::char_;     
      skip = ascii::space -eol;
    }
    qi::rule<Iterator> skip;
  };

【问题讨论】:

    标签: c++ keyword boost-spirit identifier


    【解决方案1】:

    和上次一样,我不认为船长是你的问题。

    也许是关于船长做什么的假设。

    1. space - eol 就是 blank
    2. 词位不跳过(这是定义):Boost spirit skipper issues
    3. PEG 语法是贪婪的并且从左到右。因此,如果您想避免在纯名称中匹配 "not",则需要确保您处于单词边界:Prevent the Boost Spirit Symbol parser from accepting a keyword too earlyHow to parse reserved words correctly in boost spirit

    我会写出更具自我描述性的规则(例如,eol_skipper 建议它跳过 eol,但这正是它没有跳过的内容?)。

    using Skipper = qi::blank_type;
    

    然后,只需从声明中删除船长,即可使您的 identifier 规则(pure_name?)成为隐含的​​ lexeme

      private:
        qi::rule<Iterator, Ast::AssignmentStatement()> start;
        qi::rule<Iterator, Ast::AssignmentStatement(), Skipper> assignment;
        qi::rule<Iterator, Ast::Expr(), Skipper> expr;
        qi::rule<Iterator, Ast::Negated(), Skipper> negation;
        // implicit lexemes
        qi::rule<Iterator, Ast::Identifier()> identifier;
    

    最后,使用 !p 解析器指令断言 not 在关键字/标识符边界上匹配:

        negation
            = lexeme [(lit("not") | '0') >> !(alnum|'_')] >> expr 
            ;
    

    演示时间

    Live On Coliru

    #define BOOST_SPIRIT_DEBUG
    #include <boost/fusion/adapted/struct.hpp>
    #include <boost/spirit/include/qi.hpp>
    #include <iostream>
    namespace qi = boost::spirit::qi;
    
    namespace Ast {
        using Identifier = std::string;
        struct Negated;
    
        using Expr = boost::variant<Identifier, boost::recursive_wrapper<Negated> >;
    
        struct Negated {
            Expr expr;
        };
    
        struct AssignmentStatement {
            Identifier lhs;
            Expr rhs;
        };
    }
    
    BOOST_FUSION_ADAPT_STRUCT(Ast::Negated, expr)
    BOOST_FUSION_ADAPT_STRUCT(Ast::AssignmentStatement, lhs, rhs)
    
    template <typename Iterator> struct parser : qi::grammar<Iterator, Ast::AssignmentStatement()> {
        using Skipper = qi::blank_type;
    
        parser() : parser::base_type(start) {
            using namespace qi;
    
            start      = skip(blank) [ assignment ];
    
            assignment = identifier >> '=' >> expr;
    
            expr       = negation | identifier;
    
            negation
                = lexeme [(lit("not") | '0') >> !(alnum|'_')] >> expr 
                ;
    
            identifier = char_("a-zA-Z_") >> *char_("a-zA-Z0-9_");
            // or:
            identifier = raw [ +(alpha | '_') >> *(alnum | '_') ];
    
            BOOST_SPIRIT_DEBUG_NODES((start)(expr)(assignment)(identifier)(negation))
        }
    
      private:
        qi::rule<Iterator, Ast::AssignmentStatement()> start;
        qi::rule<Iterator, Ast::AssignmentStatement(), Skipper> assignment;
        qi::rule<Iterator, Ast::Expr(), Skipper> expr;
        qi::rule<Iterator, Ast::Negated(), Skipper> negation;
        // implicit lexemes
        qi::rule<Iterator, Ast::Identifier()> identifier;
    };
    
    namespace Ast {
        std::ostream& operator<<(std::ostream& os, Negated const& o)             { return os << "NOT[" << o.expr << "]"; } 
        std::ostream& operator<<(std::ostream& os, AssignmentStatement const& a) { return os << a.lhs << " = " << a.rhs; } 
    }
    
    int main() {
        using It = std::string::const_iterator;
        for (std::string const input : {
                "a=not _b",
                "a=not not_var_name",
            })
        {
            It f = input.begin(), l = input.end();
    
            Ast::AssignmentStatement assignment;
            if (parse(f, l, parser<It>{}, assignment))
                std::cout << "Parsed " << assignment << "\n";
            else
                std::cout << "Parse failed\n";
    
            if (f!=l)
                std::cout << "Remaining unparsed input: '" << std::string(f,l) << "'\n";
        }
    }
    

    打印

    Parsed a = NOT[_b]
    Parsed a = NOT[not_var_name]
    

    注意如何定义 BOOST_SPIRIT_DEBUG 还可以为您提供调试输出,以防您下次想对规则进行故障排除:

    <start>
      <try>a=not b</try>
      <assignment>
        <try>a=not b</try>
        <identifier>
          <try>a=not b</try>
          <success>=not b</success>
          <attributes>[[a]]</attributes>
        </identifier>
        <expr>
          <try>not b</try>
          <negation>
            <try>not b</try>
            <expr>
              <try> b</try>
              <negation>
                <try> b</try>
                <fail/>
              </negation>
              <identifier>
                <try>b</try>
                <success></success>
                <attributes>[[b]]</attributes>
              </identifier>
              <success></success>
              <attributes>[[b]]</attributes>
            </expr>
            <success></success>
            <attributes>[[[b]]]</attributes>
          </negation>
          <success></success>
          <attributes>[[[b]]]</attributes>
        </expr>
        <success></success>
        <attributes>[[[a], [[b]]]]</attributes>
      </assignment>
      <success></success>
      <attributes>[[[a], [[b]]]]</attributes>
    </start>
    Parsed a = NOT[b]
    <start>
      <try>a=not notvarname</try>
      <assignment>
        <try>a=not notvarname</try>
        <identifier>
          <try>a=not notvarname</try>
          <success>=not notvarname</success>
          <attributes>[[a]]</attributes>
        </identifier>
        <expr>
          <try>not notvarname</try>
          <negation>
            <try>not notvarname</try>
            <expr>
              <try> notvarname</try>
              <negation>
                <try> notvarname</try>
                <fail/>
              </negation>
              <identifier>
                <try>notvarname</try>
                <success></success>
                <attributes>[[n, o, t, v, a, r, n, a, m, e]]</attributes>
              </identifier>
              <success></success>
              <attributes>[[n, o, t, v, a, r, n, a, m, e]]</attributes>
            </expr>
            <success></success>
            <attributes>[[[n, o, t, v, a, r, n, a, m, e]]]</attributes>
          </negation>
          <success></success>
          <attributes>[[[n, o, t, v, a, r, n, a, m, e]]]</attributes>
        </expr>
        <success></success>
        <attributes>[[[a], [[n, o, t, v, a, r, n, a, m, e]]]]</attributes>
      </assignment>
      <success></success>
      <attributes>[[[a], [[n, o, t, v, a, r, n, a, m, e]]]]</attributes>
    </start>
    Parsed a = NOT[notvarname]
    

    【讨论】:

    • 我喜欢链接中的 kw 方法。这非常适合我的语法。但它在使用时因访问冲突而崩溃。代码中的提示已经说明可能存在问题..但看不到哪一个template &lt;std::size_t N&gt; static auto kw(char const (&amp;key)[N]) -&gt; qi::rule&lt;Iterator&gt; { // qi::lit has problems with char arrays, use pointer instead. return qi::lit(key) &gt;&gt; !qi::alnum; }
    • 经过更多测试后,该代码似乎运行了.. 好吧,这没有意义,因为里面的静态只是一次.. 无论如何,它表明“kw”的第一个版本有一种终身问题..template &lt;std::size_t N&gt; static qi::rule&lt;Iterator&gt; &amp; kw(char const (&amp;key)[N]) { static qi::rule&lt;Iterator&gt; rule=qi::lit(key) &gt;&gt; !qi::alnum; return rule; }
    • @Markus 与这个问题或这个答案有什么关系?
    • 在您的第 3 点分析器中,您给了我一个指向此示例的链接。 kw 模板就是其中之一。您的代码演示代码工作正常,但使用“kw”似乎更优雅..
    • 我刚刚在这里修复了标识符规则,请在这些答案中评论其他答案的问题,或发布单独的问题。是的,auto 存在表达式模板的生命周期问题(SO 上有十几个关于此的答案)。如果这个答案有帮助,请记得投票。
    猜你喜欢
    • 2013-06-09
    • 2014-03-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多