2

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

我不明白为什么要删除字符文字或省略 [] 来“解决”问题,但我不希望语​​法因此而杂乱无章。

根据此处找到的 >> 和 > 的复合属性规则以及此处的字符解析器属性, 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. 

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

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

4

1 回答 1

2

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

尽管您正确地遵守了记录在案的属性生成规则,但真正发生的是Unused侧面更像fusion::vector1<qi::unused_type>(而不是qi::unused_type)。

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

您可以使用诸如检测 Spirit 语义动作中的参数类型之类的技术来确定我的预感是否正确。

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


稍长一点的答案是:我认为您没有展示更多内容

两件事情:

  1. 错误消息非常清楚地表明它正在尝试insert使用字符串迭代器*预期字符(或可转换)的位置。我看不到与您发布的任何代码的联系,尽管我可以猜到

    • 在某处使用 qi::raw[] (很可能)
    • 在您的 ast 结构之一中使用 iterator_pair(不太可能)
  2. 我可以编译你的“有问题的”规则样本,很好地嵌入到我的“模拟”语法中,我是根据你在上一个问题中暴露的一点点猜测建立起来的。

    • 查看我在下面使用的完整程序或查看它在 Coliru 上实时运行(我还使用 GCC 4.7.3 和 boost 1.53 在本地编译了它)

我认为也许您应该尝试发布另一个问题,同时展示一个简短的自包含正确示例来展示您真正遇到的问题。

请务必提及使用的编译器版本和 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;
}
于 2013-08-26T10:44:09.430 回答