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

#include "c1.h"

max(a, b)
{
	if (a>b)
		return(a);
	return(b);
}

degree(at)
struct tnode *at;
{
	register struct tnode *t, *t1;

	if ((t=at)==0 || t->op==0)
		return(0);
	if (t->op == CON)
		return(-3);
	if (t->op == AMPER)
		return(-2);
	if (t->op==ITOL) {
		if ((t1 = isconstant(t)) && t1->value>=0)
			return(-2);
		if ((t1=t->tr1)->type==UNSIGN && opdope[t1->op]&LEAF)
			return(-1);
	}
	if ((opdope[t->op] & LEAF) != 0) {
		if (t->type==CHAR || t->type==FLOAT || t->type==SUNSIGN)
			return(1);
		return(0);
	}
	return(t->degree);
}

pname(ap, flag)
struct tnode *ap;
{
	register i;
	register struct tnode *p;
	struct { int intx[2]; };

	p = ap;
loop:
	switch(p->op) {

/***
	case LCON:
		printf("$%o", flag>10? p->lvalue.intx[1]:p->lvalue.intx[0]);
		return;
***/

	case SFCON:
	case CON:
		psoct(p->value);
		return;

	case FCON:
		printf("L%d", (p->value>0? p->value: -p->value));
		return;

	case NAME:
		i = p->offset;
		if (flag>10)
			i =+ NCPW;
		if (p->class==OFFS && p->regno==14) {
			if (i<0)
				printf("L.%d%d(14)", fautolen, i);
			else
				printf("L.%d+%d(14)", fautolen, i);
			return;
		}
		if (i) {
			printf("%d", i);
			if (p->class!=OFFS)
				putchar('+');
			if (p->class==REG)
				regerr();
		}
		else
			if (p->class==OFFS)
				putchar('0');
		switch(p->class) {

		case SOFFS:
		case XOFFS:
			pbase(p);

		case OFFS:
			printf("(%d)", p->regno);
			return;

		case EXTERN:
		case STATIC:
			pbase(p);
			return;

		case REG:
			printf("%d", p->nloc);
			return;

		}
		error("Compiler error: pname");
		return;

	case AMPER:
/***
		putchar('$');
***/
		p = p->tr1;
		if (p->op==NAME && p->class==REG)
			regerr();
		goto loop;

/***
	case AUTOI:
		printf("(r%d)%c", p->nloc, flag==1?0:'+');
		return;

	case AUTOD:
		printf("%c(r%d)", flag==2?0:'-', p->nloc);
		return;

	case STAR:
		p = p->tr1;
		putchar('*');
		goto loop;
***/

	}
	error("pname called illegally");
}

regerr()
{
	error("Illegal use of register");
}

pbase(ap)
struct tnode *ap;
{
	register struct tnode *p;

	p = ap;
	if (p->class==SOFFS || p->class==STATIC)
		printf("L%d", p->nloc);
	else
		printf("%.8s", &(p->nloc));
}

xdcalc(ap, nrleft)
struct tnode *ap;
{
	register struct tnode *p;
	register d;

	p = ap;
	d = dcalc(p, nrleft);
	if (d<20 && p->type==CHAR) {
		if (nrleft>=1)
			d = 20;
		else
			d = 24;
	}
	return(d);
}

dcalc(ap, nrleft)
struct tnode *ap;
{
	register struct tnode *p, *p1;

	if ((p=ap)==0)
		return(0);
	switch (p->op) {

	case NAME:
		if (p->class==REG)
			return(9);

	case AMPER:
	case FCON:
	case LCON:
	case AUTOI:
	case AUTOD:
		return(12);

	case CON:
	case SFCON:
		if (p->value==0)
			return(4);
		if (p->value==1)
			return(5);
		return(8);

/***
	case STAR:
		p1 = p->tr1;
		if (p1->op==NAME||p1->op==CON||p1->op==AUTOI||p1->op==AUTOD)
			if (p->type!=LONG)
				return(12);
***/
	}
	if (p->type==LONG)
		nrleft--;
	return(p->degree <= nrleft? 20: 24);
}

notcompat(ap, ast, op)
struct tnode *ap;
{
	register at, st;
	register struct tnode *p;

