/*
	Copyright 1981
	Alcyon Corporation
	8716 Production Ave.
	San Diego, Ca.  92121
*/

char *sccs "@(#)as68 - Nov 12, 1982";

/*
 * a two pass relocatable assembler for the Motorola 68000 microprocessor

 *  Bill Allen
 *	Modified by Vicki Hutchison

 *  after any of this assembler is recompiled, it must be initialized
 *  before it will execute properly.  To initialize, become super user
 *  and execute the command:

 *		as68 -i as68init

 *  where as68 is the newly compiled version of the assembler.  With-
 *  out this initialization, the assembler will not run (probably bus
 *  error).
 */

/*
 *  Revisions :
 *
 *		Added fix to make location relative equates
 *		correct even if branch optimization occurs.		vlh 15-sep-82
 *  	Recognizes commands in uppercase.				vlh 17-sep-82
 *		Added recognization of upper case directives
 *		which do not have the preceding '.'.			vlh 17-sep-82
 *		Added recognizing of ignored directives
 *		IDNT, ORG and MASK2.							vlh 17-sep-82
 *		Added new directives XDEF, XREF.				vlh 17-sep-82
 *		Added COMLINE and SECTION.						vlh 20-sep-82
 *		Added new directive REG.						vlh 21-sep-82
 *		Added new directives DCB and OFFSET.			vlh 22-sep-82
 *		Recognizes branch extensions and takes
 *		the appropriate action.							vlh 22-sep-82
 *		Added assembler directives ifeq, ifne,
 *		ifle, iflt, ifge, ifgt.							vlh 23-sep-82
 *		Added character '$' to set of legitimate
 *		characters in a symbol.							vlh 23-sep-82
 *		Added new ignored directive OPT.				vlh 23-sep-82
 *		Recognizes non-opcodes starting in column 1
 *		as labels.										vlh 23-sep-82
 *		Added conditional assembler directives
 *		ifc, ifnc.										vlh 27-sep-82
 *		Major reworking of expression handler			vlh  1-oct-82
 *		More revisions to expression stacks				vlh  4-oct-82
 *		Added the recognition and handling of			vlh 26-oct-82
 *		the 'illegal' instruction.
 *		Added handling of the jmp suffixes				vlh 26-oct-82
 *		Fixed problem with -p flag and external			vlh 27-oct-82
 *		variable listings.
 *		Added checking for legitimate command 			vlh 28-oct-82
 *		suffixes.
 *		Added comma as a legitimate register			vlh 28-oct-82
 *		divisor for the REG directive.
 *		Fixed second pass error/instr len problem		vlh 28-oct-82
 *		Added checking for invalid bit ranges.			vlh  1-nov-82
 *		Added proper 2nd pass handling of the			vlh  2-nov-82
 *		'*' symbol (avoid turning jsr to bra).
 *		Fixed first pass guess if operand is			vlh  4-nov-82
 *		(rx,rx) instead of d(rx,rx).
 *		Check for appropriate range of 16-bit			vlh  5-nov-82
 *		immediate date.
 *		Operand type check for shift/bit manip.			vlh  5-nov-82
 *		Turn and/or/eor #xxx,sr/ccr into the			vlh  5-nov-82
 *		corresponding immediate instruction.
 *		Generate an error when an illegal pc			vlh 10-nov-82
 *		relative ea is specified.
 */

/****************************************************************************/
/*									    */
/*			    D R I   H a c k s				    */
/*			    -----------------				    */
/*									    */
/*	The following changes were made to facilitate running as68 under    */
/*	VMS and CP/M:							    */
/*									    */
/*	o	Added "-f" flag to redirect temp files to another directory */
/*		or CP/M floppy drive.					    */
/*									    */
/*	o	Added "-s" flag to redirect symbol table file.		    */
/*									    */
/*	o	Added separate source file with initialization of all 	    */
/*		external variables to be compatible with Whitesmith's C.    */
/*									    */
/*	o	Added "VMS", "UNIX", and "CPM" conditional compilation 	    */
/*		switches for these operating systems.			    */
/*									    */
/*	o	Added various listing enhancements so the printed file is   */
/*		usable on non-UNIX environments.			    */
/*									    */
/****************************************************************************/



