繁体   English   中英

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

[英]Generic parser generator in boost::spirit::x3

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

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 ::在望规则吗?)或实际界限参考(你没有通过什么x3::parse )。

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

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

修复思路:

这结合了以上所有内容:

在 Coliru 上观看直播

#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 << "Failed\n";
        }
    }
}

印刷

Parsed 42
Parsed 99

在 Coliru 上观看直播

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: parse into structs

实际上,我不会在此处复制该示例中的代码,但我认为它可能非常适用于您的用例。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM