C++ Spirit:如何解析字节数组之前的长度?

C++ Spirit:如何解析字节数组之前的长度?,c++,boost,binary,hex,boost-spirit,C++,Boost,Binary,Hex,Boost Spirit,我需要解析以下字节数组“08010000113FC208DFF01” 在这里: 第1字节“08”-ID 第二字节“01”-8字节数组的长度 3-10字节-8字节数组的元素 第11字节“01”-8字节数组的长度(应与第2字节相同) 我试图使用qi::repeat(),遵循手册并实现了以下解析器 2) 我的示例没有编译错误 grammar.hpp:75:13: error: static assertion failed: incompatible_start_rule... 我做错了什么 -

我需要解析以下字节数组“08010000113FC208DFF01”

在这里:

  • 第1字节“08”-ID
  • 第二字节“01”-8字节数组的长度
  • 3-10字节-8字节数组的元素
  • 第11字节“01”-8字节数组的长度(应与第2字节相同)
我试图使用qi::repeat(),遵循手册并实现了以下解析器

2) 我的示例没有编译错误

grammar.hpp:75:13: error: static assertion failed: incompatible_start_rule...
我做错了什么

-谢谢

第一件事:

grammar.hpp:75:13:错误:静态断言失败:不兼容的\u开始\u规则

