Анализатор 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)