# include "as68.h"
char  tfilname[80];			/* Temp filename area 		*/
char  initfnam[80];			/* Initialization filename area */
#ifdef	UNIX
char  tfilbase[] {"a6AXXXXXX"};
#else
char  tfilbase[] {"a6xxxxA"};		/* Temp file base name		*/
#endif
char  initbase[] {"as68symb.dat"};	/* Init file base name		*/
#ifdef	VMS				/* On VMS, use			*/
char *tdname = "";			/* Temps in same directory	*/
char *idname = "bin:";			/* Init  in the "bin:" directory*/
#endif					/********************************/
#ifdef	UNIX				/*				*/
char *tdname = "/tmp/";			/* UNIX Temp directory		*/
char *idname = "/lib/";			/* UNIX Init Directory		*/
#endif					/********************************/
#ifdef	CPM				/* On CP/M, defaults for all.	*/
char *tdname = "";			/* No temp prefix		*/
char *idname = "";			/* No init prefix		*/
#endif					/********************************/

char ldfn[40];			/*name of the relocatable object file*/

int brkln1 077777;		/*pass 1 break line number for debugging*/
int opcval;				/*opcode*/
int chmvq;

int hopd(), hend(), send(), horg(), sorg(), hequ(), hreg();
int hds(), sds();
int sdcb();
int hdsect(), hpsect(), sdsect(), spsect();
int hsection(), ssection(), hoffset();
int hent(), hext();
int igrst();
int hbss(), sbss();
int heven(), seven();
int hdc(), sdc(), hdcb();
int hmask2(), hcomline(), hidnt();
int hifeq(), hifne(), hiflt(), hifle(), hifgt(), hifge(), hendc();
int hifnc(), hifc(), hopt();
int hpage(),spage();
int (*p1direct[])() {
	hopd,		/*0*/
	hend,		/*1*/
	hdsect,		/*2*/
	hpsect,		/*3*/
	hequ,		/*4*/
	hequ,		/*5 .set same as .equ*/
	0,			/*6*/
	0,			/*7*/
	hdc,		/*8*/
	hent,		/*9*/
	hext,		/*10*/
	hbss,		/*11*/
	hds,		/*12*/
	heven,		/*13*/
	horg,		/*14*/
	hmask2,		/*15*/
	hreg,		/*16*/
	hdcb,		/*17*/
	hcomline,	/*18*/
	hidnt,		/*19*/
	hoffset,	/*20*/
	hsection,	/*21*/
	hifeq,		/*22*/
	hifne,		/*23*/
	hiflt,		/*24*/
	hifle,		/*25*/
	hifgt,		/*26*/
	hifge,		/*27*/
	hendc,		/*28*/
	hifc,		/*29*/
	hifnc,		/*30*/
	hopt,		/*31*/
	hpage,		/*32*/
	0};

int (*p2direct[])() {
	0,			/*0*/
	send,		/*1*/
	sdsect,		/*2*/
	spsect,		/*3*/
	0,			/*4*/
	0,			/*5*/
	0,			/*6*/
	0,			/*7*/
	sdc,		/*8*/
	0,			/*9*/
	0,			/*10*/
	sbss,		/*11*/
	sds,		/*12*/
	seven,		/*13*/
	sorg,		/*14*/
	0,			/*15*/
	0,			/*16*/
	sdcb,		/*17*/
	sds,		/*18 comline same as .ds.b*/
	0,			/*19*/
	0,			/*20*/
	ssection,	/*21*/
	0,			/*22*/
	0,			/*23*/
	0,			/*24*/
	0,			/*25*/
	0,			/*26*/
	0,			/*27*/
	0,			/*28*/
	0,			/*29*/
	0,			/*30*/
	0,			/*31*/
	spage,			/*32*/
	0};

