boost spirit X3 解析器生成原始字符串的偏移量

boost spirit X3 parser which produces offsets into the original string

我正在尝试编写一个 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

很明显,当我们在每一行上匹配特定的子字符串时,它会变得更加复杂,而不是只匹配整个内容。

这可能吗?

这是一个草稿。

我已经将 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

以及 dito 特质专精:

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) }; }
} } } }

完整演示

Live On Coliru

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