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