[comp.sources.amiga] v89i029: zc - c compiler, Part02/04

page@swan.ulowell.edu (Bob Page) (03/08/89)

Submitted-by: monty@brahms.Berkeley.EDU (Joe Montgomery)
Posting-number: Volume 89, Issue 29
Archive-name: languages/zc.2

#	This is a shell archive.
#	Remove everything above and including the cut line.
#	Then run the rest of the file through sh.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar:    Shell Archiver
#	Run the following text with /bin/sh to create:
#	d2.c
#	decl.c
#	expr.c
#	fix.c
#	fun.c
#	g2.c
# This archive created: Tue Mar  7 21:49:30 1989
cat << \SHAR_EOF > d2.c
/* Copyright (c) 1988 by Sozobon, Limited.  Author: Johann Ruegg
 *
 * Permission is granted to anyone to use this software for any purpose
 * on any computer system, and to redistribute it freely, with the
 * following restrictions:
 * 1) No charge may be made other than reasonable charges for reproduction.
 * 2) Modified versions must be clearly marked as such.
 * 3) The authors are not responsible for any harmful consequences
 *    of using this software, even if they result from defects in it.
 *
 *	d2.c
 *
 *	Declaration subroutines
 *
 *	Mostly routines for initializations
 */

#include <stdio.h>
#include "param.h"
#include "tok.h"
#include "nodes.h"
#include "cookie.h"

#if MMCC
overlay "pass2"
#endif

extern NODEP cur;
extern NODEP symtab[];
extern level;

extern int oflags[];
#define debugi	oflags['i'-'a']

su_size(lp, cp, xp, isunion)
register long *lp;
char *cp;
register NODE *xp;
{
	long sz;
	char al;

	sz = xp->n_tptr->t_size;
	al = xp->n_tptr->t_aln;
	if (isunion) {
		*lp = *lp > sz ? *lp : sz;
	} else {
		while (al & (*lp)) {    /* align new field */
			(*lp)++;
			xp->e_offs++;
		}
		*lp += sz;
	}
	*cp = *cp > al ? *cp : al;
}

lc_size(lp, rp, xp)
register long *lp;
int *rp;
register NODE *xp;
{
	long sz;
	char al;
	long arg_size();

	if (level > 1 && xp->e_sc == K_REGISTER) {
		if (lc_reg(rp, xp))
			return;
		else
			xp->e_sc = K_AUTO;
	}
	if (xp->e_sc == K_AUTO || level == 1) {
		sz = xp->n_tptr->t_size;
		al = xp->n_tptr->t_aln;
		while (al & (*lp)) {    /* align new field */
			(*lp)++;
			xp->e_offs++;
		}
		if (level == 1) {
			sz = arg_size(sz,xp);
			xp->e_offs += ARG_BASE + *lp;
		}
		*lp += sz;
		if (level != 1)
			xp->e_offs = LOC_BASE - *lp;
	}
}

su_fld(lp, alp, xp, fldw, fop)
register long *lp;
char *alp;
register NODE *xp;
int *fop;
{
	if (*alp < ALN_I)
		*alp = ALN_I;
	if (fldw == 0) {
		afterfld(lp, fop);
		return;
	}
	if (fldw + *fop > 8*SIZE_I)
		afterfld(lp, fop);
	if (xp) {
		xp->e_fldw = fldw;
		xp->e_fldo = *fop;
	}
	*fop += fldw;
}

afterfld(szp, fop)
long *szp;
int *fop;
{
	if (*fop) {
		*szp += SIZE_I;
		*fop = 0;
	}
}

ok_gsh(sc, np)
NODE *np;
{
	if (sc == K_REGISTER || sc == K_AUTO) {
		error("reg/auto outside fun");
		return 0;
	}
	return ok_ty(np, NULL);
}

ok_gx(np, endp)
NODEP np, endp;
{
	if (np)
		return ok_ty(np->n_tptr, endp);
	return 0;
}

ok_lsh(sc, np)
NODE *np;
{
	return ok_ty(np, NULL);
}

arytoptr(np)
NODEP np;
{
	NODEP tp = np->n_tptr;
	NODEP copyone();

	if (np->n_flags & N_COPYT) {    /* cant change if a dupl. */
		tp = copyone(tp);
		np->n_tptr = tp;
		np->n_flags &= ~N_COPYT;
	}
	tp->t_token = STAR;
	strcpy(tp->n_name, "Aptr to");
}

ok_lx(np,endp)
NODEP np, endp;
{
	if (np) {
		if (level == 1 && np->n_tptr->t_token == '[')
			arytoptr(np);
		return ok_ty(np->n_tptr, endp);
	}
	return 0;
}

ok_suh(np)
NODEP np;
{
	return 1;
}

ok_sux(np, endp)
NODEP np, endp;
{
	if (np)
		return ok_ty(np->n_tptr, endp);
	return 0;
}

ok_enx(np, endp)
NODEP np, endp;
{
	if (np && np->n_tptr == endp)   /* no modifiers */
		return 1;
	return 0;
}

ok_cast(np, endp)
NODEP np, endp;
{
	if (np)
		return ok_ty(np, endp);
	return 0;
}

ok_ty(np, endp)
register NODEP np, endp;
{
	NODEP child;
	long csize;
	long conlval();

	if (np == endp)
		return 1;
	child = np->n_tptr;
	if (child) {
		if (ok_ty(child, endp) == 0)
			return 0;
		csize = child->t_size;
	}

	switch (np->t_token) {
	case STAR:
		np->t_size = SIZE_P;
		np->t_aln = ALN_P;
		break;
	case '(':
		/* size 0 okay - fun ret void */
		if (child->t_token == '[') {
			error("bad func");
			return 0;
		}
		/* size 0 */
		break;
	case '[':
		if (csize == 0) {
			error("bad array");
			return 0;
		}
		if (np->n_right) {
			csize *= conlval(np->n_right);
			np->n_right = NULL;
			np->t_size = csize;
		}
		np->t_aln = child->t_aln;
		break;
	default:
		return 1;
	}
	return 1;
}

ok_revx(rv,forcast)
NODEP rv;
{
	if (rv == NULL)
		return 1;
	if (forcast == 0 && rv->e_token != ID) {
		error("need ID");
		return 0;
	}
	if (forcast && rv->e_token == ID) {
		error("ID in cast");
		return 0;
	}
	return 1;
}

opt_ginit(xp)
NODEP xp;
{
	if (xp->e_token != ID)
		return;
	if (xp->n_tptr->t_token == '(')
		return;
	switch (xp->e_sc) {
	case K_STATIC:
	case HERE_SC:
		if (cur->e_token == '=') {
			out_gv(xp, 0);   /* place in data segment */
			fadvnode();
			g_init(xp->n_tptr);
		} else
			out_gv(xp, 1);   /* place in BSS segment */
		break;
/* ? added external case ? */
	case K_EXTERN:
		out_gv(xp,0);
	}
}

opt_linit(xp)
NODEP xp;
{
	if (xp->e_token != ID)
		return;
	if (xp->n_tptr->t_token == '(')
		return;
	switch (xp->e_sc) {
	case K_STATIC:
		if (cur->e_token == '=') {
			out_gv(xp, 0);
			fadvnode();
			g_init(xp->n_tptr);
		} else
			out_gv(xp, 1);
		to_text();
		break;
	case K_AUTO:
	case K_REGISTER:
		if (cur->e_token == '=')
			a_init(xp);
		break;
	}
}

a_init(op)
NODEP op;
{
	register NODEP np, xp;
	NODEP assignx(), copynode();

	np = cur;  advnode();
	xp = assignx();
	op = copynode(op);
	np->n_left = op;
	np->n_right = xp;
	np->e_type = E_BIN;
	do_expr(np, FORSIDE);
	return;
}

opt_enval(intp)
int *intp;
{
	NODEP np;
	NODEP questx();

	if (cur->e_token == '=') {
		fadvnode();
		np = questx();
		*intp = conxval(np);
		return;
	}
}

opt_field(xp,wdp,isunion)
NODE *xp;
int *wdp;
{
	NODEP np;
	NODEP questx();
	int i;

	*wdp = -1;
	if (isunion) return;
	if (cur->e_token == ':') {
		fadvnode();
		np = questx();
		i = conxval(np);
		if (i > 8*SIZE_I) {
			error("field too big");
			i = 8*SIZE_I;
		}
		if (xp) {
			if (i <= 0 || bad_fty(xp->n_tptr)) {
				error("bad field");
				return;
			}
		} else if (i < 0) {
			error("neg field width");
			return;
		}
		*wdp = i;
		return;
	}
}

bad_fty(tp)
NODEP tp;
{
	int tok;

	tok = tp->t_token;
	if (tok == K_INT || tok == K_UNSIGNED)
		return 0;
	return 1;
}

field(xp, wd, ofp)
NODEP xp;
int *ofp;
{
}

NODEP
def_type()
{
	NODEP bas_type();

	return bas_type(K_INT);
}

#define NSC	LAST_SC-FIRST_SC+1
#define NBAS	LAST_BAS-FIRST_BAS+1

NODE basics[NBAS];
NODE str_ptr, fun_int;

struct bt {
	char	*name;
	int	size;
	char	align;
} btbl[] = {
	{"Uchar",       SIZE_C, ALN_C},
	{"Ulong",       SIZE_L, ALN_L},
	{"Long",        SIZE_L, ALN_L},
	{"Short",       SIZE_S, ALN_S},
	{"Uns",         SIZE_U, ALN_U},
	{"Int",         SIZE_I, ALN_I},
	{"Char",        SIZE_C, ALN_C},
	{"Float",       SIZE_F, ALN_F},
	{"Dbl",         SIZE_D, ALN_D},
	{"Void",        0},
};

NODEP
bas_type(btype)
{
	NODEP rv;
	static once = 0;

	if (once == 0) {
		once++;

		sprintf(str_ptr.n_name, "Ptr to");
		str_ptr.t_token = STAR;
		str_ptr.n_tptr = bas_type(K_CHAR);
		str_ptr.n_flags = N_COPYT;
		str_ptr.t_size = SIZE_P;
		str_ptr.t_aln = ALN_P;

		sprintf(fun_int.n_name, "Fun ret");
		fun_int.t_token = '(';
		fun_int.n_tptr = bas_type(K_INT);
		fun_int.n_flags = N_COPYT;
	}
	if (btype == SCON)
		return &str_ptr;
	else if (btype == '(')
		return &fun_int;
	rv = &basics[btype-FIRST_BAS];
	if (rv->t_token == 0) {
		rv->t_token = btype;
		rv->t_size = btbl[btype-FIRST_BAS].size;
		rv->t_aln = btbl[btype-FIRST_BAS].align;
		sprintf(rv->n_name, btbl[btype-FIRST_BAS].name);
	}
	return rv;
}

/* new function name seen in expr */
NODEP
new_fun(op)
NODE *op;
{
	NODEP np;
	NODEP copyone();

	/* we know left, right and tptr are NULL */
	np = copyone(op); /* ID node */
	np->n_tptr = bas_type('(');
	np->n_flags = N_COPYT;
	np->e_sc = K_EXTERN;
	new_sym(symtab, np);
	return np;
}

