增强精神带走关键字并忽略队长 [英] Boost spirit take away keyword and ignore skipper

查看:73
本文介绍了增强精神带走关键字并忽略队长的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

This is a small part of a grammer using expressions.

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

在后缀内的某种方式,我有 name_pure 来使用标识符..

Some way inside postfix I have name_pure to take an identifier ..

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

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

So far all is fine. Can write something like

a=not b

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

But if I start to use not as a name prefix like this one

a=not notvarname 

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

I get a parser Output from the AST which look like this

a=not not varname

这意味着 not 用作前缀规则,而不与 Name_pure 规则一起用作Name.

Which means the not is used as prefix rule and not as Name with the rule Name_pure.

从我的角度来看,似乎船长未正确介入.

From my point of view it looks like the Skipper is not involved correctly.

这是我的船长

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

推荐答案

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

Like last time, I don't think the skipper is your problem.

关于船长所做的假设.

  1. space - eol就是blank.
  2. 词汇无法跳过(这就是定义):提升精神队长问题
  3. PEG语法是贪婪的,并且是从左到右的.因此,如果您想避免在纯名称内匹配"not",则需要确保您在单词边界上:如何正确地解析保留字
  1. space - eol is just blank.
  2. lexemes do not skip (that's the definition): Boost spirit skipper issues
  3. PEG grammars are greedy and left-to-right. So, you need to make sure you're on a word boundary if you want to avoid matching "not" inside a purename: Prevent the Boost Spirit Symbol parser from accepting a keyword too early or How to parse reserved words correctly in boost spirit

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

I'd write the rules a lot more self-descriptive (e.g. eol_skipper suggests it skips eol, but that's exactly what it DOESN'T skip?).

using Skipper = qi::blank_type;

然后,只需从声明中删除船长,即可将identifier规则(pure_name?)隐含为lexeme:

Then, make your identifier rule (pure_name?) an implicit lexeme by just dropping the skipper from the declaration:

  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在关键字/标识符边界上匹配:

Finally, use !p parser directive to assert that not matched on a keyword/identifier boundary:

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

演示时间

在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时如何为您提供调试输出,以防万一您想对规则进行故障排除:

NOTE how defining BOOST_SPIRIT_DEBUG also gives you debug output in case you wanted to troubleshoot your rules, next time:

<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]

这篇关于增强精神带走关键字并忽略队长的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