C++ boost::spirit::qi规则减少解析错误

C++ boost::spirit::qi规则减少解析错误,c++,parsing,boost,boost-spirit,boost-spirit-qi,C++,Parsing,Boost,Boost Spirit,Boost Spirit Qi,我尝试使用boost::spirit::qi解析integer和double对的列表。在此列表之前和之后都有一个整数。该列表的一个示例是: 20 1 1.3 2 2.3 30 我要创建的结构是: typedef std::vector< std::pair<int, double> > vec_t; struct list_s{ int first; std::vector< std::pair<int, double> > list;

我尝试使用
boost::spirit::qi
解析
integer
double
对的列表。在此列表之前和之后都有一个
整数。该列表的一个示例是:

20 1 1.3 2 2.3 30
我要创建的结构是:

typedef std::vector< std::pair<int, double> > vec_t;
struct list_s{
  int first;
  std::vector< std::pair<int, double> > list;
  int last;
};
运行这个示例时,我得到

Error! Expecting <real> here: ""
为了克服上述错误。但是
20 1 1.3 2 error 30
的解析也成功了。结果将是:

20
1 , 1.3
2

有什么建议可以解决这个问题吗?

期望点会产生非回溯期望

因此,在失败后,您无法接受备用分支

这意味着您的最后一个整数将与
(int\u>double\ux)
中的整数匹配。但是,表达式需要
后面跟着的
)double
,因为它没有,所以抛出

替换为
此处
>

事实上,看起来您只是想确保整个输入/行都已使用,因此请明确您的期望:

演示

Note: also enabled rule debug (implicitly names the rule):

#define BOOST_SPIRIT_DEBUG
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/fusion/include/adapted.hpp>

#include <iostream>

namespace phoenix = boost::phoenix;
namespace qi      = boost::spirit::qi;
namespace ascii   = boost::spirit::ascii;

typedef std::vector<std::pair<int, double>> vec_t;

struct list_s{
  int first;
  vec_t list;
  int last;
};

BOOST_FUSION_ADAPT_STRUCT(list_s, first, list, last)

template <typename Iterator>
struct list_parser : qi::grammar<Iterator, list_s(), ascii::space_type>
{
  public:
    list_parser() : list_parser::base_type(r) {
        r = (
                qi::int_
                > *( qi::int_ >> qi::double_ )
                > qi::int_
            )
            > qi::eoi
            ;

      BOOST_SPIRIT_DEBUG_NODES((r))

      qi::on_error<qi::fail>
        (
            r
            , std::cout
            << phoenix::val("\nError! Expecting ")
            << qi::labels::_4 
            << phoenix::val(" here: \"")
            << phoenix::construct<std::string>(qi::labels::_3, qi::labels::_2)
            << phoenix::val("\"\n\n")
        );
    }
  private:
    qi::rule<Iterator, list_s(), ascii::space_type > r;
};

int main() {
    std::string str("20 1 1.3 2 2.3 30");

    using It = std::string::const_iterator;

    list_parser<It> p;
    It iter = str.begin(), end = str.end();

    list_s data;
    if (qi::phrase_parse(iter, end, p, ascii::space, data)){
        std::cout << data.first << "\n";

        for(auto& i : data.list) 
            std::cout << i.first << ", " << i.second << "\n";

        std::cout << data.last << "\n";
    }
}
Error! Expecting <eoi> here: "error 30"
和调试输出:

<r>
    <try>20 1 1.3 2 2.3 30</try>
    <success></success>
    <attributes>[[20, [[1, 1.3], [2, 2.3]], 30]]</attributes>
</r>
<r>
  <try>20 1 1.3 2 error 30</try>
  <fail/>
</r>

20 1 1.3 2 2.3 30

错误!此处应为:“错误30”
使用调试输出:

<r>
    <try>20 1 1.3 2 2.3 30</try>
    <success></success>
    <attributes>[[20, [[1, 1.3], [2, 2.3]], 30]]</attributes>
</r>
<r>
  <try>20 1 1.3 2 error 30</try>
  <fail/>
</r>

20 1.3 2错误30

询问者尝试过,但不喜欢它接受输入,如
20 1.3 2 error 30
(用于“接受”的定义)。当“接受”表示
解析返回true时,它会接受。我认为他/她需要一个分隔符或使用前瞻。它不需要。仔细阅读。(在答案文本中澄清)(更丑陋,性能可能更差,错误消息稍好,imho)。如何?为什么?重试不会改变规则或输入。您可以根据业务逻辑在某个地方创建一个有条件的
eps
,以决定使用哪个分支/生成哪个消息
Error! Expecting <eoi> here: "error 30"
<r>
  <try>20 1 1.3 2 error 30</try>
  <fail/>
</r>