	p = ap;
	at = p->type;
	st = ast;
	if (st==0)		/* word, byte */
		return(at!=CHAR && at!=INT && at!=UNSIGN && at!=SHORT
		    && at!= SUNSIGN && at<PTR);
	if (st==1)		/* word */
		return(at!=INT && at!=UNSIGN && at!=SHORT && at<PTR);
	st =- 2;
	/*** Make 'ptr to ptr' look like 'ptr to int' ***/
	if ((at&(~(TYPE+XTYPE))) != 0)
		at = 020;
	if ((at&(~TYPE)) != 0)
		at = at&TYPE | 020;
#ifndef DOUBLEPRECISION
	if (st==DOUBLE)
		st = FLOAT;
#endif
	if (st==FLOAT && at==DOUBLE)
		at = FLOAT;
	if (p->op==NAME && p->class==REG && op==ASSIGN && st==CHAR)
		return(0);
	return(st != at);
}

prins(op, c, itable)
struct instab *itable;
{
	register struct instab *insp;
	register char *ip;

	for (insp=itable; insp->op != 0; insp++) {
		if (insp->op == op) {
			ip = c? insp->str2: insp->str1;
			if (ip==0)
				break;
			printf("%s", ip);
			return;
		}
	}
	error("No match' for op %d", op);
}

collcon(ap)
struct tnode *ap;
{
	register op;
	register struct tnode *p;

	p = ap;
/***
	if (p->op==STAR) {
		if (p->type==LONG+PTR) /* avoid *x(r); *x+2(r) */
/***
			return(0);
		p = p->tr1;
	}
***/
	if (p->op==PLUS) {
		op = p->tr2->op;
		if (op==CON || (op==AMPER
		    && p->tr2->tr1->class!=OFFS))
			return(1);
	}
	return(0);
}

isfloat(at)
struct tnode *at;
{
	register struct tnode *t;

	t = at;
	if ((opdope[t->op]&RELAT)!=0)
		t = t->tr1;
	if (t->type==FLOAT) {
		nfloat = 1;
		return('e');
	}
	if (t->type==DOUBLE) {
		nfloat = 1;
#ifdef DOUBLEPRECISION
		return('d');
#else
		return('e');
#endif
	}
	return(0);
}

ishfloat(t)			
struct tnode *t;		
{				
	register c;

	if (c = isfloat(t))
		return(c);
#ifdef HALFW
	return('h');
#endif
#ifndef HALFW
	return(0);
#endif
}				

oddreg(t, areg)
struct tnode *t;
{
	register reg;

	reg = areg;
	if (!isfloat(t))
		switch(t->op) {
		case LLSHIFT:
		case ASLSHL:
			return((reg+1)&~01);

		case DIVIDE:
		case MOD:
		case ASDIV:
		case ASMOD:
		case PTOI:
		case ULSH:
		case ASULSH:
		case TIMES:
		case ASTIMES:
			reg++;

/***
		case TIMES:
		case ASTIMES:
***/
			return(reg|1);
		}
	return(reg);
}

/***
 *** Length of an object of type t as an argument
 ***/
arlength(t)
{
	if (t>=PTR)
		return(NCPW);
	switch(t) {

	case INT:
	case CHAR:
	case UNSIGN:
	case SHORT:
	case SUNSIGN:
		return(NCPW);


	case LONG:
		return(2*NCPW);

	case FLOAT:
	case DOUBLE:
#ifdef DOUBLEPRECISION
		return(8);
# else
		return(4);
# endif

	}
	return(1024);
}

/*
 * Strings for switch code.
 */

/***
char	dirsw[] {"\
cmp	r0,$%o\n\
jhi	L%d\n\
asl	r0\n\
jmp	*L%d(r0)\n\
.data\n\
L%d:\
" };

char	simpsw[] {"\
mov	$L%d,r1\n\
mov	r0,L%d\n\
L%d:cmp	r0,(r1)+\n\
jne	L%d\n\
jmp	*L%d-L%d(r1)\n\
.data\n\
L%d:\
"};

char	hashsw[] {"\
mov	r0,r1\n\
clr	r0\n\
div	$%o,r0\n\
asl	r1\n\
add	$L%d,r1\n\
mov	r0,*(r1)+\n\
mov	(r1)+,r1\n\
L%d:cmp	r0,-(r1)\n\
jne	L%d\n\
jmp	*L%d-L%d(r1)\n\
.data\n\
L%d:\
"};
***/

char dirsw[] {"\n\
	bp	L%d\n\
	ldar	1,0\n\
	bm	L%d\n\
	slal	1,ladc\n\
	lda	1,L%d(1)\n\
	br	1\n\
" };

