aboutsummaryrefslogtreecommitdiff
path: root/expr.c
diff options
context:
space:
mode:
Diffstat (limited to 'expr.c')
-rw-r--r--expr.c102
1 files changed, 48 insertions, 54 deletions
diff --git a/expr.c b/expr.c
index 46d81e8..b8a7df9 100644
--- a/expr.c
+++ b/expr.c
@@ -48,6 +48,8 @@ delexpr(struct expression *e)
free(e);
}
+static struct expression *mkunaryexpr(enum tokenkind, struct expression *);
+
/* 6.3.2.1 Conversion of arrays and function designators */
static struct expression *
decay(struct expression *e)
@@ -60,22 +62,52 @@ decay(struct expression *e)
t = typeunqual(e->type, &tq);
switch (t->kind) {
case TYPEARRAY:
- t = mkqualifiedtype(mkpointertype(old->type->base), tq);
- e = mkexpr(EXPRUNARY, t, EXPRFLAG_DECAYED);
- e->unary.op = TBAND;
- e->unary.base = old;
+ e = mkunaryexpr(TBAND, old);
+ e->type = mkqualifiedtype(mkpointertype(old->type->base), tq);
+ e->flags |= EXPRFLAG_DECAYED;
break;
case TYPEFUNC:
- t = mkpointertype(old->type);
- e = mkexpr(EXPRUNARY, t, EXPRFLAG_DECAYED);
- e->unary.op = TBAND;
- e->unary.base = old;
+ e = mkunaryexpr(TBAND, old);
+ e->flags |= EXPRFLAG_DECAYED;
break;
}
return e;
}
+static void
+lvalueconvert(struct expression *e)
+{
+ e->type = typeunqual(e->type, NULL);
+ e->flags &= ~EXPRFLAG_LVAL;
+}
+
+static struct expression *
+mkunaryexpr(enum tokenkind op, struct expression *base)
+{
+ struct expression *expr;
+
+ switch (op) {
+ case TBAND:
+ if (base->flags & EXPRFLAG_DECAYED)
+ return base;
+ expr = mkexpr(EXPRUNARY, mkpointertype(base->type), 0);
+ expr->unary.op = op;
+ expr->unary.base = base;
+ return expr;
+ case TMUL:
+ lvalueconvert(base);
+ if (base->type->kind != TYPEPOINTER)
+ error(&tok.loc, "cannot dereference non-pointer");
+ expr = mkexpr(EXPRUNARY, base->type->base, EXPRFLAG_LVAL);
+ expr->unary.op = op;
+ expr->unary.base = base;
+ return decay(expr);
+ }
+ /* other unary operators get compiled as equivalent binary ones */
+ fatal("internal error: unknown unary operator %d", op);
+}
+
static struct type *
inttype(uint64_t val, bool decimal, char *end)
{
@@ -248,13 +280,6 @@ primaryexpr(struct scope *s)
return e;
}
-static void
-lvalueconvert(struct expression *e)
-{
- e->type = typeunqual(e->type, NULL);
- e->flags &= ~EXPRFLAG_LVAL;
-}
-
static struct type *
commonreal(struct expression **e1, struct expression **e2)
{
@@ -407,13 +432,8 @@ postfixexpr(struct scope *s, struct expression *r)
error(&tok.loc, "array is pointer to incomplete type");
if (!(typeprop(idx->type) & PROPINT))
error(&tok.loc, "index is not an integer type");
- tmp = mkbinaryexpr(&tok.loc, TADD, arr, idx);
-
- e = mkexpr(EXPRUNARY, arr->type->base, EXPRFLAG_LVAL);
- e->unary.op = TMUL;
- e->unary.base = tmp;
+ e = mkunaryexpr(TMUL, mkbinaryexpr(&tok.loc, TADD, arr, idx));
expect(TRBRACK, "after array index");
- e = decay(e);
break;
case TLPAREN: /* function call */
next();
@@ -489,10 +509,7 @@ postfixexpr(struct scope *s, struct expression *r)
next();
break;
case TPERIOD:
- e = mkexpr(EXPRUNARY, mkpointertype(r->type), 0);
- e->unary.op = TBAND;
- e->unary.base = r;
- r = e;
+ r = mkunaryexpr(TBAND, r);
/* fallthrough */
case TARROW:
op = tok.kind;
@@ -514,10 +531,9 @@ postfixexpr(struct scope *s, struct expression *r)
error(&tok.loc, "struct/union has no member named '%s'", tok.lit);
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;
- e = decay(e);
+ e = mkunaryexpr(TMUL, r);
+ if (!lvalue)
+ e->flags &= ~EXPRFLAG_LVAL;
next();
break;
case TINC:
@@ -562,27 +578,9 @@ unaryexpr(struct scope *s)
e->incdec.post = 0;
break;
case TBAND:
- next();
- e = castexpr(s);
- if (!(e->flags & EXPRFLAG_DECAYED)) {
- l = e;
- e = mkexpr(EXPRUNARY, NULL, 0);
- e->unary.op = op;
- e->unary.base = l;
- e->type = mkpointertype(l->type);
- }
- break;
case TMUL:
next();
- l = castexpr(s);
- lvalueconvert(l);
- if (l->type->kind != TYPEPOINTER)
- error(&tok.loc, "cannot dereference non-pointer");
- e = mkexpr(EXPRUNARY, l->type->base, EXPRFLAG_LVAL);
- e->unary.op = op;
- e->unary.base = l;
- e = decay(e);
- break;
+ return mkunaryexpr(op, castexpr(s));
case TADD:
next();
e = castexpr(s);
@@ -857,13 +855,9 @@ assignexpr(struct scope *s)
e = mkexpr(EXPRCOMMA, l->type, 0);
e->comma.exprs = mkexpr(EXPRASSIGN, tmp->type, 0);
e->comma.exprs->assign.l = tmp;
- e->comma.exprs->assign.r = mkexpr(EXPRUNARY, e->type, 0);
- e->comma.exprs->assign.r->unary.op = TBAND;
- e->comma.exprs->assign.r->unary.base = l;
+ e->comma.exprs->assign.r = mkunaryexpr(TBAND, l);
res = &e->comma.exprs->next;
- l = mkexpr(EXPRUNARY, l->type, 0);
- l->unary.op = TMUL;
- l->unary.base = tmp;
+ l = mkunaryexpr(TMUL, tmp);
r = mkbinaryexpr(&tok.loc, op, l, r);
}
r = exprconvert(r, l->type);