函数定义
funcdefn 处理里,已经准备好调用参数和参数返回,接着就是调用全局函数声明来处理。如下面的代码:
#132 //
声明函数。
#133 cfunc = dclglobal(sclass, id, ty, &pt);
#134
上面的代码是处理函数全局定义。
现在就去就分析
dclglobal
函数的实现,它主要用来分析全局函数的。它的代码如下:
#001 //全局函数声明。
#002 static Symbol dclglobal(int sclass, char *id, Type ty, Coordinate *pos)
#003 {
第2行里传入的参数分析是:
sclass是这个函数名称存储类型。
id是函数的名称。
ty是函数的类型,包括返回类型。
pos是函数定义的源程序中位置。
#004
Symbol p;
#005
#006
if (sclass == 0)
#007
sclass = AUTO;
#008
else if (sclass != EXTERN && sclass != STATIC)
#009
{
#010
error("invalid storage class `%k' for `%t %s'/n",
#011
sclass, ty, id);
#012
sclass = AUTO;
#013
}
#014
第6行到第13行是处理存储类型。
#015
p = lookup(id, identifiers);
#016
if (p && p->scope == GLOBAL)
#017
{
#018
if (p->sclass != TYPEDEF && eqtype(ty, p->type, 1))
#019
ty = compose(ty, p->type);
#020
else
#021
error("redeclaration of `%s' previously declared at %w/n", p->name, &p->src);
#022
#023
if (!isfunc(ty) && p->defined && t == '=')
#024
error("redefinition of `%s' previously defined at %w/n", p->name, &p->src);
#025
#026
if (p->sclass == EXTERN && sclass == STATIC
#027
|| p->sclass == STATIC && sclass == AUTO
#028
|| p->sclass == AUTO && sclass == STATIC)
#029
warning("inconsistent linkage for `%s' previously declared at %w/n", p->name, &p->src);
#030
#031
}
#032
第15行是查找这个全局函数是否已经声明,如果已经声明就保存在p变量里。
第16行到第31行是找到这个全局函数已经声明后,就开始判断这个声明是否合法。这里也是进行很复杂的类型推断的,由于在例子里的简单类型是没有使用到,先把它们放下。
#033
if (p == NULL || p->scope != GLOBAL)
#034
{
#035
Symbol q = lookup(id, externals);
#036
if (q)
#037
{
#038
if (sclass == STATIC || !eqtype(ty, q->type, 1))
#039
warning("declaration of `%s' does not match previous declaration at %w/n", id, &q->src);
#040
#041
p = relocate(id, externals, globals);
#042
p->sclass = sclass;
#043
}
#044
else
#045
{
#046
p = install(id, &globals, GLOBAL, PERM);
#047
p->sclass = sclass;
#048
#049
//生成函数名称。
#050
(*IR->defsymbol)(p);
#051
}
#052
在第33行里,如果发现找到这个函数已经声明过,就会运行到条件语句里面。
第35行是查找这个函数是否已经在外面声明过,也就是使用external定义的函数。
第36行到第42行是找到这个函数已经在外面定义过,那么只需要重新找到原来的函数定义处理就行了。
第45行到第50行是处理本函数从没有定义过,因而就把它保存到全局函数声明表里,然后调用后端生成函数IR->defsymbol来创建本函数的名称。比如在NASM的后端生成代码里是生成
$main
名称。
#053
if (p->sclass != STATIC)
#054
{
#055
static int nglobals;
#056
nglobals++;
#057
if (Aflag >= 2 && nglobals == 512)
#058
warning("more than 511 external identifiers/n");
#059
}
第53行到第59行是统计全局函数定义的个数。
#060
}
#061
else if (p->sclass == EXTERN)
#062
p->sclass = sclass;
#063
第61行是处理这个函数定义外面定义的。
#064
p->type = ty;
#065
p->src = *pos;
#066
if (t == '=' && isfunc(p->type))
#067
{
#068
error("illegal initialization for `%s'/n", p->name);
#069
t = gettok();
#070
initializer(p->type, 0);
#071
}
#072
else if (t == '=')
#073
{
#074
initglobal(p, 0);
#075
if (glevel > 0 && IR->stabsym)
#076
{
#077
(*IR->stabsym)(p);
#078
swtoseg(p->u.seg);
#079
}
#080
}
#081
else if (p->sclass == STATIC && !isfunc(p->type)
#082
&& p->type->size == 0)
#083
error("undefined size for `%t %s'/n", p->type, p->name);
#084
return p;
#085 }
上面这段代码是处理函数初始化。
在第
84
行里返回这个函数属性符号。
通过上面的处理,就已经把一个全局函数保存到全局函数表格 globals,并且生成这个函数在生成代码里的函数名称
$main 。当然也进行了函数是否重复定义的处理。