LCC编译器的源程序分析(21)局部变量的声明

局部变量的处理是比较特别,它是复杂语句里面声明,作用域也只限于复合语句里。如下面的例子:
{
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函数主要分析了局部变量是否合法,然后添加到合适的局部变量列表里,最后分析局部变量的初始化赋值。

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