/*-----------------------------------------------------------------------75
** CCNA32.C for 32bit nasm and linkage with dynamic library for gnuLinux
**  Linking when an external C library is to be used to link externals:
**  ld --dynamic-linker /lib/ld-linux.so.2 -lc -o program program.o
** Vers: 0r1  By: s_dubrovich@yahoo.com
** ?(c): COPYLEFT - pls rename yours for branch traceability.
** Vers: v.0r4
** Tgts: gcc and gnuLinux
** Stat: works partially.
**
** 23-Jul-11 10:43:49 PM - initial.
** Sun 24 Jul 2011 05:24:23 PM CDT - replace inline with input_line.
** Tue 26 Jul 2011 05:51:08 PM CDT - begin types conversion for 32bits.
** Fri 29 Jul 2011 04:17:00 PM CDT - made [OFFSET] 4 bytes -> int.
** Sat 13 Aug 2011 04:02:40 PM CDT - v.0r2, wrk on Csp & INT_SZ
** Sun 14 Aug 2011 02:44:41 PM CDT - v.0r3, wrk on chg back to internal label prefix
**	this is so libc call names are not duplicated in the nasm src with extern fn's
** Wed 05 Oct 2011 05:06:11 PM CDT - v.0r4, chg'd sa_callstk()
** Mon 24 Oct 2011 08:28:18 AM CDT - added makefile used on Debian Linux..
*/

/***
# make file for ccna32.c

objects = ccna32.o

ccna32 : $(objects)
	gcc -std=c89 -fno-asm -ffreestanding -o ccna32 $(objects)
ccna32.o : ccna32.c
	gcc -c ccna32.c -o ccna32.o

clean:
	rm ccna32 $(objects)

# This is GNU makefile extension to notify that roughly means: 'clean' does
# not depend on any files in order to call it.
.PHONY: clean

# -eof-
***/

/* CCNA_0r1.C for pcdoslib & .exe => CCNA.EXE
** Vers: 0r1  By: s_dubrovich@yahoo.com
** ?(c): COPYLEFT - pls rename yours for branch traceability.
** 22-May-11 01:00:37 PM - v.0r1, chgd deblank to filter CR
** 23-May-11 09:27:40 PM - chg eof -> eof_flg, eol -> EOL
** 29-May-11 09:14:55 AM - modify doinclude to use fname_array.
** 30-May-11 09:27:43 AM - input -> fp_input, output -> fp_output
**  input2 -> fp_input2
** 19-Jun-11 07:51:10 AM - expanded 'Input filename' msg.
*/

/**----------------------------------------------------**/
/** File: CCN9_0r0.C                                   **/
/** Last: 19-Dec-10 09:14:35 AM                        **/
/** Prev: 19-Dec-10 09:14:35 AM                        **/
/** Base: 01-Apr-10 09:23:04 PM                        **/
/** Vers: 0r0 r8 07-Jul-2010                           **/
/** From: CCN8 v.2r8                                   **/
/**----------------------------------------------------**/

/* Note: gcc typesizes in bytes..
** char		1
** short int	2
** int		4
** ptr		4
** long		4
** double	8
*/

/******************************************************
*
*		small-c compiler
*
*		  by Ron Cain
*
******************************************************/

#define BANNER  "* * *  Small-C  V1.1  * * *"

#define VERSION "Based on Version N: July 17, 1980"

#define AUTHOR "       By Ron Cain"

/*	Define system dependent parameters	*/
/** #define CR 13 ** for pcDos text NL, see deblank **/

/*	UNIX definitions (if not stand-alone)	*/

#include < stdio.h>
#define EOL 10
#define CR 10

/*-----------------------------------------------------------------------75
** pertains to stack ops re parameter size, define as constant instead of
** decimal number of bytes in size.
*/
#define INT_SZ 4 /** Sat 13 Aug 2011 04:02:40 PM CDT **/

/**--------------------------------------------**/
#define	FALSE	0
#define	TRUE	1
#define	NO	0
#define	YES	1

/**--------------------------------------------**/
/*    Define the symbol table parameters        */

#define SYMB_SIZE	20  /** +2, struc len increased **/
#define SYMTBSZ		7200	/** orig. 5040 **/
			/** added 30Jun2010 s_d v.2r8 **/

#define NUMBSTATICS	300	/** 300 * 20 = 6000 **/

/** #def numautos 60 * 20 = 1200 + 6000 = 7200 **/

#define startstatic	symtab
#define endstatics	startstatic+NUMBSTATICS*SYMB_SIZE
#define startauto	endstatics+SYMB_SIZE
#define endautos	symtab+SYMTBSZ-SYMB_SIZE

/* Define symbol table entry format, size is SYMB_SIZE */

#define NAME	0    /** length 13 {0..12}      **/
                       /** namemax + null = 13    **/
#define IDENT	13   /** len 1 (indirection ndx)**/
#define TYPE	14   /** length 1               **/
#define STORAGE	15   /** length 1               **/
#define OFFSET	16   /** length 4 {16..19}      **/
	/** SYMB_SIZE must match tbl len **/

/*	System wide name size (for symbols)	*/
#define NAMESIZE 13   /** array size with null **/
#define NAMEMAX  12   /** truncate if needed   **/
/**--------------------------------------------**/

/*	Define possible entries for "ident"	*/
#define	VARIABLE 1
#define	ARRAY    2
#define	POINTER  3
#define	FUNCTION 4

/*** TYPES ***/
/*	Define possible entries for "type"	*/
#define	CCHAR	1	/** 1 byte **/
#define	CINT	2	/** 4 bytes **/

/** added 30Jun2010 s_d v.2r8 **/
#define	CLONG	4	/** 4 bytes **/

/** added Tue 26 Jul 2011 04:14:30 PM CDT **/
#define CSHORT	3	/** 2 bytes **/
#define CDOUBLE 5	/** 8 bytes **/
/*** eo TYPES ***/

/*	Define possible entries for "storage"	*/
#define	C_STATIC	1
#define	C_AUTO	2

/*	Define the "while" statement stack	*/
#define	WSTBLSZ	100
#define	WS_SZ		5
#define	WS_MAX	ws+WSTBLSZ-WS_SZ

/*	Define entry offsets in while stack	*/
/** indexes of int elements **/
#define	WS_SYMS 0
#define	WS_SP   1
#define	WS_LOOP 2
#define	WS_LBL  3
#define	WS_LBL2 4

/** ucc **/
/* entry offsets in "do"/"for"/"while"/"switch" stack */

#define	WSSYM	0
#define	WSSP	1
#define	WSTYP	2
#define	WSCASEP	3
#define	WSTEST	3
#define	WSINCR	4
#define	WSDEF	4
#define	WSBODY	5
#define	WSTAB	5
#define	WSEXIT	6

/* possible entries for "wstyp" */

#define	WSWHILE		0
#define	WSFOR		1
#define	WSDO		2
#define	WSSWITCH	3

/* "switch" label stack */

#define	SWSTSZ	100

/*	Define the literal pool			*/
#define	LITABSZ	1000
#define	LITMAX	LITABSZ-1

/*	Define the input line			*/
#define	LINESIZE	80
#define	LINEMAX	LINESIZE-1
#define	MP_MAX	LINEMAX

/*	Define the macro (define) pool		*/
#define	MACQ_SZ 2176  /** was 1000 **/
#define	MAC_MAX	MACQ_SZ-1

/*	Define statement types (tokens)		*/
#define	ST_IF     1
#define	ST_WHILE  2
#define	ST_RETURN 3
#define	ST_BREAK  4
#define	ST_CONT   5
#define	ST_ASM    6
#define	ST_EXPR   7
/** ucc **/
#define	ST_DO		8
#define	ST_FOR		9
#define	ST_SWITCH	10

/* Define how to carve up a name too long for the assembler */
/** originally 7,7 **/
#define asmpref	11
#define asmsuff	3

/**------------------------------------**/
/*    Now reserve some storage words    */
/**  S T A T I C   V A R I A B L E S   **/
/**------------------------------------**/
 
char	symtab[SYMTBSZ];	/* symbol table */
char	*staticptr,*autoptr;	/* ptrs to next entries */

int	ws[WSTBLSZ];	/* while stack */
int	*wsptr;		/* ptr to next entry */

/** ucc **/
int	swstcase[SWSTSZ];
int	swstlab[SWSTSZ];
int	swstp;

char	litq[LITABSZ];	/* literal pool */
int	litptr;		/* ptr to next entry */

char	macq[MACQ_SZ];	/* macro string buffer */
int	macptr;		/* and its index */

char	line[LINESIZE];	/* parsing buffer */
char	mline[LINESIZE];	/* temp macro buffer */
int	lptr,mptr;		/* ptrs into each */

/*	Misc storage	*/
int	nxtlab,		/* next avail label # */
	litlab,		/* label # assigned to literal pool */
	Msp,		/* Maximum relative stk ptr */
	Csp,		/* compiler relative stk ptr */
	argstk,		/* function arg sp */
	ncmp,		/* # open compound statements */
	errcnt,		/* # errors in compilation */
	errstop,	/* stop on error			gtf 7/17/80 */
	eof_flg,	/* set non-zero on final input eof */
	fp_input,	/* iob # for input file */
	fp_output,	/* iob # for output file (if any) */
	fp_input2,	/* iob # for "include" file */
	glbflag,	/* non-zero if internal globals */
	ctext,		/* non-zero to intermix c-source */
	cmode,		/* non-zero while parsing c-code */
			/* zero when passing assembly code */
	lastst,		/* last executed statement type */
	mainflg,	/* output is to be first asm file	gtf 4/9/80 */
	saveout,	/* holds output ptr when diverted to console	   */
			/*					gtf 7/16/80 */
	fnstart,	/* line# of start of current fn.	gtf 7/2/80 */
	lineno,		/* line# in current file		gtf 7/2/80 */
	infunc,		/* "inside function" flag		gtf 7/2/80 */
	savestart,	/* copy of fnstart "	"		gtf 7/16/80 */
	saveline,	/* copy of lineno  "	"		gtf 7/16/80 */
	saveinfn;	/* copy of infunc  "	"		gtf 7/16/80 */

char   *currfn,		/* ptr to symtab entry for current fn.	gtf 7/17/80 */
       *savecurr;	/* copy of currfn for #include		gtf 7/17/80 */
char	quote[2];	/* literal string for '"' */
char	*symbptr;	/* work ptr to any char buffer */
int	*iptr;		/* work ptr to any int buffer */

/*	>>>>> start cc0 <<<<<<		*/

/*					*/
/*	Compiler begins execution here	*/
/*					*/
main()
	{
	staticptr=startstatic;	/* clear global symbols */
	autoptr=startauto;	/* clear local symbols */
	wsptr=ws;		/* clear while stack */
	macptr=		/* clear the macro pool */
	litptr=		/* clear literal pool */
  	Msp =		/* stack ptr (maximum) */
  	Csp =		/* stack ptr (relative) */
	errcnt=		/* no errors */
	errstop=	/* keep going after an error		gtf 7/17/80 */
	eof_flg=	/* not eof yet */
	fp_input=	/* no input file */
	fp_input2=	/* or include file */
	fp_output=	/* no open units */
	saveout=	/* no diverted output */
	ncmp=		/* no open compound states */
	lastst=		/* no last statement yet */
	mainflg=	/* not first file to asm 		gtf 4/9/80 */
	fnstart=	/* current "function" started at line 0 gtf 7/2/80 */
	lineno=		/* no lines read from file		gtf 7/2/80 */
	infunc=		/* not in function now			gtf 7/2/80 */
	quote[1]=
	0;		/*  ...all set to zero.... */
	quote[0]='"';	/* fake a quote literal */
	currfn=NULL;	/* no function yet		gtf 7/2/80 */
	cmode=1;	/* enable preprocessing */

	/*				*/
	/*	compiler body	*/
	/*				*/
	ask();		/* get user options */
	openout();	/* get an output file */
	openin();	/* and initial input file */
	header();	/* intro code */
	parse(); 	/* process ALL input */
	dumpstatics();	/* and all static memory */
	trailer();	/* follow-up code */
	closeout();	/* close the output (if any) */
	errorsummary();	/* summarize errors (on console!) */
	return;		/** then exit to system */
/**	exit(); *** sjd 25-JUL-2008 ***/
	}

/*					*/
/*	Abort compilation		*/
/*		gtf 7/17/80		*/
/**--
abort()
{
	int j,k;

	if (fp_input2) endinclude();
	if (fp_input)  fclose(fp_input);
	closeout();
	toconsole();
	pl("Compilation aborted.");  nl();
	exit();
} --**/  /* end abort */

/*					*/
/*	Process all input text		*/
/*					*/
/* At this level, only static declarations, */
/*	defines, includes, and function */
/*	definitions are legal...	*/
parse()
{
	while (eof_flg == 0)		/* do until no more input */
		{
		if (amatch("char",4))
			{
			declstatic(CCHAR);
			ns();
			}
		else if (amatch("int",3))
			{
			declstatic(CINT);
			ns();
			}
		else if (match("#asm")) doasm();
		else if (match("#include")) doinclude();
		else if (match("#define")) addmac();
		else newfunc();
		deblank();	/* force eof if pending */
		} /** deblank invokes  preprocess(), input_line(), etc. **/
} /** eo parse **/

/*						*/
/*	Dump the literal pool		*/
/*						*/

