LCC编译器的源程序分析(19)全局函数的定义

函数定义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。当然也进行了函数是否重复定义的处理。

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