Динамический анализатор Spirit в зависимости от битов флага - PullRequest
2 голосов
/ 21 февраля 2012

Я пытаюсь создать синтаксический анализатор, который решает, нужно ли анализировать поля на основе содержимого начального битового поля:

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

1 Ответ

3 голосов
/ 21 февраля 2012

Хорошо, вы заставляете меня догадываться о настоящем вопросе.

Но я составил несколько тестовых случаев с «говорящими» запасными значениями. Я использую карму для форматирования результата разбора. Для правильной оценки (на самом деле, проверяя мое здравомыслие) я предоставил результаты тестов как с прямым порядком байтов, так и с байтовым порядком байтов.

Надеюсь, это поможет:

Код

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