[mod.sources] v09i024: Z80 macro cross-assembler, Part01/02

sources-request@mirror.UUCP (03/13/87)

Submitted by: pyrnj!vu-vlsi!colin (Colin Kelley)
Mod.sources: Volume 9, Issue 24
Archive-name: zmac/Part01

#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	Makefile zmac.y mio.c zmac.1 zdis.1
export PATH; PATH=/bin:$PATH
echo shar: extracting "'Makefile'" '(642 characters)'
if test -f 'Makefile'
then
	echo shar: will not over-write existing file "'Makefile'"
else
cat << \SHAR_EOF > 'Makefile'
# Makefile to make z80 macro assembler.
CFLAGS =

all:	zmac zdis

zmac:	y.tab.o mio.o
	cc $(CFLAGS) -o zmac y.tab.o mio.o

y.tab.c: zmac.y
	yacc zmac.y

zdis:	zdis.o
	cc $(CFLAGS) -o zdis zdis.o

install:
	install -s zmac /usr/local/bin
	install -s zdis /usr/local/bin

install_man:
	cp zmac.1 /usr/man/manl/zmac.l
	cp zdis.1 /usr/man/manl/zdis.l

clean:
	rm -f zdis.o zmac.o mio.o y.tab.c y.tab.o a.out core

shar: zmac.shar.1 zmac.shar.2

zmac.shar.1: Makefile zmac.y mio.c zmac.1 zdis.1
	shar -vc Makefile zmac.y mio.c zmac.1 zdis.1 > zmac.shar.1

zmac.shar.2: zdis.c serial.z serial.hex
	shar -vc zdis.c serial.z serial.hex > zmac.shar.2
SHAR_EOF
if test 642 -ne "`wc -c < 'Makefile'`"
then
	echo shar: error transmitting "'Makefile'" '(should have been 642 characters)'
fi
chmod +x 'Makefile'
fi # end of overwriting check
echo shar: extracting "'zmac.y'" '(50295 characters)'
if test -f 'zmac.y'
then
	echo shar: will not over-write existing file "'zmac.y'"
