h38126
s 00438/00000/00000
d D 1.1 82/08/02 15:22:14 cecily 1 0
e
u
U
t
T
I 1
#
/*
 * C compiler
 *
 *
 */

#include "c0.h"

/*
 * Reduce the degree-of-reference by one.
 * e.g. turn "ptr-to-int" into "int".
 */
decref(at)
{
	register t;

	t = at;
	if ((t & ~TYPE) == 0) {
		error("Illegal indirection");
		return(t);
	}
	return((t>>TYLEN) & ~TYPE | t&TYPE);
}

/*
 * Increase the degree of reference by
 * one; e.g. turn "int" to "ptr-to-int".
 */
incref(t)
{
	return(((t&~TYPE)<<TYLEN) | (t&TYPE) | PTR);
}

/*
 * Make a tree that causes a branch to lbl
 * if the tree's value is non-zero together with the cond.
 */
cbranch(t, lbl, cond)
struct tnode *t;
{
	treeout(t, 0);
	outcode("BNNN", CBRANCH, lbl, cond, line);
}

/*
 * Write out a tree.
 */
rcexpr(atp)
struct tnode *atp;
{
	register struct tnode *tp;

	/*
	 * Special optimization
	 */
	if ((tp=atp)->op==INIT && tp->tr1->op==CON) {
		if (tp->type==CHAR) {
			outcode("B1N0", BDATA, tp->tr1->value);
			return;
		} else if (tp->type==INT || tp->type==UNSIGN) {
			outcode("BN", SINIT, tp->tr1->value);
			return;
		}
	}
	treeout(tp, 0);
	outcode("BN", EXPR, line);
}

treeout(atp, isstruct)
struct tnode *atp;
{
	register struct tnode *tp;
	register struct hshtab *hp;
	register nextisstruct;

	if ((tp = atp) == 0) {
		outcode("B", NULLOP);
		return;
	}
	nextisstruct = tp->type==STRUCT;
	switch(tp->op) {

	case NAME:
		hp = tp->tr1;
		if (hp->hclass==TYPEDEF)
			error("Illegal use of type name");
		outcode("BNN", NAME, hp->hclass==0?STATIC:hp->hclass, tp->type);
		if (hp->hclass==EXTERN)
			outcode("S", hp->name);
		else
			outcode("N", hp->hoffset);
		break;

	case LCON:
		outcode("BNNN", tp->op, tp->type, tp->lvalue);
		break;

	case CON:
		outcode("BNN", tp->op, tp->type, tp->value);
		break;

	case FCON:
		outcode("BNF", tp->op, tp->type, tp->cstr);
		break;

	case STRING:
		outcode("BNNN", NAME, STATIC, tp->type, tp->tr1);
		break;

	case FSEL:
		treeout(tp->tr1, nextisstruct);
		outcode("BNNN",tp->op,tp->type,tp->tr2->bitoffs,tp->tr2->flen);
		break;

	case ETYPE:
		error("Illegal use of type");
		break;

	case AMPER:
		treeout(tp->tr1, 1);
		outcode("BN", tp->op, tp->type);
		break;


	case CALL:
		treeout(tp->tr1, 1);
		treeout(tp->tr2, 0);
		outcode("BN", CALL, tp->type);
		break;

	default:
		treeout(tp->tr1, nextisstruct);
		if (opdope[tp->op]&BINARY)
			treeout(tp->tr2, nextisstruct);
		outcode("BN", tp->op, tp->type);
		break;
	}
	if (nextisstruct && isstruct==0)
		outcode("BNN", STRASG, STRUCT, tp->strp->ssize);
}

/*
 * Generate a branch
 */
branch(lab)
{
	outcode("BN", BRANCH, lab);
}

/*
 * Generate a label
 */
label(l)
{
	outcode("BN", LABEL, l);
}

/*
 * ap is a tree node whose type
 * is some kind of pointer; return the size of the object
 * to which the pointer points.
 */
plength(ap)
struct tname *ap;
{
	register t, l;
	register struct tnode *p;

	p = ap;
	if (p==0 || ((t=p->type)&~TYPE) == 0)		/* not a reference */
		return(1);
	p->type = decref(t);
	l = length(p);
	p->type = t;
	return(l);
}

/*
 * return the number of bytes in the object
 * whose tree node is acs.
 */
length(acs)
struct tnode *acs;
{
	register t, elsz;
	long n;
	register struct tnode *cs;
	int nd;

