File:  [Research Unix] / researchv10no / cmd / lcc / c / enode.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 17:21:35 2018 UTC (8 years, 1 month ago) by root
Branches: belllabs, MAIN
CVS tags: researchv10, HEAD
researchv10 Norman

/* C compiler: type-checking and tree construction for expressions */

#include "c.h"

dclproto(static Tree addnode,(int, Tree, Tree));
dclproto(static Tree andnode,(int, Tree, Tree));
dclproto(static Type binary,(Type, Type));
dclproto(static Tree cmpnode,(int, Tree, Tree));
dclproto(static int compatible,(Type, Type));
dclproto(static Tree mulnode,(int, Tree, Tree));
dclproto(static Tree subnode,(int, Tree, Tree));

dclproto(Tree (*opnode[]),(int, Tree, Tree)) = {
#define xx(a,b,c,d,e,f,g) e,
#include "token.h"
};

/* addnode - construct tree for l + r */
static Tree addnode(op, l, r) Tree l, r; {
	int n;
	Type ty = inttype;

	if (isarith(l->type) && isarith(r->type)) {
		ty = binary(l->type, r->type);
		l = cast(l, ty);
		r = cast(r, ty);
	} else if (isptr(l->type) && isint(r->type))
		return addnode(ADD, r, l);
	else if (isptr(r->type) && isint(l->type)) {
		ty = unqual(r->type);
		if ((n = ty->type->size) == 0)
			error("unknown size of type `%t'\n", ty->type);
		l = cast(l, promote(l->type));
		if (n > 1)
			l = mulnode(MUL, constnode(n, inttype), l);
		return simplify(ADD+P, ty, l, r);
	} else
		typeerror(op, l, r);
	return simplify(op, ty, l, r);
}

/* andnode - construct tree for l [&& ||] r */
static Tree andnode(op, l, r) Tree l, r; {
	if (!isscalar(l->type) || !isscalar(r->type))
		typeerror(op, l, r);
	return simplify(op, inttype, cond(l), cond(r));
}

/* asgnnode - construct tree for l = r */
Tree asgnnode(op, l, r) Tree l, r; {
	Type aty, ty;

	r = pointer(r);
	if ((ty = assign(l->type, r)) == 0) {
		typeerror(ASGN, l, r);
		if (r->type == voidtype)
			r = retype(r, inttype);
		ty = r->type;
	}
	if (l->op != FIELD)
		l = lvalue(l);
	aty = l->type;
	if (isptr(aty))
		aty = unqual(aty)->type;
	if (isconst(aty) || (isstruct(aty) && unqual(aty)->u.sym->u.s.cfields))
		if (isaddrop(l->op) && !l->u.sym->computed && !l->u.sym->generated)
			error("assignment to const identifier `%s'\n", l->u.sym->name);
		else
			error("assignment to const location\n");
	r = cast(r, ty);
	if (l->op == FIELD && fieldsize(l->u.field) < 8*l->u.field->type->size)
		if (isunsigned(l->u.field->type))
			r = bitnode(BAND, r,
				constnode(fieldmask(l->u.field), unsignedtype));
		else {
			int n = 8*l->u.field->type->size - fieldsize(l->u.field);
			/*
			 * The value of assignment is the value of the left
			 * operand (sec. 3.3.16), which for bit fields is the
			 * same as extracting the field. When r is a constant,
			 * the explicit left shift below avoids overflow that
			 * would occur if shnode(LSH, ...) were used. The
			 * subsequent shnode(RSH, ...) will be signed and thus
			 * extend the sign bit correctly.
			 */
			if (r->op == CNST+I)
				r = constnode(r->u.v.i<<n, inttype);
			else
				r = shnode(LSH, r, constnode(n, inttype));
			r = shnode(RSH, r, constnode(n, inttype));
		}
	if (isstruct(ty)) {
		if (r->op == RIGHT && r->kids[0] && r->kids[0]->op == CALL+B
		&& isaddrop(l->op)) {
			/*
			 * When x=f() where f returns a struct and x is a simple
			 * address, release the temporary generated to hold f's
			 * return value and use x in its place. The RIGHT tree
			 * assigned to r below returns x's address, and
			 * rvalue(r) hangs that tree under an INDIR+B,
			 * thus identifying the result as an lvalue.
			 */
			r = r->kids[0];	/* CALL+B node */
			release(r->kids[1]->u.sym);
			r = tree(RIGHT, l->type,
				tree(CALL+B, r->kids[0]->type, r->kids[0], l),
				retype(isarray(l->u.sym->type) ? idnode(l->u.sym) : addrof(idnode(l->u.sym)), l->type));
			return rvalue(r);
		}
		return tree(ASGN+B, ty, l, r);
	}
	return tree(op + (isunsigned(ty) ? I : ttob(ty)), ty, l, r);
}

