Изменить тип атрибута при разборе двоичного файла с boost :: spirit - PullRequest
8 голосов
/ 15 марта 2012

Я успешно использовал boost::spirit::qi для анализа потока, состоящего из встроенных анализаторов (например, byte_, little_word и т. Д.).Однако теперь мне нужно проанализировать данные, которые не подпадают под одну из этих категорий.Например, я хотел бы преобразовать двоичное число с фиксированной запятой 16.16 в двойное число;например, little_word << little_16p16 будет анализировать uint16_t, за которым следует double (синтаксический анализ числа с фиксированной точкой).

Сначала я рассмотрел семантические действия, но (я думаю ...), что онине подходит, потому что они не изменяют тип атрибута, связанного с анализатором.Я также не могу понять, как адаптировать *1000* пример структурного анализа сотрудников к этой ситуации, потому что он опирается на неявное приведение, предоставленное boost::fusion.Этот подход не будет работать здесь, потому что я, очевидно, не могу определить неявное приведение от uint32_t до double, не вызывая серьезных проблем.

Я склонен к тому, что мне нужно добавить нетерминалы для переносавстроенные двоичные примитивные парсеры или написать терминальный парсер с нуля.Даже глядя на источник qi_binary.hpp, я не уверен, как это сделать.Может ли кто-нибудь предоставить пример кода и / или направить меня к соответствующим ссылкам, чтобы начать?

1 Ответ

7 голосов
/ 15 марта 2012
    template < typename Iterator >
    struct parser : boost::spirit::qi::grammar < Iterator, double(), boost::spirit::ascii::space_type >
    {
        struct cast_impl
        {
            template < typename A >
            struct result { typedef double type; };

            double operator()(boost::fusion::vector < boost::uint16_t, boost::uint16_t > arg) const
            {
                // cast here
                return 0;
            }
        };

        parser() : parser::base_type(main)
        {
            pair = boost::spirit::qi::little_word >> '.' >> boost::spirit::qi::little_word;
            main = pair[boost::spirit::qi::_val = cast(boost::spirit::qi::_1)];
        }

        boost::spirit::qi::rule < Iterator, boost::fusion::vector < boost::uint16_t, boost::uint16_t > (), boost::spirit::ascii::space_type > pair;
        boost::spirit::qi::rule < Iterator, double(), boost::spirit::ascii::space_type > main;

        boost::phoenix::function<cast_impl> cast;
    };

    int _tmain(int argc, _TCHAR* argv[])
    {
        typedef std::string container;

        container data_ = "\x01\x02.\x01\x02";

        container::iterator iterator_ = data_.begin();

        double value_;

        bool result_ =
            boost::spirit::qi::phrase_parse(iterator_, data_.end(),
            parser < container::iterator > (),
            boost::spirit::ascii::space,
            value_);

        return 0;
    }
...