上一次把声明的说明符已经分析得很清楚,也就是把 C 的变量和函数声明都已经了解了。最后还剩下一个问题没有解决,这个问题就是声明后面的 ID 是变量呢?还是函数?或者是指针?为了识别后面的 ID ,下面来看一个例子。如下的语句:

typedef unsigned int size_t;

这是第一行处理的代码,它通过函数 specifier 处理后,已经就把 typedef 、 unsigned 、 int 处理完成,还剩下 size_t 没有处理。从函数返回 specifier 后,接着几次递归调用才把它处理完成,现在就来看看分析这句语句的函数调用关系。如下所示:

#001 program
 
#002  decl(dclglobal)
 
#003         specifier
 
#004         dclr
 
#005               dclr1

程序先调用函数 program ,接着调用 decl 函数,紧跟着调用 specifier 和 dclr ,最后调用 dclr1 来分析,才完成这句语句的处理。其实像语句( typedef unsigned int size_t )只要调到 specifier 就已经差不多了,后面的 dclr 和 dclr1 大部分都是处理指针和函数的声明。

通过上面的分析,知道这几个函数的调用关系,心里已经有底了,但还需要更加深入去体会代码,才能真正地理解它。由于在 dclr 函数第一行就递归调用 dclr1 ,因此需要先分析函数 dclr1 ,再回来分析 dclr 函数。

#001 static Type dclr1(char **id, Symbol **params, int abstract) 
 
#002 {
 
#003  Type ty = NULL;
 
#004 
 
#005  switch (t) 
 
#006  {
 
#007  case ID:                
 
#008         if (id)
 
#009         {
 
#010               *id = token;
 
#011         }
 
#012         else
 
#013         {
 
#014               error("extraneous identifier `%s'/n", token);
 
#015         }    
 
#016 
 
#017         t = gettok(); 
 
#018         break;

第 3 行是定义返回类型。

第 5 行是通过识别当前的记号来处理后面的声明变量。比如在上面例子里的 t ,就已经是 size_t ,而 size_t 的记号是 ID 。因此第 7 行到 18 行,就是处理 ID 情况。

第 10 行是保存返回的 ID 字符串。

第 14 行是出错的提示。

第 17 行是取下一个记号。

 

下面的代码都处理更复杂的声明,现在先把它们放下,后面通过例子来解释就更加容易理解了。

#019  case '*': 
 
#020         t = gettok(); 
 
#021         if (t == CONST || t == VOLATILE) 
 
#022         {
 
#023               Type ty1;
 
#024               ty1 = ty = tnode(t, NULL);
 
#025 
 
#026               while ((t = gettok()) == CONST || t == VOLATILE)
 
#027                    ty1 = tnode(t, ty1);
 
#028 
 
#029               ty->type = dclr1(id, params, abstract);
 
#030               ty = ty1;
 
#031         } 
 
#032         else
 
#033               ty = dclr1(id, params, abstract);
 
#034 
 
#035         ty = tnode(POINTER, ty); 
 
#036         break;
 
#037  case '(': 
 
#038         t = gettok(); 
 
#039         if (abstract
 
#040               && (t == REGISTER || istypename(t, tsym) || t == ')')) 
 
#041         {
 
#042               Symbol *args;
 
#043               ty = tnode(FUNCTION, ty);
 
#044 
 
#045               enterscope();
 
#046               if (level > PARAM)
 
#047                    enterscope();
 
#048 
 
#049               args = parameters(ty);
 
#050 
 
#051               exitparams(args);
 
#052         } 
 
#053         else 
 
#054         {
 
#055               ty = dclr1(id, params, abstract);
 
#056               expect(')');
 
#057               
 
#058               if (abstract && ty == NULL
 
#059                    && (id == NULL || *id == NULL))
 
#060                    return tnode(FUNCTION, NULL);
 
#061         } 
 
#062         break;
 
#063  case '[': break;
 
#064  default: return ty;
 
