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

时间:2016-10-10 17:28:34

标签: c++ boost-spirit-qi

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

我创建了一个简单的例子,我做了类似的事情,提取字符串并将字符串中的选择字符填充到结构中。最终版本需要更复杂的解码,但这证明了一般的想法。

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

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)
)

然而,这似乎有点像黑客。是否有内置机制来支持qi错误处理?理想情况下,将直接调用ctor而不是语义操作。

编辑 - 让我澄清一下我拍摄的内容

seh做了很好的回答我的问题,但我没有完全沟通。

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;
};

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

1 个答案:

答案 0 :(得分:1)

它并不像我在这里使用任何自动属性传播那样。因此,您可以不使用BOOST_FUSION_ADAPT_ *助手¹。

MyData是一个聚合²所以如果你不想要它,你就不需要那个构造函数。 MyData{'a', '2', 'e'}aggregate initialization

最后,我使用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