char *ermsg[] {
	"label redefined",					/*1*/
	"invalid label",					/*2*/
	"invalid opcode",					/*3*/
	"no label for operand",					/*4*/
	"opcode redefined",					/*5*/
	"illegal expr",						/*6*/
	"undefined symbol in equate",				/*7*/
	0,									/*8*/
	"invalid first operand",			/*9*/
	"invalid second operand",			/*10*/
	"absolute value required",			/*11*/
	"no code or data allowed in offset",	/*12*/
	"undefined symbol",					/*13*/
	"illegal index register",			/*14*/
	"illegal constant",					/*15*/
	"illegal extension",				/*16*/	/*[vlh]*/
	"constant required",				/*17*/
	"illegal format",					/*18*/
	"illegal string",					/*19*/
	"illegal addressing mode",			/*20*/
	0,									/*21*/
	"illegal relative address",			/*22*/
	"invalid bit range",				/*23*/
	"illegal text delimiter",			/*24*/
	"unexpected endc",					/*25*/
	"endc expected",					/*26*/
	"relocation error",					/*27*/
	"symbol required",					/*28*/
	"bad use of symbol",				/*29*/
	"invalid data list",				/*30*/
	0,									/*31*/
	"missing )",						/*32*/
	"register required",				/*33*/
	"illegal size",						/*34*/
	"illegal 8-bit displacement",		/*35*/
	"illegal external",					/*36*/
	"illegal shift count",				/*37*/
	"invalid instruction length",		/*38*/
	"code or data not allowed in bss",	/*39*/
	"backward assignment to *",			/*40*/
	"illegal 16-bit displacement",		/*41*/
	"illegal 16-bit immediate",			/*42*/
	"illegal 8-bit immediate",			/*43*/
	0
};

int endit();
int rubout();
int symcon;
char endstr[] "end";
char equstr[] "equ";
char evnstr[] "even";
char orgstr[] "~.yxzorg";

int poslab;
char tlab1[NAMELEN];
int explmode;	/*explicit mode length given*/