/* declare arg name as int */
def_arg(listpp, op)
NODE **listpp, *op;
{
	register NODEP np;
	NODEP copyone();

	np = copyone(op);
	np->n_tptr = bas_type(K_INT);
	np->n_flags = N_COPYT;
	np->e_sc = K_AUTO;
	new_sym(listpp, np);
}

/* initialize 0 or 1 thing of any type (tp) */
g_init(tp)
register NODEP tp;
{
	int nsee;
	long sz;
	int oldsize;
	int seebr = 0;

	if (cur->e_token == SCON &&
		   tp->t_token == '[' &&
		   tp->n_tptr->t_token == K_CHAR) { /* hack for SCON ary */
			nsee = out_scon(cur);
			fadvnode();
			a_fix(tp, nsee);
			return 1;
	}

	if (cur->e_token == '{') {
		fadvnode();
		seebr = 1;
	}

	switch (tp->t_token) {
	case '[':
		if (tp->t_size)
			oldsize = tp->t_size / tp->n_tptr->t_size;
		else
			oldsize = 0;
		nsee = inita(tp->n_tptr, oldsize);
		if (nsee)
			a_fix(tp, nsee);
		break;
	case K_STRUCT:
		o_aln(tp->t_aln);
		nsee = inits(tp->n_right);
		break;
	case K_UNION:
		o_aln(tp->t_aln);
		nsee = g_init(tp->n_right->n_tptr);
		if (nsee) {
			sz = tp->t_size - tp->n_right->n_tptr->t_size;
			if (sz)
				o_nz(sz, 0);
		}
		break;
	default:
		nsee = init1(tp);
		break;
	}

	if (seebr) {
		if (cur->e_token == ',')
			fadvnode();
		eat('}');
	}
	return nsee ? 1 : 0;
}

/* initialize one (or 0) scalar to an expr */
init1(tp)
register NODEP tp;
{
	NODEP xp;
	NODEP assignx();

	if (debugi) {
		printf("init1");
		printnode(tp);
	}
	xp = assignx();
	if (xp) {
		if (debugi)
			printnode(xp);
		o_vinit(tp, xp);
		return 1;
	} else
		return 0;
}

/* set array size or fill array with zeros */
a_fix(tp, nsee)
register NODEP tp;
{
	int oldsize;

	if (tp->t_size) {
		oldsize = tp->t_size / tp->n_tptr->t_size;
		if (oldsize > nsee) {
			o_nz(tp->n_tptr->t_size * (oldsize-nsee),
				tp->n_tptr->t_aln);
		} else if (oldsize < nsee) {
			error("too many init exprs");
		}
	} else
		tp->t_size = nsee * tp->n_tptr->t_size;
}

/* initialize up to max items of type tp */
/* if max is 0, any number is okay */

inita(tp, maxi)
NODEP tp;
{
	int nsee;

	nsee = g_init(tp);
	if (nsee == 0)
		return 0;

	while (cur->e_token == ',') {
		if (nsee == maxi)
			break;
		fadvnode();
		nsee += g_init(tp);
	}
	return nsee;
}

/* initialize (possible) structure */
inits(np)
register NODEP np;
{
	int see1;

	see1 = g_init(np->n_tptr);
	if (see1 == 0)
		return 0;

	while (np->n_next) {
		np = np->n_next;
		if (cur->e_token == ',') {
			fadvnode();
			see1 = g_init(np->n_tptr);
		} else
			see1 = 0;
		if (see1 == 0)
			z_init(np->n_tptr);
	}

	return 1;
}

z_init(tp)
register NODEP tp;
{
	switch (tp->t_token) {
	case '[':
	case K_STRUCT:
	case K_UNION:
		o_nz(tp->t_size, tp->t_aln);
		break;
	default:
		out_zi(tp);
	}
}
SHAR_EOF
cat << \SHAR_EOF > decl.c
/* Copyright (c) 1988 by Sozobon, Limited.  Author: Johann Ruegg
 *
 * Permission is granted to anyone to use this software for any purpose
 * on any computer system, and to redistribute it freely, with the
 * following restrictions:
 * 1) No charge may be made other than reasonable charges for reproduction.
 * 2) Modified versions must be clearly marked as such.
 * 3) The authors are not responsible for any harmful consequences
 *    of using this software, even if they result from defects in it.
 *
 *	decl.c
 *
 *	Do all declarations
 *
 *	Currently,
 *		struct tags are local
 *		struct members are tied to the struct
 *		enum tags are ignored
 *		enum members are local
 */

#include <stdio.h>
#include "param.h"
#include "tok.h"
#include "nodes.h"

extern NODE *cur;
extern level;

NODEP symtab[NHASH], tagtab;
extern NODE *blktab;

NODEP alltags(), allsyms(), llook(), hlook();

extern int oflags[];
#define debug	oflags['v'-'a']

/* look for global data decls
	return when see something weird
	return last ID declared */
NODEP
glb_decls()
{
	register NODEP head, xp;
	NODEP d_type(), def_type(), d_declr();
	int sclass;

	for(;;) {
		sclass = d_scl(HERE_SC);
		head = d_type();
		if (head == NULL)
			head = def_type();
		if (ok_gsh(sclass, head) == 0)
			continue;
	more:
		xp = d_declr(head,0);
		if (ok_gx(xp,head)) {
			xp->e_sc = sclass;
			opt_ginit(xp);
			new_sym(symtab,xp);
			if (xp->n_tptr->t_token == '(') {       /* func */
				if (cur->e_token == ',' ||
				    cur->e_token == ';')
					fix_fun(xp);
				else
					return xp;
			}
		}

		if (cur->e_token == ',') {
			fadvnode();
			goto more;
		}

		if (cur->e_token == ';') {
			fadvnode();
		} else
			return NULL;
	}
}

/* do local or arg decls
	return 1 if see something */
loc_decls()
{
	register NODEP head, xp;
	NODEP d_type(), def_type(), d_declr();
	int sclass;
	int regs;
	long size;
	int rv = 0;

	size = level > 2 ? blktab->n_next->b_size : 0;
	regs = level > 1 ? blktab->n_next->b_regs : 0;
	while (is_ty_start()) {
		rv++;
		sclass = d_scl(K_AUTO);
		head = d_type();
		if (head == NULL)
			head = def_type();
		if (ok_lsh(sclass, head) == 0)
			continue;
	more:
		xp = d_declr(head,0);
		if (ok_lx(xp,head)) {
			xp->e_sc = sclass;
			if (level > 1)  /* not args */
				lc_size(&size, &regs, xp);
			new_sym(&blktab->b_syms,xp);
			fix_fun(xp);
			opt_linit(xp,sclass);
		}

		if (cur->e_token == ',') {
			fadvnode();
			goto more;
		}

		if (cur->e_token == ';') {
			fadvnode();
		} else {
			error("expect ;");
			return 1;
		}
	}
	while (STACKALN & size)
		size++;
	blktab->b_size = size;
	blktab->b_regs = regs;
	return rv;
}

/* Decls inside Struct/Union */
su_decls(listpp, isunion, sizep, alnp)
NODEP *listpp;
long *sizep;
char *alnp;
{
	register NODEP head, xp;
	NODEP d_type(), d_declr();
	long size;
	char aln;
	int fldw, fldoff;

	aln = 0;
	size = 0;
	fldoff = 0;
	for(;;) {
		head = d_type();
		if (head == NULL)
			goto out;
		if (ok_suh(head) == 0)
			continue;
	more:
		xp = d_declr(head,0);
		opt_field(xp,&fldw,isunion);
		if (ok_sux(xp,head)) {
			if (fldw > 0) { /* handle field */
				su_fld(&size,&aln,xp,fldw,&fldoff);
				xp->e_offs = size;
			} else {		/* handle non-field */
				afterfld(&size,&fldoff);
				xp->e_offs = isunion ? 0 : size;
				su_size(&size,&aln,xp,isunion);
			}
			new_sym(listpp,xp);
			listpp = &xp->n_next;
		} else if (fldw == 0) {
			afterfld(&size, &fldoff);
		}

		if (cur->e_token == ',') {
			fadvnode();
			goto more;
		}

		if (cur->e_token == ';') {
			fadvnode();
		} else
			goto out;
	}
out:
	afterfld(&size,&fldoff);
	while (aln & size)
		size++;
	*sizep = size;
	*alnp = aln;
	return;
}

/* Decls inside Enum */
en_decls()
{
	register NODEP head, xp;
	NODEP bas_type(), d_declr();
	int curval = 0;

	for(;;) {
		head = bas_type(K_INT);
	more:
		xp = d_declr(head,0);
		if (ok_enx(xp,head)) {
			opt_enval(&curval);
			xp->e_ival = curval++;
			xp->e_sc = ENUM_SC;
			new_sym(level ? blktab->b_syms : (NODE *)symtab,
				xp);
		}

		if (cur->e_token == ',') {
			fadvnode();
			goto more;
		}

		return;
	}
}

/*
 * called from expr.c, make a cast
 * only called if is_ty_start();
 */
NODE *
makecast()
{
	NODEP head, xp;
	register NODEP np;
	NODEP d_type(), d_declr(), def_type();

	head = d_type();        /* we know this is not NULL */
	xp = d_declr(head, 1);
	if (ok_cast(xp,head) == 0) {
		xp = def_type();        /* return cast to INT */
	}
	np = allocnode();
	np->e_token = TCONV;
	np->n_tptr = xp;
	if (xp == head)
		np->n_flags |= N_COPYT;
	if (debug) {
		printf("Make cast");
		printnode(np);
	}
	return np;
}

is_ty_start()
{
	NODEP rv;

	if (is_tykw(cur->e_token))
		return 1;
	if (cur->e_token == ID) {
		rv = allsyms(cur);
		if (rv && rv->e_sc == K_TYPEDEF)
			return 1;
	}
	return 0;
}

/* assemble decl and put in listpp */
new_sym(listpp, xp)
NODEP *listpp;
NODEP xp;
{
	NODEP old;

	if (xp == NULL)
		return 0;
/* put in table */
	if (debug) {
		printf("New sym sc %c", "EARTSCH"[xp->e_sc-K_EXTERN]);
		printnode(xp);
	}
	/* later look for previous definition */
	if (listpp == (NODE **)symtab) {
		old = hlook(listpp, xp);
		if (old == NULL || def2nd(old, xp))
			puthlist(listpp, xp);
	} else {
		old = llook(*listpp, xp);
		if (old == NULL || def2nd(old, xp))
			putlist(listpp, xp);
	}
	return 1;
}

/* look for storage class */
d_scl(defau)
{
	int rv;

	if (is_sclass(cur->e_token)) {
		rv = cur->e_token;
		fadvnode();
		return rv;
	}
	/* no storage class specified */
	return defau;
}