else
cat << \SHAR_EOF > 'zmac.y'
%{
/*
 *  zmac -- macro cross-assembler for the Zilog Z80 microprocessor
 *
 *  Bruce Norskog	4/78
 *
 *  Last modification  1-18-87 by cdk
 *  This assembler is modeled after the Intel 8080 macro cross-assembler
 *  for the Intel 8080 by Ken Borgendale.  The major features are:
 *	1.  Full macro capabilities
 *	2.  Conditional assembly
 *	3.  A very flexible set of listing options and pseudo-ops
 *	4.  Symbol table output
 *	5.  Error report
 *	6.  Elimination of sequential searching
 *	7.  Commenting of source
 *	8.  Facilities for system definiton files
 *
 * Revision History:
 *
 * jrp	3-8-82	Converted to run on Vax, updated syntax to conform better
 *		to the Zilog standard.
 *
 * jrp	3-15-82	Added underscore as a character type in the lex table
 *		'numpart' (0x5F).
 *
 *		Changed maximum number of characters in a label to 15
 *		from 7. Note that 'putsymtab' uses this value inside
 *		of a quoted string, so we use 15.
 *
 * jrp	2-15-83	Fixed 'getlocal' to return better local labels. It used
 *		to crash after 6 invocations.
 *
 * jrp	6-7-83	Fixed bug in the ADD IX,... instruction.
 *
 * jrp	5-11-84	Added code to print unused labels out with the symbol table
 *		Also sped up the macro processor by using stdio.
 *
 * jrp 5-22-84	Added include files ala ormac
 *
 * jrp 8-27-84	Added PHASE/DEPHASE commands
 *
 * cdk 9-20-86	Converted to run on a Pyramid.  This meant changing yylval
 *		to be a %union, and then putting in the appropriate
 *		typecasts where ints are pointers are used interchangeably.
 *		The current version still probably won't run on machines where
 *		sizeof(int) != sizeof(char *).
 *		Also changed emit() to use varargs, and got rid of the
 *		old style = in front of yacc action code.
 *			-Colin Kelley  vu-vlsi!colin
 *
 * cdk 10-2-86	Added some more typecasts to keep lint a little happier.
 *		Removed several unused variables.  Changed most vars
 *		declared as char to int, since many of them were being
 *		compared with -1!  I still don't know what's going on with
 *		est[][] being malloc'd and free'd everywhere...it looks pretty
 *		fishy...
 *
 * cdk 1-18-87  Added MIO code to emulate 'mfile' using malloc()'d memory.
 *		This was needed to get the code to work when compiled under
 *		MSC 4.0 on a PC, and it's probably faster anyway.
 *
 * cdk 2-5-87	Added 'cmp' as a synonym for 'cp', 'jmp' as a synonym for
 *		'jp', and added tolerance of accumulator specification for arithmetic
 *		and logical instructions.  (For example, 'or a,12' is now accepted,
 *		same as 'or 12'.)
 */


#define MIO		/* use emulation routines from mio.c */

#include <stdio.h>
#ifdef MSDOS
#include <fcntl.h>
#else
#include <sys/file.h>	/* for open() calls */
#endif

#ifdef vax11c
#define unlink(filename) delete(filename)
#endif

#ifdef MIO
FILE *mfopen();
#else
#define mfopen(filename,mode) fopen(filename,mode)
#define mfclose(filename,mode) fclose(filename,mode) 
#define mfputc(c,f) putc(c,f)
#define mfgetc(f) getc(f)
#define mfseek(f,loc,origin) fseek(f,loc,origin)
#define mfread(ptr,size,nitems,f) fread(ptr,size,nitems,f)
#define mfwrite(ptr,size,nitems,f) fread(ptr,size,nitems,f)
#endif /* MIO */

/*
 * DEBUG turns on pass reporting.
 * Macro debug and Token debug enables.
#define	DEBUG
#define	M_DEBUG	
#define	T_DEBUG
 */

#define ITEMTABLESIZE	2000
#define TEMPBUFSIZE	200
#define LINEBUFFERSIZE	200
#define EMITBUFFERSIZE	200
#define MAXSYMBOLSIZE	15
#define IFSTACKSIZE	20
#define MAXIFS		150
#define TITLELEN	50
#define BINPERLINE	16
#define	PARMMAX		25
#define MAXEXP		25
#define SYMMAJIC	07203
#define	NEST_IN		8


#define loop	for(;;)

yyerror(err)
char *err;
{}		/* we will do our own error printing */

struct	item	{
	char	*i_string;
	int	i_value;
	int	i_token;
	int	i_uses;
};

FILE	*fout,
	*fbuf,
	*fin[NEST_IN],
	*now_file ;

char *malloc() ;

int	pass2;	/*set when pass one completed*/
int	dollarsign ;	/* location counter */
int	olddollar ;	/* kept to put out binary */

/* program counter save for PHASE/DEPHASE */
int	phdollar, phbegin, phaseflag ;

char	*src_name[NEST_IN] ;
int	linein[NEST_IN] ;
int	now_in ;



#define bflag	0	/* balance error */
#define eflag	1	/* expression error */
#define fflag	2	/* format error */
#define iflag	3	/* bad digits */
#define mflag	4	/* multiply defined */
#define pflag	5	/* phase error */
#define uflag	6	/* undeclared used */
#define vflag	7	/* value out of range */
#define oflag	8	/* phase/dephase error */

#define FLAGS	9	/* number of flags */

char	err[FLAGS];
int	keeperr[FLAGS];
char	errlet[]="BEFIMPUVO";
char	*errname[]={
	"Balance",
	"Expression",
	"Format",
	"Digit",
	"Mult. def.",
	"Phase",
	"Undeclared",
	"Value",
	"Phase/Dephase",
};


char	linebuf[LINEBUFFERSIZE];
char	*lineptr;
char	*linemax = &linebuf[LINEBUFFERSIZE];

char	outbin[BINPERLINE];
char	*outbinp = outbin;
char	*outbinm = &outbin[BINPERLINE];

char	emitbuf[EMITBUFFERSIZE];
char	*emitptr;

char	ifstack[IFSTACKSIZE];
char	*ifptr;
char	*ifstmax = &ifstack[IFSTACKSIZE-1];


char	expif[MAXIFS];
char	*expifp;
char	*expifmax = &expif[MAXIFS];

char	hexadec[] = "0123456789ABCDEF" ;
char	*expstack[MAXEXP];
int	expptr;


int	nitems;
int	linecnt;
int	nbytes;
int	invented;


char	tempbuf[TEMPBUFSIZE];
char	*tempmax = &tempbuf[TEMPBUFSIZE-1];

char	inmlex;
char	arg_flag;
char	quoteflag;
int	parm_number;
int	exp_number;
char	symlong[] = "Symbol too long";

int	disp;
#define FLOC	PARMMAX
#define TEMPNUM	PARMMAX+1
char	**est;
char	**est2;

char	*floc;
int	mfptr;
FILE	*mfile;

char	*writesyms;


char	*title;
char	titlespace[TITLELEN];
char	*timp,*ctime();
char	*sourcef;
char	src[15];
char	bin[15];
char	mtmp[15];
char	listf[15];

char	bopt = 1,
	edef = 1,
	eopt = 1,
	fdef = 0,
	fopt = 0,
	gdef = 1,
	gopt = 1,
	iopt = 0 ,	/* list include files */
	lstoff = 0,
	lston = 0,	/* flag to force listing on */
	lopt = 0,
	mdef = 0,
	mopt = 0,
	nopt = 1 ,	/* line numbers on as default */
	oopt = 0,
	popt = 1,	/* form feed as default page eject */
	sopt = 0,	/* turn on symbol table listing */
	topt = 1;
	saveopt;

char	xeq_flag = 0;
int	xeq;

long	now;
int	line;
int	page = 1;

struct stab {
	char	t_name[MAXSYMBOLSIZE+1];
	int	t_value;
	int	t_token;
};

/*
 *  push back character
 */
int	peekc;


/*
 *  add a character to the output line buffer
 */
addtoline(ac)
int	ac;
{
	/* check for EOF from stdio */
	if (ac == -1)
		ac = 0 ;
	if (inmlex)
		return(ac);
	if (lineptr >= linemax)
		error("line buffer overflow");
	*lineptr++ = ac;
	return(ac);
}

#include <varargs.h>

/*
 *  put values in buffer for outputing
 */

/*VARARGS*/
/*ARGSUSED*/
emit(va_alist)
va_dcl
{	
	register int bytes;
	va_list ap;
	va_start(ap);

	bytes = va_arg(ap,int);

	while	(--bytes >= 0)
		if (emitptr >= &emitbuf[EMITBUFFERSIZE])
			error("emit buffer overflow");
		else {
			*emitptr++ = va_arg(ap,int);
		}
	va_end(ap);
}


emit1(opcode,regvalh,data16,type)
int	opcode,regvalh,data16,type;
{
	if (regvalh & 0x8000) {
		if (type & 1 == 0 && (disp > 127 || disp < -128))
			err[vflag]++;
		switch(type) {
		case 0:
			if (opcode & 0x8000)
				emit(4, regvalh >> 8, opcode >> 8, disp, opcode);
			else
				emit(3, regvalh >> 8, opcode, disp);
			break;
		case 1:
			emit(2, regvalh >> 8, opcode);
			break;
		case 2:
			if (data16 > 255 || data16 < -128)
				err[vflag]++;
			emit(4, regvalh >> 8, opcode, disp, data16);
			break;
		case 5:
			emit(4, regvalh >> 8, opcode, data16, data16 >> 8);
		}
	} else
		switch(type) {
		case 0:
			if (opcode & 0100000)
				emit(2, opcode >> 8, opcode);
			else
				emit(1, opcode);
			break;
		case 1:
			if (opcode & 0100000)
				emit(2, opcode >> 8, opcode);
			else
				emit(1, opcode);
			break;
		case 2:
			if (data16 > 255 || data16 < -128)
				err[vflag]++;
			emit(2, opcode, data16);
			break;
		case 3:
			if (data16 >255 || data16 < -128)
				err[vflag]++;
			emit(2, opcode, data16);
			break;
		case 5:
			if (opcode & 0100000)
				emit(4, opcode >> 8, opcode, data16, data16 >> 8);
			else
				emit(3, opcode, data16, data16 >> 8);
		}
}




emitdad(rp1,rp2)
int rp1,rp2;
{
	if (rp1 & 0x8000)
		emit(2,rp1 >> 8, rp2 + 9);
	else
		emit(1,rp2 + 9);
}


emitjr(opcode,expr)
int	opcode,expr;
{
	disp = expr - dollarsign - 2;
	if (disp > 127 || disp < -128)
		err[vflag]++;
	emit(2, opcode, disp);
}




/*
 *  put out a byte of binary 
 */
putbin(v)
{
	if(!pass2 || !bopt) return;
	*outbinp++ = v;
	if (outbinp >= outbinm) flushbin();
}



/*
 *  output one line of binary in INTEL standard form
 */
flushbin()
{
	register  char *p;
	register check;

	if (!pass2 || !bopt)
		return;
	nbytes += outbinp-outbin;
	if (check = outbinp-outbin) {
		putc(':', fbuf);
		puthex(check, fbuf);
		puthex(olddollar>>8, fbuf);
		puthex(olddollar, fbuf);
		puthex(0, fbuf);
		check += (olddollar >> 8) + olddollar;
		olddollar += (outbinp-outbin);
		for (p=outbin; p<outbinp; p++) {
			puthex(*p, fbuf);
			check += *p;
		}
		puthex(256-check, fbuf);
		putc('\n', fbuf);
		outbinp = outbin;
	}
}



/*
 *  put out one byte of hex
 */
puthex(byte, buf)
char	byte;
FILE	*buf;
{
	putc(hexadec[(byte >> 4) & 017], buf);
	putc(hexadec[byte & 017], buf);
}

/*
 *  put out a line of output -- also put out binary
 */
list(optarg)
int	optarg;
{
	register char *	p;
	register int	i;
	int  lst;

	if (!expptr)
		linecnt++;
	addtoline('\0');
	if (pass2) {
		lst = iflist();
		if (lst) {
			lineout();
			if (nopt)
				fprintf(fout, "%4d:\t", linein[now_in]);
			puthex(optarg >> 8, fout);
			puthex(optarg, fout);
			fputs("  ", fout);
			for (p = emitbuf; (p < emitptr) && (p - emitbuf < 4); p++) {
				puthex(*p, fout);
			}
			for (i = 4 - (p-emitbuf); i > 0; i--)
				fputs("  ", fout);
			putc('\t', fout);
			fputs(linebuf, fout);
		}

		if (bopt) {
			for (p = emitbuf; p < emitptr; p++)
				putbin(*p);
		}


		p = emitbuf+4;
		while (lst && gopt && p < emitptr) {
			lineout();
			if (nopt) putc('\t', fout);
			fputs("      ", fout);
			for (i = 0; (i < 4) && (p < emitptr);i++) {
				puthex(*p, fout);
				p++;
			}
			putc('\n', fout);
		}


		lsterr2(lst);
	} else
		lsterr1();
	dollarsign += emitptr - emitbuf;
	emitptr = emitbuf;
	lineptr = linebuf;
}



/*
 *  keep track of line numbers and put out headers as necessary
 */
lineout()
{
	if (line == 60) {
		if (popt)
			putc('\014', fout);	/* send the form feed */
		else
			fputs("\n\n\n\n\n", fout);
		line = 0;
	}
	if (line == 0) {
		fprintf(fout, "\n\n%s %s\t%s\t Page %d\n\n\n",
			&timp[4], &timp[20], title, page++);
		line = 4;
	}
	line++;
}


/*
 *  cause a page eject
 */
eject()
{
	if (pass2 && iflist()) {
		if (popt) {
			putc('\014', fout);	/* send the form feed */
		} else {
			while (line < 65) {
				line++;
				putc('\n', fout);
			}
		}
	}
	line = 0;
}


/*
 *  space n lines on the list file
 */
space(n)
{
	int	i ;
	if (pass2 && iflist())
		for (i = 0; i<n; i++) {
			lineout();
			putc('\n', fout);
		}
}


/*
 *  Error handling - pass 1
 */
lsterr1() {
	register int i;
	if (topt)
		for (i = 0; i <= 4; i++)
			if (err[i]) {
				errorprt(i);
				err[i] = 0;
			}
}


/*
 *  Error handling - pass 2.
 */
lsterr2(lst)
int	lst;
{
	register int i;
	for (i=0; i<FLAGS; i++)
		if (err[i]) {
			if (lst) {
				lineout();
				putc(errlet[i], fout);
				putc('\n', fout);
			}
			err[i] = 0;
			keeperr[i]++;
			if (i > 4 && topt)
				errorprt(i);
		}

	fflush(fout);	/*to avoid putc(har) mix bug*/
}

/*
 *  print diagnostic to error terminal
 */
errorprt(errnum)
int	errnum;
{
	fprintf(stderr,"%d: %s error\n%s\n",
		linecnt, errname[errnum], linebuf) ;
	fflush(stderr) ;
	return ;
}


/*
 *  list without address -- for comments and if skipped lines
 */
list1()
{
	int lst;

	addtoline('\0');
	lineptr = linebuf;
	if (!expptr) linecnt++;
	if (pass2)
		if (lst = iflist()) {
			lineout();
			if (nopt)
				fprintf(fout, "%4d:\t", linein[now_in]);
			fprintf(fout, "\t\t%s", linebuf);
			lsterr2(lst);
		}
	else
		lsterr1();
}


/*
 *  see if listing is desired
 */
iflist()
{
	register  i, j;

	if (lston)
		return(1) ;
	if (lopt)
		return(0);
	if (*ifptr && !fopt)
		return(0);
	if (!lstoff && !expptr)
		return(1);
	j = 0;
	for (i=0; i<FLAGS; i++)
		if (err[i])
			j++;
	if (expptr)
		return(mopt || j);
	if (eopt && j)
		return(1);
	return(0);
}


%}

%union	{
	struct item *itemptr;
	int ival;
	char *cval;
	}

%token <cval> STRING
%token <itemptr> NOOPERAND
%token <itemptr> ARITHC
%token ADD
%token <itemptr> LOGICAL
%token <itemptr> BIT
%token CALL
%token <itemptr> INCDEC
%token <itemptr> DJNZ
%token EX
%token <itemptr> IM
%token PHASE
%token DEPHASE
%token <itemptr> IN
%token JP
%token <itemptr> JR
%token LD
%token <itemptr> OUT
%token <itemptr> PUSHPOP
%token <itemptr> RET
%token <itemptr> SHIFT
%token <itemptr> RST
%token <itemptr> REGNAME
%token <itemptr> ACC
%token <itemptr> C
%token <itemptr> RP
%token <itemptr> HL
%token <itemptr> INDEX
%token <itemptr> AF
%token <itemptr> SP
%token <itemptr> MISCREG
%token F
%token <itemptr> COND
%token <itemptr> SPCOND
%token <ival> NUMBER
%token <itemptr> UNDECLARED
%token END
%token ORG
%token DEFB
%token DEFS
%token DEFW
%token EQU
%token DEFL
%token <itemptr> LABEL
%token <itemptr> EQUATED
%token <itemptr> WASEQUATED
%token <itemptr> DEFLED
%token <itemptr> MULTDEF
%token <ival> MOD
%token <ival> SHL
%token <ival> SHR
%token <ival> NOT
%token IF
%token ENDIF
%token <itemptr> ARGPSEUDO
%token <itemptr> LIST
%token <itemptr> MINMAX
%token MACRO
%token <itemptr> MNAME
%token <itemptr> OLDMNAME
%token ARG
%token ENDM
%token MPARM
%token <ival> ONECHAR
%token <ival> TWOCHAR

%type <itemptr> label.part symbol
%type <ival> reg evenreg realreg mem pushable bcdesp bcdehlsp mar condition
%type <ival> spcondition parenexpr expression lxexpression