main(argc,argv)
char **argv;
{
	register i, ttmp;

	register xargc;		/* Temp copy of argc		*/
	xargc = argc;

	initflg = 0;
	prtchidx = prtchars;
#ifdef	UNIX			/* Only available with UNIX	*/
	signal(2,rubout);
#endif
	pitix = itbuf;
	pexti = extbl;
	ttmp = (STESIZE*SZMT) + 2;
	bmte = sbrk(ttmp);
	if(((long)bmte) == -1L)
	{
		rpterr("Symbol Table Overflow\n");
		abort();
	}
	if((long)bmte&1)
		bmte++;		/*make it even*/
	emte = bmte + ttmp - 2;		/*end of main table*/
	if(argc<=1) usage();
	i = 1;
	shortadr = -1;	/*short addresses ok*/
	while(argv[i][0] == '-') {		/*may be print or initialize*/
		switch(argv[i++][1]) {

		case 'i':		/*initialize the assembler*/
		case 'I':
			initflg++;
			break;

		case 'p':		/*produce a listing*/
		case 'P':
			prtflg++;
			break;

		case 'u':		/*make undefined symbols external*/
		case 'U':
			undflg++;
			break;

		case 'N':		/*no branch optimization*/
		case 'n':
			didorg++;
			break;

		case 'L':		/*long addresses only*/
		case 'l':
			shortadr = 0;
			break;

		case 'f':		/* Change temp files	*/
		case 'F':
			tdname = argv[i++];
			break;

		case 's':		/* Change symbol table name */
		case 'S':
			idname = argv[i++];
			break;

		default:
			usage();
		}
	}
	strcat (tfilname,tdname);	/* Build temp filenames */
	strcat (tfilname,tfilbase);	/*			*/
					/**************************/
#ifdef	UNIX				/* For UNIX, Need to make */
	mktemp (tfilname);		/* Unique file name	  */
#endif					/**************************/
	tfilptr = &tfilname[strlen(tfilname)-1];	/* -> changed char */
#ifdef	UNIX
	tfilptr -= 6;			/* Back off PID		*/
#endif
	
	strcat (initfnam,idname);	/* Build Symbol table filename	    */
	strcat (initfnam,initbase);

	if(i>=argc) usage();
	ifn=open(argv[i],0,0);	/*open source file*/
	sfname = argv[i];	/* remember source filename */
	setldfn(argv[i]);	/*create relocatable object file name*/
	lfn=openfi(ldfn,1);	/*open loader file*/
	itfn = gettempf();	/*get a temp file for it*/
	itfnc = LASTCHTFN;	/*remember last char for unlink*/
	trbfn = gettempf();	/*temp for text relocation bits*/
	trbfnc = LASTCHTFN;
	dafn = gettempf();	/*temp for data binary*/
	dafnc = LASTCHTFN;
	drbfn = gettempf();	/*temp for data relocation bits*/
	drbfnc = LASTCHTFN;
	if(initflg) {		/*initializing te main table*/
		lmte=bmte;		/*beginning main table*/
		cszmt = SZMT;	/*current size of main table*/
		for(i=0; i<=SZIRT-2; i=+2) {
			sirt[i] = &sirt[i];		/*initialize the initial ref tables*/
			sirt[i+1] = 0;
			oirt[i] = &oirt[i];
			oirt[i+1] = 0;
		}

/*make entries in main table for directives*/
		mdemt("opd",0);			/*opcode definition*/
		mdemt(endstr,1);		/*end statement*/
		mdemt("data",2);		/*dsect directive(code DATA based)*/
		mdemt("text",3);		/*psect directive(code TEXT based)*/
		mdemt(equstr,4);		/*equate*/
		mdemt("set",5);			/*.set - same as .equ*/
		mdemt("dc",8);			/*define byte*/
		mdemt("globl",9);		/*define global (public) symbols*/
		mdemt("xdef",9);		/*[vl]define global (public symbols*/
		mdemt("xref",9);		/*[vl]define global (public) symbols*/
		mdemt("comm",10);		/*define external symbols*/
		mdemt("bss",11);		/*block storage based*/
		mdemt("ds",12);			/*block storage based*/
		mdemt(evnstr,13);		/*round pc*/
		mdemt(orgstr,14);		/*internal org for *=n*/
		mdemt("org",14);		/*[vlh]*/
		mdemt("mask2",15);		/*[vl] assemble for mask2, ignore*/
		mdemt("reg",16);		/*[vlh] register equate*/
		mdemt("dcb",17);		/*[vlh] define block*/
		mdemt("comline",18);	/*[vlh] command line*/
		mdemt("idnt",19);		/*[vlh] relocateable id record, ignore*/
		mdemt("offset",20);		/*[vlh] define offsets*/
		mdemt("section",21);	/*[vlh] define sections*/
		mdemt("ifeq",22);		/*[vlh] ca if expr = 0*/
		mdemt("ifne",23);		/*[vlh] ca if expr != 0*/
		mdemt("iflt",24);		/*[vlh] ca if expr < 0*/
		mdemt("ifle",25);		/*[vlh] ca if expr <= 0*/
		mdemt("ifgt",26);		/*[vlh] ca if expr > 0*/
		mdemt("ifge",27);		/*[vlh] ca if expr >= 0*/
		mdemt("endc",28);		/*[vlh] end ca*/
		mdemt("ifc",29);		/*[vlh] ca if string compare*/
		mdemt("ifnc",30);		/*[vlh] ca if not string compare*/
		mdemt("opt",31);		/*[vlh] ignored, assemb options*/
		mdemt("ttl",31);		/* Ignore title op also */
		mdemt("page",32);

	}
	else {	/*not initializing*/
		getsymtab();		/*read initialized main table*/
	}

	rlflg = TEXT;			/*code initially TEXT based*/
	inoffset = 0;			/*[vlh]not in offset mode*/
	loctr = 0;				/*no generated code*/
	ca = 0;					/*[vlh]depth of conditional assembly*/
	extindx = 0;			/*no external symbols yet*/
	p2flg = 0;				/*pass 1*/
	ca_true = 1;			/*[vlh]true unless in side false case*/
	absln = 1;
	sbuflen = -1;			/*no source yet*/
	fchr = gchr();			/*get first char*/
	if(!initflg) {		/*not initializing*/
		pack(orgstr,lmte);
		orgptr = lemt(oirt,TRUE);
		pack(endstr,lmte);
		endptr = lemt(oirt,TRUE);
		pack(equstr,lmte);
		equptr = lemt(oirt,TRUE);
		pack("add",lmte);
		addptr = lemt(oirt,TRUE);
		pack("addi",lmte);
		addiptr = lemt(oirt,TRUE);
		pack("addq",lmte);
		addqptr = lemt(oirt,TRUE);
		pack("sub",lmte);
		subptr = lemt(oirt,TRUE);
		pack("subi",lmte);
		subiptr = lemt(oirt,TRUE);
		pack("subq",lmte);
		subqptr = lemt(oirt,TRUE);
		pack("cmp",lmte);
		cmpptr = lemt(oirt,TRUE);
		pack("adda",lmte);
		addaptr = lemt(oirt,TRUE);
		pack("cmpa",lmte);
		cmpaptr = lemt(oirt,TRUE);
		pack("suba",lmte);
		subaptr = lemt(oirt,TRUE);
		pack("cmpm",lmte);
		cmpmptr = lemt(oirt,TRUE);
		pack("and",lmte);
		andptr = lemt(oirt,TRUE);
		pack("andi",lmte);
		andiptr = lemt(oirt,TRUE);
		pack("or",lmte);
		orptr = lemt(oirt,TRUE);
		pack("ori",lmte);
		oriptr = lemt(oirt,TRUE);
		pack("cmpi",lmte);
		cmpiptr = lemt(oirt,TRUE);
		pack("eor",lmte);
		eorptr = lemt(oirt,TRUE);
		pack("eori",lmte);
		eoriptr = lemt(oirt,TRUE);
		pack("move",lmte);
		moveptr = lemt(oirt,TRUE);
		pack("moveq",lmte);
		moveqptr = lemt(oirt,TRUE);
		pack("exg",lmte);
		exgptr = lemt(oirt,TRUE);
		pack("jsr",lmte);
		jsrptr = lemt(oirt,TRUE);
		pack("bsr",lmte);
		bsrptr = lemt(oirt,TRUE);
		pack("nop",lmte);
		nopptr = lemt(oirt,TRUE);
		pack(evnstr,lmte);
		evenptr = lemt(oirt,TRUE);
	}
	mloop();
}