char simpsw[] {"\
	ldai	1,L%d-adc\n\
	sta	0,L%d-adc\n\
L%d	ais	1,adc\n\
	cla	0,0(1)\n\
	bne	L%d\n\
	lda	1,L%d-L%d(1)\n\
	br	1\n\
" };

	/*** this assumes no more than 65534 case labels (worst case) ***/
char	hashsw[] = {"\
	ldar	1,0\n\
	li	0,0\n\
	lhi	15,%d\n\
	dar	0,15\n\
	ldar	2,0\n\
	slls	2,ladc\n\
	lda	3,L%d(2)\n\
	sta	1,0(3)\n\
	lda	3,L%d+adc(2)\n\
L%d	sis	3,adc\n\
	cla	1,0(3)\n\
	bnes	L%d\n\
	lda	1,L%d-L%d(3)\n\
	br	1\n\
"};

pswitch(afp, alp, deflab)
struct swtab *afp, *alp;
{
	register struct swtab *swp, *fp, *lp;
	register i, j, ncase, tabs, worst, best, range;	
	int *poctab;

	fp = afp;
	lp = alp;
	if (fp==lp) {
		printf("	b	L%d\n", deflab);
		return;
	}
	isn++;
	if (fp == lp-1) {
		printf("	clai	0,");
		psoct(fp->swval);
		printf("\n	be	L%d\n	b	L%d\n", fp->swlab,
				deflab);
		return;
	}
	if (sort(fp, lp))
		return;
	ncase = lp-fp;
	lp--;
	range = lp->swval - fp->swval;
	/* direct switch */
	/*** attempt to make a direct switch by making case values smaller ***/

	i = 0;
	if (fp->swval >= 0) {			/* for now, not if any < 0 */
		for (j = 1; i < 8*NCPW; i++) {
			for (swp = fp; swp <= lp; swp++)
				if (swp->swval & j)
					break;
			if (swp <= lp)
				break;
			j = (j << 1) | 1;
		}
	}

	if ((j = range >> i) > 0 && j <= 3*ncase) {
		range = j;
		if (i != 0) {
			for (swp = fp; swp <= lp; swp++)
				swp->swval >>= i;
			printf("	tai	0,");
			psoct((1<<i)-1);
			printf("\n	bnz	L%d\n", deflab);
			printf("	sraa	0,%d\n", i);
		}

		printf("* dirsw\n");
		if (fp->swval) {
			printf("	sai	0,");
			psoct(fp->swval);
			putchar('\n');
		}
		printf("	cai	0,");
		psoct(range);
		printf(dirsw, deflab, deflab, isn);
		sdata();
		printf("*<\n");		/*** for kre optimizer ***/
		label(isn);
		isn++;
		for (i=fp->swval; i<=lp->swval; i++) {
			if (i==fp->swval) {
				printf("	dc	L%d\n", fp->swlab);
				fp++;
			} else
				printf("	dc	L%d\n", deflab);
		}
		goto esw;
	}
		/** herein follows a very magic number, viz 32,
		 ** its signifigance depends on the pathetically slow
		 ** division instruction on the Interdata 7/32
		 **
		 ** hash switch timing estimates:
		 **	107us setup
		 **	6.5us/iteration, avg 2 iterations
		 **
		 ** simple switch timing estimates:
		 **	6us setup
		 **	6.5us/iteration, avg n/2 iterations
		 **
		 ** thus, breakeven when:
		 **	107 + 2 * 6.5 = 6 + (n/2)*6.5
		 **
		 **		n ~ 32
		 **/
	/* simple switch */
	if (ncase<32) {
		i = isn++;
		j = isn++;
		printf(simpsw, i, j, isn, isn, j, i);
		sdata();
		printf("*<\n");		/*** for kre optimizer ***/
		label(i);
		isn++;
		for (; fp<=lp; fp++) {
			printf("	dc	");
			psoct(fp->swval);
			putchar('\n');
		}
		printf("	ds	adc\nL%d	equ	*\n", j);
		for (fp = afp; fp<=lp; fp++)
			printf("	dc	L%d\n", fp->swlab);
		printf("	dc	L%d\n", deflab);
		goto esw;
	}
	/* hash switch */
	best = ((unsigned) ~0) >> 1;
	poctab = getblk(((ncase+2)/2) * sizeof(*poctab));
	for (i=ncase/4; i<=ncase/2; i++) {
		for (j=0; j<i; j++)
			poctab[j] = 0;
		for (swp=fp; swp<=lp; swp++)
			poctab[(unsigned)swp->swval%i]++;
		worst = 0;
		for (j=0; j<i; j++)
			if (poctab[j]>worst)
				worst = poctab[j];
		if (i*worst < best) {
			tabs = i;
			best = i*worst;
		}
	}
	i = isn++;
	printf(hashsw, tabs, isn, isn, i, i, isn+tabs+1, isn+1);
	sdata();
	printf("*<\n");		/*** for kre optimizer ***/
	printf("	align	adc\n");
	label(isn++);
	for (i = 0; i <= tabs; i++)
		printf("	dac	L%d\n", isn+i);
	for (i = 0; i < tabs; i++) {
		label(isn++);
		printf("	ds	adc");
		for (swp = fp; swp <= lp; swp++)
			if ((unsigned)swp->swval % tabs == i) {
				printf("\n	dc	");
				psoct((unsigned)swp->swval / tabs);
			}
		putchar('\n');
	}
	label(isn++);
	for (i = 0; i < tabs; i++) {
		printf("	dac	L%d\n", deflab);
		for (swp = fp; swp <= lp; swp++)
			if ((unsigned)swp->swval % tabs == i)
				printf("	dc	L%d\n", swp->swlab);
	}
esw:
	printf("*>\n");		/*** for kre optimizer ***/
	stext();
}

