Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
254 changes: 152 additions & 102 deletions lcc/src/expr.c
Original file line number Diff line number Diff line change
Expand Up @@ -136,81 +136,123 @@ static Tree unary(void) {
Tree p;

switch (t) {
case '*': t = gettok(); p = unary(); p = pointer(p);
if (isptr(p->type)
&& (isfunc(p->type->type) || isarray(p->type->type)))
p = retype(p, p->type->type);
else {
if (YYnull)
p = nullcheck(p);
p = rvalue(p);
} break;
case '&': t = gettok(); p = unary(); if (isarray(p->type) || isfunc(p->type))
p = retype(p, ptr(p->type));
else
p = lvalue(p);
if (isaddrop(p->op) && p->u.sym->sclass == REGISTER)
error("invalid operand of unary &; `%s' is declared register\n", p->u.sym->name);

else if (isaddrop(p->op))
p->u.sym->addressed = 1;
break;
case '+': t = gettok(); p = unary(); p = pointer(p);
if (isarith(p->type))
p = cast(p, promote(p->type));
else
typeerror(ADD, p, NULL); break;
case '-': t = gettok(); p = unary(); p = pointer(p);
if (isarith(p->type)) {
Type ty = promote(p->type);
p = cast(p, ty);
if (isunsigned(ty)) {
warning("unsigned operand of unary -\n");
p = simplify(ADD, ty, simplify(BCOM, ty, p, NULL), cnsttree(ty, 1UL));
} else
p = simplify(NEG, ty, p, NULL);
} else
typeerror(SUB, p, NULL); break;
case '~': t = gettok(); p = unary(); p = pointer(p);
if (isint(p->type)) {
Type ty = promote(p->type);
p = simplify(BCOM, ty, cast(p, ty), NULL);
} else
typeerror(BCOM, p, NULL); break;
case '!': t = gettok(); p = unary(); p = pointer(p);
if (isscalar(p->type))
p = simplify(NOT, inttype, cond(p), NULL);
else
typeerror(NOT, p, NULL); break;
case INCR: t = gettok(); p = unary(); p = incr(INCR, pointer(p), consttree(1, inttype)); break;
case DECR: t = gettok(); p = unary(); p = incr(DECR, pointer(p), consttree(1, inttype)); break;
case TYPECODE: case SIZEOF: { int op = t;
Type ty;
p = NULL;
t = gettok();
if (t == '(') {
t = gettok();
if (istypename(t, tsym)) {
ty = typename();
expect(')');
} else {
p = postfix(expr(')'));
ty = p->type;
}
} else {
p = unary();
ty = p->type;
}
assert(ty);
if (op == TYPECODE)
p = cnsttree(inttype, (long)ty->op);
else {
if (isfunc(ty) || ty->size == 0)
error("invalid type argument `%t' to `sizeof'\n", ty);
else if (p && rightkid(p)->op == FIELD)
error("`sizeof' applied to a bit field\n");
p = cnsttree(unsignedlong, (unsigned long)ty->size);
} } break;
case '*':
t = gettok();
p = unary();
p = pointer(p);
if (isptr(p->type)
&& (isfunc(p->type->type) || isarray(p->type->type))) {
p = retype(p, p->type->type);
} else {
if (YYnull) {
p = nullcheck(p);
}
p = rvalue(p);
}
break;
case '&':
t = gettok();
p = unary();
if (isarray(p->type) || isfunc(p->type)) {
p = retype(p, ptr(p->type));
} else {
p = lvalue(p);
}
if (isaddrop(p->op) && p->u.sym->sclass == REGISTER) {
error("invalid operand of unary &; `%s' is declared register\n", p->u.sym->name);
} else if (isaddrop(p->op)) {
p->u.sym->addressed = 1;
}
break;
case '+':
t = gettok();
p = unary();
p = pointer(p);
if (isarith(p->type)) {
p = cast(p, promote(p->type));
} else {
typeerror(ADD, p, NULL);
}
break;
case '-':
t = gettok();
p = unary();
p = pointer(p);
if (isarith(p->type)) {
Type ty = promote(p->type);
p = cast(p, ty);
if (isunsigned(ty)) {
warning("unsigned operand of unary -\n");
p = simplify(ADD, ty, simplify(BCOM, ty, p, NULL), cnsttree(ty, 1UL));
} else {
p = simplify(NEG, ty, p, NULL);
}
} else {
typeerror(SUB, p, NULL);
}
break;
case '~':
t = gettok();
p = unary();
p = pointer(p);
if (isint(p->type)) {
Type ty = promote(p->type);
p = simplify(BCOM, ty, cast(p, ty), NULL);
} else {
typeerror(BCOM, p, NULL);
}
break;
case '!':
t = gettok();
p = unary();
p = pointer(p);
if (isscalar(p->type)) {
p = simplify(NOT, inttype, cond(p), NULL);
} else {
typeerror(NOT, p, NULL);
}
break;
case INCR:
t = gettok();
p = unary();
p = incr(INCR, pointer(p), consttree(1, inttype));
break;
case DECR:
t = gettok();
p = unary();
p = incr(DECR, pointer(p), consttree(1, inttype));
break;
case TYPECODE:
case SIZEOF: {
int op = t;
Type ty;
p = NULL;
t = gettok();
if (t == '(') {
t = gettok();
if (istypename(t, tsym)) {
ty = typename();
expect(')');
} else {
p = postfix(expr(')'));
ty = p->type;
}
} else {
p = unary();
ty = p->type;
}
assert(ty);
if (op == TYPECODE) {
p = cnsttree(inttype, (long)ty->op);
} else {
if (isfunc(ty) || ty->size == 0) {
error("invalid type argument `%t' to `sizeof'\n", ty);
} else if (p && rightkid(p)->op == FIELD)
error("`sizeof' applied to a bit field\n");
p = cnsttree(unsignedlong, (unsigned long)ty->size);

}
} break;
case '(':
t = gettok();
if (istypename(t, tsym)) {
Expand Down Expand Up @@ -305,33 +347,41 @@ static Tree postfix(Tree p) {
t = gettok();
p = call(p, ty, pt);
} break;
case '.': t = gettok();
if (t == ID) {
if (isstruct(p->type)) {
Tree q = addrof(p);
p = field(q, token);
q = rightkid(q);
if (isaddrop(q->op) && q->u.sym->temporary)
p = tree(RIGHT, p->type, p, NULL);
} else
error("left operand of . has incompatible type `%t'\n",
p->type);
t = gettok();
} else
error("field name expected\n"); break;
case DEREF: t = gettok();
p = pointer(p);
if (t == ID) {
if (isptr(p->type) && isstruct(p->type->type)) {
if (YYnull)
p = nullcheck(p);
p = field(p, token);
} else
error("left operand of -> has incompatible type `%t'\n", p->type);

t = gettok();
} else
error("field name expected\n"); break;
case '.':
t = gettok();
if (t == ID) {
if (isstruct(p->type)) {
Tree q = addrof(p);
p = field(q, token);
q = rightkid(q);
if (isaddrop(q->op) && q->u.sym->temporary) {
p = tree(RIGHT, p->type, p, NULL);
}
} else {
error("left operand of . has incompatible type `%t'\n", p->type);
}
t = gettok();
} else {
error("field name expected\n");
}
break;
case DEREF:
t = gettok();
p = pointer(p);
if (t == ID) {
if (isptr(p->type) && isstruct(p->type->type)) {
if (YYnull) {
p = nullcheck(p);
}
p = field(p, token);
} else {
error("left operand of -> has incompatible type `%t'\n", p->type);
}
t = gettok();
} else {
error("field name expected\n");
}
break;
default:
return p;
}
Expand Down