boost :: spirit :: x3 разбирает медленнее, чем разбор strsep - PullRequest
0 голосов
/ 26 мая 2018

Я написал синтаксический анализатор x3 для анализа структурированного текстового файла, вот демонстрационный код:

int main() {
        char buf[10240];
        type_t example;   // def see below
        FILE* fp = fopen("text", "r");
        while (fgets(buf, 10240, fp))  // read to the buffer
        {
            int n = strlen(buf);
            example.clear();
            if (client::parse_numbers(buf, buf+n, example))  // def see below
            { // do nothing here, only parse the buf and fill into the example }
        }
    }

    struct type_t {
        int id;
        std::vector<int> fads;
        std::vector<int> fbds;
        std::vector<float> fvalues;
        float target;

        void clear() {
            fads.clear();
            fbds.clear();
            fvalues.clear();
        }


    };

    template <typename Iterator>
    bool parse_numbers(Iterator first, Iterator last, type_t& example)
    {
        using x3::int_;
        using x3::double_;
        using x3::phrase_parse;
        using x3::parse;
        using x3::_attr;
        using ascii::space;

        auto fn_id = [&](auto& ctx) { example.id = _attr(ctx); };
        auto fn_fad = [&](auto& ctx) { example.fads.push_back(_attr(ctx)); };
        auto fn_fbd = [&](auto& ctx) { example.fbds.push_back(_attr(ctx)); };
        auto fn_value = [&](auto& ctx) { example.fvalues.push_back(_attr(ctx)); };
        auto fn_target = [&](auto& ctx) { example.target = _attr(ctx); };

        bool r = phrase_parse(first, last,

            //  Begin grammar
            (
                int_[fn_id] >>
                double_[fn_target] >>
                +(int_[fn_fad] >> ':' >> int_[fn_fbd] >> ':' >> double_[fn_value])
            )
            ,
            //  End grammar

            space);

        if (first != last) // fail if we did not get a full match
            return false;
        return r;
    }
    //]
}

Правильно ли я делаю это или как улучшить?Я хотел бы посмотреть, можно ли провести какую-либо оптимизацию, прежде чем я вернусь к моей strsep реализации синтаксического анализа, поскольку она намного быстрее, чем эта x3 версия.

1 Ответ

0 голосов
/ 29 мая 2018

Почему вы используете для этого семантические действия?Интересная тема для чтения - статья Boost Spirit: «Семантические действия - зло»? и другие заметки.Разбор в структуру AST, как показано в примерах X3, например, Сотрудник - Разбор в структуры ИМО намного более естественен.Для оценки данных вам понадобится шаблон посетителей.

Здесь показано одно решение:

#include <iostream>
#include <sstream>
#include <fstream>
#include <vector>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/spirit/home/x3.hpp>

namespace ast {
    struct triple {
        double fad;
        double fbd;
        double value;
    };

    struct data {
        int id;
        double target;
        std::vector<ast::triple> triple;
    };
}

BOOST_FUSION_ADAPT_STRUCT(ast::triple, fad, fbd, value)
BOOST_FUSION_ADAPT_STRUCT(ast::data,   id, target, triple)

namespace x3 = boost::spirit::x3;

namespace parser {

    using x3::int_; using x3::double_;

    auto const triple = x3::rule<struct _, ast::triple>{ "triple" } =
        int_ >> ':' >> int_ >> ':' >> double_;
    auto const data = x3::rule<struct _, ast::data>{ "data" } =
        int_ >> double_ >> +triple;
}

int main()
{
    std::stringstream buffer;
    std::ifstream file{ R"(C:\data.txt)" };

    if(file.is_open()) {
        buffer << file.rdbuf();
        file.close();
    }

    auto iter = std::begin(buffer.str());
    auto const end = std::cend(buffer.str());
    ast::data data;

    bool parse_ok = x3::phrase_parse(iter, end, parser::data, x3::space, data);

    if(parse_ok && (iter == end)) return true;
    return false;
}

Оно компилируется (см. Wandbox ), но не 't протестирован из-за отсутствия входных данных (которые вы можете сгенерировать самостоятельно внутри main(), конечно), но вы заинтересованы только в сравнительном тестировании.

Также обратите внимание на использование stringstream для чтения rdbuf.Есть несколько способов обшарить кошку, я ссылаюсь здесь на Как читать в файле на C ++ , где быстрый подход к чтению rdbuf.

Далее, как вы провели тест?Просто измерьте время, необходимое для x3::phrase_parse() соотв.strsep только часть или двоичная дыра?время загрузки файла включительно?Это должно быть сопоставимо!Также рассмотрим кеширование файловой системы ОС и т. Д.

Кстати, было бы интересно посмотреть результаты и среду тестирования (размер файла данных, strsep реализация и т. Д.).

Добавление:

Если вы приблизительно знаете, сколько данных вы можете ожидать, вы можете предварительно выделить память для вектора, используя data.triple.reserve(10240); (или написать собственный конструктор с таким аргументом, как arg).Это предотвращает перераспределение во время синтаксического анализа (не забудьте включить это в блок try / catch для захвата std :: bad_alloc и т. Д.).IIR по умолчанию емкость 1000 на старых GCC.

...