ack/doc/em/mkdispatch.c
1988-11-11 19:13:26 +00:00

493 lines
10 KiB
C

/*
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
* See the copyright notice in the ACK home directory, in the file "Copyright".
*
*/
#include "ip_spec.h"
#include <stdio.h>
#include "em_spec.h"
#include "em_flag.h"
#ifndef NORCSID
static char rcs_id[] = "$Header$" ;
#endif
/* This program reads the human readable interpreter specification
and produces a efficient machine representation that can be
translated by a C-compiler.
*/
#define NOTAB 600 /* The max no of interpreter specs */
#define ESCAP1 256
#define ESCAP2 257
struct opform intable[NOTAB] ;
struct opform *lastform = intable-1 ;
int nerror = 0 ;
int atend = 0 ;
int line = 1 ;
extern char em_mnem[][4] ;
char esca1[] = "escape1" ;
char esca2[] = "escape2" ;
#define ename(no) ((no)==ESCAP1?esca1:(no)==ESCAP2?esca2:em_mnem[(no)])
extern char em_flag[] ;
main(argc,argv) char **argv ; {
if ( argc>1 ) {
if ( freopen(argv[1],"r",stdin)==NULL) {
fatal("Cannot open %s",argv[1]) ;
}
}
if ( argc>2 ) {
if ( freopen(argv[2],"w",stdout)==NULL) {
fatal("Cannot create %s",argv[2]) ;
}
}
if ( argc>3 ) {
fatal("%s [ file [ file ] ]",argv[0]) ;
}
atend=0 ;
readin();
atend=1 ;
checkall();
if ( nerror==0 ) {
writeout();
}
exit(nerror) ;
}
readin() {
register struct opform *nextform ;
char *ident();
char *firstid ;
for ( nextform=intable ;
!feof(stdin) && nextform<&intable[NOTAB] ; ) {
firstid=ident() ;
if ( *firstid=='\n' || feof(stdin) ) continue ;
lastform=nextform ;
nextform->i_opcode = getmnem(firstid) ;
nextform->i_flag = decflag(ident()) ;
switch ( nextform->i_flag&OPTYPE ) {
case OPMINI:
case OPSHORT:
nextform->i_num = atoi(ident()) ;
break ;
}
nextform->i_low = atoi(ident()) ;
if ( *ident()!='\n' ) {
int c ;
error("End of line expected");
while ( (c=readchar())!='\n' && c!=EOF ) ;
}
nextform++ ;
}
if ( !feof(stdin) ) fatal("Internal table too small") ;
}
char *ident() {
/* skip spaces and tabs, anything up to space,tab or eof is
a identifier.
Anything from # to end-of-line is an end-of-line.
End-of-line is an identifier all by itself.
*/
static char array[200] ;
register int c ;
register char *cc ;
do {
c=readchar() ;
} while ( c==' ' || c=='\t' ) ;
for ( cc=array ; cc<&array[(sizeof array) - 1] ; cc++ ) {
if ( c=='#' ) {
do {
c=readchar();
} while ( c!='\n' && c!=EOF ) ;
}
*cc = c ;
if ( c=='\n' && cc==array ) break ;
c=readchar() ;
if ( c=='\n' ) {
pushback(c) ;
break ;
}
if ( c==' ' || c=='\t' || c==EOF ) break ;
}
*++cc=0 ;
return array ;
}
int getmnem(str) char *str ; {
char (*ptr)[4] ;
for ( ptr = em_mnem ; *ptr<= &em_mnem[sp_lmnem-sp_fmnem][0] ; ptr++ ) {
if ( strcmp(*ptr,str)==0 ) return (ptr-em_mnem) ;
}
error("Illegal mnemonic") ;
return 0 ;
}
error(str,a1,a2,a3,a4,a5,a6) /* VARARGS1 */ char *str ; {
if ( !atend ) fprintf(stderr,"line %d: ",line) ;
fprintf(stderr,str,a1,a2,a3,a4,a5,a6) ;
fprintf(stderr,"\n");
nerror++ ;
}
mess(str,a1,a2,a3,a4,a5,a6) /* VARARGS1 */ char *str ; {
if ( !atend ) fprintf(stderr,"line %d: ",line) ;
fprintf(stderr,str,a1,a2,a3,a4,a5,a6) ;
fprintf(stderr,"\n");
}
fatal(str,a1,a2,a3,a4,a5,a6) /* VARARGS1 */ char *str ; {
error(str,a1,a2,a3,a4,a5,a6) ;
exit(1) ;
}
#define ILLGL -1
check(val) int val ; {
if ( val!=ILLGL ) error("Illegal flag combination") ;
}
int decflag(str) char *str ; {
int type ;
int escape ;
int range ;
int wordm ;
int notzero ;
type=escape=range=wordm=notzero= ILLGL ;
while ( *str ) switch ( *str++ ) {
case 'm' :
check(type) ; type=OPMINI ; break ;
case 's' :
check(type) ; type=OPSHORT ; break ;
case '-' :
check(type) ; type=OPNO ; break ;
case '1' :
check(type) ; type=OP8 ; break ;
case '2' :
check(type) ; type=OP16 ; break ;
case '4' :
check(type) ; type=OP32 ; break ;
case '8' :
check(type) ; type=OP64 ; break ;
case 'u' :
check(type) ; type=OP16U ; break ;
case 'e' :
check(escape) ; escape=0 ; break ;
case 'N' :
check(range) ; range= 2 ; break ;
case 'P' :
check(range) ; range= 1 ; break ;
case 'w' :
check(wordm) ; wordm=0 ; break ;
case 'o' :
check(notzero) ; notzero=0 ; break ;
default :
error("Unknown flag") ;
}
if ( type==ILLGL ) error("Type must be specified") ;
switch ( type ) {
case OP64 :
case OP32 :
if ( escape!=ILLGL ) error("Conflicting escapes") ;
escape=ILLGL ;
case OP16 :
case OP16U :
case OP8 :
case OPSHORT :
case OPNO :
if ( notzero!=ILLGL ) mess("Improbable OPNZ") ;
if ( type==OPNO && range!=ILLGL ) {
mess("No operand in range") ;
}
}
if ( escape!=ILLGL ) type|=OPESC ;
if ( wordm!=ILLGL ) type|=OPWORD ;
switch ( range) {
case ILLGL : type|=OP_BOTH ;
if ( type==OPMINI || type==OPSHORT )
error("Minies and shorties must have P or N") ;
break ;
case 1 : type|=OP_POS ; break ;
case 2 : type|=OP_NEG ; break ;
}
if ( notzero!=ILLGL ) type|=OPNZ ;
return type ;
}
/* ----------- checking --------------*/
int ecodes[256],codes[256],lcodes[256] ;
char eflags[256], flags[256], lflags[256] ;
int elows[256], lows[256], llows[256];
#define NMNEM (sp_lmnem-sp_fmnem+1)
#define MUST 1
#define MAY 2
#define FORB 3
char negc[NMNEM], zc[NMNEM], posc[NMNEM], lnegc[NMNEM], lposc[NMNEM] ;
checkall() {
register i,flag ;
register struct opform *next ;
int opc,low ;
for ( i=0 ; i<NMNEM ; i++ ) negc[i]=zc[i]=posc[i]=0 ;
for ( i=0 ; i<256 ; i++ ) lcodes[i]= codes[i]= ecodes[i]= -1 ;
codes[254]=ESCAP1; codes[255]=ESCAP2;
atend=0 ; line=0 ;
for ( next=intable ; next<=lastform ; next++ ) {
line++ ;
flag = next->i_flag&0377 ;
opc = next->i_opcode&0377 ;
low = next->i_low&0377 ;
chkc(flag,low,opc,low) ;
switch(flag&OPTYPE) {
case OPNO : zc[opc]++ ; break ;
case OPMINI :
case OPSHORT :
for ( i=1 ; i<((next->i_num)&0377) ; i++ ) {
chkc(flag,low+i,opc,low) ;
}
if ( !(em_flag[opc]&PAR_G) &&
(flag&OPRANGE)==OP_BOTH) {
mess("Mini's and shorties should have P or N");
}
break ;
case OP8 :
error("OP8 is removed") ;
break ;
case OP16 :
if ( flag&OP_NEG )
negc[opc]++ ;
else if ( flag&OP_POS )
posc[opc]++ ;
break ;
case OP32 :
if ( flag&OP_NEG )
lnegc[opc]++ ;
else if ( flag&OP_POS )
lposc[opc]++ ;
break ;
case OP16U :
break ;
default :
error("Illegal type") ;
break ;
}
}
atend=1 ;
for ( i=0 ; i<256 ; i++ ) if ( codes[i]== -1 ) {
mess("interpreter opcode %d not used",i) ;
}
for ( opc=0 ; opc<NMNEM ; opc++ ) {
switch(em_flag[opc]&EM_PAR) {
case PAR_NO :
ckop(opc,MUST,FORB,FORB) ;
break ;
case PAR_C:
case PAR_D:
case PAR_F:
case PAR_B:
ckop(opc,FORB,MAY,MAY) ;
break ;
case PAR_N:
case PAR_G:
case PAR_S:
case PAR_Z:
case PAR_O:
case PAR_P:
ckop(opc,FORB,MAY,FORB) ;
break ;
case PAR_R:
ckop(opc,FORB,MAY,FORB) ;
break ;
case PAR_L:
ckop(opc,FORB,MUST,MUST) ;
break ;
case PAR_W:
ckop(opc,MUST,MAY,FORB) ;
break ;
default :
error("Unknown instruction type of %s",ename(opc)) ;
break ;
}
}
}
chkc(flag,icode,emc,low) {
if ( flag&OPESC ) {
if ( ecodes[icode]!=-1 ) {
mess("Escaped opcode %d used by %s and %s",
icode,ename(emc),ename(ecodes[icode])) ;
}
ecodes[icode]=emc;
eflags[icode]=flag;
elows[icode]=low;
} else switch ( flag&OPTYPE ) {
default:
if ( codes[icode]!=-1 ) {
mess("Opcode %d used by %s and %s",
icode,ename(emc),ename(codes[icode])) ;
}
codes[icode]=emc;
flags[icode]=flag;
lows[icode]=low;
break ;
case OP32:
case OP64:
if ( lcodes[icode]!=-1 ) {
mess("Long opcode %d used by %s and %s",
icode,ename(emc),ename(lcodes[icode])) ;
}
lcodes[icode]=emc;
lflags[icode]=flag;
llows[icode]=low;
break ;
}
}
ckop(emc,zf,pf,nf) {
if ( zc[emc]>1 ) mess("More then one OPNO for %s",ename(emc)) ;
if ( posc[emc]>1 ) mess("More then one OP16(pos) for %s",ename(emc)) ;
if ( negc[emc]>1 ) mess("More then one OP16(neg) for %s",ename(emc)) ;
if ( lposc[emc]>1 ) mess("More then one OP32(pos) for %s",ename(emc)) ;
if ( lnegc[emc]>1 ) mess("More then one OP32(neg) for %s",ename(emc)) ;
switch(zf) {
case MUST:
if ( zc[emc]==0 ) mess("No OPNO for %s",ename(emc)) ;
break ;
case FORB:
if ( zc[emc]==1 ) mess("Forbidden OPNO for %s",ename(emc)) ;
break ;
}
switch(pf) {
case MUST:
if ( posc[emc]==0 ) mess("No OP16(pos) for %s",ename(emc)) ;
break ;
case FORB:
if ( posc[emc]==1 )
mess("Forbidden OP16(pos) for %s",ename(emc)) ;
break ;
}
switch(nf) {
case MUST:
if ( negc[emc]==0 ) mess("No OP16(neg) for %s",ename(emc)) ;
break ;
case FORB:
if ( negc[emc]==1 )
mess("Forbidden OP16(neg) for %s",ename(emc)) ;
break ;
}
}
static int pushchar ;
static int pushf ;
int readchar() {
int c ;
if ( pushf ) {
pushf=0 ;
c = pushchar ;
} else {
if ( feof(stdin) ) return EOF ;
c=getc(stdin) ;
}
if ( c=='\n' ) line++ ;
return c ;
}
pushback(c) {
if ( pushf ) {
fatal("Double pushback") ;
}
pushf++ ;
pushchar=c ;
if ( c=='\n' ) line-- ;
}
writeout() {
register int i;
printf("DISPATCH1");
for (i = 0; i < 256;) {
if (!(i % 8)) printf("\n%d", i);
printf("\t%s", ename(codes[i]));
if (i < 254) {
prx(flags[i],lows[i],i);
}
i++;
}
printf("\nDISPATCH2");
for (i = 0; i < 256;) {
if (ecodes[i] != -1) {
if (!(i % 8)) printf("\n%d", i);
printf("\t%s", ename(ecodes[i]));
prx(eflags[i],elows[i],i);
}
else break;
i++;
}
printf("\nDISPATCH3");
i = 0;
while (lcodes[i] != -1) {
if (!(i % 8)) printf("\n%d", i);
printf("\t%s", ename(lcodes[i]));
prx(lflags[i],llows[i],i);
i++;
}
while (i++ % 8) putchar('\t');
putchar('\n');
}
prx(flg,low,opc)
register int flg;
{
int arg = opc - low;
putchar('.');
switch(flg&OPTYPE) {
case OPNO:
putchar('z');
break;
case OP16U:
putchar('u');
break;
case OP16:
if (flg&OP_POS) putchar('p');
else if (flg&OP_NEG) putchar('n');
else putchar('l');
if (flg&OPWORD) putchar('w');
break;
case OP32:
if (flg&OP_POS) putchar('P');
else if (flg&OP_NEG) putchar('N');
else putchar('L');
if (flg&OPWORD) putchar('w');
break;
case OPSHORT:
if (flg & OPWORD) putchar('w');
else putchar('s');
/* fall through */
case OPMINI:
if (flg & OPNZ) arg++;
if (flg & OP_NEG) arg = -arg - 1;
printf("%d",arg);
if((flg&OPTYPE) == OPMINI && (flg & OPWORD)) putchar('W');
}
}