diff options
author | Michael Forney <mforney@mforney.org> | 2021-04-12 20:34:50 -0700 |
---|---|---|
committer | Michael Forney <mforney@mforney.org> | 2022-01-22 11:36:12 -0800 |
commit | 65d860fade5a39fb62b0b39081edbce199e40d58 (patch) | |
tree | 8b9f39a6aa9224efc4aae093061ddfe577a3c196 | |
parent | 0bc29c89c13a61806a28f054f04a01afd8242669 (diff) |
Port to C99
-rw-r--r-- | README.md | 4 | ||||
-rw-r--r-- | cc.h | 24 | ||||
-rwxr-xr-x | configure | 2 | ||||
-rw-r--r-- | decl.c | 62 | ||||
-rw-r--r-- | driver.c | 1 | ||||
-rw-r--r-- | eval.c | 134 | ||||
-rw-r--r-- | expr.c | 121 | ||||
-rw-r--r-- | init.c | 46 | ||||
-rw-r--r-- | map.c | 2 | ||||
-rw-r--r-- | qbe.c | 188 | ||||
-rw-r--r-- | targ.c | 6 | ||||
-rw-r--r-- | type.c | 43 | ||||
-rw-r--r-- | util.h | 2 |
13 files changed, 315 insertions, 320 deletions
@@ -16,8 +16,8 @@ It was inspired by several other small C compilers including [8cc], ## Requirements -The compiler itself is written in standard C11 and can be built with -any conforming C11 compiler. +The compiler itself is written in standard C99 and can be built with +any conforming C99 compiler. The POSIX driver depends on POSIX.1-2008 interfaces, and the `Makefile` requires a POSIX-compatible make(1). @@ -112,7 +112,7 @@ enum tokenkind { TBORASSIGN, TCOMMA, THASH, - THASHHASH, + THASHHASH }; struct location { @@ -136,7 +136,7 @@ enum typequal { QUALCONST = 1<<1, QUALRESTRICT = 1<<2, QUALVOLATILE = 1<<3, - QUALATOMIC = 1<<4, + QUALATOMIC = 1<<4 }; enum typekind { @@ -157,7 +157,7 @@ enum typekind { TYPEARRAY, TYPEFUNC, TYPESTRUCT, - TYPEUNION, + TYPEUNION }; enum typeprop { @@ -171,7 +171,7 @@ enum typeprop { PROPSCALAR = 1<<5, PROPAGGR = 1<<6, PROPDERIVED = 1<<7, - PROPFLOAT = 1<<8, + PROPFLOAT = 1<<8 }; struct param { @@ -202,10 +202,8 @@ struct type { int align; unsigned long long size; struct value *value; /* used by the backend */ - union { - struct type *base; - struct list link; /* used only during construction of type */ - }; + struct type *base; + struct list link; /* used only during construction of type */ /* qualifiers of the base type */ enum typequal qual; _Bool incomplete, flexible; @@ -225,7 +223,7 @@ struct type { char *tag; struct member *members; } structunion; - }; + } u; }; enum declkind { @@ -313,11 +311,7 @@ enum exprkind { struct stringlit { size_t size; - union { - unsigned char *data; - uint_least16_t *data16; - uint_least32_t *data32; - }; + void *data; }; struct expr { @@ -369,7 +363,7 @@ struct expr { enum builtinkind kind; } builtin; struct value *temp; - }; + } u; }; struct init { @@ -169,7 +169,7 @@ cat >config.mk <<EOF PREFIX=$prefix BINDIR=$bindir CC=${CC:-cc} -CFLAGS=${CFLAGS:--std=c11 -Wall -Wpedantic -Wno-parentheses -Wno-switch -g -pipe} +CFLAGS=${CFLAGS:--std=c99 -Wall -Wpedantic -Wno-parentheses -Wno-switch -g -pipe} LDFLAGS=$LDFLAGS EOF echo done @@ -184,8 +184,8 @@ tagspec(struct scope *s) t->prop |= PROPAGGR; t->size = 0; t->align = 0; - t->structunion.tag = tag; - t->structunion.members = NULL; + t->u.structunion.tag = tag; + t->u.structunion.members = NULL; } t->incomplete = true; if (tag) @@ -200,11 +200,11 @@ tagspec(struct scope *s) case TYPESTRUCT: case TYPEUNION: b.type = t; - b.last = &t->structunion.members; + b.last = &t->u.structunion.members; b.bits = 0; do structdecl(s, &b); while (tok.kind != TRBRACE); - if (!t->structunion.members) + if (!t->u.structunion.members) error(&tok.loc, "struct/union has no members"); next(); t->size = ALIGNUP(t->size, t->align); @@ -219,11 +219,11 @@ tagspec(struct scope *s) e = constexpr(s); if (e->kind != EXPRCONST || !(e->type->prop & PROPINT)) error(&tok.loc, "expected integer constant expression"); - i = e->constant.u; - if (e->type->basic.issigned && i >= 1ull << 63) { + i = e->u.constant.u; + if (e->type->u.basic.issigned && i >= 1ull << 63) { if (i < -1ull << 31) goto invalid; - t->basic.issigned = true; + t->u.basic.issigned = true; } else if (i >= 1ull << 32) { goto invalid; } @@ -237,7 +237,7 @@ tagspec(struct scope *s) large = true; d->type = &typeuint; } - if (large && t->basic.issigned) + if (large && t->u.basic.issigned) error(&tok.loc, "neither 'int' nor 'unsigned' can represent all enumerator values"); scopeputdecl(s, name, d); if (!consume(TCOMMA)) @@ -428,7 +428,7 @@ done: if (!t && (tq || sc && *sc || fs && *fs)) error(&tok.loc, "declaration has no type specifier"); if (t && tq && t->kind == TYPEARRAY) { - t = mkarraytype(t->base, t->qual | tq, t->array.length); + t = mkarraytype(t->base, t->qual | tq, t->u.array.length); tq = QUALNONE; } @@ -509,12 +509,12 @@ declaratortypes(struct scope *s, struct list *result, char **name, bool allowabs func: t = mktype(TYPEFUNC, PROPDERIVED); t->qual = QUALNONE; - t->func.isprototype = false; - t->func.isvararg = false; - t->func.isnoreturn = false; - t->func.params = NULL; - t->func.nparam = 0; - p = &t->func.params; + t->u.func.isprototype = false; + t->u.func.isvararg = false; + t->u.func.isnoreturn = false; + t->u.func.params = NULL; + t->u.func.nparam = 0; + p = &t->u.func.params; switch (tok.kind) { case TIDENT: if (!istypename(s, tok.lit)) { @@ -528,26 +528,26 @@ declaratortypes(struct scope *s, struct list *result, char **name, bool allowabs } /* fallthrough */ default: - t->func.isprototype = true; + t->u.func.isprototype = true; for (;;) { *p = parameter(s); p = &(*p)->next; - ++t->func.nparam; + ++t->u.func.nparam; if (!consume(TCOMMA)) break; if (consume(TELLIPSIS)) { - t->func.isvararg = true; + t->u.func.isvararg = true; break; } } - if (t->func.params->type->kind == TYPEVOID && !t->func.params->next) - t->func.params = NULL; + if (t->u.func.params->type->kind == TYPEVOID && !t->u.func.params->next) + t->u.func.params = NULL; break; case TRPAREN: break; } expect(TRPAREN, "to close function declarator"); - t->func.paraminfo = t->func.isprototype || t->func.params || tok.kind == TLBRACE; + t->u.func.paraminfo = t->u.func.isprototype || t->u.func.params || tok.kind == TLBRACE; listinsert(ptr->prev, &t->link); break; case TLBRACK: /* array declarator */ @@ -562,11 +562,11 @@ declaratortypes(struct scope *s, struct list *result, char **name, bool allowabs e = eval(assignexpr(s), EVALARITH); if (e->kind != EXPRCONST || !(e->type->prop & PROPINT)) error(&tok.loc, "VLAs are not yet supported"); - i = e->constant.u; - if (e->type->basic.issigned && i > INT64_MAX) + i = e->u.constant.u; + if (e->type->u.basic.issigned && i > INT64_MAX) error(&tok.loc, "array length must be non-negative"); delexpr(e); - t->array.length = i; + t->u.array.length = i; t->incomplete = false; } expect(TRBRACK, "after array length"); @@ -605,7 +605,7 @@ declarator(struct scope *s, struct qualtype base, char **name, bool allowabstrac if (base.type->kind == TYPEFUNC) error(&tok.loc, "array element has function type"); t->align = base.type->align; - t->size = base.type->size * t->array.length; // XXX: overflow? + t->size = base.type->size * t->u.array.length; /* XXX: overflow? */ break; } base.type = t; @@ -782,7 +782,7 @@ structdecl(struct scope *s, struct structbuilder *b) if (!base.type) error(&tok.loc, "no type in struct member declaration"); if (tok.kind == TSEMICOLON) { - if ((base.type->kind != TYPESTRUCT && base.type->kind != TYPEUNION) || base.type->structunion.tag) + if ((base.type->kind != TYPESTRUCT && base.type->kind != TYPEUNION) || base.type->u.structunion.tag) error(&tok.loc, "struct declaration must declare at least one member"); next(); addmember(b, base, NULL, align, -1); @@ -973,18 +973,18 @@ decl(struct scope *s, struct func *f) case DECLFUNC: if (align) error(&tok.loc, "function '%s' declared with alignment specifier", name); - t->func.isnoreturn |= fs & FUNCNORETURN; + t->u.func.isnoreturn |= fs & FUNCNORETURN; if (f && sc && sc != SCEXTERN) /* 6.7.1p7 */ error(&tok.loc, "function '%s' with block scope may only have storage class 'extern'", name); - if (!t->func.isprototype && t->func.params) { + if (!t->u.func.isprototype && t->u.func.params) { if (!allowfunc) error(&tok.loc, "function definition not allowed"); /* collect type information for parameters before we check compatibility */ - while (paramdecl(s, t->func.params)) + while (paramdecl(s, t->u.func.params)) ; if (tok.kind != TLBRACE) error(&tok.loc, "function declaration with identifier list is not part of definition"); - for (p = t->func.params; p; p = p->next) { + for (p = t->u.func.params; p; p = p->next) { if (!p->type) error(&tok.loc, "old-style function definition does not declare '%s'", p->name); } @@ -1026,7 +1026,7 @@ struct decl *stringdecl(struct expr *expr) if (!strings) strings = mkmap(64); assert(expr->kind == EXPRSTRING); - mapkey(&key, expr->string.data, expr->string.size); + mapkey(&key, expr->u.string.data, expr->u.string.size); entry = mapput(strings, &key); d = *entry; if (!d) { @@ -585,4 +585,5 @@ main(int argc, char *argv[]) output = "a.out"; buildexe(inputs.val, inputs.len / sizeof(*input), output); } + return 0; } @@ -14,16 +14,16 @@ cast(struct expr *expr) size = expr->type->size; if (expr->type->prop & PROPFLOAT) size |= F; - else if (expr->type->prop & PROPINT && expr->type->basic.issigned) + else if (expr->type->prop & PROPINT && expr->type->u.basic.issigned) size |= S; switch (size) { - case 1: expr->constant.u = (uint8_t)expr->constant.u; break; - case 1|S: expr->constant.u = (expr->constant.u & UINT8_MAX ^ INT8_MIN) - INT8_MIN; break; - case 2: expr->constant.u = (uint16_t)expr->constant.u; break; - case 2|S: expr->constant.u = (expr->constant.u & UINT16_MAX ^ INT16_MIN) - INT16_MIN; break; - case 4: expr->constant.u = (uint32_t)expr->constant.u; break; - case 4|S: expr->constant.u = (expr->constant.u & UINT32_MAX ^ INT32_MIN) - INT32_MIN; break; - case 4|F: expr->constant.f = (float)expr->constant.f; break; + case 1: expr->u.constant.u = (uint8_t)expr->u.constant.u; break; + case 1|S: expr->u.constant.u = (expr->u.constant.u & UINT8_MAX ^ INT8_MIN) - INT8_MIN; break; + case 2: expr->u.constant.u = (uint16_t)expr->u.constant.u; break; + case 2|S: expr->u.constant.u = (expr->u.constant.u & UINT16_MAX ^ INT16_MIN) - INT16_MIN; break; + case 4: expr->u.constant.u = (uint32_t)expr->u.constant.u; break; + case 4|S: expr->u.constant.u = (expr->u.constant.u & UINT32_MAX ^ INT32_MIN) - INT32_MIN; break; + case 4|F: expr->u.constant.f = (float)expr->u.constant.f; break; } } @@ -33,51 +33,51 @@ binary(struct expr *expr, enum tokenkind op, struct expr *l, struct expr *r) expr->kind = EXPRCONST; if (l->type->prop & PROPFLOAT) op |= F; - else if (l->type->prop & PROPINT && l->type->basic.issigned) + else if (l->type->prop & PROPINT && l->type->u.basic.issigned) op |= S; switch (op) { case TMUL: - case TMUL|S: expr->constant.u = l->constant.u * r->constant.u; break; - case TMUL|F: expr->constant.f = l->constant.f * r->constant.f; break; - case TDIV: expr->constant.u = l->constant.u / r->constant.u; break; - case TDIV|S: expr->constant.i = l->constant.i / r->constant.i; break; - case TDIV|F: expr->constant.f = l->constant.f / r->constant.f; break; - case TMOD: expr->constant.u = l->constant.u % r->constant.u; break; - case TMOD|S: expr->constant.i = l->constant.i % r->constant.i; break; + case TMUL|S: expr->u.constant.u = l->u.constant.u * r->u.constant.u; break; + case TMUL|F: expr->u.constant.f = l->u.constant.f * r->u.constant.f; break; + case TDIV: expr->u.constant.u = l->u.constant.u / r->u.constant.u; break; + case TDIV|S: expr->u.constant.i = l->u.constant.i / r->u.constant.i; break; + case TDIV|F: expr->u.constant.f = l->u.constant.f / r->u.constant.f; break; + case TMOD: expr->u.constant.u = l->u.constant.u % r->u.constant.u; break; + case TMOD|S: expr->u.constant.i = l->u.constant.i % r->u.constant.i; break; case TADD: - case TADD|S: expr->constant.u = l->constant.u + r->constant.u; break; - case TADD|F: expr->constant.f = l->constant.f + r->constant.f; break; + case TADD|S: expr->u.constant.u = l->u.constant.u + r->u.constant.u; break; + case TADD|F: expr->u.constant.f = l->u.constant.f + r->u.constant.f; break; case TSUB: - case TSUB|S: expr->constant.u = l->constant.u - r->constant.u; break; - case TSUB|F: expr->constant.f = l->constant.f - r->constant.f; break; + case TSUB|S: expr->u.constant.u = l->u.constant.u - r->u.constant.u; break; + case TSUB|F: expr->u.constant.f = l->u.constant.f - r->u.constant.f; break; case TSHL: - case TSHL|S: expr->constant.u = l->constant.u << (r->constant.u & 63); break; - case TSHR: expr->constant.u = l->constant.u >> (r->constant.u & 63); break; - case TSHR|S: expr->constant.i = l->constant.i >> (r->constant.u & 63); break; + case TSHL|S: expr->u.constant.u = l->u.constant.u << (r->u.constant.u & 63); break; + case TSHR: expr->u.constant.u = l->u.constant.u >> (r->u.constant.u & 63); break; + case TSHR|S: expr->u.constant.i = l->u.constant.i >> (r->u.constant.u & 63); break; case TBAND: - case TBAND|S: expr->constant.u = l->constant.u & r->constant.u; break; + case TBAND|S: expr->u.constant.u = l->u.constant.u & r->u.constant.u; break; case TBOR: - case TBOR|S: expr->constant.u = l->constant.u | r->constant.u; break; + case TBOR|S: expr->u.constant.u = l->u.constant.u | r->u.constant.u; break; case TXOR: - case TXOR|S: expr->constant.u = l->constant.u ^ r->constant.u; break; - case TLESS: expr->constant.u = l->constant.u < r->constant.u; break; - case TLESS|S: expr->constant.u = l->constant.i < r->constant.i; break; - case TLESS|F: expr->constant.u = l->constant.f < r->constant.f; break; - case TGREATER: expr->constant.u = l->constant.u > r->constant.u; break; - case TGREATER|S: expr->constant.u = l->constant.i > r->constant.i; break; - case TGREATER|F: expr->constant.u = l->constant.f > r->constant.f; break; - case TLEQ: expr->constant.u = l->constant.u <= r->constant.u; break; - case TLEQ|S: expr->constant.u = l->constant.i <= r->constant.i; break; - case TLEQ|F: expr->constant.u = l->constant.f <= r->constant.f; break; - case TGEQ: expr->constant.u = l->constant.u >= r->constant.u; break; - case TGEQ|S: expr->constant.u = l->constant.i >= r->constant.i; break; - case TGEQ|F: expr->constant.u = l->constant.f >= r->constant.f; break; + case TXOR|S: expr->u.constant.u = l->u.constant.u ^ r->u.constant.u; break; + case TLESS: expr->u.constant.u = l->u.constant.u < r->u.constant.u; break; + case TLESS|S: expr->u.constant.u = l->u.constant.i < r->u.constant.i; break; + case TLESS|F: expr->u.constant.u = l->u.constant.f < r->u.constant.f; break; + case TGREATER: expr->u.constant.u = l->u.constant.u > r->u.constant.u; break; + case TGREATER|S: expr->u.constant.u = l->u.constant.i > r->u.constant.i; break; + case TGREATER|F: expr->u.constant.u = l->u.constant.f > r->u.constant.f; break; + case TLEQ: expr->u.constant.u = l->u.constant.u <= r->u.constant.u; break; + case TLEQ|S: expr->u.constant.u = l->u.constant.i <= r->u.constant.i; break; + case TLEQ|F: expr->u.constant.u = l->u.constant.f <= r->u.constant.f; break; + case TGEQ: expr->u.constant.u = l->u.constant.u >= r->u.constant.u; break; + case TGEQ|S: expr->u.constant.u = l->u.constant.i >= r->u.constant.i; break; + case TGEQ|F: expr->u.constant.u = l->u.constant.f >= r->u.constant.f; break; case TEQL: - case TEQL|S: expr->constant.u = l->constant.u == r->constant.u; break; - case TEQL|F: expr->constant.u = l->constant.f == r->constant.f; break; + case TEQL|S: expr->u.constant.u = l->u.constant.u == r->u.constant.u; break; + case TEQL|F: expr->u.constant.u = l->u.constant.f == r->u.constant.f; break; case TNEQ: - case TNEQ|S: expr->constant.u = l->constant.u != r->constant.u; break; - case TNEQ|F: expr->constant.u = l->constant.f != r->constant.f; break; + case TNEQ|S: expr->u.constant.u = l->u.constant.u != r->u.constant.u; break; + case TNEQ|F: expr->u.constant.u = l->u.constant.f != r->u.constant.f; break; default: fatal("internal error; unknown binary expression"); } @@ -96,19 +96,19 @@ eval(struct expr *expr, enum evalkind kind) t = expr->type; switch (expr->kind) { case EXPRIDENT: - if (expr->ident.decl->kind != DECLCONST) + if (expr->u.ident.decl->kind != DECLCONST) break; expr->kind = EXPRCONST; - expr->constant.u = intconstvalue(expr->ident.decl->value); + expr->u.constant.u = intconstvalue(expr->u.ident.decl->value); break; case EXPRCOMPOUND: if (kind != EVALINIT) break; d = mkdecl(DECLOBJECT, t, expr->qual, LINKNONE); d->value = mkglobal(NULL, true); - emitdata(d, expr->compound.init); + emitdata(d, expr->u.compound.init); expr->kind = EXPRIDENT; - expr->ident.decl = d; + expr->u.ident.decl = d; break; case EXPRUNARY: l = eval(expr->base, kind); @@ -122,7 +122,7 @@ eval(struct expr *expr, enum evalkind kind) case EXPRSTRING: if (kind != EVALINIT) break; - l->ident.decl = stringdecl(l); + l->u.ident.decl = stringdecl(l); l->kind = EXPRIDENT; expr->base = l; break; @@ -133,22 +133,22 @@ eval(struct expr *expr, enum evalkind kind) if (l->kind == EXPRCONST) { expr->kind = EXPRCONST; if (l->type->prop & PROPINT && t->prop & PROPFLOAT) { - if (l->type->basic.issigned) - expr->constant.f = l->constant.i; + if (l->type->u.basic.issigned) + expr->u.constant.f = l->u.constant.i; else - expr->constant.f = l->constant.u; + expr->u.constant.f = l->u.constant.u; } else if (l->type->prop & PROPFLOAT && t->prop & PROPINT) { - if (t->basic.issigned) { - if (l->constant.f < INT64_MIN || l->constant.f > INT64_MAX) - error(&tok.loc, "integer part of floating-point constant %g cannot be represented as signed integer", l->constant.f); - expr->constant.i = l->constant.f; + if (t->u.basic.issigned) { + if (l->u.constant.f < INT64_MIN || l->u.constant.f > INT64_MAX) + error(&tok.loc, "integer part of floating-point constant %g cannot be represented as signed integer", l->u.constant.f); + expr->u.constant.i = l->u.constant.f; } else { - if (l->constant.f < 0 || l->constant.f > UINT64_MAX) - error(&tok.loc, "integer part of floating-point constant %g cannot be represented as unsigned integer", l->constant.f); - expr->constant.u = l->constant.f; + if (l->u.constant.f < 0 || l->u.constant.f > UINT64_MAX) + error(&tok.loc, "integer part of floating-point constant %g cannot be represented as unsigned integer", l->u.constant.f); + expr->u.constant.u = l->u.constant.f; } } else { - expr->constant = l->constant; + expr->u.constant = l->u.constant; } cast(expr); } else if (l->type->kind == TYPEPOINTER) { @@ -163,10 +163,10 @@ eval(struct expr *expr, enum evalkind kind) } break; case EXPRBINARY: - l = eval(expr->binary.l, kind); - r = eval(expr->binary.r, kind); - expr->binary.l = l; - expr->binary.r = r; + l = eval(expr->u.binary.l, kind); + r = eval(expr->u.binary.r, kind); + expr->u.binary.l = l; + expr->u.binary.r = r; switch (expr->op) { case TADD: if (r->kind == EXPRBINARY) @@ -177,21 +177,21 @@ eval(struct expr *expr, enum evalkind kind) break; if (l->kind == EXPRCONST) { binary(expr, expr->op, l, r); - } else if (l->kind == EXPRBINARY && l->type->kind == TYPEPOINTER && l->op == TADD && l->binary.r->kind == EXPRCONST) { + } else if (l->kind == EXPRBINARY && l->type->kind == TYPEPOINTER && l->op == TADD && l->u.binary.r->kind == EXPRCONST) { /* (P + C1) ± C2 -> P + (C1 ± C2) */ - binary(expr->binary.r, expr->op, l->binary.r, r); + binary(expr->u.binary.r, expr->op, l->u.binary.r, r); expr->op = TADD; - expr->binary.l = l->binary.l; + expr->u.binary.l = l->u.binary.l; } break; case TLOR: if (l->kind != EXPRCONST) break; - return l->constant.u ? l : r; + return l->u.constant.u ? l : r; case TLAND: if (l->kind != EXPRCONST) break; - return l->constant.u ? r : l; + return l->u.constant.u ? r : l; default: if (l->kind != EXPRCONST || r->kind != EXPRCONST) break; @@ -34,8 +34,8 @@ delexpr(struct expr *e) switch (e->kind) { case EXPRCALL: delexpr(e->base); - while (sub = e->call.args) { - e->call.args = sub->next; + while (sub = e->u.call.args) { + e->u.call.args = sub->next; delexpr(sub); } break; @@ -46,13 +46,13 @@ delexpr(struct expr *e) delexpr(e->base); break; case EXPRBINARY: - delexpr(e->binary.l); - delexpr(e->binary.r); + delexpr(e->u.binary.l); + delexpr(e->u.binary.r); break; case EXPRCOND: delexpr(e->base); - delexpr(e->cond.t); - delexpr(e->cond.f); + delexpr(e->u.cond.t); + delexpr(e->u.cond.f); break; /* XXX: compound assignment causes some reuse of expressions, @@ -79,7 +79,7 @@ mkconstexpr(struct type *t, uint64_t n) struct expr *e; e = mkexpr(EXPRCONST, t, NULL); - e->constant.u = n; + e->u.constant.u = n; return e; } @@ -93,7 +93,7 @@ decay(struct expr *e) struct type *t; enum typequal tq; - // XXX: combine with decl.c:adjust in some way? + /* XXX: combine with decl.c:adjust in some way? */ t = e->type; tq = e->qual; switch (t->kind) { @@ -145,6 +145,7 @@ mkunaryexpr(enum tokenkind op, struct expr *base) } /* other unary operators get compiled as equivalent binary ones */ fatal("internal error: unknown unary operator %d", op); + return NULL; } static unsigned @@ -152,7 +153,7 @@ bitfieldwidth(struct expr *e) { if (e->kind != EXPRBITFIELD) return -1; - return e->type->size * 8 - e->bitfield.bits.before - e->bitfield.bits.after; + return e->type->size * 8 - e->u.bitfield.bits.before - e->u.bitfield.bits.after; } struct expr * @@ -183,7 +184,7 @@ nullpointer(struct expr *e) return false; if (!(e->type->prop & PROPINT) && (e->type->kind != TYPEPOINTER || e->type->base != &typevoid)) return false; - return e->constant.u == 0; + return e->u.constant.u == 0; } static struct expr * @@ -311,8 +312,8 @@ mkbinaryexpr(struct location *loc, enum tokenkind op, struct expr *l, struct exp } e = mkexpr(EXPRBINARY, t, NULL); e->op = op; - e->binary.l = l; - e->binary.r = r; + e->u.binary.l = l; + e->u.binary.r = r; return e; } @@ -347,7 +348,7 @@ inttype(unsigned long long val, bool decimal, char *end) step = i % 2 || decimal ? 2 : 1; for (; i < LEN(limits); i += step) { t = limits[i].type; - if (val <= 0xffffffffffffffffu >> (8 - t->size << 3) + t->basic.issigned) + if (val <= 0xffffffffffffffffu >> (8 - t->size << 3) + t->u.basic.issigned) return t; } error(&tok.loc, "no suitable type for constant '%s'", tok.lit); @@ -487,22 +488,18 @@ stringconcat(struct stringlit *str, bool forceutf8) case 1: width = 1; encodechar = encodechar8; - buf = xreallocarray(NULL, len, 1); - str->data = buf; break; case 2: width = sizeof(uint_least16_t); encodechar = encodechar16; - buf = xreallocarray(NULL, len, width); - str->data16 = (uint_least16_t *)buf; break; case 4: width = sizeof(uint_least32_t); encodechar = encodechar32; - buf = xreallocarray(NULL, len, width); - str->data32 = (uint_least32_t *)buf; break; } + buf = xreallocarray(NULL, len, width); + str->data = buf; dst = buf; arrayforeach(&parts, p) { src = p->str; @@ -582,15 +579,15 @@ primaryexpr(struct scope *s) e = mkexpr(EXPRIDENT, d->type, NULL); e->qual = d->qual; e->lvalue = d->kind == DECLOBJECT; - e->ident.decl = d; + e->u.ident.decl = d; if (d->kind != DECLBUILTIN) e = decay(e); next(); break; case TSTRINGLIT: e = mkexpr(EXPRSTRING, NULL, NULL); - t = stringconcat(&e->string, false); - e->type = mkarraytype(t, QUALNONE, e->string.size); + t = stringconcat(&e->u.string, false); + e->type = mkarraytype(t, QUALNONE, e->u.string.size); e->lvalue = true; e = decay(e); break; @@ -623,7 +620,7 @@ primaryexpr(struct scope *s) } if (strpbrk(tok.lit, base == 16 ? ".pP" : ".eE")) { /* floating constant */ - e->constant.f = strtod(tok.lit, &end); + e->u.constant.f = strtod(tok.lit, &end); if (end == tok.lit) error(&tok.loc, "invalid floating constant '%s'", tok.lit); if (!end[0]) @@ -639,10 +636,10 @@ primaryexpr(struct scope *s) if (base == 2) src += 2; /* integer constant */ - e->constant.u = strtoull(src, &end, base); + e->u.constant.u = strtoull(src, &end, base); if (end == src) error(&tok.loc, "invalid integer constant '%s'", tok.lit); - e->type = inttype(e->constant.u, base == 10, end); + e->type = inttype(e->u.constant.u, base == 10, end); } next(); break; @@ -712,7 +709,7 @@ builtinfunc(struct scope *s, enum builtinkind kind) case BUILTINALLOCA: e = exprconvert(assignexpr(s), &typeulong); e = mkexpr(EXPRBUILTIN, mkpointertype(&typevoid, QUALNONE), e); - e->builtin.kind = BUILTINALLOCA; + e->u.builtin.kind = BUILTINALLOCA; break; case BUILTINCONSTANTP: e = mkconstexpr(&typeint, eval(condexpr(s), EVALARITH)->kind == EXPRCONST); @@ -727,15 +724,15 @@ builtinfunc(struct scope *s, enum builtinkind kind) case BUILTININFF: e = mkexpr(EXPRCONST, &typefloat, NULL); /* TODO: use INFINITY here when we can handle musl's math.h */ - e->constant.f = strtod("inf", NULL); + e->u.constant.f = strtod("inf", NULL); break; case BUILTINNANF: e = assignexpr(s); - if (!e->decayed || e->base->kind != EXPRSTRING || e->base->string.size > 1) + if (!e->decayed || e->base->kind != EXPRSTRING || e->base->u.string.size > 1) error(&tok.loc, "__builtin_nanf currently only supports empty string literals"); e = mkexpr(EXPRCONST, &typefloat, NULL); /* TODO: use NAN here when we can handle musl's math.h */ - e->constant.f = strtod("nan", NULL); + e->u.constant.f = strtod("nan", NULL); break; case BUILTINOFFSETOF: t = typename(s, NULL); @@ -758,11 +755,11 @@ builtinfunc(struct scope *s, enum builtinkind kind) break; case BUILTINUNREACHABLE: e = mkexpr(EXPRBUILTIN, &typevoid, NULL); - e->builtin.kind = BUILTINUNREACHABLE; + e->u.builtin.kind = BUILTINUNREACHABLE; break; case BUILTINVAARG: e = mkexpr(EXPRBUILTIN, NULL, assignexpr(s)); - e->builtin.kind = BUILTINVAARG; + e->u.builtin.kind = BUILTINVAARG; if (!typesame(e->base->type, typeadjvalist)) error(&tok.loc, "va_arg argument must have type va_list"); if (typeadjvalist == targ->typevalist) @@ -772,17 +769,17 @@ builtinfunc(struct scope *s, enum builtinkind kind) break; case BUILTINVACOPY: e = mkexpr(EXPRASSIGN, &typevoid, NULL); - e->assign.l = assignexpr(s); - if (!typesame(e->assign.l->type, typeadjvalist)) + e->u.assign.l = assignexpr(s); + if (!typesame(e->u.assign.l->type, typeadjvalist)) error(&tok.loc, "va_copy destination must have type va_list"); if (typeadjvalist != targ->typevalist) - e->assign.l = mkunaryexpr(TMUL, e->assign.l); + e->u.assign.l = mkunaryexpr(TMUL, e->u.assign.l); expect(TCOMMA, "after target va_list"); - e->assign.r = assignexpr(s); - if (!typesame(e->assign.r->type, typeadjvalist)) + e->u.assign.r = assignexpr(s); + if (!typesame(e->u.assign.r->type, typeadjvalist)) error(&tok.loc, "va_copy source must have type va_list"); if (typeadjvalist != targ->typevalist) - e->assign.r = mkunaryexpr(TMUL, e->assign.r); + e->u.assign.r = mkunaryexpr(TMUL, e->u.assign.r); break; case BUILTINVAEND: e = assignexpr(s); @@ -792,7 +789,7 @@ builtinfunc(struct scope *s, enum builtinkind kind) break; case BUILTINVASTART: e = mkexpr(EXPRBUILTIN, &typevoid, assignexpr(s)); - e->builtin.kind = BUILTINVASTART; + e->u.builtin.kind = BUILTINVASTART; if (!typesame(e->base->type, typeadjvalist)) error(&tok.loc, "va_start argument must have type va_list"); if (typeadjvalist == targ->typevalist) @@ -802,7 +799,7 @@ builtinfunc(struct scope *s, enum builtinkind kind) if (param->kind != EXPRIDENT) error(&tok.loc, "expected parameter identifier"); delexpr(param); - // XXX: check that this was actually a parameter name? + /* XXX: check that this was actually a parameter name? */ break; default: fatal("internal error; unknown builtin"); @@ -821,7 +818,7 @@ mkincdecexpr(enum tokenkind op, struct expr *base, bool post) error(&tok.loc, "operand of '%s' operator is const qualified", tokstr[op]); e = mkexpr(EXPRINCDEC, base->type, base); e->op = op; - e->incdec.post = post; + e->u.incdec.post = post; return e; } @@ -861,8 +858,8 @@ postfixexpr(struct scope *s, struct expr *r) break; case TLPAREN: /* function call */ next(); - if (r->kind == EXPRIDENT && r->ident.decl->kind == DECLBUILTIN) { - e = builtinfunc(s, r->ident.decl->builtin); + if (r->kind == EXPRIDENT && r->u.ident.decl->kind == DECLBUILTIN) { + e = builtinfunc(s, r->u.ident.decl->builtin); expect(TRPAREN, "after builtin parameters"); break; } @@ -870,26 +867,26 @@ postfixexpr(struct scope *s, struct expr *r) error(&tok.loc, "called object is not a function"); t = r->type->base; e = mkexpr(EXPRCALL, t->base, r); - e->call.args = NULL; - e->call.nargs = 0; - p = t->func.params; - end = &e->call.args; + e->u.call.args = NULL; + e->u.call.nargs = 0; + p = t->u.func.params; + end = &e->u.call.args; while (tok.kind != TRPAREN) { - if (e->call.args) + if (e->u.call.args) expect(TCOMMA, "or ')' after function call argument"); - if (!p && !t->func.isvararg && t->func.paraminfo) + if (!p && !t->u.func.isvararg && t->u.func.paraminfo) error(&tok.loc, "too many arguments for function call"); *end = assignexpr(s); - if (!t->func.isprototype || (t->func.isvararg && !p)) + if (!t->u.func.isprototype || (t->u.func.isvararg && !p)) *end = exprpromote(*end); else *end = exprconvert(*end, p->type); end = &(*end)->next; - ++e->call.nargs; + ++e->u.call.nargs; if (p) p = p->next; } - if (p && !t->func.isvararg && t->func.paraminfo) + if (p && !t->u.func.isvararg && t->u.func.paraminfo) error(&tok.loc, "not enough arguments for function call"); e = decay(e); next(); @@ -921,7 +918,7 @@ postfixexpr(struct scope *s, struct expr *r) if (m->bits.before || m->bits.after) { e = mkexpr(EXPRBITFIELD, r->type, r); e->lvalue = lvalue; - e->bitfield.bits = m->bits; + e->u.bitfield.bits = m->bits; } else { e = r; } @@ -1056,13 +1053,13 @@ castexpr(struct scope *s) e = mkexpr(EXPRCOMPOUND, t, NULL); e->qual = tq; e->lvalue = true; - e->compound.init = parseinit(s, t); + e->u.compound.init = parseinit(s, t); e = decay(e); *end = postfixexpr(s, e); return r; } e = mkexpr(EXPRCAST, t, NULL); - // XXX check types 6.5.4 + /* XXX check types 6.5.4 */ *end = e; end = &e->base; } @@ -1165,10 +1162,10 @@ condexpr(struct scope *s) } e = eval(e, EVALARITH); if (e->kind == EXPRCONST && e->type->prop & PROPINT) - return exprconvert(e->constant.u ? l : r, t); + return exprconvert(e->u.constant.u ? l : r, t); e = mkexpr(EXPRCOND, t, e); - e->cond.t = l; - e->cond.f = r; + e->u.cond.t = l; + e->u.cond.f = r; return e; } @@ -1186,9 +1183,9 @@ intconstexpr(struct scope *s, bool allowneg) e = constexpr(s); if (e->kind != EXPRCONST || !(e->type->prop & PROPINT)) error(&tok.loc, "not an integer constant expression"); - if (!allowneg && e->type->basic.issigned && e->constant.u > INT64_MAX) + if (!allowneg && e->type->u.basic.issigned && e->u.constant.u > INT64_MAX) error(&tok.loc, "integer constant expression cannot be negative"); - return e->constant.u; + return e->u.constant.u; } static struct expr * @@ -1197,8 +1194,8 @@ mkassignexpr(struct expr *l, struct expr *r) struct expr *e; e = mkexpr(EXPRASSIGN, l->type, NULL); - e->assign.l = l; - e->assign.r = exprconvert(r, l->type); + e->u.assign.l = l; + e->u.assign.r = exprconvert(r, l->type); return e; } @@ -1241,7 +1238,7 @@ assignexpr(struct scope *s) } tmp = mkexpr(EXPRTEMP, mkpointertype(l->type, l->qual), NULL); tmp->lvalue = true; - tmp->temp = NULL; + tmp->u.temp = NULL; e = mkassignexpr(tmp, mkunaryexpr(TBAND, l)); l = mkunaryexpr(TMUL, tmp); if (bit) { @@ -12,7 +12,7 @@ struct object { union { struct member *mem; size_t idx; - }; + } u; bool iscur; }; @@ -68,8 +68,8 @@ updatearray(struct type *t, unsigned long long i) { if (!t->incomplete) return; - if (++i > t->array.length) { - t->array.length = i; + if (++i > t->u.array.length) { + t->u.array.length = i; t->size = i * t->base->size; } } @@ -90,10 +90,10 @@ findmember(struct initparser *p, char *name) { struct member *m; - for (m = p->sub->type->structunion.members; m; m = m->next) { + for (m = p->sub->type->u.structunion.members; m; m = m->next) { if (m->name) { if (strcmp(m->name, name) == 0) { - p->sub->mem = m; + p->sub->u.mem = m; subobj(p, m->type, m->offset); return true; } @@ -122,13 +122,13 @@ designator(struct scope *s, struct initparser *p) if (t->kind != TYPEARRAY) error(&tok.loc, "index designator is only valid for array types"); next(); - p->sub->idx = intconstexpr(s, false); + p->sub->u.idx = intconstexpr(s, false); if (t->incomplete) - updatearray(t, p->sub->idx); - else if (p->sub->idx >= t->array.length) + updatearray(t, p->sub->u.idx); + else if (p->sub->u.idx >= t->u.array.length) error(&tok.loc, "index designator is larger than array length"); expect(TRBRACK, "for index designator"); - subobj(p, t->base, p->sub->idx * t->base->size); + subobj(p, t->base, p->sub->u.idx * t->base->size); break; case TPERIOD: if (t->kind != TYPESTRUCT && t->kind != TYPEUNION) @@ -153,15 +153,15 @@ focus(struct initparser *p) switch (p->sub->type->kind) { case TYPEARRAY: - p->sub->idx = 0; + p->sub->u.idx = 0; if (p->sub->type->incomplete) - updatearray(p->sub->type, p->sub->idx); + updatearray(p->sub->type, 0); t = p->sub->type->base; break; case TYPESTRUCT: case TYPEUNION: - p->sub->mem = p->sub->type->structunion.members; - t = p->sub->mem->type; + p->sub->u.mem = p->sub->type->u.structunion.members; + t = p->sub->u.mem->type; break; default: fatal("internal error: init cursor has unexpected type"); @@ -179,18 +179,18 @@ advance(struct initparser *p) t = p->sub->type; switch (t->kind) { case TYPEARRAY: - ++p->sub->idx; + ++p->sub->u.idx; if (t->incomplete) - updatearray(t, p->sub->idx); - if (p->sub->idx < t->array.length) { - subobj(p, t->base, t->base->size * p->sub->idx); + updatearray(t, p->sub->u.idx); + if (p->sub->u.idx < t->u.array.length) { + subobj(p, t->base, t->base->size * p->sub->u.idx); return; } break; case TYPESTRUCT: - p->sub->mem = p->sub->mem->next; - if (p->sub->mem) { - subobj(p, p->sub->mem->type, p->sub->mem->offset); + p->sub->u.mem = p->sub->u.mem->next; + if (p->sub->u.mem) { + subobj(p, p->sub->u.mem->type, p->sub->u.mem->offset); return; } break; @@ -216,7 +216,7 @@ parseinit(struct scope *s, struct type *t) p.sub->iscur = false; p.init = NULL; p.last = &p.init; - if (t->incomplete && !(t->kind == TYPEARRAY && t->array.length == 0)) + if (t->incomplete && !(t->kind == TYPEARRAY && t->u.array.length == 0)) error(&tok.loc, "initializer specified for incomplete type"); for (;;) { if (p.cur) { @@ -250,7 +250,7 @@ parseinit(struct scope *s, struct type *t) if (!(base->prop & PROPCHAR && expr->type->base->prop & PROPCHAR) && !typecompatible(base, expr->type->base)) error(&tok.loc, "cannot initialize array with string literal of different width"); if (t->incomplete) - updatearray(t, expr->string.size - 1); + updatearray(t, expr->u.string.size - 1); goto add; case TYPESTRUCT: case TYPEUNION: @@ -266,7 +266,7 @@ parseinit(struct scope *s, struct type *t) } add: if (p.sub > p.obj && (p.sub[-1].type->kind == TYPESTRUCT || p.sub[-1].type->kind == TYPEUNION)) - bits = p.sub[-1].mem->bits; + bits = p.sub[-1].u.mem->bits; else bits = (struct bitfield){0}; initadd(&p, mkinit(p.sub->offset, p.sub->offset + p.sub->type->size, bits, expr)); @@ -15,7 +15,7 @@ static uint64_t hash(const void *ptr, size_t len) { extern int siphash(const uint8_t *, const size_t, const uint8_t *, uint8_t *, const size_t); - static const uint8_t k[16] = {0}; // XXX: we don't have a way to get entropy in standard C + static const uint8_t k[16] = {0}; /* XXX: we don't have a way to get entropy in standard C */ uint64_t r; siphash(ptr, len, k, (uint8_t *)&r, sizeof(r)); @@ -24,7 +24,7 @@ struct value { char *name; uint64_t i; double f; - }; + } u; }; struct lvalue { @@ -116,7 +116,7 @@ mkblock(char *name) b = xmalloc(sizeof(*b)); b->label.kind = VALUE_LABEL; - b->label.name = name; + b->label.u.name = name; b->label.id = ++id; b->insts = (struct array){0}; b->jump.kind = JUMP_NONE; @@ -134,7 +134,7 @@ mkglobal(char *name, bool private) v = xmalloc(sizeof(*v)); v->kind = VALUE_GLOBAL; - v->name = name; + v->u.name = name; v->id = private ? ++id : 0; return v; @@ -144,7 +144,7 @@ char * globalname(struct value *v) { assert(v->kind == VALUE_GLOBAL && !v->id); - return v->name; + return v->u.name; } struct value * @@ -154,7 +154,7 @@ mkintconst(uint64_t n) v = xmalloc(sizeof(*v)); v->kind = VALUE_INTCONST; - v->i = n; + v->u.i = n; return v; } @@ -163,7 +163,7 @@ uint64_t intconstvalue(struct value *v) { assert(v->kind == VALUE_INTCONST); - return v->i; + return v->u.i; } static struct value * @@ -173,7 +173,7 @@ mkfltconst(int kind, double n) v = xmalloc(sizeof(*v)); v->kind = kind; - v->f = n; + v->u.f = n; return v; } @@ -197,8 +197,8 @@ qbetype(struct type *t) if (!(t->prop & PROPSCALAR)) return l; switch (t->size) { - case 1: return t->basic.issigned ? sb : ub; - case 2: return t->basic.issigned ? sh : uh; + case 1: return t->u.basic.issigned ? sb : ub; + case 2: return t->u.basic.issigned ? sh : uh; case 4: return t->prop & PROPFLOAT ? s : w; case 8: return t->prop & PROPFLOAT ? d : l; case 16: fatal("long double is not yet supported"); @@ -215,7 +215,7 @@ static void functemp(struct func *f, struct value *v) { v->kind = VALUE_TEMP; - v->name = NULL; + v->u.name = NULL; v->id = ++f->lastid; } @@ -301,7 +301,7 @@ funcbits(struct func *f, struct type *t, struct value *v, struct bitfield b) } bits += b.before; if (bits) - v = funcinst(f, t->basic.issigned ? ISAR : ISHR, class, v, mkintconst(bits)); + v = funcinst(f, t->u.basic.issigned ? ISAR : ISHR, class, v, mkintconst(bits)); return v; } @@ -509,20 +509,20 @@ convert(struct func *f, struct type *dst, struct type *src, struct value *l) if (dst->size <= src->size) return l; switch (src->size) { - case 4: op = src->basic.issigned ? IEXTSW : IEXTUW; break; - case 2: op = src->basic.issigned ? IEXTSH : IEXTUH; break; - case 1: op = src->basic.issigned ? IEXTSB : IEXTUB; break; + case 4: op = src->u.basic.issigned ? IEXTSW : IEXTUW; break; + case 2: op = src->u.basic.issigned ? IEXTSH : IEXTUH; break; + case 1: op = src->u.basic.issigned ? IEXTSB : IEXTUB; break; default: fatal("internal error; unknown integer conversion"); } } else { - if (!dst->basic.issigned) + if (!dst->u.basic.issigned) return ftou(f, class, src->size == 8 ? 'd' : 's', l); op = src->size == 8 ? IDTOSI : ISTOSI; } } else { class = dst->size == 8 ? 'd' : 's'; if (src->prop & PROPINT) { - if (!src->basic.issigned) + if (!src->u.basic.issigned) return utof(f, class, src->size == 8 ? 'l' : 'w', l); op = src->size == 8 ? ISLTOF : ISWTOF; } else { @@ -555,10 +555,10 @@ mkfunc(struct decl *decl, char *name, struct type *t, struct scope *s) emittype(t->base); /* allocate space for parameters */ - for (p = t->func.params; p; p = p->next) { + for (p = t->u.func.params; p; p = p->next) { if (!p->name) error(&tok.loc, "parameter name omitted in definition of function '%s'", name); - pt = t->func.isprototype ? p->type : typepromote(p->type, -1); + pt = t->u.func.isprototype ? p->type : typepromote(p->type, -1); emittype(pt); p->value = xmalloc(sizeof(*p->value)); functemp(f, p->value); @@ -687,14 +687,14 @@ funclval(struct func *f, struct expr *e) struct decl *d; if (e->kind == EXPRBITFIELD) { - lval.bits = e->bitfield.bits; + lval.bits = e->u.bitfield.bits; e = e->base; } switch (e->kind) { case EXPRIDENT: - d = e->ident.decl; + d = e->u.ident.decl; if (d->kind != DECLOBJECT && d->kind != DECLFUNC) - error(&tok.loc, "identifier is not an object or function"); // XXX: fix location, var name + error(&tok.loc, "identifier is not an object or function"); /* XXX: fix location, var name */ if (d == f->namedecl) { fputs("data ", stdout); emitvalue(d->value); @@ -709,7 +709,7 @@ funclval(struct func *f, struct expr *e) break; case EXPRCOMPOUND: d = mkdecl(DECLOBJECT, e->type, e->qual, LINKNONE); - funcinit(f, d, e->compound.init); + funcinit(f, d, e->u.compound.init); lval.addr = d->value; break; case EXPRUNARY: @@ -739,7 +739,7 @@ funcexpr(struct func *f, struct expr *e) switch (e->kind) { case EXPRIDENT: - d = e->ident.decl; + d = e->u.ident.decl; switch (d->kind) { case DECLOBJECT: return funcload(f, d->type, (struct lvalue){d->value}); case DECLCONST: return d->value; @@ -750,9 +750,9 @@ funcexpr(struct func *f, struct expr *e) case EXPRCONST: t = e->type; if (t->prop & PROPINT || t->kind == TYPEPOINTER) - return mkintconst(e->constant.u); + return mkintconst(e->u.constant.u); assert(t->prop & PROPFLOAT); - return mkfltconst(t->size == 4 ? VALUE_FLTCONST : VALUE_DBLCONST, e->constant.f); + return mkfltconst(t->size == 4 ? VALUE_FLTCONST : VALUE_DBLCONST, e->u.constant.f); case EXPRBITFIELD: case EXPRCOMPOUND: lval = funclval(f, e); @@ -771,10 +771,10 @@ funcexpr(struct func *f, struct expr *e) fatal("not a scalar"); v = funcinst(f, e->op == TINC ? IADD : ISUB, qbetype(t).base, l, r); v = funcstore(f, e->type, e->qual, lval, v); - return e->incdec.post ? l : v; + return e->u.incdec.post ? l : v; case EXPRCALL: - argvals = xreallocarray(NULL, e->call.nargs, sizeof(argvals[0])); - for (arg = e->call.args, i = 0; arg; arg = arg->next, ++i) { + argvals = xreallocarray(NULL, e->u.call.nargs, sizeof(argvals[0])); + for (arg = e->u.call.args, i = 0; arg; arg = arg->next, ++i) { emittype(arg->type); argvals[i] = funcexpr(f, arg); } @@ -782,14 +782,16 @@ funcexpr(struct func *f, struct expr *e) emittype(t); v = funcinst(f, ICALL, qbetype(t).base, funcexpr(f, e->base), t->value); functype = e->base->type->base; - for (arg = e->call.args, i = 0; arg; arg = arg->next, ++i) { - if (functype->func.isvararg && i == functype->func.nparam) + for (arg = e->u.call.args, i = 0; arg; arg = arg->next, ++i) { + if (functype->u.func.isvararg && i == functype->u.func.nparam) funcinst(f, IVARARG, 0, NULL, NULL); t = arg->type; funcinst(f, IARG, qbetype(t).base, argvals[i], t->value); } - //if (functype->func.isnoreturn) - // funcret(f, NULL); + /* + if (functype->func.isnoreturn) + funcret(f, NULL); + */ return v; case EXPRUNARY: switch (e->op) { @@ -806,11 +808,11 @@ funcexpr(struct func *f, struct expr *e) l = funcexpr(f, e->base); return convert(f, e->type, e->base->type, l); case EXPRBINARY: - l = funcexpr(f, e->binary.l); + l = funcexpr(f, e->u.binary.l); if (e->op == TLOR || e->op == TLAND) { b[0] = mkblock("logic_right"); b[1] = mkblock("logic_join"); - t = e->binary.l->type; + t = e->u.binary.l->type; if (e->op == TLOR) { funcjnz(f, l, t, b[1], b[0]); b[1]->phi.val[0] = mkintconst(1); @@ -820,16 +822,16 @@ funcexpr(struct func *f, struct expr *e) } b[1]->phi.blk[0] = f->end; funclabel(f, b[0]); - r = funcexpr(f, e->binary.r); - b[1]->phi.val[1] = convert(f, &typebool, e->binary.r->type, r); + r = funcexpr(f, e->u.binary.r); + b[1]->phi.val[1] = convert(f, &typebool, e->u.binary.r->type, r); b[1]->phi.blk[1] = f->end; funclabel(f, b[1]); functemp(f, &b[1]->phi.res); b[1]->phi.class = 'w'; return &b[1]->phi.res; } - r = funcexpr(f, e->binary.r); - t = e->binary.l->type; + r = funcexpr(f, e->u.binary.r); + t = e->u.binary.l->type; if (t->kind == TYPEPOINTER) t = &typeulong; switch (e->op) { @@ -837,10 +839,10 @@ funcexpr(struct func *f, struct expr *e) op = IMUL; break; case TDIV: - op = !(t->prop & PROPINT) || t->basic.issigned ? IDIV : IUDIV; + op = !(t->prop & PROPINT) || t->u.basic.issigned ? IDIV : IUDIV; break; case TMOD: - op = t->basic.issigned ? IREM : IUREM; + op = t->u.basic.issigned ? IREM : IUREM; break; case TADD: op = IADD; @@ -852,7 +854,7 @@ funcexpr(struct func *f, struct expr *e) op = ISHL; break; case TSHR: - op = t->basic.issigned ? ISAR : ISHR; + op = t->u.basic.issigned ? ISAR : ISHR; break; case TBOR: op = IOR; @@ -865,27 +867,27 @@ funcexpr(struct func *f, struct expr *e) break; case TLESS: if (t->size <= 4) - op = t->prop & PROPFLOAT ? ICLTS : t->basic.issigned ? ICSLTW : ICULTW; + op = t->prop & PROPFLOAT ? ICLTS : t->u.basic.issigned ? ICSLTW : ICULTW; else - op = t->prop & PROPFLOAT ? ICLTD : t->basic.issigned ? ICSLTL : ICULTL; + op = t->prop & PROPFLOAT ? ICLTD : t->u.basic.issigned ? ICSLTL : ICULTL; break; case TGREATER: if (t->size <= 4) - op = t->prop & PROPFLOAT ? ICGTS : t->basic.issigned ? ICSGTW : ICUGTW; + op = t->prop & PROPFLOAT ? ICGTS : t->u.basic.issigned ? ICSGTW : ICUGTW; else - op = t->prop & PROPFLOAT ? ICGTD : t->basic.issigned ? ICSGTL : ICUGTL; + op = t->prop & PROPFLOAT ? ICGTD : t->u.basic.issigned ? ICSGTL : ICUGTL; break; case TLEQ: if (t->size <= 4) - op = t->prop & PROPFLOAT ? ICLES : t->basic.issigned ? ICSLEW : ICULEW; + op = t->prop & PROPFLOAT ? ICLES : t->u.basic.issigned ? ICSLEW : ICULEW; else - op = t->prop & PROPFLOAT ? ICLED : t->basic.issigned ? ICSLEL : ICULEL; + op = t->prop & PROPFLOAT ? ICLED : t->u.basic.issigned ? ICSLEL : ICULEL; break; case TGEQ: if (t->size <= 4) - op = t->prop & PROPFLOAT ? ICGES : t->basic.issigned ? ICSGEW : ICUGEW; + op = t->prop & PROPFLOAT ? ICGES : t->u.basic.issigned ? ICSGEW : ICUGEW; else - op = t->prop & PROPFLOAT ? ICGED : t->basic.issigned ? ICSGEL : ICUGEL; + op = t->prop & PROPFLOAT ? ICGED : t->u.basic.issigned ? ICSGEL : ICUGEL; break; case TEQL: if (t->size <= 4) @@ -912,12 +914,12 @@ funcexpr(struct func *f, struct expr *e) funcjnz(f, v, e->base->type, b[0], b[1]); funclabel(f, b[0]); - b[2]->phi.val[0] = funcexpr(f, e->cond.t); + b[2]->phi.val[0] = funcexpr(f, e->u.cond.t); b[2]->phi.blk[0] = f->end; funcjmp(f, b[2]); funclabel(f, b[1]); - b[2]->phi.val[1] = funcexpr(f, e->cond.f); + b[2]->phi.val[1] = funcexpr(f, e->u.cond.f); b[2]->phi.blk[1] = f->end; funclabel(f, b[2]); @@ -927,12 +929,12 @@ funcexpr(struct func *f, struct expr *e) b[2]->phi.class = qbetype(e->type).base; return &b[2]->phi.res; case EXPRASSIGN: - r = funcexpr(f, e->assign.r); - if (e->assign.l->kind == EXPRTEMP) { - e->assign.l->temp = r; + r = funcexpr(f, e->u.assign.r); + if (e->u.assign.l->kind == EXPRTEMP) { + e->u.assign.l->u.temp = r; } else { - lval = funclval(f, e->assign.l); - r = funcstore(f, e->assign.l->type, e->assign.l->qual, lval, r); + lval = funclval(f, e->u.assign.l); + r = funcstore(f, e->u.assign.l->type, e->u.assign.l->qual, lval, r); } return r; case EXPRCOMMA: @@ -940,7 +942,7 @@ funcexpr(struct func *f, struct expr *e) funcexpr(f, e); return funcexpr(f, e); case EXPRBUILTIN: - switch (e->builtin.kind) { + switch (e->u.builtin.kind) { case BUILTINVASTART: l = funcexpr(f, e->base); funcinst(f, IVASTART, 0, l, NULL); @@ -961,11 +963,11 @@ funcexpr(struct func *f, struct expr *e) } return NULL; case EXPRTEMP: - assert(e->temp); - return e->temp; - default: - fatal("unimplemented expression %d", e->kind); + assert(e->u.temp); + return e->u.temp; } + fatal("unimplemented expression %d", e->kind); + return NULL; } static void @@ -1008,13 +1010,13 @@ funcinit(struct func *func, struct decl *d, struct init *init) dst.bits = init->bits; if (init->expr->kind == EXPRSTRING) { w = init->expr->type->base->size; - for (i = 0; i < init->expr->string.size && i * w < init->end - init->start; ++i) { + for (i = 0; i < init->expr->u.string.size && i * w < init->end - init->start; ++i) { v = mkintconst(init->start + i * w); dst.addr = funcinst(func, IADD, ptrclass, d->value, v); switch (w) { - case 1: v = mkintconst(init->expr->string.data[i]); break; - case 2: v = mkintconst(init->expr->string.data16[i]); break; - case 4: v = mkintconst(init->expr->string.data32[i]); break; + case 1: v = mkintconst(((unsigned char *)init->expr->u.string.data)[i]); break; + case 2: v = mkintconst(((uint_least16_t *)init->expr->u.string.data)[i]); break; + case 4: v = mkintconst(((uint_least32_t *)init->expr->u.string.data)[i]); break; } funcstore(func, init->expr->type->base, QUALNONE, dst, v); } @@ -1053,7 +1055,7 @@ casesearch(struct func *f, int class, struct value *v, struct switchcase *c, str label[1] = mkblock("switch_lt"); label[2] = mkblock("switch_gt"); - // XXX: linear search if c->node.height < 4 + /* XXX: linear search if c->node.height < 4 */ key = mkintconst(c->node.key); res = funcinst(f, class == 'w' ? ICEQW : ICEQL, 'w', v, key); funcjnz(f, res, NULL, c->body, label[0]); @@ -1086,13 +1088,13 @@ emitvalue(struct value *v) switch (v->kind) { case VALUE_INTCONST: - printf("%" PRIu64, v->i); + printf("%" PRIu64, v->u.i); break; case VALUE_FLTCONST: - printf("s_%.17g", v->f); + printf("s_%.17g", v->u.f); break; case VALUE_DBLCONST: - printf("d_%.17g", v->f); + printf("d_%.17g", v->u.f); break; default: if (v->kind >= LEN(sigil) || !sigil[v->kind]) @@ -1100,8 +1102,8 @@ emitvalue(struct value *v) putchar(sigil[v->kind]); if (v->kind == VALUE_GLOBAL && v->id) fputs(".L", stdout); - if (v->name) - fputs(v->name, stdout); + if (v->u.name) + fputs(v->u.name, stdout); if (v->id) printf(".%u", v->id); } @@ -1131,9 +1133,9 @@ emittype(struct type *t) return; t->value = xmalloc(sizeof(*t->value)); t->value->kind = VALUE_TYPE; - t->value->name = t->structunion.tag; + t->value->u.name = t->u.structunion.tag; t->value->id = ++id; - for (m = t->structunion.members; m; m = m->next) { + for (m = t->u.structunion.members; m; m = m->next) { for (sub = m->type; sub->kind == TYPEARRAY; sub = sub->base) ; emittype(sub); @@ -1145,7 +1147,7 @@ emittype(struct type *t) return; } fputs(" = { ", stdout); - for (m = t->structunion.members, off = 0; m;) { + for (m = t->u.structunion.members, off = 0; m;) { if (t->kind == TYPESTRUCT) { /* look for a subsequent member with a larger storage unit */ for (other = m->next; other; other = other->next) { @@ -1159,7 +1161,7 @@ emittype(struct type *t) fputs("{ ", stdout); } for (i = 1, sub = m->type; sub->kind == TYPEARRAY; sub = sub->base) - i *= sub->array.length; + i *= sub->u.array.length; emitclass(qbetype(sub).data, sub->value); if (i > 1) printf(" %" PRIu64, i); @@ -1273,14 +1275,14 @@ emitfunc(struct func *f, bool global) } emitvalue(f->decl->value); putchar('('); - for (p = f->type->func.params; p; p = p->next) { - if (p != f->type->func.params) + for (p = f->type->u.func.params; p; p = p->next) { + if (p != f->type->u.func.params) fputs(", ", stdout); emitclass(qbetype(p->type).base, p->type->value); putchar(' '); emitvalue(p->value); } - if (f->type->func.isvararg) + if (f->type->u.func.isvararg) fputs(", ...", stdout); puts(") {"); for (b = f->start; b; b = b->next) { @@ -1321,30 +1323,30 @@ dataitem(struct expr *expr, uint64_t size) expr = expr->base; if (expr->kind != EXPRIDENT) error(&tok.loc, "initializer is not a constant expression"); - decl = expr->ident.decl; + decl = expr->u.ident.decl; if (decl->value->kind != VALUE_GLOBAL) fatal("not a global"); emitvalue(decl->value); break; case EXPRBINARY: - if (expr->op != TADD || expr->binary.l->kind != EXPRUNARY || expr->binary.r->kind != EXPRCONST) + if (expr->op != TADD || expr->u.binary.l->kind != EXPRUNARY || expr->u.binary.r->kind != EXPRCONST) error(&tok.loc, "initializer is not a constant expression"); - dataitem(expr->binary.l, 0); + dataitem(expr->u.binary.l, 0); fputs(" + ", stdout); - dataitem(expr->binary.r, 0); + dataitem(expr->u.binary.r, 0); break; case EXPRCONST: if (expr->type->prop & PROPFLOAT) - printf("%c_%.17g", expr->type->size == 4 ? 's' : 'd', expr->constant.f); + printf("%c_%.17g", expr->type->size == 4 ? 's' : 'd', expr->u.constant.f); else - printf("%" PRIu64, expr->constant.u); + printf("%" PRIu64, expr->u.constant.u); break; case EXPRSTRING: w = expr->type->base->size; if (w == 1) { fputc('"', stdout); - for (i = 0; i < expr->string.size && i < size; ++i) { - c = expr->string.data[i]; + for (i = 0; i < expr->u.string.size && i < size; ++i) { + c = ((unsigned char *)expr->u.string.data)[i]; if (isprint(c) && c != '"' && c != '\\') putchar(c); else @@ -1352,10 +1354,10 @@ dataitem(struct expr *expr, uint64_t size) } fputc('"', stdout); } else { - for (i = 0; i < expr->string.size && i * w < size; ++i) { + for (i = 0; i < expr->u.string.size && i * w < size; ++i) { switch (w) { - case 2: printf("%hu ", expr->string.data16[i]); break; - case 4: printf("%u ", expr->string.data32[i]); break; + case 2: printf("%" PRIuLEAST16 " ", ((uint_least16_t *)expr->u.string.data)[i]); break; + case 4: printf("%" PRIuLEAST32 " ", ((uint_least32_t *)expr->u.string.data)[i]); break; default: assert(0); } } @@ -1400,9 +1402,9 @@ emitdata(struct decl *d, struct init *init) assert(init->expr->kind == EXPRCONST); i = (init->start - cur->start) / cur->expr->type->base->size; switch (cur->expr->type->base->size) { - case 1: cur->expr->string.data[i] = init->expr->constant.u; break; - case 2: cur->expr->string.data16[i] = init->expr->constant.u; break; - case 4: cur->expr->string.data32[i] = init->expr->constant.u; break; + case 1: ((unsigned char *)cur->expr->u.string.data)[i] = init->expr->u.constant.u; break; + case 2: ((uint_least16_t *)cur->expr->u.string.data)[i] = init->expr->u.constant.u; break; + case 4: ((uint_least32_t *)cur->expr->u.string.data)[i] = init->expr->u.constant.u; break; } } start = cur->start + cur->bits.before / 8; @@ -1418,7 +1420,7 @@ emitdata(struct decl *d, struct init *init) /* XXX: little-endian specific */ assert(cur->expr->type->prop & PROPINT); assert(cur->expr->kind == EXPRCONST); - bits |= cur->expr->constant.u << cur->bits.before % 8; + bits |= cur->expr->u.constant.u << cur->bits.before % 8; for (offset = start; offset < end; ++offset, bits >>= 8) printf("b %u, ", (unsigned)bits & 0xff); /* @@ -12,7 +12,7 @@ static const struct target alltargs[] = { .typevalist = &(struct type){ .kind = TYPEARRAY, .prop = PROPOBJECT|PROPDERIVED|PROPAGGR, .align = 8, .size = 24, - .array = {1}, .base = &(struct type){ + .u.array = {1}, .base = &(struct type){ .kind = TYPESTRUCT, .prop = PROPOBJECT|PROPAGGR, .align = 8, .size = 24, }, @@ -24,7 +24,7 @@ static const struct target alltargs[] = { .typevalist = &(struct type){ .kind = TYPESTRUCT, .prop = PROPOBJECT|PROPAGGR, .align = 8, .size = 32, - .structunion.tag = "va_list", + .u.structunion.tag = "va_list", }, .typewchar = &typeuint, }, @@ -54,6 +54,6 @@ targinit(const char *name) } if (!targ) fatal("unknown target '%s'", name); - typechar.basic.issigned = targ->signedchar; + typechar.u.basic.issigned = targ->signedchar; typeadjvalist = typeadjust(targ->typevalist); } @@ -7,7 +7,7 @@ #include "cc.h" #define INTTYPE(k, n, s, p) { \ - .kind = k, .size = n, .align = n, .basic.issigned = s, \ + .kind = k, .size = n, .align = n, .u.basic.issigned = s, \ .prop = PROPOBJECT|PROPSCALAR|PROPARITH|PROPREAL|PROPINT|p, \ } #define FLTTYPE(k, n) { \ @@ -78,11 +78,11 @@ mkarraytype(struct type *base, enum typequal qual, unsigned long long len) t = mktype(TYPEARRAY, PROPOBJECT|PROPDERIVED|PROPAGGR); t->base = base; t->qual = qual; - t->array.length = len; + t->u.array.length = len; t->incomplete = !len; if (t->base) { t->align = t->base->align; - t->size = t->base->size * len; // XXX: overflow? + t->size = t->base->size * len; /* XXX: overflow? */ } return t; @@ -100,9 +100,9 @@ typerank(struct type *t) case TYPEINT: return 4; case TYPELONG: return 5; case TYPELLONG: return 6; - default: - fatal("internal error; unhandled integer type"); } + fatal("internal error; unhandled integer type"); + return 0; } bool @@ -118,32 +118,32 @@ typecompatible(struct type *t1, struct type *t2) each other (unless they are the same type) */ return (t1->kind == TYPEENUM && t2->kind == TYPEINT || t1->kind == TYPEINT && t2->kind == TYPEENUM) && - t1->basic.issigned == t2->basic.issigned; + t1->u.basic.issigned == t2->u.basic.issigned; } switch (t1->kind) { case TYPEPOINTER: goto derived; case TYPEARRAY: - if (t1->array.length && t2->array.length && t1->array.length != t2->array.length) + if (t1->u.array.length && t2->u.array.length && t1->u.array.length != t2->u.array.length) return false; goto derived; case TYPEFUNC: - if (!t1->func.isprototype) { - if (!t2->func.isprototype) + if (!t1->u.func.isprototype) { + if (!t2->u.func.isprototype) return true; tmp = t1, t1 = t2, t2 = tmp; } - if (t1->func.isvararg != t2->func.isvararg) + if (t1->u.func.isvararg != t2->u.func.isvararg) return false; - if (!t2->func.paraminfo) { - for (p1 = t1->func.params; p1; p1 = p1->next) { + if (!t2->u.func.paraminfo) { + for (p1 = t1->u.func.params; p1; p1 = p1->next) { if (!typecompatible(p1->type, typepromote(p1->type, -1))) return false; } return true; } - for (p1 = t1->func.params, p2 = t2->func.params; p1 && p2; p1 = p1->next, p2 = p2->next) { - tmp = t2->func.isprototype ? p2->type : typepromote(p2->type, -1); + for (p1 = t1->u.func.params, p2 = t2->u.func.params; p1 && p2; p1 = p1->next, p2 = p2->next) { + tmp = t2->u.func.isprototype ? p2->type : typepromote(p2->type, -1); if (!typecompatible(p1->type, tmp)) return false; } @@ -159,15 +159,15 @@ typecompatible(struct type *t1, struct type *t2) bool typesame(struct type *t1, struct type *t2) { - // XXX: implement + /* XXX: implement */ return typecompatible(t1, t2); } struct type * typecomposite(struct type *t1, struct type *t2) { - // XXX: implement 6.2.7 - // XXX: merge with typecompatible? + /* XXX: implement 6.2.7 */ + /* XXX: merge with typecompatible? */ return t1; } @@ -179,7 +179,7 @@ typepromote(struct type *t, unsigned width) if (t->prop & PROPINT && (typerank(t) <= typerank(&typeint) || width <= typeint.size * 8)) { if (width == -1) width = t->size * 8; - return width - t->basic.issigned < typeint.size * 8 ? &typeint : &typeuint; + return width - t->u.basic.issigned < typeint.size * 8 ? &typeint : &typeuint; } return t; } @@ -200,9 +200,9 @@ typecommonreal(struct type *t1, unsigned w1, struct type *t2, unsigned w2) t2 = typepromote(t2, w2); if (t1 == t2) return t1; - if (t1->basic.issigned == t2->basic.issigned) + if (t1->u.basic.issigned == t2->u.basic.issigned) return typerank(t1) > typerank(t2) ? t1 : t2; - if (t1->basic.issigned) { + if (t1->u.basic.issigned) { tmp = t1; t1 = t2; t2 = tmp; @@ -216,6 +216,7 @@ typecommonreal(struct type *t1, unsigned w1, struct type *t2, unsigned w2) if (t2 == &typellong) return &typeullong; fatal("internal error; could not find common real type"); + return NULL; } /* function parameter type adjustment (C11 6.7.6.3p7) */ @@ -240,7 +241,7 @@ typemember(struct type *t, const char *name, unsigned long long *offset) struct member *m, *sub; assert(t->kind == TYPESTRUCT || t->kind == TYPEUNION); - for (m = t->structunion.members; m; m = m->next) { + for (m = t->u.structunion.members; m; m = m->next) { if (m->name) { if (strcmp(m->name, name) == 0) { *offset += m->offset; @@ -27,7 +27,7 @@ extern char *argv0; #define ALIGNUP(x, n) ALIGNDOWN((x) + (n) - 1, n) void warn(const char *, ...); -_Noreturn void fatal(const char *fmt, ...); +void fatal(const char *fmt, ...); void *reallocarray(void *, size_t, size_t); void *xreallocarray(void *, size_t, size_t); |