view os9/mc09/mc2.c @ 104:096b3fc7aa66

fix
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Fri, 28 Dec 2018 17:43:55 +0900
parents 09148bb27659
children 6eef99bb4771
line wrap: on
line source


#define DEBUG	error(-1)

#include "mclibos9.c"

#define INT	(-1)
#define CHAR	(-2)
#define UNSIGNED	(-3)
#define POINTER (-4)
#define ARRAY	(-5)
#define STRUCT	(-6)
#define UNION	(-7)
#define FUNCTION	(-8)
#define EMPTY	(-9)

#define STATIC	(-10)
#define GOTO	(-11)
#define RETURN	(-12)
#define BREAK	(-13)
#define CONTINUE	(-14)
#define IF	(-15)
#define ELSE	(-16)
#define FOR	(-17)
#define DO	(-18)
#define WHILE	(-19)
#define SWITCH	(-20)
#define CASE	(-21)
#define DEFAULT (-22)
#define RESERVE (-23)
#define TAG	(-24)
#define FIELD	(-25)
#define IDENT	(-26)
#define STRING	(-27)
#define MACRO	(-28)
#define BLABEL	(-29)
#define FLABEL	(-30)
#define TYPEDEF (-31)
#define SIZEOF	(-32)
#define TYPE	(-33)
#define LONG	(-34)
#define SHORT	(-35)

#define TOP	0
#define GDECL	1
#define GSDECL	2
#define GUDECL	3
#define ADECL	4
#define LDECL	5
#define LSDECL	6
#define LUDECL	7
#define STADECL 8
#define STAT	9
#define GTDECL	10
#define LTDECL	11

#define GVAR	1
#define RGVAR	2
#define CRGVAR	3
#define LVAR	4
#define RLVAR	5
#define CRLVAR	6
#define CONST	7
#define FNAME	8
#define INDIRECT	9
#define RINDIRECT	10
#define CRINDIRECT	11
#define ADDRESS 12
#define MINUS	13
#define LNOT	14
#define BNOT	15
#define INC	16
#define POSTINC 17
#define PREINC	18
#define CPOSTINC	19
#define CPREINC 20
#define DEC	21
#define CPOSTDEC	22
#define CPREDEC 23
#define MUL	24
#define UMUL	25
#define DIV	26
#define UDIV	27
#define MOD	28
#define UMOD	29
#define ADD	30
#define SUB	31
#define RSHIFT	32
#define URSHIFT 33
#define LSHIFT	34
#define ULSHIFT 35
#define GT	36
#define UGT	37
#define GE	38
#define UGE	39
#define LT	40
#define ULT	41
#define LE	42
#define ULE	43
#define EQ	44
#define NEQ	45
#define BAND	46
#define EOR	47
#define BOR	48
#define LAND	49
#define LOR	50
#define COND	51
#define ASS	52
#define CASS	53
#define ASSOP	54
#define CASSOP	55
#define COMMA	56
#define LPAR	57
#define RPAR	58
#define LBRA	59
#define RBRA	60
#define LC	61
#define RC	62
#define COLON	63
#define SM	64
#define PERIOD	65
#define ARROW	66

#define US	1
#define AS	100

#define FILERR	1
#define DCERR	2
#define STERR	3
#define EXERR	4
#define CNERR	5
#define CHERR	6
#define GSERR	7
#define LSERR	8
#define STRERR	9
#define LNERR	10
#define EOFERR	11
#define MCERR	12
#define INCERR	13
#define HPERR	14
#define TYERR	15
#define LVERR	16
#define UDERR	17
#define OPTION	18

#define GSYMS	450
#define LSYMS	50

#define HEAPSIZE	700
#define CHEAPSIZE	3000
#define LBUFSIZE	256

#define FILES 3

int sym,ch,chsave,type,mode,gfree,lfree,mflag,lineno,glineno;
int labelno,gpc,lvar,disp;
int symval,args,heap[HEAPSIZE];
int blabel,clabel,dlabel,cslabel,ilabel,control,ac,ac2,lsrc,chk,asmf;

unsigned hash;

char linebuf[LBUFSIZE],cheap[CHEAPSIZE],*chptr,*chptrsave;
char name[9],*cheapp,**av,/*obuf[320],*/*sptr,escape();

FILE *obuf;

typedef struct nametable {
	char nm[9];
	int sc,ty,dsp; } NMTBL;

NMTBL ntable[GSYMS+LSYMS],*nptr,*gnptr,*decl0(),*decl1(),*lsearch(),*gsearch();

struct {int fd,ln;/*char fcb[320]*/FILE *fcb;} *filep,filestack[FILES];

main(argc,argv)
int argc;
char **argv;
{NMTBL *nptr;
int i;
char *ccout,*modname;
	if(argc==1) exit(1);
	lsrc = chk = asmf = 0;
	ccout = "C.OUT";
	modname = "aout";
	ac=argc;
	av=argv;
	for (ac2=1; (ac2 < ac) && (*av[ac2] == '-'); ++ac2)
		switch (*(av[ac2]+1))
		{case 'S': case 's':
			lsrc = 1;
			break;
		case 'O': case 'o':
			ccout = av[ac2]+2;
			break;
                case 'M': case 'm':
                       modname = av[ac2]+2;
                       break;
		case 'C': case 'c':
			chk = 1;
			break;
		default:
			error(OPTION);
			exit(1);
		}
	fclose(stdout);
        if (!chk) {
              if ( (obuf = fopen(ccout,"w")) == NULL ) error(FILERR);
                else {
                     printf("\tmod   _eom,_name,_tylg,_atrv,_start,_GLOBALS\n");    /* os9 module header */
                     printf("_name      fcs   /%s/\n\tfcb 0\n",modname);
                }
        }
	init();
	while(1)
	{	for (nptr = &ntable[GSYMS],i=LSYMS; i--;)
			(nptr++)->sc = EMPTY;
		mode=TOP;
		while(getsym()==SM);
		mode=GDECL;
		args=0;
		decl();
	}
}
error(n)
int n;
{	if(n == EOFERR)
		if(filep!=filestack)
		{	lineno=filep->ln;
			fclose(filep->fcb);
			fprintf(stderr,"End of inclusion.\n");
			--filep;
			return;
		}
		else if(ac2!=ac)
		{	fclose(filep->fcb);
			newfile();
			return;
		}
		else if(mode == TOP)
		{	fprintf(stderr,"\nCompiled %u lines.\n",glineno-1);
			if (!chk) fprintf(stderr,
				"Total internal labels	: %u.\n",labelno-1);
			fprintf(stderr,
				"Total global variables : %u bytes.\n\n",gpc);
			printf("_%d\tRTS\n_INITIALIZE\tEQU\t_1\n",ilabel);
			printf("_GLOBALS\tEQU\t%u\n",gpc);
			exit(0);
		}
	fprintf(stderr,"%5d:%s.\n",lineno,
		(n==FILERR) ? "Can't open specified file" :
		(n==DCERR) ? "Declaration syntax" :
		(n==STERR) ? "Statement syntax" :
		(n==EXERR) ? "Expression syntax" :
		(n==CNERR) ? "Constant required" :
		(n==CHERR) ? "Illegal character" :
		(n==GSERR) ? "Too many global symbols" :
		(n==LSERR) ? "Too many local symbols" :
		(n==STRERR) ? "Too many strings or macros" :
		(n==LNERR) ? "Line too long" :
		(n==EOFERR) ? "Unexpected end of file" :
		(n==MCERR) ? "Macro syntax" :
		(n==INCERR) ? "Include syntax" :
		(n==HPERR) ? "Too long expression" :
		(n==TYERR) ? "Type mismatch" :
		(n==LVERR) ? "Lvalue required" :
		(n==UDERR) ? "Undeclared identifier" :
		(n==OPTION) ? "Illegal option" :
		"Bug of compiler");
	errmsg();
	exit(1);
}
errmsg()
{char *p,*lim;
	if(lineno==0) return;
	fprintf(stderr,"%s",linebuf);
	lim=(mflag?chptrsave:chptr);
	for (p=linebuf; p < lim;)
		fprintf(stderr,(*p++ == '\t') ? "\t" : " ");
	fprintf (stderr,"^\n");
}
checksym(s)
int s;
{char *p;
	if (sym != s)
	{	p=(s==RPAR) ? "')'": (s==RBRA) ? "']'": (s==SM) ? "';'":
		  (s==LPAR) ? "'('": (s==WHILE) ? "'while'":
		  (s==COLON) ? "':'": "Identifier";
		fprintf(stderr,"%d:%s expected.\n",lineno,p);
		errmsg();
	}
	else getsym();
}
init()
{NMTBL *nptr;
int i;
	for(nptr = ntable,i = GSYMS; i--;) (nptr++)->sc = EMPTY;
	reserve("int",INT);
	reserve("void",INT);
	reserve("char",CHAR);
	reserve("struct",STRUCT);
	reserve("union",UNION);
	reserve("unsigned",UNSIGNED);
	reserve("static",STATIC);
	reserve("goto",GOTO);
	reserve("return",RETURN);
	reserve("break",BREAK);
	reserve("continue",CONTINUE);
	reserve("if",IF);
	reserve("else",ELSE);
	reserve("for",FOR);
	reserve("do",DO);
	reserve("while",WHILE);
	reserve("switch",SWITCH);
	reserve("case",CASE);
	reserve("default",DEFAULT);
	reserve("typedef",TYPEDEF);
	reserve("sizeof",SIZEOF);
	reserve("long",LONG);
	reserve("short",SHORT);
	gpc=glineno=mflag=0;
	gfree=ilabel=1;
	labelno=2;
	cheapp=cheap;
	lfree=HEAPSIZE;
	filep=filestack;
	newfile();
	getline();
	getch();
}
newfile()
{	lineno=0;
	fprintf(stderr,"%s:\n",av[ac2]);
	if ( (filep->fcb = fopen(av[ac2++],"rc")) == NULL ) error(FILERR);
}
reserve(s,d)
char *s;
int d;
{NMTBL *nptr;
char *t;
	hash=0;
	t=name;
	while(*t++ = *s) hash=7*(hash+*s++);
	(nptr = gsearch())->sc = RESERVE;
	nptr->dsp = d;
}