sort(afp, alp)
struct swtab *afp, *alp;
{
	register struct swtab *cp, *fp, *lp;
	int intch, t;

	fp = afp;
	lp = alp;
	while (fp < --lp) {
		intch = 0;
		for (cp=fp; cp<lp; cp++) {
			if (cp->swval == cp[1].swval) {
				error("Duplicate case (%d)", cp->swval);
				return(1);
			}
			if (cp->swval > cp[1].swval) {
				intch++;
				t = cp->swval;
				cp->swval = cp[1].swval;
				cp[1].swval = t;
				t = cp->swlab;
				cp->swlab = cp[1].swlab;
				cp[1].swlab = t;
			}
		}
		if (intch==0)
			break;
	}
	return(0);
}

ispow2(atree)
{
	register int d;
	register struct tnode *tree;

	tree = atree;
	if (!isfloat(tree) && tree->tr2->op==CON) {
		d = tree->tr2->value;
		if (d>1 && (d&(d-1))==0)
			return(d);
	}
	return(0);
}

pow2(atree)
struct tnode *atree;
{
	register int d, i;
	register struct tnode *tree;

	tree = atree;
	if (d = ispow2(tree)) {
		for (i=0; (d=>>1)!=0; i++);
		tree->tr2->value = i;
		switch (tree->op) {

		case TIMES:
			tree->op = LSHIFT;
			break;

		case ASTIMES:
			tree->op = ASLSH;
			break;

		case DIVIDE:
		case PTOI:
/***
			tree->op = ULSH;
			tree->tr2->value = -i;
***/			tree->op = RSHIFT;
			break;

		case ASDIV:
/***
			tree->op = ASULSH;
			tree->tr2->value = -i;
***/			tree->op = ASRSH;
			break;

		case MOD:
			tree->op = AND;
			tree->tr2->value = (1<<i)-1;
			break;

		case ASMOD:
			tree->op = ASAND;
			tree->tr2->value = (1<<i)-1;
			break;

		default:
			error("pow2 botch");
		}
		tree = optim(tree);
	}
	return(tree);
}

cbranch(atree, albl, cond, areg)
struct tnode *atree;
{
	int l1, op;
	register lbl, reg;
	register struct tnode *tree;

