[comp.sources.misc] v05i088: Z80 Assembler/Disassembler part 3 of 3

bownesrm@beowulf.UUCP (Keptin Comrade Dr. Bob) (12/19/88)

Posting-number: Volume 5, Issue 88
Submitted-by: "Keptin Comrade Dr. Bob" <bownesrm@beowulf.UUCP>
Archive-name: z80ad/part03

#!/bin/sh
# this is part 3 of an archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file zmac/zmac.y continued
#
CurArch=3
if test ! -r ._seq_
then echo "Please unpack part 1 first!"
     exit 1; fi
( read Scheck
  if test "$Scheck" != $CurArch
  then echo "Please unpack part $Scheck next!"
       exit 1;
  else exit 0; fi
) < ._seq_ || exit 1
sed 's/^X//' << 'SHAR_EOF' >> zmac/zmac.y
X	'8',	'9',	0,	0,	0,	0,	0,	0,
X	0,	'A',	'B',	'C',	'D',	'E',	'F',	0,
X	'H',	0,	0,	0,	0,	0,	0,	'O',
X	0,	'Q',	0,	0,	0,	0,	0,	0,
X	0,	0,	0,	0,	0,	0,	0,	0,
X	0,	'a',	'b',	'c',	'd',	'e',	'f',	0,
X	'h',	0,	0,	0,	0,	0,	0,	'o',
X	0,	'q',	0,	0,	0,	0,	0,	0,
X	0,	0,	0,	0,	0,	0,	0,	0,
X	0};
X
X
X
X
X/*
X *  the following table is a list of assembler mnemonics;
X *  for each mnemonic the associated machine-code bit pattern
X *  and symbol type are given.
X */
Xstruct	item	keytab[] = {
X	"a",	7,	ACC,	0,
X	"adc",	1,	ARITHC,	0,
X	"add",	0,	ADD,	0,
X	"af",	060,	AF,	0,
X	"and",	4,	LOGICAL,	0,
X	"ascii",0,	DEFB,	0,
X	"b",	0,	REGNAME,	0,
X	"bc",	0,	RP,	0,
X	"bit",	0145500,BIT,	0,
X	"block",0,	DEFS,	0,
X	"byte",	0,	DEFB,	0,
X	"c",	1,	C,	0,
X	"call", 0315,	CALL,	0,
X	"ccf",	077,	NOOPERAND,	0,
X	"cmp",	7,	LOGICAL,	0,		/* -cdk */
X	"cp",	7,	LOGICAL,	0,
X	"cpd",	0166651,NOOPERAND,	0,
X	"cpdr",	0166671,NOOPERAND,	0,
X	"cpi",	0166641,NOOPERAND,	0,
X	"cpir",	0166661,NOOPERAND,	0,
X	"cpl",	057,	NOOPERAND,	0,
X	"d",	2,	REGNAME,	0,
X	"daa",	0047,	NOOPERAND,	0,
X	"de",	020,	RP,	0,
X	"dec",	1,	INCDEC,	0,
X	"defb",	0,	DEFB,	0,
X	"defl",0,	DEFL,	0,
X	"defs",	0,	DEFS,	0,
X	"defw",	0,	DEFW,	0,
X	"dephase",	0,	DEPHASE,	0,
X	"di",	0363,	NOOPERAND,	0,
X	"djnz",	020,	DJNZ,	0,
X	"e",	3,	REGNAME,	0,
X	"ei",	0373,	NOOPERAND,	0,
X	"eject",1,	LIST,	0,
X	"elist",3,	LIST,	0,
X	"end",	0,	END,	0,
X	"endif",0,	ENDIF,	0,
X	"endm", 0,	ENDM,	0,
X	"equ",	0,	EQU,	0,
X	"ex",	0,	EX,	0,
X	"exx",	0331,	NOOPERAND,	0,
X	"f",	0,	F,	0,
X	"flist",4,	LIST,	0,
X	"glist",5,	LIST,	0,
X	"h",	4,	REGNAME,	0,
X	"halt",	0166,	NOOPERAND,	0,
X	"hl",	040,	HL,	0,
X	"i",	0,	MISCREG,	0,
X	"if",	0,	IF,	0,
X	"im",	0166506,IM,	0,
X	"in",	0333,	IN,	0,
X	"inc",	0,	INCDEC,	0,
X	"include", 3,	ARGPSEUDO,	0,
X	"ind",	0166652,NOOPERAND,	0,
X	"indr",	0166672,NOOPERAND,	0,
X	"ini",	0166642,NOOPERAND,	0,
X	"inir",	0166662,NOOPERAND,	0,
X	"ix",	0156440,INDEX,	0,
X	"iy",	0176440,INDEX,	0,
X	"jmp",	0303,	JP,	0,		/* -cdk */
X	"jp",	0303,	JP,	0,
X	"jr",	040,	JR,	0,
X	"l",	5,	REGNAME,	0,
X	"ld",	0,	LD,	0,
X	"ldd",	0166650,NOOPERAND,	0,
X	"lddr",	0166670,NOOPERAND,	0,
X	"ldi",	0166640,NOOPERAND,	0,
X	"ldir",	0166660,NOOPERAND,	0,
X	"list",	0,	LIST,	0,
X	"m",	070,	COND,	0,
X	"macro",0,	MACRO,	0,
X	"max",	1,	MINMAX,	0,
X	"min",	0,	MINMAX,	0,
X	"mlist",6,	LIST,	0,
X	"mod",	0,	MOD,	0,
X	"nc",	020,	SPCOND,	0,
X	"neg",	0166504,NOOPERAND,	0,
X	"nolist",-1,	LIST,	0,
X	"nop",	0,	NOOPERAND,	0,
X	"not",	0,	NOT,	0,
X	"nv",	040,	COND,	0,
X	"nz",	0,	SPCOND,	0,
X	"or",	6,	LOGICAL,	0,
X	"org",	0,	ORG,	0,
X	"otdr",0166673,NOOPERAND,	0,
X	"otir",0166663,NOOPERAND,	0,
X	"out",	0323,	OUT,	0,
X	"outd",	0166653,NOOPERAND,	0,
X	"outi",	0166643,NOOPERAND,	0,
X	"p",	060,	COND,	0,
X	"pe",	050,	COND,	0,
X	"phase",	0,	PHASE,	0,
X	"po",	040,	COND,	0,
X	"pop",	0301,	PUSHPOP,	0,
X	"push", 0305,	PUSHPOP,	0,
X	"r",	010,	MISCREG,	0,
X	"res",	0145600,BIT,	0,
X	"ret",	0311,	RET,	0,
X	"reti",	0166515,NOOPERAND,	0,
X	"retn",	0166505,NOOPERAND,	0,
X	"rl",	2,	SHIFT,	0,
X	"rla",	027,	NOOPERAND,	0,
X	"rlc",	0,	SHIFT,	0,
X	"rlca",	07,	NOOPERAND,	0,
X	"rld",	0166557,NOOPERAND,	0,
X	"rr",	3,	SHIFT,	0,
X	"rra",	037,	NOOPERAND,	0,
X	"rrc",	1,	SHIFT,	0,
X	"rrca",	017,	NOOPERAND,	0,
X	"rrd",	0166547,NOOPERAND,	0,
X	"rst",	0307,	RST,	0,
X	"rsym",	1,	ARGPSEUDO,	0,
X	"sbc",	3,	ARITHC,	0,
X	"scf",	067,	NOOPERAND,	0,
X	"set",	0145700,BIT,	0,
X	"shl",	0,	SHL,	0,
X	"shr",	0,	SHR,	0,
X	"sla",	4,	SHIFT,	0,
X	"sp",	060,	SP,	0,
X	"space",2,	LIST,	0,
X	"sra",	5,	SHIFT,	0,
X	"srl",	7,	SHIFT,	0,
X	"sub",	2,	LOGICAL,	0,
X	"title",0,	ARGPSEUDO,	0,
X	"v",	050,	COND,	0,
X	"word",	0,	DEFW,	0,
X	"wsym",	2,	ARGPSEUDO,	0,
X	"xor",	5,	LOGICAL,	0,
X	"z",	010,	SPCOND,	0,
X};
X
X/*
X *  user-defined items are tabulated in the following table.
X */
X
Xstruct item	itemtab[ITEMTABLESIZE];
Xstruct item	*itemmax = &itemtab[ITEMTABLESIZE];
X
X
X
X
X
X/*
X *  lexical analyser, called by yyparse.
X */
Xyylex()
X{
X	register char	c;
X	register char *p;
X	register int	radix;
X	int  limit;
X
X	if (arg_flag)
X		return(getarg());
Xloop switch(charclass[c = nextchar()]) {
X	case F_END:
X		if (expptr) {
X			popsi();
X			continue;
X		} else return(0);
X
X	case SPACE:
X		break;
X	case LETTER:
X	case STARTER:
X		p = tempbuf;
X		do {
X			if (p >= tempmax)
X				error(symlong);
X			*p++ = (c >= 'A' && c <= 'Z') ? c + 'a' - 'A' : c;
X			while	((c = nextchar()) == '$')
X				;
X		} while	(charclass[c]==LETTER || charclass[c]==DIGIT);
X		if (p - tempbuf > MAXSYMBOLSIZE)
X			p = tempbuf + MAXSYMBOLSIZE;
X		*p++ = '\0';
X		peekc = c;
X		return(tokenofitem(UNDECLARED));
X	case DIGIT:
X		if (*ifptr) return(skipline(c));
X		p = tempbuf;
X		do	{
X			if (p >= tempmax)
X				error(symlong);
X			*p++ = (c >= 'A' && c <= 'Z') ? c + 'a' - 'A' : c;
X			while	((c = nextchar()) == '$');
X			}
X			while(numpart[c]);
X		peekc = c;
X		*p-- = '\0';
X		switch(*p)	{
X			case 'o':
X			case 'q':
X				radix = 8;
X				limit = 020000;
X				*p = '\0';
X				break;
X			case 'd':
X				radix = 10;
X				limit = 3276;
X				*p = '\0';
X				break;
X			case 'h':
X				radix = 16;
X				limit = 010000;
X				*p = '\0';
X				break;
X			case 'b':
X				radix = 2;
X				limit = 077777;
X				*p = '\0';
X				break;
X			default:
X				radix = 10;
X				limit = 3276;
X				p++;
X				break;
X			}
X
X		/*
X		 *  tempbuf now points to the number, null terminated
X		 *  with radix 'radix'.
X		 */
X		yylval.ival = 0;
X		p = tempbuf;
X		do	{
X			c = *p - (*p > '9' ? ('a' - 10) : '0');
X			if (c >= radix)
X				{
X				err[iflag]++;
X				yylval.ival = 0;
X				break;
X				}
X			if (yylval.ival < limit ||
X				(radix == 10 && yylval.ival == 3276 && c < 8) ||
X				(radix == 2 && yylval.ival == limit))
X				yylval.ival = yylval.ival * radix + c;
X			else {
X				err[vflag]++;
X				yylval.ival = 0;
X				break;
X				}
X			}
X			while(*++p != '\0');
X		return(NUMBER);
X	default:
X		if (*ifptr)
X			return(skipline(c));
X		switch(c) {
X		case ';':
X			return(skipline(c));
X		case '\'':
X			if (quoteflag) return('\'');
X			p = tempbuf;
X			p[1] = 0;
X			do	switch(c = nextchar())	{
X			case '\0':
X			case '\n':
X				err[bflag]++;
X				goto retstring;
X			case '\'':
X				if ((c = nextchar()) != '\'') {
X				retstring:
X					peekc = c;
X					*p = '\0';
X					if ((p-tempbuf) >2) {
X						yylval.cval = tempbuf;
X						return(STRING);
X					} else if (p-tempbuf == 2)	{
X						p = tempbuf;
X						yylval.ival = *p++ ;
X						yylval.ival |= *p<<8;
X						return(TWOCHAR);
X					} else	{
X						p = tempbuf;
X						yylval.ival = *p++;
X						return(ONECHAR);
X					}
X				}
X			default:
X				*p++ = c;
X			} while (p < tempmax);
X			/*
X			 *  if we break out here, our string is longer than
X			 *  our input line
X			 */
X			error("string buffer overflow");
X		default:
X			return(c);
X		}
X	}
X}
X
X/*
X *  return the token associated with the string pointed to by
X *  tempbuf.  if no token is associated with the string, associate
X *  deftoken with the string and return deftoken.
X *  in either case, cause yylval to point to the relevant
X *  symbol table entry.
X */
X
Xtokenofitem(deftoken)
Xint	deftoken;
X{
X	register  char *p;
X	register struct item *	ip;
X	register  i;
X	int  r, l, u, hash;
X
X
X#ifdef T_DEBUG
X	fputs("'tokenofitem entry'	", stderr) ;
X	fputs(tempbuf, stderr) ;
X#endif
X	/*
X	 *  binary search
X	 */
X	l = 0;
X	u = (sizeof keytab/sizeof keytab[0])-1;
X	while (l <= u) {
X		i = (l+u)/2;
X		ip = &keytab[i];
X		if ((r = strcmp(tempbuf, ip->i_string)) == 0)
X			goto found;
X		if (r < 0)
X			u = i-1;
X		else
X			l = i+1;
X	}
X
X	/*
X	 *  hash into item table
X	 */
X	hash = 0;
X	p = tempbuf;
X	while (*p) hash += *p++;
X	hash %= ITEMTABLESIZE;
X	ip = &itemtab[hash];
X
X	loop {
X		if (ip->i_token == 0)
X			break;
X		if (strcmp(tempbuf, ip->i_string) == 0)
X			goto found;
X		if (++ip >= itemmax)
X			ip = itemtab;
X	}
X
X	if (!deftoken) {
X		i = 0 ;
X		goto token_done ;
X	}
X	if (++nitems > ITEMTABLESIZE-20)
X		error("item table overflow");
X	ip->i_string = malloc(strlen(tempbuf)+1);
X	ip->i_token = deftoken;
X	ip->i_uses = 0 ;
X	strcpy(ip->i_string, tempbuf);
X
Xfound:
X	if (*ifptr) {
X		if (ip->i_token == ENDIF) {
X			i = ENDIF ;
X			goto token_done ;
X		}
X		if (ip->i_token == IF) {
X			if (ifptr >= ifstmax)
X				error("Too many ifs");
X			else *++ifptr = 1;
X		}
X		i = skipline(' ');
X		goto token_done ;
X	}
X	yylval.itemptr = ip;
X	i = ip->i_token;
Xtoken_done:
X#ifdef T_DEBUG
X	fputs("\t'tokenofitem exit'\n", stderr) ;
X#endif
X	return(i) ;
X}
X
X
X/*
X *  interchange two entries in the item table -- used by qsort
X */
Xinterchange(i, j)
X{
X	register  struct item *fp, *tp;
X	struct item temp;
X
X	fp = &itemtab[i];
X	tp = &itemtab[j];
X	temp.i_string = fp->i_string;
X	temp.i_value = fp->i_value;
X	temp.i_token = fp->i_token;
X	temp.i_uses = fp->i_uses;
X
X	fp->i_string = tp->i_string;
X	fp->i_value = tp->i_value;
X	fp->i_token = tp->i_token;
X	fp->i_uses = tp->i_uses;
X
X	tp->i_string = temp.i_string;
X	tp->i_value = temp.i_value;
X	tp->i_token = temp.i_token;
X	tp->i_uses = temp.i_uses;
X}
X
X
X
X/*
X *  quick sort -- used by putsymtab to sort the symbol table
X */
Xqsort(m, n)
X{
X	register  i, j;
X
X	if (m < n) {
X		i = m;
X		j = n+1;
X		loop {
X			do i++; while(strcmp(itemtab[i].i_string,
X					itemtab[m].i_string) < 0);
X			do j--; while(strcmp(itemtab[j].i_string,
X					itemtab[m].i_string) > 0);
X			if (i < j) interchange(i, j); else break;
X		}
X		interchange(m, j);
X		qsort(m, j-1);
X		qsort(j+1, n);
X	}
X}
X
X
X
X/*
X *  get the next character
X */
Xnextchar()
X{
X	register int c, ch;
X	static  char  *earg;
X	char *getlocal();
X
X	if (peekc != -1) {
X		c = peekc;
X		peekc = -1;
X		return(c);
X	}
X
Xstart:
X	if (earg) {
X		if (*earg)
X			return(addtoline(*earg++));
X		earg = 0;
X	}
X
X	if (expptr) {
X		if ((ch = getm()) == '\1') {	/*  expand argument  */
X			ch = getm() - 'A';
X			if (ch >= 0 && ch < PARMMAX && est[ch])
X				earg = est[ch];
X			goto start;
X		}
X		if (ch == '\2') {	/*  local symbol  */
X			ch = getm() - 'A';
X			if (ch >= 0 && ch < PARMMAX && est[ch]) {
X				earg = est[ch];
X				goto start;
X			}
X			earg = getlocal(ch, (int)est[TEMPNUM]);
X			goto start;
X		}
X
X		return(addtoline(ch));
X	}
X	ch = getc(now_file) ;
X	/* if EOF, check for include file */
X	if (ch == EOF) {
X		while (ch == EOF && now_in) {
X			fclose(fin[now_in]) ;
X			free(src_name[now_in]) ;
X			now_file = fin[--now_in] ;
X			ch = getc(now_file) ;
X		}
X		if (linein[now_in] < 0) {
X			lstoff = 1 ;
X			linein[now_in] = -linein[now_in] ;
X		} else {
X			lstoff = 0 ;
X		}
X		if (pass2 && iflist()) {
X			lineout() ;
X			fprintf(fout, "**** %s ****\n", src_name[now_in]) ;
X		}
X	}
X	if (ch == '\n')
X		linein[now_in]++ ;
X
X	return(addtoline(ch)) ;
X}
X
X
X/*
X *  skip to rest of the line -- comments and if skipped lines
X */
Xskipline(ac)
X{
X	register  c;
X
X	c = ac;
X	while (c != '\n' && c != '\0')
X		c = nextchar();
X	return('\n');
X}
X
X
X
Xmain(argc, argv)
Xchar  **argv;
X{
X	register  struct item *ip;
X	register  i;
X	int  files;
X#ifdef DBUG
X	extern  yydebug;
X#endif
X
X	fout = stdout ;
X	fin[0] = stdin ;
X	now_file = stdin ;
X	files = 0;
X
X	for (i=1; i<argc; i++) {
X		if (*argv[i] == '-') while (*++argv[i]) switch(*argv[i]) {
X
X		case 'b':	/*  no binary  */
X			bopt = 0;
X			continue;
X
X#ifdef DBUG
X		case 'd':	/*  debug  */
X			yydebug++;
X			continue;
X#endif
X
X		case 'e':	/*  error list only  */
X			eopt = 0;
X			edef = 0;
X			continue;
X
X		case 'f':	/*  print if skipped lines  */
X			fopt++;
X			fdef++;
X			continue;
X
X		case 'g':	/*  do not list extra code  */
X			gopt = 0;
X			gdef = 0;
X			continue;
X
X		case 'i':	/* do not list include files */
X			iopt = 1 ;
X			continue ;
X
X		case 'l':	/*  no list  */
X			lopt++;
X			continue;
X
X		case 'L':	/*  force listing of everything */
X			lston++;
X			continue;
X
X		case 'm':	/*  print macro expansions  */
X			mdef++;
X			mopt++;
X			continue;
X
X		case 'n':	/*  put line numbers off */
X			nopt-- ;
X			continue;
X
X		case 'o':	/*  list to standard output  */
X			oopt++;
X			continue;
X
X		case 'p':	/*  put out four \n's for eject */
X			popt-- ;
X			continue;
X
X		case 's':	/*  don't produce a symbol list  */
X			sopt++;
X			continue;
X
X		case 't':
X			topt = 0;
X			continue;
X
X		default:	/*  error  */
X			error("Unknown option");
X
X		} else if (files++ == 0) {
X			sourcef = argv[i];
X			strcpy(src, sourcef);
X			suffix(src,".z");
X			if ((now_file = fopen(src, "r")) == NULL)
X				error("Cannot open source file");
X			now_in = 0 ;
X			fin[now_in] = now_file ;
X			src_name[now_in] = src ;
X		} else if (files)
X			error("Too many arguments");
X	}
X
X
X	if (files == 0)
X		error("No source file");
X	strcpy(bin, sourcef);
X	suffix(bin,".hex");
X	if (bopt)
X#ifdef MSDOS
X		if (( fbuf = fopen(bin, "wb")) == NULL)
X#else
X		if (( fbuf = fopen(bin, "w")) == NULL)
X#endif
X			error("Cannot create binary file");
X	if (!lopt && !oopt) {
X		strcpy(listf, sourcef);
X		suffix(listf,".lst");
X		if ((fout = fopen(listf, "w")) == NULL)
X			error("Cannot create list file");
X	} else
X		fout = stdout ;
X	strcpy(mtmp, sourcef);
X	suffix(mtmp,".tmp");
X#ifdef MSDOS
X	mfile = mfopen(mtmp,"w+b") ;
X#else
X	mfile = mfopen(mtmp,"w+") ;
X#endif
X	if (mfile == NULL) {
X		error("Cannot create temp file");
X	}
X	/*unlink(mtmp);*/
X
X	/*
X	 *  get the time
X	 */
X	time(&now);
X	timp = ctime(&now);
X	timp[16] = 0;
X	timp[24] = 0;
X
X	title = sourcef;
X	/*
X	 * pass 1
X	 */
X#ifdef DEBUG
X	fputs("DEBUG-pass 1\n", stderr) ;
X#endif
X	setvars();
X	yyparse();
X	pass2++;
X	ip = &itemtab[-1];
X	while (++ip < itemmax) {
X		/* reset use count */
X		ip->i_uses = 0 ;
X
X		/* set macro names, equated and defined names */
X		switch	(ip->i_token) {
X		case MNAME:
X			ip->i_token = OLDMNAME;
X			break;
X
X		case EQUATED:
X			ip->i_token = WASEQUATED;
X			break;
X
X		case DEFLED:
X			ip->i_token = UNDECLARED;
X			break;
X		}
X	}
X	setvars();
X	fseek(now_file, (long)0, 0);
X
X#ifdef DEBUG
X	fputs("DEBUG- pass 2\n", stderr) ;
X#endif
X	yyparse();
X
X
X	if (bopt) {
X		flushbin();
X		putc(':', fbuf);
X		if (xeq_flag) {
X			puthex(0, fbuf);
X			puthex(xeq >> 8, fbuf);
X			puthex(xeq, fbuf);
X			puthex(1, fbuf);
X			puthex(255-(xeq >> 8)-xeq, fbuf);
X		} else
X			for	(i = 0; i < 10; i++)
X				putc('0', fbuf);
X		putc('\n', fbuf);
X		fflush(fbuf);
X	}
X
X	if (!lopt)
X		fflush(fout);
X	if (writesyms)
X		outsymtab(writesyms);
X	if (eopt)
X		erreport();
X	if (!lopt && !sopt)
X		putsymtab();
X	if (!lopt) {
X		eject();
X		fflush(fout);
X	}
X	exit(0);
X}
X
X
X/*
X *  set some data values before each pass
X */
Xsetvars()
X{
X	register  i;
X
X	peekc = -1;
X	linein[now_in] = linecnt = 0;
X	exp_number = 0;
X	emitptr = emitbuf;
X	lineptr = linebuf;
X	ifptr = ifstack;
X	expifp = expif;
X	*ifptr = 0;
X	dollarsign = 0;
X	olddollar = 0;
X	phaseflag = 0;
X	for (i=0; i<FLAGS; i++) err[i] = 0;
X}
X
X
X
X/*
X *  print out an error message and die
X */
Xerror(as)
Xchar *as;
X{
X
X	*linemax = 0;
X	fprintf(fout, "%s\n", linebuf);
X	fflush(fout);
X	fprintf(stderr, "%s\n", as) ;
X	exit(1);
X}
X
X
X
X/*
X *  output the symbol table
X */
Xputsymtab()
X{
X	register  struct item *tp, *fp;
X	int  i, j, k, t, rows;
X	char c, c1 ;
X
X	if (!nitems)
X		return;
X
X	/* compact the table so unused and UNDECLARED entries are removed */
X	tp = &itemtab[-1];
X	for (fp = itemtab; fp<itemmax; fp++) {
X		if (fp->i_token == UNDECLARED) {
X			nitems--;
X			continue;
X		}
X		if (fp->i_token == 0)
X			continue;
X		tp++;
X		if (tp != fp) {
X			tp->i_string = fp->i_string;
X			tp->i_value = fp->i_value;
X			tp->i_token = fp->i_token;
X			tp->i_uses = fp->i_uses ;
X		}
X	}
X
X	tp++;
X	tp->i_string = "{";
X
X	/*  sort the table */
X	qsort(0, nitems-1);
X
X	title = "**  Symbol Table  **";
X
X	rows = (nitems+3) / 4;
X	if (rows+5+line > 60)
X		eject();
X	lineout();
X	fprintf(fout,"\n\n\nSymbol Table:\n\n") ;
X	line += 4;
X
X	for (i=0; i<rows; i++) {
X		for(j=0; j<4; j++) {
X			k = rows*j+i;
X			if (k < nitems) {
X				tp = &itemtab[k];
X				t = tp->i_token;
X				c = ' ' ;
X				if (t == EQUATED || t == DEFLED)
X					c = '=' ;
X				if (tp->i_uses == 0)
X					c1 = '+' ;
X				else
X					c1 = ' ' ;
X				fprintf(fout, "%-15s%c%4x%c    ",
X					tp->i_string, c, tp->i_value & 0xffff, c1);
X			}
X		}
X		lineout();
X		putc('\n', fout);
X	}
X}
X
X
X
X
X/*
X *  put out error report
X */
Xerreport()
X{
X	register i, numerr;
X
X	if (line > 50) eject();
X	lineout();
X	numerr = 0;
X	for (i=0; i<FLAGS; i++) numerr += keeperr[i];
X	if (numerr) {
X		fputs("\n\n\nError report:\n\n", fout);
X		fprintf(fout, "%6d errors\n", numerr);
X		line += 5;
X	} else {
X		fputs("\n\n\nStatistics:\n", fout);
X		line += 3;
X	}
X
X	for (i=0; i<FLAGS; i++)
X		if (keeperr[i]) {
X			lineout();
X			fprintf(fout, "%6d %c -- %s error\n",
X				keeperr[i], errlet[i], errname[i]);
X		}
X
X	if (line > 55) eject();
X	lineout();
X	fprintf(fout, "\n%6d\tsymbols\n", nitems);
X	fprintf(fout, "%6d\tbytes\n", nbytes);
X	line += 2;
X	if (mfptr) {
X		if (line > 53) eject();
X		lineout();
X		fprintf(fout, "\n%6d\tmacro calls\n", exp_number);
X		fprintf(fout, "%6d\tmacro bytes\n", mfptr);
X		fprintf(fout, "%6d\tinvented symbols\n", invented/2);
X		line += 3;
X	}
X}
X
X
X/*
X *  lexical analyser for macro definition
X */
Xmlex()
X{
X	register  char  *p;
X	register  c;
X	int  t;
X
X	/*
X	 *  move text onto macro file, changing formal parameters
X	 */
X#ifdef	M_DEBUG
X	fprintf(stderr,"enter 'mlex'\t") ;
X#endif
X	inmlex++;
X
X	c = nextchar();
Xloop {
X	switch(charclass[c]) {
X
X	case DIGIT:
X		while (numpart[c]) {
X			putm(c);
X			c = nextchar();
X		}
X		continue;
X
X	case STARTER:
X	case LETTER:
X		t = 0;
X		p = tempbuf+MAXSYMBOLSIZE+2;
X		do {
X			if (p >= tempmax)
X				error(symlong);
X			*p++ = c;
X			if (t < MAXSYMBOLSIZE)
X				tempbuf[t++] = (c >= 'A' && c <= 'Z')  ?
X					c+'a'-'A' : c;
X			c = nextchar();
X		} while (charclass[c]==LETTER || charclass[c]==DIGIT);
X
X		tempbuf[t] = 0;
X		*p++ = '\0';
X		p = tempbuf+MAXSYMBOLSIZE+2;
X		t = tokenofitem(0);
X		if (t != MPARM) while (*p) putm(*p++);
X		else {
X			if (*(yylval.itemptr->i_string) == '?') putm('\2');
X			else putm('\1');
X			putm(yylval.itemptr->i_value + 'A');
X		}
X		if (t == ENDM) goto done;
X		continue;
X
X	case F_END:
X		if (expptr) {
X			popsi();
X			c = nextchar();
X			continue;
X		}
X
X		goto done;
X
X	default:
X		if (c == '\n') {
X			linecnt++;
X		}
X		if (c != '\1') putm(c);
X		c = nextchar();
X	}
X}
X
X	/*
X	 *  finish off the file entry
X	 */
Xdone:
X	while(c != EOF && c != '\n' && c != '\0') c = nextchar();
X	linecnt++;
X	putm('\n');
X	putm('\n');
X	putm(0);
X
X	for (c=0; c<ITEMTABLESIZE; c++)
X		if (itemtab[c].i_token == MPARM) {
X			itemtab[c].i_token = UNDECLARED;
X		}
X	inmlex = 0;
X#ifdef	M_DEBUG
X	fprintf(stderr,"exit 'mlex'\n") ;
X#endif
X}
X
X
X
X/*
X *  lexical analyser for the arguments of a macro call
X */
Xgetarg()
X{
X	register int c;
X	register char *p;
X	static int comma;
X
X	*tempbuf = 0;
X	yylval.cval = tempbuf;
X	while(charclass[c = nextchar()] == SPACE);
X
X	switch(c) {
X
X	case '\0':
X		popsi();
X	case '\n':
X	case ';':
X		comma = 0;
X		return(skipline(c));
X
X	case ',':
X		if (comma) {
X			comma = 0;
X			return(',');
X		}
X		else {
X			comma++;
X			return(ARG);
X		}
X
X	case '\'':
X		p = tempbuf;
X		do switch (c = nextchar()) {
X			case '\0':
X			case '\n':
X				peekc = c;
X				*p = 0;
X				err[bflag]++;
X				return(ARG);
X			case '\'':
X				if ((c = nextchar()) != '\'') {
X					peekc = c;
X					*p = '\0';
X					comma++;
X					return(ARG);
X				}
X			default:
X				*p++ = c;
X		} while (p < tempmax);
X		error(symlong);
X
X	default:  /* unquoted string */
X		p = tempbuf;
X		peekc = c;
X		do switch(c = nextchar()) {
X			case '\0':
X			case '\n':
X			case '\t':
X			case ' ':
X			case ',':
X				peekc = c;
X				*p = '\0';
X				comma++;
X				return(ARG);
X			default:
X				*p++ = c;
X		} while (p < tempmax);
X	}
X}
X
X
X
X
X
X/*
X *  add a suffix to a string
X */
Xsuffix(str,suff)
Xchar *str,*suff;
X{
X	while(*str != '\0' && *str != '.')
X		*str++;
X	strcpy(str, suff);
X}
X
X
X
X
X/*
X *  put out a byte to the macro file, keeping the offset
X */
Xputm(c)
Xchar c ;
X{
X	mfptr++;
X	mfputc(c,mfile) ;
X}
X
X
X
X/*
X *  get a byte from the macro file
X */
Xgetm()
X{
X	int ch;
X
X	floc++;
X	ch = mfgetc(mfile) ;
X	if (ch == EOF) {
X		ch = 0;
X		fprintf(stderr,"bad macro read\n") ;
X	}
X	return(ch);
X}
X
X
X
X/*
X *  pop standard input
X */
Xpopsi()
X{
X	register  i;
X
X	for (i=0; i<PARMMAX; i++) {
X		if (est[i]) free(est[i]);
X	}
X	floc = est[FLOC];
X	free(est);
X	expptr--;
X	est = expptr ? (char **) expstack[expptr-1] : (char **) 0;
X	mfseek(mfile, (long)floc, 0);
X	if (lineptr > linebuf) lineptr--;
X}
X
X
X
X/*
X *  return a unique name for a local symbol
X *  c is the parameter number, n is the macro number.
X */
X
Xchar *
Xgetlocal(c, n)
Xint c,n;
X{
Xstatic char local_label[10];
X	invented++;
X	if (c >= 26)
X		c += 'a' - '0';
X	sprintf(local_label, "?%c%04d", c+'a', n) ;
X	return(local_label);
X}
X
X
X
X/*
X *  read in a symbol table
X */
Xinsymtab(name)
Xchar *name;
X{
X	register struct stab *t;
X	int  s, i, sfile;
X
X	t = (struct stab *) tempbuf;
X#ifdef MSDOS
X	if ((sfile = open(name, O_RDONLY | O_BINARY)) < 0)
X#else
X	if ((sfile = open(name, O_RDONLY)) < 0)
X#endif
X		return;
X	read(sfile, (char *)t, sizeof *t);
X	if (t->t_value != SYMMAJIC)
X		return;
X
X	s = t->t_token;
X	for (i=0; i<s; i++) {
X		read(sfile, (char *)t, sizeof *t);
X		if (tokenofitem(UNDECLARED) != UNDECLARED)
X			continue;
X		yylval.itemptr->i_token = t->t_token;
X		yylval.itemptr->i_value = t->t_value;
X		if (t->t_token == MACRO)
X			yylval.itemptr->i_value += mfptr;
X	}
X
X	while ((s = read(sfile, tempbuf, TEMPBUFSIZE)) > 0) {
X		mfptr += s;
X		mfwrite(tempbuf, 1, s, mfile) ;
X	}
X}
X
X
X
X/*
X *  write out symbol table
X */
Xoutsymtab(name)
Xchar *name;
X{
X	register struct stab *t;
X	register struct item *ip;
X	int  i, sfile;
X
X	t = (struct stab *) tempbuf;
X	if ((sfile = creat(name, 0644)) < 0)
X		return;
X	for (ip=itemtab; ip<itemmax; ip++) {
X		if (ip->i_token == UNDECLARED) {
X			ip->i_token = 0;
X			nitems--;
X		}
X	}
X
X	copyname(title, (char *)t);
X	t->t_value = SYMMAJIC;
X	t->t_token = nitems;
X	write(sfile, (char *)t, sizeof *t);
X
X	for (ip=itemtab; ip<itemmax; ip++) {
X		if (ip->i_token != 0) {
X			t->t_token = ip->i_token;
X			t->t_value = ip->i_value;
X			copyname(ip->i_string, (char *)t);
X			write(sfile, (char *)t, sizeof *t);
X		}
X	}
X
X	mfseek(mfile, (long)0, 0);
X	while((i = mfread(tempbuf, 1, TEMPBUFSIZE, mfile) ) > 0)
X		write(sfile, tempbuf, i);
X}
X
X
X
X/*
X *  copy a name into the symbol file
X */
Xcopyname(st1, st2)
Xchar *st1, *st2;
X{
X	register  char  *s1, *s2;
X	register  i;
X
X	i = (MAXSYMBOLSIZE+2) & ~01;
X	s1 = st1;
X	s2 = st2;
X
X	while(*s2++ = *s1++) i--;
X	while(--i > 0) *s2++ = '\0';
X}
X
X/* get the next source file */
Xnext_source(sp)
Xchar *sp ;
X{
X
X	if(now_in == NEST_IN -1)
X		error("Too many nested includes") ;
X	if ((now_file = fopen(sp, "r")) == NULL) {
X		char ebuf[100] ;
X		sprintf(ebuf,"Can't open include file: %s", sp) ;
X		error(ebuf) ;
X	}
X	if (pass2 && iflist()) {
X		lineout() ;
X		fprintf(fout, "**** %s ****\n",sp) ;
X	}
X
X	/* save the list control flag with the current line number */
X	if (lstoff)
X		linein[now_in] = - linein[now_in] ;
X
X	/* no list if include files are turned off */
X	lstoff |= iopt ;
X
X	/* save the new file descriptor. */
X	fin[++now_in] = now_file ;
X	/* start with line 0 */
X	linein[now_in] = 0 ;
X	/* save away the file name */
X	src_name[now_in] = malloc(strlen(sp)+1) ;
X	strcpy(src_name[now_in],sp) ;
X}
SHAR_EOF
chmod 0755 zmac/zmac.y
rm -f ._seq_
echo "You have unpacked the last part"
exit 0
-- 
"If I'd known it was harmless, I'd have killed it myself"  Phillip K. Dick
Bob Bownes, aka iii, aka captain comrade doktor bobwrench
3 A Pinehurst Ave,	Albany, New York, 12203, (518)-482-8798 voice 
 bownesrm@beowulf.uucp {uunet!steinmetz,rutgers!brspyr1}!beowulf!bownesrm