以前都是简单类型的识别和语法分析,现在来分析结构的声明,它是比较复杂的一种数据类型,但结构在编写程序中使用是非常多的。由于程序的方程式就是:
数据结构
+
算法
=
程序
现在面向对象的方程式是:
数据结构
+
算法
=
对象
对象
+
对象
=
程序
由上面的公式,就可以看出程序中的数据结构是非常重要的,无论是面向对象的编程,还是面向过程的编程,有什么样的数据结构,就需要有什么样算法。而在
C
语言里,使用结构类型来描述现实中需要的抽象模型。例子里的结构声明如下:
struct _iobuf {
char *_ptr;
int _cnt;
char *_base;
int _flag;
int _file;
int _charbuf;
int _bufsiz;
char *_tmpfname;
};
typedef struct _iobuf FILE;
这是声明一个文件对象结构。现在就来分析一下
LCC
编译器是怎么样进行结构的语法分析的。先用调函数
decl(dclglobal)
,然后调用函数
specifier
,在函数
specifier
就会处理结构的声明,它的代码如下:
#001 static void decl(Symbol (*dcl)(int, char *, Type, Coordinate *))
#002 {
#003 int sclass;
#004 Type ty, ty1;
…
#074 case STRUCT:
#075 case UNION:
#076 p = &type;
#077 ty = structdcl(t);
#078 break;
上面结构定义和联合的识别,这也是比较复杂的类型,所以也调用
structdcl
来进一步处理结构体。为了仔细地了解结构的语法分析,就需要分析函数
structdcl
的代码,如下:
#001 //
结构声明处理。
#002 static Type structdcl(int op)
#003 {
#004 char *tag;
#005 Type ty;
#006 Symbol p;
#007 Coordinate pos;
#008
#009 t = gettok();
#010 pos = src;
#011 if (t == ID)
#012 {
#013 tag = token;
#014 t = gettok();
#015 }
#016 else
#017 tag = "";
#018
#019 //
结构的定义开始。
#020 if (t == '{')
#021 {
#022 static char stop[] = { IF, ',', 0 };
#023 ty = newstruct(op, tag);
#024 ty->u.sym->src = pos;
#025 ty->u.sym->defined = 1;
#026
#027 t = gettok();
#028 if (istypename(t, tsym))
#029 {
#030 //
结构成员定义。
#031 fields(ty);
#032 }
#033 else
#034 {
#035 error("invalid %k field declarations/n", op);
#036 }
#037
#038 test('}', stop);
#039 }
#040 else if (*tag && (p = lookup(tag, types)) != NULL
#041 && p->type->op == op)
#042 {
#043 ty = p->type;
#044 if (t == ';' && p->scope < level)
#045 ty = newstruct(op, tag);
#046 }
#047 else
#048 {
#049 if (*tag == 0)
#050 error("missing %k tag/n", op);
#051 ty = newstruct(op, tag);
#052 }
#053
#054 if (*tag && xref)
#055 use(ty->u.sym, pos);
#056
#057 return ty;
#058 }
处理
struct
之后,接着就要处理结构的名称,在这个例子里是
_iobuf
,它是在第
9
行里获取到这个记号,然后在第
11
行里保存
_iobuf
到变量
tag
里。
tag
也有可能是空的情况,比如像下面的语法:
typedef struct { int a; } A;
上面的语法就是在第
17
行里处理这种情况的。
在第
20
行到
39
行里,主要处理结构字段定义。像结构
_iobuf
中的定义,就是处理下面的语句:
{
char *_ptr;
int _cnt;
char *_base;
int _flag;
int _file;
int _charbuf;
int _bufsiz;
char *_tmpfname;
}
在第
23
行里创建结构的类型
ty
,然后在第
28
行里判断语句是否类型开始的记号,如果不是就是出错的定义。如果是类型,比如像例子里的
char
,就需要调用函数
fields(ty)
来处理所有的字段定义。
接着下来就需要去分析
fields
的代码,下一次再带你去分析它吧。