继续看看周边的小东西,从易到难。今天是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这三个解析代码的核心。