Skip to content
Permalink
master
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
executable file 711 lines (683 sloc) 18 KB
#include "c.h"
static char rcsid[] = "$Id$";
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 (generic(p->op) != CNST && 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/widechar->size)*sizeof (int), PERM),
tsym->u.c.v.p, (tsym->type->size/widechar->size)*sizeof (int));
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, PERM);
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, signedptr));
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);
}