usage()
{
     rpterr("Usage: as68 [-p] [-u] [-l] [-n] [-f d:] [-s d:] sourcefile\n");
     endit();
}


/*main loop*/
mloop()
{
	register i;

	while(fchr!=EOF) {
		if(absln>=brkln1)	/*break for debugging the assembler*/
			i=0;
		fcflg = 0;			/*first time thru expr pass one*/
		cisit();			/*create it for one statement*/
	}
	opcpt = endptr;
	hend();
}

#define NOCODE ((i>=0&&i<6)||i==9||i==11||i==16||(i>=LOW_CA&&i<=HI_CA))

/*create intermediate text (it) for one statement*/
/*	call with first character of statement in fchr*/
cisit()
{

	register int *p1,*p2;
	register int (*dirop)();
	register int i, col1;	/*[vlh] col1 labels in col 1...*/
	char str[NAMELEN], *l;

ciss1:
	immed[0] = immed[1] = indir[0] = indir[1] = numcon[0] = 0;
	numcon[1] = numsym[0] = numsym[1] = numreg[0] = numreg[1]=0;
	plevel = numops = opdix = explmode = 0;
cistop:
	col1 = 1;
	if(fchr==EOLC) {
		fchr = gchr();
		goto cistop;
	}
	if(fchr==' ') {
		col1 = 0;
		igblk();
		if(fchr==EOLC)		/*blank line*/
			goto cistop;
		peekc = fchr;
		if (fchr != EOF) fchr = ' ';	/* [vlh] catch eof... */
	}
	if(fchr==EOF) return;

	if(fchr=='*') {			/*ignore comments*/
		fchr = gchr();
		if(fchr=='=') {		/*relocation counter assignment*/
			fchr = gchr();	/*pass the =*/
			horg();			/*output constants if not bss*/
		}
		igrst();
		fcflg = 0;		/*clear expr first time flag for next stmt*/
		goto ciss1;
	}

/* get the opcode and label*/

	mode = 'w';			/*word mode*/
	igblk();			/*ignore blanks*/
	poslab = 1;
	gterm(TRUE);
	poslab = 0;
	if(fchr==':' || fchr=='=') {			/*there is a label*/
label:
		col1 = 0;
		if(itype!=ITSY) {			/*not a symbol*/
			uerr(2);
			lbt[0] = 0;		/*no label*/
		}
		else {
			p2 = &lmte->name[0];
			for(p1= &lbt[0]; p1 < &lbt[NAMELEN]; ) {
				*p1++ = *p2++;
			}
			if(fchr==':') fchr=gchr();		/*ignore the colons*/
		}
labl1:
		ligblk();
		if(fchr == EOF) return;
		if(fchr == '*') {
			igrst();		/*comment*/
			goto labl1;
		}
		gterm(TRUE);
		if(fchr==':' || fchr=='=') {	/*another label*/
			if(lbt[0]) {
				savelab();	/*save current label*/
				dlabl();	/*define the last one*/
				pack(tlab1,lmte);	/*restor the old lable*/
			}
			goto label;
		}
	}
	else {
		lbt[0] = 0;			/*no label*/
	}
	igblk();
	if(fchr == '=')
		goto label;
	if(itype==ITSP) {
		if(ival.wd2 == '=') {
			hequ();
			return;
		}
	}
	if(itype!=ITSY) {	/*not valid opcode*/
		goto cisi3;
	}
	if (col1) {	/* [vlh] could be a label save as is... */
		l = &str;
		strcpy(l,lmte->name,NAMELEN);
	}
	if((opcpt=lemt(oirt,TRUE))==lmte) {	/*not in opcode table*/
		if (col1) {	/* [vlh] it's a label... */
			strcpy(lmte->name,l,NAMELEN);
			goto label;
		}
cisi3:
		if (ca_true)	/* [vlh] report error if not in CA false */
			xerr(3);
		igrst();
		return;
	}
	getmode();		/*look for .b .w or .l mode flag*/
	if(opcpt->flags&OPDR) {	/* its a directive*/
		i = opcpt->vl1;
		if (!ca_true && (i < LOW_CA || i > HI_CA)) { igrst(); return; }
		if (inoffset) 	/* [vlh] */
			if (!(NOCODE)) {	/* can't generate code in offset */
				xerr(12);
				return;
			}
		dirop = p1direct[i];	/*call routine to handle directive*/
		(*dirop)();
		return;
	}
	else if (!ca_true) {		/* [vlh] */
		igrst();
		return;
	}
	else if (inoffset) {		/* [vlh] */
		xerr(12);
		return;
	}

	opcval = (opcpt->vl1);			/*opcode*/
	format = (opcpt->flags&OPFF);	/*format of this instr*/
	if (explmode)
		if (!modeok()) { xerr(16);  return; }
	dlabl();			/*define label*/
	opitb();			/*beginning of statement*/
	if(format)
		opito();		/*may have operands*/
	else
		igrst();		/*only comments*/
	format = (opcpt->flags&OPFF);	/* may have changed*/


/*end of statement*/

	i = calcilen();
	stbuf[1].itrl = i;		/*assumed instruction length*/

	stbuf[0].itrl = itwc;	/*number of it entries*/
	wostb();			/*write out statement buffer*/
	loctr =+ i;
}

