/* * (c) copyright 1983 by the Vrije Universiteit, Amsterdam, The Netherlands. * * This product is part of the Amsterdam Compiler Kit. * * Permission to use, sell, duplicate or disclose this software must be * obtained in writing. Requests for such permissions may be sent to * * Dr. Andrew S. Tanenbaum * Wiskundig Seminarium * Vrije Universiteit * Postbox 7161 * 1007 MC Amsterdam * The Netherlands * */ #include "ip_spec.h" #include #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(); } return 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 '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 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]; int elows[256], lows[256]; #define NMNEM (sp_lmnem-sp_fmnem+1) #define MUST 1 #define MAY 2 #define FORB 3 char negc[NMNEM], zc[NMNEM], posc[NMNEM] ; checkall() { register i,flag ; register struct opform *next ; int opc,low ; for ( i=0 ; ii_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 : case OP64 : 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 ; opc1 ) 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)) ; 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("DISPATCH\n"); for (i = 0; i < 256;) { if (!(i % 8)) printf("%d\t", i); printf(ename(codes[i])); if (i < 254) { prx(flags[i],lows[i],i); } else putchar('\t'); i++; if (!(i % 8)) putchar('\n'); } printf("DISPATCH2\n"); for (i = 0; i < 256;) { int x = 0; if (ecodes[i] != -1) { if (!(i % 8)) printf("%d\t", i); printf(ename(ecodes[i])); prx(eflags[i],elows[i],i); } else x = 1; i++; if (!(i % 8)) { putchar('\n'); if (x) break; } } printf("DISPATCH3\n"); i = 0; while (lcodes[i] != -1) { if (!(i % 8)) printf("%d\t", i); printf("%s\t", ename(ecodes[i])); i++; if (!(i % 8)) putchar('\n'); } if (i % 8) putchar('\n'); } prx(flg,low,opc) register int flg; { int arg = opc - low; putchar('.'); switch(flg&OPTYPE) { case OPNO: putchar('z'); 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 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'); } putchar('\t'); }