%left '|' '^'
%left '&'
%nonassoc NOT
%left '+' '-'
%left '*' '/' MOD SHL SHR
%left UNARY
%%

%{
char  *cp;
int  i;
%}

program:
	statements
|
	error	{	error("file bad");	}
;


statements:
	statement
|
	statements statement
|
	statements error	{
		fprintf(stderr,"statement error\n");
		err[fflag]++;
		quoteflag = 0;
		while(yychar != '\n' && yychar != '\0') yychar = yylex();
		list(dollarsign);
		yyclearin;yyerrok;
	}
;


statement:
	label.part '\n'	{ 
		if ($1) list(dollarsign);
		else  list1();
	}
|
	label.part operation '\n' {
		list(dollarsign);
	}
|
	symbol EQU expression '\n' {
		switch($1->i_token) {
		case UNDECLARED: case WASEQUATED:
			$1->i_token = EQUATED;
			$1->i_value = $3;
			break;
		default:
			err[mflag]++;
			$1->i_token = MULTDEF;
		}
		list($3);
	}
|
	symbol DEFL expression '\n' {
		switch($1->i_token) {
		case UNDECLARED: case DEFLED:
			$1->i_token = DEFLED;
			$1->i_value = $3;
			break;
		default:
			err[mflag]++;
			$1->i_token = MULTDEF;
		}
		list($3);
	}
|
	symbol MINMAX expression ',' expression '\n' {
		switch ($1->i_token) {
		case UNDECLARED: case DEFLED:
			$1->i_token = DEFLED;
			if ($2->i_value)	/* max */
				list($1->i_value = ($3 > $5? $3:$5));
			else list($1->i_value = ($3 < $5? $3:$5));
			break;
		default:
			err[mflag]++;
			$1->i_token = MULTDEF;
			list($1->i_value);
		}
	}
|
	IF expression '\n' {
		if (ifptr >= ifstmax)
			error("Too many ifs");
		else {
			if (pass2) {
				*++ifptr = *expifp++;
				if (*ifptr != !(yypv[2].ival)) err[pflag]++;
			} else {
				if (expifp >= expifmax)
					error("Too many ifs!");
				*expifp++ = !(yypv[2].ival);
				*++ifptr = !(yypv[2].ival);
			}
		}
		saveopt = fopt;
		fopt = 1;
		list(yypv[2].ival);
		fopt = saveopt;
	}
|
	ENDIF '\n' {
		if (ifptr == ifstack) err[bflag]++;
		else --ifptr;
		list1();
	}
|
	label.part END '\n' {
		list(dollarsign);
		peekc = 0;
	}
|
	label.part END expression '\n' {
		xeq_flag++;
		xeq = $3;
		list($3);
		peekc = 0;
	}
|
	label.part DEFS expression '\n' {
		if ($3 < 0) err[vflag]++;
		list(dollarsign);
		if ($3) {
			flushbin();
			dollarsign += $3;
			olddollar = dollarsign;
		}
	}
|
	ARGPSEUDO arg_on ARG  arg_off '\n' {
		list1();
		switch ($1->i_value) {

		case 0:		/* title */
			lineptr = linebuf;
			cp = tempbuf;
			title = titlespace;
			while ((*title++ = *cp++) && (title < &titlespace[TITLELEN]));
			*title = 0;
			title = titlespace;
			break;

		case 1:		/* rsym */
			if (pass2) break;
			insymtab(tempbuf);
			break;

		case 2:		/* wsym */
			writesyms = malloc(strlen(tempbuf)+1);
			strcpy(writesyms, tempbuf);
			break;
		case 3:		/* include file */
			next_source(tempbuf) ;
			break ;
		}
	}
|
	ARGPSEUDO arg_on '\n' arg_off {
		fprintf(stderr,"ARGPSEUDO error\n");
		err[fflag]++;
		list(dollarsign);
	}
|
	LIST '\n' {
		if ($1 != (struct item *) -1) $<ival>2 = 1;
		goto dolopt; }
|
	LIST expression '\n' {
	dolopt:
		linecnt++;
		if (pass2) {
			lineptr = linebuf;
			switch ($1->i_value) {
			case 0:	/* list */
				if ($2 < 0) lstoff = 1;
				if ($2 > 0) lstoff = 0;
				break;

			case 1:	/* eject */
				if ($2) eject();
				break;

			case 2:	/* space */
				if ((line + $2) > 60) eject();
				else space($2);
				break;

			case 3:	/* elist */
				eopt = edef;
				if ($2 < 0) eopt = 0;
				if ($2 > 0) eopt = 1;
				break;

			case 4:	/* fopt */
				fopt = fdef;
				if ($2 < 0) fopt = 0;
				if ($2 > 0) fopt = 1;
				break;

			case 5:	/* gopt */
				gopt = gdef;
				if ($2 < 0) gopt = 1;
				if ($2 > 0) gopt = 0;
				break;

			case 6: /* mopt */
				mopt = mdef;
				if ($2 < 0) mopt = 0;
				if ($2 > 0) mopt = 1;
			}
		}
	}
|
	UNDECLARED MACRO parm.list '\n' {
		$1->i_token = MNAME;
		$1->i_value = mfptr;
		mfseek(mfile, (long)mfptr, 0);
		list1();
		mlex() ;
		parm_number = 0;
	}
|
	OLDMNAME MACRO {
		$1->i_token = MNAME;
		while (yychar != ENDM && yychar) {
			while (yychar != '\n' && yychar)
				yychar = yylex();
			list1();
			yychar = yylex();
		}
		while (yychar != '\n' && yychar) yychar = yylex();
		list1();
		yychar = yylex();
	}
|
	label.part MNAME al arg.list '\n' {
	expand:
		$2->i_uses++ ;
		arg_flag = 0;
		parm_number = 0;
		list(dollarsign);
		expptr++;
		est = est2;
		est[FLOC] = floc;
		est[TEMPNUM] = (char *)exp_number++;
		floc = (char *)($2->i_value);
		mfseek(mfile, (long)floc, 0);
	}
;


label.part:
	/*empty*/
	 {	$$ = NULL;	}
|
	symbol ':' {
		switch($1->i_token) {
		case UNDECLARED:
			if (pass2)
				err[pflag]++;
			else {
				$1->i_token = LABEL;
				$1->i_value = dollarsign;
			}
			break;
		case LABEL:
			if (!pass2) {
				$1->i_token = MULTDEF;
				err[mflag]++;
			} else if ($1->i_value != dollarsign)
				err[pflag]++;
			break;
		default:
			err[mflag]++;
			$1->i_token = MULTDEF;
		}
	}
;


operation:
	NOOPERAND
		{ emit1($1->i_value, 0, 0, 1); }
|
	JP expression
		{ emit(3, 0303, $2, $2 >> 8);	}
|
	CALL expression
		{	emit(3, 0315, $2, $2 >> 8);	}
|
	RST	expression
		{ if ($2 > 7 || $2 < 0)
			err[vflag]++;
		emit(1, $1->i_value + (($2 & 7) << 3));
	}
|
	ADD ACC ',' expression
		{ emit1(0306, 0, $4, 3); }
|
	ARITHC ACC ',' expression
		{ emit1(0306 + ($1->i_value << 3), 0, $4, 3); }
|
	LOGICAL expression
		{ emit1(0306 | ($1->i_value << 3), 0, $2, 3); }
|
	LOGICAL ACC ',' expression	/* -cdk */
		{ emit1(0306 | ($1->i_value << 3), 0, $4, 3); }
|
	ADD ACC ',' reg
		{ emit1(0200 + ($4 & 0377), $4, 0, 0); }
|
	ARITHC ACC ',' reg
		{ emit1(0200 + ($1->i_value << 3) + ($4 & 0377), $4, 0, 0); }
|
	LOGICAL reg
		{ emit1(0200 + ($1->i_value << 3) + ($2 & 0377), $2, 0, 0); }
|
	LOGICAL ACC ',' reg		/* -cdk */
		{ emit1(0200 + ($1->i_value << 3) + ($4 & 0377), $4, 0, 0); }
|
	SHIFT reg
		{ emit1(0145400 + ($1->i_value << 3) + ($2 & 0377), $2, 0, 0); }
|
	INCDEC	reg
		{ emit1($1->i_value + (($2 & 0377) << 3) + 4, $2, 0, 0); }
|
	ARITHC HL ',' bcdehlsp
		{ if ($1->i_value == 1)
				emit(2,0355,0112+$4);
			else
				emit(2,0355,0102+$4);
		}
|
	ADD mar ',' bcdesp
		{ emitdad($2,$4); }
|
	ADD mar ',' mar
		{
			if ($2 != $4) {
				fprintf(stderr,"ADD mar, mar error\n");
				err[fflag]++;
			}
			emitdad($2,$4);
		}
|
	INCDEC evenreg
		{ emit1(($1->i_value << 3) + ($2 & 0377) + 3, $2, 0, 1); }
|
	PUSHPOP pushable
		{ emit1($1->i_value + ($2 & 0377), $2, 0, 1); }
|
	BIT expression ',' reg
		{
			if ($2 < 0 || $2 > 7)
				err[vflag]++;
			emit1($1->i_value + (($2 & 7) << 3) + ($4 & 0377), $4, 0, 0);
		}
|
	JP condition ',' expression
		{ emit(3, 0302 + $2, $4, $4 >> 8); }
|
	JP '(' mar ')'
		{ emit1(0351, $3, 0, 1); }
|
	CALL condition ',' expression
		{ emit(3, 0304 + $2, $4, $4 >> 8); }
|
	JR expression
		{ emitjr(030,$2); }
|
	JR spcondition ',' expression
		{ emitjr($1->i_value + $2, $4); }
|
	DJNZ expression
		{ emitjr($1->i_value, $2); }
|
	RET
		{ emit(1, $1->i_value); }
|
	RET condition
		{ emit(1, 0300 + $2); }
