aboutsummaryrefslogtreecommitdiff
path: root/bootstrap/parse.c
diff options
context:
space:
mode:
authorlemon <lsof@mailbox.org>2022-08-04 22:36:59 +0200
committerlemon <lsof@mailbox.org>2022-08-04 22:36:59 +0200
commit0fec7de747d93586eda66ce190f5f3d6715421a4 (patch)
tree2c6db93b3e6d3299d530cea20dd6468cf47b43c2 /bootstrap/parse.c
parent4b2451500b8f085321a041ebc13761a5102f0e6d (diff)
struct,unions, compound literals; mostly
Diffstat (limited to 'bootstrap/parse.c')
-rw-r--r--bootstrap/parse.c217
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, &params);
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