使用 pegtl 语法正确处理状态
Handle correcly state with pegtl grammar
我对 peg 和 pegtl 还很陌生,所以我可能遗漏了什么。
我的语法与以下语法非常相似:
using namespace tao::pegtl;
struct A : one<'A'> { };
struct B : one<'B'> { };
struct comp : seq<plus<sor<seq<A, B>, A>>,eof> { };
template< typename Rule >
struct test_action : nothing< Rule > {};
template<>
struct test_action<A>
{
template< typename Input >
static void apply(const Input& in)
{
std::cout << "A";
}
};
template<>
struct test_action<B>
{
template< typename Input >
static void apply(const Input& in)
{
std::cout << "B";
}
};
void test()
{
parse< comp, test_action >(memory_input("AAB", ""));
}
解析效果很好,但是 test_action::apply 的激活太多了。
程序输出 "AAAB",因为,如果我理解得很好,解析会尝试第一个字符的第一个替代 (AB) 并失败,然后继续
与另一个 (A)。但即使它"rewinds",它总是调用test_action::apply。
处理这种情况的正确方法是什么?
我的意图是输出 "AAB",可能不会使语法复杂化。
我问过 pegtl 库的作者,他们好心地给了我正确的方法:最好的办法是让你的解析器构造一个解析树,当它使用简单的 push 和 pop 操作回溯时很容易修复。
我为有类似疑问的人开发了下面的代码。
避免在带有附加操作的规则中回溯:
using namespace tao::pegtl;
struct A : one<'A'> { };
struct B : one<'B'> { };
struct real_A : A {};
struct real_AB : seq<A, B> {};
struct comp : seq<plus<sor<real_AB, real_A>>,eof> { };
template< typename Rule >
struct test_action : nothing< Rule > {};
template<>
struct test_action<real_A>
{
template< typename Input >
static void apply(const Input& in)
{
std::cout << "A";
}
};
template<>
struct test_action<real_AB>
{
template< typename Input >
static void apply(const Input& in)
{
std::cout << "AB";
}
};
void test()
{
parse< comp, test_action >(memory_input("AAB", ""));
}
构建解析树:
using namespace tao::pegtl;
struct A : one<'A'> { };
struct B : one<'B'> { };
struct comp : seq<plus<sor<seq<A, B>, A>>, eof> { };
template< typename Rule >
struct test_action : nothing< Rule > {};
void test()
{
auto root = parse_tree::parse<comp>(memory_input("AAB", ""));
}
我对 peg 和 pegtl 还很陌生,所以我可能遗漏了什么。 我的语法与以下语法非常相似:
using namespace tao::pegtl;
struct A : one<'A'> { };
struct B : one<'B'> { };
struct comp : seq<plus<sor<seq<A, B>, A>>,eof> { };
template< typename Rule >
struct test_action : nothing< Rule > {};
template<>
struct test_action<A>
{
template< typename Input >
static void apply(const Input& in)
{
std::cout << "A";
}
};
template<>
struct test_action<B>
{
template< typename Input >
static void apply(const Input& in)
{
std::cout << "B";
}
};
void test()
{
parse< comp, test_action >(memory_input("AAB", ""));
}
解析效果很好,但是 test_action::apply 的激活太多了。 程序输出 "AAAB",因为,如果我理解得很好,解析会尝试第一个字符的第一个替代 (AB) 并失败,然后继续 与另一个 (A)。但即使它"rewinds",它总是调用test_action::apply。 处理这种情况的正确方法是什么? 我的意图是输出 "AAB",可能不会使语法复杂化。
我问过 pegtl 库的作者,他们好心地给了我正确的方法:最好的办法是让你的解析器构造一个解析树,当它使用简单的 push 和 pop 操作回溯时很容易修复。
我为有类似疑问的人开发了下面的代码。
避免在带有附加操作的规则中回溯:
using namespace tao::pegtl; struct A : one<'A'> { }; struct B : one<'B'> { }; struct real_A : A {}; struct real_AB : seq<A, B> {}; struct comp : seq<plus<sor<real_AB, real_A>>,eof> { }; template< typename Rule > struct test_action : nothing< Rule > {}; template<> struct test_action<real_A> { template< typename Input > static void apply(const Input& in) { std::cout << "A"; } }; template<> struct test_action<real_AB> { template< typename Input > static void apply(const Input& in) { std::cout << "AB"; } }; void test() { parse< comp, test_action >(memory_input("AAB", "")); }
构建解析树:
using namespace tao::pegtl; struct A : one<'A'> { }; struct B : one<'B'> { }; struct comp : seq<plus<sor<seq<A, B>, A>>, eof> { }; template< typename Rule > struct test_action : nothing< Rule > {}; void test() { auto root = parse_tree::parse<comp>(memory_input("AAB", "")); }