diff options
Diffstat (limited to 'bootstrap/parse.c')
| -rw-r--r-- | bootstrap/parse.c | 217 |
1 files changed, 204 insertions, 13 deletions
diff --git a/bootstrap/parse.c b/bootstrap/parse.c index 71e2a74..659f756 100644 --- a/bootstrap/parse.c +++ b/bootstrap/parse.c @@ -531,12 +531,12 @@ parsetype(struct parser *P) { struct tok tok; if (lexmatch(P, &tok, '*')) { return interntype((struct type) { - TYptr, - g_targ.ptrsize, + TYptr, g_targ.ptrsize, .child = parsetype(P) }); } else if (lexmatch(P, &tok, '[')) { i64 length = -1; + const struct type *child; if (!lexmatch(P, &tok, ']')) { struct expr ex = parseexpr(P); if (!fold(&ex) || ex.t != Eintlit) @@ -546,11 +546,12 @@ parsetype(struct parser *P) { fatal(P, ex.span, "negative array length"); lexexpect(P, ']'); } + child = parsetype(P); + if (!completetype(child)) + fatal(P, tok.span, "array of incomplete type"); return interntype((struct type) { - TYarr, - g_targ.ptrsize, - .child = parsetype(P), - .length = length + TYarr, length * child->size, child->align, + .child = child, .length = length }); } else if (lexmatch(P, &tok, TKkw_const)) { return constify(parsetype(P)); @@ -626,6 +627,111 @@ mkarraytype(const struct type *child, size_t n) { }); } +static struct aggfield * +structidx2fld(const struct type *ty, int idx) { + if (idx < 0 || idx >= ty->agg.flds.n) + return NULL; + return &ty->agg.flds.d[idx]; +} + +static int +structfldnam2idx(const struct type *ty, const char *name) { + int i; + assert(name); + for (i = 0; i < ty->agg.flds.n; ++i) + if (!strcmp(name, ty->agg.flds.d[i].name)) + return i; + return -1; +} + +static struct expr +parsestructini(struct parser *P, const struct type *ty) { + struct expr ex = {Eini}; + struct tok tok; + vec_t(struct iniarg) args = {0}; + int idx = 0; + struct aggfield *fld; + + ex.span = lexpeek(P).span; + + while (!lexmatch(P, &tok, '}')) { + struct expr e; + + if (lexmatch(P, &tok, '.')) { + const char *fnam = (tok = lexexpect(P, TKident)).str; + lexexpect(P, ':'); + idx = structfldnam2idx(ty, fnam); + if (idx < 0) + fatal(P, tok.span, "struct has no field `%s'", fnam); + } + + fld = structidx2fld(ty, idx++); + e = parseexpr(P); + if (!fld) + fatal(P, e.span, + "excess elements in struct initializer"); + if (!typeof2(e.ty, fld->ty)) + fatal(P, e.span, "incompatible element type in struct initializer"); + + vec_push(&args, ((struct iniarg) { + .fld = fld->name, + e + })); + + if (!lexmatch(P, &tok, ',')) { + lexexpect(P, '}'); + break; + } + } + + ex.ty = ty; + vec_slice_cpy(&ex.ini.args, &args); + return ex; +} + +static struct expr +parsearrini(struct parser *P, const struct type *ty) { + struct expr ex = {Eini}; + struct tok tok; + vec_t(struct iniarg) args = {0}; + i64 iota = 0; + + ex.span = lexpeek(P).span; + + while (!lexmatch(P, &tok, '}')) { + struct expr e; + + if (lexmatch(P, &tok, '[')) { + struct expr i = parseexpr(P); + if (!fold(&i) || i.t != Eintlit) + fatal(P, i.span, + "array initializer element index not a compile-time integer"); + iota = i.i; + if (iota < 0) + fatal(P, i.span, "array initializer element index is negative"); + lexexpect(P, ']'); + lexexpect(P, '='); + } + + e = parseexpr(P); + if (!typeof2(ty->child, e.ty)) + fatal(P, e.span, "incompatible element type in array initializer"); + if (ty->length >= 0 && iota >= ty->length) + fatal(P, e.span, + "excess elements in array initializer"); + vec_push(&args, ((struct iniarg) { .idx = iota++, e })); + + if (!lexmatch(P, &tok, ',')) { + lexexpect(P, '}'); + break; + } + } + + ex.ty = ty; + vec_slice_cpy(&ex.ini.args, &args); + return ex; +} + static struct expr pexprimary(struct parser *P) { struct expr ex = {0}; @@ -736,6 +842,16 @@ pexprimary(struct parser *P) { ex.t = Eenumval; ex.enu.vname = vname; ex.enu.i = ex.ty->enu.vals.d[i].i; + } else if (lexmatch(P, &tok, '{')) { + P->used_targetty = 1; + if (!P->targty) + fatal(P, tok.span, "cannot infer type for compound initializer"); + if (lexmatch(P, &tok, '}')) + ex.t = Ezeroini, ex.ty = P->targty; + else if (P->targty->t == TYstruct) + ex = parsestructini(P, P->targty); + else if (P->targty->t == TYarr) + ex = parsearrini(P, P->targty); } else { experr: fatal(P, tok.span, "expected expression (near %s)", tok2str(tok)); @@ -1176,8 +1292,9 @@ parsevardecl(struct parser *P, struct decl *decl) { } } - if (ini && decl->t == Dstatic && !fold(ini)) - fatal(P, ini->span, "static initializer isn't constant"); + // TODO static initialzier constants are a superset of folded constants + // if (ini && decl->t == Dstatic && !fold(ini)) + // fatal(P, ini->span, "static initializer isn't constant"); if (ini && !typeof2(ty, ini->ty)) fatal(P, tok.span, "incompatible initializer type"); @@ -1585,6 +1702,9 @@ parsefn(struct decl *decl, struct parser *P) { } vec_slice_cpy(&fn->params, ¶ms); fn->retty = unconstify(parsetype(P)); + if (fn->retty != ty_void && !completetype(fn->retty)) { + fatal(P, tok.span, "return type is incomplette"); + } fn->selfty = fntype(fn); if (!lexmatch(P, &tok, ';')) { struct env *env = xcalloc(1, sizeof *env); @@ -1732,7 +1852,7 @@ parseenum(struct parser *P, const char *name) { struct type ty = {TYenum}; static int id = 0; i64 iota = 0, max = 0, min = 0; - vec_t(struct enumfield) vals = {0}; + vec_t(struct enumval) vals = {0}; if (lexmatch(P, &tok, ':')) { ty.enu.intty = unconstify(parsetype(P)); @@ -1760,7 +1880,7 @@ parseenum(struct parser *P, const char *name) { if (val > max) max = val; iota = val + 1; - vec_push(&vals, ((struct enumfield) { fnam, val })); + vec_push(&vals, ((struct enumval) { fnam, val })); if (!lexmatch(P, &tok, ',')) { lexexpect(P, '}'); @@ -1779,10 +1899,56 @@ parseenum(struct parser *P, const char *name) { assert(ty.enu.intty); } + ty.size = ty.enu.intty->size; + ty.align = ty.enu.intty->align; ty.enu.name = name; ty.enu.id = id++; vec_slice_cpy(&ty.enu.vals, &vals); + return interntype(ty); +} + +static const struct type * +parseagg(struct parser *P, const char *name, int kind) { + struct tok tok; + struct type ty = {kind}; + static int id = 0; + size_t size = 0, align = 1; + vec_t(struct aggfield) flds = {0}; + + if (lexmatch(P, &tok, ';')) { + ty.agg.fwd = 1; + } else { + lexexpect(P, '{'); + while (!lexmatch(P, &tok, '}')) { + const char *fnam = (tok = lexexpect(P, TKident)).str; + const struct type *ty = parsetype(P); + size_t off = kind == TYunion ? 0 : ALIGNUP(size, ty->align); + + if (!completetype(ty)) + fatal(P, tok.span, "aggregate field `%s' is of incomplete type", fnam); + + align = MAX(align, ty->align); + if (kind == TYstruct) + size = off + ty->size; + else + size = MAX(size, ty->size); + + vec_push(&flds, ((struct aggfield) { + off, fnam, ty + })); + + if (!lexmatch(P, &tok, ',')) { + lexexpect(P, '}'); + break; + } + } + } + ty.size = ALIGNUP(size, align); + ty.align = align; + ty.agg.name = name; + vec_slice_cpy(&ty.agg.flds, &flds); + ty.agg.id = id++; return interntype(ty); } @@ -1790,7 +1956,8 @@ static void parsedecl(struct decl *decl, struct parser *P, bool toplevel) { struct tok tok = { .span = P->tokspan }; bool externp = 0; - const char *name ; + const char *name; + int kind; memset(decl, 0, sizeof *decl); if (lexmatch(P, &tok, TKkw_extern)) @@ -1834,14 +2001,38 @@ parsedecl(struct decl *decl, struct parser *P, bool toplevel) { if (externp) fatal(P, tok.span, "enum cannot be `extern'"); decl->name = lexexpects(P, TKident, "enum name").str; decl->ty = parseenum(P, decl->name); - + } else if (lexmatch(P, &tok, TKkw_struct)) { + struct decl *d2; + kind = TYstruct; + if (externp) fatal(P, tok.span, "struct cannot be `extern'"); + agg: + decl->name = lexexpects(P, TKident, "struct name").str; + decl->ty = parseagg(P, decl->name, kind); + d2 = (struct decl *)finddecl(P, decl->name); + if (d2 && d2->t == Dtype && d2->ty->t == kind && d2->ty->agg.fwd) { + // modify existing forward declaration + *(size_t *)&d2->ty->size = decl->ty->size; + *(size_t *)&d2->ty->align = decl->ty->align; + *(bool *)&d2->ty->agg.fwd = 0; + memcpy((void *)&d2->ty->agg.flds, &decl->ty->agg.flds, + sizeof d2->ty->agg.flds); + uninterntype(decl->ty); + decl = d2; + envput(P->curenv, d2); + goto noputdecl; + } + } else if (lexmatch(P, &tok, TKkw_union)) { + if (externp) fatal(P, tok.span, "union cannot be `extern'"); + kind = TYunion; + goto agg; } else { fatal(P, tok.span, "expected declaration (near %s)", tok2str(tok)); } - decl->span = tok.span; putdecl(P, tok.span, decl); +noputdecl: + decl->span = tok.span; } void |