/** Test as DB "Str",0, .. Null terminated **/
/** litptr represents next free position in table **/
/** Table Entries are null terminated strings **/
/** Strings are from litq 0 up to litptr **/

dumplits()
{
	int j,k;

	if (litptr == 0) return;	/* if nothing there, exit...*/
	sa_dseg();			/* Put back in data segment. */
	printlabel (litlab);		/* print literal label */
	k=0;				/* init an index... */

	while (k < litptr)		/** loop thru literal strings buffer **/
		{			/** do one line per string **/
		j = 1;			/** instring flag, reset for each DB **/
		defbyte();		/** B.O.L. pseudo-op to define byte, DB **/
		if (litq[k]) foutput_chr(34); /** start string with quote **/

		while (j)		/** j is control flag **/
			{
			if ((litq[k] & 127) == 0)  
				{	/** next is null **/
				if (j == 1)
					{ /** leading null is probably an error **/
					foutput_chr(',');
					foutput_chr('0');
					nl(); /** one str per DB, next line. **/
					j = 0; k++;
					break;
					}	/** break while, to ck j **/
				}
			else if ((litq[k] & 127) < ' ') k++;  /** filter lo **/
			else if ((litq[k] & 127) > '~') k++;  /** filter hi **/
			else	{	/** xfer chr, lookahead for next is chr **/
				foutput_chr((litq[k++] & 127));
				if ((litq[k]& 127) == 0) foutput_chr(34);
					/** eo str quote **/
				}
			}	/** EO Line **/
		}	/** gone thru Literals **/
	sa_cseg();	/* Put back in code segment. */
}  /** eo dumplits **/

/*						*/
/*	Dump all static variables	*/
/*						*/
/** modified for NASM 'TIMES amt D{B|W} 0' **/

dumpstatics()
{
	int j;

	if (glbflag == 0) return;	/* don't if user said no */

	sa_dseg();		/* Put back in data segment. */
	symbptr = startstatic;

	while	(symbptr < staticptr)
		{
		if (symbptr[IDENT] != FUNCTION)
			/* do if anything but function */
			{
			asm_symb(symbptr);
				/* output name as label... */
			colon();
			def_sizein();  /** TIMES Prefix **/

				/* issue amount needed. */
			j = (	(symbptr[OFFSET] & 255) + 
				((symbptr[OFFSET+1] & 255) << 8) +
				((symbptr[OFFSET+2] & 255) << 16) +
				((symbptr[OFFSET+3] & 255) << 24) );

		/**	outdec(j);	**/  /* need that many */
			if (j) outdec(j);  /** prevent TIMES 0 db 0 **/
			else outdec(1);

				/* issue assembler defn type... */
			if (symbptr[IDENT] == POINTER) /* Pointer */
				defstorptr();
			else
				{
				if (symbptr[TYPE] == CCHAR) /* Character */
					defstorchr();
				if (symbptr[TYPE] == CINT)	/* Integer */
					defstorint();
				}
			nl();
			}
		symbptr = symbptr + SYMB_SIZE;
		}
	sa_cseg();		/* Put back in code segment. */
}

/*						*/
/*	Dump all auto variables		*/
/*						*/
/** dumped as comments to each function **/

dumpautos()
{
	int j;

	if (ctext == 0) return; /** User said to skip.  **/
	symbptr = startauto;	/** Start at beginning. **/
	while (symbptr != autoptr)
		{  /** autoptr is the end, ptr to the next free **/
		sa_comment();
		tab();
		asm_symb(symbptr);
				/* output name as label... */
		tab();
				/* issue assembler defn ident... */
		if (symbptr[IDENT] == VARIABLE)  outstr("VAR");
		else if (symbptr[IDENT] == ARRAY)  outstr("ARRAY");
		else if (symbptr[IDENT] == POINTER)  outstr("PTR");
		else if (symbptr[IDENT] == FUNCTION)  outstr("FUNC");
		tab();
				/* issue assembler defn type... */
		if (symbptr[TYPE] == CCHAR)  outstr("CHAR");
		else if (symbptr[TYPE] == CINT)  outstr("INT");
		tab();
				/* issue OFFSET. */
		j = (		(symbptr[OFFSET] & 255) + 
				((symbptr[OFFSET+1] & 255) << 8) +
				((symbptr[OFFSET+2] & 255) << 16) +
				((symbptr[OFFSET+3] & 255) << 24) );
		outdec(j);
		nl();
		symbptr = symbptr + SYMB_SIZE;
		}
}

/*					*/
/*	Report errors for user	*/
/*					*/

errorsummary()
	{
	/* see if anything left hanging... */
	if (ncmp) error("missing closing bracket");
		/* open compound statement ... */
	nl();
	outstr("There were ");
	outdec(errcnt);	/* total # errors */
	outstr(" errors in compilation.");
	nl();
	}

/** EO C86N-0.C **/

/*	>>>>> start cc1 <<<<<<	*/

/*					*/
/*	Get options from user	*/
/*					*/
ask()
{
	int k,num[1];

	kill();		/* clear input line */
/**	foutput_chr(12);	* clear the screen *  **/
	nl();nl();		/* print banner */
	pl(BANNER);
	nl();
	pl(AUTHOR);
	nl();nl();
/**	pl("Distributed by: The Code Works(tm)");
	pl("                Box 550, Goleta, CA 93017");
  -originally. ***/
	pl("* NASM Version, 26-Mar-2010 *");
	nl();
	pl(VERSION);
	nl();
	nl();

	/* see if user wants to interleave the c-text */
	/*	in form of comments (for clarity) */
	pl("Do you want the c-text to appear (y,N) ? ");
	gets(line);		/* get answer */
	ctext = 0;		/* assume no */
	if ((inspect_chr()=='Y')|(inspect_chr()=='y'))
		ctext=1;	/* user said yes */

	/* see if the user is compiling everything at once */
	/*	(as is usually the case) - gtf 4/9/80 */
	pl("Are you compiling the whole program at once (Y,n) ? ");
	gets(line);
	if ((inspect_chr() != 'N') & (inspect_chr() != 'n'))
		{	/* single file - assume... */
		glbflag = 1;  /* define globals */
		mainflg = 1;  /* first file to assembler */
		nxtlab  = 0;  /* start numbers at lowest possible */
		}
	else {		/* one of many - ask everything */
	 	/* see if user wants us to allocate static */
	 	/*  variables by name in this module	*/
	 	/*	(pseudo external capability)	*/
	 	pl("Do you want the globals to be defined (y,N) ? ");
	 	gets(line);
		glbflag = 0;
	 	if ((inspect_chr() == 'Y') | (inspect_chr() == 'y'))
	 		glbflag = 1;	/* user said yes */

	 	/* see if we should put out the stuff	*/
	 	/*	needed for the first assembler	*/
	 	/*	file. - gtf 4/9/80			*/
		pl("Is the output file the first one the assembler will see (y,N) ? ");
	 	gets(line);
	 	mainflg = 0;
		if ((inspect_chr() == 'Y') | (inspect_chr() == 'y'))
	 		mainflg = 1;	/* indeed it is */

	 	/* get first allowable number for compiler-generated */
	 	/*	labels (in case user will append modules) */
		while (1)
			{
	 		pl("Starting number for labels (0) ? ");
	 		gets(line);
	 		if (inspect_chr() == 0)
				{
				num[0] = 0;
				break;
				}
			if (k = number(num)) break;
	 		}
	 	nxtlab = num[0];
		}

	/* see if user wants to be sure to see all errors */
	pl("Should I pause after an error (y,N) ? ");
	gets(line);
	errstop = 0;
	if ((inspect_chr() == 'Y') | (inspect_chr() == 'y')) errstop = 1;

	litlab = getlabel();	/* first label=literal pool */ 
	kill();			/* erase line */
}

/*					*/
/*	Get output filename	*/
/*					*/
openout()
{
	kill();			/* erase line */
	fp_output = 0;			/* start with none */
	pl("Output filename? "); /* ask...*/
	gets(line);			/* get a filename */
	if (inspect_chr() == 0) return;	/* none given... */
	if ((fp_output = fopen(line,"w")) == NULL) /* if given, open */
		{
		fp_output = 0;	/* can't open */
		error("Open failure!");
		}
  /*** TBI, else output filename to asm file, & for MAP ***/
	kill();			/* erase line */
}

/*					*/
/*	Get (next) input file	*/
/*					*/
openin()
{
	fp_input = 0;			/* none to start with */
	while (fp_input == 0){		/* any above 1 allowed */
		kill();			/* clear line */
		if (eof_flg)break;	/* if user said none */
		pl("Input filename? (..or just [Enter] key to finish.) > ");
		gets(line);			/* get a name */
		if (inspect_chr() == 0)
			{
			eof_flg = 1;
			break;
			} /* none given... */
		if ((fp_input = fopen(line,"r")) != NULL)
			newfile();		/* gtf 7/16/80 */
		else	{
			fp_input = 0;	/* can't open it */
			pl("Open failure");
			}
		}
	kill();	/* erase line */
}

/*					*/
/*	Reset line count, etc.	*/
/*			gtf 7/16/80	*/
newfile()
{
	lineno  = 0;	/* no lines read */
	fnstart = 0;	/* no fn. start yet. */
	currfn  = NULL;	/* because no fn. yet */
	infunc  = 0;	/* therefore not in fn. */
}  /* end newfile */

/*						*/
/*	Open an include file		*/
/*						*/
/** added tmp array for filename instead of input_line ptr to handle CR **/

char fname_array[14];

doinclude()
{
	int i;
	char *src;

	deblank();	/* skip over to name */
	toconsole();					/* gtf 7/16/80 */
	outstr("#include ");
	outstr(line+lptr);

	i = 0;
	src = line+lptr;	/** copy input_line filename to prep array **/
	while (*src != CR)
		{
		fname_array[i++] = *src++;
		}
	fname_array[i] = 0;		/** null terminate str **/

	nl();
	tofile();

	if (fp_input2)					/* gtf 7/16/80 */
		error("Cannot nest include files");
	else if ((fp_input2 = fopen(&fname_array[0],"r")) == NULL)
		{
		fp_input2 = 0;
		error("Open failure on include file");
		}
	else {
		saveline = lineno;
		savecurr = currfn;
		saveinfn = infunc;
		savestart= fnstart;
		newfile();
		}
	kill();	/* clear rest of line */
			/* so next read will come from */
			/* new file (if open */
}

/*						*/
/*	Close an include file		*/
/*				gtf 7/16/80	*/
endinclude()
{
	toconsole();
	outstr("#end include"); nl();
	tofile();

	fp_input2  = 0;
	lineno  = saveline;
	currfn  = savecurr;
	infunc  = saveinfn;
	fnstart = savestart;
}  /* end endinclude */

/*						*/
/*	Close the output file		*/
/*						*/
closeout()
{
	tofile();	/* if diverted, return to file */
	if (fp_output) fclose(fp_output); /* if open, close it */
	fp_output = 0;		/* mark as closed */
}

/*						*/
/*	Declare a static variable	*/
/*	  (i.e. define for use)		*/
/*						*/
/* makes an entry in the symbol table so subsequent */
/*  references can call symbol by name	*/
/** globals (statics) are found outside a function block **/
/** this fn is called when a TYPE `int or `char is found **/

declstatic(typ) int typ;	/* typ is cchar or cint */
{
	int k,j;
	char sname[NAMESIZE]; /** 1st mention of sname array **/
		/** sname is an auto, on stack processing array. **/

	while (1) /** loop while comma'd **/
		{
		while (1)
			{  /** is_identifier() gets & validates identifier **/
			if (endst()) return;	/* do line */
			k = 1;			/* assume 1 element */

			if (match("*"))		/* pointer ? */
				j = POINTER;	/* yes */
			else j = VARIABLE;	/* no */

			if (is_identifier(sname) == 0)	/* name ok? */
				illname();		/* no... const, */
			if(findstatic(sname))	/* already there? */
				multidef(sname);
			if (match("["))		/* array? */
				{
				k = mk_subscript(); /* get size */
				if (k) j = ARRAY;	/* !0=array */
				else j = POINTER; /* 0=ptr, a[] */
				}
			addstatic(sname,j,typ,k); /* add symbol */
			break;
			}
		if (match(",") == 0) return;	/* more? */
		}
}

/*						*/
/*	Declare auto variables		*/
/*	(i.e. define for use)		*/
/*						*/
/* works just like "declstatic" but modifies machine stack */
/*	and adds symbol table entry with appropriate */
/*	stack offset to find it again			*/
/** called when symbol is an automatic **/

declauto(typ) int typ;	/* typ is cchar or cint */
{
	int k,j;
	char sname[NAMESIZE];

	while (1)
		{
		while (1)
			{ /** is_identifier() gets & validates identifier **/
			if (endst()) return;

			if (match("*"))
				j = POINTER;
			else j = VARIABLE;

			if (is_identifier(sname) == 0) illname(); /** const **/

			if (findauto(sname)) multidef(sname);

			if (match("["))
				{
				k = mk_subscript();
				if (k)
					{  /** if int, double size of char **/
					j = ARRAY;
					if (typ == CINT) k = 4 * k;
					}
				else
					{
					j = POINTER;
					k = 4;		/** was 2 **/
					}
				}
			else
				if ((typ == CCHAR) & (j != POINTER)) k = 1;
				else k = 4;		/** was 4 **/

			/* change machine stack */
			/** negative from activation frame, sp, for auto **/

			Msp = Msp - k;
			addauto(sname,j,typ,Msp);
			break;
			}
		if (match(",") == 0) return;
		}
}

