在
C
语言里,有一种语句叫做复合语句。它是由
{ }
把一些语句括起来的,如下面的例子:
{
y = x + 1;
z = y + 2;
}
在
LCC
里处理这样的复合语句的函数是
compound
,它在上面函数定义函数
funcdefn
是这样调用的:
#150 labels = table(NULL, LABELS);
#151 stmtlabs = table(NULL, LABELS);
#152 refinc = 1.0;
#153 regcount = 0;
#154 codelist = &codehead;
#155 codelist->next = NULL;
#156
#157 if (!IR->wants_callb && isstruct(rty))
#158 retv = genident(AUTO, ptr(unqual(rty)), PARAM);
#159
上面的代码是准备生成代码。
#160 //
分析函数定义里的复合语句。
#161 compound(0, NULL, 0);
在第
161
行里就是调用
compound
函数,第一个参数设置为
0
,第二个参数也是设置为空
NULL
,第三个参数是
0
。那么
compound
又是怎么样去分析复合语句,以及生成什么样的中间表示,以便后面生成汇编代码的呢?带着这几个疑问去看它的代码,就很容易理解了。
它的代码如下:
#001 //
复合语句分析函数。
#002 void compound(int loop, struct swtch *swp, int lev)
#003 {
#004 Code cp;
#005 int nregs;
#006
#007 walk(NULL, 0, 0);
#008
在第
7
行里调用函数
walk
来复位一些前面使用过的全局变量,以便后面可以正确地分析。
#009 //
代码块开始。
#010 cp = code(Blockbeg);
第
10
行是创建代码开始块
cp
,并保存这块代码块到代码列表
codelist
里。
#011 enterscope();
#012 assert(level >= LOCAL);
#013
#014 if (level == LOCAL && events.entry)
#015 apply(events.entry, cfunc, NULL);
#016
#017 definept(NULL);
#018
第
11
行是增加复合语句的作用域。
第
14
行处理事件入口。
第
17
行是保存一个定义点,什么叫做定义点呢?它其实是为了调试使用的,比如在
C
源程序里,不是所有的行都可以设置断点的,而是有代码生成的行才能设置断点。当然定义点还可以作其它使用,比如调试时运行一句,跳到下一句,就需要使用到定义来同步。
#019 //
复合语句开始字符。
#020 expect('{');
#021 autos = registers = NULL;
#022 if (level == LOCAL && IR->wants_callb
#023 && isstruct(freturn(cfunc->type)))
#024 {
#025 retv = genident(AUTO, ptr(unqual(freturn(cfunc->type))), level);
#026 retv->defined = 1;
#027 retv->ref = 1;
#028 registers = append(retv, registers);
#029 }
#030
第
20
行是测试是否复合语句的开始。
第
22
行到第
29
行是处理函数返回值。
#031 //
局部变量声明处理
.
#032 while ( kind[t] == CHAR || kind[t] == STATIC
#033 || istypename(t, tsym) && getchr() != ':')
#034 {
#035 decl(dcllocal);
#036 }
#037
第
32
行到第
36
行就是处理复合语句里所有局部变量的声明,局部变量的声明跟前面分析全局变量的声明是差不多的,不过它是调用函数
dcllocal
来处理局部变量的。这里也是递归地调用
decl
来处理声明。后面再仔细地分析局部变量的声明。
#038 //
#039 {
#040 int i;
#041 Symbol *a = ltov(&autos, STMT);
#042 nregs = length(registers);
#043 for (i = 0; a[i]; i++)
#044 registers = append(a[i], registers);
#045 cp->u.block.locals = ltov(®isters, FUNC);
#046 }
#047
上面代码是处理自动类型和寄存器类型的局部变量的。
#048
#049 if (events.blockentry)
#050 apply(events.blockentry, cp->u.block.locals, NULL);
#051
上面处理定义了事件响应处理。
#052 while (kind[t] == IF || kind[t] == ID)
#053 {
#054 statement(loop, swp, lev);
#055 }
#056
上面代码是调用语句分析函数
statement
来处理,当然它也递归调用的。
#057 walk(NULL, 0, 0);
#058
#059 foreach(identifiers, level, checkref, NULL);
#060 {
#061 int i = nregs, j;
#062 Symbol p;
#063 for ( ; (p = cp->u.block.locals[i]) != NULL; i++) {
#064 for (j = i; j > nregs
#065 && cp->u.block.locals[j-1]->ref < p->ref; j--)
#066 cp->u.block.locals[j] = cp->u.block.locals[j-1];
#067 cp->u.block.locals[j] = p;
#068 }
#069 }
#070
第
57
行复位所有使用全部变量。
第
59
行到第
69
行是统计变量的引用计数。
#071 if (level == LOCAL)
#072 {
#073 Code cp;
#074 for (cp = codelist; cp->kind < Label; cp = cp->prev)
#075 ;
#076
#077 if (cp->kind != Jump)
#078 {
#079 if (freturn(cfunc->type) != voidtype)
#080 {
#081 warning("missing return value/n");
#082 retcode(cnsttree(inttype, 0L));
#083 }
#084 else
#085 retcode(NULL);
#086 }
#087 }
#088
第
71
行处理局部函数返回值,如果在第
77
行里代码的类型不是跳转,就需生成返回代码。
#089 if (events.blockexit)
#090 apply(events.blockexit, cp->u.block.locals, NULL);
#091
#092 cp->u.block.level = level;
#093 cp->u.block.identifiers = identifiers;
#094 cp->u.block.types = types;
#095
#096 code(Blockend)->u.begin = cp;
#097
#098 if (reachable(Gen))
#099 definept(NULL);
#100
#101 if (level > LOCAL)
#102 {
#103 exitscope();
#104 expect('}');
#105 }
#106 }
上面保存复合语句的代码属性,就处理完成了复合语句。
这样就可以把复合语句分析完成,下一次再去仔细地分析在复合语句实现局部变量和简单语句的分析。