decl()
{NMTBL *n;
int t;
	if(sym==STATIC)
		if(mode==LDECL)
		{	getsym();
			mode=STADECL;
		}
		else error(DCERR);
	else if(sym==TYPEDEF)
		if(mode==GDECL)
		{	getsym();
			mode=GTDECL;
		}
		else if(mode==LDECL)
		{	getsym();
			mode=LTDECL;
		}
		else error(DCERR);
	if((t=typespec())==0) return;
	if(sym==SM) return;
	type=t;
	n=decl0();
	reverse(t);
	if(args||sym==LC) {fdecl(n);return;}
	def(n);
	while(sym==COMMA)
	{	getsym();
		type=t;
		n=decl0();
		reverse(t);
		if(args) error(DCERR);
		def(n);
	}
	if(sym!=SM) error(DCERR);
	if(mode==GTDECL) mode=GDECL;
	if(mode==STADECL||mode==LTDECL) mode=LDECL;
}
typespec()
{int t;
	switch(sym)
	{case INT:
	case CHAR:
		t= sym;
		getsym();
		break;
	case STRUCT:
	case UNION:
		t=sdecl(sym);
		break;
	case UNSIGNED:
		t = UNSIGNED;
		if(getsym()==INT) getsym();
		break;
	case SHORT:
		t=CHAR;
		if(getsym()==INT) getsym();
		break;
	case LONG:
		t=INT;
		if(getsym()==INT) getsym();
		break;
	default:
		if(sym==IDENT)
			if(nptr->sc==TYPE)
			{	t=nptr->ty;
				getsym();
				break;
			}
			else if(nptr->sc==EMPTY && gnptr->sc==TYPE)
			{	t=gnptr->ty;
				getsym();
				break;
			}
		if(mode==LDECL) return 0;
		t= INT;
	}
	return t;
}
struct nametable *decl0()
{NMTBL *n;
	if(sym==MUL)
	{	getsym();
		n=decl0();
		type=list2(POINTER,type);
		return n;
	}
	return decl1();
}
NMTBL *decl1()
{NMTBL *n;
int i,t;
	if(sym==LPAR)
	{	getsym();
		n=decl0();
		checksym(RPAR);
	}
	else if (sym == IDENT)
	{	n=nptr;
		getsym();
	}
	else error(DCERR);
	while(1)
		if(sym==LBRA)
			if(getsym()==RBRA)
			{	getsym();
				if(mode!=ADECL) error(DCERR);
				t=type;
				type=list2(POINTER,type);
			}
			else
			{	t=type;
				i=cexpr(expr());
				checksym(RBRA);
				type=list3(ARRAY,t,i);
			}
		else if(sym==LPAR)
		{	if(mode==GDECL) {mode=ADECL;getsym();mode=GDECL;}
			else getsym();
			if(sym==RPAR) getsym();
			else
			{	n->sc=FUNCTION;
				adecl();
				n->sc=EMPTY;
			}
			type=list2(FUNCTION,type);
		}
		else return n;
}
adecl()
{	if(mode!=GDECL) error(DCERR);
	mode=ADECL;
	args= 2;
	while(1)
	{	if(sym!=IDENT) error(DCERR);
		nptr->ty = INT;
		nptr->sc = LVAR;
		nptr->dsp = (args += 2);
		if(getsym()!=COMMA) break;
		getsym();
	}
	checksym(RPAR);
	mode=GDECL;
	return;
}
reverse(t1)
int t1;
{int t2,t3;
	t2=t1;
	while(type!=t1)
	{	t3=cadr(type);
		rplacad(type,t2);
		t2=type;
		type=t3;
	}
	type=t2;
}
size(t)
int t;
{	if(t==CHAR) return 1;
	if(scalar(t)) return 2;
	if(car(t)==STRUCT||car(t)==UNION)
	{	if(cadr(t)==-1) error(DCERR);
		return(cadr(t));
	}
	if(car(t)==ARRAY) return(size(cadr(t))*caddr(t));
	else error(DCERR);
	/*NOTREACHED*/
}
def(n)
NMTBL *n;
{int sz,nsc,ndsp,slfree,l,t,e;
	if(car(type)==FUNCTION)
	{	fcheck(n);
		return;
	}
	if (n->sc!=EMPTY &&
	    (mode!=ADECL || n->sc!=LVAR || n->ty!=INT) &&
	    (mode!=GSDECL&&mode!=LSDECL || n->sc!=FIELD || n->dsp!=disp) &&
	    (mode!=GUDECL&&mode!=LUDECL || n->sc!=FIELD || n->dsp!=0) )
		 error(DCERR);
	sz = size(n->ty = type);
	switch(mode)
	{case GDECL:
		printf("%s\tEQU\t%u\n",n->nm,gpc);
	case STADECL:
		nsc = GVAR;
		ndsp = gpc;
		if(sym==ASS)
		{	t=type;
			if(!scalar(t))
				error(TYERR);
			if(mode==STADECL) printf("\tBRA\t_%d\n",l=fwdlabel());
			fwddef(ilabel);
			getsym();
			slfree=lfree;
			e=expr1();
			if(car(e)==CONST)
			{	lddim(cadr(e));
				indexy(t==CHAR?"STB":"STD",gpc);
			}
			else if(t!=CHAR)
			{	if(car(e)==ADDRESS&&car(cadr(e))==GVAR)
					leaxy(cadr(cadr(e)));
				else if(car(e)==FNAME)
					leaxpcr((NMTBL *)cadr(e));
				else error(TYERR);
				stxy(gpc);
			}
			else error(TYERR);
			lfree=slfree;
			jmp(ilabel=fwdlabel());
			if(mode==STADECL) fwddef(l);
			type=t;
		}
		gpc +=sz;
		break;
	case GSDECL:
		nsc = FIELD;
		ndsp = disp;
		disp += sz;
		break;
	case GUDECL:
		nsc = FIELD;
		ndsp = 0;
		if (disp < sz) disp = sz;
		break;
	case GTDECL:
		nsc = TYPE;
		break;
	case ADECL:
		if(type==CHAR) ++(n->dsp);
		else if (!scalar(type)) error(TYERR);
		return;
	case LDECL:
		nsc = LVAR;
		ndsp = (disp -= sz);
		break;
	case LSDECL:
		nsc = FIELD;
		ndsp = disp;
		disp += sz;
		break;
	case LUDECL:
		nsc = FIELD;
		ndsp = 0;
		if (disp < sz) disp = sz;
		break;
	case LTDECL:
		nsc = TYPE;
		break;
	default:
		error(DCERR);
	}
	n->sc = nsc;
	n->dsp = ndsp;
}
sdecl(s)
int s;
{int smode,sdisp,type;
NMTBL *nptr0;
	smode=mode;
	if (mode==GDECL || mode==GSDECL || mode==GUDECL || mode==GTDECL)
		mode=(s==STRUCT?GSDECL:GUDECL);
	else mode=(s==STRUCT?LSDECL:LUDECL);
	sdisp=disp;
	disp=0;
	if (getsym() == IDENT)
	{	nptr0 = nptr;
		if (getsym() == LC)
		{	if (nptr0->sc != EMPTY) error(DCERR);
			nptr0->sc = TAG;
			nptr0->ty = list2(s,-1);
			while (getsym() != RC) decl();
			getsym();
			rplacad(type = nptr0->ty,disp);
		}
		else
		{	if(nptr0->sc == EMPTY) nptr0=gnptr;
			if(nptr0->sc == EMPTY) error(UDERR);
			if(nptr0->sc != TAG) error(TYERR);
			type = nptr0->ty;
		}
	}
	else if(sym==LC)
	{	while(getsym() != RC) decl();
		getsym();
		type = list2(s,disp);
	}
	else error(DCERR);
	disp=sdisp;
	mode=smode;
	return type;
}
fdecl(n)
NMTBL *n;
{	args=0;
	fcheck(n);
	mode=ADECL;
	lfree= HEAPSIZE;
	while (sym!=LC) {decl(); getsym();}
	disp=0;
	mode=STAT;
	while (typeid(getsym()) || sym==STATIC || sym==TYPEDEF)
	{	mode=LDECL;
		decl();
		mode=STAT;
	}
	control=1;
	printf("%s\n\tPSHS\tU\n\tLEAU\t,S\n",n->nm);
	if(disp) printf("\tLEAS\t%d,S\n",disp);
	lvar= -disp;
	while(sym!=RC) statement();
	if (control) return2();
}
fcheck(n)
NMTBL *n;
{	if(mode!=GDECL||car(type)!=FUNCTION) error(DCERR);
	if(n->sc==FUNCTION) compatible(n->ty,cadr(type));
	else if(n->sc!=EMPTY) error(DCERR);
	n->sc=FUNCTION;
	n->ty=cadr(type);
}
compatible(t1,t2)
int t1,t2;
{	if(integral(t1))
	{	if(t1!=t2) error(TYERR);
	}
	else if(car(t1)!=car(t2)) error(TYERR);
	else if((car(t1)==STRUCT || car(t1)==UNION) && cadr(t1)!=cadr(t2))
		error(TYERR);
	else if(car(t1)==POINTER || car(t1)==ARRAY ||car(t1)==FUNCTION)
		compatible(cadr(t1),cadr(t2));
}
scalar(t)
int t;
{	return(integral(t)||car(t)==POINTER);
}
integral(t)
int t;
{	return(t==INT||t==CHAR||t==UNSIGNED);
}