/* binary - usual arithmetic conversions, return target type */
static Type binary(xty, yty) Type xty, yty; {
	if (isdouble(xty) || isdouble(yty))
		return doubletype;
	if (xty == floattype || yty == floattype)
		return floattype;
	if (isunsigned(xty) || isunsigned(yty))
		return unsignedtype;
	return inttype;
}

/* bitnode - construct tree for l [& | ^ %] r */
Tree bitnode(op, l, r) Tree l, r; {
	Type ty = inttype;

	if (isint(l->type) && isint(r->type)) {
 		ty = binary(l->type, r->type);
		l = cast(l, ty);
		r = cast(r, ty);
		if (op != MOD) {
			l = cast(l, unsignedtype);
			r = cast(r, unsignedtype);
		}
	} else
		typeerror(op, l, r);
	if (op == MOD)
		return simplify(op, ty, l, r);
	return cast(simplify(op, unsignedtype, l, r), ty);
}

/* callnode - construct call node to f, return type ty, arguments args */
Tree callnode(f, ty, args) Tree f, args; Type ty; {
	Tree p;

	if (args)
		f = tree(RIGHT, f->type, args, f);
	if (isstruct(ty)) {
		Symbol t1 = temporary(AUTO, unqual(ty));
		if (ty->size == 0)
			error("illegal use of incomplete type `%t'\n", ty);
		p = tree(RIGHT, ty, tree(CALL+B, ty, f, lvalue(idnode(t1))),
			idnode(t1));
	} else {
		Type rty = ty;
		if (isenum(ty))
			rty = unqual(ty)->type;
		else if (isptr(ty))
			rty = unsignedtype;
		p = tree(CALL + widen(rty), rty, f, 0);
		if (isptr(ty))
			p = cast(p, ty);
	}
	return p;
}

/* cmpnode - construct tree for l [< <= >= >] r */
static Tree cmpnode(op, l, r) Tree l, r; {
	Type ty = unsignedtype;

	if (isarith(l->type) && isarith(r->type)) {
		ty = binary(l->type, r->type);
		l = cast(l, ty);
		r = cast(r, ty);
	} else if (compatible(l->type, r->type)) {
		l = cast(l, ty);
		r = cast(r, ty);
	} else
		typeerror(op, l, r);
	return simplify(op + ttob(ty), inttype, l, r);
}

/* compatible - are ty1 & ty2 sans qualifiers pointers to compatible object or incomplete types? */
static int compatible(ty1, ty2) Type ty1, ty2; {
	if (isptr(ty1) && !isfunc(ty1->type) && isptr(ty2) && !isfunc(ty2->type)) {
		do {
			ty1 = unqual(ty1->type);
			ty2 = unqual(ty2->type);
		} while (isptr(ty1) && isptr(ty2));
		return eqtype(ty1, ty2, 0);
	}
	return 0;
}

/* condnode - build a tree for e ? l : r */
Tree condnode(e, l, r) Tree e, l, r; {
	Symbol t1 = 0;
	Type ty = 0, lty = l->type, rty = r->type;
	Tree p;
	
	if (isarith(lty) && isarith(rty)) {
		ty = binary(lty, rty);
		l = cast(l, ty);
		r = cast(r, ty);
	} else if (eqtype(lty, rty, 1)
	|| isptr(lty) && isint(rty) && assign(lty, r))
		ty = unqual(lty);
	else if (isptr(rty) && isint(lty) && assign(rty, l))
		ty = unqual(rty);
	else if (isptr(lty) && isptr(rty)) {
		lty = lty->type;
		rty = rty->type;
		if (unqual(lty) == voidtype || unqual(rty) == voidtype)
			ty = voidtype;
		else if (eqtype(unqual(lty), unqual(rty), 1))
			ty = unqual(lty);
		if (ty) {
			if (isconst(lty) || isconst(rty))
				ty = qual(CONST, ty);
			if (isvolatile(lty) || isvolatile(rty))
				ty = qual(VOLATILE, ty);
			ty = ptr(ty);
		}
	}
	if (ty == 0) {
		typeerror(COND, l, r);
		ty = inttype;
	} else if (e->op == CNST+D || e->op == CNST+F) {
		e = cast(e, doubletype);
		return retype(e->u.v.d != 0.0 ? l : r, ty);
	} else if (generic(e->op) == CNST) {
		e = cast(e, unsignedtype);
		return retype(e->u.v.u ? l : r, ty);
	} else if (ty != voidtype && ty->size > 0) {
		Opcode op = generic(e->op);
		t1 = temporary(REGISTER, ty);
		l = root(asgn(t1, l));
		if (op != AND && op != OR && op != NOT && op != EQ && op != NE
		&&  op !=  LE && op != LT && op !=  GE && op != GT && op != RIGHT
		&& r->op == CNST+I && r->u.v.i == 0
		&& assign(e->type, r)) {
			/* e1?e2:0 => ((t1=e1,t1)?(t1=e2): ) */
			e = tree(RIGHT, ty, asgn(t1, cast(e, ty)), idnode(t1));
			r = 0;
		} else
			r = root(asgn(t1, r));
	}
	p = tree(COND, ty, cond(e), tree(RIGHT, ty, l, r));
	p->u.sym = t1;
	return p;
}