/** EO C86N-1.C **/
/*	>>>>>> start of cc2 <<<<<<<<	*/

/*						*/
/*	Get required array size		*/
/*						*/

/* invoked when declared variable is followed by "[" */
/*	this routine makes subscript the absolute */
/*	size of the array. */
/** doesn't eval expression, nor multi-dimensions. **/

mk_subscript()
{
	int num[1];

	if (match("]")) return 0;	/* null size */
	if (number(num) == 0)	/* go after a number */
		{
		error("must be constant");	/* it isn't */
		num[0] = 1;		/* so force one */
		}
	if (num[0] < 0)
		{
		error("negative size illegal");
		num[0] = (-num[0]);
		}
	needbrack("]");		/* force single dimension */
	return num[0];		/* and return size */
}

/*					*/
/*	Begin a function		*/
/*					*/

/* Called from "parse" this routine tries to make a function */
/*	out of what follows.	*/
/** is_identifier() gets & validates identifier **/ 

newfunc()
{
	char n[NAMESIZE];	/* ptr => currfn,  gtf 7/16/80 */
	int argtop;		/* max arg stack size */

	/** trap for non-function as syntax error, at this point **/
	/** is_identifier() gets & validates identifier **/

	if (is_identifier(n) == 0)  /** might be const **/
		{
		error("illegal function or declaration");
		kill();	/* invalidate line */
		return;
		}

	fnstart = lineno;	/* remember where fn began gtf 7/2/80 */
	infunc = 1;		/* note, in function now. gtf 7/16/80 */

	if (currfn = findstatic(n))	/* already in symbol table ? */
		{
		if (currfn[IDENT] != FUNCTION) multidef(n);
			/* already variable by that name */
		else if (currfn[OFFSET] == FUNCTION) multidef(n);
			/* already function by that name */
		else currfn[OFFSET] = FUNCTION;
			/* otherwise we have what was earlier*/
			/*  assumed to be a function */
		}

	/* if not in table, define as a function now */

	else currfn = addstatic(n,FUNCTION,CINT,FUNCTION);

	/* Indicate to console what routine that we're in. */

	toconsole();					/* gtf 7/16/80 */
	outstr("====== ");
	outstr(currfn + NAME);
	outstr("()");
	nl();
	tofile();

	/* we had better see open paren for args... */
	/** formal parameter processing at the beginning
		of a function declaration **/

	if (match("(") == 0) error("missing open paren");
	asm_symb(n); colon(); nl();	/* print function name */
	autoptr = startauto;		/* "clear" local symbol table*/
	argstk = 0;				/* init arg count */
	while (match(")") == 0)		/* then count args */
		{	/* any legal name bumps arg count */
			/** is_identifier() gets & validates identifier **/
		if (is_identifier(n))
			{
			if (findauto(n)) multidef(n);
			else	{
				addauto(n,0,0,argstk);
					/* Add local symbol to be later */
					/* processed by getarg(). */
				argstk = argstk + 2;
				}
			}
		else	{
			error("illegal argument name");
			junk();
			}
		deblank();

		/* if not closing paren, should be comma */
		if (streq(line+lptr,")") == 0)
			{
			if (match(",") == 0)
			error("expected comma");
			}
		if (endst()) break;
		}

	argtop = argstk;	/* Save max arg stack size. */
	while (argstk)	/* now let user declare what types  */
		{		/* of things those arguments were */
		if (amatch("char",4))
			{
			getarg(CCHAR,argtop);
			ns();
			continue;
			}
		else if (amatch("int",3))
			{
			getarg(CINT,argtop);
			ns();
			continue;
			}
		else	{
			error("wrong number args");
			break;
			}
		}

	Msp = 00;		/* Preset local stack ptr. */
	Csp = 00;		/* preset stack ptr */
	FN_Prolog();		/* Do function initialization. */
				/* AutoC size is undetermined here, not **/
				/* till statement() is processed **/

	if (statement() != ST_RETURN)	/* do all statements, but if */
					/* last one is a return, skip */
		{			/* cleaning up the stack */
		sa_rtnstk(0);
		sa_ret();
		}

	/* Handle function termination. */
	FN_Epilog();		/* Do function termination. */
	Msp = Csp = 0;		/* reset stack ptr again */
	dumpautos();		/* Dump the local symbol table. */
	autoptr = startauto;	/* deallocate all locals */
	dumplits();		/* Dump the literal pool for the function.*/
	litlab = getlabel();	/* Now re-initialize the pool. */
	litptr = 0;
	infunc = 0;		/* not in fn. any more	gtf 7/2/80 */
} /** eo newfunc **/

/*						*/
/*	Declare argument types		*/
/*						*/
/* called from "newfunc" this routine adds an entry in the */
/*	local symbol table for each named argument */

	/* top tells how the max arg stack size was found while
	   scanning arguments.  From this, we can calculate the
	   the actual stack offset and stuff it back into the
	   local symbol table.
	*/
	/* t = cchar or cint, top = max arg stack */

getarg(t,top) int t,top;
	{
	char n[NAMESIZE], *argptr;
	int j, auto_addr;

	while (1)
		{
		if (argstk == 0) return;	/* no more args */
		if (match("*")) j = POINTER;
		else j = VARIABLE;
			/** is_identifier() gets & validates identifier **/
		if (is_identifier(n))
			{
			if (match("["))	/* pointer ? */
				/* it is a pointer, so skip all */
				/* stuff between "[]" */
				{
				while (scan_nxt() != ']')
					if (endst()) break;
				j = POINTER;	/* add entry as pointer */
				}
			if (argptr = findauto(n))
				{
				argptr[IDENT] = j;
					/* save type info for arg just 
					   found. */
				argptr[TYPE] = t;
				auto_addr = top - (argptr[OFFSET+3]<<24)
						- (argptr[OFFSET+2]<<16)
						- (argptr[OFFSET+1]<<8)
						- argptr[OFFSET]+4;	/** was +2 **/

				/*Calculate offset to arg taking
				  into account the return address
				  and the saved EBP register left
				  on the stack. */

				argptr[OFFSET] = auto_addr;
				argptr[OFFSET+1] = auto_addr>>8;
				argptr[OFFSET+2] = auto_addr>>16;
				argptr[OFFSET+3] = auto_addr>>24;

				/*save offset back in local symbol
				  table entry. */
				}
			else
				error("expecting argument name");
			}
		else
			illname();
		argstk = argstk - 2;	/* cnt down */
		if (endst()) return;
		if (match(",") == 0) error("expected comma");
		}
}

/*					*/
/*	Statement parser		*/
/*					*/
/* called whenever syntax requires	*/
/*	a statement. 			 */
/*  this routine performs that statement */
/*  and returns a number telling which one */

statement()
{
	if ((inspect_chr()==0) & (eof_flg)) return;
	else if (amatch("char",4))
		{
		declauto(CCHAR);
		ns();
		}
	else if (amatch("int",3))
		{
		declauto(CINT);
		ns();
		}
	else if (match("{"))  compound();
	else if (amatch("if",2))
		{
		doif();
		lastst = ST_IF;
		}
	else if (amatch("do",2))
		{
		dodo();
		lastst = ST_DO;
		}
	else if (amatch("while",5))
		{
		dowhile();
		lastst = ST_WHILE;
		}
	else if (amatch("return",6))
		{
		doreturn();
		ns();
		lastst = ST_RETURN;
		}
	else if (amatch("break",5))
		{
		dobreak();
		ns();
		lastst = ST_BREAK;
		}
	else if (amatch("continue",8))
		{
		docont();
		ns();
		lastst = ST_CONT;
		}
/**** -not ready for prime time-
	else if (amatch ("for", 3))
		{
		dofor ();
		lastst = STFOR;
		}
	else if (amatch ("switch", 6))
		{
		doswitch ();
		lastst = STSWITCH;
		}
****/
/***	else if (amatch("case",4))
		{
		docase ();
		lastst = statement ();
		}
	else if (amatch("default", 7))
		{
		dodefault ();
		lastst = statement();
		}
***/
	else if (match(";"));
	else if (match("#asm"))
		{
		doasm();
		lastst = ST_ASM;
		}

	/* if nothing else, assume it's an expression */
	else	{ /** presume comma expr possible **/
		expression(YES); /** an expression ending with a  **/ 
		ns();		/** semicolon is a statement in C. **/
		lastst = ST_EXPR;
		}
	return lastst;
}		/** eo statement **/

/*					*/
/*	Semicolon enforcer	*/
/*					*/
/* called whenever syntax requires a semicolon */

ns()
{
	if (match(";") == 0)  error("missing semicolon");
}

/*					*/
/*	Compound statement	*/
/*					*/
/* allow any number of statements to fall between "{}" */

compound()
{
	++ncmp;		/* new level open */
	while (match("}") == 0) statement(); /* do one */
	--ncmp;		/* close current level */
}

/*				*/
/*	"if" statement	*/
/*				*/

doif()
{
	int flev,fsp,flab1,flab2;
	int t_lbl;

	flev = autoptr;		/* record current local level */
	fsp = Csp;			/* record current stk ptr */

	t_lbl = getlabel();	/** for true branch **/
	flab1 = getlabel();	/* get label for false branch */

/**	logical_test(flab1);	* get expression, and branch false */
	logic_tst(t_lbl,flab1); /** test new fn **/
/**	logical_tst2(flab1,FALSE);	* get expression, and branch false */

	sa_mk_lbl(t_lbl);		/** codegen true branch label **/

	statement();		/* if true, do a statement */
	Csp = sa_modstk(fsp);	/* then clean up the stack */
	autoptr = flev;		/* and deallocate any locals */
	if (amatch("else",4) == 0)	/* if...else ? */
		{			/* simple "if"...print false label */
		sa_mk_lbl(flab1);
		return;		/* and exit */
		}

	/* an "if...else" statement. */

	sa_jump(flab2 = getlabel());		/* jump around false code */
	printlabel(flab1); colon(); nl();	/* print false label */
	statement();				/* and do "else" clause */
	Csp = sa_modstk(fsp);			/* then clean up stk ptr */
	autoptr = flev;				/* and deallocate locals */
	sa_mk_lbl(flab2);				/* print true label */
}		/** eo doif **/

/*						*/
/*	"do" statement "while" (expr)	*/
/*						*/
dodo()
{
	int ws[WS_SZ];		/* allocate local stack */
	int t_lbl;			/** auto 'True' Label **/

	ws[WS_SYMS] = autoptr;	/* record local level */
	ws[WS_SP] = Csp;		/* and stk ptr */

	ws[WS_LBL2] = getlabel();	/* do loop label */
	ws[WS_LOOP] = getlabel();	/* and looping label */
	t_lbl = getlabel();	/** make a unique label for our use **/
	ws[WS_LBL] = getlabel();	/* and exit label */

	addwhile(ws);		/* add entry to stack */

		/* (for "break" statement) */
	sa_mk_lbl(ws[WS_LBL2]);	/* loop label */
	statement();		/* do a statement, body of do_while */
	if (amatch("while",5) == 0)
		{
		error("'while' expected.");
		return;		/* and exit */
		}

	sa_mk_lbl(ws[WS_LOOP]);		/* cont label, at while(expr) */
/**	logical_test(ws[WS_LBL]);	* get expression and branch false */

	logic_do_tst(t_lbl,ws[WS_LBL]); /** test new fn, for DO **/
/**	sa_mk_lbl(t_lbl);	** codegen true branch label **/

	sa_jump(ws[WS_LBL2]);		/* continue to loop */

	sa_mk_lbl(ws[WS_LBL]);		/* exit label */

	ns();					/* look for ending semi-colon. */
	autoptr = ws[WS_SYMS];		/* deallocate locals */
	Csp = sa_modstk(ws[WS_SP]);	/* clean up stk ptr */
	delwhile();				/* delete stack entry */
}		/** eo dodo **/


/*						*/
/*	"while" (expr) statement	*/
/*						*/

dowhile()
{
	int ws[WS_SZ];			/* allocate local stack */
	int t_lbl;			/** auto 'True' Label **/

	ws[WS_SYMS] = autoptr;		/* record local level */
	ws[WS_SP] = Csp;			/* and stk ptr */

	ws[WS_LOOP] = getlabel();	/* and looping label */
	t_lbl = getlabel();	/** make a unique label for our use **/
	ws[WS_LBL] = getlabel();		/* and exit label */
	addwhile(ws);			/* add entry to stack */

		/* (for "break" statement) */
	sa_mk_lbl(ws[WS_LOOP]);		/* loop label */
/**	logical_test(ws[WS_LBL]);	* see if true */ 
	logic_tst(t_lbl,ws[WS_LBL]); /** test new fn **/

	sa_mk_lbl(t_lbl);		/** codegen true branch label **/

	statement();			/* if so, do a statement */
	sa_jump(ws[WS_LOOP]);		/* loop to label */
	sa_mk_lbl(ws[WS_LBL]);		/* exit label */
	autoptr = ws[WS_SYMS];		/* deallocate locals */
	Csp = sa_modstk(ws[WS_SP]);	/* clean up stk ptr */
	delwhile();				/* delete stack entry */
}		/** eo dowhile **/

/*
 *	"for" statement
 */