statement()
{int slfree;
	switch(sym)
	{case IF:
		doif();
		return;
	case WHILE:
		dowhile();
		return;
	case DO:
		dodo();
		return;
	case FOR:
		dofor();
		return;
	case SWITCH:
		doswitch();
		return;
	case LC:
		docomp();
		return;
	case BREAK:
		jmp(blabel);
		getsym();
		checksym(SM);
		return;
	case CONTINUE:
		jmp(clabel);
		getsym();
		checksym(SM);
		return;
	case CASE:
		docase();
		statement();
		return;
	case DEFAULT:
		dodefault();
		statement();
		return;
	case RETURN:
		doreturn();
		return;
	case GOTO:
		dogoto();
		return;
	case SM:
		getsym();
		return;
	default:if(sym==IDENT&&skipspc()==':')
		{	dolabel();
			statement();
		}
		else
		{	slfree=lfree;
			gexpr(expr());
			lfree=slfree;
			checksym(SM);
		}
	}
}
doif()
{int l1,l2,slfree;
	getsym();
	checksym(LPAR);
	slfree=lfree;
	bexpr(expr(),0,l1=fwdlabel());
	lfree=slfree;
	checksym(RPAR);
	statement();
	if(sym==ELSE)
	{	if (l2 = control) jmp(l2=fwdlabel());
		fwddef(l1);
		getsym();
		statement();
		if (l2) fwddef(l2);
	}
	else fwddef(l1);
}
dowhile()
{int sbreak,scontinue,slfree,e;
	sbreak=blabel;
	scontinue=clabel;
	blabel=fwdlabel();
	clabel=backdef();
	getsym();
	checksym(LPAR);
	slfree=lfree;
	e=expr();
	checksym(RPAR);
	if(sym==SM)
	{	bexpr(e,1,clabel);
		lfree=slfree;
		getsym();
	}
	else
	{	bexpr(e,0,blabel);
		lfree=slfree;
		statement();
		jmp(clabel);
	}
	fwddef(blabel);
	clabel=scontinue;
	blabel=sbreak;
}
dodo()
{int sbreak,scontinue,l,slfree;
	sbreak=blabel;
	scontinue=clabel;
	blabel=fwdlabel();
	clabel=fwdlabel();
	l=backdef();
	getsym();
	statement();
	fwddef(clabel);
	checksym(WHILE);
	checksym(LPAR);
	slfree=lfree;
	bexpr(expr(),1,l);
	lfree=slfree;
	checksym(RPAR);
	checksym(SM);
	fwddef(blabel);
	clabel=scontinue;
	blabel=sbreak;
}
dofor()
{int sbreak,scontinue,l,e,slfree;
	sbreak=blabel;
	scontinue=clabel;
	blabel=fwdlabel();
	getsym();
	checksym(LPAR);
	slfree=lfree;
	if(sym!=SM)
	{	gexpr(expr());
		checksym(SM);
	}
	else getsym();
	lfree=slfree;
	l=backdef();
	if(sym!=SM)
	{	bexpr(expr(),0,blabel);
		checksym(SM);
	}
	else getsym();
	lfree=slfree;
	if(sym==RPAR)
	{	clabel=l;
		getsym();
		statement();
	}
	else
	{	clabel=fwdlabel();
		e=expr();
		checksym(RPAR);
		statement();
		fwddef(clabel);
		gexpr(e);
		lfree=slfree;
	}
	jmp(l);
	fwddef(blabel);
	clabel=scontinue;
	blabel=sbreak;
}
doswitch()
{int sbreak,scase,sdefault,slfree;
	sbreak=blabel;
	blabel=fwdlabel();
	sdefault=dlabel;
	dlabel=0;
	scase=cslabel;
	getsym();
	checksym(LPAR);
	slfree=lfree;
	gexpr(expr());
	lfree=slfree;
	checksym(RPAR);
	cslabel = control = 0;
	statement();
	if(dlabel) printf("_%d\tEQU\t_%d\n",cslabel,dlabel);
	else fwddef(cslabel);
	cslabel=scase;
	dlabel=sdefault;
	fwddef(blabel);
	blabel=sbreak;
}
docomp()
{	getsym();
	while(sym!=RC) statement();
	getsym();
}
docase()
{int c,n,l,slfree;
	c=0;
	n=2;
	slfree=lfree;
	while(sym==CASE)
	{	getsym();
		c=list2(cexpr(expr()),c);
		n+=6;
		checksym(COLON);
	}
	l=fwdlabel();
	if (control)
	{	control=0;
		if (n>127) jmp(l);
		else printf("\tBRA\t_%d\n",l);
	}
	if (cslabel) fwddef(cslabel);
	while(cadr(c))
	{	cmpdimm(car(c));
		if((n-=6)>127) jcond(l,0);
		else printf("\tBEQ\t_%d\n",l);
		c=cadr(c);
	}
	lfree=slfree;
	cmpdimm(car(c));
	jcond(cslabel=fwdlabel(),1);
	fwddef(l);
}
dodefault()
{	getsym();
	checksym(COLON);
	if (dlabel) error(STERR);
	if (!cslabel) jmp(cslabel = fwdlabel());
	dlabel = backdef();
}
doreturn()
{int slfree;
	if(getsym()==SM)
	{	getsym();
		return2();
		return;
	}
	slfree=lfree;
	gexpr(expr());
	lfree=slfree;
	checksym(SM);
	control=0;
	switch(lvar)
	{case 0:
		ret("");
		return;
	case 2:
		ret("X,");
		return;
	default:unlink();
		return;
	}
}
return2()
{	control=0;
	switch(lvar)
	{case 0:
		ret("");
		return;
	case 1:
		ret("A,");
		return;
	case 2:
		ret("D,");
		return;
	case 3:
		ret("A,X,");
		return;
	case 4:
		ret("D,X,");
		return;
	default:unlink();
		return;
	}
}
ret(reg)
char *reg;
{	printf("\tPULS\t%sU,PC\n",reg);
}
unlink()
{	printf("\tLEAS\t,U\n");
	ret("");
}
dogoto()
{NMTBL *nptr0;
	getsym();
	nptr0=nptr;
	checksym(IDENT);
	if(nptr0->sc == BLABEL || nptr0->sc == FLABEL) jmp(nptr0->dsp);
	else if(nptr0->sc == EMPTY)
	{	nptr0->sc = FLABEL;
		jmp(nptr0->dsp = fwdlabel());
	}
	else error(STERR);
	checksym(SM);
}
dolabel()
{	if(nptr->sc == FLABEL) fwddef(nptr->dsp);
	else if(nptr->sc != EMPTY) error(TYERR);
	nptr->sc = BLABEL;
	nptr->dsp = backdef();
	getsym();
	checksym(COLON);
}