/* constnode - return a tree for a constant n of type ty (int or unsigned) */
Tree constnode(n, ty) unsigned n; Type ty; {
	Tree p;

	if (isarray(ty))
		p = tree(CNST+P, atop(ty), 0, 0);
	else
		p = tree(CNST + ttob(ty), ty, 0, 0);
	p->u.v.u = n;
	return p;
}

/* eqnode - construct tree for l [== !=] r */
Tree eqnode(op, l, r) Tree l, r; {
	if (isint(l->type) && isptr(r->type))
		return eqnode(op, r, l);
	if (isptr(l->type) && isint(r->type)) {
		l = cast(l, unsignedtype);
		r = cast(r, unsignedtype);
		if (r->op != CNST+U || r->u.v.u)
			error("operands of %s have incompatible types\n",
				op == EQ ? "==" : "!=");
		return simplify(op + U, inttype, l, r);
	}
	if (isptr(l->type) && isptr(r->type) && eqtype(unqual(l->type), unqual(r->type), 1)
	||  isptr(l->type) && !isfunc(l->type->type)
	&& (isptr(r->type) &&  unqual(r->type->type) == voidtype)
	||  isptr(r->type) && !isfunc(r->type->type)
	&& (isptr(l->type) &&  unqual(l->type->type) == voidtype)) {
		l = cast(l, unsignedtype);
		r = cast(r, unsignedtype);
		return simplify(op + U, inttype, l, r);
	}
	return cmpnode(op, l, r);
}

/* mulnode - construct tree for l [* /] r */
static Tree mulnode(op, l, r) Tree l, r; {
	Type ty = inttype;

	if (isarith(l->type) && isarith(r->type)) {
		ty = binary(l->type, r->type);
		l = cast(l, ty);
		r = cast(r, ty);
	} else
		typeerror(op, l, r);
	return simplify(op, ty, l, r);
}

/* shnode - construct tree for l [>> <<] r */
Tree shnode(op, l, r) Tree l, r; {
	Type ty = inttype;

	if (isint(l->type) && isint(r->type)) {
		ty = promote(l->type);
		l = cast(l, ty);
		r = cast(r, inttype);
	} else
		typeerror(op, l, r);
	return simplify(op, ty, l, r);
}

/* subnode - construct tree for l - r */
static Tree subnode(op, l, r) Tree l, r; {
	int n;
	Type ty = inttype;

	if (isarith(l->type) && isarith(r->type)) {
		ty = binary(l->type, r->type);
		l = cast(l, ty);
		r = cast(r, ty);
	} else if (isptr(l->type) && !isfunc(l->type->type) && isint(r->type)) {
		ty = unqual(l->type);
		if ((n = ty->type->size) == 0)
			error("unknown size of type `%t'\n", ty->type);
		r = cast(r, promote(r->type));
		if (n > 1)
			r = mulnode(MUL, constnode(n, inttype), r);
		return simplify(SUB+P, ty, l, r);
	} else if (compatible(l->type, r->type)) {
		if ((n = deref(l->type)->size) == 0)
			error("unknown size of type `%t'\n", deref(l->type));
		l = simplify(SUB+U, unsignedtype, cast(l, unsignedtype),
			cast(r, unsignedtype));
		return simplify(DIV+I, inttype, cast(l, inttype), constnode(n, inttype));
	} else
		typeerror(op, l, r);
	return simplify(op, ty, l, r);
}

/* typeerror - issue "operands of op have illegal types `l' and `r'" */
void typeerror(op, l, r) Tree l, r; {
	int i;
	static struct { Opcode op; char *name; } ops[] = {
		ASGN, "=",	INDIR, "*",	NEG,  "-",
		ADD,  "+",	SUB,   "-",	LSH,  "<<",
		MOD,  "%",	RSH,   ">>",	BAND, "&",
		BCOM, "~",	BOR,   "|",	BXOR, "^",
		DIV,  "/",	MUL,   "*",	EQ,   "==",
		GE,   ">=",	GT,    ">",	LE,   "<=",
		LT,   "<",	NE,    "!=",	AND,  "&&",
		NOT,  "!",	OR,    "||",	COND, "?:",
		0, 0
	};

	op = generic(op);
	for (i = 0; ops[i].op; i++)
		if (op == ops[i].op)
			break;
	assert(ops[i].name);
	if (r)
		error("operands of %s have illegal types `%t' and `%t'\n",
			ops[i].name, l->type, r->type);
	else
		error("operand of unary %s has illegal type `%t'\n", ops[i].name,
			l->type);
}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.