LCC编译器的源程序分析(20)复合语句

在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(&registers, 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 }
上面保存复合语句的代码属性,就处理完成了复合语句。

这样就可以把复合语句分析完成,下一次再去仔细地分析在复合语句实现局部变量和简单语句的分析。

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License