|
	LD reg ',' reg
		{
			if (($2 & 0377) == 6 && ($4 & 0377) == 6) {
				fprintf(stderr,"LD reg, reg error\n");
				err[fflag]++;
			}
			emit1(0100 + (($2 & 7) << 3) + ($4 & 7),$2 | $4, 0, 0);
		}
|
	LD reg ',' expression
		{ emit1(6 + (($2 & 0377) << 3), $2, $4, 2); }
|
	LD reg ',' '(' RP ')'
		{	if ($2 != 7) {
				fprintf(stderr,"LD reg, (RP) error\n");
				err[fflag]++;
			}
			else emit(1, 012 + $5->i_value);
		}
|
	LD reg ',' parenexpr
		{
			if ($2 != 7) {
				fprintf(stderr,"LD reg, (expr) error\n");
				err[fflag]++;
			}
			else emit(3, 072, $4, $4 >> 8);
		}
|
	LD '(' RP ')' ',' ACC
		{ emit(1, 2 + $3->i_value); }
|
	LD parenexpr ',' ACC
		{ emit(3, 062, $2, $2 >> 8); }
|
	LD reg ',' MISCREG
		{
			if ($2 != 7) {
				fprintf(stderr,"LD reg, MISCREG error\n");
				err[fflag]++;
			}
			else emit(2, 0355, 0127 + $4->i_value);
		}
|
	LD MISCREG ',' ACC
		{ emit(2, 0355, 0107 + $2->i_value); }
|
	LD evenreg ',' lxexpression
		{ emit1(1 + ($2 & 060), $2, $4, 5); }
|
	LD evenreg ',' parenexpr
		{
			if (($2 & 060) == 040)
				emit1(052, $2, $4, 5);
			else
				emit(4, 0355, 0113 + $2, $4, $4 >> 8);
		}
|
	LD parenexpr ',' evenreg
		{
			if (($4 & 060) == 040)
				emit1(042, $4, $2, 5);
			else
				emit(4, 0355, 0103 + $4, $2, $2 >> 8);
		}
|
	LD evenreg ',' mar
		{
			if ($2 != 060) {
				fprintf(stderr,"LD evenreg error\n");
				err[fflag]++;
			}
			else
				emit1(0371, $4, 0, 1);
		}
|
	EX RP ',' HL
		{
			if ($2->i_value != 020) {
				fprintf(stderr,"EX RP, HL error\n");
				err[fflag]++;
			}
			else
				emit(1, 0353);
		}
|
	EX AF ',' AF setqf '\'' clrqf
		{ emit(1, 010); }
|
	EX '(' SP ')' ',' mar
		{ emit1(0343, $6, 0, 1); }
|
	IN realreg ',' parenexpr
		{
			if ($2 != 7) {
				fprintf(stderr,"IN reg, (expr) error\n");
				err[fflag]++;
			}
			else	{
				if ($4 < 0 || $4 > 255)
					err[vflag]++;
				emit(2, $1->i_value, $4);
			}
		}
|
	IN realreg ',' '(' C ')'
		{ emit(2, 0355, 0100 + ($2 << 3)); }
|
	IN F ',' '(' C ')'
		{ emit(2, 0355, 0160); }
|
	OUT parenexpr ',' ACC
		{
			if ($2 < 0 || $2 > 255)
				err[vflag]++;
			emit(2, $1->i_value, $2);
		}
|
	OUT '(' C ')' ',' realreg
		{ emit(2, 0355, 0101 + ($6 << 3)); }
|
	IM expression
		{
			if ($2 > 2 || $2 < 0)
				err[vflag]++;
			else
				emit(2, $1->i_value >> 8, $1->i_value + (($2 + ($2 > 0)) << 3));
		}
|
	PHASE expression
		{
			if (phaseflag) {
				err[oflag]++;
			} else {
				phaseflag = 1;
				phdollar = dollarsign;
				dollarsign = $2;
				phbegin = dollarsign;
			}
		}
|
	DEPHASE
		{
			if (!phaseflag) {
				err[oflag]++;
			} else {
				phaseflag = 0;
				dollarsign = phdollar + dollarsign - phbegin;
			}
		}
|
	ORG expression
		{
			if (phaseflag) {
				err[oflag]++;
				dollarsign = phdollar + dollarsign - phbegin;
				phaseflag = 0;
			}
			if ($2-dollarsign) {
				flushbin();
				olddollar = $2;
				dollarsign = $2;
			}
		}
|
	DEFB db.list
|
	DEFW dw.list
|
	ENDM
;


parm.list:
|
	parm.element
|
	parm.list ',' parm.element
;


parm.element:
	UNDECLARED
		{
			$1->i_token = MPARM;
			if (parm_number >= PARMMAX)
				error("Too many parameters");
			$1->i_value = parm_number++;
		}
;


arg.list:
	/* empty */
|
	arg.element
|
	arg.list ',' arg.element
;


arg.element:
	ARG
		{
			cp = malloc(strlen(tempbuf)+1);
			est2[parm_number++] = cp;
			strcpy(cp, tempbuf);
		}
;
reg:
	realreg
|
	mem
;
realreg:
	REGNAME
		{
			$$ = $1->i_value;
		}
|
	ACC
		{
			$$ = $1->i_value;
		}
|
	C
		{
			$$ = $1->i_value;
		}
;
mem:
	'(' HL ')'
		{
			$$ = 6;
		}
|
	'(' INDEX expression ')'
		{
			disp = $3;
			$$ = ($2->i_value & 0177400) | 6;
		}
|
	'(' INDEX ')'
		{
			disp = 0;
			$$ = ($2->i_value & 0177400) | 6;
		}
;
evenreg:
	bcdesp
|
	mar
;
pushable:
	RP
		{
			$$ = $1->i_value;
		}
|
	AF
		{
			$$ = $1->i_value;
		}
|
	mar
;
bcdesp:
	RP
		{
			$$ = $1->i_value;
		}
|
	SP
		{
			$$ = $1->i_value;
		}
;
bcdehlsp:
	bcdesp
|
	HL
		{
			$$ = $1->i_value;
		}
;
mar:
	HL
		{
			$$ = $1->i_value;
		}
|
	INDEX
		{
			$$ = $1->i_value;
		}
;
condition:
	spcondition
|
	COND
		{
			$$ = $1->i_value;
		}
;
spcondition:
	SPCOND
		{
			$$ = $1->i_value;
		}
|
	C
		{	$$ = 030;	}
;
db.list:
	db.list.element
|
	db.list ',' db.list.element
;
db.list.element:
	TWOCHAR
		{
			emit(2, $1, $1>>8);
		}
|
	STRING
		{
			cp = $1;
			while (*cp != '\0')
				emit(1,*cp++);
		}
|
	expression
		{
			if ($1 < -128 || $1 > 255)
					err[vflag]++;
			emit(1, $1 & 0377);
		}
;


dw.list:
	dw.list.element
|
	dw.list ',' dw.list.element
;


dw.list.element:
	expression
		{
			emit(2, $1, $1>>8);
		}
;



lxexpression:
	expression
|
	TWOCHAR
;

parenexpr:
	'(' expression ')'
		{	$$ = $2;	}
;

expression:
	error
		{
			err[eflag]++;
			$$ = 0;
		}
|
	LABEL
		{	$$ = $1->i_value; $1->i_uses++ ;	}
|
	NUMBER
|
	ONECHAR
|
	EQUATED
		{	$$ = $1->i_value;	}
|
	WASEQUATED
		{	$$ = $1->i_value;	}
|
	DEFLED
		{	$$ = $1->i_value;	}
|
	'$'
		{	$$ = dollarsign;	}
|
	UNDECLARED
		{
			err[uflag]++;
			$$ = 0;
		}
|
	MULTDEF
		{	$$ = $1->i_value;	}
|
	expression '+' expression
		{	$$ = $1 + $3;	}
|
	expression '-' expression
		{	$$ = $1 - $3;	}
|
	expression '/' expression
		{	$$ = $1 / $3;	}
|
	expression '*' expression
		{	$$ = $1 * $3;	}
|
	expression MOD expression
		{	$$ = $1 % $3;	}
|
	expression '&' expression
		{	$$ = $1 & $3;	}
|
	expression '|' expression
		{	$$ = $1 | $3;	}
|
	expression '^' expression
		{	$$ = $1 ^ $3;	}
|
	expression SHL expression
		{	$$ = $1 << $3;	}
|
	expression SHR expression
		{	$$ = (($1 >> 1) & 077777) >> ($3 - 1);	}
|
	'[' expression ']'
		{	$$ = $2;	}
|
	NOT expression
		{	$$ = ~$2;	}
|
	'+' expression %prec UNARY
		{	$$ = $2;	}
|
	'-' expression %prec UNARY
		{	$$ = -$2;	}
;

symbol:
	UNDECLARED
|
	LABEL
|
	MULTDEF
|
	EQUATED
|
	WASEQUATED
|
	DEFLED
;


al:
	{
		if (expptr >= MAXEXP)
			error("Macro expansion level");
		est2 = (char **) malloc((PARMMAX +4) * sizeof(char *));
		expstack[expptr] = (char *)est2 ;
		for (i=0; i<PARMMAX; i++)
			est2[i] = 0;
		arg_flag++;
	}
;


arg_on:
	{	arg_flag++;	}
;

arg_off:
		{	arg_flag = 0;	}
;

setqf:
		{	quoteflag++;	}
;

clrqf:
		{	quoteflag = 0;	}

;

%%
/*extern int	yylval;*/

#define F_END	0
#define OTHER	1
#define SPACE	2
#define DIGIT	3
#define LETTER	4
#define STARTER 5


/*
 *  This is the table of character classes.  It is used by the lexical
 *  analyser. (yylex())
 */