#065  }
 
#066 
 
#067  while (t == '(' || t == '[')
 
#068  {
 
#069         switch (t) 
 
#070         {
 
#071         case '(': // 
 函数声明。
 
#072               t = gettok(); 
 
#073               { 
 
#074                    Symbol *args;
 
#075                    ty = tnode(FUNCTION, ty);
 
#076 
 
#077                    enterscope();
 
#078                    if (level > PARAM)
 
#079                          enterscope();
 
#080 
 
#081                    // 
 分析参数列表。
 
#082                    args = parameters(ty);
 
#083 
 
#084                    if (params && *params == NULL)
 
#085                        *params = args;
 
#086                    else
 
#087                          exitparams(args);
 
#088               }
 
#089               break;
 
#090         case '[': // 
 数据声明。
 
#091               t = gettok(); 
 
#092               { 
 
#093                    int n = 0;
 
#094                    if (kind[t] == ID) 
 
#095                    {
 
#096                          n = intexpr(']', 1);
 
#097                          if (n <= 0) 
 
#098                          {
 
#099                               error("`%d' is an illegal array size/n", n);
 
#100                               n = 1;
 
#101                          }
 
#102                    } 
 
#103                    else
 
#104                          expect(']');
 
#105 
 
#106                    ty = tnode(ARRAY, ty);
 
#107                    ty->size = n; 
 
#108               } 
 
#109               break;
 
#110         default: 
 
#111               assert(0);
 
#112         }
 
#113  }
 
#114  return ty;
 
#115 }

上面的函数分析例子 size_t 的 ID 后,就直在第 114 行返回类型 ty ,但 ty 是空的,因为它没有其它复合的类型在里面。

通过上面函数 dclr1 的处理,就把 ID 识别出来,那么这句语句( typedef unsigned int size_t; )已经完全分析完成,也就是完成语法的分析。

 

接着下来就返回到调用函数 dclr ,它的代码如下:

#001 // 
 基本声明分析函数。
 
#002 static Type dclr(Type basety, char **id, Symbol **params, int abstract) 
 
#003 {
 
#004  Type ty = dclr1(id, params, abstract);
 
#005 
 
#006  for ( ; ty; ty = ty->type)
 
#007  {
 
#008 
 
#009         switch (ty->op) 
 
#010         {
 
#011         case POINTER:
 
#012               basety = ptr(basety);
 
#013               break;
 
#014         case FUNCTION:
 
#015               basety = func(basety, ty->u.f.proto,
 
#016                    ty->u.f.oldstyle);
 
#017               break;
 
#018         case ARRAY:
 
#019               basety = array(basety, ty->size, 0);
 
#020               break;
 
#021         case CONST: case VOLATILE:
 
#022               basety = qual(ty->op, basety);
 
#023               break;
 
#024         default: assert(0);
 
#025         }
 
#026 
 
#027  }
 
#028 
 
#029  if (Aflag >= 2 && basety->size > 32767)
 
#030         warning("more than 32767 bytes in `%t'/n", basety);
 
#031 
 
#032  return basety;
 
#033 }
 
#034

第 4 行里从函数 dclr1 返回来的 ty 是空的,因此 for 循环是不会运行的。

第 11 行到第 13 行是处理指针类型。

第 14 行到第 17 行是处理函数类型声明。

第 18 行是处理数组类型声明。

第 21 行是处理常量和不能删除类型声明。

在第 32 行里把传送入来的类型直接返回了。

 

通过上面两个函数的分析,肯定是完成了所有声明部份的处理,并且把声明的类型属性保存在 basety 返回。如果还不理解声明的类型属性,就可以看看前面的文章,已经介绍了类型初始化的类型结构定义,当然初始化的类型都是基本类型,但在这里是会有扩展类型的,主要保存在类型结构的 type 字段里。

时间又到了,下次再仔细地分析怎么样把分析出来的类型与 ID 保存到符号表里。