LCC编译器的源程序分析(69)全局变量的初始化

来源:互联网 发布:建筑学就业前景知乎 编辑:程序博客网 时间:2024/05/18 03:05
前面已经介绍了全局函数和全局变量的声明处理,但全局变量的初始化,还没有详细地分析,现在就来干这件事情。比如编写C的程序,有如下的代码:
#001 
#002 int g_nTest = 100;
#003 
#004 int main(void)
#005 {
#006  int nTest1 = 1;
#007  int nTest2 = 2;
像第2行代码就是全局变量的声明和初始化在一起的,那么在LCC里是怎么样处理它的呢?它的具体的分析流程是这样的:
先调用函数dclglobal,其代码如下:
#001 //保存符号的类型.
#002  p->type = ty;
#003 
#004  //保存符号的位置
#005  p->src = *pos;
#006 
#007  //是否函数非法初始化.
#008  if (t == '=' && isfunc(p->type))
#009  {
#010         error("illegal initialization for `%s'/n", p->name);
#011         t = CCaiCompiler::Instance()->GetLex()->GetToken();
#012         initializer(p->type, 0);
#013  }
#014  else if (t == '=')
#015  {
#016         //全局变量初始化.
#017         initglobal(p, 0);
#018         if (glevel > 0 && IR->stabsym)
#019         {
#020               (*IR->stabsym)(p);
#021               swtoseg(p->u.seg);
#022         }
#023  }
#024  else if (p->sclass == STATIC && !isfunc(p->type)
#025         && p->type->size == 0)
#026  {
#027         //错误大小.
#028         error("undefined size for `%t %s'/n", p->type, p->name);
#029  }
#030 
在第14行里,就会把g_nTest变量后面的等号识别出来,然后就进入处理后面常量表达式的流程了。也就是调用函数initglobal来处理常量表达式的一大堆的工作,比如常量的计算,常量的类型,常量的保存位置等等。
 
initglobal函数如下:
#001 //初始化全局变量.
#002 static void initglobal(Symbol p, int flag)
#003 {
#004  Type ty;
#005 
#006  if (t == '=' || flag)
#007  {
#008         if (p->sclass == STATIC)
#009         {
#010               //静态变量分配在常量区或者数据区.
#011               for (ty = p->type; isarray(ty); ty = ty->pType)
#012                    ;
#013               defglobal(p, isconst(ty) ? LIT : DATA);
#014         }
#015         else
#016         {
#017               //分配在数据区.
#018               defglobal(p, DATA);
#019         }
#020 
#021         if (t == '=')
#022         {
#023               t = CCaiCompiler::Instance()->GetLex()->GetToken();
#024         }
#025 
#026         //常量初始化处理.
#027         ty = initializer(p->type, 0);
#028 
#029 
#030         if (isarray(p->type) && p->type->size == 0)
#031         {
#032               p->type = ty;
#033         }
#034 
#035         if (p->sclass == EXTERN)
#036         {
#037               p->sclass = AUTO;
#038         }
#039 
#040  }
#041 }
在初始化initglobal函数里,调用函数defglobal来保存这个全局变量符号到汇编不同的段里,比如在数据段,还是在常量段。最后调用函数initializer来处理常量表达式,当然常量的值也需要保存到数据区的。
 