char	charclass[] = {
	F_END,	OTHER,	OTHER,	OTHER,	OTHER,	OTHER,	OTHER,	OTHER,
	OTHER,	SPACE,	OTHER,	OTHER,	OTHER,	SPACE,	OTHER,	OTHER,
	OTHER,	OTHER,	OTHER,	OTHER,	OTHER,	OTHER,	OTHER,	OTHER,
	OTHER,	OTHER,	OTHER,	OTHER,	OTHER,	OTHER,	OTHER,	OTHER,
	SPACE,	OTHER,	OTHER,	OTHER,	OTHER,	OTHER,	OTHER,	OTHER,
	OTHER,	OTHER,	OTHER,	OTHER,	OTHER,	OTHER,	OTHER,	OTHER,
	DIGIT,	DIGIT,	DIGIT,	DIGIT,	DIGIT,	DIGIT,	DIGIT,	DIGIT,
	DIGIT,	DIGIT,	OTHER,	OTHER,	OTHER,	OTHER,	OTHER,	STARTER,
	STARTER,LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER,
	LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER,
	LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER,
	LETTER, LETTER, LETTER, OTHER,	OTHER,	OTHER,	OTHER,	LETTER,
	OTHER,	LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER,
	LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER,
	LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER,
	LETTER, LETTER, LETTER, OTHER,	OTHER,	OTHER,	OTHER,	OTHER,
};


/*
 *  the following table tells which characters are parts of numbers.
 *  The entry is non-zero for characters which can be parts of numbers.
 */
char	numpart[] = {
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
	'0',	'1',	'2',	'3',	'4',	'5',	'6',	'7',
	'8',	'9',	0,	0,	0,	0,	0,	0,
	0,	'A',	'B',	'C',	'D',	'E',	'F',	0,
	'H',	0,	0,	0,	0,	0,	0,	'O',
	0,	'Q',	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	'a',	'b',	'c',	'd',	'e',	'f',	0,
	'h',	0,	0,	0,	0,	0,	0,	'o',
	0,	'q',	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
	0};




/*
 *  the following table is a list of assembler mnemonics;
 *  for each mnemonic the associated machine-code bit pattern
 *  and symbol type are given.
 */
struct	item	keytab[] = {
	"a",	7,	ACC,	0,
	"adc",	1,	ARITHC,	0,
	"add",	0,	ADD,	0,
	"af",	060,	AF,	0,
	"and",	4,	LOGICAL,	0,
	"ascii",0,	DEFB,	0,
	"b",	0,	REGNAME,	0,
	"bc",	0,	RP,	0,
	"bit",	0145500,BIT,	0,
	"block",0,	DEFS,	0,
	"byte",	0,	DEFB,	0,
	"c",	1,	C,	0,
	"call", 0315,	CALL,	0,
	"ccf",	077,	NOOPERAND,	0,
	"cmp",	7,	LOGICAL,	0,		/* -cdk */
	"cp",	7,	LOGICAL,	0,
	"cpd",	0166651,NOOPERAND,	0,
	"cpdr",	0166671,NOOPERAND,	0,
	"cpi",	0166641,NOOPERAND,	0,
	"cpir",	0166661,NOOPERAND,	0,
	"cpl",	057,	NOOPERAND,	0,
	"d",	2,	REGNAME,	0,
	"daa",	0047,	NOOPERAND,	0,
	"de",	020,	RP,	0,
	"dec",	1,	INCDEC,	0,
	"defb",	0,	DEFB,	0,
	"defl",0,	DEFL,	0,
	"defs",	0,	DEFS,	0,
	"defw",	0,	DEFW,	0,
	"dephase",	0,	DEPHASE,	0,
	"di",	0363,	NOOPERAND,	0,
	"djnz",	020,	DJNZ,	0,
	"e",	3,	REGNAME,	0,
	"ei",	0373,	NOOPERAND,	0,
	"eject",1,	LIST,	0,
	"elist",3,	LIST,	0,
	"end",	0,	END,	0,
	"endif",0,	ENDIF,	0,
	"endm", 0,	ENDM,	0,
	"equ",	0,	EQU,	0,
	"ex",	0,	EX,	0,
	"exx",	0331,	NOOPERAND,	0,
	"f",	0,	F,	0,
	"flist",4,	LIST,	0,
	"glist",5,	LIST,	0,
	"h",	4,	REGNAME,	0,
	"halt",	0166,	NOOPERAND,	0,
	"hl",	040,	HL,	0,
	"i",	0,	MISCREG,	0,
	"if",	0,	IF,	0,
	"im",	0166506,IM,	0,
	"in",	0333,	IN,	0,
	"inc",	0,	INCDEC,	0,
	"include", 3,	ARGPSEUDO,	0,
	"ind",	0166652,NOOPERAND,	0,
	"indr",	0166672,NOOPERAND,	0,
	"ini",	0166642,NOOPERAND,	0,
	"inir",	0166662,NOOPERAND,	0,
	"ix",	0156440,INDEX,	0,
	"iy",	0176440,INDEX,	0,
	"jmp",	0303,	JP,	0,		/* -cdk */
	"jp",	0303,	JP,	0,
	"jr",	040,	JR,	0,
	"l",	5,	REGNAME,	0,
	"ld",	0,	LD,	0,
	"ldd",	0166650,NOOPERAND,	0,
	"lddr",	0166670,NOOPERAND,	0,
	"ldi",	0166640,NOOPERAND,	0,
	"ldir",	0166660,NOOPERAND,	0,
	"list",	0,	LIST,	0,
	"m",	070,	COND,	0,
	"macro",0,	MACRO,	0,
	"max",	1,	MINMAX,	0,
	"min",	0,	MINMAX,	0,
	"mlist",6,	LIST,	0,
	"mod",	0,	MOD,	0,
	"nc",	020,	SPCOND,	0,
	"neg",	0166504,NOOPERAND,	0,
	"nolist",-1,	LIST,	0,
	"nop",	0,	NOOPERAND,	0,
	"not",	0,	NOT,	0,
	"nv",	040,	COND,	0,
	"nz",	0,	SPCOND,	0,
	"or",	6,	LOGICAL,	0,
	"org",	0,	ORG,	0,
	"otdr",0166673,NOOPERAND,	0,
	"otir",0166663,NOOPERAND,	0,
	"out",	0323,	OUT,	0,
	"outd",	0166653,NOOPERAND,	0,
	"outi",	0166643,NOOPERAND,	0,
	"p",	060,	COND,	0,
	"pe",	050,	COND,	0,
	"phase",	0,	PHASE,	0,
	"po",	040,	COND,	0,
	"pop",	0301,	PUSHPOP,	0,
	"push", 0305,	PUSHPOP,	0,
	"r",	010,	MISCREG,	0,
	"res",	0145600,BIT,	0,
	"ret",	0311,	RET,	0,
	"reti",	0166515,NOOPERAND,	0,
	"retn",	0166505,NOOPERAND,	0,
	"rl",	2,	SHIFT,	0,
	"rla",	027,	NOOPERAND,	0,
	"rlc",	0,	SHIFT,	0,
	"rlca",	07,	NOOPERAND,	0,
	"rld",	0166557,NOOPERAND,	0,
	"rr",	3,	SHIFT,	0,
	"rra",	037,	NOOPERAND,	0,
	"rrc",	1,	SHIFT,	0,
	"rrca",	017,	NOOPERAND,	0,
	"rrd",	0166547,NOOPERAND,	0,
	"rst",	0307,	RST,	0,
	"rsym",	1,	ARGPSEUDO,	0,
	"sbc",	3,	ARITHC,	0,
	"scf",	067,	NOOPERAND,	0,
	"set",	0145700,BIT,	0,
	"shl",	0,	SHL,	0,
	"shr",	0,	SHR,	0,
	"sla",	4,	SHIFT,	0,
	"sp",	060,	SP,	0,
	"space",2,	LIST,	0,
	"sra",	5,	SHIFT,	0,
	"srl",	7,	SHIFT,	0,
	"sub",	2,	LOGICAL,	0,
	"title",0,	ARGPSEUDO,	0,
	"v",	050,	COND,	0,
	"word",	0,	DEFW,	0,
	"wsym",	2,	ARGPSEUDO,	0,
	"xor",	5,	LOGICAL,	0,
	"z",	010,	SPCOND,	0,
};

/*
 *  user-defined items are tabulated in the following table.
 */

struct item	itemtab[ITEMTABLESIZE];
struct item	*itemmax = &itemtab[ITEMTABLESIZE];





/*
 *  lexical analyser, called by yyparse.
 */
yylex()
{
	register char	c;
	register char *p;
	register int	radix;
	int  limit;

	if (arg_flag)
		return(getarg());
loop switch(charclass[c = nextchar()]) {
	case F_END:
		if (expptr) {
			popsi();
			continue;
		} else return(0);

	case SPACE:
		break;
	case LETTER:
	case STARTER:
		p = tempbuf;
		do {
			if (p >= tempmax)
				error(symlong);
			*p++ = (c >= 'A' && c <= 'Z') ? c + 'a' - 'A' : c;
			while	((c = nextchar()) == '$')
				;
		} while	(charclass[c]==LETTER || charclass[c]==DIGIT);
		if (p - tempbuf > MAXSYMBOLSIZE)
			p = tempbuf + MAXSYMBOLSIZE;
		*p++ = '\0';
		peekc = c;
		return(tokenofitem(UNDECLARED));
	case DIGIT:
		if (*ifptr) return(skipline(c));
		p = tempbuf;
		do	{
			if (p >= tempmax)
				error(symlong);
			*p++ = (c >= 'A' && c <= 'Z') ? c + 'a' - 'A' : c;
			while	((c = nextchar()) == '$');
			}
			while(numpart[c]);
		peekc = c;
		*p-- = '\0';
		switch(*p)	{
			case 'o':
			case 'q':
				radix = 8;
				limit = 020000;
				*p = '\0';
				break;
			case 'd':
				radix = 10;
				limit = 3276;
				*p = '\0';
				break;
			case 'h':
				radix = 16;
				limit = 010000;
				*p = '\0';
				break;
			case 'b':
				radix = 2;
				limit = 077777;
				*p = '\0';
				break;
			default:
				radix = 10;
				limit = 3276;
				p++;
				break;
			}

		/*
		 *  tempbuf now points to the number, null terminated
		 *  with radix 'radix'.
		 */
		yylval.ival = 0;
		p = tempbuf;
		do	{
			c = *p - (*p > '9' ? ('a' - 10) : '0');
			if (c >= radix)
				{
				err[iflag]++;
				yylval.ival = 0;
				break;
				}
			if (yylval.ival < limit ||
				(radix == 10 && yylval.ival == 3276 && c < 8) ||
				(radix == 2 && yylval.ival == limit))
				yylval.ival = yylval.ival * radix + c;
			else {
				err[vflag]++;
				yylval.ival = 0;
				break;
				}
			}
			while(*++p != '\0');
		return(NUMBER);
	default:
		if (*ifptr)
			return(skipline(c));
		switch(c) {
		case ';':
			return(skipline(c));
		case '\'':
			if (quoteflag) return('\'');
			p = tempbuf;
			p[1] = 0;
			do	switch(c = nextchar())	{
			case '\0':
			case '\n':
				err[bflag]++;
				goto retstring;
			case '\'':
				if ((c = nextchar()) != '\'') {
				retstring:
					peekc = c;
					*p = '\0';
					if ((p-tempbuf) >2) {
						yylval.cval = tempbuf;
						return(STRING);
					} else if (p-tempbuf == 2)	{
						p = tempbuf;
						yylval.ival = *p++ ;
						yylval.ival |= *p<<8;
						return(TWOCHAR);
					} else	{
						p = tempbuf;
						yylval.ival = *p++;
						return(ONECHAR);
					}
				}
			default:
				*p++ = c;
			} while (p < tempmax);
			/*
			 *  if we break out here, our string is longer than
			 *  our input line
			 */
			error("string buffer overflow");
		default:
			return(c);
		}
	}
}

