前年写了 gcc源码分析,感觉写的不好,如果没有源代码读起来很痛苦,基本上是读天书,这一次改了一种写法,用另一种思路来写,希望这一次能好一点:
1.基本数据结构
编译器前端主要的任务就是把输入的源码转换成一棵语法树,
在gcc中,树的每一个节点用一个结构体来表示,下面就来谈一谈gcc中用到的这个结构体:
union tree_node
{
struct tree_common common;
struct tree_identifier identifier;
struct tree_list list;
struct tree_exp exp;
struct tree_type type;
struct tree_decl decl;
struct tree_int_cst int_cst;
struct tree_string string;
struct tree_bind_stmt bind_stmt;
struct tree_stmt stmt;
};
这个结构体由两部分组成,一个通用部分struct tree_common,另一个就是同节点相关的部分;
比如如果这个节点记录的是一个ID,那相关部分就用struct tree_identifier,
如果记录的是一个整形数值就用struct tree_int_cst来表示。
所以这个结构体就用一个联合体来表示,所谓联合体就是它的所有成员的起始地址都一样,为了让两个
结构体不相互干扰,就让具体类型的结构体第一个成员变量所占据的空间恰恰就是通用部分的大小;比如struct tree_identifier结构体,它的定义如下:
struct tree_identifier
{
char common[sizeof (struct tree_common)];
int length;
char *pointer;
};
你看它前面部分的common成员变量,它占据的空间是sizeof (struct tree_common),恰恰就是通用结构的大小
后面就是这个表示ID有关系的部分了,对于ID来说,我们关心它的长度,就用一个length来记录,然后就是
ID的名称,这里就用char *来表示。
对任意一个ID来说,它通常还有一个类型,比如它是interger,char ,short 或者表示的是一个function,
这个类型记在tree_common中,下面看看tree_common结构:
struct tree_common
{
int uid;
union tree_node *chain;
union tree_node *type;
enum tree_code code : 8;
unsigned permanent_attr : 1;
unsigned external_attr : 1;
unsigned public_attr : 1;
unsigned inline_attr : 1;
unsigned static_attr : 1;
unsigned regdecl_attr : 1;
unsigned this_vol_attr : 1;
unsigned volatile_attr : 1;
unsigned packed_attr : 1;
unsigned readonly_attr : 1;
unsigned addressable_attr:1;
unsigned used_attr:1;
unsigned unsigned_attr:1;
unsigned literal_attr:1;
unsigned asm_written_attr: 1;
};
重要成员变量分析:
uid : 就是不重复的一个标识ID,用来与其他节点区分开来;
chain : 用于许多目的,比如记录输出到调试器的东西;
type :对于表达式,它是一个数据类型;POINTER_TYPE节点就是一个指针,ARRAY_TYPE节点就使
元素的数据类型;
code :表示这个节点的种类,所有的种类记录在tree.def中
版权声明:本文为博主原创文章,未经博主允许不得转载。