[comp.sources.amiga] v89i026: a68k - 68000 assembler v2.42, Part04/04

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

Submitted-by: jlydiatt@jlami.wimsey.bc.ca (Jeff Lydiatt)
Posting-number: Volume 89, Issue 26
Archive-name: languages/a68k242.4

#	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:
#	Symtab.c
#	Operands.c
# This archive created: Tue Mar  7 20:42:31 1989
cat << \SHAR_EOF > Symtab.c
/*------------------------------------------------------------------*/
/*								    */
/*		      MC68000 Cross Assembler			    */
/*								    */
/*	      Copyright	(c) 1985 by Brian R. Anderson		    */
/*								    */
/*	   Symbol table	manipulation - January 6, 1989		    */
/*								    */
/*   This program may be copied	for personal, non-commercial use    */
/*   only, provided that the above copyright notice is included	    */
/*   on	all copies of the source code.	Copying	for any	other use   */
/*   without the consent of the	author is prohibited.		    */
/*								    */
/*------------------------------------------------------------------*/
/*								    */
/*		Originally published (in Modula-2) in		    */
/*	    Dr.	Dobb's Journal, April, May, and June 1986.          */
/*								    */
/*	 AmigaDOS conversion copyright 1989 by Charlie Gibbs.	    */
/*								    */
/*------------------------------------------------------------------*/

#include <stdio.h>
#include "a68kdef.h"
#include "a68kglb.h"

long Value;	/* Passed from ReadSymTab to CalcValue */

/* Functions */
extern int  Instructions(), ObjDir();
extern int  GetInstModeSize(), GetMultReg();
extern int  GetArgs(), GetAReg();
extern long AddrBndW(),	AddrBndL();
char *AddName();
struct SymTab *NextSym();
struct SymTab **HashIt();

int  LineParts(), ReadSymTab(),	OpenIncl(), CountNest();
long GetValue(), CalcValue();
char *GetField();



int OpenIncl (name, dirlist) char *name, *dirlist;
/* Opens the file whose	name is	in "name".  The current
    directory is tried first.  If that fails, the directory
    names in "dirlist" (separated by commas) are then tried
    until either a file	is found or the	list is	exhausted.
    If the file	is found in a subdirectory, "name" is
    modified to	include	the entire path	specification.
    If another input file is open when this routine is called,
    it is closed first.	 Returns TRUE if successful, FALSE if not.  */
{
    register char *s, *t;
    char dirname[MAXLINE];

    if (In.fd != NULL)
	close (In.fd);		/* Close the inner file	*/

    if ((In.fd = open (name, 0)) != -1)	{
	In.Ptr = In.Lim	= In.Buf;
	if (Quiet < 0)
	    fprintf (stderr, "\n%s line ", name);
	return (TRUE);		/* Found it in current directory */
    }
    s =	dirlist;
    while (*s) {
	s = GetField (s, dirname);
	t = dirname + strlen (dirname) - 1;
	if ((*t	!= '/') && (*t != ':'))
	    strcat (dirname, "/");      /* Slash after directory name */
	strcat (dirname, name);
	if ((In.fd = open (dirname, 0))	!= -1) {
	    In.Ptr = In.Lim = In.Buf;
	    strcpy (name, dirname);	/* Return entire path */
	    if (Quiet <	0)
		fprintf	(stderr, "\n%s line ", name);
	    return (TRUE);	/* Found it in a subdirectory */
	}
	if (*s)
	    s++;		/* Skip	over separator and try again */
    }
    In.fd = NULL;
    return (FALSE);		/* Couldn't find it anywhere */
}



int LineParts (dummy) int dummy;
/* Gets	the next statement and extracts	its component parts.
    If end of file is reached, and we're in a macro or include
    file, the file is closed and the next outermost file is
    continued.	If we have reached the end of the source file, or
    encounter an ENDM or MEXIT directive within	a macro	expansion,
    the	current	input file is closed and TRUE is returned.

    If we're in a user macro (indicated by UPtr being nonzero),
    we'll get the next statement from the save area in memory instead.

    Macro arguments, if	any, are substituted.

    LineCount is incremented if	a statement was	successfully read.

    If this is the first call of this routine (i.e. LineCount is zero)
    and	HeaderFN is not	a null string, we'll return an INCLUDE statement
    requesting the specified header file, rather than reading the first
    statement from the source file.

    The	following fields are set up:
	Line	- statement line image
	Label	- instruction label (without trailing colon)
	OpCode	- instruction mnemonic (converted to upper case)
	SrcOp	- first	(source) operand
	DestOp	- second (destination) operand
	Size	- size from OpCode
	LabLoc	- displacement to start	of instruction label
	OpLoc	- displacement to start	of instruction mnemonic
	SrcLoc	- displacement to start	of source operand
	DestLoc	- displacement to start	of destination operand
	InFNum	- decremented if end of	file is	reached
	InF	- incremented if end of	file is	reached
	LabLine	- set to LineCount if this line	is labeled
			(unless	it's a local label)
								*/
{
    register int i, c;
    int	eofflag;
    char *x;


    while (1) {	/* Repeat until	we get something (not end of INCLUDE) */
	Line[0]	= Label[0] = OpCode[0] = SrcOp[0] = DestOp[0] =	'\0';
	LabLoc = OpLoc = SrcLoc	= DestLoc = 0;
	Src.Mode = Dest.Mode = NULL;
	FwdShort = FALSE;

	if ((LineCount==0) && (HeaderFN[0])) {	/* Header file */
	    strcpy (Line, "        INCLUDE ");  /* Make an INCLUDE stmt. */
	    strcat (Line, HeaderFN);
	    strcat (Line, "        ;Generated for header file");
	    strcpy (OpCode, "INCLUDE"); /* Dummy op code */
	    OpLoc = 8;
	    strcpy (SrcOp, HeaderFN);	/* Dummy source	operand	*/
	    SrcLoc = 16;
	    LineCount++;
	    ErrLim = AddrAdv = InstSize	= nO = nS = nD = nX = 0;
	    PrntAddr = FALSE;
	    return (FALSE);
	}

	if (InF->UPtr != 0) {			/* User	macro input */
	    GetMacLine (dummy);
	    eofflag = FALSE;
	} else {				/* Normal file input */
	    eofflag = GetLine (dummy);
	}
	if ((Line[0] !=	'\0') && (Line[0] != '*') && (Line[0] != ';')) {
	    SubArgs (dummy);	/* Substitute macro arguments */
	    GetParts (dummy);	/* Break Line into its component parts */
	}

	/* ------ If we	have reached the end of	a macro	or ------ */
	/* ------ include file,	return to the calling file ------ */

	i = eofflag;				/* End of file */

	if (i) {
	    if (SkipNest != 0) {
		Error (OpLoc, NoENDC);	/* ENDC	is missing */
		WriteListLine (&List);	/* It's not normally listed */
		SkipNest = 0;
	    }
	} else if ((InF->NArg != -1)&&(Dir != Macro)) {	/* Macro exits */
	    if (strcmp (OpCode,	"ENDM") == 0) {
		i = TRUE;
		(InF->Line)++;		/* Count ENDM directive	*/
		if (SkipNest !=	0) {
		    Error (OpLoc, NoENDC);  /* ENDC is missing */
		    WriteListLine (&List);  /* It's not normally listed */
		    SkipNest = 0;
		}
	    } else if (SkipNest	== 0) {
		if (strcmp (OpCode, "MEXIT") == 0) {
		    i =	TRUE;
		    (InF->Line)++;	/* Count MEXIT directive */
		}
	    }
	}
	if (!i)	{			/* Not end of file or macro */
	    if (PrevDir	== MacCall) {
		if (strcmp (OpCode, "MACRO") == 0) {
		    (InF->Line)++;	/* Count macro header */
		    continue;		/*  and	ignore it.    */
		}
	    }
	    if (SkipNest == 0) {	/* If we're not skipping, */
		break;			/*  we got something.	  */
	    } else {
		(InF->Line)++;		/* Count skipped lines */
		SkipNest += CountNest (OpCode);	/* Adjust SkipNest */
		continue;
	    }
	}
	if (!Pass2 && (IncStart	!= 0) && (IncPtr == InF)) {
	    SkipLim->Start = IncStart;	/* End of skippable INCLUDE */
	    SkipLim->Finish=LineCount;	/* Save	line numbers for pass 2	*/
	    SkipLim->MCount = MacCount;	/* Save	macro counter too */
	    if (SkipLim->Set1 != NULL) {
		SetFixLim--;
		x = (char *) SkipLim + sizeof (struct SkipEnt);
		if (x >	(char *) SetFixLim) {
		    SetFixLim++;	/* No room for final entry */
		} else {
		    SetFixLim->Sym  = NULL;	/* Null	entry	     */
		    SetFixLim->Val  = 0;	/*  indicates end of */
		    SetFixLim->Hunk = 0;	/*  SET	symbol list. */
		}
	    }
	    SkipLim++;
	    IncStart = 0;
	}
	if (InFNum == 0)
	    break;			/* End of source file */
	if (i =	(InF->UPtr == 0)) {
	    if (Quiet <	0)
		fprintf	(stderr, "%d\n", InF->Line);
	    close (In.fd);		/* Close inner file */
	    In.fd = NULL;
	}
	NextFNS	= InF->NPtr;		/* Release space on name stack */
	InFNum--;			/* Return to outer file	*/
	InF++;
	if (InFNum < OuterMac)
	    OuterMac = 0;		/* End of outer	macro */
	if (InF->UPtr == 0) {
	    if (i)
		ShowFile (FALSE);	/* Inner file -> outer file */
	    else if (InnrFMac) {
		ShowFile (FALSE);	/* Inner user macro -> file */
		InnrFMac = FALSE;
	    }
	    if (In.fd == NULL) {
		In.fd =	open (InF->NPtr, 0);
		lseek (In.fd, InF->Pos,	0);
		In.Ptr = In.Lim	= In.Buf;
	    }
	} else if (i) {
	    InnrFMac = TRUE;	/* Inner file -> outer user macro */
	}
    }
    LineCount++;			/* Bump	line counter */
    (InF->Line)++;
    if ((Label[0] != '\0') && (Label[0] != '\\'))
	if ((Label[0] <	'0') || (Label[0] > '9'))
	    LabLine = LineCount;	/* Save	line number of label */
    if (Quiet != 0) {
	i = (Quiet < 0 ? InF->Line : LineCount);
	if ((i % Quiet)	== 0) {		/* Display progress */
	    ShowLine (i);
	}
    }
    ErrLim = AddrAdv = InstSize	= nO = nS = nD = nX = 0;
    PrntAddr = FALSE;

    if (LineCount == DebugStart)
	fprintf	(stderr, "%d\n", LineCount);
    if ((LineCount >= DebugStart) && (LineCount	<= DebugEnd))
	printf ("%9lx %5d %s\n", AddrCnt, LineCount, Line);

    return (eofflag);
}



