在填充到结构体之前解码提取的表达式

Decode extracted expression prior to populating into a struct

本文关键字:解码 提取 表达式 填充 结构体      更新时间:2023-10-16

我正在尝试创建一个boost::spirit::qi解析器,它将从'编码'字符串填充结构。字符串的内容是ascii十六进制数据,但我需要提取的字段不一定是按字节对齐的。

我创建了一个简单的例子,我做了类似的事情,提取一个字符串,并从字符串中填充select字符到一个结构体。最终版本需要更复杂的解码,但这里演示了总体思路。

我的解析器。我已经将十六进制字符串解析器绑定到构造结构的语义操作。

template <typename Iterator>
struct MyDataParser : qi::grammar<Iterator, MyData()>
{
    static MyData ExtractMyData( const std::vector<char, std::allocator<char> >& val)
    {
        return MyData(val.at(0), val.at(3), val.at(6));
    }
    MyDataParser() : MyDataParser::base_type( decode_rule )
    {
        using namespace qi::labels;
        auto data_string = qi::repeat(8)[qi::xdigit];
        decode_rule %=
            data_string[ boost::phoenix::bind(&ExtractMyData,_1) ]
            ;
    }
    qi::rule<Iterator, MyData()> decode_rule;
};

结构体声明。需要两个构造函数来编译。

struct MyData
{
    char first_char;
    char fourth_char;
    char seventh_char;
    MyData(char first = 0, char fourth = 0, char seventh = 0)
        : first_char(first), fourth_char(fourth), seventh_char(seventh) {}
    MyData( const std::vector<char, std::allocator<char> >& val)
        : first_char(val.at(0)), fourth_char(val.at(3)), seventh_char(val.at(6)) {}
};
BOOST_FUSION_ADAPT_STRUCT(
    MyData,
    (char, first_char)
    (char, fourth_char)
    (char, seventh_char)
)

然而,这看起来有点像一个hack。是否有一个内置的机制来支持qi错误处理?理想情况下,应该直接调用该actor,而不是调用语义操作。

编辑-让我澄清一下我在拍摄什么

他很好地回答了我的问题,但我没有传达全部内容。

1)我想解码一个十六进制字符串使用转换函数。2)使用不耦合到结构体的解析器执行上述操作。

在完美的情况下,我将有一个最终的顶级规则,看起来像这样:

auto rule %= char_
          << int_
          << hex_str_parser
          << repeat(8)[char_]
          ;

这将填充到一个结构体中,该结构体的定义类似如下:

struct MyData {
    char my_char;
    int my_int;
    unsigned my_hex_value1;  // extracted vai hex_str_parser
    unsigned my_hex_value2;  // extracted vai hex_str_parser
    unsigned my_hex_value3;  // extracted vai hex_str_parser
    std::string my_string;
};

我如何定义一个规则,根据自定义规则从嵌入字符串中提取内容,并无缝地适合另一个解析器?

在我看来,这里并没有使用任何自动属性传播。因此,您可以不使用BOOST_FUSION_ADAPT_*帮助程序¹。

MyData是一个聚合²,所以如果您不想要它,则不需要该构造函数。MyData{'a', '2', 'e'}为聚合初始化。

最后,我将使用phoenix::function来使语义动作更漂亮:

Live On Coliru

#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <iostream>
namespace qi = boost::spirit::qi;
struct MyData { char first_char, fourth_char, seventh_char; };
template <typename Iterator>
struct MyDataParser : qi::grammar<Iterator, MyData()>
{
    MyDataParser() : MyDataParser::base_type(start)
    {
        using namespace qi;
        start = repeat(8)[xdigit] [_val = _decode(_1)];
    }
  private:
    qi::rule<Iterator, MyData()> start;
    struct DecodeF {
        MyData operator()(const std::vector<char, std::allocator<char> >& val) const {
            return { val.at(0), val.at(3), val.at(6) };
        }
    };
    boost::phoenix::function<DecodeF> _decode;
};
int main() {
    std::string const input = "12345678";
    MyData data;
    if (qi::parse(input.begin(), input.end(), MyDataParser<std::string::const_iterator>(), data))
        std::cout << data.first_char << ":" << data.fourth_char << ":" << data.seventh_char << "n";
}

打印

1:4:7

除此之外,他们是老式的。c++ 11允许BOOST_FUSION_ADAPT_STRUCT(MyData, first_char, fourth_char, seventh_char)²实际上,这里是POD