语法分析是比较复杂的处理,下面再来分析一个例子,它的代码如下:
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
所声明的类型。