expr()
{	return(rvalue(expr0()));
}
expr0()
{int e;
	e=expr1();
	while(sym==COMMA) {getsym();e=list3(COMMA,e,rvalue(expr1()));}
	return e;
}
expr1()
{int e1,e2,t,op;
	e1=expr2();
	switch (sym)
	{case ASS:
		lcheck(e1);
		t=type;
		getsym();
		e2=rvalue(expr1());
		if(t==CHAR) {type= INT;return(list3(CASS,e1,e2));}
		type=t;
		return(list3(ASS,e1,e2));
	case ADD+AS: case SUB+AS: case MUL+AS: case DIV+AS: case MOD+AS:
	case RSHIFT+AS: case LSHIFT+AS: case BAND+AS: case EOR+AS: case BOR+AS:
		op = sym-AS;
		lcheck(e1);
		t=type;
		getsym();
		e2=rvalue(expr1());
		if(!integral(type)) error(TYERR);
		if((t==UNSIGNED||type==UNSIGNED)&&
			(op==MUL||op==DIV||op==MOD||op==RSHIFT||op==LSHIFT))
			op=op+US;
		if(t==CHAR)
		{	type= INT;
			return(list4(CASSOP,e1,e2,op));
		}
		type=t;
		if(integral(t)) return(list4(ASSOP,e1,e2,op));
		if((op!=ADD&&op!=SUB)||car(t)!=POINTER) error(TYERR);
		e2=binop(MUL,e2,list2(CONST,size(cadr(t))),INT,UNSIGNED);
		type=t;
		return list4(ASSOP,e1,e2,op);
	default:
		return(e1);
	}
}
expr2()
{int e1,e2,e3,t;
	e1=expr3();
	if(sym==COND)
	{	e1=rvalue(e1);
		getsym();
		e2=rvalue(expr2());
		t=type;
		checksym(COLON);
		e3=rvalue(expr2());
		if(car(e1)==CONST)
			if(cadr(e1)) {type=t;return e2;}
			else return e3;
		if(type==INT||t!=INT&&type==UNSIGNED) type=t;
		return(list4(COND,e1,e2,e3));
	}
	return(e1);
}
expr3()
{int e;
	e=expr4();
	while(sym==LOR)
	{	e=rvalue(e);
		getsym();
		e=list3(LOR,e,rvalue(expr4()));
		type= INT;
	}
	return(e);
}
expr4()
{int e;
	e=expr5();
	while(sym==LAND)
	{	e=rvalue(e);
		getsym();
		e=list3(LAND,e,rvalue(expr5()));
		type= INT;
	}
	return(e);
}
expr5()
{int e1,e2,t;
	e1=expr6();
	while(sym==BOR)
	{	e1=rvalue(e1);
		t=type;
		getsym();
		e2=rvalue(expr6());
		e1=binop(BOR,e1,e2,t,type);
	}
	return(e1);
}
expr6()
{int e1,e2,t;
	e1=expr7();
	while(sym==EOR)
	{	e1=rvalue(e1);
		t=type;
		getsym();
		e2=rvalue(expr7());
		e1=binop(EOR,e1,e2,t,type);
	}
	return(e1);
}
expr7()
{int e1,e2,t;
	e1=expr8();
	while(sym==BAND)
	{	e1=rvalue(e1);
		t=type;
		getsym();
		e2=rvalue(expr8());
		e1=binop(BAND,e1,e2,t,type);
	}
	return(e1);
}
expr8()
{int e,op;
	e=expr9();
	while((op=sym)==EQ||op==NEQ)
	{	e=rvalue(e);
		getsym();
		e=list3(op,e,rvalue(expr9()));
		type= INT;
	}
	return e;
}
expr9()
{int e1,e2,t,op;
	e1=expr10();
	while((op=sym)==GT||op==GE||op==LT||op==LE)
	{	e1=rvalue(e1);
		t=type;
		getsym();
		e2=rvalue(expr10());
		if(t==INT&&type==INT) e1=list3(op,e1,e2);
		else e1=list3(op+US,e1,e2);
		type= INT;
	}
	return e1;
}
expr10()
{int e1,e2,t,op;
	e1=expr11();
	while((op=sym)==RSHIFT||op==LSHIFT)
	{	e1=rvalue(e1);
		t=type;
		getsym();
		e2=rvalue(expr11());
		e1=binop(op,e1,e2,t,type);
	}
	return e1;
}
expr11()
{int e1,e2,t,op;
	e1=expr12();
	while((op=sym)==ADD||op==SUB)
	{	e1=rvalue(e1);
		t=type;
		getsym();
		e2=rvalue(expr12());
		e1=binop(op,e1,e2,t,type);
	}
	return e1;
}
expr12()
{int e1,e2,t,op;
	e1=expr13();
	while((op=sym)==MUL||op==DIV||op==MOD)
	{	e1=rvalue(e1);
		t=type;
		getsym();
		e2=rvalue(expr13());
		e1=binop(op,e1,e2,t,type);
	}
	return e1;
}
expr13()
{int e,op;
	switch (op = sym)
	{case INC: case DEC:
		getsym();
		lcheck(e=expr13());
		if(type==CHAR)
		{	type= INT;
			return(list2(op==INC?CPREINC:CPREDEC,e));
		}
		if(integral(type))
			return(list3(PREINC,e,op==INC?1:-1));
		if(car(type)!=POINTER) error(TYERR);
		return(list3(PREINC,e,
			op==INC?size(cadr(type)):-size(cadr(type)) ));
	case MUL:
		getsym();
		e=rvalue(expr13());
		return(indop(e));
	case BAND:
		getsym();
		switch(car(e=expr13()))
		{case INDIRECT:
			e=cadr(e);
			break;
		case GVAR:
		case LVAR:
			e=list2(ADDRESS,e);
			break;
		case FNAME:
			return e;
		default:error(LVERR);
		}
		type=list2(POINTER,type);
		return e;
	case SUB:
		getsym();
		e=rvalue(expr13());
		if(!integral(type)) error(TYERR);
		return(car(e)==CONST?list2(CONST,-cadr(e)):list2(MINUS,e));
	case BNOT:
		getsym();
		e=rvalue(expr13());
		if(!integral(type)) error(TYERR);
		return(car(e)==CONST?list2(CONST,~cadr(e)):list2(BNOT,e));
	case LNOT:
		getsym();
		return(list2(LNOT,rvalue(expr13())));
	case SIZEOF:
		if(getsym()==LPAR)
			if(typeid(getsym()))
			{	e=list2(CONST,size(typename()));
				type=INT;
				checksym(RPAR);
				return e;
			}
			else
			{	e=expr0();
				checksym(RPAR);
				expr16(e);
				if(sym==INC||sym==DEC)
				{	getsym();
					if(type==CHAR) type=INT;
					else if(!scalar(type))
						error(TYERR);
				}
			}
		else expr13();
		e=list2(CONST,size(type));
		type=INT;
		return e;
	}
	e=expr14();
	if((op=sym)==INC||op==DEC)
	{	lcheck(e);
		getsym();
		if(type==CHAR)
		{	type= INT;
			return(list2(op==INC?CPOSTINC:CPOSTDEC,e));
		}
		if(integral(type))
			return(list3(POSTINC,e,op==INC?1:-1));
		if(car(type)!=POINTER) error(TYERR);
		return (list3(POSTINC,e,
			op == INC ? size(cadr(type)): -size(cadr(type)) ));
	}
	return e;
}
expr14()
{int e1,t;
	switch(sym)
	{case IDENT:
		switch(nptr->sc)
		{case GVAR:
			e1=list2(GVAR,nptr->dsp);
			type=nptr->ty;
			getsym();
			break;
		case LVAR:
			e1=list2(LVAR,nptr->dsp);
			type=nptr->ty;
			getsym();
			break;
		case FUNCTION:
			e1=list2(FNAME,(int)nptr);
			type=list2(FUNCTION,nptr->ty);
			getsym();
			break;
		case EMPTY:
			if(getsym()==LPAR)
			{	nptr->sc = FUNCTION;
				nptr->ty= INT;
				type= list2(FUNCTION,INT);
				e1=expr15(list2(FNAME,(int)nptr));
				break;
			}
		default:error(UDERR);
		}
		break;
	case STRING:
		e1=list3(STRING,(int)sptr,symval);
		type=list3(ARRAY,CHAR,symval);
		getsym();
		break;
	case CONST:
		type= INT;
		e1=list2(CONST,symval);
		getsym();
		break;
	case LPAR:
		if(typeid(getsym()))
		{	t=typename();
			checksym(RPAR);
			e1=expr13();
			type=t;
			return e1;
		}
		e1=expr0();
		checksym(RPAR);
		break;
	default:error(EXERR);
	}
	return expr16(e1);
}
expr16(e1)
int e1;
{int e2,t;
	while(1)
		if(sym==LBRA)
		{	e1=rvalue(e1);
			t=type;
			getsym();
			e2=rvalue(expr0());
			checksym(RBRA);
			e1=binop(ADD,e1,e2,t,type);
			e1=indop(e1);
		}
		else if(sym==LPAR) e1=expr15(e1);
		else if(sym==PERIOD) e1=strop(e1);
		else if(sym==ARROW) e1=strop(indop(rvalue(e1)));
		else break;
	if(car(e1)==FNAME) type=list2(POINTER,type);
	return e1;
}
rvalue(e)
int e;
{	if(type==CHAR)
	{	type= INT;
		switch(car(e))
		{case GVAR:
			return(list2(CRGVAR,cadr(e)));
		case LVAR:
			return(list2(CRLVAR,cadr(e)));
		case INDIRECT:
			return(list2(CRINDIRECT,cadr(e)));
		default:return(e);
		}
	}
	if(!integral(type))
		if(car(type)==ARRAY)
		{	type=list2(POINTER,cadr(type));
			if(car(e)==INDIRECT) return cadr(e);
			return list2(ADDRESS,e);
		}
		else if(car(type)!=POINTER) error(TYERR);
	switch(car(e))
	{case GVAR:
		return(list2(RGVAR,cadr(e)));
	case LVAR:
		return(list2(RLVAR,cadr(e)));
	case INDIRECT:
		return(list2(RINDIRECT,cadr(e)));
	default:return(e);
	}
}
lcheck(e)
int e;
{	if(!scalar(type)||car(e)!=GVAR&&car(e)!=LVAR&&car(e)!=INDIRECT)
		error(LVERR);
}
indop(e)
int e;
{	if(type!=INT&&type!=UNSIGNED)
		if(car(type)==POINTER) type=cadr(type);
		else error(TYERR);
	else type= CHAR;
	if(car(e)==ADDRESS) return(cadr(e));
	return(list2(INDIRECT,e));
}
strop(e)
{	getsym();
	if (sym!=IDENT||nptr->sc!=FIELD) error(TYERR);
	if (integral(type)||car(type)!=STRUCT && car(type)!=UNION)
		e=rvalue(e);
	type = nptr->ty;
	switch(car(e))
	{case GVAR:
	case LVAR:
		e=list2(car(e),cadr(e) + nptr->dsp);
		break;
	case INDIRECT:
		if(!nptr->dsp) break;
		e=list2(INDIRECT,list3(ADD,cadr(e),list2(CONST,nptr->dsp)));
		break;
	default:
		e=list2(INDIRECT,list3(ADD,e,list2(CONST,nptr->dsp)));
	}
	getsym();
	return e;
}
binop(op,e1,e2,t1,t2)
int op,e1,e2,t1,t2;
{int e;
	if(car(e1)==CONST&&car(e2)==CONST)
	{	e1=cadr(e1);
		e2=cadr(e2);
		type= INT;
		switch(op)
		{case BOR:
			e=e1|e2;break;
		case EOR:
			e=e1^e2;break;
		case BAND:
			e=e1&e2;break;
		case ADD:
			if(integral(t1))
			{	if(integral(t2))
					e=e1+e2;
				else
				{	if(car(t2)!=POINTER) error(TYERR);
					e=size(cadr(t2))*e1+e2;
					type=t2;
				}
			}
			else
			{	if(car(t1)!=POINTER) error(TYERR);
				e=e1+size(cadr(t1))*e2;
				type=t1;
			}
			break;
		case SUB:
			if(integral(t1))
				e=e1-e2;
			else
			{	if(car(t1)!=POINTER) error(TYERR);
				e=e1-size(cadr(t1))*e2;
				type=t1;
			}
			break;
		case MUL:
			e=e1*e2;break;
		case DIV:
			if(!e2) error(EXERR);e=e1/e2;break;
		case MOD:
			if(!e2) error(EXERR);e=e1%e2;break;
		case RSHIFT:
			e=e1>>e2;break;
		case LSHIFT:
			e=e1<<e2;
		}
		return list2(CONST,e);
	}
	if((op==ADD||op==MUL||op==BOR||op==EOR||op==BAND)&&
		(car(e1)==CONST||car(e2)!=CONST&&
		(car(e1)==RGVAR||car(e1)==RLVAR)))
		{e=e1;e1=e2;e2=e;e=t1;t1=t2;t2=e;}
	if(op==ADD)
	{	if(integral(t1))
		{	if(integral(t2))
			{	if(t1==INT) type=t2;else type=t1;
				return(list3(ADD,e1,e2));
			}
			if(car(t2)!=POINTER) error(TYERR);
			e=binop(MUL,e1,list2(CONST,size(cadr(t2))),t1,INT);
			type=t2;
			return(list3(ADD,e,e2));
		}
		if(car(t1)!=POINTER||!integral(t2)) error(TYERR);
		e=binop(MUL,e2,list2(CONST,size(cadr(t1))),t2,INT);
		type=t1;
		if(car(e1)==ADDRESS&&car(e)==CONST)
			return(list2(ADDRESS,list2(car(cadr(e1)),
				cadr(cadr(e1))+cadr(e))));
		return(list3(ADD,e1,e));
	}
	if(op==SUB)
	{	if(integral(t1))
		{	if(!integral(t2)) error(TYERR);
			if(t1==INT) type=t2;else type=t1;
			return(list3(SUB,e1,e2));
		}
		if(car(t1)!=POINTER) error(TYERR);
		if(integral(t2))
		{	e=binop(MUL,e2,list2(CONST,size(cadr(t1))),t2,INT);
			type=t1;
			return(list3(SUB,e1,e));
		}
		if(car(t2)!=POINTER)
			error(TYERR);
		compatible(t1,t2);
		e=list3(SUB,e1,e2);
		e=binop(DIV,e,list2(CONST,size(cadr(t1))),UNSIGNED,INT);
		type= INT;
		return e;
	}
	if(!integral(t1)||!integral(t2)) error(TYERR);
	if(t1==INT) type=t2;else type=t1;
	if((op==MUL||op==DIV)&&car(e2)==CONST&&cadr(e2)==1) return e1;
	if(op==BOR||op==EOR||op==BAND) return(list3(op,e1,e2));
	return(list3(type==UNSIGNED?op+US:op,e1,e2));
}
expr15(e1)
int e1;
{int t,args;
	t=type;
	if(integral(t)||car(t)!=FUNCTION)
		error(TYERR);
	t=cadr(t);
	getsym();
	args=0;
	while(sym!=RPAR)
	{	args=list2(rvalue(expr1()),args);
		if(sym!=COMMA) break;
		getsym();
	}
	checksym(RPAR);
	if(t==CHAR) type= INT;else type=t;
	return list3(FUNCTION,e1,args);
}
typeid(s)
int s;
{	return (integral(s) || s==SHORT || s==LONG || s==STRUCT || s==UNION ||
		(s==IDENT && nptr->sc==TYPE));
}
typename()
{int t;
	type=t=typespec();
	ndecl0();
	reverse(t);
	return type;
}
ndecl0()
{	if(sym==MUL)
	{	getsym();
		return type=list2(POINTER,ndecl0());
	}
	return ndecl1();
}
ndecl1()
{int i,t;
	if(sym==LPAR)
		if(getsym()==RPAR) {type=list2(FUNCTION,type); getsym();}
		else
		{	ndecl0();
			checksym(RPAR);
		}
	while(1)
		if(sym==LBRA)
		{	getsym();
			t=type;
			i=cexpr(expr());
			checksym(RBRA);
			type=list3(ARRAY,t,i);
		}
		else if(sym==LPAR)
		{	getsym();
			checksym(RPAR);
			type=list2(FUNCTION,type);
		}
		else return type;
}

