局部变量的处理是比较特别,它是复杂语句里面声明,作用域也只限于复合语句里。如下面的例子:

{
 
 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 函数主要分析了局部变量是否合法,然后添加到合适的局部变量列表里,最后分析局部变量的初始化赋值。