Анализатор Boost Spirit X3, который производит смещения в исходную строку

Я пытаюсь написать анализатор boost::spirit::x3, который вместо создания подстрок (например) вместо этого производит смещения и длины строк совпадений в источнике.

Я пробовал различные комбинации on_success обработчики, семантические действия и ничего действительно не сработало.

дано:

ABC\n
DEFG\n
HI\n

Я хотел бы парсер, который произвел std::vector<boost::tuple<size_t, size_t>> содержащий:

0,3
4,4
9,2

где очевидно, что это становится более сложным, когда мы сопоставляем конкретные подстроки в каждой строке, а не просто принимаем все это.

Это возможно?

1 ответ

Решение

Вот быстрый черновик.

Я заменил tuple<p, len> со структурой POD, потому что взаимодействие между x3::raw[] а также fusion/adapted/std_tuple.hpp таков, что нужно специализироваться traits::move_to в любом случае.

В таких случаях я очень предпочитаю специализированный пользовательский тип, а не специальный случай некоторых общих стандартных типов библиотек, которые могут конфликтовать с другими видами использования в других местах.

Итак, пусть структура будет

using It = char const*;
struct Range {
   It data;
   size_t size;
};

Затем, чтобы проанализировать следующий пример ввода:

char const input[] = "{ 123, 234, 345 }\n{ 456, 567, 678 }\n{ 789, 900, 1011 }";

Нам не нужно ничего, кроме простой грамматики:

x3::raw ['{' >> (x3::int_ % ',') >> '}'] % x3::eol

И специализация дито-черта:

namespace boost { namespace spirit { namespace x3 { namespace traits {
    template <> void move_to<It, Range>(It b, It e, Range& r) { r = { b, size_t(e-b) }; }
} } } }

Полная демонстрация

Жить на Колиру

#include <boost/spirit/home/x3.hpp>
#include <iostream>

using It = char const*;
struct Range {
   It data;
   size_t size;
};

namespace boost { namespace spirit { namespace x3 { namespace traits {
    template <> void move_to<It, Range>(It b, It e, Range& r) { r = { b, size_t(e-b) }; }
} } } }

int main() {
    char const input[] = "{ 123, 234, 345 }\n{ 456, 567, 678 }\n{ 789, 900, 1011 }";

    std::vector<Range> ranges;

    namespace x3 = boost::spirit::x3;
    if (x3::phrase_parse(
            std::begin(input), std::end(input), 
            x3::raw ['{' >> (x3::int_ % ',') >> '}'] % x3::eol,
            x3::blank,
            ranges)
        )
    {
        std::cout << "Parse results:\n";
        for (auto const& r : ranges) {
            std::cout << "(" << (r.data-input) << "," << r.size << ")\n";
        }
    } else {
        std::cout << "Parse failed\n";
    }
}

Печать:

Parse results:
(0,17)
(18,17)
(36,18)
Другие вопросы по тегам