【问题标题】:Boost Spirit Qi Attribute Propagation提升灵气属性传播
【发布时间】:2013-08-26 09:28:19
【问题描述】:

我遇到了 Boost Spirit Qi 语法问题,它发出了不需要的类型,导致编译错误:

error C2664: 'std::basic_string<_Elem,_Traits,_Ax> &std::basic_string<_Elem,_Traits,_Ax>::insert(unsigned int,const std::basic_string<_Elem,_Traits,_Ax> &)' : cannot convert parameter 1 from 'std::_String_iterator<_Elem,_Traits,_Alloc>' to 'unsigned int'

这是导致问题的语法:

    qi::rule<Iterator, qi::unused_type()> gr_newline;

            // asmast::label() just contains an identifier struct that is properly emitted from gr_identifier
    qi::rule<Iterator, asmast::label(), skipper<Iterator> > gr_label;

    gr_newline = +( char_('\r')
                   |char_('\n')
                  );

这失败了:

gr_label = gr_identifier
           >> ':'
           > gr_newline;

但以下 所有工作:

// This parses OK
gr_label = gr_identifier
           > gr_newline;

// This also parses OK
gr_label = gr_identifier
           > ':'
           > gr_newline;

    // This also parses OK
    // **Why does this work when parenthesized?**
    gr_label = gr_identifier
           >> (':'
                > skip_grammar.gr_newline
              );

// This also parses OK
gr_label = gr_identifier
           >> omit[':'
                    > gr_newline];

我不明白为什么删除字符文字或省略[]它可以“解决”问题,但我不希望语​​法因此而混乱。

根据 >> 和 > 的复合属性规则找到 here,以及字符解析器属性 here,gr_label 应该只发出 asmast::label

a: A, b: B --> (a >> b): tuple<A, B>
a: A, b: Unused --> (a >> b): A  <---- This one here is the one that should match so far as I understand
a: Unused, b: B --> (a >> b): B
a: Unused, b: Unused --> (a >> b): Unused


 Expression Attribute
 c          unused or if c is a Lazy Argument, the character type returned by invoking it. 

但是,不知何故,某些东西污染了预期的属性,并导致编译器错误。

所以我的问题是这个语法在哪里发出了不需要的属性,以及如何摆脱它。

