前面分析了表达式的语法,也分析了语句的语法,但它们最终的目的就是生成合适的中间表示,在
LCC
里是采用树作为中间表示的。
现在就来分析语句生成什么样的树表示,下面的语句是来自例子里,如下:
int nTest1 = 1;
这个语句是声明了一个局部变量
nTest1
,并且给
nTest1
赋值为
1
。
LCC
编译器要把它变换到分析树的表示,这样才利于后面的分析和使用。它的分析树如下:
左子树
=
右子树
赋值树:
左子树
-----ID
树
右子树
-----
常量表达式树
由语法分析可知,赋值语句分析过程是先生成常量表达式树,然后生成
ID
树,最后生成赋值树,把它变换到
DAG
树,然后添加到代码表。
在函数
dcllocal
里调用下面的语句生成赋值树:
walk(root(asgn(p, e)), 0, 0);
其中
e
就是已经分析生成的表达式树,在这里应是常量表达式树。
p
是指向
ID
树的符号,在
asgn
函数里生成
ID
树。这样就可以生成赋值树返回。
接着下来,我们先分析一下
ID
树怎么样表示的,它的代码如下:
#001 Tree idtree(Symbol p)
#002 {
#003 int op;
#004 Tree e;
#005 Type ty = p->type ? unqual(p->type) : voidptype;
#006
第
5
行是判断类型是否存在,如果没有类型指定为
void
类型,否则就获取符号指向的类型,并且用
unqual
宏判断类型是否基本类型,如果不是,就需要获取它的基本类型。
#007 if (p->scope == GLOBAL || p->sclass == STATIC)
#008 op = ADDRG;
#009 else if (p->scope == PARAM)
#010 {
#011 op = ADDRF;
#012 if (isstruct(p->type) && !IR->wants_argb)
#013 {
#014 e = tree(mkop(op,voidptype), ptr(ptr(p->type)), NULL, NULL);
#015 e->u.sym = p;
#016 return rvalue(rvalue(e));
#017 }
#018 }
#019 else if (p->sclass == EXTERN)
#020 {
#021 assert(p->u.alias);
#022 p = p->u.alias;
#023 op = ADDRG;
#024 }
#025 else
#026 op = ADDRL;
#027
第
7
行是根据变量的作用域和存储类型来区分变量是否全局变量。如果是全局变量,就在第
8
行里标识操作符的类型为全局变量
ADDRG
。
第
9
行是判断是否参数变量,如果是就在第
11
行里标识操作符的类型为
ADDRF
。
第
19
行是判断是否外面文件的变量,如果是也需要把它定义为全局变量的类型
ADDRG
。
第
26
行标识操作符的类型
ADDRL
,这就是局部变量的类型。也就是上面例子里
nTest1
变量的类型。
#028 p->ref += refinc;
#029
#030 if (isarray(ty))
#031 e = tree(mkop(op,voidptype), p->type, NULL, NULL);
#032 else if (isfunc(ty))
#033 e = tree(mkop(op,funcptype), p->type, NULL, NULL);
#034 else
#035 e = tree(mkop(op,voidptype), ptr(p->type), NULL, NULL);
#036
#037 e->u.sym = p;
#038 if (isptr(e->type))
#039 e = rvalue(e);
#040
#041 return e;
#042 }
第
28
行是添加这个变量的引用计数。
第
30
行是判断是否数组类型处理。
第
32
行是判断函数类型处理。
第
35
行是生成其它类型的
ID
树。
第
38
行是判断是否指针类型,如果是指针类型,就需要生成取地址的操作
INDIR
。
在
LCC
里把所有变量都会生成指针的操作,主要有三种:
ADDRGP
,
ADDRFP
,
ADDRLP
。如果是指针类型,就需要生成右值操作树。最后变量
nTest1
就生成下面的
ID
树:
INDIR
树
-----ADDRL
树
在
asgn
函数里会生成赋值树,它是调用下面语句实现的:
e = asgntree(ASGN, idtree(p), e);
在函数
asgntree
里根据
ID
树的类型和表达式
e
树的类型进行自动转换,并生成赋值树的操作类型。也就是生成下面的赋值树:
ASGN
树:
左子树
----- INDIR
树
-----ADDRL
树
右子树
-----
常量表达式树
通过上面的处理,就可以把赋值表达式语句生成一棵赋值树返回给
walk
函数更进一步处理。下一次再分析怎么样把树变换到无环有向图(
DAG
)表示。