NODEP
d_declr(head, forcast)
NODEP head;
{
	NODEP e1;
	NODEP declarator(), rev_decl();
	NODEP xp, tailp;

	e1 = declarator();
	xp = rev_decl(e1, &tailp, forcast);
	if (xp) {
		tailp->n_tptr = head;
		tailp->n_flags |= N_COPYT;
		return xp;
	} else if (forcast)
		return head;
	else
		return NULL;
}

NODEP
rev_decl(np,tailpp,forcast)
NODEP np, *tailpp;
{
	NODEP rv, scan, nxt;

	rv = NULL;
	for (scan = np; scan != NULL; scan = nxt) {
		nxt = scan->n_next;
		scan->n_next = NULL;
		if (rv == NULL) {
			*tailpp = scan;
			scan->n_tptr = NULL;
			rv = scan;
		} else {
			scan->n_tptr = rv;
			rv = scan;
		}
		e_to_t(rv);
		switch (rv->t_token) {
		case UNARY '*':
			sprintf(rv->n_name, "Ptr to");
			break;
		case '(':
			sprintf(rv->n_name, "Fun ret");
			break;
		case '[':
			sprintf(rv->n_name, "Ary of");
			break;
		case ID:
			break;
		default:
			error("bad type xpr");
			return NULL;
		}
	}
	/* if normal decl and see something, must see id first */
	if (!ok_revx(rv,forcast))
		rv = NULL;
	return rv;
}

/*
 * Looking for type part of a decl
 */
NODEP
d_type()
{
	int btype, adj;
	NODEP rv;
	NODEP bas_type(), decl_su(), decl_enum();

	/* look for 'struct', 'union', 'enum' or typedef ID */
	switch (cur->e_token) {
	case ID:
		rv = allsyms(cur);
		if (rv && rv->e_sc == K_TYPEDEF) {
			fadvnode();
			rv = rv->n_tptr;
			return rv;
		}
		return NULL;
	case K_STRUCT:
		return decl_su(0);
	case K_UNION:
		return decl_su(1);
	case K_ENUM:
		return decl_enum();
	}

	/* look for modifiers 'long', 'short', 'unsigned' */
	adj = 0;
	while (is_tadj(cur->e_token)) {
		switch (cur->e_token) {
		case K_SHORT:
			adj |= SAW_SHORT;
			break;
		case K_LONG:
			adj |= SAW_LONG;
			break;
		case K_UNSIGNED:
			adj |= SAW_UNS;
			break;
		}
		fadvnode();
	}

	/* look for base type 'char', 'int', 'float', 'double', 'void'*/
	if (is_btype(cur->e_token)) {
		btype = cur->e_token;
		fadvnode();
	} else if (adj == 0)    /* saw nothing */
		return NULL;
	else
		btype = K_INT;

	if (adj)
		btype = adj_type(btype, adj);
	rv = bas_type(btype);
	return rv;
}

NODEP
decl_enum()
{
	NODEP bas_type();

	fadvnode();     /* skip 'enum' */

	if (cur->e_token == ID) {       /* ignore tag */
		fadvnode();
	}
	if (cur->e_token == '{') {      /* new declaration */
		fadvnode();     /* skip '{' */
		en_decls();     /* global scope */
		if (cur->e_token != '}')
			error("expect }");
		else
			fadvnode();     /* skip '}' */
	}
	return bas_type(K_INT);
}

extern lineno;

NODEP
decl_su(isunion)
{
	register NODEP rv, tagp;
	NODEP *attab;

	fadvnode();     /* skip 'struct' or 'union' */

	attab = level ? &blktab->b_tags : &tagtab;
	tagp = NULL;
	if (cur->e_token == ID) {       /* hold on to ID node */
		tagp = cur;
		e_to_t(tagp);
		advnode();
		nnmadd(tagp, isunion ? ".U" : ".S");
	}
	if (cur->e_token == '{') {      /* new declaration */
		if (tagp == NULL) {     /* make fake name */
			tagp = allocnode();
			sprintf(tagp->n_name, isunion ? "%dU" :
					"%dS", lineno);
		}
		fadvnode();     /* skip '{' */
		if (rv = llook(*attab, tagp)) {
			freenode(tagp);
			if (rv->n_right) {
				errors("struct redefined", rv->n_name);
				freenode(rv->n_right);
				rv->n_right = NULL;
			}
		} else {		/* new defn */
			rv = tagp;
			rv->t_token = isunion ? K_UNION : K_STRUCT;
			rv->n_flags |= N_BRKPR; /* break print loops */
			putlist(attab, rv);
		}
		su_decls(&rv->n_right, isunion,
				&rv->t_size, &rv->t_aln);
		if (cur->e_token != '}')
			error("expect }");
		else
			fadvnode();     /* skip '}' */
	} else {		/* reference to old */
		if (tagp == NULL) {
			error("nonsense struct");
			goto out;
		}
		/* ANSI special decl
			struct <tag> ;
		   for hiding old tag within block */
		if (cur->e_token == ';' && level)
			rv = llook(*attab, tagp);
		else
			rv = alltags(tagp);
		if (rv == NULL) {       /* delayed tag */
			rv = tagp;
			rv->t_token = isunion ? K_UNION : K_STRUCT;
			rv->n_flags |= N_BRKPR; /* break print loops */
			putlist(attab, rv);
			goto out;
		} else
			freenode(tagp);
	}
out:
	return rv;
}

NODE *
alltags(np)
NODE *np;
{
	register NODE *bp;
	NODE *rv;

	for (bp=blktab; bp != NULL; bp = bp->n_next)
		if ((rv = llook(bp->b_tags, np)) != NULL)
			return rv;
	return llook(tagtab, np);
}

NODE *
allsyms(np)
NODE *np;
{
	register NODE *bp;
	NODE *rv;

	for (bp=blktab; bp != NULL; bp = bp->n_next)
		if ((rv = llook(bp->b_syms, np)) != NULL)
			return rv;
	return hlook(symtab, np);
}

sim_type(a,b)
register NODE *a, *b;
{
more:
	if (a == b)
		return 1;
	if (a == NULL || b == NULL)
		return 0;
	if (a->t_token != b->t_token)
		return 0;
	if (a->t_size != b->t_size && a->t_size && b->t_size)
		return 0;
	a = a->n_tptr;
	b = b->n_tptr;
	goto more;
}

/* 2nd def of same name at same level */
/* OK if one extern and types the same */
def2nd(old,new)
NODEP old, new;
{
	int osc, nsc;

	if (sim_type(old->n_tptr, new->n_tptr) == 0)
		goto bad;
	osc = old->e_sc;
	nsc = new->e_sc;
	if (nsc == K_EXTERN) {  /* works only if no further use allowed */
		freenode(new);
		return 0;
	}
	if (osc == K_EXTERN) {
		/* replace old def with new one */
		/* for now, just put new one on list too */
		return 1;
	}
bad:
	errorn("bad 2nd decl of ", new);
	/* use 2nd def so other stuff works */
	return 1;
}

/* saw fun but no body */
fix_fun(np)
NODE *np;
{
	if (np == NULL) return;
	if (np->n_tptr->t_token == '(') {       /* fix to extern */
		if (np->e_sc != K_TYPEDEF)
			np->e_sc = K_EXTERN;
	}
}

e_to_t(np)
NODE *np;
{
	int token;

	token = np->e_token;
	np->t_token = token;
	np->t_size = 0;
	np->t_aln = 0;
}
SHAR_EOF
cat << \SHAR_EOF > expr.c
/* Copyright (c) 1988 by Sozobon, Limited.  Author: Johann Ruegg
 *
 * Permission is granted to anyone to use this software for any purpose
 * on any computer system, and to redistribute it freely, with the
 * following restrictions:
 * 1) No charge may be made other than reasonable charges for reproduction.
 * 2) Modified versions must be clearly marked as such.
 * 3) The authors are not responsible for any harmful consequences
 *    of using this software, even if they result from defects in it.
 *
 *	expr.c
 *
 *	Expression parse routines
 *
 *	All routines return either NULL or a valid tree
 *		binop nodes have non-null left and right
 *		unop nodes have non-null left
 *
 *	Special nodes:
 *		'(' : function call.  left:name-expr right:args 
 *		',': if part of function arg list, ival:num. descendants
 *		'?' : ?switch.  left:test-expr right:':' part
 *		  ':' : left:true-expr right:false-expr
 *		TCONV: left:convertee tptr:type-list
 *		TSIZEOF: tptr:type-list
 *
 */

#include <stdio.h>
#include "param.h"
#include "nodes.h"
#include "tok.h"

extern NODEP cur;
NODEP getnode();
NODEP opt_follow();

extern int oflags[];
#define debug oflags['x'-'a']

advnode()
{
	cur = getnode();
}

fadvnode()
{
	freenode(cur);
	cur = getnode();
}

NODEP
gete_or_ty()
{
	NODEP getexpr(), makecast();
	NODEP rv;

	if (is_ty_start()) {
		rv = makecast();
		if (debug) {
			printf("TY_X");
			printnode(rv);
		}
		return rv;
	} else
		return getexpr();
}

/* call this for any expr including comma's */
NODEP
getexpr()
{
	NODEP np, get_f_expr();

	np = get_f_expr(0);
	return np;
}

NODEP
get_f_expr(flg)
int flg;
{
	NODEP assignx();
	register NODEP op, lpart, rpart;
	int i = 0;

	lpart = assignx();
	if (lpart == NULL) {
		return NULL;
	}
	i++;
more:
	if (cur->e_token != ',')
		return lpart;

	op = cur;  advnode();
	rpart = assignx();
	if (rpart == NULL) {
		error("',' expr syntax");
		return lpart;
	}
	i++;
	op->n_left = lpart;
	op->n_right = rpart;
	op->e_type = E_BIN;
	op->e_ival = flg ? i : 0;
	lpart = op;
	if (debug) {
		printf("COMMA");
		printnode(op);
	}
	goto more;
}

/* call this if you want expr w/o comma's */
NODEP
assignx()
{
	NODEP questx();
	register NODEP op, lpart, rpart;

	lpart = questx();
	if (lpart == NULL)
		return NULL;
	if (!isassign(cur->e_token) && cur->e_token != '=')
		return lpart;
	op = cur;  advnode();
	rpart = assignx();
	if (rpart == NULL) {
		error("'=op' expr syntax");
		return lpart;
	}
	op->n_left = lpart;
	op->n_right = rpart;
	op->e_type = E_BIN;
	if (debug) {
		printf("ASSIGN");
		printnode(op);
	}
	return op;
}

/* call this if you want expr w/o assign's or comma's */
/* i.e. constant-expression */
NODEP
questx()
{
	NODEP binary();
	register NODEP holdq, holdc;
	NODEP qpart, tpart, fpart;

	qpart = binary();
	if (qpart == NULL)
		return NULL;
	if (cur->e_token != '?')
		return qpart;
	holdq = cur;  advnode();
	tpart = questx();
	if (tpart == NULL || cur->e_token != ':') {
bad:
		error("'?:' expr syntax");
		return qpart;
	}
	holdc = cur;  advnode();
	fpart = questx();
	if (fpart == NULL) goto bad;
	holdc->n_left = tpart;
	holdc->n_right = fpart;
	holdc->e_type = E_BIN;
	holdq->n_left = qpart;
	holdq->n_right = holdc;
	holdq->e_type = E_BIN;
	if (debug) {
		printf("QUEST");
		printnode(holdq);
	}
	return holdq;
}

