本文共 6357 字,大约阅读时间需要 21 分钟。
前面已经介绍了全局函数和全局变量的声明处理,但全局变量的初始化,还没有详细地分析,现在就来干这件事情。比如编写 C 的程序,有如下的代码: 像第 2 行代码就是全局变量的声明和初始化在一起的,那么在 LCC 里是怎么样处理它的呢?它的具体的分析流程是这样的: #008 if (t == '=' && isfunc(p->type)) #010 error("illegal initialization for `%s'/n", p->name); #011 t = CCaiCompiler::Instance()->GetLex()->GetToken(); #012 initializer(p->type, 0); #018 if (glevel > 0 && IR->stabsym) #024 else if (p->sclass == STATIC && !isfunc(p->type) #025 && p->type->size == 0) #028 error("undefined size for `%t %s'/n", p->type, p->name); 在第 14 行里,就会把 g_nTest 变量后面的等号识别出来,然后就进入处理后面常量表达式的流程了。也就是调用函数 initglobal 来处理常量表达式的一大堆的工作,比如常量的计算,常量的类型,常量的保存位置等等。 #002 static void initglobal(Symbol p, int flag) #006 if (t == '=' || flag) #008 if (p->sclass == STATIC) #010 // 静态变量分配在常量区或者数据区 . #011 for (ty = p->type; isarray(ty); ty = ty->pType) #013 defglobal(p, isconst(ty) ? LIT : DATA); #023 t = CCaiCompiler::Instance()->GetLex()->GetToken(); #027 ty = initializer(p->type, 0); #030 if (isarray(p->type) && p->type->size == 0) #035 if (p->sclass == EXTERN) 在初始化 initglobal 函数里,调用函数 defglobal 来保存这个全局变量符号到汇编不同的段里,比如在数据段,还是在常量段。最后调用函数 initializer 来处理常量表达式,当然常量的值也需要保存到数据区的。 函数 initializer 是用来处理常量表达式的,它的代码如下: #001 /* 常量表达式的处理 - constexpr | { constexpr ( , constexpr )* [ , ] } */ #002 Type initializer(Type ty, int lev) #007 static char follow[] = { IF, CHAR, STATIC, 0 }; #019 t = CCaiCompiler::Instance()->GetLex()->GetToken(); #021 initend(lev, follow); #032 // 根据左边类型和右边的类型来选择合适的返回类型 . #033 if ((aty = assign(ty, e)) != NULL) #040 error("invalid initialization type; found `%t' expected `%t'/n", #052 if ((isunion(ty) || isstruct(ty)) && ty->size == 0) #055 static char follow[] = { CHAR, STATIC, 0 }; #056 error("cannot initialize undefined `%t'/n", ty); #057 skipto(';', follow); #060 else if (isunion(ty)) #065 t = CCaiCompiler::Instance()->GetLex()->GetToken(); #066 n = initstruct(ty->u.sym->u.s.flist->type->size, ty, lev + 1); #067 initend(lev, follow); #072 error("missing { in initialization of `%t'/n", ty); #074 n = initstruct(ty->u.sym->u.s.flist->type->size, ty, lev + 1); #077 else if (isstruct(ty)) #082 t = CCaiCompiler::Instance()->GetLex()->GetToken(); #083 n = initstruct(0, ty, lev + 1); #088 n = initstruct(ty->size, ty, lev + 1); #092 error("missing { in initialization of `%t'/n", ty); #093 n = initstruct(ty->u.sym->u.s.flist->type->size, ty, lev + 1); #099 aty = unqual(ty->pType); #102 if (isarray(ty) && ischar(aty)) #106 if (ty->size > 0 && ty->size == tsym->type->size - 1) #107 tsym->type = array(chartype, ty->size, 0); #109 n = tsym->type->size; #110 (*IR->defstring)((int)tsym->type->size, (char*)tsym->u.c.v.p); #111 t = CCaiCompiler::Instance()->GetLex()->GetToken(); #115 t = CCaiCompiler::Instance()->GetLex()->GetToken(); #118 ty = initializer(ty, lev + 1); #119 initend(lev, follow); #123 n = initchar(0, aty); #126 else if (lev > 0 && ty->size > 0) #127 n = initchar(ty->size, aty); #129 { /* eg, char c[] = 0; */ #130 error("missing { in initialization of `%t'/n", ty); #131 n = initchar(1, aty); #134 else if (isarray(ty)) #137 if (t == SCON && aty == widechar) #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); #144 n = tsym->type->size; #145 for (i = 0; i < n; i += widechar->size) #149 (*IR->defconst)(widechar->op, widechar->size, v); #152 t = CCaiCompiler::Instance()->GetLex()->GetToken(); #156 t = CCaiCompiler::Instance()->GetLex()->GetToken(); #157 if (t == SCON && aty == widechar) #159 ty = initializer(ty, lev + 1); #160 initend(lev, follow); #164 n = initarray(0, aty, lev + 1); #167 else if (lev > 0 && ty->size > 0) #168 n = initarray(ty->size, aty, lev + 1); #171 error("missing { in initialization of `%t'/n", ty); #172 n = initarray(aty->size, aty, lev + 1); #181 error("too many initializers/n"); #182 else if (n < ty->size) #183 (*IR->space)(ty->size - n); #185 else if (isarray(ty) && ty->pType->size > 0) #186 ty = array(ty->pType, n/ty->pType->size, 0); 通过调用表达式处理函数 expr1 来计算常量的值,然后调用后端接口 genconst 来生成保存常量的代码,并且设置变量 g_nTest 的初始化为常量表达式的值。这样就把全局变量初始化的代码分析完成。 转载地址:http://ilooi.baihongyu.com/