C++ 可选表达式和解析错误位置的问题

C++ 可选表达式和解析错误位置的问题,c++,boost,boost-spirit,boost-spirit-qi,boost-fusion,C++,Boost,Boost Spirit,Boost Spirit Qi,Boost Fusion,我正试图为特定的消息格式编写我的第一个boost spirit解析器,但遇到了一些问题。使用的boost库版本是1.49.0 #include <iostream> #include <sstream> #include <boost/spirit/include/qi.hpp> #include <boost/spirit/include/support_multi_pass.hpp> #include <boost/spirit/incl

我正试图为特定的消息格式编写我的第一个boost spirit解析器,但遇到了一些问题。使用的boost库版本是1.49.0

#include <iostream>
#include <sstream>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/support_multi_pass.hpp>
#include <boost/spirit/include/classic_position_iterator.hpp>
#include <boost/fusion/adapted/struct/adapt_struct.hpp>

namespace qi = boost::spirit::qi;

struct message
{
  std::string title;
  std::string sender;
  std::string receiver;
  unsigned int seqNo;
  std::string senderRef;
  std::string receiverRef;
  unsigned int seqNoRef;
  std::string id;
};

BOOST_FUSION_ADAPT_STRUCT(
    message,
    (std::string, title)
    (std::string, sender)
    (std::string, receiver)
    (unsigned int, seqNo)
    (std::string, senderRef)
    (std::string, receiverRef)
    (unsigned int, seqNoRef)
    (std::string, id)
)

template<typename Iterator>
struct MyQiGrammar : qi::grammar<Iterator, message(), qi::space_type>
{
  MyQiGrammar() : MyQiGrammar::base_type(start) {
    qi::uint_parser<unsigned int, 10, 3, 3> uint_3p;

    delim     = qi::char_("-/");            // some values are delimited by '-' or '/'

    title    %= qi::repeat(3)[qi::upper];   // exactly 3 upper case letters
    sender   %= +qi::upper;                 // at least one upper case letter
    receiver %= +qi::upper;                 // at least one upper case letter
    seqNo    %= uint_3p;                    // exactly 3 digits (e.g. 001)
    id       %= qi::repeat(1,7)[qi::alnum]; // at least 1 upper case letter and maximum 7

    start    %=
        '('
        >> title
        >> sender >> delim >> receiver >> seqNo
        >> -(sender >> delim >> receiver >> seqNo)
        >> delim >> id
        >>
        ')';
  }

  qi::rule<Iterator> delim;
  qi::rule<Iterator, std::string(), qi::space_type> title;
  qi::rule<Iterator, std::string(), qi::space_type> sender, receiver, id;
  qi::rule<Iterator, unsigned int(), qi::space_type> seqNo;
  qi::rule<Iterator, message(), qi::space_type> start;
};

int
main(int args, char** argv)
{
  typedef std::istreambuf_iterator<char> base_iterator_type;
  typedef boost::spirit::multi_pass<base_iterator_type> forward_iterator_type;
  typedef boost::spirit::classic::position_iterator2<forward_iterator_type> pos_iterator_type;
  typedef MyQiGrammar<pos_iterator_type> qi_parser;

  std::string rawMsg = "(ABCZ/Y002-GWI4576)";
  qi_parser myGrammarParser;
  message msg;

  std::istringstream iss(rawMsg);
  base_iterator_type in_begin(iss);
  forward_iterator_type fwd_begin = boost::spirit::make_default_multi_pass(in_begin);
  forward_iterator_type fwd_end;
  pos_iterator_type pos_begin(fwd_begin, fwd_end);
  pos_iterator_type pos_end;

  std::cout << rawMsg << std::endl;

  try {
    bool msgRes = qi::phrase_parse(pos_begin, pos_end,
                                   myGrammarParser,
                                   qi::space,
                                   msg);

    if(msgRes) {
      std::cout << "Parsing succeeded!" << std::endl;

      if(pos_begin == pos_end) {
        std::cout << "Full match!" << std::endl;
        std::cout << "Title                  : " << msg.title << std::endl;
        std::cout << "Sender                 : " << msg.sender << std::endl;
        std::cout << "Receiver               : " << msg.receiver << std::endl;
        std::cout << "Sequence number        : " << msg.seqNo << std::endl;
        std::cout << "Sender (ref.)          : " << msg.senderRef << std::endl;
        std::cout << "Receiver (ref.)        : " << msg.receiverRef << std::endl;
        std::cout << "Sequence number (ref.) : " << msg.seqNoRef << std::endl;
        std::cout << "Message Identifier     : " << msg.id << std::endl;
      }
    } else {
      std::cout << "Parsing failed!" << std::endl;
      std::cout << "Stopped at: " << pos_begin.get_position().line
                << ":" << pos_begin.get_position().column << std::endl;
    }
  } catch(qi::expectation_failure<pos_iterator_type>& e) {
    const boost::spirit::classic::file_position_base<std::string>& pos = e.first.get_position();
    std::stringstream ss;

    ss << "Parse error at line " << pos.line << " column " << pos.column
       << "\n\t" << e.first.get_currentline()
       << "\n\t" << std::string(pos.column, ' ') << "^--here";

    std::cerr << ss.str() << std::endl;
  }

  return 0;
}

这是为什么?

提出了一个类似的(更容易分析)问题。还解释了如何解决另一个类似的问题。使用其中描述的方法,你可以得到我认为可以得到你期望的结果。(添加标签和/或可能有助于你的问题获得更多曝光)如果你想将
seqNoRef
初始化为1,你应该在默认构造函数中这样做,类似的东西可以工作。非常感谢!有趣的是,一个新的结构可以解决这个问题,但不是一个带有可选运算符的括号。为什么不在回答中加上这个?
'('<TITLE><SENDER>'/'<RECEIVER><SEQNO>[<SENDERREF>'/'<RECEIVERREF><SEQNOREF>]'-'<MID>')'
Parsing succeeded!
Full match!
Title                  : ABC
Sender                 : Z
Receiver               : Y
Sequence number        : 2
Sender (ref.)          :
Receiver (ref.)        : GWI4576             <--- Message identifier
Sequence number (ref.) : 3072563792          <--- uninitialized, can be neglected
Message Identifier     :
Parsing succeeded!
Full match!
Title                  : ABC
Sender                 : Z
Receiver               : Y
Sequence number        : 2
Sender (ref.)          : YZ                  <--- Sender and receiver!?
Receiver (ref.)        : GWI4576             <--- Message identifier
Sequence number (ref.) : 3214704440          <--- uninitialized, but should be 1
Message Identifier     :
Parsing failed!
Stopped at: 1:1