/*
 *  return the token associated with the string pointed to by
 *  tempbuf.  if no token is associated with the string, associate
 *  deftoken with the string and return deftoken.
 *  in either case, cause yylval to point to the relevant
 *  symbol table entry.
 */

tokenofitem(deftoken)
int	deftoken;
{
	register  char *p;
	register struct item *	ip;
	register  i;
	int  r, l, u, hash;


#ifdef T_DEBUG
	fputs("'tokenofitem entry'	", stderr) ;
	fputs(tempbuf, stderr) ;
#endif
	/*
	 *  binary search
	 */
	l = 0;
	u = (sizeof keytab/sizeof keytab[0])-1;
	while (l <= u) {
		i = (l+u)/2;
		ip = &keytab[i];
		if ((r = strcmp(tempbuf, ip->i_string)) == 0)
			goto found;
		if (r < 0)
			u = i-1;
		else
			l = i+1;
	}

	/*
	 *  hash into item table
	 */
	hash = 0;
	p = tempbuf;
	while (*p) hash += *p++;
	hash %= ITEMTABLESIZE;
	ip = &itemtab[hash];

	loop {
		if (ip->i_token == 0)
			break;
		if (strcmp(tempbuf, ip->i_string) == 0)
			goto found;
		if (++ip >= itemmax)
			ip = itemtab;
	}

	if (!deftoken) {
		i = 0 ;
		goto token_done ;
	}
	if (++nitems > ITEMTABLESIZE-20)
		error("item table overflow");
	ip->i_string = malloc(strlen(tempbuf)+1);
	ip->i_token = deftoken;
	ip->i_uses = 0 ;
	strcpy(ip->i_string, tempbuf);

found:
	if (*ifptr) {
		if (ip->i_token == ENDIF) {
			i = ENDIF ;
			goto token_done ;
		}
		if (ip->i_token == IF) {
			if (ifptr >= ifstmax)
				error("Too many ifs");
			else *++ifptr = 1;
		}
		i = skipline(' ');
		goto token_done ;
	}
	yylval.itemptr = ip;
	i = ip->i_token;
token_done:
#ifdef T_DEBUG
	fputs("\t'tokenofitem exit'\n", stderr) ;
#endif
	return(i) ;
}


/*
 *  interchange two entries in the item table -- used by qsort
 */
interchange(i, j)
{
	register  struct item *fp, *tp;
	struct item temp;

	fp = &itemtab[i];
	tp = &itemtab[j];
	temp.i_string = fp->i_string;
	temp.i_value = fp->i_value;
	temp.i_token = fp->i_token;
	temp.i_uses = fp->i_uses;

	fp->i_string = tp->i_string;
	fp->i_value = tp->i_value;
	fp->i_token = tp->i_token;
	fp->i_uses = tp->i_uses;

	tp->i_string = temp.i_string;
	tp->i_value = temp.i_value;
	tp->i_token = temp.i_token;
	tp->i_uses = temp.i_uses;
}



/*
 *  quick sort -- used by putsymtab to sort the symbol table
 */
qsort(m, n)
{
	register  i, j;

	if (m < n) {
		i = m;
		j = n+1;
		loop {
			do i++; while(strcmp(itemtab[i].i_string,
					itemtab[m].i_string) < 0);
			do j--; while(strcmp(itemtab[j].i_string,
					itemtab[m].i_string) > 0);
			if (i < j) interchange(i, j); else break;
		}
		interchange(m, j);
		qsort(m, j-1);
		qsort(j+1, n);
	}
}



/*
 *  get the next character
 */
nextchar()
{
	register int c, ch;
	static  char  *earg;
	char *getlocal();

	if (peekc != -1) {
		c = peekc;
		peekc = -1;
		return(c);
	}

start:
	if (earg) {
		if (*earg)
			return(addtoline(*earg++));
		earg = 0;
	}

	if (expptr) {
		if ((ch = getm()) == '\1') {	/*  expand argument  */
			ch = getm() - 'A';
			if (ch >= 0 && ch < PARMMAX && est[ch])
				earg = est[ch];
			goto start;
		}
		if (ch == '\2') {	/*  local symbol  */
			ch = getm() - 'A';
			if (ch >= 0 && ch < PARMMAX && est[ch]) {
				earg = est[ch];
				goto start;
			}
			earg = getlocal(ch, (int)est[TEMPNUM]);
			goto start;
		}

		return(addtoline(ch));
	}
	ch = getc(now_file) ;
	/* if EOF, check for include file */
	if (ch == EOF) {
		while (ch == EOF && now_in) {
			fclose(fin[now_in]) ;
			free(src_name[now_in]) ;
			now_file = fin[--now_in] ;
			ch = getc(now_file) ;
		}
		if (linein[now_in] < 0) {
			lstoff = 1 ;
			linein[now_in] = -linein[now_in] ;
		} else {
			lstoff = 0 ;
		}
		if (pass2 && iflist()) {
			lineout() ;
			fprintf(fout, "**** %s ****\n", src_name[now_in]) ;
		}
	}
	if (ch == '\n')
		linein[now_in]++ ;

	return(addtoline(ch)) ;
}


/*
 *  skip to rest of the line -- comments and if skipped lines
 */
skipline(ac)
{
	register  c;

	c = ac;
	while (c != '\n' && c != '\0')
		c = nextchar();
	return('\n');
}



main(argc, argv)
char  **argv;
{
	register  struct item *ip;
	register  i;
	int  files;
#ifdef DBUG
	extern  yydebug;
#endif

	fout = stdout ;
	fin[0] = stdin ;
	now_file = stdin ;
	files = 0;

	for (i=1; i<argc; i++) {
		if (*argv[i] == '-') while (*++argv[i]) switch(*argv[i]) {

		case 'b':	/*  no binary  */
			bopt = 0;
			continue;

#ifdef DBUG
		case 'd':	/*  debug  */
			yydebug++;
			continue;
#endif

		case 'e':	/*  error list only  */
			eopt = 0;
			edef = 0;
			continue;

		case 'f':	/*  print if skipped lines  */
			fopt++;
			fdef++;
			continue;

		case 'g':	/*  do not list extra code  */
			gopt = 0;
			gdef = 0;
			continue;

		case 'i':	/* do not list include files */
			iopt = 1 ;
			continue ;

		case 'l':	/*  no list  */
			lopt++;
			continue;

		case 'L':	/*  force listing of everything */
			lston++;
			continue;

		case 'm':	/*  print macro expansions  */
			mdef++;
			mopt++;
			continue;

		case 'n':	/*  put line numbers off */
			nopt-- ;
			continue;

		case 'o':	/*  list to standard output  */
			oopt++;
			continue;

		case 'p':	/*  put out four \n's for eject */
			popt-- ;
			continue;

		case 's':	/*  don't produce a symbol list  */
			sopt++;
			continue;

		case 't':
			topt = 0;
			continue;

		default:	/*  error  */
			error("Unknown option");

		} else if (files++ == 0) {
			sourcef = argv[i];
			strcpy(src, sourcef);
			suffix(src,".z");
			if ((now_file = fopen(src, "r")) == NULL)
				error("Cannot open source file");
			now_in = 0 ;
			fin[now_in] = now_file ;
			src_name[now_in] = src ;
		} else if (files)
			error("Too many arguments");
	}


	if (files == 0)
		error("No source file");
	strcpy(bin, sourcef);
	suffix(bin,".hex");
	if (bopt)
#ifdef MSDOS
		if (( fbuf = fopen(bin, "wb")) == NULL)
#else
		if (( fbuf = fopen(bin, "w")) == NULL)
#endif
			error("Cannot create binary file");
	if (!lopt && !oopt) {
		strcpy(listf, sourcef);
		suffix(listf,".lst");
		if ((fout = fopen(listf, "w")) == NULL)
			error("Cannot create list file");
	} else
		fout = stdout ;
	strcpy(mtmp, sourcef);
	suffix(mtmp,".tmp");
#ifdef MSDOS
	mfile = mfopen(mtmp,"w+b") ;
#else
	mfile = mfopen(mtmp,"w+") ;
#endif
	if (mfile == NULL) {
		error("Cannot create temp file");
	}
	/*unlink(mtmp);*/

	/*
	 *  get the time
	 */
	time(&now);
	timp = ctime(&now);
	timp[16] = 0;
	timp[24] = 0;

	title = sourcef;
	/*
	 * pass 1
	 */
#ifdef DEBUG
	fputs("DEBUG-pass 1\n", stderr) ;
#endif
	setvars();
	yyparse();
	pass2++;
	ip = &itemtab[-1];
	while (++ip < itemmax) {
		/* reset use count */
		ip->i_uses = 0 ;

		/* set macro names, equated and defined names */
		switch	(ip->i_token) {
		case MNAME:
			ip->i_token = OLDMNAME;
			break;

		case EQUATED:
			ip->i_token = WASEQUATED;
			break;

		case DEFLED:
			ip->i_token = UNDECLARED;
			break;
		}
	}
	setvars();
	fseek(now_file, (long)0, 0);

#ifdef DEBUG
	fputs("DEBUG- pass 2\n", stderr) ;
#endif
	yyparse();


	if (bopt) {
		flushbin();
		putc(':', fbuf);
		if (xeq_flag) {
			puthex(0, fbuf);
			puthex(xeq >> 8, fbuf);
			puthex(xeq, fbuf);
			puthex(1, fbuf);
			puthex(255-(xeq >> 8)-xeq, fbuf);
		} else
			for	(i = 0; i < 10; i++)
				putc('0', fbuf);
		putc('\n', fbuf);
		fflush(fbuf);
	}

	if (!lopt)
		fflush(fout);
	if (writesyms)
		outsymtab(writesyms);
	if (eopt)
		erreport();
	if (!lopt && !sopt)
		putsymtab();
	if (!lopt) {
		eject();
		fflush(fout);
	}
	exit(0);
}


