LCC编译器的源程序分析(12)自定义类型的声明

语法分析是比较复杂的处理,下面再来分析一个例子,它的代码如下:
typedef unsigned short wchar_t;
typedef wchar_t wint_t;
第一句语句在 LCC 里的处理,前面已经解释清楚,主要生成 wchar_t 保存符号表里,并且记录这个 ID 的类型属性。
那么第二句是怎么样通过上面的函数来分析的呢?接下来就去分析 C 编译器怎么处理它。
与第一句语句一样,先识别 typedef 出来,接着就调函数 decl(dclglobal) ,然后调用函数 specifier 来处理。在函数 specifier 里:
#001 // 说明
#002 static Type specifier(int *sclass)
#003 {
#004  int cls, cons, sign, size, type, vol;
#005  Type ty = NULL;
#006 
#007  cls = vol = cons = sign = size = type = 0;
#027         case STATIC:
#028         case EXTERN:
#029         case TYPEDEF: 
#030               p = &cls; 
#031               t = gettok();     
#032               break;
#033 
在第 29 行里识别 typedef 作为存储类型,那么下一个 wchar_t 是怎么处理的呢?因为它是作为 ID 识别的,但它又自己定义的类型。其实奥秘就在词法分析函数 gettok() 里,现在再来回头去分析一下它,以前已经分析识别 ID 的代码,在这里就需要使用它了。函数 gettok() 部份代码如下:
#095         id:
#096               if (limit - rcp < MAXLINE) {
#097                    cp = rcp - 1;
#098                    fillbuf();
#099                    rcp = ++cp;
#100               }
#101               assert(cp == rcp);
#102               token = (char *)rcp - 1;
#103               while (map[*rcp]&(DIGIT|LETTER))
#104                    rcp++;
#105               token = stringn(token, (char *)rcp - token);
#106               tsym = lookup(token, identifiers);
#107               cp = rcp;
#108               return ID;
在第 96 行到第 99 行是重新填充字符缓冲区,以便识别完整的变量 ID 出来。
在第 102 行到第 105 行里,就获取 ID 的字符串,并保存到 token 里。
在第 106 行里查找这个 ID 是否已经声明,如果没有声明返回是空指令给 tsym
在第 108 行里返回 ID 这个记号来标识当前已经识别出一个 ID 了。
再仔细地看一下第 106 行,它通过函数 lookup 到符号表 identifiers 查找当前的 ID 是否已经声明,如果已经声明就返回给 tsym 保存。由于语句( typedef wchar_t wint_t;
)中的 wchar_t 在前面已经声明,那么这里的 tsym 肯定就是返回它了,这样就得到了 wchar_t 的类型属性了。有了类型属性,在函数 specifier 的处理代码如下:
#079         case ID:
#080               if (istypename(t, tsym) && type == 0
#081                    && sign == 0 && size == 0)
#082               {
#083                    use(tsym, src);
#084                    ty = tsym->type;
#085 
#086                    if (isqual(ty)     && ty->size != ty->type->size)
#087                    {
#088                          ty = unqual(ty);
#089                         
#090                          if (isconst(tsym->type))
#091                               ty = qual(CONST, ty);
#092 
#093                          if (isvolatile(tsym->type))
#094                               ty = qual(VOLATILE, ty);
#095 
#096                          tsym->type = ty;
#097                    }
#098 
#099                    p = &type;
#100                    t = gettok();
#101               }
#102               else
#103               {
#104                    p = NULL;
#105               }   
#106               break;
由于在词法分析函数 gettok() 获取到了 tsym ,也就是已经声明的类型 wchar_t ,所以在第 80 行和第 81 行判断它是类型,而不是变量 ID 了,就进入第 83 行里面处理,并在第 84 行保存当前的类型 ty ,也就是 wchar_t 声明的类型。再获取下一个记号,它是 wint_t ,接着的处理就跟其它声明处理是一样的了,在 specifier 返回类型,在 decl 函数里保存到符号表 identifiers
 
现在再来总结一下处理语句( typedef wchar_t wint_t; ),先识别 typedef ,接着通过词法分析里查找符号表可以知道 wchar_t 已经声明为类型,接着就可以保存 wint_t 到符号表,它的类型就是 wchar_t 所声明的类型。
 

你可能感兴趣的:(自定义)