boost::spirit::x3 中的通用解析器生成器

Generic parser generator in boost::spirit::x3

本文关键字:spirit x3 boost      更新时间:2023-10-16

我正在尝试编写通用解析器生成器。我想出了以下代码:

auto attr_to_val = [](auto& ctx) { _val(ctx) = boost::fusion::at_c<2>(_attr(ctx)); };
auto parser_gen = [](const std::string a, auto&& p) {
return((boost::spirit::x3::string(a) >> boost::spirit::x3::blank >> p)[attr_to_val]);
};

并尝试像这样使用它:

int a;
auto action = [&a](auto& ctx) { a = _val(ctx); };
auto parser = (parser_gen("aaa", boost::spirit::x3::uint_))[action];
parse(bar.begin(), bar.end(), parser);

但它给出了很多关于无法将boost::fusion::deque转换为int的错误。另一方面,当我像这样更改它时,恕我直言,这相当于上述模板代码的扩展:

auto pars = (
boost::spirit::x3::string("aaa") >>
boost::spirit::x3::blank >> boost::spirit::x3::uint_)[attr_to_val];
int a;
auto action = [&a](auto& ctx) { a = _val(ctx); };
parse(bar.begin(), bar.end(), pars);

一切都很好。我做错了什么,我怎样才能parser_gen工作?

  1. 您不需要公开所有属性,从而大大简化了属性类型。

  2. 要匹配字符串文字而不将其公开为键(显然,您无论如何都不想要,因为您在语义操作中忽略了它(,请使用x3::lit("aaa")而不是x3::string("aaa")。在 x3 表达式中,裸"aaa"将自动解释为x3::lit("aaa")(由于x3::as_parser(。

  3. 更重要的是,你正在at_c<2>暗示你也不想x3::blank暴露。为什么不干脆x3::omit[x3::blank]?更好的是,考虑使用船长,并隐含它。

  4. action中,您使用的是x3::_val,这取决于声明的规则的属性(看不到 x3::rule?或实际的绑定引用(您不会向x3::parse传递任何内容(。

    由于您的操作绑定到解析器参数,因此您似乎想要它的属性,可以用x3::_attr()来查询。

    似乎你可以完全不用语义操作,见下文

修复想法:

这结合了上述所有内容:

使用船长
  • (请参阅提升精神船长问题(
  • 简化文字

科里鲁现场观看

#include <boost/spirit/home/x3.hpp>
#include <iostream>
namespace x3 = boost::spirit::x3;
int main() {
auto parser_gen = [=](std::string const a, auto&& p) {
return x3::skip(x3::blank)[ x3::lit(a) >> p ];
};
for (std::string const bar : { "aaa 42", "aaa99", }) {
int a;
if (parse(begin(bar), end(bar), parser_gen("aaa", x3::uint_), a)) {
std::cout << "Parsed " << a << "n";
} else {
std::cout << "Failedn";
}
}
}

指纹

Parsed 42
Parsed 99
  • 使用检查强制空格/标记边界的label()帮助程序(请参阅从匹配的子字符串中停止 X3 符号(

科里鲁现场观看

namespace {
template <typename P>
auto label_gen(P p) {
return x3::omit[ x3::lexeme[ x3::as_parser(p) >> (&x3::punct | !x3::graph) ] ];
}
template <typename L, typename P> auto parser_gen(L l, P p) {
return x3::skip(x3::blank)[ label_gen(l) >> p ];
}
}

现在打印的匹配项少一个:

Parsed 42
Failed

奖励:做有用的事情

所以,我的猜测是你想以一种有用的方式组合这些标签/值对中的多个,也许可以解释这些动作。现在,你可以从这个答案中得到一个页面:Boost Spirit x3:解析成结构。

实际上,我将避免在此处重现该示例中的代码,但我认为它可能非常适合您的用例。