NODEP
binary()
{
	NODEP unary(), buildbin();
	register NODEP rv, op, e2;

	rv = unary();
	if (rv == NULL)
		return NULL;
	rv->e_prec = 0;
more:
	if (cur->e_prec == 0)	/* not binary op */
		return rv;
	op = cur;  advnode();
	e2 = unary();
	if (e2 == NULL) {
		error("bin-op expr syntax");
		return rv;
	}
	e2->e_prec = 0;
	rv = buildbin(rv, op, e2);
	if (debug) {
		printf("BINARY");
		printnode(rv);
	}
	goto more;
}

NODEP
buildbin(lpart, op, upart)
NODEP lpart, op, upart;
{
	register NODEP look, tail;
	NODEP rv;

	tail = NULL;
	look = lpart;
	for (look=lpart; op->e_prec < look->e_prec; look=look->n_right)
		tail = look;
	if (tail == NULL) {
		op->n_left = lpart;
		op->n_right = upart;
		rv = op;
	} else {
		tail->n_right = op;
		op->n_left = look;
		op->n_right = upart;
		rv = lpart;
	}
	op->e_type = E_BIN;
	return rv;
}

NODEP
unary()
{
	register NODEP tp,e1;
	NODEP primary();

	if (cur->e_flags & CAN_U) {
		tp = cur;  advnode();
		if (tp->e_prec) {  /* also have BINARY op */
			tp->e_token = UNARY tp->e_token;
			strcat(tp->n_name, "U");
		}
		tp->n_left = unary();
		tp->e_type = E_UNARY;
		goto check;
	} else
	switch (cur->e_token) {
	case '(':
		fadvnode();
		tp = gete_or_ty();
		if (cur->e_token != ')') {
			error("missing )");
		} else
			fadvnode();
		if (tp == NULL)
			return NULL;
		if (tp->e_token == TCONV && tp->n_left == NULL) {
			sprintf(tp->n_name, "cast to");
			tp->n_left = unary();
			tp->e_type = E_UNARY;
		} else {
			tp = opt_follow(tp);
			goto out;
		}
		goto check;
	case K_SIZEOF:
		tp = cur;
		advnode();
		if (cur->e_token == '(') { /* may be type expr */
			fadvnode();
			e1 = gete_or_ty();
			if (cur->e_token != ')') {
				error("missing )");
			} else
				fadvnode();
		} else
			e1 = unary();
		if (e1 == NULL) {
			error("sizeof expr syntax");
			return NULL;
		}
		if (e1->e_token == TCONV) {
			freeunit(tp);
			e1->e_token = TSIZEOF;
			sprintf(e1->n_name, "T-sizeof");
			tp = e1;
			tp->e_type = E_LEAF;
			goto out;
		} else {
			tp->e_type = E_UNARY;
			tp->n_left = e1;
		}
		goto check;
	default:
		tp = primary();
		goto out;
	}
check:
	if (tp == NULL) return NULL;
	if (tp->n_left == NULL) {
		error("u-op expr syntax");
		return NULL;
	}
out:
	if (debug) {
		printf("UNARY");
		printnode(tp);
	}
	return tp;
}

NODEP
primary()
{
	register NODEP e1;

	switch (cur->e_token) {
	case ID:
	case ICON:
	case FCON:
	case SCON:
		e1 = cur;
		e1->e_type = E_LEAF;
		advnode();
		break;
	case '(':
		fadvnode();
		e1 = getexpr();
		if (cur->e_token != ')')
			error("missing )");
		else
			fadvnode();
		break;
	default:
		e1 = NULL;
	}
	if (e1 == NULL)
		return NULL;
	return opt_follow(e1);
}

NODEP
opt_follow(np)
NODEP np;
{
	register NODEP tp, e1, t2;

	switch (cur->e_token) {
	case '[':
		tp = cur;  advnode();
		e1 = getexpr();
		if (cur->e_token != ']') {
			error("missing ]");
			return np;
		} else {
			t2 = cur;  advnode();
		}
		if (e1 == NULL) {
			error("empty []");
			return np;
		}
		t2->n_left = np;
		t2->n_right = e1;
		t2->e_type = E_BIN;
		t2->e_token = '+';
		strcpy(t2->n_name, "+ [");

		tp->n_left = t2;
		tp->e_type = E_UNARY;
		tp->e_token = STAR;
		strcpy(tp->n_name, "U*");

		goto out;
	case '(':
		tp = cur;
		advnode();
		e1 = get_f_expr(1);
		if (cur->e_token != ')')
			error("expect )");
		else
			fadvnode();
		tp->n_left = np;
		tp->n_right = e1;
		tp->e_type = E_SPEC;
		goto out;
	case '.':
	case ARROW:
		tp = cur;  advnode();
		if (cur->e_token != ID) {
			error("expect ID");
			return np;
		}
		tp->n_left = np;
		tp->n_right = cur;
		tp->e_type = E_SPEC;
		if (tp->e_token == ARROW) { /* make into (*X).Y */
			tp->e_token = '.';
			strcpy(tp->n_name, ".");

			t2 = allocnode();
			t2->e_token = STAR;
			t2->n_left = np;
			t2->e_type = E_UNARY;
			strcpy(t2->n_name, "U*");

			tp->n_left = t2;	
		}
		advnode();
		goto out;
	case DOUBLE '+':
	case DOUBLE '-':
		tp = cur;  advnode();
		tp->e_token = (tp->e_token == DOUBLE '+') ? POSTINC : POSTDEC;
		strcat(tp->n_name, "post");
		tp->n_left = np;
		tp->e_type = E_UNARY;
		goto out;
	default:
		return np;
	}
out:
	return opt_follow(tp);
}

/* restricted version of unary for declarations or coertions */
/* allows NULL primary part */
NODEP
declarator()
{
	register NODEP tp,e1;
	NODEP ty_primary(), ty_follow();

	if (cur->e_token == '*') {
		tp = cur;
		tp->e_token = UNARY tp->e_token;
		strcat(tp->n_name, "U");
		advnode();
		tp->n_left = declarator();
		return tp;
	} else
	switch (cur->e_token) {
	case '(':
		tp = cur;
		advnode();
		e1 = declarator();
		if (cur->e_token != ')') {
			error("expect )");
		} else
			fadvnode();
		if (e1 == NULL) {	/* special "fun of" */
			/* left and right already NULL */
			return ty_follow(tp);
		} else {
			freeunit(tp);
			return ty_follow(e1);
		}
	default:
		return ty_primary();
	}
}

/* restricted version of primary for "declarator" */
NODEP
ty_primary()
{
	register NODEP e1;
	NODEP ty_follow();

	switch (cur->e_token) {
	case ID:
		e1 = cur;
		advnode();
		break;
	case '(':
		fadvnode();
		e1 = declarator();
		if (cur->e_token != ')')
			error("expect )");
		else
			fadvnode();
		break;
	default:
		e1 = NULL;
	}
	return ty_follow(e1);
}

/* restricted version of opt_follow for 'declarator' */
/* allow null [] */
NODEP
ty_follow(np)
NODEP np;
{
	register NODEP tp, e1;
	NODEP ty_args();

	switch (cur->e_token) {
	case '[':
		tp = cur;
		advnode();
		e1 = questx();
		if (cur->e_token != ']')
			error("expect ]");
		else
			fadvnode();
		tp->n_left = np;
		tp->n_right = e1;
		goto out;
	case '(':
		tp = cur;
		advnode();
		e1 = ty_args();	/* allow args of fun to follow */
		if (cur->e_token != ')')
			error("expect )");
		else
			fadvnode();
		tp->n_left = np;
		tp->n_right = e1;
		goto out;
	default:
		return np;
	}
out:
	return ty_follow(tp);
}

/* called for args of function declaration or NULL */
NODEP
ty_args()
{
	NODEP opt_id();
	register NODEP rv, tail, new;

	rv = opt_id();
	if (rv == NULL)
		return NULL;
	tail = rv;
more:
	if (cur->e_token != ',')
		return rv;
	fadvnode();
	new = opt_id();
	if (new == NULL) {
		error("expect as-op value");
		return rv;
	}
	tail->n_left = new;
	tail = new;
	goto more;
}

NODEP
opt_id()
{
	NODEP rv;

	if (cur->e_token == ID) {
		rv = cur;
		advnode();
		return rv;
	} else
		return NULL;
}
SHAR_EOF
cat << \SHAR_EOF > fix.c
/* Copyright (c) 1988 by Sozobon, Limited.  Author: Johann Ruegg
 *
 * Permission is granted to anyone to use this software for any purpose
 * on any computer system, and to redistribute it freely, with the
 * following restrictions:
 * 1) No charge may be made other than reasonable charges for reproduction.
 * 2) Modified versions must be clearly marked as such.
 * 3) The authors are not responsible for any harmful consequences
 *    of using this software, even if they result from defects in it.
 *
 *	fix.c
 *
 *	Motorola has is not consistent in what operations allow
 *	which operands.  This section compensates for that --
 *	tries to find the best way to do something.
 */

#include <stdio.h>
#include "param.h"
#include "nodes.h"
#include "flags.h"
#include "bstok.h"
#include "gen.h"
#include "ops.h"

#define FAIL 0
#define OKAY 1

#define CL_IMM	IOPD
#define CL_AREG	AOPD
#define CL_DREG DOPD
#define CL_ADR	MOPD

#define RETAREG	0x100
#define RETDREG 0x200
#define RETLEFT	0x400
#define RETRIGHT 0x800

#define LISTMP	1
#define RISTMP	2
#define NDASSOC	4
#define CANRL	8
#define CANLR	0x10
#define CANRD	0x20
#define CANDL	0x40
#define CANLD	0x80
#define CANDD	0x100
#define CANDR	0x200

struct mtbl {
	int restr;
	char *code;
	int needregs;
} tbl2[] = {
	{LISTMP|CANRL,
		"\tN.S\t>A,<A\n", RETLEFT},
	{RISTMP|CANLR|NDASSOC,
		"\tN.S\t<A,>A\n", RETRIGHT},
	{CANRD,
		"\tmove.S\t<A,A\n\tN.S\t>A,A\n", RETDREG},
	{CANLD|NDASSOC,
		"\tmove.S\t>A,A\n\tN.S\t<A,A\n", RETDREG},
	/* only EOR and shifts get to here */
	{CANDL|LISTMP,
		"\tmove.S\t>A,R1\n\tN.S\tR1,A\n", RETLEFT|1},
	{CANDR|RISTMP|NDASSOC,
		"\tmove.S\t<A,R1\n\tN.S\tR1,A\n", RETRIGHT|1},
	{CANDD,
		"\tmove.S\t<A,A\n\tmove.S\t>A,R1\n\tN.S\tR1,A\n",
			RETDREG|1},
	{0}
};