/*
 *  set some data values before each pass
 */
setvars()
{
	register  i;

	peekc = -1;
	linein[now_in] = linecnt = 0;
	exp_number = 0;
	emitptr = emitbuf;
	lineptr = linebuf;
	ifptr = ifstack;
	expifp = expif;
	*ifptr = 0;
	dollarsign = 0;
	olddollar = 0;
	phaseflag = 0;
	for (i=0; i<FLAGS; i++) err[i] = 0;
}



/*
 *  print out an error message and die
 */
error(as)
char *as;
{

	*linemax = 0;
	fprintf(fout, "%s\n", linebuf);
	fflush(fout);
	fprintf(stderr, "%s\n", as) ;
	exit(1);
}



/*
 *  output the symbol table
 */
putsymtab()
{
	register  struct item *tp, *fp;
	int  i, j, k, t, rows;
	char c, c1 ;

	if (!nitems)
		return;

	/* compact the table so unused and UNDECLARED entries are removed */
	tp = &itemtab[-1];
	for (fp = itemtab; fp<itemmax; fp++) {
		if (fp->i_token == UNDECLARED) {
			nitems--;
			continue;
		}
		if (fp->i_token == 0)
			continue;
		tp++;
		if (tp != fp) {
			tp->i_string = fp->i_string;
			tp->i_value = fp->i_value;
			tp->i_token = fp->i_token;
			tp->i_uses = fp->i_uses ;
		}
	}

	tp++;
	tp->i_string = "{";

	/*  sort the table */
	qsort(0, nitems-1);

	title = "**  Symbol Table  **";

	rows = (nitems+3) / 4;
	if (rows+5+line > 60)
		eject();
	lineout();
	fprintf(fout,"\n\n\nSymbol Table:\n\n") ;
	line += 4;

	for (i=0; i<rows; i++) {
		for(j=0; j<4; j++) {
			k = rows*j+i;
			if (k < nitems) {
				tp = &itemtab[k];
				t = tp->i_token;
				c = ' ' ;
				if (t == EQUATED || t == DEFLED)
					c = '=' ;
				if (tp->i_uses == 0)
					c1 = '+' ;
				else
					c1 = ' ' ;
				fprintf(fout, "%-15s%c%4x%c    ",
					tp->i_string, c, tp->i_value & 0xffff, c1);
			}
		}
		lineout();
		putc('\n', fout);
	}
}




/*
 *  put out error report
 */
erreport()
{
	register i, numerr;

	if (line > 50) eject();
	lineout();
	numerr = 0;
	for (i=0; i<FLAGS; i++) numerr += keeperr[i];
	if (numerr) {
		fputs("\n\n\nError report:\n\n", fout);
		fprintf(fout, "%6d errors\n", numerr);
		line += 5;
	} else {
		fputs("\n\n\nStatistics:\n", fout);
		line += 3;
	}

	for (i=0; i<FLAGS; i++)
		if (keeperr[i]) {
			lineout();
			fprintf(fout, "%6d %c -- %s error\n",
				keeperr[i], errlet[i], errname[i]);
		}

	if (line > 55) eject();
	lineout();
	fprintf(fout, "\n%6d\tsymbols\n", nitems);
	fprintf(fout, "%6d\tbytes\n", nbytes);
	line += 2;
	if (mfptr) {
		if (line > 53) eject();
		lineout();
		fprintf(fout, "\n%6d\tmacro calls\n", exp_number);
		fprintf(fout, "%6d\tmacro bytes\n", mfptr);
		fprintf(fout, "%6d\tinvented symbols\n", invented/2);
		line += 3;
	}
}


/*
 *  lexical analyser for macro definition
 */
mlex()
{
	register  char  *p;
	register  c;
	int  t;

	/*
	 *  move text onto macro file, changing formal parameters
	 */
#ifdef	M_DEBUG
	fprintf(stderr,"enter 'mlex'\t") ;
#endif
	inmlex++;

	c = nextchar();
loop {
	switch(charclass[c]) {

	case DIGIT:
		while (numpart[c]) {
			putm(c);
			c = nextchar();
		}
		continue;

	case STARTER:
	case LETTER:
		t = 0;
		p = tempbuf+MAXSYMBOLSIZE+2;
		do {
			if (p >= tempmax)
				error(symlong);
			*p++ = c;
			if (t < MAXSYMBOLSIZE)
				tempbuf[t++] = (c >= 'A' && c <= 'Z')  ?
					c+'a'-'A' : c;
			c = nextchar();
		} while (charclass[c]==LETTER || charclass[c]==DIGIT);

		tempbuf[t] = 0;
		*p++ = '\0';
		p = tempbuf+MAXSYMBOLSIZE+2;
		t = tokenofitem(0);
		if (t != MPARM) while (*p) putm(*p++);
		else {
			if (*(yylval.itemptr->i_string) == '?') putm('\2');
			else putm('\1');
			putm(yylval.itemptr->i_value + 'A');
		}
		if (t == ENDM) goto done;
		continue;

	case F_END:
		if (expptr) {
			popsi();
			c = nextchar();
			continue;
		}

		goto done;

	default:
		if (c == '\n') {
			linecnt++;
		}
		if (c != '\1') putm(c);
		c = nextchar();
	}
}

	/*
	 *  finish off the file entry
	 */
done:
	while(c != EOF && c != '\n' && c != '\0') c = nextchar();
	linecnt++;
	putm('\n');
	putm('\n');
	putm(0);

	for (c=0; c<ITEMTABLESIZE; c++)
		if (itemtab[c].i_token == MPARM) {
			itemtab[c].i_token = UNDECLARED;
		}
	inmlex = 0;
#ifdef	M_DEBUG
	fprintf(stderr,"exit 'mlex'\n") ;
#endif
}



/*
 *  lexical analyser for the arguments of a macro call
 */
getarg()
{
	register int c;
	register char *p;
	static int comma;

	*tempbuf = 0;
	yylval.cval = tempbuf;
	while(charclass[c = nextchar()] == SPACE);

	switch(c) {

	case '\0':
		popsi();
	case '\n':
	case ';':
		comma = 0;
		return(skipline(c));

	case ',':
		if (comma) {
			comma = 0;
			return(',');
		}
		else {
			comma++;
			return(ARG);
		}

	case '\'':
		p = tempbuf;
		do switch (c = nextchar()) {
			case '\0':
			case '\n':
				peekc = c;
				*p = 0;
				err[bflag]++;
				return(ARG);
			case '\'':
				if ((c = nextchar()) != '\'') {
					peekc = c;
					*p = '\0';
					comma++;
					return(ARG);
				}
			default:
				*p++ = c;
		} while (p < tempmax);
		error(symlong);

	default:  /* unquoted string */
		p = tempbuf;
		peekc = c;
		do switch(c = nextchar()) {
			case '\0':
			case '\n':
			case '\t':
			case ' ':
			case ',':
				peekc = c;
				*p = '\0';
				comma++;
				return(ARG);
			default:
				*p++ = c;
		} while (p < tempmax);
	}
}





/*
 *  add a suffix to a string
 */
suffix(str,suff)
char *str,*suff;
{
	while(*str != '\0' && *str != '.')
		*str++;
	strcpy(str, suff);
}




/*
 *  put out a byte to the macro file, keeping the offset
 */
putm(c)
char c ;
{
	mfptr++;
	mfputc(c,mfile) ;
}



/*
 *  get a byte from the macro file
 */
getm()
{
	int ch;

	floc++;
	ch = mfgetc(mfile) ;
	if (ch == EOF) {
		ch = 0;
		fprintf(stderr,"bad macro read\n") ;
	}
	return(ch);
}



/*
 *  pop standard input
 */
popsi()
{
	register  i;

	for (i=0; i<PARMMAX; i++) {
		if (est[i]) free(est[i]);
	}
	floc = est[FLOC];
	free(est);
	expptr--;
	est = expptr ? (char **) expstack[expptr-1] : (char **) 0;
	mfseek(mfile, (long)floc, 0);
	if (lineptr > linebuf) lineptr--;
}



/*
 *  return a unique name for a local symbol
 *  c is the parameter number, n is the macro number.
 */

char *
getlocal(c, n)
int c,n;
{
static char local_label[10];
	invented++;
	if (c >= 26)
		c += 'a' - '0';
	sprintf(local_label, "?%c%04d", c+'a', n) ;
	return(local_label);
}



/*
 *  read in a symbol table
 */
