动态Spirit解析器取决于标志位

时间:2012-02-20 21:27:39

标签: c++ binary-data boost-spirit

我正在尝试构建一个解析器,它根据初始位字段的内容决定是否解析字段:

rule<Iterator, locals<uint32_t> > r =
    big_dword [_a = _1]
    >> (((_a & 0x01) >> big_dword) | attr(100))
    >> (((_a & 0x10) >> big_dword) | attr(0))
    >> (((_a & 0x80) >> big_qword) | attr(0))
    ;

也就是说,如果设置了LSB,它只会尝试提取第一个字段,如果没有,它会将默认值100作为属性等公开,依此类推其他字段。

(来自:spirit-general列表)

1 个答案:

答案 0 :(得分:3)

好的,你让我猜实际的问题。

但是我用一些'告诉'后备值编写了一些测试用例。我使用业力来格式化解析结果。为了更好的衡量(真的检查我自己的理智),我提供了little-endian和big-endian测试结果。

希望这会有所帮助:

代码

#include <boost/fusion/adapted.hpp>
#include <boost/tuple/tuple_io.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/karma.hpp>
#include <boost/spirit/include/phoenix.hpp>

namespace qi    = boost::spirit::qi;
namespace karma = boost::spirit::karma;
namespace phx   = boost::phoenix;

template <typename dword_t, typename qword_t, typename Cases>
void test(const dword_t& dword, const qword_t& qword, const Cases& cases)
{
    typedef boost::tuple<uint32_t,uint32_t,uint32_t,uint64_t> attr_t;
    typedef const char* Iterator;
    int count = 0;

    for (auto testcase : cases)
    {
        Iterator f = reinterpret_cast<const char*>(&*testcase.begin());
        Iterator l = reinterpret_cast<const char*>(&*testcase.end());
        Iterator b = f;

        qi::rule<Iterator, attr_t(), qi::locals<uint32_t> > r;

        r %=   dword [ qi::_a = qi::_1 ]
            >> (( qi::eps(qi::_a & 0x01ul) > dword) | qi::attr(0x0123ul ))
            >> (( qi::eps(qi::_a & 0x10ul) > dword) | qi::attr(0x0234ul ))
            >> (( qi::eps(qi::_a & 0x80ul) > qword) | qi::attr(0x0345ull))
            ;

        attr_t data;
        bool ok = qi::parse(f,l,r,data);

        std::cout << std::dec    << "testcase "         << count++ << "\t"
                  << "success: " << std::boolalpha      << ok      << "\t"
                  << "parsed: "  << std::distance(b, f) << (f==l?"(complete)\n":"(incomplete)\n")
                  << "\t"        << std::hex            << data    << "\n";
    }
}

typedef std::vector<uint32_t> Input;

int main()
{
    std::cout << "little endian: ";
    test(qi::dword, qi::qword, std::list<Input> { 
            { 0x11110000u, 0x22220000u, 0x44440000u, 0x88880000u, 0x99990000u, },
            { 0x11110001u, 0x22220000u, 0x44440000u, 0x88880000u, 0x99990000u, },
            { 0x11110010u, 0x22220000u, 0x44440000u, 0x88880000u, 0x99990000u, },
            { 0x11110080u, 0x22220000u, 0x44440000u, 0x88880000u, 0x99990000u, },
            { 0x11110011u, 0x22220000u, 0x44440000u, 0x88880000u, 0x99990000u, },
            { 0x11110081u, 0x22220000u, 0x44440000u, 0x88880000u, 0x99990000u, },
            { 0x11110091u, 0x22220000u, 0x44440000u, 0x88880000u, 0x99990000u, },
        });

    std::cout << "\nbig endian: ";
    test(qi::big_dword, qi::big_qword, std::list<Input> { 
            { 0x00001111u, 0x00002222u, 0x00004444u, 0x00008888u, 0x00009999u, },
            { 0x01001111u, 0x00002222u, 0x00004444u, 0x00008888u, 0x00009999u, },
            { 0x10001111u, 0x00002222u, 0x00004444u, 0x00008888u, 0x00009999u, },
            { 0x80001111u, 0x00002222u, 0x00004444u, 0x00008888u, 0x00009999u, },
            { 0x11001111u, 0x00002222u, 0x00004444u, 0x00008888u, 0x00009999u, },
            { 0x81001111u, 0x00002222u, 0x00004444u, 0x00008888u, 0x00009999u, },
            { 0x91001111u, 0x00002222u, 0x00004444u, 0x00008888u, 0x00009999u, },
        });
}

输出

little endian: testcase 0   success: true   parsed: 4(incomplete)
    (11110000 123 234 345)
testcase 1  success: true   parsed: 8(incomplete)
    (11110001 22220000 234 345)
testcase 2  success: true   parsed: 8(incomplete)
    (11110010 123 22220000 345)
testcase 3  success: true   parsed: 12(incomplete)
    (11110080 123 234 4444000022220000)
testcase 4  success: true   parsed: 12(incomplete)
    (11110011 22220000 44440000 345)
testcase 5  success: true   parsed: 16(incomplete)
    (11110081 22220000 234 8888000044440000)
testcase 6  success: true   parsed: 20(complete)
    (11110091 22220000 44440000 9999000088880000)

big endian: testcase 0  success: true   parsed: 4(incomplete)
    (11110000 123 234 345)
testcase 1  success: true   parsed: 8(incomplete)
    (11110001 22220000 234 345)
testcase 2  success: true   parsed: 8(incomplete)
    (11110010 123 22220000 345)
testcase 3  success: true   parsed: 12(incomplete)
    (11110080 123 234 2222000044440000)
testcase 4  success: true   parsed: 12(incomplete)
    (11110011 22220000 44440000 345)
testcase 5  success: true   parsed: 16(incomplete)
    (11110081 22220000 234 4444000088880000)
testcase 6  success: true   parsed: 20(complete)
    (11110091 22220000 44440000 8888000099990000)