getmode()
{
	if (fchr=='.') {
		fchr = gchr();
		switch (fchr) {
			case 'b':
			case 'B':
			case 's':
			case 'S':
				modelen = 1;
				mode = BYTE;
				break;
			case 'w':
			case 'W':
				modelen = 2;
				mode = WORD;
				break;
			case 'l':
			case 'L':
				modelen = 4;
				mode = LONG;
				break;
			default:
				peekc = fchr;
				fchr = '.';
				goto getm1;
		}
		explmode++;
		fchr = gchr();
		igblk();
		return;
	}
getm1:
	if(opcpt == exgptr) {	/*length is long*/
		modelen = 4;
		mode = LONG;
	}
	else {
		mode = WORD;		/*default is word*/
		modelen = 2;
	}
}

/* check to be sure specified mode is legal */
modeok()	/* [vlh] */
{
	switch(format) {
		case 0  :
		case 14 :
		case 18 :
			return(FALSE);
		case 13 :
		case 15 :
		case 20 :
		case 21 :
			return(modelen==1?FALSE:TRUE);
		case 4  :
		case 25 :
			return(modelen==1?TRUE:FALSE);
		case 7  :
		case 9  :
			return(modelen==2?FALSE:TRUE);
		case 5  :
		case 11 :
		case 28 :
			return(modelen==2?TRUE:FALSE);
		case 6  :
			return(modelen==4?FALSE:TRUE);
		case 12 :
		case 30 :
		case 22 :
		case 29 :
			return(modelen==4?TRUE:FALSE);
		default :
			return(TRUE);
	}
}