bexpr(e1,cond,l1)
int e1,l1;
char cond;
{int e2,l2;
	if (chk) return;
	e2=cadr(e1);
	switch(car(e1))
	{case LNOT:
		bexpr(e2,!cond,l1);
		return;
	case GT:
		rexpr(e1,l1,cond?"GT":"LE");
		return;
	case UGT:
		rexpr(e1,l1,cond?"HI":"LS");
		return;
	case GE:
		rexpr(e1,l1,cond?"GE":"LT");
		return;
	case UGE:
		rexpr(e1,l1,cond?"HS":"LO");
		return;
	case LT:
		rexpr(e1,l1,cond?"LT":"GE");
		return;
	case ULT:
		rexpr(e1,l1,cond?"LO":"HS");
		return;
	case LE:
		rexpr(e1,l1,cond?"LE":"GT");
		return;
	case ULE:
		rexpr(e1,l1,cond?"LS":"HI");
		return;
	case EQ:
		rexpr(e1,l1,cond?"EQ":"NE");
		return;
	case NEQ:
		rexpr(e1,l1,cond?"NE":"EQ");
		return;
	case LAND:
		bexpr(e2,0,cond?(l2=fwdlabel()):l1);
		bexpr(caddr(e1),cond,l1);
		if(cond) fwddef(l2);
		return;
	case LOR:
		bexpr(e2,1,cond?l1:(l2=fwdlabel()));
		bexpr(caddr(e1),cond,l1);
		if(!cond) fwddef(l2);
		return;
	case CRGVAR:
		ldby(e2);
		jcond(l1,cond);
		return;
	case CRLVAR:
		ldbu(e2);
		jcond(l1,cond);
		return;
	case CONST:
		if(cond&&e2||!cond&&!e2) jmp(l1);
		return;
	case RGVAR:
	case RLVAR:
	case CRINDIRECT:
		gexpr(e1);
		jcond(l1,cond);
		return;
	default:gexpr(e1);
		subdim(0);
		jcond(l1,cond);
		return;
	}
}
rexpr(e1,l1,s)
int e1,l1;
char *s;
{	gexpr(list3(SUB,cadr(e1),caddr(e1)));
	printf("\tLB%s\t_%d\n",s,l1);
}
jcond(l,cond)
int l;
char cond;
{	printf("\tLB%s\t_%d\n",cond?"NE":"EQ",l);
}
jmp(l)
int l;
{	control=0;
	printf("\tLBRA\t_%d\n",l);
}
fwdlabel()
{	return labelno++;
}
fwddef(l)
int l;
{	control=1;
	printf("_%d\n",l);
}
backdef()
{	control=1;
	printf("_%d\n",labelno);
	return labelno++;
}