/*****
dofor ()
{
	int	ws[7],
		*pws;

	ws[WSSYM] = autoptr;
	ws[WSSP] = Csp;
	ws[WSTYP] = WSFOR;
	ws[WSTEST] = getlabel ();
	ws[WSINCR] = getlabel ();
	ws[WSBODY] = getlabel ();
	ws[WSEXIT] = getlabel ();
	addwhile (ws);
	pws = readwhile ();
	needbrack ("(");

	if (match (";") == 0) {
		expression (YES);
		ns ();
	}
	gnlabel (pws[WSTEST]);

	if (match (";") == 0) {
		expression (YES);
		testjump (pws[WSBODY], TRUE);
		jump (pws[WSEXIT]);
		ns ();
	} else
		pws[WSTEST] = pws[WSBODY];
	gnlabel (pws[WSINCR]);

	if (match (")") == 0) {
		expression (YES);
		needbrack (")");
		jump (pws[WSTEST]);
	} else
		pws[WSINCR] = pws[WSTEST];
	gnlabel (pws[WSBODY]);
	statement (NO);
	jump (pws[WSINCR]);
	gnlabel (pws[WSEXIT]);
	locptr = pws[WSSYM];
	stkp = modstk (pws[WSSP]);
	delwhile ();
}
*****/

/*
 *	"switch" statement
 */
/*****
doswitch ()
{
	int	ws[7];
	int	*ptr;

	ws[WSSYM] = locptr;
	ws[WSSP] = stkp;
	ws[WSTYP] = WSSWITCH;
	ws[WSCASEP] = swstp;
	ws[WSTAB] = getlabel ();
	ws[WSDEF] = ws[WSEXIT] = getlabel ();
	addwhile (ws);
	immed ();
	printlabel (ws[WSTAB]);
	nl ();
	gpush ();
	needbrack ("(");
	expression (YES);
	needbrack (")");
	stkp = stkp + intsize(); **'?case' will adjust the stack **
	gjcase ();
	statement (NO);
	ptr = readswitch ();
	jump (ptr[WSEXIT]);
	dumpsw (ptr);
	gnlabel (ptr[WSEXIT]);
	locptr = ptr[WSSYM];
	stkp = modstk (ptr[WSSP]);
	swstp = ptr[WSCASEP];
	delwhile ();
}
*****/
/*
 *	"case" label
 */
/*****
docase ()
{
	int	val;

	val = 0;
	if (readswitch ()) {
	
		if (number (&val) == 0)
		
			if (pstr (&val) == 0)
				error ("bad case label");
		addcase (val);
	
		if (match (":") == 0)
			error ("missing colon");
	} else
		error ("no active switch");
}
*****/
/*
 *	"default" label
 */
/*****
dodefault ()
{
	int	*ptr,
		lab;

	if (ptr = readswitch ()) {
		ptr[WSDEF] = lab = getlabel ();
		gnlabel (lab);
	
		if (match (":") == 0)
			error ("missing colon");
	} else
		error ("no active switch");
}
*****/

/*					*/
/*	"return" statement	*/
/*					*/
doreturn()
{		/* if not end of statement, get an expression */
	if (endst() == 0) expression(YES);
	sa_rtnstk(0);			/* clean up stk */
	sa_ret();			/* and exit function */
}		/** eo doreturn **/

/*					*/
/*	"break" statement		*/
/*					*/
dobreak()
{
	int *ptr;

	/* see if any "whiles" are open */

	if ((ptr=readwhile()) == 0) return;	/* no */
	sa_modstk((ptr[WS_SP]));		/* else clean up stk ptr */
	sa_jump(ptr[WS_LBL]);			/* jump to exit label */
}		/** eo dobreak **/

/*					*/
/*	"continue" statement	*/
/*					*/
docont()
{
	int *ptr;

	/* see if any "whiles" are open */

	if ((ptr = readwhile()) == 0) return;	/* no */
	sa_modstk((ptr[WS_SP]));		/* else clean up stk ptr */
	sa_jump(ptr[WS_LOOP]);			/* jump to loop label */
}

/*					*/
/*	"asm" pseudo-statement	*/
/*					*/
/* enters mode where assembly language statement are */
/*	passed intact through parser	*/

doasm()
{
	int a;

	cmode = 0;		/* mark mode as "asm" */
	a = 1;

	while (a == 1)
		{
		input_line();	/* get and print lines */
		if (match("#endasm"))
			{	/* until... */
			sa_comment();
			outstr(line); /** pass back endasm comment **/ 
			break;
			}
		if (eof_flg) break;
		outstr(line);
		nl();
		}
/**	kill();		* invalidate line */
	cmode = 1;		/* then back to parse level */
}

/** EO C86N-2.C **/

/*	>>>>> start of cc3 <<<<<<<<<	*/

/*					*/
/*	Perform a function call	*/
/*					*/
/* called from heir11, this routine will either call		*/
/*	the named function, or if the supplied ptr is		*/
/*	zero, will call the contents of Primary Register	*/

callfunction(ptr)  char *ptr;	/* symbol table entry (or 0) */
{
	int nargs;

	nargs = 0;
	deblank();				/* already saw open paren */
/** Primary Register has target address, push PR [1]**/
	if (ptr == 0) sa_push();	
	while (streq(line+lptr,")") == 0)
		{
		if (endst()) break;
		expression(NO);			/* get an argument */
		if (ptr==0) sa_swapstk();	/* don't push addr */
		sa_push();			/* push argument */
		nargs = nargs + INT_SZ;		/* count args*2 */
		if (match(",") == 0) break;
		}
	needbrack(")");
	if (ptr) sa_call(ptr);
	else sa_callstk();
          /** target address is on the stack already [1] **/
	Csp = sa_modstk(Csp + nargs);		/* clean up arguments */
}		/** eo callfunction **/

junk()
{
	if (an(scan_nxt()))
		while (an(inspect_chr())) g_nxtchr();

	else	while (an(inspect_chr()) == 0)
			{
			if (inspect_chr() == 0) break;
			g_nxtchr();
			}
	deblank();
}

endst()
{
	deblank();
	return ((streq(line+lptr,";") | (inspect_chr() == 0)));
}

illname()
{
	error("illegal symbol name");
	junk();
}

multidef(sname) char *sname;
{
	error("already defined");
	sa_comment();
	outstr(sname); nl();
}

needbrack(str) char *str;
{
	if (match(str) == 0)
		{
		error("missing bracket");
		sa_comment();
		outstr(str);
		nl();
		}
}

needlval()
{
	error("must be lvalue");
}

/** -= Scope =- match sname to static's, secondly **/

findstatic(sname) char *sname;
{
	char *ptr;

	ptr = startstatic;
	while	(ptr != staticptr)
		{
		if (astreq(sname,ptr,NAMEMAX)) return ptr;
		ptr = ptr + SYMB_SIZE;
		}
	return 0;
}

/** -= Scope =- match sname to auto's, firstly **/
/** - on match, return ptr to sname in auto's table - **/

findauto(sname) char *sname;
{
	char *ptr;

	ptr = startauto;
	while	(ptr != autoptr)
		{
		if (astreq(sname,ptr,NAMEMAX)) return ptr;
			/** matched, return with ptr into tbl **/
		ptr = ptr + SYMB_SIZE;  /** ptr == &sname[0]   **/
		}
	return 0;
}

/* catch previously defined symbol and return its ptr, symbptr, which is
** its address in the static symbol table.  If not previously defined,
** define it now.
*/

addstatic(sname,id,typ,value) char *sname,id,typ; int value;
{
	char *ptr;

	if (symbptr = findstatic(sname)) return symbptr; /** exists **/
	if (staticptr >= endstatics)			/** trap for no room **/
		{
		error("global symbol table overflow");
		return 0;
		}
	symbptr = ptr = staticptr;
	while (an(*ptr++ = *sname++));		/* copy name */
	symbptr[IDENT] = id;
	symbptr[TYPE] = typ;
	symbptr[STORAGE] = C_STATIC;
	symbptr[OFFSET] = value;
	symbptr[OFFSET+1] = value >> 8;
	symbptr[OFFSET+2] = value >> 16;
	symbptr[OFFSET+3] = value >> 24;
	staticptr = staticptr + SYMB_SIZE;	/** update to next free position **/
	return symbptr;
}

addauto(sname,id,typ,value) char *sname,id,typ; int value;
{
	char *ptr;

	if (symbptr = findauto(sname)) return symbptr;
	if (autoptr >= endautos)
		{
		error("local symbol table overflow");
		return 0;
		}
	symbptr = ptr = autoptr;
	while (an(*ptr++ = *sname++));	/* copy name */
	symbptr[IDENT] = id;
	symbptr[TYPE] = typ;
	symbptr[STORAGE] = C_AUTO;
	symbptr[OFFSET] = value;
	symbptr[OFFSET+1] = value >> 8;
	symbptr[OFFSET+2] = value >> 16;
	symbptr[OFFSET+3] = value >> 24;
	autoptr = autoptr + SYMB_SIZE;
	return symbptr;
}

/* Test if next input string is legal symbol name */
/** A legal identifier is a chr, perhaps followed by alphanumerics **/
/** is_identifier, token input, ck lexeme in line buffer, returns T..F **/
/** sname[k] limit?? **/
/** ex. sname[NAMESIZE]; **/
/** was symname() -> tok_in() -> is_identifier **/

is_identifier(sname) char *sname;  
{  /** LEX ck, 1st chr alpha, rest alpha-numeric, append null **/
	int k;
	char c;

	deblank();
		/** 1st check for leading chr for identifier **/
	if (alpha(inspect_chr()) == 0) return FALSE; /** 0 **/
		/** flag lexeme as number ? **/

	k = 0;  /** inspect next chr for alph-numeric **/ 
		/** retrieve identifier from stream **/
	while (an(inspect_chr())) sname[k++] = g_nxtchr();
	sname[k] = 0;   /** append null **/
	return TRUE;	/** 1 **/
}

/* Return next avail internal label number */

getlabel()
{
	return(++nxtlab);
}

/* 1 - Print specified number as label */

printlabel(label) int label;
{	/**	outasm("cc"); **/
	outasm("L_");
	outudec(label);
}

/** 2 - Print specified number as label **/
/** printlabel(flab1);colon();nl();     **/

sa_mk_lbl(n) int n;
{
	outasm("L_");
	outudec(n);
	colon();
	nl();
}

/* Print specified number as label for stack */

ostklbl()
{	/**	outasm("cs");  **/
	outasm("AutoC");  /** auto constant **/
	outudec(litlab);
}

/* Test if given character is alpha */
/** including underscore **/

alpha(c) char c;
{
	c = c & 127;
	return (((c >= 'a') & (c <= 'z')) |
		((c >= 'A') & (c <= 'Z')) | (c == '_'));
}

/* Test if given character is numeric */

numeric(c) char c;
{
	c = c & 127;
	return((c >= '0') & (c <= '9'));
}

/* Test if given character is alphanumeric */
an(c) char c;
{
	return((alpha(c)) | (numeric(c)));
}

/* Print a carriage return and a string only to console */
pl(str) char *str;
{
	int k;

	k = 0;
	putchar(EOL);
	while (str[k]) putchar(str[k++]);
}

addwhile(ptr) int ptr[];
{
	int k;

	if (wsptr == WS_MAX)
		{
		error("too many active whiles");
		return;
		}
	k = 0;
	while (k < WS_SZ)
		{
		*wsptr++ = ptr[k++];
		}
}

delwhile()
{
	if (readwhile()) wsptr = wsptr-WS_SZ;
}

readwhile()
{
	if (wsptr == ws)
		{
		error("no active do/for/while/switch");
		return 0;
		}
	else	return (wsptr-WS_SZ);
}

/*** Additional Statement Support Routines ***/
/*****

findwhile ()
{
	int	*ptr;

	for (ptr = wsptr; ptr != ws;) {
		ptr = ptr - WSSIZ;
		if (ptr[WSTYP] != WSSWITCH)
			return (ptr);
	}
	error ("no active do/for/while");
	return (0);
}

readswitch ()
{
	int	*ptr;

	if (ptr = readwhile ())
		if (ptr[WSTYP] == WSSWITCH)
			return (ptr);
	return (0);
}

addcase (val)
int	val;
{
	int	lab;

	if (swstp == SWSTSZ)
		error ("too many case labels");
	else {
		swstcase[swstp] = val;
		swstlab[swstp++] = lab = getlabel ();
		printlabel (lab);
		col ();
		nl ();
	}
}
*****/
/***------***/

/** Note: the line[] and lptr are statics for the following **/
/**  tokenizing functions, inwhich line[] is for line buffered input **/
/** was chr(), -> inspect_chr() **/

inspect_chr()  /** inspect current chr, doesn't advance pointer **/
{
	return (line[lptr] & 127);
}

lookahead() /** lookahead, but doesn't advance ptr **/
{
	if (inspect_chr() == 0) return 0;
	else return (line[lptr+1] & 127);
}

 /** ret chr from linebuffer and advance ptr unless null chr **/
g_nxtchr()
{
	if (inspect_chr() == 0) return 0;
	else return (line[lptr++] & 127);
}

 /** reindex & null terminate input line **/
kill()
{
	lptr = 0;
	line[lptr] = 0;
}

 /** ck chr at line[lptr], if null & !eof_flg, get next line[] fill **/
 /** bridges line breaks, & preprocess stuff **/
