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

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

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

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

最佳答案

  • 您不需要公开所有属性,大大简化了属性类型。
  • 要匹配字符串文字而不将其公开为键(显然,您无论如何都不想这样做,因为您在语义操作中忽略了它),请使用 x3::lit("aaa") 而不是 x3::string("aaa") 。在 x3 表达式中,裸 "aaa" 将自动被解释为 x3::lit("aaa")(由于 x3::as_parser )。
  • 更重要的是,您正在处理 at_c<2> 暗示您也不希望 x3::blank 暴露。为什么不简单地 x3::omit[x3::blank] ?更好的是,考虑使用 skipper ,并隐含。
  • action 中,您使用的是 x3::_val ,这取决于声明的规则的属性(看不到 x3::rule 吗?)或实际的绑定(bind)引用(您没有向 x3::parse 传递任何内容)。

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

    It seems you might be able to do without semantic actions altogether, see below


  • 修复思路:

    这结合了以上所有内容:
  • 使用 skipper (参见 Boost spirit skipper issues )
  • 简化字面量

  • 看到它 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
    
  • 使用 label() 助手检查强制空白/ token 边界(请参阅 Stop X3 symbols from matching substrings )

  • 看到它 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

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

    关于c++ - boost::spirit::x3 中的通用解析器生成器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60152454/

    相关文章:

    C++ boost::bind/lambda 和 operator bool()

    c++ - C/C++ 宏 : How to generate two separate sections of code with one macro (boost preprocessor library? )

    c++ - 如何处理二维数组中写入的条件

    c++ - 为每个变量创建一个新的 typedef 有什么意义?

    c++ - 为什么我还必须使用 -lstdc++fs?

    c++ - 在 std::unordered_map 中查找对应于相同值的所有键

    c++ - 为什么 memory_order 作为 std::atomic 函数的运行时参数给出

    c++ - 如何将枚举类用作一组标志?

    c++ - 已删除的默认构造函数被标识为歧义错误中的候选者

    c++ - 将编译器标志添加到 CMakeLists.txt