gexpr(e1)
int e1;
{int e2,e3;
	if (chk) return;
	e2 = cadr(e1);
	switch (car(e1))
	{case GVAR:
		leaxy(e2);
		return;
	case RGVAR:
		lddy(e2);
		return;
	case CRGVAR:
		ldby(e2);
		sex();
		return;
	case LVAR:
		leaxu(e2);
		return;
	case RLVAR:
		lddu(e2);
		return;
	case CRLVAR:
		ldbu(e2);
		sex();
		return;
	case FNAME:
		leaxpcr((NMTBL *)e2);
		tfrxd();
		return;
	case CONST:
		if (e2) lddim(e2);
		else clrd();
		return;
	case STRING:
		string(e1);
		return;
	case FUNCTION:
		function(e1);
		return;
	case INDIRECT:
		indirect(e1);
		return;
	case RINDIRECT: case CRINDIRECT:
		rindirect(e1);
		return;
	case ADDRESS:
		gexpr(e2);
		tfrxd();
		return;
	case MINUS:
		gexpr(e2);
		printf("\tNEGA\n\tNEGB\n\tSBCA\t#0\n");
		return;
	case BNOT:
		gexpr(e2);
		printf("\tCOMA\n\tCOMB\n");
		return;
	case PREINC:
		switch (car(e2))
		{case GVAR: case LVAR:
			ldd(e2);
			adddim(caddr(e1));
			std(e2);
			return;
		default:
			gexpr(e2);
			lddx();
			adddim(caddr(e1));
			stdx();
			return;
		}
	case POSTINC:
		switch (car(e2))
		{case GVAR: case LVAR:
			ldd(e2);
			adddim(e3 = caddr(e1));
			std(e2);
			subdim(e3);
			return;
		default:
			gexpr(e2);
			lddx();
			adddim(e3=caddr(e1));
			stdx();
			subdim(e3);
			return;
		}
	case CPOSTINC:
		gexpr(e2);
		ldbx();
		incx();
		sex();
		return;
	case CPREINC:
		gexpr(e2);
		incx();
		ldbx();
		sex();
		return;
	case CPOSTDEC:
		gexpr(e2);
		ldbx();
		decx();
		sex();
		return;
	case CPREDEC:
		gexpr(e2);
		decx();
		ldbx();
		sex();
		return;
	case MUL: case UMUL:
		if (car(e3=caddr(e1)) == CONST)
		{	if (0 < (e3 = cadr(e3)) && e3 <= 10)
			{	gexpr(e2);
				switch (e3)
				{case 8:
					asld();
				case 4:
					asld();
				case 2:
					asld();
				case 1:
					return;
				case 10:
					asld();
				case 5:
					pushd();
					asld();
					asld();
					addds();
					return;
				case 6:
					asld();
				case 3:
					pushd();
					asld();
					addds();
					return;
				case 9: case 7:
					pushd();
					asld();
					asld();
					asld();
					if (e3 == 9) addds(); else subds();
					return;
				}
			}
		}
	case DIV:    case UDIV:	   case MOD:	case UMOD:
	case LSHIFT: case ULSHIFT: case RSHIFT: case URSHIFT:
		binexpr(e1);
		return;
	case ADD: case SUB: case BAND: case EOR: case BOR:
		machinop(e1);
		return;
	case COND:
		e2=fwdlabel();
		bexpr(cadr(e1),0,e2);
		gexpr(caddr(e1));
		jmp(e3=fwdlabel());
		fwddef(e2);
		gexpr(cadddr(e1));
		fwddef(e3);
		return;
	case ASS: case CASS:
		assign(e1);
		return;
	case ASSOP: case CASSOP:
		assop(e1);
		return;
	case COMMA:
		gexpr(e2);
		gexpr(caddr(e1));
		return;
	default:
		bexpr(e1,1,e2=fwdlabel());
		clrd();
		printf("\tBRA\t*+5\n");
		fwddef(e2);
		lddim(1);
	}
}
string(e1)
int e1;
{char *s;
int i,l,lb;
	s=(char *)cadr(e1);
	lb=fwdlabel();
	if ((l = caddr(e1)) < 128)
		printf("\tLEAX\t2,PC\n\tBRA\t_%d\n",lb);
	else
		printf("\tLEAX\t3,PC\n\tLBRA\t_%d\n",lb);
	do
	{	printf("\tFCB\t%d",*s++);
		for (i=8; --l && --i;) printf(",%d",*s++);
		printf("\n");
	}
	while (l);
	fwddef(lb);
}
function(e1)
int e1;
{int e2,e3,e4,e5,nargs;
NMTBL *n;
	e2 = cadr(e1);
	nargs = 0;
	for (e3 = caddr(e1); e3; e3 = cadr(e3))
	{	n=(NMTBL *)(e5=(cadr(e4 = car(e3))));
		switch(car(e4))
		{case FNAME:
			leaxpcr(n);
			pushx();
			break;
		case ADDRESS:
			gexpr(e5);
			pushx();
			break;
		default:gexpr(e4);
			pushd();
		}
		++nargs;
	}
	if (car(e2) == FNAME)
	{	n=(NMTBL *)cadr(e2);
		printf("\tLBSR\t%s\n",n->nm);
	}
	else
	{	gexpr(e2);
		printf("\tJSR\t,X\n");
	}
	if (nargs) printf("\tLEAS\t%d,S\n",2*nargs);
}
indirect(e1)
int e1;
{int e2,e3,e4;
	e3 = cadr(e2 = cadr(e1));
	switch(car(e2))
	{case RGVAR: case RLVAR:
		ldx(e2);
		return;
	case ADD:
		if(car(e3)==ADDRESS)
		{	gexpr(caddr(e2));
			gexpr(cadr(e3));
			opdx("LEAX");
			return;
		}
		switch(car(e4 = caddr(e2)))
		{case RGVAR: case RLVAR:
			gexpr(e3);
			ldx(e4);
			opdx("LEAX");
			return;
		}
	default:
		gexpr(e2);
		tfrdx();
	}
}

machinop(e1)
int e1;
{int e2,e3;
	e2 = cadr(e1);
	switch (car(e3 = caddr(e1)))
	{case RGVAR: case RLVAR: case CONST:
		gexpr(e2);
		oprt(car(e1),e3);
		return;
	default:
		gexpr(e3);
		pushd();
		gexpr(e2);
		tosop(car(e1));
		return;
	}
}

rindirect(e1)
int e1;
{char *op;
int e2,e3,e4,byte,l;
	op = ((byte = (car(e1) == CRINDIRECT)) ? "LDB" : "LDD");
	e3 = cadr(e2 = cadr(e1));
	switch (car(e2))
	{case RGVAR: case RLVAR:
		indir(op,e2);
		sextend(byte);
		return;
	case ADD:
		if(car(e3)==ADDRESS)
		{	gexpr(caddr(e2));
			gexpr(cadr(e3));
			opdx(op);
			sextend(byte);
			return;
		}
		switch(car(e4=caddr(e2)))
		{case RGVAR: case RLVAR:
			gexpr(e3);
			ldx(e4);
			opdx(op);
			sextend(byte);
			return;
		case CONST:
			switch (car(e3))
			{case RGVAR: case RLVAR:
				ldx(e3);
				indexx(op,cadr(e4));
				sextend(byte);
				return;
			}
		default:
			gexpr(e3);
			pushd();
			gexpr(e4);
			pulx();
			opdx(op);
			sextend(byte);
			return;
		}
	case PREINC:
		if ((l = caddr(e2)) == -1 || l == -2)
			switch (car(e3))
			{case GVAR: case LVAR:
				ldx(e3);
				predecx(op,l);
				stx(e3);
				sextend(byte);
				return;
			}
		break;
	case POSTINC:
		if ((l = caddr(e2)) == 1 || l == 2)
			switch (car(e3))
			{case GVAR: case LVAR:
				ldx(e3);
				postincx(op,l);
				stx(e3);
				sextend(byte);
				return;
			}
		break;
	}
	gexpr(e2);
	tfrdx();
	indexx(op,0);
	sextend(byte);
}
assign(e1)
int e1;
{char *op;
int e2,e3,e4,e5,l;
	op = (car(e1) == CASS ? "STB" : "STD");
	e3 = cadr(e2 = cadr(e1));
	e4 = caddr(e1);
	switch(car(e2))
	{case GVAR: case LVAR:
		gexpr(e4);
		index(op,e2);
		return;
	case INDIRECT:
		switch(car(e3))
		{case RGVAR: case RLVAR:
			gexpr(e4);
			indir(op,e3);
			return;
		case ADD:
			if (car(caddr(e3)) == CONST)
				switch (car(e5=cadr(e3)))
				{case RGVAR: case RLVAR:
					gexpr(e4);
					ldx(e5);
					indexx(op,cadr(caddr(e3)));
					return;
				}
			break;
		case PREINC:
			if ((l = caddr(e3)) == -1 || l == -2)
				switch (car(e5=cadr(e3)))
				{case GVAR: case LVAR:
					gexpr(e4);
					ldx(e5);
					predecx(op,l);
					stx(e5);
					return;
				}
			break;
		case POSTINC:
			if ((l = caddr(e3)) == 1 || l == 2)
				switch (car(e5=cadr(e3)))
				{case GVAR: case LVAR:
					gexpr(e4);
					ldx(e5);
					postincx(op,l);
					stx(e5);
					return;
				}
			break;
		}
	}
	switch (car(e4))
	{case RGVAR: case CRGVAR: case RLVAR: case CRLVAR: case CONST:
		gexpr(e2);
		gexpr(e4);
		break;
	default:
		gexpr(e4);
		pushd();
		gexpr(e2);
		pulld();
	}
	indexx(op,0);
	return;
}
assop(e1)
int e1;
{int e2,e3,byte,op;
char *ldop,*stop;
	ldop = ((byte = (car(e1) == CASSOP)) ? "LDB" : "LDD");
	stop = (byte ? "STB" : "STD");
	e2 = cadr(e1);
	e3 = caddr(e1);
	op = cadddr(e1);
	switch (car(e2))
	{case GVAR: case LVAR:
		switch (car(e3))
		{case RGVAR: case RLVAR: case CONST:
			if (simpop(op))
			{	index(ldop,e2);
				sextend(byte);
				oprt(op,e3);
				index(stop,e2);
				return;
			}
		default:
			gexpr(e3);
			pushd();
			index(ldop,e2);
			sextend(byte);
			tosop(op);
			index(stop,e2);
			return;
		}
	default:
		switch (car(e3))
		{case RGVAR: case RLVAR: case CONST:
			if (simpop(op))
			{	gexpr(e2);
				indexx(ldop,0);
				sextend(byte);
				oprt(op,e3);
				indexx(stop,0);
				return;
			}
		default:
			gexpr(e3);
			pushd();
			gexpr(e2);
			indexx(ldop,0);
			sextend(byte);
			tosop(op);
			indexx(stop,0);
			return;
		}
	}
}
simpop(op)
int op;
{	return (op == ADD || op == SUB ||
		op == BAND || op == EOR || op == BOR);
}
oprt(op,e1)
int op,e1;
{int e2;
	e2 = cadr(e1);
	switch (car(e1))
	{case RGVAR:
		oprt1(op,"Y",e2);
		return;
	case RLVAR:
		oprt1(op,"U",e2);
		return;
	case CONST:
		oprtc(op,e2);
		return;
	}
}
oprt1(op,index,n)
int op,n;
char *index;
{	switch (op)
	{case ADD:
		printf("\tADDD\t%d,%s\n",n,index);
		return;
	case SUB:
		printf("\tSUBD\t%d,%s\n",n,index);
		return;
	case BAND: case EOR: case BOR:
		dualop(op,index,n);
		return;
	}
}
dualop(op,index,n)
int op;
char *index;
int n;
{char *ops;
	ops =  ((op == BAND) ? "AND" :
		(op == EOR)  ? "EOR" :
		(op == BOR)  ? "OR"  : (char *)DEBUG);
	printf("\t%sA\t%d,%s\n\t%sB\t%d+1,%s\n",ops,n,index,ops,n,index);
}