/* calculate the instruction length in bytes*/
calcilen()
{

	register i,j;
	register long l;
	register char *p;

	i = 2;		/*all instrs at least 2 bytes*/

	switch(format) {

	case 20:
		i =+ 2;	/*for reg mask*/
	case 1:		/*two ea's -- one of which may be a reg*/
	case 15:
	case 30:
	case 26:
	case 5:
	case 3:
	case 21:
		i =+ lenea(1);
	case 16:
	case 24:
	case 25:
	case 29:
		i =+ lenea(0);
		break;

	case 9:		/* [vlh] explicit jmp length... */
		if (!explmode)
			i =+ lenea(0);
		else
			return(mode==LONG?6:4);	/*[vlh] explicit jmp.? */
		break;

	case 7:
		i =+ (immed[0]) ? 2+lenea(1) : lenea(1);
		break;

	case 14:
	case 11:
	case 19:
		i =+ 2;		/*always 4 bytes*/
		break;

	case 6:		/*relative branches*/
		if(itwc == ITOP1+1) {
			if(stbuf[ITOP1].itty == ITCN)
				l = stbuf[ITOP1].itop;
			else if(stbuf[ITOP1].itty == ITSY) {
				p = stbuf[ITOP1].itop.ptrw2;
				if(p->flags&SYDF)
					l = p->vl1;	/*symbol value*/
				else
					goto loffst;
			}
			else {
				goto loffst;
			}
			l =- (loctr+2);
			if(l<=127 && l>=-128)	/*8 bit offset*/
				break;
		}
loffst:
		if (!explmode || modelen > 1) /*[vlh] recognize br extensions*/
			i =+ 2;		/*long offset for branches*/
		break;

	case 2:
		i =+ (mode==LONG?4:2) + lenea(1);
		break;

	case 23:
		if(immed[0])
			i =+ (mode==LONG?4:2);
	case 17:
	case 22:
		i =+ lenea(1);
		break;

	case 8:
		if(numops==1)		/*memory shift instruction*/
			i =+ shiftea(0);
		break;
	}

	return(i);
}

/* calc the length of an effective address*/
lenea(lidx)
{
	register i;

	if(immed[lidx])
		return(mode==LONG?4:2);
	return(shiftea(lidx));
}

shiftea(lidx)
{
	if(indir[lidx])
		return((numcon[lidx] || numsym[lidx]) ? 2 : 0);
	if(numsym[lidx] || numcon[lidx])
		return((!shortadr || numcon[lidx]==2) ? 4 : 2);
	return(0);
}

/*
 *define a label if there is one to define
 *	call with:
 *		label name in lbt if it exists
 *		else lbt[0] == 0
 */
dlabl()
{
	register i;

	if(lbt[0]) {	/*got a label*/
		pack(lbt,lmte);		/*put label in main table*/
		lblpt=lemt(sirt,FALSE);	/*look up label*/
		if(lblpt != lmte) {		/*symbol entered previously*/
			if(lbt[0] == '~') {	/*local symbol -- may be duplicate*/
				lblpt = lmte;
				mmte();
			}
			else {
				if(lblpt->flags&SYXR) {
					uerr(29);
					lblpt = 0;
					return;
				}
				if((lblpt->flags)&SYDF) {
					uerr(1);
					lblpt = 0;
					return;
				}
			}
		}
		else {
			mmte();		/*make label entry in main table*/
		}
		lblpt->flags =| SYDF;	/*label is now defined*/
		lblpt->flags =| (rlflg==DATA)?SYRA:(rlflg==BSS)?SYBS:SYRO;
		lblpt->vl1 = loctr;		/*label value*/
	}
	else
		lblpt = 0;
}

/*
 * output it for operands
 *		gets intput from gterm
 *		puts output in stbuf using itwc as an index
 *		itwc should point at the next entry to be made in stbuf
 */
opito()
{
	register lopcomma;

	lopcomma = symcon = chmvq = 0;
	numops++;				/*count first operand*/
	while(1) {
		starmul = symcon;	/*star is multiply op if flag is set*/
		if(fchr=='\'' || fchr=='"')
			lopcomma = 0;
		gterm(FALSE);	/*get a term*/
		if(itwc==ITOP1 && format==CLRFOR && opcval==CLRVAL)
			chgclr();
		opitoo();	/*output it for one operand*/
		if(itype==ITSP && ival.wd2==',') {
			if (plevel==1 && !numcon[opdix])	/* [vlh] */
				numcon[opdix] = 1;
			if(lopcomma)
				uerr(30);
			lopcomma++;
			igblk();	/*ignore blanks for 68000 C compiler*/
		}
		else
			lopcomma=0;
		if(ival==EOLC && itype==ITSP)	/*end of operands*/
			break;
		if(fchr==EOLC) {
			fchr=gchr();
			break;
		}
	}
	if(chmvq)		/*changed move to moveq*/
		if(numops!=2 || immed[1] || indir[1] || numcon[1] || numsym[1] ||
		  numreg[1]>=AREGLO) {
			stbuf[2].itop.ptrw2 = moveptr;	/*change it back*/
			opcpt = moveptr;
		}

	if (stbuf[2].itop.ptrw2==cmpptr) 	/* [vlh] cmp -> cmpm ?? */
		if (numreg[0] && numreg[1] && indir[0] && indir[1]) {
			stbuf[2].itop.ptrw2 = cmpmptr;
			opcpt = cmpmptr;
		}

	if(lopcomma)
		uerr(30);
}

