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的初始化为常量表达式的值。这样就把全局变量初始化的代码分析完成。

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