	lbl = albl;
	reg = areg;
again:
	if ((tree=atree)==0)
		return;
	switch(tree->op) {

	case LOGAND:
		if (cond) {
			cbranch(tree->tr1, l1=isn++, 0, reg);
			cbranch(tree->tr2, lbl, 1, reg);
			label(l1);
		} else {
			cbranch(tree->tr1, lbl, 0, reg);
			cbranch(tree->tr2, lbl, 0, reg);
		}
		return;

	case LOGOR:
		if (cond) {
			cbranch(tree->tr1, lbl, 1, reg);
			cbranch(tree->tr2, lbl, 1, reg);
		} else {
			cbranch(tree->tr1, l1=isn++, 1, reg);
			cbranch(tree->tr2, lbl, 0, reg);
			label(l1);
		}
		return;

	case EXCLA:
		cbranch(tree->tr1, lbl, !cond, reg);
		return;

	case SEQNC:
		rcexpr(tree->tr1, efftab, reg);
		atree = tree->tr2;
		goto again;

	case ITOL:
		tree = tree->tr1;
		break;
	}
	op = tree->op;
	if (opdope[op]&RELAT
	 && tree->tr1->op==ITOL && tree->tr2->op==ITOL) {
		tree->tr1 = tree->tr1->tr1;
		tree->tr2 = tree->tr2->tr1;
	}
	if (tree->type==LONG
	  || opdope[op]&RELAT&&tree->tr1->type==LONG) {
		longrel(tree, lbl, cond, reg);
		return;
	}
	rcexpr(tree, cctab, reg);
	op = tree->op;
	if ((opdope[op]&RELAT)==0)
		op = NEQUAL;
	else {
		if (iszero(tree->tr2))
			op =+ 200;      /* not using 'compare' instuction */
/***
		else
			op = maprel[op-EQUAL];
***/
	}
/***
	if (isfloat(tree))
		printf("cfcc\n");
***/
	branch(lbl, op, !cond);
}

branch(lbl, aop, c)
{
	register op;

	putchar('\t');
	if(op=aop)
		prins(op, c, brtab);
	else
		putchar('b');
	printf("\tL%d\n", lbl);
}

longrel(atree, lbl, cond, reg)
struct tnode *atree;
{
	int xl1, xl2, xo, xz;
	register int op, isrel;
	register struct tnode *tree;

	reorder(&atree, cctab, reg);
	tree = atree;
	isrel = 0;
	if (opdope[tree->op]&RELAT) {
		isrel++;
		op = tree->op;
	} else
		op = NEQUAL;
	if (!cond)
		op = notrel[op-EQUAL];
	xl1 = xlab1;
	xl2 = xlab2;
	xo = xop;
	xlab1 = lbl;
	xlab2 = 0;
	xop = op;
	xz = xzero;
	xzero = !isrel || tree->tr2->op==ITOL && tree->tr2->tr1->op==CON
		&& tree->tr2->tr1->value==0;
	if (tree->op==ANDN) {
		tree->op = TAND;
		tree->tr2 = optim(tnode(COMPL, LONG, tree->tr2));
	}
    doitover:
	if (cexpr(tree, cctab, reg) < 0) {
		if (tree->op==TAND) {
			tree->op = ANDN;
			tree->tr2 = optim(tnode(COMPL, LONG, tree->tr2));
			goto doitover;
		}
		if (isrel) {
			tree->op = MINUS;
			tree->type = LONG;
			tree = optim(tree);
		}
/***
		printf("ashc	$0,r%d\n", rcexpr(tree, regtab, reg));
***/
		branch(xlab1, op, 0);
	}
	xlab1 = xl1;
	xlab2 = xl2;
	xop = xo;
	xzero = xz;
}

/*
 * Tables for finding out how best to do long comparisons.
 * First dimen is whether or not the comparison is with 0.
 * Second is which test: e.g. a>b->
 *	cmp	a,b
 *	bgt	YES		(first)
 *	blt	NO		(second)
 *	cmp	a+2,b+2
 *	bhi	YES		(third)
 *  NO:	...
 * Note some tests may not be needed.
 */
char	lrtab[2][3][6] {
	0,	NEQUAL,	LESS,	LESS,	GREAT,	GREAT,
	NEQUAL,	0,	GREAT,	GREAT,	LESS,	LESS,
	EQUAL,	NEQUAL,	LESSEQP,LESSP,	GREATQP,GREATP,

	0,	NEQUAL,	LESS,	LESS,	GREATEQ,GREAT,
	NEQUAL,	0,	GREAT,	0,	0,	LESS,
	EQUAL,	NEQUAL,	EQUAL,	0,	0,	NEQUAL,
};

xlongrel(f)
{
	register int op, bno;

	op = xop;
	if (f==0) {
		if (bno = lrtab[xzero][0][op-EQUAL])
			branch(xlab1, bno, 0);
		if (bno = lrtab[xzero][1][op-EQUAL]) {
			xlab2 = isn++;
			branch(xlab2, bno, 0);
		}
		if (lrtab[xzero][2][op-EQUAL]==0)
			return(1);
	} else {
		branch(xlab1, lrtab[xzero][2][op-EQUAL], 0);
		if (xlab2)
			label(xlab2);
	}
	return(0);
}