struct mtbl tblmul[] = {
	{CANRL|LISTMP,
		"\tmulU\t>A,<A\n", RETLEFT},
	{CANLR|RISTMP,
		"\tmulU\t<A,>A\n", RETRIGHT},
	{CANRD,
		"\tmove.w\t>A,A\n\tmulU\t<A,A\n", RETDREG},
	{0}
};

struct mtbl tbldiv[] = {
	{CANRL|LISTMP,
		"\text.l\t<A\n\tdivs\t>A,<A\n", RETLEFT},
	{CANRD,
		"\tmove.w\t<A,A\n\text.l\tA\n\tdivs\t>A,A\n", RETDREG},
	{0}
};

struct mtbl tbludiv[] = {
	{CANRD,
		"\tclr.l\tA\n\tmove.w\t<A,A\n\tdivu\t>A,A\n", RETDREG},
	{0}
};

struct mtbl tblc[] = {
	{CANRL,
		"\tcmp.<S\t>A,<A\n", 0},
	{CANRD,
		"\tmove.<S\t<A,R1\n\tcmp.<S\t>A,R1\n", 1},
/* shouldnt get to here! */
	{CANDL,
		"\tmove.<S\t>A,R1\n\tcmp.<S\tR1,<A\n", 1},
	{CANDD,
		"\tmove.<S\t>A,R1\n\tmove.<S\t<A,R2\n\tcmp.<S\tR1,R2\n", 2},
	{0}
};

struct mtbl tblas[] = {
	{CANRL,
		"\tN.S\t>A,<A\n", RETLEFT},
	{CANDL,
		"\tmove.S\t>A,R1\n\tN.S\tR1,A\n", 1|RETLEFT},
	/* only MUL, DIV and shifts should get to here */
	{CANRD,
		"\tmove.S\t<A,A\n\tN.S\t>A,A\n\tmove.S\tA,<A\n",
			RETDREG},
	{CANLD|NDASSOC,
		"\tmove.S\t>A,A\n\tN.S\t<A,A\n\tmove.S\tA,<A\n",
			RETDREG},
	{CANDD,
	"\tmove.S\t<A,A\n\tmove.S\t>A,R1\n\tN.S\tR1,A\n\tmove.S\tA,<A\n",
			RETDREG|1},
	{0}
};

struct mtbl tblamul[] = {
	{CANRL,
		"\tmulU\t>A,<A\n", RETLEFT},
	{CANLR|RISTMP,
		"\tmulU\t<A,>A\n\tmove.w\t>A,<A\n", RETRIGHT},
	{CANRD,
		"\tmove.w\t<A,A\n\tmulU\t>A,A\n\tmove.w\tA,<A\n", RETDREG},
	{0}
};

struct mtbl tbladiv[] = {
	{CANRL,
		"\text.l\t<A\n\tdivs\t>A,<A\n", RETLEFT},
	{CANRD,
	"\tmove.w\t<A,A\n\text.l\tA\n\tdivs\t>A,A\n\tmove.w\tA,<A\n",
		RETDREG},
	{0}
};

struct mtbl tbluadiv[] = {
	{CANRD,
	"\tclr.l\tA\n\tmove.w\t<A,A\n\tdivu\t>A,A\n\tmove.w\tA,<A\n",
		RETDREG},
	{0}
};

struct mtbl tblamod[] = {
	{CANRL,
		"\text.l\t<A\n\tdivs\t>A,<A\n\tswap\t<A\n", RETLEFT},
	{CANRD,
  "\tmove.w\t<A,A\n\text.l\tA\n\tdivs\t>A,A\n\tswap\tA\n\tmove.w\tA,<A\n",
		RETDREG},
	{0}
};

struct mtbl tbluamod[] = {
	{CANRD,
  "\tclr.l\tA\n\tmove.w\t<A,A\n\tdivu\t>A,A\n\tswap\tA\n\tmove.w\tA,<A\n",
		RETDREG},
	{0}
};

class(np)
NODEP np;
{
	switch (np->g_token) {
	case ICON:
		return CL_IMM;
	case ONAME:
		return (np->g_flags & IMMEDID) ? CL_IMM : CL_ADR;
	case OREG:
		return (np->g_flags & IMMEDID) ? CL_IMM : CL_ADR;
	case PUSHER:
		return CL_ADR;
	case REGVAR:
		if (np->g_rno < AREG)
			return CL_DREG;
		else
			return CL_AREG;
	default:
		printf("Weird class ");
		return CL_IMM;
	}
}

int canswap;
NODEP matchnp;

fix_cmp(np, flags)
NODEP np;
{
	NODEP rp = np->n_right;

	/* special stuff for ICON 0 */
	if (rp->g_token == ICON && rp->g_offs == 0 &&
		(rp->g_flags & IMMEDID)) {
		addcode(np, "<Q");
		return OKAY;
	}
	canswap = 0;
	return fix_sub(np, flags, tblc);
}

fix2ops(np, flags)
NODEP np;
{
	canswap = flags & ASSOC;
	return fix_sub(np, flags, tbl2);
}

fixmul(np, flags)
NODEP np;
{
	return fix_sub(np, flags, tblmul);
}

fixdiv(np, flags)
NODEP np;
{
	return fix_sub(np, flags, np->g_ty == ET_U ? tbludiv : tbldiv);
}

fixmod(np, flags)
NODEP np;
{
	int r;

	r = fixdiv(np, flags);
	addcode(np, "\tswap\tA\n");
	return r;
}

fixamul(np, flags)
NODEP np;
{
	return fix_sub(np, flags, tblamul);
}

fixadiv(np, flags)
NODEP np;
{
	return fix_sub(np, flags, np->g_ty == ET_U ? tbluadiv : tbladiv);
}

fixamod(np, flags)
NODEP np;
{
	return fix_sub(np, flags, np->g_ty == ET_U ? tbluamod : tblamod);
}

fix_asn(np, flags)
NODEP np;
{
	canswap = 0;
	return fix_sub(np, flags, tblas);
}

fix_sub(np, flags, tbl)
register NODEP np;
struct mtbl *tbl;
{
	NODEP lp = np->n_left, rp = np->n_right;
	int lclass, rclass;
	register struct mtbl *p;
	int rv;

	lclass = class(lp);
	rclass = class(rp);
	matchnp = np;

	for (p = tbl; p->restr; p++)
		if ((rv = cando(flags, p->restr, lclass, rclass))) {
			dotbl(p, np);
			return OKAY;
		}
	printf("no code table match! ");
	return FAIL;
}

dotbl(p, np)
struct mtbl *p;
NODEP np;
{
	register int i, k;

	if (p->needregs) {
		i = p->needregs;
		if (i & RETLEFT)
			inherit(np);
		else if (i & RETRIGHT)
			rinherit(np);
		else if (i & RETAREG)
			retreg(np, ralloc(AREG));
		else if (i & RETDREG)
			retreg(np, ralloc(0));
		k = i & 7;
		while (k--)
			tempr(np, 0);
		k = (i/AREG) & 7;
		while (k--)
			tempr(np, AREG);
	}
	addcode(np, p->code);
}

#define canflag(l,r)	(l << cansh[r])

short cansh[] = {0, 0, 4, 0, 8, 0, 0, 0, 12};

cando(flags, restr, lc, rc)
register restr;
{
	NODEP lp = matchnp->n_left, rp = matchnp->n_right;

	if (restr & RISTMP) {
		if ((rc & (CL_DREG|CL_AREG)) == 0 ||
			istemp(rp->g_rno) == 0)
			return 0;
	} else if (restr & LISTMP) {
		if ((lc & (CL_DREG|CL_AREG)) == 0 ||
			istemp(lp->g_rno) == 0)
			return 0;
	}
	if (restr & NDASSOC) {
		if (canswap == 0)
			return 0;
	}
	if (restr & (CANLR|CANLD)) {
		flags |= quickflag(lp, flags);
	} else if (restr & (CANRL|CANRD)) {
		flags |= quickflag(rp, flags);
	}
	flags &= 0xfff;
	if (restr & CANLR) {
		if ((flags & canflag(lc,rc)) == 0)
			return 0;
	} else if (restr & CANRL) {
		if ((flags & canflag(rc,lc)) == 0)
			return 0;
	} else if (restr & CANRD) {
		if ((flags & canflag(rc,CL_DREG)) == 0)
			return 0;
	} else if (restr & CANDL) {
		if ((flags & canflag(CL_DREG,lc)) == 0)
			return 0;
	} else if (restr & CANLD) {
		if ((flags & canflag(lc,CL_DREG)) == 0)
			return 0;
	} else if (restr & CANDR) {
		if ((flags & canflag(CL_DREG,rc)) == 0)
			return 0;
	} else if (restr & CANDD) {
		if ((flags & DOPD) == 0)
			return 0;
	}
	return 1;
}

quickflag(np, flags)
NODEP np;
{
	long offs;

	if (np->g_token != ICON)
		return 0;
	offs = np->g_offs;
	if ((flags & QOPD) && np->g_offs >= 1 && np->g_offs <= 8)
		return IOPD;
	if ((flags & ONEOPM) && np->g_offs == 1)
		return IOPM;
	return 0;
}

/*
 * stuff to do field extract and field assign
 * Yes, this stuff can be optimized a lot more ... feel free
 */
fldget(np, flags)
register NODEP np;
{
	int how;

	how = 1;
	if (np->g_fldo == 0)
		how = 0;	/* no shift needed */
	else if (np->g_fldo > 8)
		how = 2;	/* shift too big for immediate */

	np->n_left->g_offs += np->g_offs;	/* major HACK, hope it works */

	retreg(np, ralloc(0));

	addcode(np, "\tmove\t<A,A\n");		/* get word */
	if (how)				/* shift to position */
		addcode(np, how==1 ?	"\tlsr\t#Y,A\n" :
			"\tlsr\t#8,A\n\tlsr\t#Z,A\n");
	addcode(np, "\tand\t#W,A\n");		/* mask off top */

	return OKAY;
}

fldasn(np, flags)
register NODEP np;
{
	int how;

	how = 1;
	if (np->g_fldo == 0)
		how = 0;	/* no shift needed */
	else if (np->g_fldo > 8)
		how = 2;	/* shift too big for immediate */

	retreg(np, ralloc(0));

	tempr(np, 0);

	addcode(np, "\tmove\t>A,A\n");		/* value */
	if (needmask(np))		/* mask off high bits */
		addcode(np, "\tand\t#W,A\n");
	if (how)	/* shift into position */
		addcode(np, how==1 ?	"\tlsl\t#Y,A\n" :
					"\tlsl\t#8,A\n\tlsl\t#Z,A\n");

	addcode(np, "\tmove\t<A,R1\n");		/* old value */
	addcode(np, "\tand\t#X,R1\n");		/* mask out old value */
	addcode(np, "\tor\tA,R1\n");		/* set new field */
	addcode(np, "\tmove\tR1,<A\n");		/* store new word */

	if (how && (flags & NOVAL_OK) == 0)	/* return value */
		addcode(np, how==1 ?	"\tlsr\t#Y,A\n" :
					"\tlsr\t#8,A\n\tlsr\t#Z,A\n");

	return OKAY;
}