scan_nxt()
{
	while (inspect_chr() == 0)
		{
		if (eof_flg) return 0;
		input_line();
		preprocess();
		}
	return g_nxtchr();
}

 /** ck line[] for null (EOL), if so, get next line, ret chr or null **/
 /** called only by preprocess() **/
inchar()
{
	if (inspect_chr() == 0) input_line();
	if (eof_flg) return 0;
	return (g_nxtchr());
}

 /** main input function, chrs accumulate into static line[], **/
 /** also echoes to file commentary tokens, if desired by user. **/
 /** a byte value > 7Fh (sign set) is read as eof in this function **/
 /** On return, line[] holds string of k's, where k is of the set **/
 /** of bytes {1..7Fh} with a null termination, 0. **/

input_line()
{
	int k, unit;

	while(1)
		{
		if (fp_input == 0) openin();
		if (eof_flg) return;
		if ((unit = fp_input2) == 0) unit = fp_input;
		kill();  /** clear line index **/

		while ((k = getc(unit)) > 0)  /** main fetch fn **/
			{
			if ((k == EOL) | (lptr >= LINEMAX)) break; /** chg >= to > **/
			line[lptr++] = k;	/** store input in static char array **/
			}	/** a null in stream will abort while **/

		line[lptr] = 0;	/* append null */
		lineno++;	/* read one more line	gtf 7/2/80 */

		if (k <= 0)  /** eof is - flag **/
			{
			fclose(unit);
			if (fp_input2) endinclude();	/* gtf 7/16/80 */
			else fp_input = 0;
			}
		if (lptr)	/** indicates something was read to process **/
			{	/** if flgs, echo to FILE as comment **/
			if ((ctext) & (cmode))
				{
				sa_comment();
				outstr(line); /** FILE output **/
				nl();
				}
			lptr = 0;	/** reindex for next time **/
			return;	/** -with line[] filled to process **/
			}
		}
}

/** EO C86N-3.C **/

/*	>>>>>> start of cc4 <<<<<<<	*/

/** macro line buffer used to hold temps also **/

keepch(c) char c;
{
	mline[mptr] = c;
	if (mptr < MP_MAX) mptr++;
	return c;
}

/** space or tab chr compression **/
/** quoted string handler **/
/** char constant handler **/
/** comments handler **/
/** macro substitution **/

preprocess()
{
	int k;
	char c, sname[NAMESIZE];

	if (cmode == 0) return; /** ck preprocess flg **/
	mptr = lptr = 0;        /** reset static ptrs **/
	while	(inspect_chr())
		{
		if ((inspect_chr() == ' ') | (inspect_chr() == 9))
			{  /** space or tab chr compression **/
			keepch(' '); /** keep one space, compact the rest **/
			while	((inspect_chr() == ' ') | (inspect_chr() == 9))
				g_nxtchr(); /** rets chr or null at line[lptr] **/
			}
		else	if (inspect_chr() == '"')
			{  /** quoted string into macro buffer **/
			keepch(inspect_chr()); /** cpy into mline **/
			g_nxtchr();
			while	(inspect_chr() != '"')
				{
				if (inspect_chr() == 0)
					{
					error("missing quote");
					break;
					}
				keepch(g_nxtchr());
				}
			g_nxtchr();
			keepch('"');  /** cpy into mline **/
			}
		else if (inspect_chr() == 39)
			{  /** 39d is single quote, apostrophe **/
			keepch(39);
			g_nxtchr();
			while	(inspect_chr() != 39)
				{
				if (inspect_chr() == 0)
					{
					error("missing apostrophe");
					break;
					}
				keepch(g_nxtchr());
				}
			g_nxtchr();
			keepch(39);  /** cpy into mline **/
			}
		else	if ((inspect_chr() == '/') & (lookahead() == '*'))
			{  /** comments, like this one **/
			inchar(); inchar();
			while	(((inspect_chr() == '*') & (lookahead() == '/')) == 0)
				{
				if (inspect_chr() == 0) input_line();
				else inchar();
				if (eof_flg) break;
				}
			inchar();inchar();
			}
		else	if (an(inspect_chr()))
			{  /** macro substitution by lookup is done here **/
			k = 0;
			while	(an(inspect_chr()))
				{  /** copy token **/
				if (k < NAMEMAX) sname[k++] = inspect_chr();
				g_nxtchr();  /** advance thru line[] **/
				}
			sname[k] = 0;  /** append null to extracted token **/
			if (k = findmac(sname))  /** token is macr defined **/
				while	(c = macq[k++]) keepch(c);  /** cpy into mline **/
			else	{  /** ordinary token is copied without substitution **/
				k = 0;
				while	(c = sname[k++]) keepch(c);  /** cpy into mline **/
				}
			}
		else keepch(g_nxtchr());  /** cpy into mline **/
		}
	keepch(0);  /** null terminate token placed into mline[] **/
	if (mptr >= MP_MAX) error("line too long");
	lptr = mptr = 0;
	while	(line[lptr++] = mline[mptr++]);  /** do the substitution **/
	lptr = 0;
}

addmac()
{
	char sname[NAMESIZE];
	int k;

	if (is_identifier(sname) == 0)
		{ /** is_identifier() gets & validates identifier **/
		illname();
		kill();
		return;
		}
	k = 0;
	while	(putmac(sname[k++]));
	while	(inspect_chr() == ' ' | inspect_chr() == 9) g_nxtchr();
	while	(putmac(g_nxtchr()));
	if (macptr >= MAC_MAX) error("macro table full");
	}

putmac(c) char c;
{
	macq[macptr] = c;
	if (macptr < MAC_MAX) macptr++;
	return c;
}

findmac(sname) char *sname;
{
	int k;

	k = 0;
	while	(k < macptr)
		{
		if(astreq(sname,macq+k,NAMEMAX))
			{
			while	(macq[k++]);
			return k;
			}
		while	(macq[k++]);
		while	(macq[k++]);
		}
	return 0;
}

/* direct output to console		gtf 7/16/80 */
toconsole()
{
	saveout = fp_output;
	fp_output = 0;
}  /* end toconsole */

/* direct output back to file		gtf 7/16/80 */
tofile()
{
	if(saveout) fp_output = saveout;
	saveout = 0;
}  /* end tofile */

foutput_chr(c) char c;	/** FILE output **/
{
	if (c == 0) return 0;
	if (fp_output)
		{	/** put to file, output **/
		if ((putc(c,fp_output)) <= 0)
			{
			closeout();
			error("Output file error");
			abort();		/* gtf 7/17/80 */
			}
		}
	else putchar(c);
	return c;
}

outstr(ptr) char ptr[];
 {
	int k;
	k = 0;
	while (foutput_chr(ptr[k++]));
 }

/* write text destined for the assembler to read */
/* (i.e. stuff not in comments)			*/
/*  gtf  6/26/80 */

outasm(ptr) char *ptr;
{
/**	while(foutput_chr(toupperi(*ptr++))); **/
	while	(foutput_chr(*ptr++));  /** don't UC quoted str **/
}  /* end outasm */

nl()	{ foutput_chr(EOL); }
tab()	{ foutput_chr(9); }
colon() { foutput_chr(58); }
bell()  { foutput_chr(7); }	/* gtf 7/16/80 */

/** Error Notification **/

error(ptr) char ptr[];
{
	int k;
	char junk[81];

	toconsole();
	bell();
	outstr("Line "); outdec(lineno); outstr(", ");
	if (infunc == 0)
		foutput_chr('(');
	if (currfn == NULL)
		outstr("start of file");
	else	outstr(currfn + NAME);
	if (infunc == 0)
		foutput_chr(')');
	outdec(lineno-fnstart);
	outstr(": ");  outstr(ptr);  nl();

	outstr(line); nl();

	k = 0;	/* skip to error position */
	while	(k < lptr)
		{
		if (line[k++] == 9) tab();
		else	foutput_chr(' ');
		}
	foutput_chr('^');  nl();
	++errcnt;

	if (errstop)
		{
		pl("Continue (Y,n,g) ? ");
		gets(junk);		
		k = junk[0];
		if ((k == 'N') | (k == 'n')) abort();
		if ((k == 'G') | (k == 'g')) errstop = 0;
		}
	tofile();
}	/* end error */

ol(ptr) char ptr[];
{
	ot(ptr);
	nl();
}

ot(ptr) char ptr[];
{
	tab();
	outasm(ptr);
}

/** returns zero if no match, otherwise > 0 = str length. **/
/** str2 is null terminated, which is the limit of comparing. **/
/** in effect, str2 is contained in str1. **/

streq(str1,str2) char str1[],str2[];
 {
	int k;

	k = 0;
	while (str2[k])
		{
		if ((str1[k]) != (str2[k])) return 0;
		k++;
		}
	return k;
 }

 /** alphanumeric string match, 0 is mismatch, else len **/
astreq(str1,str2,len) char str1[],str2[]; int len;
 {
	int k;
	k = 0;
	while (k < len)
		{
		if ((str1[k]) != (str2[k])) break;
		if (str1[k] == 0) break;
		if (str2[k] == 0) break;
		k++;
		}
	if (an(str1[k])) return 0; /** mismatch before eos **/
	if (an(str2[k])) return 0; /** mismatch before eos **/
	return k;
 }

match(lit) char *lit;
{
	int k;
	deblank();
	if (k = streq(line + lptr,lit))
		{ /** lit is null terminated, eos, for compare **/
		lptr = lptr + k;
		return 1;
		}
 	return 0;
}

amatch(lit,len) char *lit; int len;
 {
	int k;
	deblank();
	if (k = astreq(line + lptr,lit,len))
		{
		lptr = lptr + k;
		while	(an(inspect_chr())) scan_nxt();
		return 1;
		}
	return 0;
 }

/* Note: added filter of CR for filesystems where NL is CR,LF.
** The parsing strategy is to make each \n into a null, so
** each line is a null terminated string.  This routine scans
** thru the line buffer removing leading space, tab, CR, and
** requests new string if a null is inlined.
*/
deblank()
{
	int a;

	a = 1;
	while (a == 1)
		{
		while (inspect_chr()==0)
			{
			input_line();
			preprocess();  /** calls input_line, so? **/
			if (eof_flg) break;
			}
		if (inspect_chr() == ' ') g_nxtchr();
		else if (inspect_chr() == 9) g_nxtchr();
		else if (inspect_chr() == CR) g_nxtchr();
		else return;
		}
}

/* Output a signed number to the ASM file. */

outdec(number) int number;
 {
	int k, zs;
	char c;

	zs = 0;
	k = 10000;
	if (number<0)
		{number=(-number);
		foutput_chr('-');
		}
	else
		foutput_chr('+');
	while (k>=1)
		{
		c=number/k + '0';
		if ((c!='0')|(k==1)|(zs))
			{zs=1;foutput_chr(c);}
		number=number%k;
		k=k/10;
		}
 }


/* Output an unsigned number to ASM file. */

outudec(number) int number;
{
	int k,zs;
	char c;

	zs = 0;
	k = 10000;
	if (number<0)
		number = (-number);
	while (k >= 1)
		{
		c = number / k + '0';
		if ((c != '0') | (k == 1) | (zs))
			{
			zs = 1;
			foutput_chr(c);
			}
		number = number % k;
		k = k / 10;
		}
}		/** eo outudec **/


/* return the length of a string */
/* gtf 4/8/80 */

strlen(s) char *s;
{
	char *t;

	t = s;
	while (*s) s++;
	return(s-t);
}	/* end strlen */

/* convert lower case to upper */
/* gtf 6/26/80 */
/** chgd from raise() -> toupperi() - i for internal fn **/

toupperi(c) char c;
{
	if ((c >= 'a') & (c <= 'z'))
		c = c - 'a' + 'A';
	return(c);
}	/* end toupperi */

/** EO C86N-4.C **/

/*	>>>>>>> start of cc5 <<<<<<<	*/
/** higher precedence operators are acted on first, **/
/** tho the flow control enters at the lowest precedence, **/
/** the lower precedence is acted on upon return from **/
/** higher precedence ascent. **/

	/* - 3 element evaluation array of ints -
	** eval[0] = Symbol table address, else 0 for constant
	** eval[1] = type indirect object to fetch, else 0 for
        	     static object (const.)
	** eval[2] = type pointer or array, else 0
	*/

/** expression(Y..N) loop if comma operator is allowed in expr **/
/** comma is lowest precedence operator in C and acted on last **/
/** comma, precedence level 15 **/
/** vers_2 expression for comma'd expression **/
/** caller- expr2(NO); or expr2(YES); for comma'd expr. **/
/** identifiers with sa_ or _sa are codegen functions, i.e., **/
/** syntactic actions to output backend code, generically **/
/** patterned after stack machine operations. **/

expression(comma) int comma;
{  /** precedence level 15 **/
	int eval[3];

/** was: if (heir1(eval))  rq_val_sa(eval); **/
	do {
	if (heir1(eval))  rq_val_sa(eval);
	if (comma == 0)  return;
	} while (match(","));
}

/** assignments, precedence level 14 **/
/** {=} of {=,+=,-=,/=,*=,%=,<<=,>>=,&=,^=,|=} **/

heir1(eval) int eval[];
{
	int k, eval2[3];

	k = heir1a(eval); /** link to heir2->heir1a here **/

	if (match("="))
		{
		if (k == 0)
			{
			needlval();
			return 0;
			}
		if (eval[1])  sa_push();  /** syntatic action **/
		if (heir1(eval2))  rq_val_sa(eval2);
		sa_store(eval);
		return 0;
		}
	else return k;
}