label(l)
{
	printf("L%d	equ	*\n", l);
}

/***
popstk(a)
{
	if (a)
		printf("	aai	7,%d\n", a);
}
***/

error(s, p1, p2, p3, p4, p5, p6)
{

	nerror++;
	fprintf(stderr, "%d: ", line);
	fprintf(stderr, s, p1, p2, p3, p4, p5, p6);
	putc('\n', stderr);
}

psoct(an)
{
	register int n, sign;

	sign = 0;
	if ((n = an) < 0 && n >= -0177777) {	/*** Interdata CAL bug ***/
		n = -n;
		sign = '-';
	}
#ifdef HALFW
	printf("%cx'%x'", sign, n);
#endif
#ifndef HALFW
	printf("%cy'%x'", sign, n);
#endif
}

/*
 * Read in an intermediate file.
 *
 *   new operator ENDPROC indicates end-of function definition,
 *   so ok to increment fautolen to generate new L.* labels.
 *   This opcode should be a no-op for the pdp's.
 */
getree()
{
	LTYPE itol();
	static struct tnode *expstack[20];
	register struct tnode **sp;
	register t, op;
	register t1;
	static char s[9];
	register struct swtab *swp;
	double atof();
	static char numbuf[64];
	struct tname *np;
	struct xtname *xnp;
	struct ftconst *fp;
	struct lconst *lp;
	struct fasgn *sap;
	int lbl, cond;
	int lbl2, lbl3;			/*** f77 3-way if! ***/

	curbase = funcbase;
	sp = expstack;
	for (;;) {
		if (sp >= &expstack[20])
			error("Stack botch");
		op = geti();
		if ((op&0177400) != 0177000) {
			error("Intermediate file error");
			exit(1);
		}
		lbl = 0;
		switch(op =& 0377) {

	case SINIT:
		printf("	dc	");
		psoct(geti());
		putchar('\n');
		break;

	case EOFC:
		return;

	case BDATA:
		if (geti() == 1) {
			printf("	db	");
			for (t=1; ; t++) {
				psoct(geti());
				if (geti() != 1)
					break;
				if ((t&07) == 0)
					printf("\n	db	");
				else
					putchar(',');
			}
			printf("\n");
		}
		break;

	case PROG:
		stext();
		break;

	case DATA:
		sdata();
		break;

	case BSS:
#ifdef unix
		printf("  bss\n");
#else
		sdata();
#endif
		break;

	case SYMDEF:
		outname(s);
/***
		printf(".globl%s%s\n", s[0]?"	_":"", s);
***/
		if (s[0])
			printf("  entry %s\n", s);
		sfuncr.nloc = 0;
		break;

	case GLOBAL:
		outname(s);
		printf("  extrn %s\n", s);
		break;

	case RETRN:
		printf("\tlm\t8,L.%d-%d(14)\n\taai\t7,L.%d\n",
			fautolen, 8*NCPW, fautolen);
		printf("	br	15\n");
		break;

	case CSPACE:
		outname(s);
		t = geti();
#ifdef unix
		printf("%s\tcomn\n\tds\t%d\n\tends\n", s, t);
#else
		sdata();
		printf("  entry %s\n%s\tequ\t*", s, s);
		printf("	%d bytes\n", t);
		if (t1 = t/(8*NCPW))
			printf("	do %d\n	dc	0,0,0,0,0,0,0,0\n", t1);
		t =% 8*NCPW;
		if (t1 = t/NCPW) {
			for (printf("	dc	0"); --t1; )
				printf(",0");
			putchar('\n');
		}
		if (t =% NCPW) {
			for (printf("	db	0"); --t; )
				printf(",0");
			putchar('\n');
		}
#endif
		break;

	case SSPACE:
#ifdef unix
		printf("\tds\t%d\n", geti());
#else
		printf("\tdo\t%d\n\tdb\t0\n", geti());
#endif
		break;

	case EVEN:
		printf("  align adc\n");
		break;

	case SAVE:
		printf("\tsai\t7,L.%d\n\tstm\t8,L.%d-%d(7)\n",
			fautolen, fautolen, 8*NCPW);
		printf("\tldar\t14,7\n");
		break;

	case SETSTK:
		t = geti()+NCPW*maxtemp;
		printf("L.%d equ %d\n", fautolen, t);
		break;

	case ENDPROC:
           maxtemp = ntemp = pstack = 2;
		fautolen++;
		break;

	case PROFIL:
		t = geti();
		printf("\tla\t1,L%d\n\tbal\t15,mcount\n", t);
#ifdef unix
		printf("  bss\nL%d\tdas\t1\n  pure\n", t);
#else
		sdata();
		printf("L%d\tdas\t1\n", t);
		stext();
#endif
		break;

	case SNAME:
		t = outname(s);
#ifndef unix
		putchar('*');
#endif
		printf("~%s equ L%d\n", t, geti());
		break;

	case ANAME:
		t = outname(s);
#ifndef unix
		putchar('*');
#endif
		printf("~%s equ %d\n", t, geti());
		break;

	case RNAME:
		t = outname(s);
#ifndef unix
		putchar('*');
#endif
		printf("~%s sym 20,%d\n", t, geti());
		break;

	case SWIT:
		t = geti();
		line = geti();
		curbase = funcbase;
		while(swp=getblk(sizeof(*swp)), swp->swlab = geti())
			swp->swval = geti();
		pswitch(funcbase, swp, t);
		break;

	case CBRANCH:
		lbl = geti();
		cond = geti();
		goto xpr;

	case C3BRANCH:			/*** f77 special [sic] ***/
		lbl  = geti();
		lbl2 = geti();
		lbl3 = geti();
		goto xpr;


	case EXPR:
	     xpr:
		line = geti();
		if (sp != &expstack[1]) {
			error("Expression input botch");
			exit(1);
		}
		nstack = 0;
		printf("*@%d\n", line);
		*sp = optim(*--sp);
		switch (op)  {

			case CBRANCH:
				cbranch(*sp, lbl, cond, 0);
				break;

			case EXPR:
				rcexpr(*sp, efftab, 0);
				break;

			case C3BRANCH:
				rcexpr(*sp, cctab, 0);
				printf("\tbp\tL%d\n", lbl3);
				printf("\tbm\tL%d\n", lbl);
				printf("\tbe\tL%d\n", lbl2);
				break;

			default:
				error("Bad case of expression");
				exit(1);
			}

		curbase = funcbase;
		break;

	case NAME:
		t = geti();
		if (t==EXTERN) {
			np = getblk(sizeof(*xnp));
			np->type = geti();
			outname(np->name);
		} else {
			np = getblk(sizeof(*np));
			np->type = geti();
			np->nloc = geti();
		}
		np->op = NAME;
		np->class = t;
		np->regno = 0;
		np->offset = 0;
		*sp++ = np;
		break;

	case CON:
		geti();	/* ignore type, assume int */
		*sp++ = tconst(geti());
		break;

	case LCON:
		geti();	/* ignore type, assume long */
		t = geti();
		op = geti();
		if (t==0 && op>=0 || t == -1 && op<0) {
			*sp++ = tnode(ITOL, LONG, tconst(op));
			break
struct tnode *atree;
{
	struct { int intx[4]; };
	register struct tnode *subtre, *tree;
	register int *p;
	double static fv;
	struct { int integer; };
	register struct ftconst *fp;

	if ((tree=atree)==0)
		return(0);
    again:
	if (tree->op==AMPER && tree->tr1->op==STAR) {
		subtre = tree->tr1->tr1;
		subtre->type = tree->type;
		return(optim(subtre));
	}
	subtre = tree->tr1 = optim(tree->tr1);
	switch (tree->op) {

/***
	case ITOF:
		if (tree->tr1->type==UNSIGN) {
			tree->tr1 = unoptim(tnode(ITOL, LONG, tree->tr1));
			tree->op = LTOF;
		}
		break;
***/

	case ITOC:
		p = tree->tr1;
		/*
		 * Sign-extend PDP-11 characters
		***   mask off high bits
		 */
		if (p->op==CON) {
/***
			p->value = p->value << 8 >> 8;
***/
			p->value &= 0377;
			return(p);
		}
		/***
		else if (p->op==NAME) {
			p->type = CHAR;
			return(p);
		}
		***/
		break;

	case LTOI:
		p = tree->tr1;
		switch (p->op) {
		case NAME:
			p->offset =+ NCPW;
			p->type = tree->type;
			return(p);

		case STAR:
			p->type = tree->type;
			p->tr1->type = tree->type+PTR;
			p->tr1 = tnode(PLUS, tree->type, p->tr1, tconst(2));
			return(optim(p));

		case ITOL:
			return(p->tr1);

		case PLUS:
		case MINUS:
		case AND:
		case ANDN:
		case OR:
		case EXOR:
			p->tr2 = tnode(LTOI, tree->type, p->tr2);
		case NEG:
		case COMPL:
			p->tr1 = tnode(LTOI, tree->type, p->tr1);
			p->type = tree->type;
			return(optim(p));
		}
		break;

	case FSEL:
		tree->op = AND;
		tree->tr1 = tree->tr2->tr1;
		tree->tr2->tr1 = subtre;
		tree->tr2->op = RSHIFT;
		tree->tr1->value = (1 << tree->tr1->value) - 1;
		return(optim(tree));

	case FSELR:
		tree->op = LSHIFT;
		tree->type = UNSIGN;
		tree->tr1 = tree->tr2;
		tree->tr1->op = AND;
		tree->tr2 = tree->tr2->tr2;
		tree->tr1->tr2 = subtre;
		tree->tr1->tr1->value = (1 << tree->tr1->tr1->value) -1;
		return(optim(tree));

	case AMPER:
		if (subtre->op==STAR)
			return(subtre->tr1);
/*** temporarily removed because it loses auto offsets
		if (subtre->op==NAME && subtre->class == OFFS) {
			p = tnode(PLUS, tree->type, subtre, tree);
			subtre->type = tree->type;
			tree->op = CON;
			tree->type = INT;
			tree->degree = 0;
			tree->value = subtre->offset;
			subtre->class = REG;
			subtre->nloc = subtre->regno;
			subtre->offset = 0;
			return(optim(p));
		}
***/
		break;

	case STAR:
		if (subtre->op==AMPER) {
			subtre->tr1->type = tree->type;
			return(subtre->tr1);
		}
		if (tree->type==STRUCT)
			break;
		if (subtre->op==NAME && subtre->class==REG) {
			subtre->type = tree->type;
			subtre->class = OFFS;
			subtre->regno = subtre->nloc;
			return(subtre);
		}
		p = subtre->tr1;
/***
		if ((subtre->op==INCAFT||subtre->op==DECBEF)&&tree->type!=LONG
		 && p->op==NAME && p->class==REG && p->type==subtre->type) {
			p->type = tree->type;
			p->op = subtre->op==INCAFT? AUTOI: AUTOD;
			return(p);
		}
***/
		if (subtre->op==PLUS && p->op==NAME && p->class==REG) {
			if (subtre->tr2->op==CON) {
				p->offset =+ subtre->tr2->value;
				p->class = OFFS;
				p->type = tree->type;
				p->regno = p->nloc;
				return(p);
			}
			if (subtre->tr2->op==AMPER
#ifdef unix
			    && subtre->tr2->tr1->class != OFFS
#else
			    && subtre->tr2->tr1->class == STATIC
#endif
			      ) {
				subtre = subtre->tr2->tr1;
				subtre->class =+ XOFFS-EXTERN;
				subtre->regno = p->nloc;
				subtre->type = tree->type;
				return(subtre);
			}
		}
		break;
	case EXCLA:
		if ((opdope[subtre->op]&RELAT)==0)
			break;
		tree = subtre;
		tree->op = notrel[tree->op-EQUAL];
		break;

	case NEG:
	case COMPL:
		if (tree->type==CHAR)
			tree->type = INT;
		if (tree->op == subtre->op)
			return(subtre->tr1);
		if (subtre->op==ITOL) {
			subtre->op = tree->op;
			subtre->type = subtre->tr1->type;
			tree->op = ITOL;
			tree->type = LONG;
			goto again;
		}
		if (tree->op!=NEG)
			break;
		/*
		 * Interdata FP negation
		 */
		if (subtre->op==SFCON) {
			subtre->value =^ (1<<31);
			subtre->fvalue.intx[0] =^ (1<<31);
			return(subtre);
		}
		if (subtre->op==FCON) {
			subtre->fvalue.intx[0] =^ (1<<31);
			return(subtre);
		}
		if (subtre->op == LCON) {
			subtre->lvalue = -subtre->lvalue;
			return(subtre);
		}
	}
	if (subtre->op == CON) switch(tree->op) {

	case NEG:
		subtre->value = -subtre->value;
		return(subtre);
