diff options
Diffstat (limited to 'src/tools/lcc/src/expr.c')
-rw-r--r-- | src/tools/lcc/src/expr.c | 711 |
1 files changed, 711 insertions, 0 deletions
diff --git a/src/tools/lcc/src/expr.c b/src/tools/lcc/src/expr.c new file mode 100644 index 0000000..b8cb08b --- /dev/null +++ b/src/tools/lcc/src/expr.c @@ -0,0 +1,711 @@ +#include "c.h" + + +static char prec[] = { +#define xx(a,b,c,d,e,f,g) c, +#define yy(a,b,c,d,e,f,g) c, +#include "token.h" +}; +static int oper[] = { +#define xx(a,b,c,d,e,f,g) d, +#define yy(a,b,c,d,e,f,g) d, +#include "token.h" +}; +float refinc = 1.0; +static Tree expr2(void); +static Tree expr3(int); +static Tree nullcheck(Tree); +static Tree postfix(Tree); +static Tree unary(void); +static Tree primary(void); +static Type super(Type ty); + +static Type super(Type ty) { + switch (ty->op) { + case INT: + if (ty->size < inttype->size) + return inttype; + break; + case UNSIGNED: + if (ty->size < unsignedtype->size) + return unsignedtype; + break; + case POINTER: + return unsignedptr; + } + return ty; +} +Tree expr(int tok) { + static char stop[] = { IF, ID, '}', 0 }; + Tree p = expr1(0); + + while (t == ',') { + Tree q; + t = gettok(); + q = pointer(expr1(0)); + p = tree(RIGHT, q->type, root(value(p)), q); + } + if (tok) + test(tok, stop); + return p; +} +Tree expr0(int tok) { + return root(expr(tok)); +} +Tree expr1(int tok) { + static char stop[] = { IF, ID, 0 }; + Tree p = expr2(); + + if (t == '=' + || (prec[t] >= 6 && prec[t] <= 8) + || (prec[t] >= 11 && prec[t] <= 13)) { + int op = t; + t = gettok(); + if (oper[op] == ASGN) + p = asgntree(ASGN, p, value(expr1(0))); + else + { + expect('='); + p = incr(op, p, expr1(0)); + } + } + if (tok) + test(tok, stop); + return p; +} +Tree incr(int op, Tree v, Tree e) { + return asgntree(ASGN, v, (*optree[op])(oper[op], v, e)); +} +static Tree expr2(void) { + Tree p = expr3(4); + + if (t == '?') { + Tree l, r; + Coordinate pts[2]; + if (Aflag > 1 && isfunc(p->type)) + warning("%s used in a conditional expression\n", + funcname(p)); + p = pointer(p); + t = gettok(); + pts[0] = src; + l = pointer(expr(':')); + pts[1] = src; + r = pointer(expr2()); + if (events.points) + { + apply(events.points, &pts[0], &l); + apply(events.points, &pts[1], &r); + } + p = condtree(p, l, r); + } + return p; +} +Tree value(Tree p) { + int op = generic(rightkid(p)->op); + + if (p->type != voidtype + && (op==AND || op==OR || op==NOT || op==EQ || op==NE + || op== LE || op==LT || op== GE || op==GT)) + p = condtree(p, consttree(1, inttype), + consttree(0, inttype)); + return p; +} +static Tree expr3(int k) { + int k1; + Tree p = unary(); + + for (k1 = prec[t]; k1 >= k; k1--) + while (prec[t] == k1 && *cp != '=') { + Tree r; + Coordinate pt; + int op = t; + t = gettok(); + pt = src; + p = pointer(p); + if (op == ANDAND || op == OROR) { + r = pointer(expr3(k1)); + if (events.points) + apply(events.points, &pt, &r); + } else + r = pointer(expr3(k1 + 1)); + p = (*optree[op])(oper[op], p, r); + } + return p; +} +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(); + if (istypename(t, tsym)) { + Type ty, ty1 = typename(), pty; + expect(')'); + ty = unqual(ty1); + if (isenum(ty)) { + Type ty2 = ty->type; + if (isconst(ty1)) + ty2 = qual(CONST, ty2); + if (isvolatile(ty1)) + ty2 = qual(VOLATILE, ty2); + ty1 = ty2; + ty = ty->type; + } + p = pointer(unary()); + pty = p->type; + if (isenum(pty)) + pty = pty->type; + if ((isarith(pty) && isarith(ty)) + || (isptr(pty) && isptr(ty))) { + explicitCast++; + p = cast(p, ty); + explicitCast--; + } else if ((isptr(pty) && isint(ty)) + || (isint(pty) && isptr(ty))) { + if (Aflag >= 1 && ty->size < pty->size) + warning("conversion from `%t' to `%t' is compiler dependent\n", p->type, ty); + + p = cast(p, ty); + } else if (ty != voidtype) { + error("cast from `%t' to `%t' is illegal\n", + p->type, ty1); + ty1 = inttype; + } + if (generic(p->op) == INDIR || ty->size == 0) + p = tree(RIGHT, ty1, NULL, p); + else + p = retype(p, ty1); + } else + p = postfix(expr(')')); + break; + default: + p = postfix(primary()); + } + return p; +} + +static Tree postfix(Tree p) { + for (;;) + switch (t) { + case INCR: p = tree(RIGHT, p->type, + tree(RIGHT, p->type, + p, + incr(t, p, consttree(1, inttype))), + p); + t = gettok(); break; + case DECR: p = tree(RIGHT, p->type, + tree(RIGHT, p->type, + p, + incr(t, p, consttree(1, inttype))), + p); + t = gettok(); break; + case '[': { + Tree q; + t = gettok(); + q = expr(']'); + if (YYnull) { + if (isptr(p->type)) + p = nullcheck(p); + else if (isptr(q->type)) + q = nullcheck(q); + } + p = (*optree['+'])(ADD, pointer(p), pointer(q)); + if (isptr(p->type) && isarray(p->type->type)) + p = retype(p, p->type->type); + else + p = rvalue(p); + } break; + case '(': { + Type ty; + Coordinate pt; + p = pointer(p); + if (isptr(p->type) && isfunc(p->type->type)) + ty = p->type->type; + else { + error("found `%t' expected a function\n", p->type); + ty = func(voidtype, NULL, 1); + p = retype(p, ptr(ty)); + } + pt = src; + 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; + default: + return p; + } +} +static Tree primary(void) { + Tree p; + + assert(t != '('); + switch (t) { + case ICON: + case FCON: p = tree(mkop(CNST,tsym->type), tsym->type, NULL, NULL); + p->u.v = tsym->u.c.v; + break; + case SCON: if (ischar(tsym->type->type)) + tsym->u.c.v.p = stringn(tsym->u.c.v.p, tsym->type->size); + else + tsym->u.c.v.p = memcpy(allocate(tsym->type->size, PERM), tsym->u.c.v.p, tsym->type->size); + tsym = constant(tsym->type, tsym->u.c.v); + if (tsym->u.c.loc == NULL) + tsym->u.c.loc = genident(STATIC, tsym->type, GLOBAL); + p = idtree(tsym->u.c.loc); break; + case ID: if (tsym == NULL) + { + Symbol p = install(token, &identifiers, level, FUNC); + p->src = src; + if (getchr() == '(') { + Symbol q = lookup(token, externals); + p->type = func(inttype, NULL, 1); + p->sclass = EXTERN; + if (Aflag >= 1) + warning("missing prototype\n"); + if (q && !eqtype(q->type, p->type, 1)) + warning("implicit declaration of `%s' does not match previous declaration at %w\n", q->name, &q->src); + + if (q == NULL) { + q = install(p->name, &externals, GLOBAL, PERM); + q->type = p->type; + q->sclass = EXTERN; + q->src = src; + (*IR->defsymbol)(q); + } + p->u.alias = q; + } else { + error("undeclared identifier `%s'\n", p->name); + p->sclass = AUTO; + p->type = inttype; + if (p->scope == GLOBAL) + (*IR->defsymbol)(p); + else + addlocal(p); + } + t = gettok(); + if (xref) + use(p, src); + return idtree(p); + } + if (xref) + use(tsym, src); + if (tsym->sclass == ENUM) + p = consttree(tsym->u.value, inttype); + else { + if (tsym->sclass == TYPEDEF) + error("illegal use of type name `%s'\n", tsym->name); + p = idtree(tsym); + } break; + case FIRSTARG: + if (level > PARAM && cfunc && cfunc->u.f.callee[0]) + p = idtree(cfunc->u.f.callee[0]); + else { + error("illegal use of `%k'\n", FIRSTARG); + p = cnsttree(inttype, 0L); + } + break; + default: + error("illegal expression\n"); + p = cnsttree(inttype, 0L); + } + t = gettok(); + return p; +} +Tree idtree(Symbol p) { + int op; + Tree e; + Type ty = p->type ? unqual(p->type) : voidptype; + + if (p->scope == GLOBAL || p->sclass == STATIC) + op = ADDRG; + else if (p->scope == PARAM) { + op = ADDRF; + if (isstruct(p->type) && !IR->wants_argb) + { + e = tree(mkop(op,voidptype), ptr(ptr(p->type)), NULL, NULL); + e->u.sym = p; + return rvalue(rvalue(e)); + } + } else if (p->sclass == EXTERN) { + assert(p->u.alias); + p = p->u.alias; + op = ADDRG; + } else + op = ADDRL; + p->ref += refinc; + if (isarray(ty)) + e = tree(mkop(op,voidptype), p->type, NULL, NULL); + else if (isfunc(ty)) + e = tree(mkop(op,funcptype), p->type, NULL, NULL); + else + e = tree(mkop(op,voidptype), ptr(p->type), NULL, NULL); + e->u.sym = p; + if (isptr(e->type)) + e = rvalue(e); + return e; +} + +Tree rvalue(Tree p) { + Type ty = deref(p->type); + + ty = unqual(ty); + return tree(mkop(INDIR,ty), ty, p, NULL); +} +Tree lvalue(Tree p) { + if (generic(p->op) != INDIR) { + error("lvalue required\n"); + return value(p); + } else if (unqual(p->type) == voidtype) + warning("`%t' used as an lvalue\n", p->type); + return p->kids[0]; +} +Tree retype(Tree p, Type ty) { + Tree q; + + if (p->type == ty) + return p; + q = tree(p->op, ty, p->kids[0], p->kids[1]); + q->node = p->node; + q->u = p->u; + return q; +} +Tree rightkid(Tree p) { + while (p && p->op == RIGHT) + if (p->kids[1]) + p = p->kids[1]; + else if (p->kids[0]) + p = p->kids[0]; + else + assert(0); + assert(p); + return p; +} +int hascall(Tree p) { + if (p == 0) + return 0; + if (generic(p->op) == CALL || (IR->mulops_calls && + (p->op == DIV+I || p->op == MOD+I || p->op == MUL+I + || p->op == DIV+U || p->op == MOD+U || p->op == MUL+U))) + return 1; + return hascall(p->kids[0]) || hascall(p->kids[1]); +} +Type binary(Type xty, Type yty) { +#define xx(t) if (xty == t || yty == t) return t + xx(longdouble); + xx(doubletype); + xx(floattype); + xx(unsignedlonglong); + xx(longlong); + xx(unsignedlong); + if ((xty == longtype && yty == unsignedtype) + || (xty == unsignedtype && yty == longtype)) { + if (longtype->size > unsignedtype->size) + return longtype; + else + return unsignedlong; + } + xx(longtype); + xx(unsignedtype); + return inttype; +#undef xx +} +Tree pointer(Tree p) { + if (isarray(p->type)) + /* assert(p->op != RIGHT || p->u.sym == NULL), */ + p = retype(p, atop(p->type)); + else if (isfunc(p->type)) + p = retype(p, ptr(p->type)); + return p; +} +Tree cond(Tree p) { + int op = generic(rightkid(p)->op); + + if (op == AND || op == OR || op == NOT + || op == EQ || op == NE + || op == LE || op == LT || op == GE || op == GT) + return p; + p = pointer(p); + return (*optree[NEQ])(NE, p, consttree(0, inttype)); +} +Tree cast(Tree p, Type type) { + Type src, dst; + + p = value(p); + if (p->type == type) + return p; + dst = unqual(type); + src = unqual(p->type); + if (src->op != dst->op || src->size != dst->size) { + switch (src->op) { + case INT: + if (src->size < inttype->size) + p = simplify(CVI, inttype, p, NULL); + break; + case UNSIGNED: + if (src->size < inttype->size) + p = simplify(CVU, inttype, p, NULL); + else if (src->size < unsignedtype->size) + p = simplify(CVU, unsignedtype, p, NULL); + break; + case ENUM: + p = retype(p, inttype); + break; + case POINTER: + if (isint(dst) && src->size > dst->size) + warning("conversion from `%t' to `%t' is undefined\n", p->type, type); + p = simplify(CVP, super(src), p, NULL); + break; + case FLOAT: + break; + default: assert(0); + } + { + src = unqual(p->type); + dst = super(dst); + if (src->op != dst->op) + switch (src->op) { + case INT: + p = simplify(CVI, dst, p, NULL); + break; + case UNSIGNED: + if (isfloat(dst)) { + Type ssrc = signedint(src); + Tree two = cnsttree(longdouble, (double)2.0); + p = (*optree['+'])(ADD, + (*optree['*'])(MUL, + two, + simplify(CVU, ssrc, + simplify(RSH, src, + p, consttree(1, inttype)), NULL)), + simplify(CVU, ssrc, + simplify(BAND, src, + p, consttree(1, unsignedtype)), NULL)); + } else + p = simplify(CVU, dst, p, NULL); + break; + case FLOAT: + if (isunsigned(dst)) { + Type sdst = signedint(dst); + Tree c = cast(cnsttree(longdouble, (double)sdst->u.sym->u.limits.max.i + 1), src); + p = condtree( + simplify(GE, src, p, c), + (*optree['+'])(ADD, + cast(cast(simplify(SUB, src, p, c), sdst), dst), + cast(cnsttree(unsignedlong, (unsigned long)sdst->u.sym->u.limits.max.i + 1), dst)), + simplify(CVF, sdst, p, NULL)); + } else + p = simplify(CVF, dst, p, NULL); + break; + default: assert(0); + } + dst = unqual(type); + } + } + src = unqual(p->type); + switch (src->op) { + case INT: + if (src->op != dst->op || src->size != dst->size) + p = simplify(CVI, dst, p, NULL); + break; + case UNSIGNED: + if (src->op != dst->op || src->size != dst->size) + p = simplify(CVU, dst, p, NULL); + break; + case FLOAT: + if (src->op != dst->op || src->size != dst->size) + p = simplify(CVF, dst, p, NULL); + break; + case POINTER: + if (src->op != dst->op) + p = simplify(CVP, dst, p, NULL); + else { + if ((isfunc(src->type) && !isfunc(dst->type)) + || (!isfunc(src->type) && isfunc(dst->type))) + warning("conversion from `%t' to `%t' is compiler dependent\n", p->type, type); + + if (src->size != dst->size) + p = simplify(CVP, dst, p, NULL); + } + break; + default: assert(0); + } + return retype(p, type); +} +Tree field(Tree p, const char *name) { + Field q; + Type ty1, ty = p->type; + + if (isptr(ty)) + ty = deref(ty); + ty1 = ty; + ty = unqual(ty); + if ((q = fieldref(name, ty)) != NULL) { + if (isarray(q->type)) { + ty = q->type->type; + if (isconst(ty1) && !isconst(ty)) + ty = qual(CONST, ty); + if (isvolatile(ty1) && !isvolatile(ty)) + ty = qual(VOLATILE, ty); + ty = array(ty, q->type->size/ty->size, q->type->align); + } else { + ty = q->type; + if (isconst(ty1) && !isconst(ty)) + ty = qual(CONST, ty); + if (isvolatile(ty1) && !isvolatile(ty)) + ty = qual(VOLATILE, ty); + ty = ptr(ty); + } + if (YYcheck && !isaddrop(p->op) && q->offset > 0) /* omit */ + p = nullcall(ty, YYcheck, p, consttree(q->offset, inttype)); /* omit */ + else /* omit */ + p = simplify(ADD+P, ty, p, consttree(q->offset, inttype)); + + if (q->lsb) { + p = tree(FIELD, ty->type, rvalue(p), NULL); + p->u.field = q; + } else if (!isarray(q->type)) + p = rvalue(p); + + } else { + error("unknown field `%s' of `%t'\n", name, ty); + p = rvalue(retype(p, ptr(inttype))); + } + return p; +} +/* funcname - return name of function f or a function' */ +char *funcname(Tree f) { + if (isaddrop(f->op)) + return stringf("`%s'", f->u.sym->name); + return "a function"; +} +static Tree nullcheck(Tree p) { + if (!needconst && YYnull && isptr(p->type)) { + p = value(p); + if (strcmp(YYnull->name, "_YYnull") == 0) { + Symbol t1 = temporary(REGISTER, voidptype); + p = tree(RIGHT, p->type, + tree(OR, voidtype, + cond(asgn(t1, cast(p, voidptype))), + vcall(YYnull, voidtype, (file && *file ? pointer(idtree(mkstr(file)->u.c.loc)) : cnsttree(voidptype, NULL)), cnsttree(inttype, (long)lineno) , NULL)), + idtree(t1)); + } + + else + p = nullcall(p->type, YYnull, p, cnsttree(inttype, 0L)); + + } + return p; +} +Tree nullcall(Type pty, Symbol f, Tree p, Tree e) { + Type ty; + + if (isarray(pty)) + return retype(nullcall(atop(pty), f, p, e), pty); + ty = unqual(unqual(p->type)->type); + return vcall(f, pty, + p, e, + cnsttree(inttype, (long)ty->size), + cnsttree(inttype, (long)ty->align), + (file && *file ? pointer(idtree(mkstr(file)->u.c.loc)) : cnsttree(voidptype, NULL)), cnsttree(inttype, (long)lineno) , NULL); +} |