/*** install levels 13 (?:), 12 (||), 11 (&&) here ***/

/** (?:), precedence level 13 **/
/** conditional operator, ternary, takes three expressions **/
/** cond_expr ::= expr ? expr : expr **/

heir1a (eval) int eval[];
{
	int	k, eval2[3], T_lbl, F_lbl, X_lbl;

	k = heir1b(eval);
	deblank();

	if (streq(line+lptr,"?") == 0) return(k);

	if (k) rq_val_sa(eval);

	while (1)
		{
		if (match ("?"))
			{
			T_lbl = getlabel();
			F_lbl = getlabel();
			X_lbl = getlabel();
			sa_if_tst(T_lbl,F_lbl);

			sa_mk_lbl(T_lbl);
				/** expression evaluation, higher precedence **/
			if (heir1b (eval2)) rq_val_sa(eval2);

			sa_jump(X_lbl);

			deblank();

			if (match (":") == 0)
				{
				error ("missing colon");
				return (0);
				}
		/** colon matched, do expr3 **/
			sa_mk_lbl(F_lbl);
				/** expression evaluation, higher precedence **/
			if (heir1b (eval2)) rq_val_sa(eval2);


			sa_mk_lbl(X_lbl);
			}
		else	return (0);
		}
}


/** (||), precedence level 12 - either, both, true yields true. **/

heir1b (eval) int eval[];
{
	int k, eval2[3], t_lbl, flab1;

	k = heir1c(eval);

	deblank();
	if (streq(line+lptr,"||") == 0) return(k);

	if (k) rq_val_sa(eval);

	while (1)
		if (match ("||"))
			{
			sa_mk_bool();	/** prim reg -> bool **/
			sa_push();
				/** expression evaluation, higher precedence **/
			if (heir1c (eval2)) rq_val_sa(eval2);

			sa_mk_bool();	/** prim reg -> bool **/
			sa_pop();  /* Pop into the secondary register */
			sa_or();
			}
		else	return (0);
}

/** (&&), precedence level 11 - both true yields true **/

heir1c (eval) int eval[];
{
	int k, eval2[3], t_lbl, flab1;

	k = heir2(eval);

	deblank();
	if (streq(line+lptr,"&&") == 0) return(k);

	if (k) rq_val_sa(eval);

	while (1)
		if (match ("&&"))
			{
			sa_mk_bool();	/** prim reg -> bool **/
			sa_push();
				/** expression evaluation, higher precedence **/
			if (heir2 (eval2)) rq_val_sa(eval2);

			sa_mk_bool();	/** prim reg -> bool **/
			sa_pop();  /* Pop into the secondary register */
			sa_and();
			}
		else	return (0);
}

/** bitwise inclusive OR, precedence level 10 **/

heir2(eval) int eval[];
{
	int k, eval2[3];

	k = heir3(eval);

	deblank();
	if (inspect_chr() != '|') return k;

	/** added '||' ck for heir1b **/
	if (streq(line+lptr,"||") != 0) return(k);

	if (k)  rq_val_sa(eval);
	while	(1)
		{
		if (match("|"))
			{
			sa_push();  /** syntatic action **/
			if (heir3(eval2)) rq_val_sa(eval2);
			sa_pop();   /** syntatic action **/
			sa_or();    /** syntatic action **/
			}
		else return 0;
		}
}

/** bitwise exclusive OR, precedence level 9 **/

heir3(eval) int eval[];
{
	int k, eval2[3];

	k = heir4(eval);

	deblank();
	if (inspect_chr() != '^') return k;

	if (k)  rq_val_sa(eval);
	while	(1)
		{
		if (match("^"))
			{
			sa_push();  /** syntatic action **/
			if (heir4(eval2)) rq_val_sa(eval2);
			sa_pop();   /** syntatic action **/
			sa_xor();   /** syntatic action **/
			}
		else return 0;
		}
}

/** bitwise AND, precedence level 8 **/

heir4(eval) int eval[];
{
	int k, eval2[3];

	k = heir5(eval);

	deblank();
	if (inspect_chr() != '&') return k;

	/** added '&&' ck for heir1c **/
	if (streq(line+lptr,"&&") != 0) return(k);

	if (k) rq_val_sa(eval);
	while (1)
		{
		if (match("&"))
			{
			sa_push();
			if (heir5(eval2))  rq_val_sa(eval2);
			sa_pop();
			sa_and();
			}
		else return 0;
		}
}

/** equality operator; (T..F) equivalence, precedence level 7.1 **/
/** equality operator; not_equal, precedence level 7.2 **/

heir5(eval) int eval[];
{
	int k, eval2[3];

	k = heir6(eval);

	deblank();
	if ((streq(line+lptr,"==") == 0) &
		(streq(line+lptr,"!=") == 0))  return k;

	if (k)  rq_val_sa(eval);
	while (1)
		{
		if (match("=="))
			{
			sa_push();
			if (heir6(eval2))  rq_val_sa(eval2);
			sa_pop();
			sa_eq();
			}
		else if (match("!="))
			{
			sa_push();
			if (heir6(eval2))  rq_val_sa(eval2);
			sa_pop();
			sa_not_equal();
			}
		else return 0;
		}
}

/** relational operator; less than, <, precedence level 6.1 **/
/** relational operator; less than or eq, <=, precedence level 6.2 **/
/** relational operator; greater than or eq, >=, precedence level 6.3 **/
/** relational operator; greater than, >, precedence level 6.4 **/

heir6(eval) int eval[];
{
	int k, eval2[3];

	k = heir7(eval);

	deblank();
	if ((streq(line+lptr,"<") == 0) &
		(streq(line+lptr,">") == 0) &
		(streq(line+lptr,"<=") == 0) &
		(streq(line+lptr,">=") == 0))  return k;

	if (streq(line+lptr,">>"))  return k;
	if (streq(line+lptr,"<<"))  return k;

	if (k) rq_val_sa(eval);

	while (1)
		{
		if (match("<="))
			{
			sa_push();
			if (heir7(eval2))  rq_val_sa(eval2);
			sa_pop();
			if (eval[2] | eval2[2])
				{
				sa_uless_oreq();
				continue;
				}
			sa_sless_or_eq();
			}
		else if (match(">="))
			{
			sa_push();
			if (heir7(eval2))  rq_val_sa(eval2);
			sa_pop();
			if (eval[2] | eval2[2])
				{
				sa_uge();
				continue;
				}
			sa_sge();
			}
		else if ((streq(line+lptr,"<")) &
				(streq(line+lptr,"<<") == 0))
			{
			scan_nxt();
			sa_push();
			if (heir7(eval2))  rq_val_sa(eval2);
			sa_pop();
			if (eval[2] | eval2[2])
				{
				sa_uless_than();
				continue;
				}
			sa_sless_than();
			}
		else if ((streq(line+lptr,">")) &
				(streq(line+lptr,">>") == 0))
			{
			scan_nxt();
			sa_push();
			if (heir7(eval2))  rq_val_sa(eval2);
			sa_pop();
			if (eval[2] | eval2[2])
				{
				sa_ugt();
				continue;
				}
			sa_sgreater_than();
			}
		else return 0;
		}
}

/** EO C86N-5.C **/

/*	>>>>>> start of cc6 <<<<<<	*/
/** shift operator; left shift, <<, precedence level 5.1 **/
/** shift operator; right shift, >>, precedence level 5.2 **/
 /* Arithmetic left shift the secondary register by the */
 /*  count in the primary. (results in primary) */

heir7(eval) int eval;
{
	int k, eval2[3];

	k = heir8(eval);

	deblank();
	if ((streq(line+lptr,">>") == 0) &
		(streq(line+lptr,"<<") == 0))  return k;

	if (k)  rq_val_sa(eval);
	while (1)
		{
		if (match(">>"))
			{
			sa_push();
			if (heir8(eval2))  rq_val_sa(eval2);
			sa_pop();
			sa_asr();
			}
		else if (match("<<"))
			{
			sa_push();
			if (heir8(eval2))  rq_val_sa(eval2);
			sa_pop();
			sa_asl();
			}
		else return 0;
		}
}

/** binary arithmetic operator; add, +, precedence level 4.1 **/
/** binary arithmetic operator; subtract, -, precedence level 4.2 **/

heir8(eval) int eval[];
{
	int k, eval2[3];

	k = heir9(eval);

	deblank();
	if ((inspect_chr() != '+') & (inspect_chr() != '-'))  return k;

	if (k)  rq_val_sa(eval);
	while (1)
		{
		if (match("+"))
			{
			sa_push();
			if (heir9(eval2))  rq_val_sa(eval2);
			if (dbltest(eval,eval2))
				sa_doublereg();
			sa_pop();
			if (dbltest(eval2,eval))
				{
				sa_swap();
				sa_doublereg();
				sa_swap();
				}
			sa_add();
			result(eval,eval2);
			}
		else if (match("-"))
			{
			sa_push();
			if (heir9(eval2))  rq_val_sa(eval2);
			if (dbltest(eval,eval2)) sa_doublereg();
			sa_pop();

			if (dbltest(eval2,eval))
				{
				sa_swap();
				sa_doublereg();
				sa_swap();
				}
			sa_sub();
			if ((eval[2] == CINT) & (eval2[2] == CINT))
				{
				sa_swap();
				sa_immed();
				ol("1");
				sa_asr();  /** div by 2 **/
				}
			result(eval,eval2);
			}
		else return 0;
		}
}

/** binary arithmetic operator; multiply, *, precedence level 3.1 **/
/** binary arithmetic operator; divide, /, precedence level 3.2 **/
/** binary arithmetic operator; modulo, %, precedence level 3.3 **/

heir9(eval) int eval[];
{
	int k, eval2[3];

	k = heir10(eval);

	deblank();
	if ((inspect_chr() != '*') & (inspect_chr() != '/') &
		(inspect_chr() != '%'))  return k;

	if (k)  rq_val_sa(eval);
	while (1)
		{
		if (match("*"))
			{
			sa_push();			/** Push Primary Reg. **/
			if (heir9(eval2))  rq_val_sa(eval2);
			sa_pop();			/** Pop into Secondary Reg. **/
			sa_mult();
			}
		else if (match("/"))
			{
			sa_push();
			if (heir10(eval2))  rq_val_sa(eval2);
			sa_pop();
			sa_div();
			}
		else if (match("%"))
			{
			sa_push();
			if (heir10(eval2))  rq_val_sa(eval2);
			sa_pop();
			sa_modulo();
			}
		else return 0;
		}
}

/** unary operator; increment, ++, precedence level 2.7 **/
/** unary operator; decrement, --, precedence level 2.8 **/
/** unary operator; minus, -, precedence level 2.3 **/
/** unary operator; indirection, *, precedence level 2.5 **/
/** unary operator; address of, &, precedence level 2.6 **/
/** unary operator; logical not, !, precedence level 2.1 **/
/** unary operator; bitwise one's complement, ~, precedence level 2.2 **/
/** TBI, ~, sizeof, cast (typename)expr **/

heir10(eval) int eval[];
{
	int k;
	char *ptr;

	if (match("++"))
		{
		if ((k = heir10(eval)) == 0)
			{
			needlval();
			return 0;
			}

		if (eval[1])  sa_push();
		rq_val_sa(eval);
		sa_inc();
		if (eval[2] == CINT)  sa_inc();
		sa_store(eval);
		return 0;
		}

	else if (match("--"))
		{
		if ((k = heir10(eval)) == 0)
			{
			needlval();
			return 0;
			}

		if (eval[1])  sa_push();
		rq_val_sa(eval);
		sa_dec();
		if (eval[2] == CINT)  sa_dec();
		sa_store(eval);
		return 0;
		}

	else if (match("-"))
		{
		k = heir10(eval);

		if (k) rq_val_sa(eval);
		sa_neg();              /** two's complement **/
		return 0;
		}

/** bitwise complement, one's complement, bit flip **/
	else if (match("~"))
		{
		k = heir10(eval);

		if (k) rq_val_sa(eval);
		sa_not();
		return 0;
		}

/** boolean logical negate, 0->1, >0->0 **/
	else if (match("!"))
		{
		k = heir10(eval);

		if (k) rq_val_sa(eval);
		sa_mk_nbool();	/** prim reg -> not (bool) **/
		return 0;
		}

	else if (match("*"))
		{
		k = heir10(eval);

		if (k) rq_val_sa(eval);
		if (ptr = eval[0]) eval[1] = ptr[TYPE];
		else 	eval[1] = CINT;
		eval[2] = 0; /*flag as not ptr or array*/
		return 1;
		}

	else	if (match("&"))
		{
		k = heir10(eval);

		if (k == 0)
			{
			error("illegal address");
			return 0;
			}
		ptr = eval[0];
		eval[2] = ptr[TYPE];
		if (eval[1]) return 0;

		/* global & non-array */
		sa_immedo();  /* global & non-array & function */
		outstr(ptr);
		nl();
		eval[1] = ptr[TYPE];
		return 0;
		}
	else 
		{  /** for recursive non-match of above unary ops **/
		k = heir11(eval);

		if (match("++"))
			{
			if (k == 0)
				{
				needlval();
				return 0;
				}
			if (eval[1])  sa_push();
			rq_val_sa(eval);
			sa_inc();
			if (eval[2] == CINT) sa_inc();
			sa_store(eval);
			sa_dec();
			if (eval[2] == CINT) sa_dec();
			return 0;
			}
		else	if (match("--"))
			{
			if (k == 0)
				{
				needlval();
				return 0;
				}
			if (eval[1])  sa_push();
			rq_val_sa(eval);
			sa_dec();
			if (eval[2] == CINT)  sa_dec();
			sa_store(eval);
			sa_inc();
			if (eval[2] == CINT)  sa_inc();
			return 0;
			}
		else return k;
		}
}

