aboutsummaryrefslogtreecommitdiffhomepage
path: root/parse.c
diff options
context:
space:
mode:
authorlemon <lsof@mailbox.org>2023-05-29 11:37:32 +0200
committerlemon <lsof@mailbox.org>2023-05-29 11:37:32 +0200
commit1c04435e5d33378ffa8eca65ca1ed35f3f9f4134 (patch)
treeeab923f7dde10ba1d71d8efe025891e743009203 /parse.c
parent84824a0ed3a0cf90728078b74ca39778c51e60b9 (diff)
field access
Diffstat (limited to 'parse.c')
-rw-r--r--parse.c122
1 files changed, 88 insertions, 34 deletions
diff --git a/parse.c b/parse.c
index 3da90c0..ceef1f2 100644
--- a/parse.c
+++ b/parse.c
@@ -219,6 +219,7 @@ finddecl(struct parser *pr, const char *name)
{
struct env *e;
struct decl *l;
+ assert(name);
for (e = pr->env; e; e = e->up) {
for (l = NULL; enviterdecl(&l, e);) {
if (name == l->name)
@@ -234,6 +235,7 @@ gettagged(struct parser *pr, struct span *span, enum typetag tt, const char *nam
struct env *e;
struct tagged *l;
struct typedata td = {0};
+ assert(name);
for (e = pr->env; e; e = e->up) {
for (l = NULL; envitertagged(&l, e);) {
if (name == ttypenames[typedata[l->ty.dat].id]) {
@@ -256,6 +258,7 @@ deftagged(struct parser *pr, struct span *span, enum typetag tt, const char *nam
{
struct tagged *l;
struct typedata td = {0};
+ assert(name);
for (l = NULL; envitertagged(&l, pr->env);) {
if (name == ttypenames[typedata[l->ty.dat].id]) {
*span = l->span;
@@ -473,6 +476,8 @@ bintypecheck(const struct span *span, enum toktag tt, struct expr *lhs, struct e
}
switch (k &~ BCSET) {
case 0:
+ if (isagg(ty) && !(lhs->qual & QCONST) && typedata[ty.dat].anyconst)
+ error(&lhs->span, "cannot assign to aggregate with const-qualified member");
if (!assigncheck(ty, rhs))
goto Error;
break;
@@ -639,7 +644,7 @@ tkprec(int tt)
static struct expr
exprparse(struct parser *pr, int prec)
{
- struct token tk;
+ struct token tk, tk2;
struct span span;
struct expr ex, rhs, tmp;
struct decl *decl;
@@ -683,7 +688,7 @@ Unary:
break;
case TKSTRLIT:
ex = mkexpr(ESTRLIT, tk.span,
- mkarrtype(mktype(TYCHAR), 0, tk.len+1), .s = { (char *)tk.s, tk.len });
+ mkarrtype(mktype(TYCHAR), 0, tk.len+1), .s = { (uchar *)tk.s, tk.len });
break;
case TKIDENT:
decl = finddecl(pr, tk.s);
@@ -754,7 +759,7 @@ Postfix:
rhs = commaexpr(pr);
span = ex.span;
if (!joinspan(&span.ex, tk.span.ex) || !joinspan(&span.ex, ex.span.ex)
- || (peek(pr, &tk), !joinspan(&span.ex, tk.span.ex)))
+ || (peek(pr, &tk2), !joinspan(&span.ex, tk.span.ex)))
span = tk.span;
expect(pr, ']', NULL);
@@ -776,14 +781,48 @@ Postfix:
tmp.sub = exprdup(pr, iszero(rhs) ? &ex : &tmp);
tmp.span = span;
tmp.t = EDEREF;
+ tmp.qual = ex.ty.flag & TFCHLDQUAL;
tmp.ty = ty;
ex = tmp;
goto Postfix;
case '(': /* call(args) */
- span = ex.span;
lex(pr, &tk);
+ span = ex.span;
ex = callexpr(pr, &span, &ex);
goto Postfix;
+ case TKARROW:
+ if (ex.ty.t != TYPTR && ex.ty.t != TYARRAY)
+ error(&ex.span, "operand to -> is not a pointer (%ty)", ex.ty);
+ else
+ ex = mkexpr(EDEREF, ex.span, typechild(ex.ty), .qual = ex.ty.flag & TFCHLDQUAL,
+ .sub = exprdup(pr, &ex));
+ /* fallthru */
+ case '.':
+ lex(pr, &tk);
+ span = ex.span;
+ peek(pr, &tk2); /* field name */
+ if (!expect(pr, TKIDENT, NULL)) tk2.s = "";
+ if (!joinspan(&span.ex, tk.span.ex) || !joinspan(&span.ex, tk2.span.ex))
+ span = tk.span;
+ if (!isagg(ex.ty)) {
+ error(&span, "member access operand is not an aggregate (%ty)%s", ex.ty,
+ ex.ty.t == TYPTR && isagg(typechild(ex.ty)) ? "; did you mean to use '->'?" : "");
+ } else {
+ struct fielddata fld = {.t = mktype(TYINT)};
+ if (*tk2.s && !getfield(&fld, ex.ty, tk2.s))
+ error(&span, "'%ty' has no such field: '%s'", ex.ty, tk2.s);
+ if (ex.t == EGETF && ex.qual == fld.qual) { /* accumulate */
+ ex.span = span;
+ ex.ty = fld.t;
+ ex.fld.off += fld.off;
+ ex.fld.bitoff = fld.bitoff;
+ ex.fld.bitsiz = fld.bitsiz;
+ } else {
+ ex = mkexpr(EGETF, span, fld.t, .qual = ex.qual | fld.qual, .sub = exprdup(pr, &ex),
+ .fld = { fld.off, fld.bitsiz, fld.bitoff });
+ }
+ }
+ goto Postfix;
}
/* unary operators (process) */
@@ -914,6 +953,8 @@ static union irref
expraddr(struct function *fn, const struct expr *ex)
{
struct decl *decl;
+ union irref r;
+ struct instr ins;
switch (ex->t) {
case ESYM:
@@ -933,6 +974,16 @@ expraddr(struct function *fn, const struct expr *ex)
break;
case EDEREF:
return exprvalue(fn, ex->sub);
+ case EGETF:
+ r = expraddr(fn, ex->sub);
+ assert(ex->fld.bitsiz == 0);
+ if (ex->fld.off == 0) return r;
+ ins.cls = KPTR;
+ ins.op = Oadd;
+ ins.l = r;
+ ins.r = mkintcon(fn, KI4, ex->fld.off);
+ return addinstr(fn, ins);
+ break;
default:
assert(!"lvalue?>");
}
@@ -1071,7 +1122,10 @@ exprvalue(struct function *fn, const struct expr *ex)
enum irclass cls = type2cls[ex->ty.t];
struct instr ins = {0};
int swp = 0;
- struct expr *sub = ex->sub;
+ struct expr *sub;
+
+ eval((struct expr *)ex, EVFOLD);
+ sub = ex->sub;
if (ex->ty.t == TYARRAY || ex->ty.t == TYFUNC)
return expraddr(fn, ex);
@@ -1082,6 +1136,8 @@ exprvalue(struct function *fn, const struct expr *ex)
return mkintcon(fn, cls, ex->i);
case ESYM:
return genload(fn, ex->ty, expraddr(fn, ex));
+ case EGETF:
+ return genload(fn, ex->ty, expraddr(fn, ex));
case ECAST:
if (ex->ty.t == TYVOID) return exprvalue(fn, sub);
case EPLUS:
@@ -1329,8 +1385,6 @@ stmt(struct parser *pr, struct function *fn)
t = newblk(fn);
f = newblk(fn);
r = exprvalue(fn, &ex);
- if (!isint(ex.ty))
- r = cvt(fn, TYINT, ex.ty.t, r);
EMITS {
putjump(fn, Jbcnd, r, t, f);
useblk(fn, t);
@@ -1366,8 +1420,6 @@ stmt(struct parser *pr, struct function *fn)
putjump(fn, Jb, NOREF, begin, NULL);
useblk(fn, begin);
r = exprvalue(fn, &ex);
- if (!isint(ex.ty))
- r = cvt(fn, TYINT, ex.ty.t, r);
EMITS {
putjump(fn, Jbcnd, r, t = newblk(fn), end = newblk(fn));
useblk(fn, t);
@@ -1535,10 +1587,8 @@ buildagg(struct parser *pr, enum typetag tt, const char *name, int id)
struct token tk;
union type t;
struct span flexspan;
- struct field fbuf[32];
- uchar qbuf[arraylength(fbuf)/4];
- vec_of(struct field) fld = VINIT(fbuf, arraylength(fbuf));
- vec_of(uchar) qual = VINIT(qbuf, arraylength(qbuf));
+ struct namedfield fbuf[32];
+ vec_of(struct namedfield) fld = VINIT(fbuf, arraylength(fbuf));
struct typedata td = {tt};
bool isunion = tt == TYUNION;
const char *tag = isunion ? "union" : "struct";
@@ -1563,12 +1613,13 @@ buildagg(struct parser *pr, enum typetag tt, const char *name, int id)
uint align = typealign(decl.ty);
uint siz = typesize(decl.ty);
uint off = isunion ? 0 : alignup(td.siz, align);
- struct field f = { decl.name, decl.ty, off };
+ struct namedfield f = { decl.name, { decl.ty, off, .qual = decl.qual }};
vpush(&fld, f);
- if (decl.qual) {
- td.anyconst |= decl.qual & QCONST;
- while (qual.n < tdqualsiz(fld.n)) vpush(&qual, 0);
- tdsetqual(qual.p, fld.n-1, decl.qual);
+ td.anyconst |= decl.qual & QCONST;
+ if (isagg(decl.ty)) {
+ td.anyconst |= typedata[decl.ty.dat].anyconst;
+ if (typedata[decl.ty.dat].flexi)
+ error(&decl.span, "nested aggregate has flexible array member");
}
if (isunion)
td.siz = td.siz < siz ? siz : td.siz;
@@ -1579,19 +1630,19 @@ buildagg(struct parser *pr, enum typetag tt, const char *name, int id)
} while (st.more);
}
if (fld.n == 0) {
- struct field dummy = { "", mktype(TYCHAR), 0 };
+ struct namedfield dummy = { "", { mktype(TYCHAR), 0 }};
error(&tk.span, "%s cannot have zero members", tag);
vpush(&fld, dummy);
td.siz = td.align = 1;
}
td.siz = alignup(td.siz, td.align);
- if (qual.p) while (qual.n < tdqualsiz(fld.n)) vpush(&qual, 0);
- td.quals = qual.p;
td.fld = fld.p;
td.nmemb = fld.n;
- t = completetype(name, id, &td);
+ if (id != -1)
+ t = completetype(name, id, &td);
+ else
+ t = mktagtype(name, &td);
vfree(&fld);
- vfree(&qual);
return t;
}
@@ -1616,6 +1667,7 @@ tagtype(struct parser *pr, enum toktag kind)
enum typetag tt = kind == TKWenum ? TYENUM : kind == TKWstruct ? TYSTRUCT : TYUNION;
const char *tag = NULL;
+ peek(pr, &tk);
if (match(pr, &tk, TKIDENT))
tag = tk.s;
span = tk.span;
@@ -1627,17 +1679,19 @@ tagtype(struct parser *pr, enum toktag kind)
t = gettagged(pr, &span, tt, tag, /* def? */ peek(pr, NULL) == ';');
} else {
if (tt != TYENUM) {
- t = deftagged(pr, &span, tt, tag);
- if (t.t != tt || !isincomplete(t)) {
- if (t.t != tt)
- error(&tk.span,
- "defining tagged type %'tk as %tt clashes with previous definition",
- &tk, kind);
- else
- error(&tk.span, "redefinition of '%tt %s'", kind, tag);
- note(&span, "previous definition:");
+ if (tag) {
+ t = deftagged(pr, &span, tt, tag);
+ if (t.t != tt || !isincomplete(t)) {
+ if (t.t != tt)
+ error(&tk.span,
+ "defining tagged type %'tk as %tt clashes with previous definition",
+ &tk, kind);
+ else
+ error(&tk.span, "redefinition of '%tt %s'", kind, tag);
+ note(&span, "previous definition:");
+ }
}
- t = buildagg(pr, tt, tag, typedata[t.dat].id);
+ t = buildagg(pr, tt, tag, tag ? typedata[t.dat].id : -1);
} else {
t = buildenum(pr, tag);
}
@@ -2111,7 +2165,7 @@ pdecl(struct declstate *st, struct parser *pr) {
}
if (first && st->tagdecl && match(pr, &tk, ';')) {
- decl = (struct decl) { st->base, st->scls, st->qual, st->align };
+ decl = (struct decl) { st->base, st->scls, st->qual, st->align, tk.span };
return decl;
}
decl = declarator(st, pr);