diff options
-rw-r--r-- | decl.c | 74 | ||||
-rw-r--r-- | expr.c | 16 | ||||
-rw-r--r-- | init.c | 80 | ||||
-rw-r--r-- | qbe.c | 2 | ||||
-rw-r--r-- | type.c | 20 | ||||
-rw-r--r-- | type.h | 5 |
6 files changed, 113 insertions, 84 deletions
@@ -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"); @@ -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; @@ -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 */ @@ -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 @@ -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; } @@ -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 *); |