LCC编译器的源程序分析(15)结构类型成员的声明

上次只介绍到开始分析结构类型的定义开始部分,接着就要去分析它的成员类型定义了。它调用函数来处理结构的成员,如下代码:
#001 static void fields(Type ty)
#002 {
#003 {
#004 int n = 0;
#005 while (istypename(t, tsym))
#006 {
#007 static char stop[] = { IF, CHAR, '}', 0 };
#008
#009 Type ty1 = specifier(NULL);
第5行判断是否类型定义,如果是的话就不断地进行字段列表处理。
在第9行里就调用上前介绍过的声明函数specifier来分析,这里也是递归调用的。主要用来分析一行代码的声明处理。
下面第10行的for循环主要是处理声明逗号表达式的。
#010 for (;;)
#011 {
#012 Field p;
#013 char *id = NULL;
#014
#015 Type fty = dclr(ty1, &id, NULL, 0);
#016
#017 p = newfield(id, ty, fty);
#018 if (Aflag >= 1 && !hasproto(p->type))
#019 warning("missing prototype\n");
#020
第15行进行一个声明的处理,也是调用函数dclr来递归处理。

#021 if (t == ':')
#022 {
#023 if (unqual(p->type) != inttype
#024 && unqual(p->type) != unsignedtype)
#025 {
#026 error("‘%t’ is an illegal bit-field type\n",
#027 p->type);
#028 p->type = inttype;
#029 }
#030
#031 t = gettok();
#032 p->bitsize = intexpr(0, 0);
#033 if (p->bitsize > 8*inttype->size || p->bitsize < 0)
#034 {
#035 error("‘%d’ is an illegal bit-field size\n",
#036 p->bitsize);
#037 p->bitsize = 8*inttype->size;
#038 }
#039 else if (p->bitsize == 0 && id)
#040 {
#041 warning("extraneous 0-width bit field ‘%t %s’ ignored\n", p-
#042 >type, id);
#043
#044 p->name = stringd(genlabel(1));
#045 }
#046 p->lsb = 1;
#047 }

第21行到第47行是处理结构里按位分配的成员。比如像下面的结构:
struct tag
{
int a:2;
int b:6;
};
第23行到第29行是判断位类型的合法性。
第32行就是处理识别这个位的大小,比如上面的结构里,就是识别2和6的功能。在函数intexpr里计算常量表达的值,比如计算2+5的大小,然后返回给p->bitsize保存起来。
第33行到第45行都是判断这个位大小值是否合法。

#048 else
#049 {
#050 if (id == NULL)
#051 error("field name missing\n");
#052 else if (isfunc(p->type))
#053 error("‘%t’ is an illegal field type\n", p->type);
#054 else if (p->type->size == 0)
#055 error("undefined size for field ‘%t %s’\n",
#056 p->type, id);
#057 }
#058
第48行到第58行都是处理结构定义是否出错。
第50行里是判断声明的变量没有出错。
第52行里是判断是否定义函数的类型。
第54行里是判断数据类型的大小错误。

#059 if (isconst(p->type))
#060 ty->u.sym->u.s.cfields = 1;
#061 if (isvolatile(p->type))
#062 ty->u.sym->u.s.vfields = 1;
#063
#064 n++;
#065 if (Aflag >= 2 && n == 128)
#066 warning("more than 127 fields in ‘%t’\n", ty);
#067 if (t != ',')
#068 break;
#069
#070 t = gettok();
#071 }
#072
第59行是判断类型是否常量类型。
第61行是判断类型是否不可删除的特性。
第67行是判断是否同时声明多个变量,也就是使用逗号表达式的方式。

#073 test(';', stop);
#074 }
#075 }
#076
在第73行里是判断一行代码的声明是否完整。
在第75行就是不断地回到前去分析整个结构的所有声明。

下面的代码主要是处理字段的对齐方式和计算结构的大小。
#077 {
#078 int bits = 0, off = 0, overflow = 0;
#079 Field p, *q = &ty->u.sym->u.s.flist;
#080 ty->align = IR->structmetric.align;
#081
第80行是获取生成代码的对齐方式。

#082 for (p = *q; p; p = p->link)
#083 {
在第82行里,就是遍历整个结构的成员声明。由于在上面调用函数newfield里就生成一个链表来保存所有结构成员类型声明。

#084 int a = p->type->align ? p->type->align : 1;
#085
#086 if (p->lsb)
#087 a = unsignedtype->align;
#088
#089 if (ty->op == UNION)
#090 off = bits = 0;
#091 else if (p->bitsize == 0 || bits == 0
#092 || bits - 1 + p->bitsize > 8*unsignedtype->size)
#093 {
#094 off = add(off, bits2bytes(bits-1));
#095 bits = 0;
#096 chkoverflow(off, a - 1);
#097 off = roundup(off, a);
#098 }
#099
#100 if (a > ty->align)
#101 ty->align = a;
#102
#103 p->offset = off;
#104
#105 if (p->lsb)
#106 {
#107 if (bits == 0)
#108 bits = 1;
#109
#110 if (IR->little_endian)
#111 p->lsb = bits;
#112 else
#113 p->lsb = 8*unsignedtype->size - bits + 1 - p->bitsize + 1;
#114 bits += p->bitsize;
#115 }
#116 else
#117 off = add(off, p->type->size);
#118
#119 if (off + bits2bytes(bits-1) > ty->size)
#120 ty->size = off + bits2bytes(bits-1);
#121
#122 if (p->name == NULL
#123 || !('1' <= *p->name && *p->name <= '9'))
#124 {
#125 *q = p;
#126 q = &p->link;
#127 }
#128 }
#129
#130 *q = NULL;
#131 chkoverflow(ty->size, ty->align - 1);
#132 ty->size = roundup(ty->size, ty->align);
#133 if (overflow)
#134 {
#135 error("size of ‘%t’ exceeds %d bytes\n", ty, inttype->u.sym->u.limits.max.i);
#136 ty->size = inttype->u.sym->u.limits.max.i&(~(ty->align - 1));
#137 }
#138 }
#139 }
上面的代码计算所有成员所占的空间,以及按后端的生成代码的方式来组织对齐方式。并且所有位成员占用的空间。在第131行里要计算结构是否溢出。

分析结构的成员,跟分析其它的声明是大体相同的,主要多了对齐的方式和位结构的方式。由于在汇编里访问结构的成员都是以相对地址来访问一个结构的成员的,因此需要计算所有成员的偏移量,还有不同的CPU对内存的对齐方式也不一样,速度也不一样。比如在IA32里,如果4字节边界对齐的内存变量,访问的速度就比不对齐的快。到这里,就把整个复杂的结构类型声明分析完成了,下一次开始进行函数的声明。

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License