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

你可能感兴趣的:(汇编编译器)