/* change clr.l An to suba.l An,An*/
chgclr()
{
	register char *p;

	if(itype==ITSY) {	/*first op is symbol*/
		p = lemt(sirt,FALSE);
		if(p==lmte)
			return;
		if(!(p->flags&SYER) || p->vl1<AREGLO)		/*not A reg*/
			return;
		opcpt = subaptr;	/*make it a suba instr*/
		opitb();
		opitoo();		/*output first operand -- An*/
		itype = ITSP;
		ival = ',';
		opitoo();		/*output a comma*/
		itype = ITSY;	/*now the A reg again*/
	}
}

/*output it for one operand*/
opitoo()
{
	register i;
	register char *sp;

	symcon = 0;
	if(itype==ITSP) {				/*special symbol*/
		if(ival.wd2==',' && !plevel) {		/* another operand */
			numops++;
			if(!opdix)
				opdix++;
		}
		if(ival.wd2==' ') {		/*end of operands*/
			while(fchr!=EOLC)		/*ignore rest of statement*/
				fchr=gchr();
			return;
		}
		if(ival.wd2==EOLC)
			return;
	}
	else		/*symbol or constant*/
		symcon = 1;

	if(itwc >= STMAX) {			/*it overflow*/
		rpterr("i.t. overflow\n");
		abort();
	}
	pitw->itty = itype;		/*type of it entry*/

/*put symbol in it buffer*/
	if(itype==ITSY) {
		sp=lemt(sirt,FALSE);		/*look up it main table*/
		pitw->itop.ptrw2 = sp;	/*ptr to symbol entry*/
		if(sp==lmte)			/*first occurrance*/
			mmte();
		itwc++;				/*count entries in it buffer*/
		pitw++;
		if(!(sp->flags&SYER))	/*is it a register?*/
			numsym[opdix]++;
		else		/*yes, a register*/
			numreg[opdix] = sp->vl1;
		return;
	}
	else if(itype == ITCN ) {
		if(ival.wd1 && ival.wd1 != -1)
			numcon[opdix] = 2;
		else if(!numcon[opdix])
			numcon[opdix] = 1;
		if(numops == 1)
			tryquick();
	}

/* special characters and constants*/
	pitw->itop = ival;
	pitw->itrl = reloc;
	itwc++;
	pitw++;
}

/* change add into addq and sub into subq if possible*/
tryquick()
{
	register char *p;
	register long l;

	if(fchr!=',' || !immed[0])
		return;
	l = ival;
	if(itwc != ITOP1+1) {
		if(itwc!=ITOP1+2 || stbuf[ITOP1+1].itty!=ITSP ||
		  stbuf[ITOP1+1].itop.wd2 != '-')
			return;
		l = -l;
	}
	p = stbuf[2].itop.ptrw2;
	if(p==moveptr) {
		if(explmode && modelen != 4)	/*dont change .w or .b*/
			return;
		if(l>=-128 && l<=127) {
			stbuf[2].itop.ptrw2 = moveqptr;
			opcpt = moveqptr;
			chmvq++;
		}
		return;
	}
	if(l<=0 || l>8) {
		return;
	}
	if(p==addptr || p==addiptr) {
		stbuf[2].itop.ptrw2 = opcpt = addqptr;
	}
	else if(p==subptr || p==subiptr) {
		stbuf[2].itop.ptrw2 = opcpt = subqptr;
	}
}

strcpy(str1, str2, len)
register char *str1, *str2;
register int len;
{
	while (len--)
		*str1++ = *str2++;
}

/* index - find the index of a character in a string*/
/*		This is identical to Software Tools index.*/
index(str,chr)				/* returns index of c in str or -1*/
char *str;				/* pointer to string to search*/
char chr;				/* character to search for*/
{
	register char *s;
	register int i;

	for( s = str, i = 0; *s != '\0'; i++ )
		if( *s++ == chr )
			return(i);
	return(-1);
}

