aboutsummaryrefslogtreecommitdiffstats
path: root/lcc/src/expr.c
diff options
context:
space:
mode:
Diffstat (limited to 'lcc/src/expr.c')
-rwxr-xr-xlcc/src/expr.c1418
1 files changed, 709 insertions, 709 deletions
diff --git a/lcc/src/expr.c b/lcc/src/expr.c
index 30b79cc..79f8f40 100755
--- a/lcc/src/expr.c
+++ b/lcc/src/expr.c
@@ -1,709 +1,709 @@
-#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, (long 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, (long 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);
-}
+#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, (long 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, (long 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);
+}