【问题讨论】:

    标签: c++ boost-spirit boost-spirit-qi


    【解决方案1】:

    问题似乎是因为你在这里混搭&gt;&gt;&gt;

    虽然您正确地遵守了记录的属性生成规则,但真正似乎发生的是Unused 端更像fusion::vector1&lt;qi::unused_type&gt;(而不是qi::unused_type)。

    旁注:
    <em>这也解释了“<strong>为什么在括号中起作用?</strong>” - <br> 你正在改变表达式评估的顺序(否决运算符优先级)
    并获得另一种类型。

    您可以使用以下技术了解我的预感是否正确,例如Detecting the parameter types in a Spirit semantic action.

    所以,简短的回答是:这就是它的工作原理。无论这是一个错误、文档中的遗漏还是只是一个功能,在 SO 上讨论确实没有建设性。我指的是 [spirit-general] 邮件列表(注意他们也有一个活跃的#IRC 频道)。


    略长的答案是:我认为你没有展示更多内容

    两件事:

    1. 错误消息非常清楚地表明它正在尝试insert 一个字符串迭代器*,其中需要一个字符(或可转换字符)。我没有看到与您发布的任何代码的联系,尽管我可以猜到

      • 在某处使用 qi::raw[](很可能)
      • 在您的 ast 结构之一中使用 iterator_pair(不太可能)
    2. 我可以编译你的“有问题的”规则样本,很好地嵌入到我的“模拟”语法中

      • 查看我在下面使用的完整程序或查看它running Live on Coliru(我还使用 GCC 4.7.3 和 boost 1.53 在本地编译了此程序)

    我认为也许您应该尝试发布另一个问题,同时显示一个 Short Self Contained Correct Example 来展示您真正遇到的问题。

    请务必提及所使用的编译器版本和 boost 版本。

    完整的 SSCCE 示例

    #define BOOST_SPIRIT_DEBUG
    #include <boost/spirit/include/qi.hpp>
    
    namespace qi    = boost::spirit::qi;
    
    namespace asmast
    {
        typedef std::string label;
    }
    
    template <typename It, typename Skipper = qi::blank_type>
        struct parser : qi::grammar<It, Skipper>
    {
        parser() : parser::base_type(start)
        {
            using namespace qi;
    
            start = lexeme["Func" >> !(alnum | '_')] > function;
            function = gr_identifier
                        >> "{"
                        >> -(
                                  gr_instruction
                                | gr_label
                              //| gr_vardecl
                              //| gr_paramdecl
                            ) % eol
                        > "}";
    
            gr_instruction_names.add("Mov", unused);
            gr_instruction_names.add("Push", unused);
            gr_instruction_names.add("Exit", unused);
    
            gr_instruction = lexeme [ gr_instruction_names >> !(alnum|"_") ] > gr_operands;
            gr_operands = -(gr_operand % ',');
    
            gr_identifier = lexeme [ alpha >> *(alnum | '_') ];
            gr_operand    = gr_identifier | gr_string;
            gr_string     = lexeme [ '"' >> *("\"\"" | ~char_("\"")) >> '"' ];
    
            gr_newline = +( char_('\r')
                           |char_('\n')
                          );
    
            gr_label = gr_identifier >> ':' > gr_newline;
    
            BOOST_SPIRIT_DEBUG_NODES((start)(function)(gr_instruction)(gr_operands)(gr_identifier)(gr_operand)(gr_string));
        }
    
      private:
        qi::symbols<char, qi::unused_type> gr_instruction_names;
        qi::rule<It, Skipper> start, function, gr_instruction, gr_operands, gr_operand, gr_string;
        qi::rule<It, qi::unused_type()> gr_newline;
        qi::rule<It, asmast::label(), Skipper> gr_label, gr_identifier;
    };
    
    int main()
    {
        typedef boost::spirit::istream_iterator It;
        std::cin.unsetf(std::ios::skipws);
        It f(std::cin), l;
    
        parser<It, qi::blank_type> p;
    
        try
        {
            bool ok = qi::phrase_parse(f,l,p,qi::blank);
            if (ok)   std::cout << "parse success\n";
            else      std::cerr << "parse failed: '" << std::string(f,l) << "'\n";
    
            if (f!=l) std::cerr << "trailing unparsed: '" << std::string(f,l) << "'\n";
            return ok;
        } catch(const qi::expectation_failure<It>& e)
        {
            std::string frag(e.first, e.last);
            std::cerr << e.what() << "'" << frag << "'\n";
        }
    
        return false;
    }
    

    【讨论】:

    • 再次感谢您的详细解答。对于我的生活,我无法弄清楚如何不跳过换行符,因此我可以使用它们来分隔指令,同时仍然在某些地方跳过换行符。我已经尝试过这个 gr_newline 的想法,用 skip() 和其他一些东西更改跳过语法,但它总是以过于复杂的方式结束,而且可能还有错误。我想我会花一些时间看看您的帖子,并尝试找出一种新方法来跳过某些地方的换行符。
    • 顺便说一句,我所有的东西都是基于 Qi 附带的 MiniC 样本,包括船长。
    • @namezero 使用qi::blank 而不是qi::space 作为船长?此外,qi::eol 已经匹配换行符。
    • @namezero 不管怎样,船长不是这里的问题。所以,我想说,不要改变它。我只是展示我对它的看法,以证明 gr_label 规则编译得很好。
    • 嗯,我猜它归结为:) 但是thatnks,eol 是完美的,这样我就不需要gr_newline。它现在似乎有点工作,我很欣赏你的例子!
    猜你喜欢
    • 1970-01-01
    • 2013-11-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-19
    相关资源
    最近更新 更多