表示(令人惊讶)您使用了不兼容的开始规则。违规者是语法基类声明中缺少的
locals
参数。不要将实现细节添加到公共接口,而是考虑使用一个包装开始规则,该规则调用真正的语法分析器入口点,该点具有“代码”>本地语言< /COD>参数。
此外:

  • 什么是
    m_优先级
    呢?您的问题没有解决它,示例输入也没有(因此它不应该解析,因为只有8byte元素,并且没有优先级)

  • 您是否忘记调整AVLData

  • 忽略这一点,具有语义操作的规则不会自动传播其属性。这很好,因为您可能不需要AST节点中的那些冗余计数(
    m_numodata
    m_numodata\u last

    您可以使用
    operator%=
    而不是
    operator=
    来指定规则定义,从而强制自动传播

  • 可以使用
    omit
    从合成属性中忽略属性

  • 您可能需要验证开始/结束字节,例如:

    uint_byte_p(0x08)
    
    要检查结束字节是否与第二个匹配,请执行以下操作:

    qi::omit[uint_byte_p [ qi::_pass = (qi::_a == qi::_1) ] ]
    

    感谢@jv_uuu再次进行双重检查,您确实可以在那里说
    省略(uint_byte_p(_a))

  • 如果语法指定了
    ascii::blank\u type
    ,则无法为其传递
    qi::blank
    。它需要匹配。再次:考虑使用开始规则隐藏船长,而不是暴露实现细节。

  • 此外,在这个特定的示例中,如果您真的希望在输入字符串中的任何地方都接受空格,我会感到惊讶。还要注意,
    int\u parser
    是隐式lexeme(这意味着数组元素或字节即使在此配置中也不能包含空格)。您应该检查这些是否都符合您的要求

  • 使用期望点实际上排除了解析失败的可能性(除非第一个字节无法解析,因为第一个
    uint\u byte\u p
    前面没有像
    qi::eps>uint\u byte\u p
    这样的期望点)。考虑使用<代码> >代码>以获得正常的序列语义。

修复这些问题会产生工作代码:

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

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

typedef unsigned int BYTE; // what large bytes you have, grandma!?

struct AVLData {
    uint64_t m_timestamp;
    BYTE m_priority;
};

struct AVLDataArray {
    BYTE m_codecID;
    std::vector<AVLData> m_data;
};

BOOST_FUSION_ADAPT_STRUCT(AVLData, m_timestamp, m_priority) // you need to adapt all your types
BOOST_FUSION_ADAPT_STRUCT(AVLDataArray, m_codecID, m_data)

template <typename Iterator, typename Skipper = ascii::blank_type>
    struct Grammar: qi::grammar <Iterator, AVLDataArray(), Skipper>
    {
        Grammar() : Grammar::base_type(start)
        {
            qi::uint_parser<BYTE, 16, 2, 2> uint_byte_p;
            qi::uint_parser<uint64_t, 16, 16, 16> uint_8_byte_p;

            avl_array %= uint_byte_p(0x08)
                      >> qi::omit[uint_byte_p[qi::_a = qi::_1]] 
                      >> qi::repeat(qi::_a)[uint_8_byte_p >> uint_byte_p]
                      >> qi::omit[uint_byte_p [ qi::_pass = (qi::_a == qi::_1) ] ]
                      ;

            start      = avl_array;

            BOOST_SPIRIT_DEBUG_NODES((avl_array)(start));
        }

    private:
        qi::rule<Iterator, AVLDataArray(), Skipper> start;
        qi::rule<Iterator, AVLDataArray(), Skipper, qi::locals<BYTE>> avl_array;
};

int main() {
    std::string const input = "080100000113fc208dff" /*priority:*/ "2a" /*end prioirity*/ "01";

    auto f(begin(input)), l(end(input));
    Grammar<std::string::const_iterator> g;

    AVLDataArray array;
    bool ok = qi::phrase_parse(f,l,g,ascii::blank,array);

    if (ok && f == l) 
    {
        std::cout << "Parse succeeded\n";
        std::cout << "Codec: " << array.m_codecID << "\n";
        for(auto& element : array.m_data)
            std::cout << "element: 0x" << std::hex << element.m_timestamp << " prio " << std::dec << element.m_priority << "\n";
    } else
    {
        std::cout << "Parse failed\n";
        std::cout << "->stopped at [" + std::string(f, l) + "]";
    }

    return 0;
}
    data       = qi::repeat(qi::_r1)[uint_8_byte_p >> uint_byte_p]
              ;
    avl_array %= uint_byte_p(0x08)
              >> qi::omit[uint_byte_p[qi::_a = qi::_1]] 
              >> data(qi::_a)
              >> qi::omit[uint_byte_p [ qi::_pass = (qi::_a == qi::_1) ] ]
              ;
并且在启用调试信息的情况下:

<start>
  <try>080100000113fc208dff</try>
  <avl_array>
    <try>080100000113fc208dff</try>
    <success></success>
    <attributes>[[8, [[1185345998335, 42]]]]</attributes><locals>(1)</locals>
  </avl_array>
  <success></success>
  <attributes>[[8, [[1185345998335, 42]]]]</attributes>
</start>
规则如下:

qi::rule<Iterator, std::vector<AVLData>(BYTE), Skipper> data;
qi::rule<Iterator, AVLDataArray(),             Skipper, qi::locals<BYTE>> avl_array;
qi::规则数据;
qi::规则avl_数组;

答案不错,我认为
uint\u byte\u p[qi::\u pass==(qi::\u a==qi::\u 1)]
也可以写成
uint\u byte\u p(qi::\u a)
@jv\u。我的测试告诉我不是这样。(我想,从性能的角度来看,缺少此功能有一点道理)如果不太麻烦的话,您可以展示这些测试吗?我认为它做了它应该做的(而且显然(而且令人困惑的是,因为它肯定会工作)。计算结果为无符号整数的惰性参数的使用是Oops<代码>\u pass==应该是作业(
\u pass=
)@jv\uu我回家后会编辑是的,我们都是盲人:p。
<start>
  <try>080100000113fc208dff</try>
  <avl_array>
    <try>080100000113fc208dff</try>
    <success></success>
    <attributes>[[8, [[1185345998335, 42]]]]</attributes><locals>(1)</locals>
  </avl_array>
  <success></success>
  <attributes>[[8, [[1185345998335, 42]]]]</attributes>
</start>
    data       = qi::repeat(qi::_r1)[uint_8_byte_p >> uint_byte_p]
              ;
    avl_array %= uint_byte_p(0x08)
              >> qi::omit[uint_byte_p[qi::_a = qi::_1]] 
              >> data(qi::_a)
              >> qi::omit[uint_byte_p [ qi::_pass = (qi::_a == qi::_1) ] ]
              ;
qi::rule<Iterator, std::vector<AVLData>(BYTE), Skipper> data;
qi::rule<Iterator, AVLDataArray(),             Skipper, qi::locals<BYTE>> avl_array;