aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--decl.c74
-rw-r--r--expr.c16
-rw-r--r--init.c80
-rw-r--r--qbe.c2
-rw-r--r--type.c20
-rw-r--r--type.h5
6 files changed, 113 insertions, 84 deletions
diff --git a/decl.c b/decl.c
index 03dfb3d..3e574b2 100644
--- a/decl.c
+++ b/decl.c
@@ -147,7 +147,7 @@ funcspec(enum funcspecifier *fs)
return 1;
}
-static void structdecl(struct scope *, struct type *);
+static void structdecl(struct scope *, struct type *, struct member ***);
static struct type *
tagspec(struct scope *s)
@@ -156,6 +156,7 @@ tagspec(struct scope *s)
char *tag;
enum typekind kind;
struct declaration *d;
+ struct member **end;
uint64_t i;
switch (tok.kind) {
@@ -189,7 +190,7 @@ tagspec(struct scope *s)
t->size = 0;
t->align = 0;
t->structunion.tag = tag;
- t->structunion.members = (struct array){0};
+ t->structunion.members = NULL;
}
t->incomplete = true;
if (tag)
@@ -203,8 +204,9 @@ tagspec(struct scope *s)
switch (t->kind) {
case TYPESTRUCT:
case TYPEUNION:
+ end = &t->structunion.members;
while (tok.kind != TRBRACE)
- structdecl(s, t);
+ structdecl(s, t, &end);
next();
t->size = ALIGNUP(t->size, t->align);
t->incomplete = false;
@@ -621,51 +623,55 @@ paramdecl(struct scope *s, struct parameter *params)
return true;
}
-// XXX: cleanup
static void
-structdecl(struct scope *s, struct type *t)
+addmember(struct type *t, struct member ***end, struct type *mt, char *name, int align)
{
- struct type *base;
struct member *m;
- int basealign, align;
- base = declspecs(s, NULL, NULL, &basealign);
+ m = xmalloc(sizeof(*m));
+ m->type = mt;
+ m->name = name;
+ m->next = NULL;
+ **end = m;
+ *end = &m->next;
+
+ assert(mt->align > 0);
+ if (align < mt->align)
+ align = mt->align;
+ t->size = ALIGNUP(t->size, align);
+ if (t->kind == TYPESTRUCT) {
+ m->offset = t->size;
+ t->size += mt->size;
+ } else {
+ m->offset = 0;
+ if (t->size < mt->size)
+ t->size = mt->size;
+ }
+ if (t->align < align)
+ t->align = align;
+}
+
+static void
+structdecl(struct scope *s, struct type *t, struct member ***end)
+{
+ struct type *base, *mt;
+ char *name;
+ int align;
+
+ base = declspecs(s, NULL, NULL, &align);
if (!base)
error(&tok.loc, "no type in struct member declaration");
if (tok.kind == TSEMICOLON) {
if ((base->kind != TYPESTRUCT && base->kind != TYPEUNION) || base->structunion.tag)
error(&tok.loc, "struct declaration must declare at least one member");
next();
- if (basealign < base->align)
- basealign = base->align;
- t->size = ALIGNUP(t->size, basealign);
- arrayforeach (&base->structunion.members, m)
- m->offset += t->size;
- arrayaddbuf(&t->structunion.members, base->structunion.members.val, base->structunion.members.len);
- t->size += ALIGNUP(base->size, basealign);
- if (t->align < basealign)
- t->align = basealign;
+ addmember(t, end, base, NULL, align);
return;
}
for (;;) {
- align = basealign;
if (tok.kind != TCOLON) {
- m = arrayadd(&t->structunion.members, sizeof(*m));
- m->type = declarator(s, base, &m->name, false);
- assert(m->type->align > 0);
- if (align < m->type->align)
- align = m->type->align;
- t->size = ALIGNUP(t->size, align);
- if (t->kind == TYPESTRUCT) {
- m->offset = t->size;
- t->size += m->type->size;
- } else {
- m->offset = 0;
- if (t->size < m->type->size)
- t->size = m->type->size;
- }
- if (t->align < align)
- t->align = align;
+ mt = declarator(s, base, &name, false);
+ addmember(t, end, mt, name, align);
}
if (tok.kind == TCOLON)
error(&tok.loc, "bit-fields are not yet supported");
diff --git a/expr.c b/expr.c
index 88cf764..28dc68f 100644
--- a/expr.c
+++ b/expr.c
@@ -373,6 +373,7 @@ postfixexpr(struct scope *s, struct expression *r)
struct parameter *p;
struct member *m;
char *name;
+ uint64_t offset;
enum tokenkind op;
bool lvalue;
@@ -434,10 +435,10 @@ postfixexpr(struct scope *s, struct expression *r)
name = expect(TIDENT, "after ','");
if (t->kind != TYPESTRUCT && t->kind != TYPEUNION)
error(&tok.loc, "type is not a struct/union type");
- m = typemember(t, name);
- if (!m)
+ offset = 0;
+ if (!typemember(t, name, &offset))
error(&tok.loc, "struct/union has no member named '%s'", name);
- e = mkconstexpr(&typeulong, m->offset);
+ e = mkconstexpr(&typeulong, offset);
free(name);
expect(TRPAREN, "after member name");
} else {
@@ -497,11 +498,12 @@ postfixexpr(struct scope *s, struct expression *r)
error(&tok.loc, "expected identifier after '->' operator");
lvalue = op == TARROW || r->unary.base->flags & EXPRFLAG_LVAL;
r = exprconvert(r, mkpointertype(&typechar));
- m = typemember(t, tok.lit);
- if (!m)
+ offset = 0;
+ t = typemember(t, tok.lit, &offset);
+ if (!t)
error(&tok.loc, "struct/union has no member named '%s'", tok.lit);
- r = mkbinaryexpr(&tok.loc, TADD, r, mkconstexpr(&typeulong, m->offset));
- r = exprconvert(r, mkpointertype(mkqualifiedtype(m->type, tq)));
+ r = mkbinaryexpr(&tok.loc, TADD, r, mkconstexpr(&typeulong, offset));
+ r = exprconvert(r, mkpointertype(mkqualifiedtype(t, tq)));
e = mkexpr(EXPRUNARY, r->type->base, lvalue ? EXPRFLAG_LVAL : 0);
e->unary.op = TMUL;
e->unary.base = r;
diff --git a/init.c b/init.c
index 2335db4..2ccf058 100644
--- a/init.c
+++ b/init.c
@@ -3,7 +3,6 @@
#include <inttypes.h>
#include <stdbool.h>
#include <stdint.h>
-#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "util.h"
@@ -84,16 +83,48 @@ updatearray(struct type *t, uint64_t i)
}
static void
+subobj(struct initparser *p, struct type *t, uint64_t off)
+{
+ off += p->sub->offset;
+ if (++p->sub == p->obj + LEN(p->obj))
+ fatal("internal error: too many designators");
+ p->sub->type = t;
+ p->sub->offset = off;
+ p->sub->iscur = false;
+}
+
+static bool
+findmember(struct initparser *p, char *name)
+{
+ struct member *m;
+
+ for (m = p->sub->type->structunion.members; m; m = m->next) {
+ if (m->name) {
+ if (strcmp(m->name, name) == 0) {
+ p->sub->mem = m;
+ subobj(p, m->type, m->offset);
+ return true;
+ }
+ } else {
+ subobj(p, m->type, m->offset);
+ if (findmember(p, name))
+ return true;
+ --p->sub;
+ }
+ }
+ return false;
+}
+
+static void
designator(struct scope *s, struct initparser *p)
{
struct type *t;
uint64_t offset;
- const char *name;
+ char *name;
p->sub = p->cur;
- t = p->sub->type;
- offset = p->sub->offset;
for (;;) {
+ t = p->sub->type;
switch (tok.kind) {
case TLBRACK:
if (t->kind != TYPEARRAY)
@@ -105,32 +136,21 @@ designator(struct scope *s, struct initparser *p)
else if (p->sub->idx >= t->array.length)
error(&tok.loc, "index designator is larger than array length");
expect(TRBRACK, "for index designator");
- t = t->base;
- offset += p->sub->idx * t->size;
+ subobj(p, t->base, p->sub->idx * t->base->size);
break;
case TPERIOD:
if (t->kind != TYPESTRUCT && t->kind != TYPEUNION)
error(&tok.loc, "member designator only valid for struct/union types");
next();
name = expect(TIDENT, "for member designator");
- arrayforeach (&t->structunion.members, p->sub->mem) {
- if (strcmp(p->sub->mem->name, name) == 0)
- break;
- }
- if (!p->sub->mem)
+ if (!findmember(p, name))
error(&tok.loc, "%s has no member named '%s'", t->kind == TYPEUNION ? "union" : "struct", name);
- t = p->sub->mem->type;
- offset += p->sub->mem->offset;
+ free(name);
break;
default:
expect(TASSIGN, "after designator");
return;
}
- if (++p->sub == p->obj + LEN(p->obj))
- fatal("internal error: too many designators");
- p->sub->type = t;
- p->sub->offset = offset;
- p->sub->iscur = false;
}
}
@@ -138,9 +158,7 @@ static void
focus(struct initparser *p)
{
struct type *t;
- uint64_t offset;
- offset = p->sub->offset;
switch (p->sub->type->kind) {
case TYPEARRAY:
p->sub->idx = 0;
@@ -150,17 +168,13 @@ focus(struct initparser *p)
break;
case TYPESTRUCT:
case TYPEUNION:
- p->sub->mem = p->sub->type->structunion.members.val;
+ p->sub->mem = p->sub->type->structunion.members;
t = p->sub->mem->type;
break;
default:
t = p->sub->type;
}
- if (++p->sub == p->obj + LEN(p->obj))
- fatal("internal error: too many designators");
- p->sub->type = typeunqual(t, NULL);
- p->sub->offset = offset;
- p->sub->iscur = false;
+ subobj(p, typeunqual(t, NULL), 0);
}
static void
@@ -171,7 +185,6 @@ advance(struct initparser *p)
for (;;) {
--p->sub;
- offset = p->sub->offset;
switch (p->sub->type->kind) {
case TYPEARRAY:
++p->sub->idx;
@@ -179,15 +192,15 @@ advance(struct initparser *p)
updatearray(p->sub->type, p->sub->idx);
if (p->sub->idx < p->sub->type->array.length) {
t = p->sub->type->base;
- offset += t->size * p->sub->idx;
+ offset = t->size * p->sub->idx;
goto done;
}
break;
case TYPESTRUCT:
- ++p->sub->mem;
- if (p->sub->mem != (void *)((uintptr_t)p->sub->type->structunion.members.val + p->sub->type->structunion.members.len)) {
+ p->sub->mem = p->sub->mem->next;
+ if (p->sub->mem) {
t = p->sub->mem->type;
- offset += p->sub->mem->offset;
+ offset = p->sub->mem->offset;
goto done;
}
break;
@@ -196,10 +209,7 @@ advance(struct initparser *p)
error(&tok.loc, "too many initializers for type");
}
done:
- ++p->sub;
- p->sub->type = typeunqual(t, NULL);
- p->sub->offset = offset;
- p->sub->iscur = false;
+ subobj(p, typeunqual(t, NULL), offset);
}
/* 6.7.9 Initialization */
diff --git a/qbe.c b/qbe.c
index ad82331..670ad83 100644
--- a/qbe.c
+++ b/qbe.c
@@ -928,7 +928,7 @@ aggr(struct type *t)
}
break;
case TYPESTRUCT:
- arrayforeach (&t->structunion.members, m) {
+ for (m = t->structunion.members; m; m = m->next) {
if (typeprop(m->type) & PROPAGGR)
aggr(m->type);
else
diff --git a/type.c b/type.c
index c9a3a1e..7414f0a 100644
--- a/type.c
+++ b/type.c
@@ -271,15 +271,25 @@ typecommonreal(struct type *t1, struct type *t2)
fatal("internal error; could not find common real type");
}
-struct member *
-typemember(struct type *t, const char *name)
+struct type *
+typemember(struct type *t, const char *name, uint64_t *offset)
{
struct member *m;
assert(t->kind == TYPESTRUCT || t->kind == TYPEUNION);
- arrayforeach (&t->structunion.members, m) {
- if (strcmp(m->name, name) == 0)
- return m;
+ for (m = t->structunion.members; m; m = m->next) {
+ if (m->name) {
+ if (strcmp(m->name, name) == 0) {
+ *offset += m->offset;
+ return m->type;
+ }
+ } else {
+ t = typemember(m->type, name, offset);
+ if (t) {
+ *offset += m->offset;
+ return t;
+ }
+ }
}
return NULL;
}
diff --git a/type.h b/type.h
index 82c3929..d02df31 100644
--- a/type.h
+++ b/type.h
@@ -45,6 +45,7 @@ struct member {
char *name;
struct type *type;
uint64_t offset;
+ struct member *next;
};
struct type {
@@ -84,7 +85,7 @@ struct type {
} func;
struct {
char *tag;
- struct array members;
+ struct member *members;
} structunion;
};
};
@@ -102,7 +103,7 @@ struct type *typecommonreal(struct type *, struct type *);
struct type *typeargpromote(struct type *);
struct type *typeintpromote(struct type *);
enum typeproperty typeprop(struct type *);
-struct member *typemember(struct type *, const char *name);
+struct type *typemember(struct type *, const char *, uint64_t *);
struct parameter *mkparam(char *, struct type *);