commit fbbb8e4d78e8b2e9410699fd27af282cc6ddfc4b
parent 3f8af2ba7b8f79bd577ca4f2fef5fb922494042d
Author: Quentin Carbonneaux <quentin.carbonneaux@yale.edu>
Date: Mon, 15 Aug 2016 22:59:52 -0700
parse union types
Diffstat:
M | all.h | | | 8 | +++++--- |
M | parse.c | | | 163 | +++++++++++++++++++++++++++++++++++++++++++++++-------------------------------- |
M | sysv.c | | | 11 | ++++++++--- |
3 files changed, 110 insertions(+), 72 deletions(-)
diff --git a/all.h b/all.h
@@ -25,6 +25,7 @@ typedef struct Con Con;
typedef struct Addr Mem;
typedef struct Fn Fn;
typedef struct Typ Typ;
+typedef struct Seg Seg;
typedef struct Dat Dat;
enum Reg {
@@ -422,8 +423,9 @@ struct Fn {
struct Typ {
char name[NString];
int dark;
- ulong size;
int align;
+ size_t size;
+ int nunion;
struct Seg {
enum {
@@ -433,8 +435,8 @@ struct Typ {
Styp,
};
uint type:2;
- uint len:30;
- } seg[NSeg+1];
+ uint len:30; /* index in typ[] for Styp */
+ } (*seg)[NSeg+1];
};
struct Dat {
diff --git a/parse.c b/parse.c
@@ -412,20 +412,23 @@ parseref()
}
static int
-parsecls(int *tyn)
+findtyp(int i)
{
- int i;
+ while (--i >= 0)
+ if (strcmp(tokval.str, typ[i].name) == 0)
+ return i;
+ err("undefined type :%s", tokval.str);
+}
+static int
+parsecls(int *tyn)
+{
switch (next()) {
default:
err("invalid class specifier");
case Ttyp:
- for (i=0; i<ntyp; i++)
- if (strcmp(tokval.str, typ[i].name) == 0) {
- *tyn = i;
- return 4;
- }
- err("undefined type :%s", tokval.str);
+ *tyn = findtyp(ntyp);
+ return 4;
case Tw:
return Kw;
case Tl:
@@ -788,18 +791,85 @@ parsefn(int export)
}
static void
+parseseg(Seg *seg, Typ *ty, int t)
+{
+ Typ *ty1;
+ int n, c, a, al, type;
+ size_t sz, s;
+
+ n = 0;
+ sz = 0;
+ al = ty->align;
+ while (t != Trbrace) {
+ type = Sint;
+ switch (t) {
+ default: err("invalid type member specifier");
+ case Td: type = Sflt;
+ case Tl: s = 8; a = 3; break;
+ case Ts: type = Sflt;
+ case Tw: s = 4; a = 2; break;
+ case Th: s = 2; a = 1; break;
+ case Tb: s = 1; a = 0; break;
+ case Ttyp:
+ type = Styp;
+ ty1 = &typ[findtyp(ntyp-1)];
+ s = ty1->size;
+ a = ty1->align;
+ break;
+ }
+ if (a > al)
+ al = a;
+ if ((a = sz & (s-1))) {
+ a = s - a;
+ if (n < NSeg) {
+ /* padding segment */
+ seg[n].type = Spad;
+ seg[n].len = a;
+ n++;
+ }
+ }
+ t = nextnl();
+ if (t == Tint) {
+ c = tokval.num;
+ t = nextnl();
+ } else
+ c = 1;
+ sz += a + c*s;
+ if (type == Styp)
+ s = ty1 - typ;
+ for (; c>0 && n<NSeg; c--, n++) {
+ seg[n].type = type;
+ seg[n].len = s;
+ }
+ if (t != Tcomma)
+ break;
+ t = nextnl();
+ }
+ if (t != Trbrace)
+ err(", or } expected");
+ seg[n].type = Sint;
+ seg[n].len = 0;
+ a = 1 << al;
+ sz = (sz + a - 1) & -a;
+ if (sz >= ty->size)
+ ty->size = sz;
+ ty->align = al;
+}
+
+static void
parsetyp()
{
Typ *ty;
- int t, n, c, a, al, type;
- ulong sz, s;
+ int t, n, al;
if (ntyp >= NTyp)
err("too many type definitions");
ty = &typ[ntyp++];
+ ty->dark = 0;
ty->align = -1;
+ ty->size = 0;
if (nextnl() != Ttyp || nextnl() != Teq)
- err("type name, then = expected");
+ err("type name and then = expected");
strcpy(ty->name, tokval.str);
t = nextnl();
if (t == Talign) {
@@ -818,62 +888,23 @@ parsetyp()
ty->size = tokval.num;
if (ty->align == -1)
err("dark types need alignment");
- t = nextnl();
- } else {
- ty->dark = 0;
- n = 0;
- sz = 0;
- al = 0;
- while (t != Trbrace) {
- type = Sint;
- switch (t) {
- default: err("invalid size specifier %c", tokval.chr);
- case Td: type = Sflt;
- case Tl: s = 8; a = 3; break;
- case Ts: type = Sflt;
- case Tw: s = 4; a = 2; break;
- case Th: s = 2; a = 1; break;
- case Tb: s = 1; a = 0; break;
- }
- if (a > al)
- al = a;
- if ((a = sz & (s-1))) {
- a = s - a;
- if (n < NSeg) {
- /* padding segment */
- ty->seg[n].type = Spad;
- ty->seg[n].len = a;
- n++;
- }
- }
- t = nextnl();
- if (t == Tint) {
- c = tokval.num;
- t = nextnl();
- } else
- c = 1;
- sz += a + c*s;
- for (; c>0 && n<NSeg; c--, n++) {
- ty->seg[n].type = type;
- ty->seg[n].len = s;
- }
- if (t != Tcomma)
- break;
- t = nextnl();
- }
- if (n >= NSeg)
- ty->dark = 1;
- else
- ty->seg[n].len = 0;
- if (ty->align == -1)
- ty->align = al;
- else
- al = ty->align;
- a = 1 << al;
- ty->size = (sz + a - 1) & -a;
+ if (nextnl() != Trbrace)
+ err("} expected");
+ return;
}
- if (t != Trbrace)
- err(", or } expected");
+ n = 0;
+ ty->seg = vnew(1, sizeof ty->seg[0], emalloc);
+ if (t == Tlbrace)
+ do {
+ if (t != Tlbrace)
+ err("invalid union member");
+ vgrow(&ty->seg, n+1);
+ parseseg(ty->seg[n++], ty, nextnl());
+ t = nextnl();
+ } while (t != Trbrace);
+ else
+ parseseg(ty->seg[n++], ty, t);
+ ty->nunion = n;
}
static void
diff --git a/sysv.c b/sysv.c
@@ -21,6 +21,7 @@ aclass(AClass *a, Typ *t)
{
int e, s, n, cls;
uint sz, al;
+ Seg *seg;
sz = t->size;
al = 1u << t->align;
@@ -45,11 +46,12 @@ aclass(AClass *a, Typ *t)
return;
}
+ seg = t->seg[0];
a->inmem = 0;
for (e=0, s=0; e<2; e++) {
cls = -1;
- for (n=0; n<8 && t->seg[s].len; s++) {
- switch (t->seg[s].type) {
+ for (n=0; n<8 && seg[s].len; s++) {
+ switch (seg[s].type) {
case Spad:
/* don't change anything */
break;
@@ -60,8 +62,11 @@ aclass(AClass *a, Typ *t)
case Sint:
cls = Kl;
break;
+ case Styp:
+ assert(!"todo");
+ break;
}
- n += t->seg[s].len;
+ n += seg[s].len;
}
assert(n <= 8);
a->cls[e] = cls;