前一章分析完了main.cpp,了解了mini_c的主流程。现在来看看抽象语法树的定义:ast.hpp
首先,为一些对象打上id,方便编译错误时由对象的id查找到出错的位置(这个是由annotation记录的,后边会讲)
struct tagged
{
int id; // Used to annotate the AST with the iterator position.
// This id is used as a key to a map<int, Iterator>
// (not really part of the AST.)
};
带id的对象包括:identifier、function_call、function、return_statement。
struct nil {};
struct unary;
struct function_call;
struct expression;
struct identifier : tagged
{
identifier(std::string const& name = "") : name(name) {}
std::string name;
};
typedef boost::variant<
nil
, bool
, unsigned int
, identifier
, boost::recursive_wrapper<unary>
, boost::recursive_wrapper<function_call>
, boost::recursive_wrapper<expression>
>
operand;
后边是对nil的定义,unary(一元表达式)、function_call、expression进行提前声明。
identifier的定义没啥好说的。
operand(操作数)的定义有点意思。操作数可以是空,也可以是bool、unsigned int 或 变量 或 一元表达式 或 函数调用 或 更general的表达式。它用variant来表达这种概念。
但unary、function_call、expression为什么要用boost::recursive_wrapper来定义呢?
因为它们有循环包含关系
- unary(一元表达式)里有两个成员,一个是optoken,另一个就是operand。
- expression包含了operation的列表,operation又包含了operand,所以是循环的。
- function_call里有一个expression的list,所以也是循环包含的
对于这种循环包含的对象,我们一般都用指针相互指向,对象动态分配获得。但这样的话我们就要负责对象的动