needmask(np)
register NODEP np;
{
	NODEP lp = np->n_left;

	if (np->g_fldw + np->g_fldo >= 16)
		return 0;

	if (lp->g_token != ICON)
		return 1;
	if ((int)lp->g_offs & ~ones(np->g_fldw)) {
		warn("value too big for field");
		return 1;
	}
	return 0;
}
SHAR_EOF
cat << \SHAR_EOF > fun.c
/* Copyright (c) 1988 by Sozobon, Limited.  Author: Johann Ruegg
 *
 * Permission is granted to anyone to use this software for any purpose
 * on any computer system, and to redistribute it freely, with the
 * following restrictions:
 * 1) No charge may be made other than reasonable charges for reproduction.
 * 2) Modified versions must be clearly marked as such.
 * 3) The authors are not responsible for any harmful consequences
 *    of using this software, even if they result from defects in it.
 *
 *	fun.c
 *
 *	Handle function entry, exit, etc.
 *	Parse statements.
 *	Also, general syntax error recovery strategy.
 */

#include <stdio.h>
#include "param.h"
#include "tok.h"
#include "nodes.h"
#include "cookie.h"

#if MMCC
overlay "pass2"
#endif

extern NODE *cur;

int level;
NODE *blktab;
NODE *labels;

struct swittbl {
	NODEP	caselist;
	int	deflbl;
} *curswit;

int curbrk, curcont;
int funtopl, funbotl, funretl, funstrl;
NODEP funtyp;
int maxregs;
long maxlocs;

int skipon;

NODEP glb_decls();

extern int oflags[];
#define debugl oflags['l'-'a']
#define debugs oflags['s'-'a']
#define debugv oflags['v'-'a']

findtok(x)
{
	while (cur->e_token != EOFTOK && cur->e_token != x)
		fadvnode();
	if (cur->e_token == EOFTOK)
		exit(1);
}

extern NODEP symtab[];

program()
{
	NODEP last;

	skipon = 0;
more:
	last = glb_decls();
	if (cur->e_token == EOFTOK)
		return;
	if (last) skipon = 0;   /* saw something valid */
	if (last && last->n_tptr && last->n_tptr->t_token == '(') {
	/* possible function definition */
		if (debugs) {
			printf("FUN ");
			put_nnm(last);
		}
		out_fstart(last);
		last->e_sc = K_EXTERN;
		fun_start(last->n_tptr);
		args_blk(last->n_tptr->n_right);
		sub_block();
		fun_end();
		clr_lvl(); /* for args block */
		goto more;
	}
	/* error if get to here */
	if (last) {
		error("missing ;");
		goto more;
	} else {
		skip();
		goto more;
	}
}

fun_start(np)
NODEP np;
{
	NODEP functy();

	funtyp = functy(np);
	curbrk = curcont = -1;
	funtopl = new_lbl();
	funbotl = new_lbl();
	funretl = new_lbl();
	switch (funtyp->t_token) {
	case K_STRUCT:
	case K_UNION:
		funstrl = new_lbl();
		break;
	default:
		funstrl = 0;
	}
	maxregs = 0;
	maxlocs = 0;
	out_br(funbotl);
	def_lbl(funtopl);
}

fun_end()
{
	NODEP np;

	if (labels) {
		for (np = labels; np; np = np->n_next)
			if (np->c_defined == 0)
				errorn("undefined label", np);
		freenode(labels);
		labels = NULL;
	}
	def_lbl(funretl);
	out_fret(maxregs, funstrl);
	def_lbl(funbotl);
	out_fend(maxregs, maxlocs);
	out_br(funtopl);
	if (funstrl)
		out_fs(funstrl, funtyp->t_size);
}

skip()
{
	if (skipon == 0) {
		error("syntax (try skipping...)");
		skipon = 1;
	}
	fadvnode();
}

block()
{
	int some;
	int sawsome;

	some = loc_decls();
	if (cur->e_token == EOFTOK)
		return;
	if (some) skipon = 0;
more:
	sawsome = stmts();
	if (sawsome) skipon = 0;
	if (cur->e_token == '}') {
		if (blktab->b_regs > maxregs)
			maxregs = blktab->b_regs;
		if (blktab->b_size + blktab->b_tsize > maxlocs)
			maxlocs = blktab->b_size + blktab->b_tsize;
		return;
	}

	/* error if get to here */
	if (cur->e_token == EOFTOK || is_tykw(cur->e_token))
		/* get out of block */
		return;
	else {
		skip();
		goto more;
	}
}

clr_lvl()
{
	NODE *bp;

	level--;
	bp = blktab;
	blktab = bp->n_next;
	bp->n_next = NULL;
	if (debugl && bp->b_syms) {
		printf("local syms %d", level);
		printlist(bp->b_syms);
	}
	freenode(bp->b_syms);
	if (debugl && bp->b_tags) {
		printf("local tags %d", level);
		printlist(bp->b_tags);
	}
	freenode(bp->b_tags);
	freenode(bp);
}

eat(c)
{
	char *p = "assume X";

	if (cur->e_token == c)
		fadvnode();
	else {
		p[strlen(p) - 1] = c;
		error(p);
	}
}

sub_block()
{
	register NODE *new;

	if (debugs)
		printf("{ ");
	eat('{');
	level++;
	new = allocnode();
	new->n_next = blktab;
	sprintf(new->n_name, "sub{");
	blktab = new;
	block();
	clr_lvl();
	eat('}');
	if (debugs)
		printf("}\n");
}

args_blk(np)
NODEP np;
{
	register NODE *p;
	register NODE *new;
	NODE *tp;
	NODEP llook();
	long size;
	int rmask;

	size = 0;
	rmask = 0;
	new = allocnode();
	new->n_next = blktab;
	sprintf(new->n_name, "arg{");
	blktab = new;
	level++;
	loc_decls();
	/* make sure all decls were in arg list */
	for (p=new->b_syms; p != NULL; p = p->n_next)
		if (llook(np, p) == NULL)
			errorn("ID not param", p);
	/* now make any names not mentioned INT */
	/* and generate offsets and alloc regs */
	for (p=np; p != NULL; p = p->n_next) {
		if ((tp=llook(new->b_syms, p)) == NULL) {
			def_arg(&new->b_syms, p);
			tp = new->b_syms;
		}
		lc_size(&size, &rmask, tp);
		if (tp->e_sc == K_REGISTER)
			reg_arg(&rmask, tp);
		if (debugv) {
			printf("final o%ld r%d ", tp->e_offs, tp->e_rno);
			put_nnm(tp);
			putchar('\n');
		}
	}
	new->b_regs = rmask;
}

reg_arg(rp, xp)
int *rp;
NODEP xp;
{
	if (lc_reg(rp, xp) == 0) {      /* out of regs? */
		xp->e_sc = K_AUTO;
		return;
	}
	out_argreg(xp);
}


stmts()
{
	int didsome;

	didsome = 0;
	while (stmt())
		didsome++;
	return didsome;
}

stmt_bc(brk,cont)
{
	int svb, svc;

	svb = curbrk;
	svc = curcont;
	curbrk = brk;
	curcont = cont;

	stmt();

	curbrk = svb;
	curcont = svc;
}

stmt_b(brk)
{
	int svb;

	svb = curbrk;
	curbrk = brk;

	stmt();

	curbrk = svb;
}

/* do a single statement */
stmt()
{
	register tok;
	NODEP np;
	NODEP getexpr();
	int i;

more:
	tok = cur->e_token;
	if (is_stkw(tok)) {
		if (is_blkst(tok)) {
			i = blk_stmt();
		} else if (is_brast(tok)) {
			i = bra_stmt();
		} else if (is_lblst(tok)) {
			i = lbl_stmt();
		} else
			i = asm_stmt();
		if (i == 0)
			goto more;
		return 1;
	}
	else if (tok == '{') {
		sub_block();
		return 1;
	} else if (tok == ';') {
		fadvnode();
		return 1;
	}
	np = getexpr();
	if (np) {
		if (cur->e_token == ':') {
			fadvnode();
			label(np);
			goto more;
		}
		expr_stmt(np);
		if (cur->e_token != ';')
			error("missing ;");
		else
			fadvnode();
		return 1;
	}
	return 0;
}

expr_stmt(np)
NODEP np;
{
	if (debugs) {
		printf("E_STMT ");
		if (debugs > 1)
			printnode(np);
	}
	do_expr(np, FORSIDE);
}

label(np)
NODEP np;
{
	register NODEP tp;
	NODEP llook();

	if (debugs) {
		printf("LABEL ");
		if (debugs > 1)
			printnode(np);
	}
	if (np->e_token != ID) {
		error("weird label");
		return;
	}
	tp = llook(labels, np);
	if (tp) {
		freenode(np);
		if (tp->c_defined) {
			error("duplicate label");
			return;
		}
	} else {
		putlist(&labels, np);
		tp = np;
		tp->c_casel = new_lbl();
	}
	tp->c_defined = 1;
	def_lbl(tp->c_casel);
}


extern int lineno;

blk_stmt()
{
	register tok;
	int l1, l2, l3;
	NODEP e1, e2, e3;
	NODEP opt_expr(), paren_expr(), def_type();
	struct swittbl locswit, *oldp;
	int svline, svline2;

	tok = cur->e_token;
	fadvnode();
	switch (tok) {
	case K_IF:
		if (debugs)
			printf("IF ");
		l1 = new_lbl();
		e1 = paren_expr();
		gen_brf(e1, l1);
		eat(')');
		stmt();
		opt_else(l1);
		return 1;
	case K_WHILE:
		if (debugs)
			printf("WHILE ");
		e1 = paren_expr();
		l1 = new_lbl();
		l2 = new_lbl();

		def_lbl(l1);
		gen_brf(e1,l2);
		eat(')');

		stmt_bc(l2,l1);

		out_br(l1);
		def_lbl(l2);
		return 1;
	case K_DO:
		if (debugs)
			printf("DO ");
		l1 = new_lbl();
		l2 = new_lbl();
		l3 = new_lbl();
		def_lbl(l1);

		stmt_bc(l3,l2);

		def_lbl(l2);
		eat(K_WHILE);
		e1 = paren_expr();
		gen_brt(e1, l1);
		eat(')');
		eat(';');
		def_lbl(l3);
		return 1;
	case K_FOR:
		if (debugs)
			printf("FOR ");
		l1 = new_lbl();
		l2 = new_lbl();
		l3 = new_lbl();
		eat('(');
		e1 = opt_expr();
		expr_stmt(e1);
		eat(';');
		def_lbl(l1);
		e2 = opt_expr();
		if (e2)
			gen_brf(e2,l3);
		eat(';');
		e3 = opt_expr();        /* save for later */
		svline = lineno;
		eat(')');

		stmt_bc(l3,l2);

		def_lbl(l2);

		svline2 = lineno;
		lineno = svline;
		expr_stmt(e3);
		lineno = svline2;

		out_br(l1);
		def_lbl(l3);
		return 1;
	case K_SWITCH:
		if (debugs)
			printf("SWITCH ");
		e1 = paren_expr();
		l1 = new_lbl();
		l2 = new_lbl();
		to_d0(e1, def_type());
		eat(')');

		out_br(l2);
		oldp = curswit;
		curswit = &locswit;
		locswit.caselist = NULL;
		locswit.deflbl = -1;

		stmt_b(l1);

		out_br(l1);
		def_lbl(l2);
		gen_switch(locswit.caselist, locswit.deflbl);
		curswit = oldp;
		def_lbl(l1);
		return 1;
	case K_ELSE:
		error("unexpected 'else'");
		fadvnode();
		return 0;
	}
}

