局部变量的处理是比较特别,它是复杂语句里面声明,作用域也只限于复合语句里。如下面的例子:
{
int a = 2;
}
上面的
a
就是局部变量的声明。
现在再来仔细地分析
compound
里处理局部变量的代码。如下:
#031 //
局部变量声明处理
.
#032 while ( kind[t] == CHAR || kind[t] == STATIC
#033 || istypename(t, tsym) && getchr() != ':')
#034 {
#035 decl(dcllocal);
#036 }
上面调用函数
decl
来处理声明,跟前面介绍过的声明是一样的。只有一个地方不同,它是调用函数
dcllocal
来分析局部变量的。下面再来回顾一下
decl
函数:
#001 static void decl(Symbol (*dcl)(int, char *, Type, Coordinate *))
#002 {
…
#010 if (t == ID || t == '*' || t == '(' || t == '[')
#011 {
#012 char *id;
#013 Coordinate pos;
#014 id = NULL;
#015 pos = src;
#016
#017 if (level == GLOBAL)
#018 {
…
#047 }
#048 else
#049 {
#050 ty1 = dclr(ty, &id, NULL, 0);
#051 }
在以前处理的变量声明全是全局变量,因此不会运行到第
50
行的代码。
…
#076 else
#077 {
#078 (void)(*dcl)(sclass, id, ty1, &pos);
#079 }
在第
78
行里是调用局部变量声明函数
dcllocal
来分析局部变量。
那么局部变量函数又是怎么样处理局部变量的呢?前面已经分析了全局变量,参数变量,现在就来分析
dcllocal
的代码,如下:
#001 //
局部变量声明
.
#002 static Symbol dcllocal(int sclass, char *id, Type ty, Coordinate *pos)
#003 {
#004 Symbol p, q;
#005
#006 if (sclass == 0)
#007 sclass = isfunc(ty) ? EXTERN : AUTO;
#008 else if (isfunc(ty) && sclass != EXTERN)
#009 {
#010 error("invalid storage class `%k' for `%t %s'/n",
#011 sclass, ty, id);
#012 sclass = EXTERN;
#013 }
#014 else if (sclass == REGISTER
#015 && (isvolatile(ty) || isstruct(ty) || isarray(ty)))
#016 {
#017 warning("register declaration ignored for `%t %s'/n",
#018 ty, id);
#019 sclass = AUTO;
#020 }
#021
第
6
行到第
20
行处理局部变量的存储类型。
#022 //
查找是否已经声明。
#023 q = lookup(id, identifiers);
#024 if (q && q->scope >= level
#025 || q && q->scope == PARAM && level == LOCAL)
#026 if (sclass == EXTERN && q->sclass == EXTERN
#027 && eqtype(q->type, ty, 1))
#028 ty = compose(ty, q->type);
#029 else
#030 error("redeclaration of `%s' previously declared at %w/n", q->name, &q->src);
#031
第
23
行是查找局部变量是否已经声明过。
在第
24
行是判断这个类型是否复合类型,如果不是就会出错处理;如果是的话,就进行复合类型处理。
#032 //
保存到局部变量表。
#033 assert(level >= LOCAL);
#034 p = install(id, &identifiers, level,
#035 sclass == STATIC || sclass == EXTERN ? PERM : FUNC);
#036 p->type = ty;
#037 p->sclass = sclass;
#038 p->src = *pos;
#039
第
34
行是保存局部变量到
identifiers
符号表。
第
36
行到第
38
行保存局部变量的属性。
#040 switch (sclass)
#041 {
#042 case EXTERN:
#043 q = lookup(id, globals);
#044 if (q == NULL || q->sclass == TYPEDEF || q->sclass == ENUM)
#045 {
#046 q = lookup(id, externals);
#047 if (q == NULL)
#048 {
#049 q = install(p->name, &externals, GLOBAL, PERM);
#050 q->type = p->type;
#051 q->sclass = EXTERN;
#052 q->src = src;
#053 (*IR->defsymbol)(q);
#054 }
#055 }
#056
#057 if (!eqtype(p->type, q->type, 1))
#058 warning("declaration of `%s' does not match previous declaration at %w/n", q->name, &q->src);
#059
#060 p->u.alias = q;
#061 break;
第
42
行处理声明为外面定义的局部变量处理。
#062 case STATIC:
#063 (*IR->defsymbol)(p);
#064 initglobal(p, 0);
#065 if (!p->defined)
#066 if (p->type->size > 0)
#067 {
#068 defglobal(p, BSS);
#069 (*IR->space)(p->type->size);
#070 }
#071 else
#072 error("undefined size for `%t %s'/n",
#073 p->type, p->name);
#074 p->defined = 1;
#075 break;
上面的代码是处理静态局部变量。
#076 case REGISTER:
#077 registers = append(p, registers);
#078 regcount++;
#079 p->defined = 1;
#080 break;
上面的代码是处理寄存器类型的局部变量,添加到
registers
列表。
#081 case AUTO:
#082 autos = append(p, autos);
#083 p->defined = 1;
#084 if (isarray(ty))
#085 p->addressed = 1;
#086
#087 break;
上面的代码是处理一般最常用的
auto
类型局部变量,并且添加到
autos
列表。
#088 default: assert(0);
#089 }
#090
#091
下面的代码开始处理局部变量定义时的初始化行为。
#092 //
局部变量的初始化处理。
#093 if (t == '=')
#094 {
#095 Tree e;
#096 if (sclass == EXTERN)
#097 error("illegal initialization of `extern %s'/n", id);
#098
第
93
行判断赋值开始。
第
96
行判断外部变量不能进行初始化。
#099 t = gettok();
#100 definept(NULL);
#101
#102 if (isscalar(p->type)
#103 || isstruct(p->type) && t != '{')
#104 {
#105 if (t == '{')
#106 {
#107 t = gettok();
#108 e = expr1(0);
#109 expect('}');
#110 }
#111 else
#112 e = expr1(0);
第
102
行是判断简单类型的初始化,还是数组的初始化。
第
105
行到第
110
行是处理结构的初始化。
第
112
行是处理简单的表达式初始化。表达式函数
expr1
是一个复杂的处理函数,后面再仔细地分析它的实现。
#113 }
#114 else
#115 {
#116 Symbol t1;
#117 Type ty = p->type, ty1 = ty;
#118 while (isarray(ty1))
#119 ty1 = ty1->type;
#120 if (!isconst(ty) && (!isarray(ty) || !isconst(ty1)))
#121 ty = qual(CONST, ty);
#122
#123 t1 = genident(STATIC, ty, GLOBAL);
#124 initglobal(t1, 1);
#125 if (isarray(p->type) && p->type->size == 0
#126 && t1->type->size > 0)
#127 p->type = array(p->type->type,
#128 t1->type->size/t1->type->type->size, 0);
#129 e = idtree(t1);
#130 }
#131
第
115
行到
130
行是处理数组的初始化。
#132 walk(root(asgn(p, e)), 0, 0);
#133 p->ref = 1;
#134 }
#135
第
132
行是先调用函数
asgn
生成赋值语法树,并且作为中间表示。接着调用函数
walk
去遍历整个赋值树,进行
DAG
处理,删除一些公共表达式。后面再细述这些处理。
#136 if (!isfunc(p->type) && p->defined && p->type->size <= 0)
#137 error("undefined size for `%t %s'/n", p->type, id);
#138
#139 return p;
#140 }
第
136
行是处理局部变量类型出错。
在第
139
行里返回这个局部变量的符号表示。
像第一节里的例子:
int nTest1 = 1;
int nTest2 = 2;
int nTest3;
int i;
上面这些局部变量都是通过上面的函数来处理完成的。
dcllocal
函数主要分析了局部变量是否合法,然后添加到合适的局部变量列表里,最后分析局部变量的初始化赋值。