summary refs log tree commit diff
diff options
context:
space:
mode:
authorQuentin Carbonneaux <quentin.carbonneaux@yale.edu>2016-08-15 22:59:52 -0700
committerQuentin Carbonneaux <quentin.carbonneaux@yale.edu>2016-08-16 12:54:24 -0700
commitfbbb8e4d78e8b2e9410699fd27af282cc6ddfc4b (patch)
treeff19ad7b7d03c8ed953e253106fd603dfdf65a76
parent3f8af2ba7b8f79bd577ca4f2fef5fb922494042d (diff)
downloadroux-fbbb8e4d78e8b2e9410699fd27af282cc6ddfc4b.tar.gz
parse union types
-rw-r--r--all.h8
-rw-r--r--parse.c163
-rw-r--r--sysv.c11
3 files changed, 110 insertions, 72 deletions
diff --git a/all.h b/all.h
index 08056c4..b6392e5 100644
--- 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
index 38c212e..7afa977 100644
--- 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
index c8bc730..7e5b819 100644
--- 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;