NODEP
paren_expr()
{
	NODEP np;
	NODEP need_expr();

	eat('(');
	np = need_expr();
	return np;
}

bra_stmt()
{
	register tok;
	NODEP np, tp;
	NODEP opt_expr(), llook();

	tok = cur->e_token;
	fadvnode();
	switch (tok) {
	case K_BREAK:
		if (debugs)
			printf("BRK");
		eat(';');
		out_br(curbrk);
		return 1;
	case K_CONTINUE:
		if (debugs)
			printf("CONT ");
		eat(';');
		out_br(curcont);
		return 1;
	case K_RETURN:
		if (debugs)
			printf("RETURN ");
		np = opt_expr();
		if (np) {
			if (funstrl)
				ret_stru(np);
			else
				to_d0(np, funtyp);
		}
		out_br(funretl);
		eat(';');
		return 1;
	case K_GOTO:
		if (debugs)
			printf("GOTO ");
		np = cur;  advnode();
		if (np->e_token != ID)
			error("bad goto");
		else {
			tp = llook(labels, np);
			if (tp) {
				freenode(np);
			} else {
				tp = np;
				putlist(&labels, tp);
				tp->c_casel = new_lbl();
			}
			out_br(tp->c_casel);
		}
		eat(';');
		return 1;
	}
}

lbl_stmt()
{
	register tok;
	NODEP need_expr(), np;
	int l1, i;

	l1 = new_lbl();
	tok = cur->e_token;
again:
	fadvnode();
	switch (tok) {
	case K_CASE:
		if (debugs)
			printf("CASE ");
		np = need_expr();
		i = conxval(np);
		add_case(i,l1);
		eat(':');
		break;
	case K_DEFAULT:
		if (debugs)
			printf("DEFAULT ");
		if (curswit->deflbl >= 0)
			error("multiple 'default'");
		curswit->deflbl = l1;
		eat(':');
	}
	tok = cur->e_token;	/* lookahead for more cases */
	if (tok == K_CASE || tok == K_DEFAULT)
		goto again;
	def_lbl(l1);
	return 0;
}

asm_stmt()
{
	NODEP np, getexpr();

	fadvnode();
	np = getexpr();
	if (np == NULL || np->e_token != SCON) {
		error("bad asm() func");
	} else {
		out_asm(np);
		freenode(np);
	}
	eat(';');
}

NODEP
opt_expr()
{
	NODE *np, *getexpr();

	np = getexpr();
	if (np) {
		if (debugs) {
			printf("OXPR ");
			if (debugs > 1)
				printnode(np);
		}
	}
	return np;
}

NODEP
need_expr()
{
	NODE *np, *getexpr();

	np = getexpr();
	if (np) {
		if (debugs) {
			printf("NXPR ");
			if (debugs > 1)
				printnode(np);
		}
	} else
		error("need expr");
	return np;
}

opt_else(l1)
{
	int l2;

	if (cur->e_token == K_ELSE) {
		if (debugs)
			printf("ELSE ");
		fadvnode();
		l2 = new_lbl();
		out_br(l2);
		def_lbl(l1);
		stmt();
		def_lbl(l2);
	} else
		def_lbl(l1);
}

add_case(val, lbl)
{
	NODEP np, last, p;

	np = allocnode();
	np->c_casev = val;
	np->c_casel = lbl;
	sprintf(np->n_name, "%d:%d", val, lbl);

	last = NULL;
	for (p = curswit->caselist; p; last=p, p=p->n_next)
		if (p->c_casev == val) {
			error("duplicate case");
			return;
		} else if (p->c_casev > val)
			break;
	if (last) {
		last->n_next = np;
		np->n_next = p;
	} else {
		curswit->caselist = np;
		np->n_next = p;
	}
	if (debugs) {
		printf("CASELIST\n");
		printnode(curswit->caselist);
	}
}

to_d0(np, typ)
NODEP np, typ;
{
	NODEP tp;

	tp = allocnode();
	tp->e_token = TCONV;
	tp->n_tptr = typ;
	tp->n_flags |= N_COPYT;
	tp->n_left = np;
	tp->e_type = E_UNARY;
	strcpy(tp->n_name, "r cast");

	do_expr(tp, IND0);
}

ret_stru(np)
NODEP np;
{
	p2_expr(&np);
	if (same_type(np->n_tptr, funtyp) == 0) {
		error("bad struct return type");
		return;
	}
	genx(np, RETSTRU);
}
SHAR_EOF
cat << \SHAR_EOF > g2.c
/* Copyright (c) 1988 by Sozobon, Limited.  Author: Johann Ruegg
 *
 * Permission is granted to anyone to use this software for any purpose
 * on any computer system, and to redistribute it freely, with the
 * following restrictions:
 * 1) No charge may be made other than reasonable charges for reproduction.
 * 2) Modified versions must be clearly marked as such.
 * 3) The authors are not responsible for any harmful consequences
 *    of using this software, even if they result from defects in it.
 *
 *	g2.c
 *
 *	Generate code for binary nodes.
 */

#include <stdio.h>
#include "param.h"
#include "nodes.h"
#include "flags.h"
#include "bstok.h"
#include "gen.h"
#include "ops.h"

#define FAIL	0
#define OKAY	1

extern int cookflags[];

#define isimmed(np)     ((np)->g_flags & IMMEDID)
#define isareg(np)      ((np)->g_token == REGVAR && (np)->g_rno >= AREG)

struct bop {
	char *s_op, *u_op;
	int opflags;
} bops[] = {
	{"muls",        "mulu", EOPD |ASSOC},
	{"divs",        "divu", EOPD},
	{"divs",        "divu", EOPD},
	{"and",         "and",  EOPD|DOPE|IOPE |ASSOC},
	{"or",          "or",   EOPD|DOPE|IOPE |ASSOC},
	{"eor",         "eor",  DOPE|IOPE |ASSOC},
	{"add",         "add",  EOPD|DOPE|EOPA|IOPE|AOPA|AOPD |ASSOC},
	{"sub",         "sub",  EOPD|DOPE|EOPA|IOPE|AOPA|AOPD},
	{"asl",         "lsl",  DOPD|QOPD|ONEOPM},
	{"asr",         "lsr",  DOPD|QOPD|ONEOPM},
};

char *tstnm[] = {
	"lt",           /* < */
	"gt",           /* > */
	"le",           /* <= */
	"ge",           /* >= */
	"eq",           /* == */
	"ne",           /* != */
};

int tstx[] = {
	B_LT, B_GT, B_LE, B_GE, B_EQ, B_NE
};

char *utstnm[] = {
	"cs",           /* < */
	"hi",           /* > */
	"ls",           /* <= */
	"cc",           /* >= */
	"eq",           /* == */
	"ne",           /* != */
};

int utstx[] = {
	B_ULT, B_UGT, B_ULE, B_UGE, B_EQ, B_NE
};

b_eval(np, cookie)
register NODEP np;
{
	NODEP lp = np->n_left, rp = np->n_right;
	NODEP tp;
	int lcook = FORADR, rcook = FORADR;

	switch (np->g_token) {          /* special cookies */
	case DOUBLE '&':
	case DOUBLE '|':
		lcook = rcook = FORCC;
		break;
	case '?':
		lcook = FORCC;
		break;
	case '(':
		rcook = FORPUSH;
		break;
	case ',':
		if (np->g_offs) /* function args */
			lcook = rcook = FORPUSH;
		else {
			lcook = FORSIDE;
			rcook = cookie;
		}
		break;
	case '=':
		rcook = FORIMA;
		break;
	case '+':
	case '-':
		tp = rp;
		while (tp->g_token == TCONV && tp->g_ty != ET_F)
			tp = tp->n_left;
		if (tp->g_token == ICON)
			lcook = FORIMA;
		break;
	}

	if (np->g_type == EV_LR) {
		if (eval(lp,lcook) == FAIL)
			return FAIL;
		freetmps(lp);
		if (eval(rp,rcook) == FAIL)
			return FAIL;
		freetmps(rp);
	} else if (np->g_type == EV_RL) {
		if (eval(rp,rcook) == FAIL)
			return FAIL;
		freetmps(rp);
		if (eval(lp,lcook) == FAIL)
			return FAIL;
		freetmps(lp);
	} else {	/* EV_LRSEP */
		if (eval(lp,lcook) == FAIL)
			return FAIL;
		freetmps(lp);
		free1(NULL, lp);
		if (eval(rp,rcook) == FAIL)
			return FAIL;
		freetmps(rp);
	}
	return b_sube(np, cookflags[cookie]);
}