oprtc(op,n)
int op,n;
{	switch (op)
	{case ADD:
		adddim(n);
		return;
	case SUB:
		subdim(n);
		return;
	case BAND: case EOR: case BOR:
		dualc(op,n);
		return;
	}
}
dualc(op,n)
int op;
int n;
{char *ops;
	ops =  ((op == BAND) ? "AND" :
		(op == EOR)  ? "EOR" :
		(op == BOR)  ? "OR"  : (char *)DEBUG);
	printf("\t%sA\t#%d\n\t%sB\t#%d\n",ops,(n >> 8) & 0xff,ops,n & 0xff);
}
tosop(op)
int op;
{	switch (op)
	{case ADD:
		addds();
		return;
	case SUB:
		subds();
		return;
	case BAND: case EOR: case BOR:
		dualtosop(op);
		return;
	default:
		pulx();
		library(op);
	}
}
dualtosop(op)
int op;
{char *ops;
	ops =  ((op == BAND) ? "AND" :
		(op == EOR)  ? "EOR" :
		(op == BOR)  ? "OR"  : (char *)DEBUG);
	printf("\t%sA\t,S+\n\t%sB\t,S+\n",ops,ops);
}
pushd()
{	printf("\tPSHS\tD\n");
}
pushx()
{	printf("\tPSHS\tX\n");
}
pulld()
{	printf("\tPULS\tD\n");
}
pulx()
{	printf("\tPULS\tX\n");
}
tfrdx()
{	printf("\tTFR\tD,X\n");
}
tfrxd()
{	printf("\tTFR\tX,D\n");
}
/*
exgdx()
{	printf("\tEXG\tD,X\n");
}
*/
asld()
{	printf("\tASLB\n\tROLA\n");
}
adddim(n)
{	printf("\tADDD\t#%d\n",n);
}
subdim(n)
{	printf("\tSUBD\t#%d\n",n);
}
cmpdimm(n)
int n;
{	printf("\tCMPD\t#%d\n",n);
}
addds()
{	printf("\tADDD\t,S++\n");
}
subds()
{	printf("\tSUBD\t,S++\n");
}
clrd()
{	printf("\tCLRA\n\tCLRB\n");
}
lddim(n)
int n;
{	printf("\tLDD\t#%d\n",n);
}

ldd(e)
int e;
{	switch (car(e))
	{case GVAR:
		lddy(cadr(e));
		return;
	case LVAR:
		lddu(cadr(e));
		return;
	default:
		DEBUG;
	}
}

lddx()
{	printf("\tLDD\t,X\n");
}
lddy(n)
int n;
{	printf("\tLDD\t%d,Y\n",n);
}
lddu(n)
int n;
{	printf("\tLDD\t%d,U\n",n);
}

std(e)
int e;
{	switch (car(e))
	{case GVAR:
		stdy(cadr(e));
		return;
	case LVAR:
		stdu(cadr(e));
		return;
	default:
		DEBUG;
	}
}
stdx()
{	printf("\tSTD\t,X\n");
}
stdy(n)
int n;
{	printf("\tSTD\t%d,Y\n",n);
}
stdu(n)
int n;
{	printf("\tSTD\t%d,U\n",n);
}

ldbx()
{	printf("\tLDB\t,X\n");
}
/*
stbx()
{	printf("\tSTB\t,X\n");
}
*/
ldby(n)
int n;
{	printf("\tLDB\t%d,Y\n",n);
}
ldbu(n)
int n;
{	printf("\tLDB\t%d,U\n",n);
}
predecx(op,l)
char *op;
int l;
{	printf("\t%s\t,%sX\n",op,(l == -1 ? "-" : "--"));
}
postincx(op,l)
char *op;
int l;
{	printf("\t%s\t,X%s\n",op,(l == 1 ? "+" : "++"));
}
leaxy(n)
int n;
{	printf("\tLEAX\t%d,Y\n",n);
}
leaxu(n)
int n;
{	printf("\tLEAX\t%d,U\n",n);
}
leaxpcr(n)
NMTBL *n;
{	printf("\tLEAX\t%s,PCR\n",n->nm);
}

ldx(e)
int e;
{	switch (car(e))
	{case GVAR: case RGVAR:
		ldxy(cadr(e));
		return;
	case LVAR: case RLVAR:
		ldxu(cadr(e));
		return;
	default:
		DEBUG;
	}
}

ldxy(n)
int n;
{	printf("\tLDX\t%d,Y\n",n);
}
ldxu(n)
int n;
{	printf("\tLDX\t%d,U\n",n);
}
/*
ldxi(n)
int n;
{	printf("\tLDX\t#%d\n",n);
}
*/
stx(e)
int e;
{	switch (car(e))
	{case GVAR:
		stxy(cadr(e));
		return;
	case LVAR:
		stxu(cadr(e));
		return;
	default:
		DEBUG;
	}
}

stxy(n)
int n;
{	printf("\tSTX\t%d,Y\n",n);
}
stxu(n)
int n;
{	printf("\tSTX\t%d,U\n",n);
}

sex()
{	printf("\tSEX\n");
}
incx()
{	printf("\tINC\t,X\n");
}
decx()
{	printf("\tDEC\t,X\n");
}
opdx(op)
char *op;
{	printf("\t%s\tD,X\n",op);
}
indexx(op,n)
char *op;
int n;
{	printf("\t%s\t%d,X\n",op,n);
}

index(op,e)
char *op;
int e;
{	switch (car(e))
	{case GVAR:
		indexy(op,cadr(e));
		return;
	case LVAR:
		indexu(op,cadr(e));
		return;
	default:
		DEBUG;
	}
}

indexy(op,n)
char *op;
int n;
{	printf("\t%s\t%d,Y\n",op,n);
}
indexu(op,n)
char *op;
int n;
{	printf("\t%s\t%d,U\n",op,n);
}


indir(op,e)
char *op;
int e;
{	switch (car(e))
	{case RGVAR:
		indiry(op,cadr(e));
		return;
	case RLVAR:
		indiru(op,cadr(e));
		return;
	default:
		DEBUG;
	}
}

indiry(op,n)
char *op;
int n;
{	printf("\t%s\t[%d,Y]\n",op,n);
}
indiru(op,n)
char *op;
int n;
{	printf("\t%s\t[%d,U]\n",op,n);
}
sextend(byte)
int byte;
{	if (byte) sex();
}
binexpr(e1)
int e1;
{	gexpr(caddr(e1));
	pushd();
	gexpr(cadr(e1));
	pulx();
	library(car(e1));
}
library(op)
int op;
{	printf("\tLBSR\t_0000%d\n",
	       ((op == MUL || op == UMUL) ? 1 :
		(op == DIV)	? 2 :
		(op == UDIV)	? 3 :
		(op == MOD)	? 4 :
		(op == UMOD)	? 5 :
		(op == LSHIFT)	? 6 :
		(op == ULSHIFT) ? 7 :
		(op == RSHIFT)	? 8 :
		(op == URSHIFT) ? 9 : DEBUG));
}
cexpr(e)
int e;
{	if (car(e) != CONST) error(CNERR);
	return (cadr(e));
}

