提升精神属性传播

时间:2013-08-26 09:28:19

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

我遇到了一个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];

我不明白为什么删除字符文字或省略[]它“修复”问题,但我不希望语​​法混乱。

根据&gt;&gt;的复合属性规则和&gt;找到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. 

但是,某些东西会污染目标属性,并导致编译器错误。

所以我的问题是这个语法发出了一个不受欢迎的属性,以及如何摆脱它。

1 个答案:

答案 0 :(得分:2)

问题似乎是因为你在这里混合搭配>>>

虽然您正确地观察了记录的属性生成规则,但真正似乎发生的是Unused方更像fusion::vector1<qi::unused_type>(而不是qi::unused_type )。

  

旁注: 这也解释了“为什么在括号时才能正常工作?” - 您正在改变表达式评估的顺序(推翻运算符优先级)
并获得另一种类型。

您可以使用诸如此类技术来确定我的预感是否正确Detecting the parameter types in a Spirit semantic action

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


略长的答案是: 我认为您还没有显示

两件事:

  1. 错误消息非常清楚地表明它正在尝试insert 字符串迭代器 * ,其中包含字符(或可兑换)。我没有看到你发布的任何代码的连接,但我可以猜到

    • 在某处使用qi :: raw [](非常可能)
    • 在你的一个结构中使用iterator_pair(非常不可能)
  2. 我可以编译你的“有问题”的规则标本就好嵌入我的“模拟”语法中,我根据你在previous question中暴露的一点点来猜测。

    • 查看我在下面使用的完整程序或查看 running Live on Coliru (我也使用GCC 4.7.3在本地编译并提升1.53)
  3.   

    我想也许您应该尝试发布另一个问题,同时显示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;
    }