【问题标题】:Generic parser generator in boost::spirit::x3boost::spirit::x3 中的通用解析器生成器
【发布时间】:2020-05-25 21:25:23
【问题描述】:

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

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 工作?

【问题讨论】:

    标签: c++ c++11 boost boost-spirit


    【解决方案1】:
    1. 您不需要公开所有属性,大大简化了属性类型。

    2. 1234563 .在 x3 表达式中,一个裸露的"aaa" 将自动被解释为x3::lit("aaa")(由于x3::as_parser)。
    3. 更重要的是,您正在处理 at_c&lt;2&gt; 暗示您也不希望 x3::blank 暴露。为什么不简单地x3::omit[x3::blank]?更好的是,考虑使用船长,并隐含它。

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

      由于您的操作绑定到解析器参数,因此您似乎需要 its 属性,可以改为使用 x3::_attr() 进行查询。

      看来你完全可以不用语义动作,见下文

    修正想法:

    这结合了以上所有内容:

    Live On 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
    

    Live On 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

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

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多