insymtab(name)
char *name;
{
	register struct stab *t;
	int  s, i, sfile;

	t = (struct stab *) tempbuf;
#ifdef MSDOS
	if ((sfile = open(name, O_RDONLY | O_BINARY)) < 0)
#else
	if ((sfile = open(name, O_RDONLY)) < 0)
#endif
		return;
	read(sfile, (char *)t, sizeof *t);
	if (t->t_value != SYMMAJIC)
		return;

	s = t->t_token;
	for (i=0; i<s; i++) {
		read(sfile, (char *)t, sizeof *t);
		if (tokenofitem(UNDECLARED) != UNDECLARED)
			continue;
		yylval.itemptr->i_token = t->t_token;
		yylval.itemptr->i_value = t->t_value;
		if (t->t_token == MACRO)
			yylval.itemptr->i_value += mfptr;
	}

	while ((s = read(sfile, tempbuf, TEMPBUFSIZE)) > 0) {
		mfptr += s;
		mfwrite(tempbuf, 1, s, mfile) ;
	}
}



/*
 *  write out symbol table
 */
outsymtab(name)
char *name;
{
	register struct stab *t;
	register struct item *ip;
	int  i, sfile;

	t = (struct stab *) tempbuf;
	if ((sfile = creat(name, 0644)) < 0)
		return;
	for (ip=itemtab; ip<itemmax; ip++) {
		if (ip->i_token == UNDECLARED) {
			ip->i_token = 0;
			nitems--;
		}
	}

	copyname(title, (char *)t);
	t->t_value = SYMMAJIC;
	t->t_token = nitems;
	write(sfile, (char *)t, sizeof *t);

	for (ip=itemtab; ip<itemmax; ip++) {
		if (ip->i_token != 0) {
			t->t_token = ip->i_token;
			t->t_value = ip->i_value;
			copyname(ip->i_string, (char *)t);
			write(sfile, (char *)t, sizeof *t);
		}
	}

	mfseek(mfile, (long)0, 0);
	while((i = mfread(tempbuf, 1, TEMPBUFSIZE, mfile) ) > 0)
		write(sfile, tempbuf, i);
}



/*
 *  copy a name into the symbol file
 */
copyname(st1, st2)
char *st1, *st2;
{
	register  char  *s1, *s2;
	register  i;

	i = (MAXSYMBOLSIZE+2) & ~01;
	s1 = st1;
	s2 = st2;

	while(*s2++ = *s1++) i--;
	while(--i > 0) *s2++ = '\0';
}

/* get the next source file */
next_source(sp)
char *sp ;
{

	if(now_in == NEST_IN -1)
		error("Too many nested includes") ;
	if ((now_file = fopen(sp, "r")) == NULL) {
		char ebuf[100] ;
		sprintf(ebuf,"Can't open include file: %s", sp) ;
		error(ebuf) ;
	}
	if (pass2 && iflist()) {
		lineout() ;
		fprintf(fout, "**** %s ****\n",sp) ;
	}

	/* save the list control flag with the current line number */
	if (lstoff)
		linein[now_in] = - linein[now_in] ;

	/* no list if include files are turned off */
	lstoff |= iopt ;

	/* save the new file descriptor. */
	fin[++now_in] = now_file ;
	/* start with line 0 */
	linein[now_in] = 0 ;
	/* save away the file name */
	src_name[now_in] = malloc(strlen(sp)+1) ;
	strcpy(src_name[now_in],sp) ;
}
SHAR_EOF
if test 50295 -ne "`wc -c < 'zmac.y'`"
then
	echo shar: error transmitting "'zmac.y'" '(should have been 50295 characters)'
fi
chmod +x 'zmac.y'
fi # end of overwriting check
echo shar: extracting "'mio.c'" '(2326 characters)'
if test -f 'mio.c'
then
	echo shar: will not over-write existing file "'mio.c'"
else
cat << \SHAR_EOF > 'mio.c'
/*
 * mio.c - Colin Kelley  1-18-87
 *   routines to emulate temporary file handling with memory instead
 *
 */

#include <stdio.h>
#define MALLOC_SIZE 10000

unsigned char *malloc(), *realloc();

static unsigned char *mhead;		/* pointer to start of malloc()d area */
static unsigned char *mend;			/* pointer to current (just beyond) EOF*/
static unsigned char *mptr;			/* pointer to current position */
static unsigned int msize;			/* size of chunk mhead points to */

FILE *
mfopen(filename,mode)
char *filename,*mode;
{
	if ((mhead = malloc(MALLOC_SIZE)) == 0) {
		msize = 0;
		return (0);
	}
	msize = MALLOC_SIZE;
	mend = mptr = mhead;
	return ((FILE *)1);				/* not used */
}

mfclose(f)
FILE *f;
{
	if (mhead) {
		free(mhead);
		return (0);
	}
	else
		return (-1);
}

unsigned int
mfputc(c,f)
unsigned int c;
FILE *f;
{
register unsigned char *p;
	while (mptr >= mhead + msize) {
		if ((p = realloc(mhead,msize+MALLOC_SIZE)) == (unsigned char *)-1) {
			fputs("mio: out of memory\n",stderr);
			return (-1);
		}
		else {
			msize += MALLOC_SIZE;
			mptr = (unsigned char *) (p + (unsigned int)(mptr - mhead));
			mhead = p;
		}
	}
	*mptr = c & 255;
	mend = ++mptr;
	return c;
}

unsigned int
mfgetc(f)
FILE *f;
{
	if (mptr >= mend)		/* no characters left */
		return (-1);
	else
		return (*mptr++);
}

mfseek(f,loc,origin)
FILE *f;
long loc;
int origin;
{
	if (origin != 0) {
		fputs("mseek() only implemented with 0 origin",stderr);
		return (-1);
	}
	mptr = mhead + loc;
	return (0);
}

mfread(ptr, size, nitems,f)
char *ptr;
unsigned int size, nitems;
FILE *f;
{
register unsigned int i = 0;
	while (i < nitems) {
		if ((mptr + size) > mend)
			break;
		bcopy(mptr,ptr,size);
		ptr += size;
		mptr += size;
		i++;
	}
	return (i);
}

mfwrite(ptr, size, nitems, f)
char *ptr;
int size, nitems;
FILE *f;
{
register unsigned int i = 0;
register unsigned char *p;
	while (i < nitems) {
		while (mptr + size >= mhead + msize) {
			if ((p = realloc(mhead,msize+MALLOC_SIZE)) == (unsigned char *)-1){
				fputs("mio: out of memory\n",stderr);
				return (-1);
			}
			else {
				msize += MALLOC_SIZE;
				mptr = (unsigned char *) (p + (unsigned int)(mptr - mhead));
				mhead = p;
			}
		}
		if ((mptr + size) > mhead + msize)
			break;
		bcopy(ptr,mend,size);
		ptr += size;
		mend += size;
		mptr = mend;
	}
	return (i);
}
SHAR_EOF
if test 2326 -ne "`wc -c < 'mio.c'`"
then
	echo shar: error transmitting "'mio.c'" '(should have been 2326 characters)'
fi
chmod +x 'mio.c'
fi # end of overwriting check
echo shar: extracting "'zmac.1'" '(1329 characters)'
if test -f 'zmac.1'
then
	echo shar: will not over-write existing file "'zmac.1'"
else
cat << \SHAR_EOF > 'zmac.1'
.TH ZMAC l 
.SH NAME
zmac \- macro cross-assembler for the Zilog Z80 microprocessor
.SH SYNOPSIS
zmac [-bdefgilLmnopst] infile
.SH DESCRIPTION
The
.I Zmac
assembler is modeled after the Intel 8080 macro cross-assembler
for the Intel 8080 by Ken Borgendale.  The major features are:  Full
macro capabilities, Conditional assembly, A very flexible set of
listing options and pseudo-ops, Symbol table output, Error report,
Elimination of sequential searching, Commenting of source, Facilities
for system definiton files.
.PP
.I Zmac
assembles the specified input file (default extension .z) and
produces a .hex output file.  The options are:
.TP 8
.B b
no binary  
.TP 8
.B d
debug  
.TP 8
.B e
error list only  
.TP 8
.B f
print if skipped lines  
.TP 8
.B g
do not list extra code  
.TP 8
.B i
do not list include files 
.TP 8
.B l
no list  
.TP 8
.B L
force listing of everything 
.TP 8
.B m
print macro expansions  
.TP 8
.B n
put line numbers off 
.TP 8
.B o
list to standard output  
.TP 8
.B p
put out four \\n's for eject 
.TP 8
.B s
don't produce a symbol list  
.TP 8
.B t
don't know what this option does
.SH SEE ALSO
zdis(l)
.SH FILES
Source is in /usr/local/src/zmac directory.
.SH BUGS
The man page is incomplete.  If anyone discovers more information about
using zmac, please consider helping to update the man page.
SHAR_EOF
if test 1329 -ne "`wc -c < 'zmac.1'`"
then
	echo shar: error transmitting "'zmac.1'" '(should have been 1329 characters)'
fi
chmod +x 'zmac.1'
fi # end of overwriting check
echo shar: extracting "'zdis.1'" '(526 characters)'
if test -f 'zdis.1'
then
	echo shar: will not over-write existing file "'zdis.1'"
else
cat << \SHAR_EOF > 'zdis.1'
.TH ZDIS l 
.SH NAME
zdis \- disassembler for Z80 cross-assembler
.SH SYNOPSIS
zdis < infile.hex
.SH DESCRIPTION
.I Zdis
reads a hex file created by
.I zmac
and produces a disassembly on stdout.
.SH SEE ALSO
zmac(l)
.SH FILES
Source is in /usr/local/src/zmac directory.
.SH BUGS
Zdis ignores the program counter field in the hex file.  Instead it assumes
that the hex file has an ORG of 0.
.sp
The man page is incomplete.  If anyone discovers more information about
using zdis, please consider helping to update the man page.
SHAR_EOF
if test 526 -ne "`wc -c < 'zdis.1'`"
then
	echo shar: error transmitting "'zdis.1'" '(should have been 526 characters)'
fi
chmod +x 'zdis.1'
fi # end of overwriting check
#	End of shell archive
exit 0