boost之spirit学习-mini_c(5)

原创 2012年03月29日 21:53:46

继续看看周边的小东西,从易到难。今天是annotation.hpp

annotation.hpp里定义了一个类:annotation。

顾名思义,它是给抽象语法树里的对象做标注的。标注什么呢?标注对象的位置。每个待标注的对象有一个id,这个id是一个iterator数组的下标。每次标注一个对象时,就把该对象的位置追加到iter数组的尾部,同时把该数据在数组中的下标作为id赋给该对象。

具体如何实现的呢?上代码:

    template <typename Iterator>
    struct annotation
    {   
        template <typename, typename>
        struct result { typedef void type; };

        std::vector<Iterator>& iters;
        annotation(std::vector<Iterator>& iters)
          : iters(iters) {}

首先,annotation定义了一个result嵌套结构体类型。这是boost的一个常用手法,用于获取函数对象的类型。例如函数对象F可能声明两个函数:

A operator() (int);
B operator() (double);
但怎么在编译时得知F(double)的返回值类型是A还是B呢?C++11引入了decltype可以解决这个问题。但在还没有C++11的时候,就要自己指定了。然后用boost::result_of<F(T1, T2...)>::type来获取。

annotation这个地方的result定义和boost::result_of还不太一样,不是用函数签名作为模板参数,而是直接用函数参数作为模板函数。这个应该是phoenix::function内部的使用方式吧(我猜测)。


然后定义了一个vector<Iterator>的引用。这个引用来自error_handler,全局只有一份,多个annotation对象共享。

        struct set_id
        {
            typedef void result_type;

            int id;
            set_id(int id) : id(id) {}

            void operator()(ast::function_call& x) const
            {
                x.function_name.id = id;
            }

            void operator()(ast::identifier& x) const
            {
                x.id = id;
            }

            template <typename T>
            void operator()(T& x) const
            {
                // no-op
            }
        };

        void operator()(ast::operand& ast, Iterator pos) const
        {
            int id = iters.size();
            iters.push_back(pos);
            boost::apply_visitor(set_id(id), ast);
        }

接下来这段比较有意思。定义了一个叫set_id的函数对象类型。用来给各种不同的语法对象设置id。看起来很蛋疼的样子,不就是设置一个id字段嘛,似乎有种脱了裤子放屁的味道。

其实不然,这是boost::variant的规范使用模式。boost::variant相当于一个C++版的高级union。你不知道它里面现在存的是什么类型,但你想针对每种不同的类型做一个特定的操作,boost::apply_visitor就派上用场了。它会根据ast里当前存储的实际类型,调用相应的operator()重载函数。

        void operator()(ast::variable_declaration& ast, Iterator pos) const
        {   
            int id = iters.size();
            iters.push_back(pos);
            ast.lhs.id = id; 
        }   

        void operator()(ast::assignment& ast, Iterator pos) const
        {   
            int id = iters.size();
            iters.push_back(pos);
            ast.lhs.id = id; 
        }   

        void operator()(ast::return_statement& ast, Iterator pos) const
        {   
            int id = iters.size();
            iters.push_back(pos);
            ast.id = id; 
        }   

        void operator()(ast::identifier& ast, Iterator pos) const
        {   
            int id = iters.size();
            iters.push_back(pos);
            ast.id = id; 
        }   
    };  

后边就是针对各种不同的语法对象做标注的重载函数了。这些operator()函数分别对应着annotation的各处使用:

        on_success(identifier,
            annotation_function(error_handler.iters)(_val, _1));
        on_success(variable_declaration,
            annotation_function(error_handler.iters)(_val, _1));
        on_success(assignment,
            annotation_function(error_handler.iters)(_val, _1));
        on_success(return_statement,
            annotation_function(error_handler.iters)(_val, _1));
        on_success(primary_expr,
            annotation_function(error_handler.iters)(_val, _1));
on_success是spirit::qi的一个函数:

    template <
        typename Iterator, typename T0, typename T1, typename T2
      , typename F>
    void on_success(rule<Iterator, T0, T1, T2>& r, F f)
接受两个参数,第一个是处理的规则 ,第二个是个函数对象,在成功匹配规则时调用。

函数对象的调用为:

                typedef
                    fusion::vector<
                        Iterator&
                      , Iterator const&
                      , Iterator const&>
                params;
                skip_over(first, last, skipper);
                params args(first, last, i);
                f(args, context);
f只接受两个参数,但第一个参数是boost::fusion::vector,估计spirit的_1、_2会把这种类型的参数打平。

所以可以认为f接受4个参数:first、last、i、context。

_val表示rule解析出的attribute,存储在context里。_1就表示first啦。


ok ,今天的解析到此为止,下班回家。改天正式开始解析function、statement、expression这三个解析代码的核心。




版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

boost之spirit学习-mini_c(2)

main.cpp就一个main函数,倒是直接明了 main函数大概的流程: 读代码文件 使用spirit将代码解析成抽象语法树 使用compiler把语法树编译成字节码 从编译后...

boost之spirit学习-mini_c(3)

前一章分析完了main.cpp,了解了mini_c的主流程。现在来看看抽象语法树的定义:ast.hpp 首先,为一些对象打上id,方便编译错误时由对象的id查找到出错的位置(这个是由anno...

boost之spirit学习-mini_c(4)

今天看看error_handler.hpp,先把这些周边的东西搞清楚。 /////////////////////////////////////////////////////////...

boost之spirit学习

最近一段时间对boost比较着迷。看了一些boost代码后惊叹C++居然可以写成这样。 C++强大的模板、运算符重载让C++拥有强大的灵活性,可以模仿很多其它语言的语法,在解决某个具体问题时可以...

Boost.Spirit x3学习笔记

为了能够在Visual Studio 2015 RC上运行,需要做如下修改 1、修改boost/spirit/home/x3/nonterminal/detail/rule.hpp中的has_on_e...

boost库spirit

  • 2016-10-09 22:03
  • 1.67MB
  • 下载

boost 中spirit 连续解析 employee 成容器变量

#include #include #include #include #include #include #include #include #include #include ...

在msvc中使用Boost.Spirit.X3

http://www.cnblogs.com/IndignangAngel/p/5026269.html Preface “Examples of designs that meet ...

boost之词法解析器spirit

boost之词法解析器spirit http://blog.csdn.net/crazyhacking/article/details/37603075 摘要:解析...

用Boost::spirit库写C++的源代码解析器(二) 完善的C++ enum的解析器(完全符合C++规范)

经过两天对Spirit、phoenix的熟悉终于完善了enum的解析器,他完全符合C++规范。   #include #include #include #include #include ...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)