getsym()
{NMTBL *nptr0,*nptr1;
int i;
char c;
	if (alpha(skipspc()))
	{	i = hash = 0;
		while (alpha(ch) || digit(ch))
		{	if (i <= 7) hash=7*(hash+(name[i++]=ch));
			getch();
		}
		name[i] = '\0';
		nptr0 = gsearch();
		if (nptr0->sc == RESERVE) return sym = nptr0->dsp;
		if (nptr0->sc == MACRO && !mflag)
		{	mflag++;
			chsave = ch;
			chptrsave = chptr;
			chptr = (char *)nptr0->dsp;
			getch();
			return getsym();
		}
		sym = IDENT;
		gnptr=nptr=nptr0;
		if (mode==GDECL || mode==GSDECL || mode==GUDECL ||
		    mode==GTDECL || mode==TOP)
			return sym;
		nptr1=lsearch();
		if (mode==STAT)
			if (nptr1->sc == EMPTY) return sym;
			else { nptr=nptr1; return sym;}
		nptr=nptr1;
		return sym;
	}
	else if (digit(ch))
	{	symval=0;
		if (ch == '0')
		{	if (getch() == 'x' || ch == 'X')
				while(1)
					if(digit(getch()))
						symval=symval*16+ch-'0';
					else if('a'<=ch&&ch<='f')
						symval=symval*16+ch-'a'+10;
					else if('A'<=ch&&ch<='F')
						symval=symval*16+ch-'A'+10;
					else break;
			else while (digit(ch)) {symval=symval*8+ch-'0';getch();}
		}
		else while(digit(ch)) {symval=symval*10+ch-'0';getch();}
		return sym=CONST;
	}
	else if(ch=='\'')
	{	getch();
		symval=escape();
		if(ch!='\'') error(CHERR);
		getch();
		return sym=CONST;
	}
	else if(ch=='"')
	{	getstring();
		return sym= STRING;
	}
	c=ch;
	getch();
	switch(c)
	{case '*':
		return postequ(MUL,MUL+AS);
	case '&':
		if(ch=='&') {getch();return sym=LAND;}
		return postequ(BAND,BAND+AS);
	case '-':
		if(ch=='>') {getch();return sym=ARROW;}
		if(ch=='-') {getch();return sym=DEC;}
		return postequ(SUB,SUB+AS);
	case '!':
		return postequ(LNOT,NEQ);
	case '~':
		return sym=BNOT;
	case '+':
		if(ch=='+') {getch();return sym=INC;}
		return postequ(ADD,ADD+AS);
	case '%':
		return postequ(MOD,MOD+AS);
	case '^':
		return postequ(EOR,EOR+AS);
	case '|':
		if(ch=='|') {getch();return sym=LOR;}
		return postequ(BOR,BOR+AS);
	case '=':
		return postequ(ASS,EQ);
	case '>':
		if(ch=='>') {getch();return postequ(RSHIFT,RSHIFT+AS);}
		return postequ(GT,GE);
	case '<':
		if(ch=='<') {getch();return postequ(LSHIFT,LSHIFT+AS);}
		return postequ(LT,LE);
	case '(':
		return sym=LPAR;
	case ')':
		return sym=RPAR;
	case '[':
		return sym=LBRA;
	case ']':
		return sym=RBRA;
	case '{':
		return sym=LC;
	case '}':
		return sym=RC;
	case ',':
		return sym=COMMA;
	case ';':
		return sym=SM;
	case ':':
		return sym=COLON;
	case '?':
		return sym=COND;
	case '.':
		return sym=PERIOD;
	case '/':
		if(ch!='*') return postequ(DIV,DIV+AS);
		getch();
		while(ch=='*'?getch()!='/':getch());
		getch();
		return getsym();
	default:
		error(CHERR);
		return getsym();
	}
}
postequ(s1,s2)
int s1,s2;
{	if(ch=='=') {getch();return sym=s2;}
	return sym=s1;
}
alpha(c)
char c;
{	return('a'<=c&&c<='z'||'A'<=c&&c<='Z'||c=='_');
}
digit(c)
char c;
{	return('0'<=c&&c<='9');
}
NMTBL *gsearch()
{NMTBL *nptr,*iptr;
	iptr=nptr= &ntable[hash % GSYMS];
	while(nptr->sc!=EMPTY && neqname(nptr->nm))
	{	if (++nptr== &ntable[GSYMS]) nptr=ntable;
		if (nptr==iptr) error(GSERR);
	}
	if (nptr->sc == EMPTY) copy(nptr->nm);
	return nptr;
}
NMTBL *lsearch()
{NMTBL *nptr,*iptr;
	iptr=nptr= &ntable[hash%LSYMS+GSYMS];
	while(nptr->sc!=EMPTY && neqname(nptr->nm))
	{	if (++nptr== &ntable[LSYMS+GSYMS]) nptr= &ntable[GSYMS];
		if (nptr==iptr) error(LSERR);
	}
	if (nptr->sc == EMPTY) copy(nptr->nm);
	return nptr;
}
neqname(p)
char *p;
{char *q;
	q=name;
	while(*p) if(*p++ != *q++) return 1;
	return *q!=0;
}
copy(p)
char *p;
{char *q;
	q=name;
	while(*p++= *q++);
}
getstring()
{	getch();
	symval = 0;
	sptr = cheapp;
	while (ch != '"')
	{	*cheapp++ = escape();
		symval++;
		if (cheapp >= cheap+CHEAPSIZE) error(STRERR);
	}
	getch();
	*cheapp++ = '\0';
	symval++;
}
skipspc()
{	while(ch=='\t'||ch=='\n'||ch==' '||ch=='\r') getch();
	return ch;
}
getch()
{	if(*chptr) return ch= *chptr++;
	if(mflag) {mflag=0;chptr=chptrsave;return ch=chsave;}
	getline();
	return getch();
}
char escape()
{char c;
	if ((c=ch) == '\\')
	{	if (digit(c=getch()))
		{	c = ch-'0';
			if (digit(getch()))
			{	c = c*8+ch-'0';
				if (digit(getch())) {c=c*8+ch-'0';getch();}
			}
			return c;
		}
		getch();
		switch(c)
		{case 'n':
			return '\n';
		case 't':
			return '\t';
		case 'b':
			return '\b';
		case 'r':
			return '\r';
		case 'f':
			return '\f';
		case '\n':
			return escape();
		default:
			return c;
		}
	}
	if (c == '\n') error(EXERR);
	getch();
	return c;
}
FILE *getfname()
{int i;
char name[14];
	getch();
	if(skipspc()!='"') error(INCERR);
	for(i=0;(getch()!='"' && ch!='\n');)
		if(i<13) name[i++]=ch;
	if(ch=='\n') error(INCERR);
	name[i]=0;
	return ( (filep+1)->fcb = fopen(name,"rc") );
}
getline()
{int i;
int c;
	lineno++;
	glineno++;
	chptr=linebuf;
	i=0;
	while ((*chptr++ = c = getc(filep->fcb)) != '\n')
	{	if (++i > LBUFSIZE-2) error(LNERR);
		if (c==EOF)
		{	error(EOFERR);
			--chptr;
		}
	}
	*chptr = '\0';
	if (lsrc && !asmf) printf("* %s",linebuf);
	if (*(chptr = linebuf) == '#')
	{	++chptr;
		if (macroeq("define"))
		{	i=mode;
			mode=GDECL;
			ch= *chptr;
			if (getsym() == IDENT)
			{	if (nptr->sc == EMPTY)
				{	nptr->sc = MACRO;
					nptr->dsp = (int)cheapp;
					while ((*cheapp++ = c = *chptr++)
							&& c != '\n');
					*cheapp++ = '\0';
					if (cheapp >= cheap+CHEAPSIZE)
						error(STRERR);
					if (!c) error(EOFERR);
				}
				else error(MCERR);
			}
			else error(MCERR);
			mode=i;
			*(chptr = linebuf) = '\0';
		}
		else if (macroeq("include"))
		{	fprintf(stderr,"%s",linebuf);
			if(filep+1 >= filestack + FILES) error(FILERR);
			if ( ((filep+1)->fcb=getfname()) == NULL) error(FILERR);
			(filep+1)->ln=lineno;
			lineno=0;
			++filep;
			*(chptr = linebuf) = '\0';
		}
		else if (macroeq("asm"))
		{	if (asmf) error(MCERR);
			asmf = 1;
			getline();
			while (asmf)
			{	printf("%s",linebuf);
				getline();
			}
		}
		else if (macroeq("endasm"))
		{	if (!asmf) error(MCERR);
			asmf = 0;
		}
		else if (macroeq(" "))
			getline();
		else error(MCERR);
	}
}

macroeq(s)
char *s;
{char *p;
	for (p = chptr; *s;) if (*s++ != *p++) return 0;
	chptr = p;
	return 1;
}

car(e)
int e;
{	return heap[e];
}
cadr(e)
int e;
{	return heap[e+1];
}
caddr(e)
int e;
{	return heap[e+2];
}
cadddr(e)
int e;
{	return heap[e+3];
}
list2(e1,e2)
int e1,e2;
{int e;
	e=getfree(2);
	heap[e]=e1;
	heap[e+1]=e2;
	return e;
}
list3(e1,e2,e3)
int e1,e2,e3;
{int e;
	e=getfree(3);
	heap[e]=e1;
	heap[e+1]=e2;
	heap[e+2]=e3;
	return e;
}
list4(e1,e2,e3,e4)
int e1,e2,e3,e4;
{int e;
	e=getfree(4);
	heap[e]=e1;
	heap[e+1]=e2;
	heap[e+2]=e3;
	heap[e+3]=e4;
	return e;
}
getfree(n)
int n;
{int e;
	switch (mode)
	{case GDECL: case GSDECL: case GUDECL: case GTDECL:
		e=gfree;
		gfree+=n;
		break;
	default:
		lfree-=n;
		e=lfree;
	}
	if(lfree<gfree) error(HPERR);
	return e;
}
rplacad(e,n)
int e,n;
{	heap[e+1]=n;
	return e;
}