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

来源:互联网 发布:mac dreamweaver cs6 编辑:程序博客网 时间:2024/05/22 00:20
上次只介绍到开始分析结构类型的定义开始部分,接着就要去分析它的成员类型定义了。它调用函数来处理结构的成员,如下代码:
#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行就是处理识别这个位的大小,比如上面的结构里,就是识别26的功能。在函数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字节边界对齐的内存变量,访问的速度就比不对齐的快。到这里,就把整个复杂的结构类型声明分析完成了,下一次开始进行函数的声明。
 
原创粉丝点击