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

前面已经介绍了全局函数和全局变量的声明处理,但全局变量的初始化,还没有详细地分析,现在就来干这件事情。比如编写 C 的程序,有如下的代码:
#001
#002int g_nTest = 100;
#003
#004int main(void)
#005{
#006int nTest1 = 1;
#007int nTest2 = 2;
像第 2 行代码就是全局变量的声明和初始化在一起的,那么在 LCC 里是怎么样处理它的呢?它的具体的分析流程是这样的:
先调用函数 dclglobal ,其代码如下:
#001// 保存符号的类型 .
#002p->type = ty;
#003
#004// 保存符号的位置
#005p->src = *pos;
#006
#007// 是否函数非法初始化 .
#008if (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}
#014else 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}
#024else 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// 初始化全局变量 .
#002static void initglobal(Symbol p, int flag)
#003{
#004Type ty;
#005
#006if (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 )* [ , ] } */
#002Type initializer(Type ty, int lev)
#003{
#004int n = 0;
#005Tree e;
#006Type aty = NULL;
#007static char follow[] = { IF, CHAR, STATIC, 0 };
#008
#009ty = unqual(ty);
#010if (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
#052if ((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}
#060else 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}
#077else 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
#097if (isarray(ty))
#098 {
#099 aty = unqual(ty->pType);
#100}
#101
#102if (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}
#134else 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//
#177if (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}
#185else if (isarray(ty) && ty->pType->size > 0)
#186 ty = array(ty->pType, n/ty->pType->size, 0);
#187else
#188{
#189 ty->size = n;
#190}
#191
#192// 返回类型 .
#193return ty;
#194}
通过调用表达式处理函数 expr1 来计算常量的值,然后调用后端接口 genconst 来生成保存常量的代码,并且设置变量 g_nTest 的初始化为常量表达式的值。这样就把全局变量初始化的代码分析完成。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值