函数initializer是用来处理常量表达式的,它的代码如下:
#001 /* 常量表达式的处理 - constexpr | { constexpr ( , constexpr )* [ , ] } */
#002 Type initializer(Type ty, int lev)
#003 {
#004  int n = 0;
#005  Tree e;
#006  Type aty = NULL;
#007  static char follow[] = { IF, CHAR, STATIC, 0 };
#008 
#009  ty = unqual(ty);
#010  if (isscalar(ty))
#011  {
#012         //基本类型初始化.
#013         needconst++;
#014 
#015         //
#016         if (t == '{')
#017         {
#018               //复合表达式的分析.
#019               t = CCaiCompiler::Instance()->GetLex()->GetToken();
#020               e = expr1(0);
#021               initend(lev, follow);
#022         }
#023         else
#024         {
#025               //表达式分析1.
#026               e = expr1(0);
#027         }
#028 
#029         //返回基本类型的表达式树.
#030         e = pointer(e);
#031 
#032         //根据左边类型和右边的类型来选择合适的返回类型.
#033         if ((aty = assign(ty, e)) != NULL)
#034         {
#035               //类型转换.
#036               e = cast(e, aty);
#037         }
#038         else
#039         {
#040               error("invalid initialization type; found `%t' expected `%t'/n",
#041                    e->type, ty);
#042         }
#043 
#044         //根据常量表达式生成代码.
#045         n = genconst(e, 1);
#046 
#047 
#048         deallocate(STMT);
#049         needconst--;
#050  }
#051 
#052  if ((isunion(ty) || isstruct(ty)) && ty->size == 0)
#053  {
#054         //联合或结果初始化出错.
#055         static char follow[] = { CHAR, STATIC, 0 };
#056         error("cannot initialize undefined `%t'/n", ty);
#057         skipto(';', follow);
#058         return ty;
#059  }
#060  else if (isunion(ty))
#061  {
#062         //联合的初始化.
#063         if (t == '{')
#064         {
#065               t = CCaiCompiler::Instance()->GetLex()->GetToken();
#066               n = initstruct(ty->u.sym->u.s.flist->type->size, ty, lev + 1);
#067               initend(lev, follow);
#068         }
#069         else
#070         {
#071               if (lev == 0)
#072                    error("missing { in initialization of `%t'/n", ty);
#073 
#074               n = initstruct(ty->u.sym->u.s.flist->type->size, ty, lev + 1);
#075         }
#076  }
#077  else if (isstruct(ty))
#078  {
#079         //结构初始化.
#080         if (t == '{')
#081         {
#082               t = CCaiCompiler::Instance()->GetLex()->GetToken();
#083               n = initstruct(0, ty, lev + 1);
#084               test('}', follow);
#085         }
#086         else if (lev > 0)
#087         {
#088               n = initstruct(ty->size, ty, lev + 1);
#089         }   
#090         else
#091         {
#092               error("missing { in initialization of `%t'/n", ty);
#093               n = initstruct(ty->u.sym->u.s.flist->type->size, ty, lev + 1);
#094         }
#095  }
#096 
#097  if (isarray(ty))
#098   {
#099         aty = unqual(ty->pType);       
#100  }   
#101 
#102  if (isarray(ty) && ischar(aty))
#103  {
#104         if (t == SCON)
#105         {
#106               if (ty->size > 0 && ty->size == tsym->type->size - 1)
#107                    tsym->type = array(chartype, ty->size, 0);
#108 
#109               n = tsym->type->size;
#110               (*IR->defstring)((int)tsym->type->size, (char*)tsym->u.c.v.p);
#111               t = CCaiCompiler::Instance()->GetLex()->GetToken();
#112         }
#113         else if (t == '{')
#114         {
#115               t = CCaiCompiler::Instance()->GetLex()->GetToken();
#116               if (t == SCON)
#117               {
#118                    ty = initializer(ty, lev + 1);
#119                    initend(lev, follow);
#120                    return ty;
#121               }
#122 
#123               n = initchar(0, aty);
#124               test('}', follow);
#125         }
#126         else if (lev > 0 && ty->size > 0)
#127               n = initchar(ty->size, aty);
#128         else
#129         {    /* eg, char c[] = 0; */
#130               error("missing { in initialization of `%t'/n", ty);
#131               n = initchar(1, aty);
#132         }
#133  }
#134  else if (isarray(ty))
#135  {
#136         //数组初始化.
#137         if (t == SCON && aty == widechar)
#138         {
#139               int i;
#140               unsigned int *s = (unsigned int *)tsym->u.c.v.p;
#141               if (ty->size > 0 && ty->size == tsym->type->size - widechar->size)
#142                    tsym->type = array(widechar, ty->size/widechar->size, 0);
#143 
#144               n = tsym->type->size;
#145               for (i = 0; i < n; i += widechar->size)
#146               {
#147                    Value v;
#148                    v.u = *s++;
#149                    (*IR->defconst)(widechar->op, widechar->size, v);
#150               }
#151  
#152               t = CCaiCompiler::Instance()->GetLex()->GetToken();
#153         }
#154         else if (t == '{')
#155         {
#156               t = CCaiCompiler::Instance()->GetLex()->GetToken();
#157               if (t == SCON && aty == widechar)
#158               {
#159                    ty = initializer(ty, lev + 1);
#160                    initend(lev, follow);
#161                    return ty;
#162               }
#163 
#164               n = initarray(0, aty, lev + 1);
#165               test('}', follow);
#166         }
#167         else if (lev > 0 && ty->size > 0)
#168               n = initarray(ty->size, aty, lev + 1);
#169         else
#170         {
#171               error("missing { in initialization of `%t'/n", ty);
#172               n = initarray(aty->size, aty, lev + 1);
#173         }
#174  }   
#175 
#176  //
#177  if (ty->size)
#178  {
#179         //类型大小是否合适.
#180         if (n > ty->size)
#181               error("too many initializers/n");
#182         else if (n < ty->size)
#183               (*IR->space)(ty->size - n);
#184  }
#185  else if (isarray(ty) && ty->pType->size > 0)
#186         ty = array(ty->pType, n/ty->pType->size, 0);
#187  else
#188  {
#189         ty->size = n;
#190  }
#191 
#192  //返回类型.
#193  return ty;
#194 }
 
通过调用表达式处理函数expr1来计算常量的值,然后调用后端接口genconst来生成保存常量的代码,并且设置变量g_nTest的初始化为常量表达式的值。这样就把全局变量初始化的代码分析完成。
 


原创粉丝点击