/** EO C86N-6.C **/
/*	>>>>>> start of cc7 <<<<<<	*/

/** primary operator; function parenthesis, (), precedence level 1.1 **/
/** primary op; subscripting square brakets, [], precedence level 1.2 **/
/** primary operator; member access, ->, precedence level 1.3 **/
/** primary operator; member access, ., precedence level 1.4 **/

heir11(eval) int *eval;
{
	int k; char *ptr;

	k = primary(eval);

	ptr = eval[0];  /** address of symbol in symb_tbl **/
	deblank();
	if ((inspect_chr() == '[') | (inspect_chr() == '('))
	while (1)
		{
		if (match("["))
			{
			if (ptr == 0)
				{
				error("can't subscript");
				junk();
				needbrack("]");
				return 0;
				}
			else if (ptr[IDENT] == POINTER)  rq_val_sa(eval);
			else if (ptr[IDENT] != ARRAY)
				{
				error("can't subscript");
				k = 0;
				}
			sa_push();
			expression(YES);
			needbrack("]");

			if (ptr[TYPE] == CINT)  sa_doublereg();
			sa_pop();
			sa_add();
			eval[0] = eval[2] = 0;
			eval[1] = ptr[TYPE];
			k = 1;
			}
		else if (match("("))
			{
			if (ptr == 0)
				{
				callfunction(0);
				}
			else if (ptr[IDENT] != FUNCTION)
				{
				rq_val_sa(eval);
				callfunction(0);
				}
			else callfunction(ptr);
			k = eval[0] = 0;
			}
		else return k;
		}
	if (ptr == 0)  return k;
	if (ptr[IDENT] == FUNCTION)
		{
		sa_immedo();  /* global & non-array & function */
		asm_symb(ptr);
		nl();
		return 0;
		}
	return k;
}

/** primary is called when an expression is expected, it is **/
/** the highest precedence level, it is acted on first. **/
/** **/

primary(eval) int *eval;
{
	char *ptr, sname[NAMESIZE]; /** auto symb array **/
	int num[1], k;

	eval[2] = 0;	/* Clear ptr/array type. */
	if (match("("))  /** parenthesized expression **/
		{
		k = heir1(eval); /** recursive call to ck for rvalue **/
		needbrack(")");
		return k;
		}

		/** is_identifier() gets & validates identifier **/
	if (is_identifier(sname))
		{
		if (ptr = findauto(sname))  /** srch auto tbl 1st **/
			{
			sa_deref(ptr);  /** code gen fn, syntatic action **/
					/** get stk relative addr of auto var **/
			 /** set eval[] according to auto identifier **/
			eval[0] = ptr;
			eval[1] = ptr[TYPE];
			if (ptr[IDENT] == POINTER)
				{
				eval[1] = CINT;
				eval[2] = ptr[TYPE];
				}
			if (ptr[IDENT] == ARRAY)
				{
				eval[2] = ptr[TYPE];
				return 0;
				}
			else return 1; /** auto VARIABLE, or auto POINTER **/
			 /** ! auto ARRAY or FUNCTION **/
			 /** fn()'s are external static by definition. **/
			 /** so the IDENT is a auto; VARIABLE or POINTER **/
			}

		if (ptr = findstatic(sname))  /** srch static tbl 2nd **/
			if (ptr[IDENT] != FUNCTION)
				{ /** set eval[] according to static identifier **/
				eval[0] = ptr;  /** ptr to symb in tbl **/
				eval[1] = 0;
				if (ptr[IDENT] != ARRAY)
					{
					if (ptr[IDENT] == POINTER)
						eval[2] = ptr[TYPE];
					return 1;
					}
				 /** .else. array & !function */
				sa_immedo();
				asm_symb(ptr); nl();
				eval[1] = eval[2] = ptr[TYPE];
				return 0;
				}

	/** not found in auto tbl, not in static tbl, **/
	/** so add the unknown identifier as a static function, **/
	/** variables are declared symbols, already (elsewhere) **/
	/** parsed & entered into the auto or static symbol tables. **/
	/** The defaults for undeclared functions are setup now. **/

		ptr = addstatic(sname,FUNCTION,CINT,0);
		eval[0] = ptr;  /** address of its entry in symb tbl **/
		eval[1] = 0;    /** functions are static objects **/
		return 0;       /** FALSE, not an expression **/
		}	/** eo if (is_identifier(sname)) **/

	if (kind_const(num))  return (eval[0] = eval[1] = 0);

	else	{
		error("invalid expression");
		sa_immed(); outdec(0); nl();
		junk();
		return 0;
		}
} /** eo primary **/

	/* - 3 element evaluation array of ints -
	** eval[0] = Symbol table address, else 0 for constant
	** eval[1] = type indirect object to fetch, else 0 for
        	     static object (or const.)
	** eval[2] = type pointer or array, else 0
	*/

sa_store(eval) int *eval;
{
	if (eval[1] == 0) sa_putmem(eval[0]); /** is const **/
	else sa_putstk(eval[1]);
}

/** eval[1] holds typeobj, char or int, 0 for const. **/
/** This is to Retrieve Value, from auto or static **/
/** Syntactic Action for Dereferencing Symbol Value **/
/** Ren rvalue -> rq_val_sa                         **/

rq_val_sa(eval) int *eval;
{	/** not a const & indirect obj **/
	if ((eval[0] != 0) & (eval[1] == 0))
		sa_getmem(eval[0]); /** gen syntactic action **/
	else  /** const or static **/
		sa_indirect(eval[1]); /** gen syntactic action **/
}

	/*
	** true if val1 -> int pointer or int array and
	** val2 not ptr or array
	*/

dbltest(val1,val2) int val1[], val2[];
{
	if (val1[2] != CINT) return 0;
	if (val2[2]) return 0;
	return 1;
}
	/* - 3 element evaluation array of ints -
	** eval[0] = Symbol table address, else 0 for constant
	** eval[1] = type indirect object to fetch, else 0 for
	       	     static object (const.)
	** eval[2] = type pointer or array, else 0
	*/

/*** determine type of binary operation ***/

result(eval,eval2) int eval[], eval2[];
{
	if (eval[2] & eval2[2])	/*both are type ptr or array.*/
		{
		eval[2] = 0;
		}
	else	if (eval2[2])	/*eval2 is type ptr or array. */
		{
		eval[0] = eval2[0];
		eval[1] = eval2[1];
		eval[2] = eval2[2];
		}
}

/** boolean conditional test - jmp - if (t) **/
/** !superceded! **/
/**** logical_test(label) int label;
{
	needbrack("(");
	expression();
	needbrack(")");
	sa_tst_jump(label); ** gen syntactic action **
}  ****/

/** Ver_2 boolean conditional test - jmp - if (tf) **/
/**** -- abandoned --
logical_tst2(label,tf) int label, tf;
{
	needbrack("(");
	expression();      ** ref expr2(YES); for comma'd **
	needbrack(")");
	sa_tst2_jmp(label,tf); ** gen syntactic action **
}  ****/

logic_tst(t_lbl,flab1) int t_lbl, flab1;
{
	needbrack("(");
	expression(YES);
	needbrack(")");
	sa_if_tst(t_lbl,flab1);
}

/** new, for DO **/
logic_do_tst(t_lbl,flab1) int t_lbl, flab1;
{
	needbrack("(");
	expression(YES);
	needbrack(")");
	sa_do_tst(t_lbl,flab1); /** true label, false=exit label **/
}

kind_const(val) int val[];  /** parameter is a ptr, *val **/
{
	if (number(val))  sa_immed();
	else if (chr_const(val))  sa_immed();
	else if (str_const(val))
		{
		sa_immedo();  /* global & non-array & function */
		printlabel(litlab);
		}
	else return 0;	
	outdec(val[0]);
	nl();
	return 1;
}

number(val) int val[];
{
	int k, minus; char c;

	k = minus = 1;
	while (k)
		{
		k = 0;
		if (match("+")) k=1;
		if (match("-"))
			{
			minus = (-minus);
			k = 1;
			}
		}

	if (numeric(inspect_chr()) == 0) return 0;
	while (numeric(inspect_chr()))
		{
		c = scan_nxt();
		k = k * 10 + (c - '0');
		}
	if (minus < 0)  k =(-k);
	val[0] = k;
	return 1;
}

chr_const(val) int val[];
{
	int k; char c;

	k = 0;
	if (match("'") == 0) return 0;
	while ((c = g_nxtchr()) != 39)  /** 39 is single quote **/
		k = (k & 255) * 256 + (c & 127);
	val[0] = k;
	return 1;
}

str_const(val) int val[];
{  /** quoted string entered into Literal Str Table **/
	char c;

	if (match(quote) == 0) return 0;
	val[0] = litptr;
	while (inspect_chr() != '"')
		{
		if (inspect_chr() == 0) break;
		if (litptr >= LITMAX)
			{  /** cleanup literal error **/
			error("string space exhausted");
			while (match(quote) == 0)
				if (g_nxtchr() == 0) break;
			return 1;
			}
		litq[litptr++] = g_nxtchr(); /** cpy to literal tbl **/
		}
	g_nxtchr();
	litq[litptr++] = 0; /** null terminate str **/
	return 1;
}  /** quoted str entered into Literals Table **/

/** EO C86N-7.C **/

/*	>>>>>> start of cc8 <<<<<<<	*/

/* Begin a comment line for the assembler */
sa_comment()
{
	foutput_chr(';');
}

/* Put out assembler info before any code is generated */
header()
{
	/** sa_comment();nl(); **/
	if(mainflg){		/* do stuff needed for first */
		ol(";; ----===*******===----");
		ol("%INCLUDE 'PROLOG.NSM' "); /** NASM form **/ 
		outstr(";; --== NASM vers. 26-Mar-2010 ==--"); nl();
		ol(";; ***---- Program Body ----***");
		ol("  [SECTION .text]");
		}
}

/* Print any assembler stuff needed after all code */

trailer()
{
	nl();	/* 6 May 80 rj errorsummary() now goes to console */
	ol("%INCLUDE 'EPILOG.NSM' "); /** NASM form **/              
	sa_comment();
	outstr(" --- End of Compilation ---");
	nl();
}

/* Continue code segment stuff. */
sa_cseg()
{
	nl();
	ol("  [SECTION .text]"); /* Start Code Segment from last point. */              
}

/* Continue data segment stuff. */
sa_dseg()
{
	nl();
	ol("  [SECTION .data]"); /* Start Data Segment from last point. */              
}

/* Function initialization. */
FN_Prolog()
{
	ol("PUSH EBP");		/*Save old frame ptr.*/
	ot("SUB  ESP, ");	/*Adjust stack beyond new frame.*/
	ostklbl();
	nl();
	ol("MOV  EBP, ESP");	/*Get new frame ptr.*/
	nl();
}

/* Function termination. */
FN_Epilog()
{
	nl();
	ostklbl();		/*Generate frame size.*/
	ot("EQU ");
	outudec(Msp);
	nl();
}

/* Print out a name such that it won't annoy the assembler */
/*	(by matching anything reserved, like opcodes.) */
/*	gtf 4/7/80 */
/** chgd outname() -> asm_symb(), removed leading "cz" **/
/** removed toupperi, nasm is case sensitive. **/

/* CHG(a).. Sun 14 Aug 2011 02:44:41 PM CDT added back leading chr
** to symbols generated for nasm so that the io_clib extern labels
** are not duplicates. ie..
** CHG: fclose(); -> fclose: -> call fclose ;extern clib_fn
** TO:  fclose(); -> _fclose: -> call fclose ;extern clib_fn
*/

asm_symb(sname) char *sname;
{
	int len, i, j;

	/** outasm("cz"); **/
	outasm("_");		/** CHG(a) **/
	len = strlen(sname);
	if (len > (asmpref+asmsuff))
		{
		i = asmpref;
		len = len - asmpref - asmsuff;
		while (i-- > 0)  /** no case conversion version **/
			foutput_chr(*sname++);
		while (len-- > 0)
			sname++;
		while (*sname)
			foutput_chr(*sname++);

	/****	while(i-- > 0)
			foutput_chr(toupperi(*sname++));
		while(len-- > 0)
			sname++;
		while(*sname)
			foutput_chr(toupperi(*sname++)); ****/
		}
	else	outasm(sname);
} /* end asm_symb */

/* Fetch a static memory cell into the primary register */
sa_getmem(sym) char *sym;
{
	if ((sym[IDENT] != POINTER) & (sym[TYPE] == CCHAR))
		{
		ot("MOV  AL, [Byte ");
		asm_symb(sym+NAME);
	/**	ot("]"); **/
		outasm("]");
		nl();
		ol("CBW");
		ol("MOV  EBX, EAX");
		nl();
		}
	else
		{
		ot("MOV  EBX, [DWord ");
		asm_symb(sym+NAME);
	/**	ot("]"); **/
		outasm("]");
		nl();
		}
}

