网站建议:179001057@qq.com

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

技术2022-05-11  0

 LCC编译器的源程序分析(69)全局变量的初始化     前面已经介绍了全局函数和全局变量的声明处理,但全局变量的初始化,还没有详细地分析,现在就来干这件事情。比如编写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的初始化为常量表达式的值。这样就把全局变量初始化的代码分析完成。    

最新回复(0)