|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T z
Length: 50295 (0xc477) Types: TextFile Names: »zmac.y«
└─⟦a0efdde77⟧ Bits:30001252 EUUGD11 Tape, 1987 Spring Conference Helsinki └─⟦this⟧ »EUUGD11/euug-87hel/sec1/zmac/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) ; }