提升精神带走关键词并忽略船长

时间:2017-11-22 06:08:46

标签: c++ keyword boost-spirit identifier

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

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

在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

这意味着用作前缀规则,而不是Name用于规则 Name_pure

从我的观点来看,看起来船长没有正确参与。

这是我的船长

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

1 个答案:

答案 0 :(得分:2)

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

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

  1. space - eol只是blank
  2. lexemes不会跳过(这是定义):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
  4. 我写了更多自我描述的规则(例如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]