	cs = acs;
	t = cs->type;
	n = 1;
	nd = 0;
	while ((t&XTYPE) == ARRAY) {
		t = decref(t);
		n =* cs->subsp[nd++];
	}
	if ((t&~TYPE)==FUNC)
		return(0);
	if (t>=PTR)
		elsz = SZPTR;
	else switch(t&TYPE) {

	case INT:
	case UNSIGN:
		elsz = SZINT;
		break;

	case CHAR:
		elsz = 1;
		break;

	case SHORT:
	case SUNSIGN:
		return(SZSHORT*n);

	case FLOAT:
		elsz = SZFLOAT;
		break;

	case LONG:
		elsz = SZLONG;
		break;

	case DOUBLE:
		elsz = SZDOUB;
		break;

	case STRUCT:
		if ((elsz = cs->strp->ssize) == 0)
			error("Undefined structure");
		break;
	default:
		error("Compiler error (length)");
		return(0);
	}
	n *= elsz;
	if (n >= (unsigned)50000) {
		error("Warning: very large data structure");
		nerror--;
	}
	return(n);
}

/*
 * The number of bytes in an object, rounded up to a word.
 */
rlength(cs)
struct tnode *cs;
{
	return((length(cs)+ALIGN) & ~ALIGN);
}

/*
 * After an "if (...) goto", look to see if the transfer
 * is to a simple label.
 */
simplegoto()
{
	register struct hshtab *csp;

	if ((peeksym=symbol())==NAME && nextchar()==';') {
		csp = csym;
		if (csp->hblklev == 0)
			pushdecl(csp);
		if (csp->hclass==0 && csp->htype==0) {
			csp->htype = ARRAY;
			csp->hflag =| FLABL;
			if (csp->hoffset==0)
				csp->hoffset = isn++;
		}
		if ((csp->hclass==0||csp->hclass==STATIC)
		 &&  csp->htype==ARRAY) {
			peeksym = -1;
			return(csp->hoffset);
		}
	}
	return(0);
}

/*
 * Return the next non-white-space character
 */
nextchar()
{
	while (spnextchar()==' ')
		peekc = 0;
	return(peekc);
}

/*
 * Return the next character, translating all white space
 * to blank and handling line-ends.
 */
spnextchar()
{
	register c;

	if ((c = peekc)==0)
		c = getchar();
	if (c=='\t' || c=='\014')	/* FF */
		c = ' ';
	else if (c=='\n') {
		c = ' ';
		if (inhdr==0)
			line++;
		inhdr = 0;
	} else if (c=='\001') {	/* SOH, insert marker */
		inhdr++;
		c = ' ';
	}
	peekc = c;
	return(c);
}

/*
 * is a break or continue legal?
 */
chconbrk(l)
{
	if (l==0)
		error("Break/continue error");
}

/*
 * The goto statement.
 */
dogoto()
{
	register struct tnode *np;

	*cp++ = tree();
	build(STAR);
	chkw(np = *--cp, -1);
	rcexpr(block(JUMP,0,NULL,NULL,np));
}

/*
 * The return statement, which has to convert
 * the returned object to the function's type.
 */
doret()
{
	register struct tnode *t;

	if (nextchar() != ';') {
		t = tree();
		*cp++ = &funcblk;
		*cp++ = t;
		build(ASSIGN);
		cp[-1] = cp[-1]->tr2;
		if (funcblk.type==CHAR)
			cp[-1] = block(ITOC, INT, NULL, NULL, cp[-1]);
		build(RFORCE);
		rcexpr(*--cp);
	}
	branch(retlab);
}

/*
 * Coded output:
 *   B: beginning of line; an operator
 *   N: a number
 *   S: a symbol (external)
 *   1: number 1
 *   0: number 0
 */
outcode(s, a)
char *s;
{
	extern errno;
	register *ap;
#ifdef unix
	register FILE *bufp;
#else
	register *bufp;
#endif
	int n;
	register char *np;

#ifdef unix
	bufp = stdout;
	if (strflg)
		bufp = sbufp;
#else
	bufp = obuf;
	if (strflg)
		bufp = sbuf;
#endif
	ap = &a;
	errno = 0;
	for (;;) switch(*s++) {
	case 'B':
		putw(*ap++ | (0376<<8), bufp);
		continue;

	case 'N':
		putw(*ap++, bufp);
		continue;

	case 'F':
		n = 1000;
		goto str;

	case 'S':
		n = NCPS;
	str:
		np = *ap++;
		while (n-- && *np) {
			putc(*np++&0177, bufp);
		}
		putc(0, bufp);
		continue;

	case '1':
		putw(1, bufp);
		continue;

	case '0':
		putw(0, bufp);
		continue;

	case '\0':
#ifdef unix
		if (ferror(bufp)) {
#else
		if (errno) {
#endif
			error("Write error on temp");
			exit(1);
		}
		return;

	default:
		error("Botch in outcode");
	}
}
E 1
