• 2.X3-解析器语义动作


    Parser Semantic Actions(解析器语义动作)

    前面的示例非常简单。它只是识别数据,但没有对数据执行任何操作。它只回答了一个问题:输入是否匹配? 现在,我们希望从已解析的内容中提取信息。例如,我们可能希望在成功匹配后存储已解析的数字。为此,您需要使用语义动作。

    语义动作可以附加到语法规范的任何位置。这些动作是多态的函数对象,每当解析器成功识别输入的一部分时,它们就会被调用。假设您有一个解析器 p 和一个多态的C++函数对象 f。您可以通过将函数对象 f 附加到解析器来使解析器在匹配输入时调用它:

    p[f]
    
    • 1

    上述表达式将函数对象 f 与解析器 p 关联起来。f 应该是一个多态函数对象,其签名为:

    template <typename Context>
    void operator()(Context const& ctx) const;
    
    • 1
    • 2

    我们也可以使用C++14中的通用lambda函数,形式如下:

    [](auto& ctx) { /*...*/ }
    
    • 1

    从上下文中,我们可以提取相关信息:

    FunctionDescriptionExmaple
    _val对直接或间接调用parser p 的最内层规则的属性的引用_val(ctx) = “Gotya!”
    _where输入流的迭代器范围_where(ctx).begin()
    _attr对解析器 p 的属性的引用_val(ctx) += _attr(ctx)
    _pass一个用于强制解析器 p 失败的布尔标志的引用_pass(ctx) = false

    Examples of Semantic Actions

    struct print_action
    {
        template <typename Context>
        void operator()(Context const& ctx) const
        {
            std::cout << _attr(ctx) << std::endl;
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    需要注意的是,使用函数对象时,我们需要拥有一个带有 Context 参数的 operator()。如果我们不关心上下文,可以使用 unused_type。我们将在其他地方看到更多关于 unused_type 的内容。unused_type 是Spirit库提供的支持类。

    所有示例都解析以下格式的输入:

    "{NNN}
    
    • 1

    其中 NNN 是大括号内的整数(例如,{44})。

    第一个示例展示了如何附加一个函数对象:

    parse(first, last, '{' >> int_[print_action()] >> '}');
    
    • 1

    有什么新内容吗?int_ 是 double_ 的兄弟。我相信你可以猜到这个解析器是做什么的。

    下一个示例展示了如何使用C++14 lambda函数:

    auto f = [](auto& ctx){ std::cout << _attr(ctx) << std::endl; };
    parse(first, last, '{' >> int_[f] >> '}');
    
    • 1
    • 2

    Exmaple

    #include 
    
    #include 
    
    // Presented are various ways to attach semantic actions
    //  * Using plain function pointer
    //  * Using simple function object
    
    namespace client
    {
        namespace x3 = boost::spirit::x3;
        using x3::_attr;
    
        struct print_action
        {
            template <typename Context>
            void operator()(Context const& ctx) const
            {
                std::cout << _attr(ctx) << std::endl;
            }
        };
    }
    
    int main()
    {
        using boost::spirit::x3::int_;
        using boost::spirit::x3::parse;
        using client::print_action;
    
        { // example using function object
    
            char const *first = "{43}", *last = first + std::strlen(first);
            parse(first, last, '{' >> int_[print_action()] >> '}');
        }
    
        { // example using C++14 lambda
    
            using boost::spirit::x3::_attr;
            char const *first = "{44}", *last = first + std::strlen(first);
            auto f = [](auto& ctx){ std::cout << _attr(ctx) << std::endl; };
            parse(first, last, '{' >> int_[f] >> '}');
        }
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
  • 相关阅读:
    VirtualLab Fusion中的参数耦合
    【Java SE】数组常见问题及技巧用法
    绕不过的并发编程--synchronized原理
    【LeetCode Cookbook(C++ 描述)】一刷二叉树之递归遍历(DFS)(下)
    工业智能网关BL110应用之五十: 数据上传云金鸽Modbus的配置
    postMessage跨域传参
    一次生产环境的docker MySQL故障
    V 神:Rollup 二层网络的三个阶段
    【QT+QGIS跨平台编译】之五十三:【QGIS_CORE跨平台编译】—【qgssqlstatementparser.cpp生成】
    Java 之 IO流
  • 原文地址:https://blog.csdn.net/qq_40178082/article/details/133844840