GetMacLine (dummy) int dummy;
/* Gets	the next stored	user macro line. */
{
    register char *s, *t;
    register struct NameChunk *np;

    s =	InF->UPtr;
    if (*s == '\n') {           /* Continue in next chunk */
	np = NameStart;
	while ((s < (char *) np)
	|| (s >	((char *) np + CHUNKSIZE)))
	    np = np->Link;	/* Find	the chunk we're in */
	InF->UPtr = (char *) (np->Link)	+ sizeof (struct NameChunk *);
	s = InF->UPtr;
    }
    t =	Line;
    while (*t++	= *s++)	/* Copy	InF->UPtr to Line, then	bump InF->UPtr.	*/
	;		/*  (It's faster than doing a strcpy followed   */
    InF->UPtr =	s;	/*  by a strlen	to bump	the pointer.)		*/
}



int GetLine (dummy) int	dummy;
/* Gets	the next line from the current input file and leaves it	in Line.
    Returns TRUE if end	of file	has been reached, FALSE	otherwise.	*/
{
    register char *s;
    register int c;
    register char *t, *m, *l;

    s =	Line;
    t =	In.Ptr;				/* Use a register for speed */
    m =	Line + MAXLINE - 1;		/* Limit of "Line" */
    while (1) {				/* Get Line, expanding tabs */
	if (t >= In.Lim) {
	    t =	In.Buf;			/* Re-fill the buffer */
	    In.Lim = In.Buf + read (In.fd, In.Buf, BUFFSIZE);
	    if (In.Lim == In.Buf) {
		*s = '\0';              /* End of file */
		In.Ptr = t;
		return (s <= Line);	/* Last	line might have	no \n */
	    }
	}
	if ((c = *t++) == '\n') {
	    break;
	}
#ifdef MSDOS
	if (c == 26) {
	    *s = '\0';                  /* Catch MS-DOS EOF char. */
	    In.Ptr = t;
	    return (s <= Line);
	}
	if ((s < m) && (c != 13)) {	/* Ignore excess */
#else
	if (s <	m) {			/* Ignore excess */
#endif
	    if ((c == '\t') && !KeepTabs) {
		l = Line + (((s	- Line)	+ 8) & ~7);
		if (l >	m)
		    l =	m;		/* Tabbed off the end */
		while (s < l)
		    *s++ = ' ';         /* Expand tabs */
	    } else {
		*s++ = c;		/* Normal character */
	    }
	}
    }
    *s = '\0';                  /* Terminate the string in Line */
    In.Ptr = t;
    return (FALSE);
}



SubArgs	(dummy)	int dummy;
/* Macro argument substitution routine */
{
    int	j;
    register char *s, *t, *x;
    char subline[MAXLINE];

    if (InF->NArg == -1)
	return;			/* Not a macro - leave Line alone */

    s =	Line;
    t =	subline;
    while (*s) {
	if ((*t++ = *s++) != '\\') {
	    continue;
	}
	x = s--;
	t--;
	if (*x == '@') {        /* \@ - substitute macro number */
	    x =	t;
	    *t++ = '.';
	    j =	InF->MCnt % 1000;
	    *t++ = j / 100 + '0';
	    j =	j % 100;
	    *t++ = j / 10 + '0';
	    *t++ = j % 10 + '0';
	    strcpy (t, s+2);		/* Remainder of	Line */
	    strcpy (Line, subline);	/* Replace Line	*/
	    while (*t != '\\')          /* Check for more substitutions */
		if (*t)
		    t++;
		else
		    return;		/* All done */
	    s =	t - subline + Line;	/* Do the next substitution */
	    continue;
	}
	if ((*x	< '0') || (*x > '9')) {
	    s++;		/* False alarm - it's a  */
	    t++;		/*  named local	variable */
	    continue;
	}

	s++;
	*t = '\0';
	j = 0;			/* Get argument	index */
	while ((*s >= '0') && (*s <= '9')) {
	    j *= 10;
	    j += *s++ -	'0';    /* Current digit */
	}
	if (j == 0)
	    strcpy (t, MacSize);	/* Macro call size */
	else if	((j > 0) && (j <= InF->NArg)) {
	    x =	InF->NPtr;
	    while (j > 0) {		/* Find	argument */
		x += strlen (x)	+ 1;
		j--;
	    }
	    strcpy (t, x);		/* Insert it */
	}
	while (*t)
	    t++;			/* Skip	over replacement */
	strcpy (t, s);			/* Remainder of	Line */
	strcpy (Line, subline);		/* Replace Line	*/
	while (*t != '\\')              /* Check for more substitutions */
	    if (*t)
		t++;
	    else
		return;			/* All done */
	s = t -	subline	+ Line;		/* Do the next substitution */
    }
}



GetParts (dummy) int dummy;
/* Break up Line into its component parts. */
{
    register char *s, *x;

    Size = S0;
    s =	Line;
    if (!isspace (*s)) {
	x = Label;
	while (!isspace	(*s) &&	(*s != ';') && (*s != '\0'))
	    *x++ = *s++;		/* Get the label */
	*x-- = '\0';
	while (*x == ':') {
	    *x-- = '\0';                /* Strip trailing colon(s) */
	    if (x < Label)
		break;
	}
    }
    while (OpLoc == 0) {
	while (isspace (*s))
	    s++;			/* Skip	over to	opcode */
	if ((*s	== ';') || (*s == '\0'))
	    return;			/* End of statement image */
	OpLoc =	s - Line;
	x = OpCode;
	while (!isspace	(*s) &&	(*s != ';') && (*s != '\0'))
	    *x++ = *s++;		/* Get the opcode */
	*x-- = '\0';
	if (*x == ':') {                /* It's actually a label */
	    if (Label[0]) {
		Error (OpLoc, MultLab);	/* Multiple labels */
	    } else {
		while ((x >= OpCode) &&	(*x == ':'))
		    *x-- = '\0';
		strcpy (Label, OpCode);	/* Get the label */
	    }
	    OpLoc = 0;			/* Try again for opcode	*/
	    OpCode[0] =	'\0';
	}
    }
    for	(x = OpCode; *x; x++)		/* Convert OpCode */
	*x = toupper(*x);		/*  to upper case */
    x -= 2;
    if ((x < OpCode) ||	(*x != '.'))    /* If no explicit size is given */
	Size = Word;			/*  default to Word (16	bits).	*/
    else {
	*x++ = '\0';                    /* Chop off size extension */
	switch (*x) {
	case 'B':                       /* Byte */
	case 'S':                       /* Short Branch */
	    Size = Byte;
	    break;
	case 'L':                       /* Long */
	    Size = Long;
	    break;
	default:
	    Size = Word;		/* Default to Word */
	    break;
	}
    }
    while (isspace(*s))
	s++;				/* Skip	over to	operands */
    if ((*s == ';') || (*s == '\0'))
	return;				/* There are no	operands */
    SrcLoc = s - Line;
    s =	GetField (s, SrcOp);		/* Op1 (source)	*/
    if (*s == ',')
	s++;
    if (!isspace (*s) && (*s !=	'\0') && (*s != ';')) {
	DestLoc	= s - Line;
	s = GetField (s, DestOp);	/* Op2 (destination) */
    }
}



ShowFile (newline) int newline;
/* Shows the current file name if we're displaying all input modules.
    If "newline" is TRUE, go to a new line before displaying the name. */
{
    if ((Quiet < 0) && (InF->UPtr == 0))
	if (newline)
	    fprintf (stderr, "\n%s line ", InF->NPtr);
	else
	    fprintf (stderr, "%s line ", InF->NPtr);
}



ShowLine (i) register int i;
/* Shows the current line number and backs up over it. */
{
    if (i >= 10000)
	fprintf	(stderr, "%5d\b\b\b\b\b", i);
    else if (i >= 1000)
	fprintf	(stderr, "%4d\b\b\b\b", i);
    else if (i >= 100)
	fprintf	(stderr, "%3d\b\b\b", i);
    else if (i >= 10)
	fprintf	(stderr, "%2d\b\b", i);
    else
	fprintf	(stderr, "%1d\b", i);
    fflush (stderr);		/* Make	sure it	gets out */
}



char *GetField (s, d) register char *s,	*d;
/* Gets	a field	from "s", returns result in "d".
    Stops on the first comma, semicolon, or white space	not
	enclosed within	apostrophes or parentheses.
    Returns stopping location.
    If already at end of "s", "d" is set to null string. */
{
    register char c;
    register int parncnt, instring;

    instring = FALSE;
    parncnt = 0;

    while (c = *s) {
	if (instring) {
	    *d++ = c;
	} else {
	    if (isspace(c) || (c == ';'))
		break;
	    else if ((c	== ',') && (parncnt == 0))
		break;
	    else {
		*d++ = c;
		if (c == '(')
		    parncnt++;
		else if	(c == ')')
		    parncnt--;
	    }
	}
	if (c == '\'')
	    instring = !instring;
	s++;
    }
    *d = '\0';
    return (s);
}



long GetValue (operand,	loc) char *operand; int	loc;
/* Determines value of expression */
/* Hunk2 is set	to hunk	number of result (ABSHUNK if absolute).
   If the expression consists solely of	self-defining terms,
	DefLine2 is set	to zero.  Otherwise, DefLine2 is set
	to the highest statement number	in which any symbol in
	the expression was defined.  If	the expression contains
	any undefined symbols, DefLine2	is set to NODEF.
    The	following code is based	on a regular-to-Polish expression
	converter described in "A Guide to FORTRAN IV Programming"
	by Daniel D. McCracken (John Wiley & Sons, Inc.	1965,
	3rd printing August 1968).  However, rather than generating
	the entire Polish expression, this routine will	evaluate
	and combine two	terms as soon as an operator of	lower
	precedence is encountered.				*/
{
    register char *o, *s;
    char tempop[MAXLINE];
    int	 oloc, parncnt,	nextprec, instring;
    long templong;
    struct TermStack *origterm;

    instring = (unsigned int) '~';
    OpPrec[instring] = 9;	/* Fudge IsOperator for	speed */
    nextprec = TRUE;		/* Assume there's only a single term */
    for	(o = operand; *o; o++) {
	if (IsOperator (o)) {
	    nextprec = FALSE;	/* It's not a single term */
	    break;
	}
    }
    instring = (unsigned int) '~';
    OpPrec[instring] = '\0';    /* Restore IsOperator */
    if (nextprec)
	return(CalcValue(operand,loc));	/* Short cut for single	term */

    Hunk2 = ABSHUNK;
    parncnt = DefLine2 = 0;
    o =	(char *) (((long) NextFNS + 3L)	& ~3L);
    origterm = Term = (struct TermStack	*) o;	/* Term	stack */
    Ops	= (struct OpStack *) InF;		/* Operator stack */
    Ops--;
    ParseSpace (0);
    Ops->chr = ' ';     /* Prime the operator stack */
    Ops->prec =	-1;
    if ((char *) Ops < Low2)
	Low2 = (char *)	Ops;

    /* Get all tokens.
	Terms are evaluated, and operator precedence is	determined.
	Left and right parentheses are given a precedence of
	    1 and 2 respectively.
	Binary operators are given precedence values starting at 3.
	Unary plus is ignored.
	Unary minus is converted to zero minus the remainder of
	    of the expression -	its precedence is set to 9 to
	    ensure that	the simulated unary operator is	evaluated
	    before the remainder of the	expression.
	Logical	not (~), being another unary operator, is converted
	    to -1 exclusive-ORed with the remainder of the expression.
	    Its	precedence is also set to 9.				*/

    o =	operand;			/* Current position in operand */

    while (1) {
	while (*o == '(') {             /* Left parenthesis */
	    Ops--;
	    ParseSpace (0);
	    Ops->chr  =	'(';
	    Ops->prec =	1;
	    if ((char *) Ops < Low2)
		Low2 = (char *)	Ops;
	    parncnt++;
	    o++;
	}
	if ((*o	== '+') || (*o == '-') || (*o == '~')) {    /* Unary op */
	    if (*o != '+') {    /* Ignore unary plus */
		Ops--;
		ParseSpace (sizeof (struct TermStack));
		Term->value   =	(*o == '-') ? 0 : -1;   /* Dummy value */
		Term->hunk    =	ABSHUNK;
		Term->oploc   =	loc + (o - operand);
		Term->defline =	0;
		Term++;
		if ((char *) Term > High2)
		    High2 = (char *) Term;
		Ops->chr  = *o;		/* Now get the operator	itself */
		Ops->prec = 9;		/* Do it ASAP */
		if ((char *) Ops < Low2)
		    Low2 = (char *) Ops;
	    }
	    o++;
	    if (*o == '(')
		continue;	/* Inner parenthesized expression */
	}
	oloc = loc + (o	- operand);

	s = tempop;				/* Get a term */
	if (*o == '*') {        /* It's a location counter reference, */
	    *s++ = *o++;	/*   not a multiplication operator!   */
	} else {
	    if (IsOperator (o) || (*o == '\0')) {
		Error (oloc, OperErr);	/* Unexpected operator or no terms */
		return (0L);
	    }
	    instring = (unsigned int) '~';
	    OpPrec[instring] = 9;	/* Fudge IsOperator for	speed */
	    instring = FALSE;
	    while (*o) {
		if (*o == '\'')
		    instring=!instring;	/* String delimiter */
		if (!instring && IsOperator (o))
		    break;		/* Found an operator - stop */
		*s++ = *o++;		/* Get a character */
	    }
	    instring = (unsigned int) '~';
	    OpPrec[instring] = '\0';    /* Restore IsOperator */
	}
	*s = '\0';
	ParseSpace (sizeof (struct TermStack));
	Term->value   =	CalcValue (tempop, oloc);
	Term->hunk    =	Hunk2;
	Term->oploc   =	oloc;
	Term->defline =	DefLine2;
	Term++;
	if ((char *) Term > High2)
	    High2 = (char *) Term;
	Hunk2 =	DefLine2 = 0;

	while (*o == ')') {                     /* Right parenthesis */
	    if (parncnt	== 0) {
		Error ((int) (loc + (o - operand)), OperErr);
		return (0L);
	    }
	    CondCalc (2);		/* Unstack what	we can */
	    if (Ops->chr == '(')
		Ops++;			/* Drop	paired parentheses */
	    else {
		Ops--;
		ParseSpace (0);
		Ops->chr  = ')';        /* Stack parenthesis for now */
		Ops->prec = 2;
		if ((char *) Ops < Low2)
		    Low2 = (char *) Ops;
	    }
	    parncnt--;
	    o++;
	}
	if (*o)	{
	    nextprec = IsOperator (o);
	    if ((nextprec == 0)	|| (*o == '(')) {
		Error ((int) (loc + (o - operand)), OperErr);
		return (0L);		/* Expected an operator	*/
	    }
	    CondCalc (nextprec);	/* Unstack what	we can */
	    Ops--;
	    ParseSpace (0);
	    Ops->chr  =	*o;		/* Stack the next operator */
	    Ops->prec =	nextprec;
	    if ((char *) Ops < Low2)
		Low2 = (char *)	Ops;
	    if ((*o == '<') || (*o == '>'))
		o++;	/* Skip	over two-character operator */
	    o++;
	} else {
	    if (parncnt) {
		Error ((int) (loc + (o - operand)), OperErr);
		return (0L);	/* Too many left parentheses */
	    }
	    CondCalc (0);		/* Unstack what's left */
	    if (--Term != origterm)	/* Should be only one term left	*/
		Error (Term->oploc, OperErr);		/* Parser bug? */
	    Hunk2    = Term->hunk;
	    DefLine2 = Term->defline;
	    return (Term->value);	/* Final value */
	}
    }
}



CondCalc (newprec) int newprec;
/* As long as the top operator on the operator stack has a precedence
    greater than or equal to the contents of "newprec", this routine
    will pop the two top terms from the	term stack, combine them
    according to the operator on the top of the	operator stack (which
    is also popped), and push the result back onto the term stack. */
{
    while (Ops->prec >=	newprec) {	/* Unstack an operator */
	Term -=	2;
	if (Ops->chr ==	'+') {          /* Relocatable addition */
	    if (Term->hunk == ABSHUNK)
		Term->hunk = (Term+1)->hunk;	/* A+R */
	    else if ((Term+1)->hunk != ABSHUNK)	{
		Error ((Term+1)->oploc,	RelErr);    /* R+R - error */
		Term->hunk = ABSHUNK;		/* Make	it absolute */
	    }
	} else if (Ops->chr == '-') {           /* Subtraction */
	    if (Term->hunk == (Term+1)->hunk)
		Term->hunk = ABSHUNK;		/* R-R - absolute */
	    else if ((Term+1)->hunk != ABSHUNK)	{   /* R-R across hunks	*/
		Error ((Term+1)->oploc,	RelErr);    /*	is an error -	*/
		Term->hunk = ABSHUNK;		    /* make it absolute	*/
	    }
	} else if ((Term->hunk != ABSHUNK)
	|| ((Term+1)->hunk != ABSHUNK))	{
	    Error (Term->oploc,RelErr);		/* All other operations	*/
	    Term->hunk = ABSHUNK;		/*   must be absolute	*/
	}
	if ((Term+1)->defline >	Term->defline)	/* Definition */
	    Term->defline = (Term+1)->defline;	/*  line nos. */

	switch (Ops->chr) {		/* Perform the operation */
	case '+':
	    Term->value	+= (Term+1)->value;
	    break;
	case '-':
	    Term->value	-= (Term+1)->value;
	    break;
	case '*':
	    Term->value	*= (Term+1)->value;
	    break;
	case '/':
	    if ((Term+1)->value)
		Term->value /= (Term+1)->value;
	    else
		Term->value = 0;     /*	Don't divide by zero */
	    break;
	case '&':
	    Term->value	&= (Term+1)->value;
	    break;
	case '!':
	case '|':
	    Term->value	|= (Term+1)->value;
	    break;
	case '<':
	    Term->value	<<= (Term+1)->value;
	    break;
	case '>':
	    Term->value	>>= (Term+1)->value;
	    break;
	case '~':
	    Term->value	^= (Term+1)->value;
	    break;
	default:
	    Error (Term->oploc,	OperErr);	/* Parser bug? */
	    break;
	}
	Term++;
	Ops++;
    }
}



int IsOperator (o) register char *o;
/* Tests whether "o" points to a valid operator or parenthesis.
    Returns the	precedence of the operator, or 0 if it isn't one. */
{
    register unsigned int i;

    i =	(unsigned int) *o;
    i =	(unsigned int) OpPrec[i];
    if (i != 6)
	return ((int) i);
    if (*(o+1) == *o)
	return ((int) i);	/* << or >> */
    else
	return (0);		/* False alarm */
}



long CalcValue (operand, loc) char *operand; int loc;
/* Evaluates a single term (called by GetValue).
    Hunk2 receives relative hunk number	(ABSHUNK if absolute).
    If the value is a symbol, DefLine2 is set to the line number
	where it was defined, or NODEF if it is	undefined.
	For self-defining terms, DefLine2 is set to zero.	*/
{
    register long result;	/* Result is calculated	here */
    register char *s, *numstart;
    register int  radix;
    int	 neg, overflow;
    char maxdig;	/* Highest valid digit in current radix	*/
    char delim;		/* String delimiter (' or ") */

    Hunk2 = ABSHUNK;			/* Assume value	is absolute */
    DefLine2 = 0;			/* and self-defining */
    result = 0;
    overflow = FALSE;
    if (neg = (*operand	== '-'))
	numstart = operand + 1;		/* Negative value */
    else
	numstart = operand;		/* Positive value */

    if ((*numstart >= '0') && (*numstart <= '9')) {
	radix =	10;		/* Decimal number */
	maxdig = '9';
    } else if (*numstart == '$') {
	radix =	16;		/* Hexadecimal number */
	maxdig = '9';
    } else if (*numstart == '@') {
	radix =	8;		/* Octal number	*/
	maxdig = '7';
    } else if (*numstart == '%') {
	radix =	2;		/* Binary number */
	maxdig = '1';
    } else
	radix =	0;		/* Not a number	*/

    if (radix != 0) {			/* Some	sort of	number */
	result = 0;
	if (radix != 10)
	    numstart++;			/* Allow for type character */
	for (s = numstart; *s; s++) {
	    result *= radix;
	    if ((*s >= '0') && (*s <= maxdig)) {
		result += (*s -	'0');
	    } else if (radix ==	16) {
		if ((*s	>= 'A') && (*s <= 'F'))
		    result += (*s - 'A' + 10);
		else if	((*s >=	'a') && (*s <= 'f'))
		    result += (*s - 'a' + 10);
		else
		    Error (loc + s - operand, OperErr);
	    } else if (!neg && (radix==10) && (*s=='$') && (*(s+1)=='\0')) {
		if (ReadSymTab (operand)) {	/* Look	up local label */
		    result = Value;		/* Get its value */
		    AddRef (LineCount);		/* Add reference */
		    if (Sym->Flags & 0x60)
			Error (loc, AddrErr);	/* Can't use a register equate */
		} else {
		    Error (loc,	Undef);		/* Undefined */
		}
		break;
	    } else {
		Error (loc + s - operand, OperErr);
	    }
	}
    } else if ((*operand == '\'') || (*operand == '"')) {
	delim =	*operand;		/* Character value delimiter */
	result = 0;
	s = operand + 1;
	while (1) {
	    if (*s == '\0') {
		Error (loc+s-operand,NoStrEnd);	/* End is missing */
		result = 0;
		break;
	    }
	    if (*s == delim) {		/* End of string? */
		if (*(++s) != delim)	/* Check next character	*/
		    break;		/* End of string */
	    }		/* Otherwise it's an apostrophe in the string */
	    if ((result	& 0xFF000000L) && !overflow) {
		Error (loc+s-operand, SizeErr);	/* Result overflowed */
		overflow = TRUE;
		result = 0;
	    }
	    if (!overflow)
		result = (result << 8) + *s;
	    s++;
	}
    } else if ((*operand == '*') && (*(operand+1) == '\0')) {
	result = AddrCnt;	/* Value of location counter */
	Hunk2 =	CurrHunk;	/* Use current section's hunk number */
    } else {
	if (ReadSymTab (operand)) {	/* Look	up symbol */
	    result = Value;		/* Get its value */
	    AddRef (LineCount);		/* Add reference */
	    if (Sym->Flags & 0x60)
		Error (loc, AddrErr);	/* Can't use a register equate */
	} else if (strcmp (operand, "NARG") == 0) {
	    result = InF->NArg;		/* Number of arguments */
	    if (result == -1)
		result = 0;		/* No arguments	outside	macros */
	} else
	    Error (loc,	Undef);		/* Undefined */
    }
    if (neg) {
	result = -result;		/* Negative value */
	if (Hunk2 != ABSHUNK)
	    Error (loc,	RelErr);	/* Must	be absolute */
    }
    return (result);
}



AddSymTab (label, value, hunk, line, flags)
char label[];
long value, hunk;
int line, flags;
/* Inserts a new entry to the symbol table and increments NumSyms.
    "Sym" will be set to point to the new entry.
    If the label is a local label (i.e.	the first character is
    a numeric digit or a backslash), the current contents of LabLine
    will be converted to characters and	appended to the	label before
    it is added.  If the first character of the	label is a backslash
    (i.e. a named local	variable) a dollar sign	will be	appended
    to the label ahead of the value of LabLine.			*/
{
    char wlab[MAXLINE],	wnum[6];
    register struct SymTab *chainsym, **hashindex;

    strcpy (wlab, label);
    if (((label[0] >= '0') && (label[0] <= '9')) || (label[0] == '\\')) {
	if (label[0] ==	'\\')
	    strcat (wlab, "$");
	sprintf	(wnum, "%d", LabLine);  /* If it's a local label, */
	strcat (wlab, wnum);		/*    append LabLine	  */
    }

    Sym	= SymLim;			/* Pointer to new entry	*/
    SymLim++;				/* Bump	limit pointer */
    if (((char *) SymLim - (char *) SymCurr) > CHUNKSIZE) {
	Sym = (struct SymTab *)	malloc ((unsigned) CHUNKSIZE);
	if (Sym	== NULL)
	    quit_cleanup ("Out of memory!\n");
	SymCurr->Link =	Sym;		/* Link	from previous chunk */
	SymCurr	= Sym;			/* Make	the new	chunk current */
	SymCurr->Link =	NULL;		/* Clear forward pointer */
	Sym++;				/* Skip	over pointer entry */
	SymLim = Sym;			/* New table limit */
	SymLim++;			/* Bump	it */
    }
    Sym->Link =	NULL;		/* Clear hash chain link */
    Sym->Nam = AddName(wlab,0);	/* Pointer to symbol */
    Sym->Val   = value;		/* Value */
    Sym->Hunk  = hunk;		/* Hunk	number */
    Sym->Defn  = line;		/* Statement number */
    Sym->Flags = flags;		/* Flags */
    Sym->Ref1  = NULL;		/* Reference pointer */
    NumSyms++;			/* Count symbols */

    hashindex =	HashIt (wlab);	/* Get hash index */
    if (*hashindex == NULL) {
	*hashindex = Sym;	/* First entry in this hash chain */
	return;
    }
    chainsym = *hashindex;
    while (chainsym->Link != NULL)
	chainsym = chainsym->Link;	/* Scan	for end	of hash	chain */
    chainsym->Link = Sym;		/* Insert new entry at the end */
}



char *AddName (name, macflag) char *name; int macflag;
/* Adds	the name in "name" to the name heap.
    "macflag" can take any of the following values:
	0 - normal name
	1 - first line of macro	text - there must be room on the
		name heap for at least one character following "name".
	2 - additional lines of	macro text - make sure there's room
		for an addition	character (as in 1 above).  Also,
		if it is necessary to allocate a new chunk of memory,
		first place a newline character	after the last entry
		in the old chunk.  This	acts as	a flag when retrieving
		lines of macro text during an expansion.
    This function returns a pointer to "name" on the name heap. */
{
    register char *s, *t;
    struct NameChunk *n;

    s =	NameLim	+ strlen(name) + 1;	/* The new entry ends here */
    if (macflag)			/* If this is a	macro, */
	s++;				/*  allow for continuation flag. */
    if ((s - (char *) NameCurr)	> CHUNKSIZE) {	/* If this chunk is full */
	if (macflag == 2)		/* If this is more macro text */
	    *NameLim = '\n';            /*  insert continuation flag. */
	n = (struct NameChunk *) malloc	((unsigned) CHUNKSIZE);
	if (n == NULL)
	    quit_cleanup ("Out of memory!\n");
	NameCurr->Link = n;		/* Link	from previous chunk */
	NameCurr = n;			/* Make	the new	chunk current */
	NameCurr->Link = NULL;		/* Clear forward pointer */
	s = (char *) NameCurr;
	NameLim	= s + sizeof (char *);	/* Skip	over pointer entry */
    }
    s =	NameLim;
    t =	name;
    while ((*s++ = *t++) != '\0')       /* Store name */
	;
    t =	NameLim;
    NameLim = s;			/* Update table	limit */
    return (t);
}



int ReadSymTab (label) char label[];
/* Searches the	symbol table for the given label.
   If not found, points	Sym to NULL and	returns	FALSE.
   If found, points Sym	to the proper table entry,
     and sets up the following fields:
	Value	 - value of symbol
	Hunk2	 - hunk	number in which	symbol resides
		   ABSHUNK if value is absolute
		   ones	complement of symbol table index if external
	DefLine2 - statement number in which symbol was	defined
			(NODEF if undefined )
    If the label is a local label (i.e.	the first character is
    numeric), the current contents of LabLine will be converted
    to characters and appended to the label before it is searched.
    (This matches the way AddSymTab added the label to the table.)
    If the first character of the label	is a backslash (i.e. a
    named local	variable) a dollar sign	will be	appended to the
    label ahead	of the value of	LabLine.			*/
{
    char wlab[MAXLINE],	wnum[6];
    register struct SymTab **hashindex;

    strcpy (wlab, label);
    if (((label[0] >= '0') && (label[0] <= '9')) || (label[0] == '\\')) {
	if (label[0] ==	'\\')
	    strcat (wlab, "$");
	sprintf	(wnum, "%d", LabLine);  /* If it's a local label, */
	strcat (wlab, wnum);		/*    append LabLine	  */
    }
    hashindex =	HashIt (wlab);	/* Get hash index */
    Sym	= *hashindex;
    while (Sym != NULL)	{
	if (strcmp (Sym->Nam, wlab) == 0) {
	    Value = Sym->Val;		/* Found it */
	    Hunk2 = Sym->Hunk;
	    if (!(Sym->Flags & 9))
		Hunk2 &= 0x0000FFFFL;	/* Isolate hunk	number */
	    DefLine2 = Sym->Defn;
	    return (TRUE);
	}
	Sym = Sym->Link;
    }
    Value = 0;			/* Didn't find it - */
    Hunk2 = ABSHUNK;		/* set value to	absolute zero */
    DefLine2 = NODEF;
    return (FALSE);
}



struct SymTab **HashIt (label) register	char *label;
/* Returns a pointer to	the hash table entry corresponding to "label" */
{
    register unsigned i;

    i =	0;
    while (*label) {
	i = ((i	<< 3) -	i + *label++) %	HashSize;
    }
    return (Hash + i);
}



struct SymTab *NextSym (sym) register struct SymTab *sym;
/* Returns a pointer to	the next symbol	table entry in memory,
    or NULL if there are no more symbol	table entries.
    SymChunk and SymChLim must be properly set up.	*/
{
    register struct SymTab *sp;

    if (sym == NULL)
	return (NULL);		/* We're nowhere - get out */
    sym++;
    sp = sym;
    sp++;
    if ((SymLim	>= SymChunk) &&	(SymLim	<= SymChLim))
	if (sym	>= SymLim)
	    return (NULL);	/* End of symbol table entries */
    if (sp > SymChLim) {
	if ((SymChunk =	SymChunk->Link)	== NULL)
	    return (NULL);	/* End of the last chunk */
	SymChLim = (struct SymTab *) ((char *) SymChunk	+ CHUNKSIZE);
	sym = SymChunk;
	sym++;			/* First entry in the new chunk	*/
    }
    return (sym);
}



AddRef (linenum) int linenum;
/* Adds	"linenum" to the list of references
    for	the symbol pointed to by Sym.		*/
{
    register int i;
    register struct Ref	*ref, *prevref;

    if (!Pass2)
	return;			/* Pass	2 only!	*/
    if (!XrefList)
	return;			/* No cross-reference */
    prevref = NULL;
    ref	= Sym->Ref1;
    while (ref)	{		/* Chase pointers */
	for (i = 0; i <	MAXREF;	i++) {	    /* Scan reference entry */
	    if (ref->RefNum[i] == 0) {	    /*	for an empty slot   */
		ref->RefNum[i] = linenum;   /* Insert new line number */
		return;
	    }
	}
	prevref	= ref;			/* Remember where we were */
	ref = ref->NextRef;		/* Link	to the next entry */
    }
    ref	= RefLim;			/* Pointer to new entry	*/
    RefLim++;				/* Bump	limit pointer */
    if (((char *) RefLim - (char *) SymCurr) > CHUNKSIZE) {
	ref = (struct Ref *) malloc ((unsigned)	CHUNKSIZE);
	if (ref	== NULL) {
	    fprintf (stderr, "     \nOut of memory");
	    fprintf (stderr, " - cross-reference disabled.\n");
	    XrefList = FALSE;
	    return;
	}
	SymCurr->Link =	(struct	SymTab *) ref;	/* Link	from prev. chunk */
	SymCurr	= (struct SymTab *)ref;	/* Make	the new	chunk current */
	SymCurr->Link =	NULL;		/* Clear forward pointer */
	ref++;				/* Skip	over pointer entry */
	RefLim = ref;			/* New table limit */
	RefLim++;			/* Bump	it */
    }
    ref->NextRef = NULL;		/* Pointer to next entry */
    ref->RefNum[0] = linenum;		/* First reference in new entry	*/
    for	(i = 1;	i < MAXREF; i++)
	ref->RefNum[i] = 0;		/* Clear remaining slots */
    if (prevref	== NULL)
	Sym->Ref1 = ref;		/* Link	to first entry */
    else
	prevref->NextRef = ref;		/* Link	to next	entry */
}



int CountNest (s) register char	*s;
/* Returns 1 if	"s" contains any IF statement (i.e. IFEQ, etc.).
   Returns -1 if "s" contains "ENDC" or "ENDIF".
   Returns 0 in	all other cases.		*/
{
   if (strcmp (s, "ENDC") == 0)
       return (-1);
   else	if (strcmp (s, "ENDIF") == 0)
       return (-1);
   else	if (*s++ != 'I')
	return (0);
   else	if (*s++ != 'F')
	return (0);
   else	if (strcmp (s, "EQ") == 0)
       return (1);
   else	if (strcmp (s, "NE") == 0)
       return (1);
   else	if (strcmp (s, "GT") == 0)
       return (1);
   else	if (strcmp (s, "GE") == 0)
       return (1);
   else	if (strcmp (s, "LT") == 0)
       return (1);
   else	if (strcmp (s, "LE") == 0)
       return (1);
   else	if (strcmp (s, "C" ) == 0)
       return (1);
   else	if (strcmp (s, "NC") == 0)
       return (1);
   else	if (strcmp (s, "D" ) == 0)
       return (1);
   else	if (strcmp (s, "ND") == 0)
       return (1);
   else
       return (0);
}



Heap2Space (n) int n;
/* Die if we can't find "n" bytes on the secondary heap. */
{
    if ((NextFNS + n) >	(char *) InF) {
	printf ("\n%5d   %s\n", LineCount, Line);
	quit_cleanup ("Secondary heap overflow - assembly terminated.\n");
    }
}



ParseSpace (n) int n;
/* Special version of Heap2Space for the expression parser */
{
    if (((char *) Term + n) > (char *) Ops) {
	printf ("\n%5d   %s\n", LineCount, Line);
	quit_cleanup ("Secondary heap overflow - assembly terminated.\n");
    }
}
SHAR_EOF
cat << \SHAR_EOF > Operands.c
/*------------------------------------------------------------------*/
/*								    */
/*		      MC68000 Cross Assembler			    */
/*								    */
/*	      Copyright	(c) 1985 by Brian R. Anderson		    */
/*								    */
/*		Operand	processor - January 10,	1989		    */
/*								    */
/*   This program may be copied	for personal, non-commercial use    */
/*   only, provided that the above copyright notice is included	    */
/*   on	all copies of the source code.	Copying	for any	other use   */
/*   without the consent of the	author is prohibited.		    */
/*								    */
/*------------------------------------------------------------------*/
/*								    */
/*		Originally published (in Modula-2) in		    */
/*	    Dr.	Dobb's Journal, April, May, and June 1986.          */
/*								    */
/*	 AmigaDOS conversion copyright 1989 by Charlie Gibbs.	    */
/*								    */
/*------------------------------------------------------------------*/

#include <stdio.h>
#include "a68kdef.h"
#include "a68kglb.h"

/* Functions */
extern int  LineParts(), Instructions(), ObjDir();
extern int  ReadSymTab(), OpenIncl(), CountNest();
extern long AddrBndW(),	AddrBndL(), GetValue(),	CalcValue();
extern char *AddName(),	*GetField();
extern struct SymTab *NextSym();
extern struct SymTab **HashIt();

int GetArgs(), GetAReg(), GetInstModeSize(), GetMultReg();



int GetArgs (name) char	*name;
/* Gets	macro arguments	and adds them to FNStack after adding "name".
    Returns the	number of arguments added to the stack.
    Note that this might not be	the full number	of arguments
    provided if	the stack overflowed.				*/
{
    register char *s, *t;
    int	narg, instring;
    char currarg[MAXLINE];		/* Current argument */

    narg = strlen (name) + 1;
    Heap2Space (narg);			/* Find	space for name */
    strcpy (NextFNS, name);		/* Add name to stack */
    NextFNS += narg;			/* Bump	pointer	*/
    if (NextFNS	> High2)
	High2 =	NextFNS;		/* Update high-water mark */

    narg = 0;				/* Argument counter */

    s =	Line + SrcLoc;			/* Now scan Line */
    while (!isspace(*s)	&& (*s != ';') && (*s != '\0')) {
	t = currarg;
	if (instring = (*s == '<'))     /* String delimiter */
	    s++;
	while (1) {
	    if (*s == '\0')
		break;			/* End of line */
	    if (instring) {
		if (*s == '>') {
		    s++;
		    break;		/* End of string */
		}
	    } else {
		if ((*s	== ',')         /* End of operand */
		|| isspace(*s)		/* End of all operands */
		|| (*s == ';'))         /* Start of comments */
		    break;
	    }
	    *t++ = *s++;		/* Get a character */
	}
	*t++ = '\0';
	Heap2Space (t -	currarg);	/* Check for space */
	strcpy (NextFNS, currarg);	/* Store argument */
	NextFNS	+= t - currarg;		/* Next	available space	*/
	if (NextFNS > High2)
	    High2 = NextFNS;		/* High-water mark */
	narg++;				/* Count arguments */
	if (*s == ',')
	    s++;			/* Skip	over separator */
    }
    return (narg);			/* Successful completion */
}



EffAdr (EA, Bad) register struct OpConfig *EA; int Bad;
/* Adds	effective address field	to Op (BITSET representing opcode) */
{
    if ((1 << (EA->Mode	- 1)) IN Bad) {
	Error (EA->Loc,	ModeErr);	/* Invalid mode	*/
	return;
    } else if (EA->Mode	> 12)		/* Special modes */
	return;
    else if (EA->Mode <	8)		/* Register direct or indirect */
	Op |= ((EA->Mode - 1) << 3) | EA->Rn;
    else
	Op |= 0x0038 | (EA->Mode - 8);	/* Absolute modes */
    OperExt (EA);
}



OperExt	(EA) register struct OpConfig *EA;
/* Calculate operand Extension word, and check range of	operands */
{
    switch (EA->Mode) {
	case AbsL:
	    break;   /*	No range checking needed */
	case AbsW:
	case ARDisp:
	case PCDisp:
	    if ((EA->Value < -32768) ||	(EA->Value > 32767))
		Error (EA->Loc,	SizeErr);
	    break;
	case ARDisX:
	case PCDisX:
	    if ((EA->Value < -128) || (EA->Value > 127))
		Error (EA->Loc,	SizeErr);
	    EA->Value &= 0x00FF;		      /* Displacement */
	    EA->Value |= EA->Xn	<< 12;			/* Index reg. */
	    if (EA->X == Areg)	   EA->Value |=	0x8000;	/* Addr. Reg. */
	    if (EA->Xsize == Long) EA->Value |=	0x0800;	/* Long	reg.  */
	    break;
	case Imm:
	    if (Size ==	Word) {
		if ((EA->Value < -32768) || (EA->Value > 65535L))
		    Error (EA->Loc, SizeErr);
	    } else if (Size == Byte)
		if ((EA->Value < -128) || (EA->Value > 255))
		    Error (EA->Loc, SizeErr);
	    break;
    }
}



GetOperand (oper, op, pcconv)
char *oper; register struct OpConfig *op; int pcconv;
/* Finds mode and value	for source or destination operand.
    If PC-relative addressing is permitted, "pcconv" gives the
    offset to the displacement word; otherwise "pcconv" is zero. */
{
    register char *s, *t;
    register int  i;
    char *opend;
    char UCoper[MAXLINE], tempop[MAXLINE];
    int	 rloc;
    long templong;

    op->Value =	op->Defn = 0;
    op->Mode = Null;
    op->X    = X0;
    op->Hunk = ABSHUNK;

    if (*oper == '\0')
	return;				/* Nothing to process */

    s =	oper;
    t =	UCoper;
    while (*t++	= toupper (*s++))	/* Upper-case version */
	;
    opend = s -	2;			/* Last	character of operand */

    if (*oper == '#') {                 /* Immediate */
	op->Value = GetValue (oper+1, (op->Loc)+1);
	op->Mode  = Imm;
	op->Hunk  = Hunk2;
	op->Defn  = DefLine2;
	return;
    }

    i =	IsRegister (oper, opend-oper+1);
    if (i >= 0)	{
	op->Mode = (i &	8) ? ARDir : DReg;	/* Register type */
	op->Rn = i & 7;				/* Register number */
	return;
    } else if (i == -2)	{
	op->Mode = MultiM;			/* Equated register list */
	op->Value = Sym->Val;
	return;
    } else if ((*oper == '(') && (*opend == ')')) {
	i = IsRegister (oper+1,	opend-oper-1);
	if (i >= 8 && i	<= 15) {
	    op->Mode = ARInd;		/* Address Register indirect */
	    op->Rn = i - 8;
	    return;
	} else if (i !=	-1) {
	    Error (op->Loc, AddrErr);	/* Data	register is invalid */
	    return;
	}	/* else	may be parenthesized expression	*/
    } else if ((*oper == '(')           /* Post-increment */
    && (*opend == '+')
    && (*(opend-1) == ')')) {
	op->Mode = ARPost;
	op->Rn = GetAReg (oper+1, opend-oper-2,	op->Loc	+ 1);
	return;
    } else if ((*oper == '-')           /* Pre-decrement */
    && (*opend == ')')
    && (*(oper+1) == '(')) {
	i = IsRegister (oper+2,	opend-oper-2);
	if (i >= 8 && i	<= 15) {
	    op->Mode = ARPre;
	    op->Rn = i - 8;
	    return;
	} else if (i > 0) {
	    Error (op->Loc, AddrErr);	/* Data	register is invalid */
	    return;
	}	/* else	parenthesized expression with leading minus? */
    } else if (strcmp (UCoper, "SR") == 0) {
	op->Mode = SR;				/* Status Register */
	return;
    } else if (strcmp (UCoper, "CCR") == 0) {
	op->Mode = CCR;			/* Condition Code Register */
	return;
    } else if (strcmp (UCoper, "USP") == 0) {
	op->Mode = USP;			/* User	Stack Pointer */
	return;
    }

    /* Try to split off	displacement (if present).
	We'll assume we have a register expression if the operand
	ends with a parenthesized expression not preceded by an
	operator.  I know this code is a real kludge, but that's
	the result of the bloody syntax.  Thanks, Motorola.	*/

    s =	opend;				/* Last	character */
    if (i = (*s	== ')'))                /* Trailing parenthesis? */
	while (*(--s) != '(')           /* Find left parenthesis */
	    if (s <= oper)
		break;
    if (s <= oper)			/* Must	not be at beginning */
	i = FALSE;
    if (i) {
	if (s == (oper+1)) {
	    if (*oper == '-')
		i = FALSE;		/* Leading minus sign */
	} else {
	    t =	s - 1;
	    if (*t == '*') {            /* Location counter? */
		t--;
		if (!IsOperator	(t) || (*t == ')'))
		    i =	FALSE;		/* No, it's multiplication */
	    } else if (IsOperator (t) && (*t !=	')')) {
		i = FALSE;		/* Preceded by an operator */
	    }
	}
    }

    if (i) {		/* Looks like a	displacement mode */
	*s = '\0';
	op->Value = GetValue (oper, op->Loc);	/* Displacement	*/
	op->Hunk  = Hunk2;			/* Hunk	number */
	op->Defn  = DefLine2;			/* Line	where defined */
	*s++ = '(';                             /* Restore parenthesis */

	rloc = op->Loc + s - oper;	/* The register	starts here */
	s = GetField (s, tempop);	/* Get address register	*/
	if (*s == '\0')                 /* If there's no index register */
	    tempop[strlen(tempop)-1] = '\0';    /* chop parenthesis */

	if ((tempop[2] == '\0')
	&& (toupper (tempop[0])	== 'P')
	&& (toupper (tempop[1])	== 'C')) {
	    op->Mode = PCDisp;			/* Program Counter */
	    if (op->Hunk == CurrHunk) {
		op->Value -= (AddrCnt+pcconv);	/* Adjust displacement */
		op->Hunk = ABSHUNK;
	    }
	} else {
	    if ((op->Value == 0)	/* If displacement is zero   */
	    && (op->Hunk == ABSHUNK)	/*  and	is absolute	     */
	    && (op->Defn < LineCount)	/*  and	is already defined   */
	    && !(OpM68R	IN AdrModeA))	/*  and	isn't for a MOVEP    */
		op->Mode = ARInd;	/*  forget the displacement. */
	    else
		op->Mode = ARDisp;	/* Address reg.	w/displacement */
	    op->Rn = GetAReg (tempop, strlen (tempop), rloc);
	}
	if (*s != '\0') {               /* Index register is present */
	    if (op->Mode == PCDisp)
		op->Mode = PCDisX;	/* Program Counter indexed */
	    else
		op->Mode = ARDisX;	/* Address Register indexed */
	    if (*s != ',')
		Error (op->Loc,	AddrErr);	/* Bad separator */
	    s++;				/* Skip	separator */
	    rloc = op->Loc + s - oper;		/* Start of index */
	    s =	GetField (s, tempop);		/* Get index register */
	    t =	tempop + strlen(tempop);
	    if (*s == '\0')
		*(--t) = '\0';                  /* Chop parenthesis */
	    else
		Error (rloc, AddrErr);		/* It better be	there */

	    t -= 2;
	    if ((t < tempop) ||	(*t != '.')) {
		op->Xsize = Word;	/* Size	defaults to 16 bits */
		t += 3;
	    } else {
		*t++ = '\0';                    /* Chop off size code */
		switch (toupper	(*t)) {
		case 'W':                       /* Word */
		    op->Xsize =	Word;
		    break;
		case 'L':                       /* Long */
		    op->Xsize =	Long;
		    break;
		default:
		    Error (op->Loc+s-1-oper, SizeErr);	/* Invalid size	*/
		    op->Xsize =	Word;		/* Make	it word	for now	*/
		}
	    }
	    i =	IsRegister (tempop,t-tempop-1);	/* Get register	*/
	    op->Xn = i & 7;			/* Index register number */
	    if ((i >= 0) && (i <= 7))
		op->X =	Dreg;			/* Data	Register */
	    else if ((i	>= 8) && (i <= 15))
		op->X =	Areg;			/* Address Register */
	    else
		Error (rloc, AddrErr);		/* Invalid register */
	}

	if ((op->Hunk >= 0) && (op->Hunk != ABSHUNK))
	    Error (op->Loc, RelErr);	/*  Relocatable	displacement */
	return;
    }

    if ((i = GetMultReg	(oper, op->Loc)) != 0) {
	op->Value = (long) i;
	op->Mode = MultiM;		/* Register list for MOVEM */
	return;
    }

    op->Value =	GetValue (oper,	op->Loc);	/* Get operand value */
    op->Hunk  =	Hunk2;
    op->Defn  =	DefLine2;
    op->Mode  =	AbsL;		/* Assume absolute long	addressing */

    if (DefLine2 < LineCount) {		/* Backward reference */

	if (Hunk2 < 0) {
	    return;		/* External - leave as absolute	long */

	} else if (Hunk2 == CurrHunk) {	/* Reference to	current	hunk */
	    if (pcconv)	{
		templong = op->Value-(AddrCnt+pcconv);	/* PC disp. */
		if ((templong >= -32768) && (templong <= 32767)) {
		    op->Mode = PCDisp;	/* Convert to PC relative mode */
		    op->Value=templong;	/* Adjust displacement */
		    op->Hunk = ABSHUNK;
		}
	    }

	} else if (Hunk2 == ABSHUNK) {	/* Absolute value */
	    if ((op->Value >= -32768) && (op->Value <= 32767))
		op->Mode = AbsW;	/* Absolute word */

	} else if (SmallData &&	(op->Value>=0) && (op->Value<=65535L)) {
	    op->Mode = ARDisp;		/* Make	it a data reference */
	    op->Rn = 4;			/*  through register A4	    */
	    op->Value -= 32768L;	/* Adjust displacement */
	    op->Hunk = ABSHUNK;
	}
	return;			/* Could default to absolute long */

    } else if (!SmallData) {	/* Fwd.	reference - if not small data */
	return;			/*  leave as absolute long addressing */

    } else if (!Pass2) {	/* Forward reference, pass 1 */
	op->Mode = ARDisp;	/* Assume displacement */
	op->Rn = 4;		/*  from register A4   */
	op->Hunk = ABSHUNK;
	return;

    } else {			/* On pass 2 we	know what it is	*/

	if (Hunk2 < 0) {
	    Error (op->Loc,FwdRef);	/* External - must be 32 bits */
	    op->Mode = AbsW;		/* Force absolute word anyway */

	} else if (Hunk2 == CurrHunk) {	/* It's in the current hunk */
	    op->Mode = PCDisp;		/* Convert to PC relative mode */
	    op->Value -= AddrCnt + pcconv;	/* Adjust displacement */
	    op->Hunk = ABSHUNK;
	    if (!pcconv	|| (op->Value <	-32768)	|| (op->Value >	32767))
		Error (op->Loc,FwdRef);	/* It doesn't fit! */

	} else if (Hunk2 == ABSHUNK) {	/* It's absolute */
	    op->Mode = AbsW;		/* It has to fit in a word */
	    if ((op->Value < -32768) ||	(op->Value > 32767))
		Error (op->Loc,FwdRef);	/* It doesn't fit! */

	} else {
	    op->Mode = ARDisp;		/* Assume data reference */
	    op->Rn = 4;			/*  through register A4	 */
	    op->Value -= 32768L;	/* Adjust displacement */
	    if ((op->Value < -32768) ||	(op->Value > 32767))
		Error (op->Loc,FwdRef);	/* It doesn't fit! */
	}
    }
}



int GetMultReg (oper, loc) char	*oper; int loc;
/* Builds a register mask for the MOVEM	instruction.
    Returns the	mask in	the low-order portion of its value if
    "oper" is a valid multiple-register list; otherwise returns 0. */
{
    register char *s, *t;
    register int  j;
    int	t1, t2;		/* Temporary variables for registers */
    int	range;		/* We're processing a range of registers */
    int	multext;	/* The result is built here */

    multext = 0;
    range = FALSE;
    s =	oper;
    if (IsOperator (s))
	return (0);			/* Starts with an operator! */

    while (1) {
	for (t = s; *t;	t++) {
	    if ((*t == '-') || (*t == '/')) {
		break;
	    }
	}
	if ((multext ==	0) && (*t == '\0'))
	    return (0);			/* Reject single term */
	if ((t2	= IsRegister (s, t-s)) < 0)
	    return (0);			/* Not a recognizable register */

	if (!range) {
	    multext |= (1 << t2);	/* Single register */
	    t1 = t2;		/* Save	number in case it's a range */
	} else {			/* Range of registers */
	    range = FALSE;
	    if (t1 > t2) {
		j = t1;			/* Swap	registers if backwards */
		t1 = t2;
		t2 = j;
	    }
	    for	(j = t1; j <= t2; j++)
		multext	|= (1 << j);	/* Mark	all registers in range */
	    if (*t == '-')
		return (0);		/* Invalid range */
	}
	if (*t == '\0')
	    break;			/* Normal end of operand */
	if (*t++ == '-')
	    range = TRUE;		/* Range indicator */
	if (*t == '\0')
	    return (0);			/* Premature end of operand */
	s = t;
    }
    return (multext);
}



int GetAReg (op, len, loc) char	*op; int len, loc;
/* Validate an address register	specification.
    Valid specifications are A0	through	A7 , SP, or an EQUR label.
    The	address	register number	will be	returned if it is valid.
    Otherwise, Error will be called, using "loc" for the error
    location (this is its only use), and zero (A0) will	be returned. */
{
    register int i;

    i =	IsRegister (op,	len);		/* Get register	number */
    if ((i >= 8) && (i <= 15))
	return (i - 8);			/* Valid address register */
    else {
	Error (loc, AddrErr);		/* Not an address register */
	return (0);			/* Set to A0 */
    }
}



int IsRegister (op, len) char *op; int len;
/* Check whether the current operand is	an address or data register.
    Valid specifications are D0	throuth	D7, A0 through A7, SP,
    or any symbol equated to a register	with the EQUR directive.
    Return values:
	0 through 7 - data registers 0 through 7 respectively
	8 through 15 - address registers 0 through 7 respectively
	-1 - not a recognizable	register
	-2 - Equated register list for MOVEM instruction (REG)	*/
{
    char tempop[MAXLINE];
    register char *s;
    register int  i;

    if (len == 2) {		/* Two-character specification */
	i = toupper (*op);
	s = op + 1;
	if ((i == 'S') && (toupper (*s) == 'P')) {
	    return (15);		/* Stack Pointer */
	} else if ((*s >= '0') && (*s <= '7')) {
	    if (i == 'A') {
		return (*s - '0' + 8);  /* Address Register */
	    } else if (i == 'D') {
		return (*s - '0');      /* Data Register */
	    }
	}
    }
    if (!GotEqur)			/* If we have no EQURs to check	*/
	return (-1);			/*  don't waste any time here.  */
    for	(i = 0,	s = op;	i < len; i++) {
	if (IsOperator (s))
	    return (-1);		/* It sure isn't a label */
	tempop[i] = *s++;
    }
    tempop[i] =	'\0';
    if (ReadSymTab (tempop)) {
	if (Sym->Flags & 0x60) {
	    AddRef (LineCount);		/* Found a register or list */
	    return ((Sym->Flags	& 0x20)	? (int)	Sym->Val : -2);
	}
    }
    return (-1);			/* Not a recognizable register */
}



int GetInstModeSize (Mode) register int	Mode;
/* Determines the size for the various instruction modes. */
{
    switch (Mode) {
	case ARDisp:
	case ARDisX:
	case PCDisp:
	case PCDisX:
	case AbsW:
	    return (2);
	case AbsL:
	    return (4);
	case MultiM:
	    return (0);		/* Accounted for by code generator */
	case Imm:
	    if (Size ==	Long)
		return (4);
	    else
		return (2);
	default:
	    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.