|
|
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) ;
}