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

你可能感兴趣的:(null,存储,Class,编译器,initialization)