/* Fetch the stack relative address of the specified automatic symbol */
/*	into the primary register */

sa_deref(sym) char *sym;
{
	ot("LEA  EBX, [");
	ostklbl();
	outdec(	(sym[OFFSET] & 255) + 
		((sym[OFFSET+1] & 255) << 8) +
		((sym[OFFSET+2] & 255) << 16) +
		((sym[OFFSET+3] & 255) << 24) );

	outasm("+EBP]");
	nl();
}

/* Store the primary register into the specified */
/* static memory cell. */

sa_putmem(sym) char *sym;
{
	if ((sym[IDENT] != POINTER) & (sym[TYPE] == CCHAR))
		{
		ot("MOV  Byte [");
		asm_symb(sym+NAME);
	/**	ot("], BL");  **/
		outasm("], BL");
		nl();
		}
	else
		{
		ot("MOV  DWord [");
		asm_symb(sym+NAME);
	/**	ot("], BX");  **/
		outasm("], EBX");
		nl();
		}
}

/* Store the specified object type in the primary register */
/* at the address on the top of the stack. */
/** presumes DS:EDI is address of target **/

sa_putstk(typeobj) char typeobj;
{
	ol("POP  EDI");
	Csp = Csp + INT_SZ;
	if (typeobj == CCHAR)
	   ol("MOV  Byte [EDI], BL");
	else
	   ol("MOV  DWord [EDI], EBX");
}

/* Fetch the specified object type indirect through the */
/*	primary register into the primary register */
/** called as: indirect(eval[1], eval[0]);  **/
/** these are auto class on stack **/
/*** reverted, problem with array[0] is DS relative ***/

sa_indirect(typeobj) char typeobj;
{
	if (typeobj == CCHAR)
		{
	/**	ol("MOV  AL, [SS:BX]"); **/
		ol("MOV  AL, [EBX]");
		ol("CBW");
		ol("MOV  EBX, EAX");
		}
/**	else  ol("MOV  BX, [SS:BX]"); **/
	else  ol("MOV  EBX, [EBX]");
}

/* Swap the primary and secondary registers */

sa_swap()
{
	ol("XCHG EBX, EDX");
}

/* Print partial instruction to get an immediate value */
/*	into the primary register */

sa_immed()
{
	ot("MOV  EBX, ");
}

/* Print partial instruction to get an immediate value */
/*	into the primary register */
/* global & non-array & function */

sa_immedo()
{
	ot("MOV  EBX, ");
}

/* Push the primary register onto the stack */

sa_push()
{
	ol("PUSH EBX");
	Csp = Csp - INT_SZ;
}

/* Pop the top of the stack into the secondary register */

sa_pop()
{
	ol("POP  EDX");
	Csp = Csp + INT_SZ;
}

/* Swap the primary register and the top of the stack */
/** ck for DS dependency - note, EA can use SS: vs default DS: **/
/*** reverted, problem with array[0] is DS relative ***/

sa_swapstk()
{
	ol("MOV  EDI, ESP");
	ol("XCHG EBX, [EDI]"); /** small memory model dependent **/
/**	ol("XCHG BX, [SS:EDI]");  ** mem model independent **/
}

/** EO C86N-8.C **/
/*	>>>>>> start of cc9 <<<<<<<	*/

/* Call the specified subroutine name */

sa_call(sname) char *sname;
{
	ot("CALL ");
	asm_symb(sname);
	nl();
}

/* Call a run-time library routine */

sa_callrts(sname) char *sname;
{
	ot("CALL ");
	outasm(sname);
	nl();
}  /*end callrts*/

/* Return from subroutine */

sa_ret()
{
	ol("RET");
}

/* Perform subroutine call to addr on top of stack */
/*** reverted, problem with array[0] is DS relative ***/

sa_callstk()
{		/** new vers **/
	ol("POP  EBX");		/** TOS holds pointer to target **/
	ol("CALL EBX");

/** old version..
	sa_immed();
	outasm("( $+10)");
	nl();
	ol("MOV  EDI, ESP");
	ol("XCHG EBX, [EDI]"); ** small memory model dependent **
*-*	ol("XCHG BX, [SS:EDI]"); ** mem model independent *-*
	ol("JMP  EBX");		**/

	Csp=Csp-INT_SZ;
	}

/* Jump to specified internal label number */

sa_jump(label) int label;
{
	ot("JMP  ");
	printlabel(label);
	nl();
}

/* Test the primary register and jump if false to label */
/** testjump()->sa_tst_jump() **/
/** caller - logical_test(label); - superceded **/
/**** sa_tst_jump(label) int label;
{
	ol("OR   EBX, EBX");
	ol("JNZ  $+5");
	ot("JMP  ");
	printlabel(label);
	nl();
}  ****/

/* ver_2 - Test the primary register and jump if false to label */
/** the supplied condition, tf, dictates which form to codegen **/
/**** caller - logical_tst2(label,tf); !abandoned! --
sa_tst2_jmp(label, tf) int label, tf;
{
	ol("OR   EBX,EBX");
	if (tf)  ot("JNZ  ");
	else     ot("JZ   ");
	printlabel(label);
	nl();
}  ****/

/** ver_3 **/
sa_if_tst(t_lbl,flab1) int t_lbl, flab1;
{
	ol("OR   EBX, EBX");
	ot("JNZ  ");
	printlabel(t_lbl);
	nl();
	ot("JMP  ");
	printlabel(flab1);
	nl();
}

sa_do_tst(t_lbl,flab1) int t_lbl, flab1;
{  /** do .. while specific **/
	ol("OR   EBX, EBX");
	ot("JNZ  ");
	printlabel(t_lbl);
	nl();
	ot("JMP  ");
	printlabel(flab1);
	nl();
	sa_mk_lbl(t_lbl);	/** codegen true branch label here **/
}

/** Added, Modified for NASM, caller dumpstatics() **/

def_sizein()
{
	ot("TIMES "); /**ot("DS ");**/
}

/*Print pseudo-op to define storage (Character). */
/** caller dumpstatics() **/

defstorchr()
{
	ot("DB 0"); /** RB **/
}

/*Print pseudo-op to define storage (Integer). */
/** caller dumpstatics() **/
/*
** chg to DD
*/

defstorint()
{
	ot("DD 0"); /** RW **/
}

/*Print pseudo-op to define storage (Pointer). */
/** caller dumpstatics() **/
/*
** -chg- to DD
*/

defstorptr()
{
	ot("DD 0"); /** RW **/
}

/* Print pseudo-op to define a byte */

defbyte()
{
	ot("DB ");
}

/* Print pseudo-op to define a word
** -chg- to DD
*/

defword()
{
	ot("DD ");
}

/* Modify the stack pointer to the new value indicated */

sa_modstk(newsp) int newsp;
{
	int k;

	k = newsp - Csp;
	if (k == 0)  return newsp;
	ot("ADD  ESP, ");
	outdec(k);
	nl();
	return newsp;
}

/* Modify the stack pointer to the new value indicated */

sa_rtnstk(newsp) int newsp;
{
	if (Msp != 0)
		{
		ot("ADD  ESP, ");	/*Remove frame from stack.*/
		ostklbl();
		nl();
		}
	ol("POP  EBP");
	return newsp;
}

/*
**	Primary Register   = EBX
**	Secondary Register = EDX
*/

/* Double the primary register */

sa_doublereg()
{
	ol("SAL  EBX, 1");
}

/* Add the primary and secondary registers */
/*	(results in primary) */

sa_add()
{
	ol("ADD  EBX, EDX");
}

/* Subtract the primary register from the secondary */
/*	(results in primary) */

sa_sub()
{
	ol("SUB  EDX, EBX");
	ol("MOV  EBX, EDX");
}

/* Multiply the primary and secondary registers */
/*	(results in primary) */
/** MUL EAX, r/m32 -> EDX:EAX **/

sa_mult()
{
	ol("MOV  EAX, EBX");	/** primary **/
/**	ol("PUSH EDX");		**/
	ol("MUL  EDX");		/** secondary **/
/**	ol("POP  EDX");		**/
	ol("MOV  EBX, EAX");	/** result: lo dword in primary,
** hi dword in secondary register for return **/
}

/* Divide the secondary register by the primary */
/*	(quotient in primary, remainder in secondary) */
/**
*** DIV EDX:EAX, r/m32 -> EAX = Quo., EDX = Rem.
*** 
**/

sa_div()
{
	ol("MOV  EAX, EDX");
	ol("CDQ");		/** signed EAX -> qword, EDX:EAX **/
	ol("IDIV  EBX");	/** signed div by primary **/
	ol("MOV  EBX, EAX");	/** EAX Quo., EDX signed Rem.
** returns Quo. in Primary, signed Rem. in Secondary. **/
}

/* Compute remainder (modulo) of secondary register */
/*	divided by the primary */
/*	(remainder in primary, quotient in secondary) */

sa_modulo()
{
	sa_div();
	sa_swap();
}

/* Inclusive 'or' the primary and the secondary registers */
/*	(results in primary) */

sa_or()
{
	ol("OR   EBX, EDX");
}

/* Exclusive 'or' the primary and seconday registers */
/*	(results in primary) */

sa_xor()
{
	ol("XOR  EBX, EDX");
}

/* 'And' the primary and secondary registers */
/*	(results in primary) */

sa_and()
{
	ol("AND  EBX, EDX");
}

/* Arithmetic shift right the secondary register by the */
/*  count in the primary (results in primary) */

sa_asr()
{
	ol("MOV  ECX, EBX");
	ol("SAR  EDX, CL");
	ol("MOV  EBX, EDX");
}

/* Arithmetic left shift the secondary register by the */
/*  count in the primary. (results in primary) */

sa_asl()
{
	ol("MOV  ECX, EBX");
	ol("SAL  EDX, CL");
	ol("MOV  EBX, EDX");
}

/* Form two's complement of primary register */

sa_neg()
{
	ol("NEG  EBX");
}

/* Form one's complement of primary register */
sa_not()
{
	ol("NOT  EBX");
}

/* Increment the primary register by one */

sa_inc()
{
	ol("INC  EBX");
}

/* Decrement the primary register by one */

sa_dec()
{
	ol("DEC  EBX");
}

/* Following are the conditional operators */
/* They compare the secondary register against the primary */
/* and put a literal 1 in the primary if the condition is */
/* true, otherwise they clear the primary register */

/* Test for equal */

sa_eq()
{
	sa_callrts("cceq");
}

/* Test for not equal */

sa_not_equal()
{
	sa_callrts("ccne");
}

/* Test for less than (signed) */

sa_sless_than()
{
	sa_callrts("cclt");
}

/* Test for less than or equal to (signed) */

sa_sless_or_eq()
{
	sa_callrts("ccle");
}

/* Test for greater than (signed) */

sa_sgreater_than()
{
	sa_callrts("ccgt");
}

/* Test for greater than or equal to (signed) */

sa_sge()
{
	sa_callrts("ccge");
}

/* Test for less than (unsigned) */

sa_uless_than()
{
	sa_callrts("ccult");
}

/* Test for less than or equal to (unsigned) */

sa_uless_oreq()
{
	sa_callrts("ccule");
}

/* Test for greater than (unsigned) */

sa_ugt()
{
	sa_callrts("ccugt");
}

/* Test for greater than or equal to (unsigned) */

sa_uge()
{
	sa_callrts("ccuge");
}

/** Convert primary value into logical (boolean) value, **/
/** that is, (0 if 0, 1 otherwise) **/

sa_mk_bool()
{
	int t_lbl;

	t_lbl = getlabel();	/** make a unique label for our use **/
	ol("AND  EBX, 0FFFFFFFFh");
	ot("JZ   ");		/** already zero. **/
	printlabel(t_lbl);
	nl();
	ol("MOV  EBX, 1");		/** .else. > 0, set to one. **/
	sa_mk_lbl(t_lbl);	/** codegen true branch label here **/
}

/** Convert primary value into logical not (boolean) value, **/
/** that is, (1 if 0, 0 otherwise) **/

sa_mk_nbool()
{
	int t_lbl, f_lbl;

	t_lbl = getlabel();	/** make a unique label for our use **/
	f_lbl = getlabel();

	ol("AND  EBX, 0FFFFFFFFh");
	ot("JNZ  ");		/** jz means already zero. **/
	printlabel(t_lbl);
	nl();

	ol("MOV  EBX, 1");		/** .else. zero, invert to one. **/
	ot("JMP  ");
	printlabel(f_lbl);
	nl();

	sa_mk_lbl(t_lbl);	/** codegen true branch label here **/
	ol("MOV  EBX, 0"); /** invert to zero **/
	sa_mk_lbl(f_lbl);
}


/** EO C86N-9.C **/


/**-------------------------------------**/
/** extern functions:       **/
/** these are temp stubs for testing!!  **/
/** CALL gets | gets(line);		**/
/** CALL fopen | fopen(line,"w")	**/
/** CALL fclose | fclose(output);	**/
/** putchar				**/
/** getc				**/
/** putc				**/
/** gets				**/
/** -- verify stack variables & cleanup **/
/** Comment these out if using stdlib.h **/
/** FOR SCCNT8.C only **/
/**getc(){;} gets(){;} putc(){;}  **/
/**putchar(){;} fopen(){;} fclose(){;}  **/


/*	<<<<< End of Compiler >>>>>	*/

/** EOF **/