b_sube(np, flags)
register NODEP np;
{
	NODEP lp = np->n_left, rp = np->n_right;
	register int i, r;
	int argsize;
	char buf[40];

	if (isassign(np->g_token))
		return as_eval(np);

	switch (np->g_token) {
	case '=':
		if (specasn(np, flags) || strasn(np))
			return OKAY;
		inherit(np);
		addcode(np, "\tmove.S\t>A,<A\n");
		return OKAY;

	case '(':
		argsize = argmod(rp);
		free1(NULL,rp);
		if (np->g_ty == ET_A) {         /* struct returned */
			frc_ral(AREG);
			indir(np, AREG);
		} else {
			frc_ral(0);
			retreg(np, 0);
		}
		 externfuncref(np);
		sprintf(buf, "\tjsr\t<A\n\tadd.w\t#%d,sp\n", argsize);
		addcode(np, buf);
		return OKAY;

	case ',':
		if (np->g_offs == 0)    /* normal ',' */
			rinherit(np);
		return OKAY;

	case DOUBLE '&':
		free1(NULL, rp);
		r = ralloc(0);
		retreg(np, r);
		holdlbls(np);
		np->g_betw = iscc(lp) ? "<FL1\n" :
			"<Q\tbeq\tL1\n";
		addcode(np, iscc(rp) ? ">FL1\n" :
			">Q\tbeq\tL1\n");
		addcode(np, "\tmoveq\t#1,A\n");
		addcode(np, "\tbra\tL2\nL1:\tclr\tA\nL2:\n");
		return OKAY;

	case DOUBLE '|':
		free1(NULL, rp);
		r = ralloc(0);
		retreg(np, r);
		holdlbls(np);
		np->g_betw = iscc(lp) ? "<TL1\n" :
			"<Q\tbne\tL1\n";
		addcode(np, iscc(rp) ? ">TL1\n" :
			">Q\tbne\tL1\n");
		addcode(np, "\tclr\tA\n");
		addcode(np, "\tbra\tL2\nL1:\tmoveq\t#1,A\nL2:\n");
		return OKAY;

	case '?':
		rinherit(np);
		rinhlbls(np);
		np->g_betw = iscc(lp) ? "<FL1\n" : "<Q\tbeq\tL1\n";
		return OKAY;

	case ':':
		free1(NULL, rp);
		r = ralloc(0);
		retreg(np, r);
		holdlbls(np);
		np->g_betw = same_a(np, lp) ?
			"\tbra\tL2\nL1:\n"  :
			"\tmove.S\t<A,A\n\tbra\tL2\nL1:\n";
		if (!same_a(np, rp))
			addcode(np, "\tmove.S\t>A,A\n");
		addcode(np, "L2:\n");
		return OKAY;

	case '<':
		i = 0;	goto dotst;
	case '>':
		i = 1;	goto dotst;
	case LTEQ:
		i = 2;	goto dotst;
	case GTEQ:
		i = 3;	goto dotst;
	case DOUBLE '=':
		i = 4;	goto dotst;
	case NOTEQ:
		i = 5;
dotst:
		fix_cmp(np, EOPD|EOPA|IOPE|AOPA|AOPD);
		if (flags & CC_OK) {
			np->g_token = (lp->g_ty == ET_U ?
			utstx[i] : tstx[i]) + BR_TOK;
		} else {
			strcpy(np->n_name, lp->g_ty == ET_U ?
			utstnm[i] : tstnm[i]);
			r = ralloc(0);
			retreg(np, r);
			addcode(np, "\tsN\tA\n\tand.w\t#1,A\n");
		}
		return OKAY;

	case '*':
		return fixmul(np, bops[0].opflags);
	case '/':
		return fixdiv(np, bops[1].opflags);
	case '%':
		return fixmod(np, bops[2].opflags);
	case '&':       i = 3;  goto doop;
	case '|':       i = 4;  goto doop;
	case '^':       i = 5;  goto doop;
	case '+':
		if (optadd(np, flags, 1))
			return OKAY;
			i = 6;	goto doop;
	case '-':
		if (optadd(np, flags, -1))
			return OKAY;
			i = 7;	goto doop;
	case DOUBLE '<':i = 8;  goto doop;
	case DOUBLE '>':i = 9;
doop:
		strcpy(np->n_name, np->g_ty == ET_U ?
			bops[i].u_op : bops[i].s_op);
		r = fix2ops(np, bops[i].opflags);
		cc_hack(np);
		return r;
	case FIELDAS:
		return fldasn(np, flags);
	default:
		printf("Weird b_eval %s ", np->n_name);
		return FAIL;
	}
}

as_eval(np)
register NODEP np;
{
	NODEP rp = np->n_right;
	register int op, i, r;

	rp = np->n_right;

	op = np->g_token;
	op -= ASSIGN 0;
	switch (op) {

	/* these get unfolded now */
	case '*':
			return fixamul(np, bops[0].opflags);
	case '/':
			return fixadiv(np, bops[1].opflags);
	case '%':
			return fixamod(np, bops[2].opflags);
	case '&':       i = 3;  goto doop;
	case '|':       i = 4;  goto doop;
	case '^':       i = 5;  goto doop;
	case '+':       i = 6;  goto doop;
	case '-':       i = 7;  goto doop;
	case DOUBLE '<':i = 8;  goto doop;
	case DOUBLE '>':i = 9;
doop:
		strcpy(np->n_name, np->g_ty == ET_U ?
			bops[i].u_op : bops[i].s_op);
		r = fix_asn(np, bops[i].opflags);
		cc_hack(np);
		return r;

	default:
		printf("Weird as_eval %s ", np->n_name);
		return FAIL;
	}
}

rinherit(np)
register NODEP np;
{
	register NODEP rp = np->n_right;

	np->g_token = rp->g_token;
	np->g_offs = rp->g_offs;
	np->g_rno = rp->g_rno;
	np->g_flags |= RCHILDNM | (rp->g_flags & IMMEDID);
}

argmod(np)
register NODEP np;
{
	int size = 0;

	if (np->g_token == ',') {
		np->g_type = EV_RL;
		size += argmod(np->n_right);
		size += argmod(np->n_left);
		return size;
	}
	size += onearg(np);
	return size;
}

onearg(np)
register NODEP np;
{
	int rv;

	/* hack small ICON */
	if (np->g_sz == 1 && np->g_token == ICON)
		np->g_sz = 2;
	/* hack push of 0 */
	if (np->g_token == ICON && np->g_offs == 0 && isimmed(np)) {
		addcode(np, "\tclr.S\t-(sp)\n");
		return (int)np->g_sz;
	}
	/* hack push of #OREG */
	if (np->g_token == OREG && isimmed(np)) {
		np->g_flags &= ~IMMEDID;
		addcode(np, "\tpea\tA\n");
		return 4;
	}

	if (np->g_ty == ET_A) {
		rv = np->g_bsize;
		strpush(np);
		freetmps(np);
		free1(NULL,np);
		return rv;
	}

	switch (np->g_sz) {
	case 1:
		addcode(np,
		   "\tmove.b\tA,d0\n\text.w\td0\n\tmove.w\td0,-(sp)\n");
		return 2;
	case 2:
		addcode(np,
		   "\tmove.w\tA,-(sp)\n");
		return 2;
	default:
		addcode(np,
		   "\tmove.l\tA,-(sp)\n");
		return 4;
	}
}

#define MAXD DRV_START
#define MAXA (ARV_START-AREG)
#define NEEDALL (MAXA*AREG + MAXD)

order(np)
register NODEP np;
{
	int l, r;

	switch (np->g_type) {
	case E_BIN:
		order(np->n_right);
		r = np->n_right->g_needs;
	case E_UNARY:
		order(np->n_left);
		l = np->n_left->g_needs;
		break;
	default:	/* leaf */
		np->g_type = EV_NONE;
		np->g_needs = 0;
		return;
	}

	if (np->g_type == E_UNARY) {
		switch (np->g_token) {
		case STAR:
			np->g_needs = merge(l,AREG);
			break;
		case '(':
			np->g_needs = NEEDALL;
			break;
		case POSTINC:
		case POSTDEC:
		case '!':
			np->g_needs = merge(l,1);
			break;
		case '.':
			if (np->g_fldw) {
				np->g_needs = merge(l,1);
				break;
			}
			/* else fall through */
		default:
			np->g_needs = l;
		}
		np->g_type = EV_LEFT;
		return;
	}

/* at this point, have binary node */

	switch (np->g_token) {
	case DOUBLE '&':
	case DOUBLE '|':
	case '?':
	case ':':
		/* always left-right, no extra regs */
		np->g_type = EV_LRSEP;
		np->g_needs = merge(1, merge(l,r));
		return;
	case ',':
		np->g_needs = merge(l, r);
		np->g_type = EV_LRSEP;
		return;
	case '(':
		np->g_needs = NEEDALL;
		break;
	case '^':
	case DOUBLE '<':
	case DOUBLE '>':
	case ASSIGN '/':
	case ASSIGN DOUBLE '<':
	case ASSIGN DOUBLE '>':
		np->g_needs = merge(bin(l,r), 2);
		break;
	default:
		np->g_needs = merge(bin(l,r), 1);
	}

	if (isassign(np->g_token) || np->g_token == '=')
		np->g_type = EV_RL;	/* NO PUSHER's on L */
	else
		np->g_type = worst_1st(l, r);
	flag_saves(np, l, r);
}

flag_saves(np, l, r)
NODEP np;
{
	NODEP *cpp;
	register int other;

	if (np->g_type == EV_LR) {
		cpp = &np->n_left;
		other = r;
	} else {
		cpp = &np->n_right;
		other = l;
	}
	if ((other & 7) >= MAXD || (other/AREG) >= MAXA)
		addtmp(np, cpp);
}

addtmp(np, cpp)
NODEP np, *cpp;
{
	NODEP cp, tp;
	NODEP copyone();

	cp = *cpp;
	tp = copyone(cp);
	tp->n_left = cp;
	*cpp = tp;
	tp->g_token = PUSHER;
	strcpy(tp->n_name, "pusher");
	tp->g_type = EV_LEFT;
}

worst_1st(l,r)
{
	int ld, rd;

	ld = l & 7;
	rd = r & 7;
	if (rd > ld)
		return EV_RL;
	if (r > l)
		return EV_RL;
	return EV_LR;
}

bin(l,r)
{
	int la, ra, na;
	int ld, rd, nd;

	la = l/AREG;
	ra = r/AREG;
	ld = l & 7;
	rd = r & 7;
	na = la > ra ? la : ra;
	if (ld == rd)
		nd = ld == MAXD ? MAXD : ld+1;
	else
		nd = ld > rd ? ld : rd;
	return na*AREG + nd;
}

merge(need, have)
{
	int na, nd, ha, hd, xa, xd;

	na = need/AREG;
	ha = have/AREG;
	nd = need & 7;
	hd = have & 7;
	xa = na > ha ? na : ha;
	xd = nd > hd ? nd : hd;
	return xa*AREG + xd;
}

holdlbls(np)
NODEP np;
{
	np->g_bsize = new_lbl();
	new_lbl();
}

rinhlbls(np)
NODEP np;
{
	np->g_bsize = np->n_right->g_bsize;
}

/* limited version of same address check
	assume one of these is a temp register */
same_a(p1, p2)
NODEP p1, p2;
{
	if (p1->g_token != p2->g_token)
		return 0;
	if (p1->g_rno != p2->g_rno)
		return 0;
	return 1;
}

optadd(np, flags, sign)
register NODEP np;
{
	NODEP lp = np->n_left, rp = np->n_right;

	if (rp->g_token != ICON)
		return 0;
	if (isimmed(lp) && isimmed(rp)) {
		switch (lp->g_token) {
		case OREG:
		case ONAME:
			inherit(np);
			if (sign == -1)
				rp->g_offs = -rp->g_offs;
			np->g_offs += rp->g_offs;

			if ((flags & IMMA_OK) == 0)
				imm_oreg(np);
			return 1;
		default:
			return 0;
		}
	}
	return 0;
}

iscc(np)
NODEP np;
{
	return (np->g_token >= BR_TOK) || (np->g_flags & SIDE_CC);
}

cc_hack(np)
NODEP np;
{
	if (isareg(np))
		return;
	np->g_flags |= SIDE_CC;
}

cctok(np)
NODEP np;
{
	if (np->g_token >= BR_TOK)
		return np->g_token - BR_TOK;
	if (np->g_flags & SIDE_CC)
		return B_NE;
	printf("cctok error ");
	return 0;
}
SHAR_EOF
#	End of shell archive
exit 0
-- 
Bob Page, U of Lowell CS Dept.  page@swan.ulowell.edu  ulowell!page
Have five nice days.