Pristine Ack-5.5
[Ack-5.5.git] / doc / em / mkdispatch.c
1 /*
2  * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
3  * See the copyright notice in the ACK home directory, in the file "Copyright".
4  *
5  */
6
7 #include "ip_spec.h"
8 #include <stdio.h>
9 #include "em_spec.h"
10 #include "em_flag.h"
11
12 #ifndef NORCSID
13 static char rcs_id[] = "$Id: mkdispatch.c,v 1.6 1994/06/24 10:03:13 ceriel Exp $" ;
14 #endif
15
16 /* This program reads the human readable interpreter specification
17    and produces a efficient machine representation that can be
18    translated by a C-compiler.
19 */
20
21 #define NOTAB   600    /* The max no of interpreter specs */
22 #define ESCAP1  256
23 #define ESCAP2  257
24
25 struct opform intable[NOTAB] ;
26 struct opform *lastform = intable-1 ;
27
28 int nerror = 0 ;
29 int atend  = 0 ;
30 int line   = 1 ;
31
32 extern char em_mnem[][4] ;
33 char esca1[] = "escape1" ;
34 char esca2[] = "escape2" ;
35 #define ename(no)       ((no)==ESCAP1?esca1:(no)==ESCAP2?esca2:em_mnem[(no)])
36
37 extern char em_flag[] ;
38
39 main(argc,argv) char **argv ; {
40         if ( argc>1 ) {
41                 if ( freopen(argv[1],"r",stdin)==NULL) {
42                         fatal("Cannot open %s",argv[1]) ;
43                 }
44         }
45         if ( argc>2 ) {
46                 if ( freopen(argv[2],"w",stdout)==NULL) {
47                         fatal("Cannot create %s",argv[2]) ;
48                 }
49         }
50         if ( argc>3 ) {
51                 fatal("%s [ file [ file ] ]",argv[0]) ;
52         }
53         atend=0 ;
54         readin();
55         atend=1 ;
56         checkall();
57         if ( nerror==0 ) {
58                 writeout();
59         }
60         exit(nerror) ;
61 }
62
63 readin() {
64         register struct opform *nextform ;
65         char *ident();
66         char *firstid ;
67
68         for ( nextform=intable ;
69                 !feof(stdin) && nextform<&intable[NOTAB] ; ) {
70                 firstid=ident() ;
71                 if ( *firstid=='\n' || feof(stdin) ) continue ;
72                 lastform=nextform ;
73                 nextform->i_opcode = getmnem(firstid) ;
74                 nextform->i_flag   = decflag(ident()) ;
75                 switch ( nextform->i_flag&OPTYPE ) {
76                 case OPMINI:
77                 case OPSHORT:
78                         nextform->i_num = atoi(ident()) ;
79                         break ;
80                 }
81                 nextform->i_low    = atoi(ident())    ;
82                 if ( *ident()!='\n' ) {
83                         int c ;
84                         error("End of line expected");
85                         while ( (c=readchar())!='\n' && c!=EOF ) ;
86                 }
87                 nextform++ ;
88         }
89         if ( !feof(stdin) ) fatal("Internal table too small") ;
90 }
91
92 char *ident() {
93         /* skip spaces and tabs, anything up to space,tab or eof is
94            a identifier.
95            Anything from # to end-of-line is an end-of-line.
96            End-of-line is an identifier all by itself.
97         */
98
99         static char array[200] ;
100         register int c ;
101         register char *cc ;
102
103         do {
104                 c=readchar() ;
105         } while ( c==' ' || c=='\t' ) ;
106         for ( cc=array ; cc<&array[(sizeof array) - 1] ; cc++ ) {
107                 if ( c=='#' ) {
108                         do {
109                                 c=readchar();
110                         } while ( c!='\n' && c!=EOF ) ;
111                 }
112                 *cc = c ;
113                 if ( c=='\n' && cc==array ) break ;
114                 c=readchar() ;
115                 if ( c=='\n' ) {
116                         pushback(c) ;
117                         break ;
118                 }
119                 if ( c==' ' || c=='\t' || c==EOF ) break ;
120         }
121         *++cc=0 ;
122         return array ;
123 }
124
125 int getmnem(str) char *str ; {
126         char (*ptr)[4] ;
127
128         for ( ptr = em_mnem ; *ptr<= &em_mnem[sp_lmnem-sp_fmnem][0] ; ptr++ ) {
129                 if ( strcmp(*ptr,str)==0 ) return (ptr-em_mnem) ;
130         }
131         error("Illegal mnemonic") ;
132         return 0 ;
133 }
134
135 error(str,a1,a2,a3,a4,a5,a6) /* VARARGS1 */ char *str ; {
136         if ( !atend ) fprintf(stderr,"line %d: ",line) ;
137         fprintf(stderr,str,a1,a2,a3,a4,a5,a6) ;
138         fprintf(stderr,"\n");
139         nerror++ ;
140 }
141
142 mess(str,a1,a2,a3,a4,a5,a6) /* VARARGS1 */ char *str ; {
143         if ( !atend ) fprintf(stderr,"line %d: ",line) ;
144         fprintf(stderr,str,a1,a2,a3,a4,a5,a6) ;
145         fprintf(stderr,"\n");
146 }
147
148 fatal(str,a1,a2,a3,a4,a5,a6) /* VARARGS1 */ char *str ; {
149         error(str,a1,a2,a3,a4,a5,a6) ;
150         exit(1) ;
151 }
152
153 #define ILLGL   -1
154
155 check(val) int val ; {
156         if ( val!=ILLGL ) error("Illegal flag combination") ;
157 }
158
159 int decflag(str) char *str ; {
160         int type ;
161         int escape ;
162         int range ;
163         int wordm ;
164         int notzero ;
165
166         type=escape=range=wordm=notzero= ILLGL ;
167         while ( *str ) switch ( *str++ ) {
168         case 'm' :
169                 check(type) ; type=OPMINI ; break ;
170         case 's' :
171                 check(type) ; type=OPSHORT ; break ;
172         case '-' :
173                 check(type) ; type=OPNO ; break ;
174         case '1' :
175                 check(type) ; type=OP8 ; break ;
176         case '2' :
177                 check(type) ; type=OP16 ; break ;
178         case '4' :
179                 check(type) ; type=OP32 ; break ;
180         case '8' :
181                 check(type) ; type=OP64 ; break ;
182         case 'u' :
183                 check(type) ; type=OP16U ; break ;
184         case 'e' :
185                 check(escape) ; escape=0 ; break ;
186         case 'N' :
187                 check(range) ; range= 2 ; break ;
188         case 'P' :
189                 check(range) ; range= 1 ; break ;
190         case 'w' :
191                 check(wordm) ; wordm=0 ; break ;
192         case 'o' :
193                 check(notzero) ; notzero=0 ; break ;
194         default :
195                 error("Unknown flag") ;
196         }
197         if ( type==ILLGL ) error("Type must be specified") ;
198         switch ( type ) {
199         case OP64 :
200         case OP32 :
201                 if ( escape!=ILLGL ) error("Conflicting escapes") ;
202                 escape=ILLGL ;
203         case OP16 :
204         case OP16U :
205         case OP8 :
206         case OPSHORT :
207         case OPNO :
208                 if ( notzero!=ILLGL ) mess("Improbable OPNZ") ;
209                 if ( type==OPNO && range!=ILLGL ) {
210                         mess("No operand in range") ;
211                 }
212         }
213         if ( escape!=ILLGL ) type|=OPESC ;
214         if ( wordm!=ILLGL ) type|=OPWORD ;
215         switch ( range) {
216         case ILLGL : type|=OP_BOTH ;
217                      if ( type==OPMINI || type==OPSHORT )
218                              error("Minies and shorties must have P or N") ;
219                      break ;
220         case 1     : type|=OP_POS  ; break ;
221         case 2     : type|=OP_NEG  ; break ;
222         }
223         if ( notzero!=ILLGL ) type|=OPNZ ;
224         return type ;
225 }
226
227 /* ----------- checking --------------*/
228
229 int ecodes[256],codes[256],lcodes[256] ;
230 char eflags[256], flags[256], lflags[256] ;
231 int elows[256], lows[256], llows[256];
232
233 #define NMNEM   (sp_lmnem-sp_fmnem+1)
234 #define MUST    1
235 #define MAY     2
236 #define FORB    3
237
238 char negc[NMNEM], zc[NMNEM], posc[NMNEM], lnegc[NMNEM], lposc[NMNEM] ;
239
240 checkall() {
241         register i,flag ;
242         register struct opform *next ;
243         int opc,low ;
244
245         for ( i=0 ; i<NMNEM ; i++ ) negc[i]=zc[i]=posc[i]=0 ;
246         for ( i=0 ; i<256 ; i++ ) lcodes[i]= codes[i]= ecodes[i]= -1 ;
247         codes[254]=ESCAP1; codes[255]=ESCAP2;
248
249         atend=0 ; line=0 ;
250         for ( next=intable ; next<=lastform ; next++ ) {
251                 line++ ;
252                 flag = next->i_flag&0377 ;
253                 opc  = next->i_opcode&0377 ;
254                 low  = next->i_low&0377 ;
255                 chkc(flag,low,opc,low) ;
256                 switch(flag&OPTYPE) {
257                 case OPNO : zc[opc]++ ; break ;
258                 case OPMINI :
259                 case OPSHORT :
260                         for ( i=1 ; i<((next->i_num)&0377) ; i++ ) {
261                                 chkc(flag,low+i,opc,low) ;
262                         }
263                         if ( !(em_flag[opc]&PAR_G) &&
264                              (flag&OPRANGE)==OP_BOTH) {
265               mess("Mini's and shorties should have P or N");
266                         }
267                         break ;
268                 case OP8 :
269                         error("OP8 is removed") ;
270                         break ;
271                 case OP16 :
272                         if ( flag&OP_NEG )
273                                 negc[opc]++ ;
274                         else if ( flag&OP_POS )
275                                 posc[opc]++ ;
276                         break ;
277                 case OP32 :
278                         if ( flag&OP_NEG )
279                                 lnegc[opc]++ ;
280                         else if ( flag&OP_POS )
281                                 lposc[opc]++ ;
282                         break ;
283                 case OP16U :
284                         break ;
285                 default :
286                         error("Illegal type") ;
287                         break ;
288                 }
289         }
290         atend=1 ;
291         for ( i=0 ; i<256 ; i++ ) if ( codes[i]== -1 ) {
292                 mess("interpreter opcode %d not used",i) ;
293         }
294         for ( opc=0 ; opc<NMNEM ; opc++ ) {
295                 switch(em_flag[opc]&EM_PAR) {
296                 case PAR_NO :
297                         ckop(opc,MUST,FORB,FORB) ;
298                         break ;
299                 case PAR_C:
300                 case PAR_D:
301                 case PAR_F:
302                 case PAR_B:
303                         ckop(opc,FORB,MAY,MAY) ;
304                         break ;
305                 case PAR_N:
306                 case PAR_G:
307                 case PAR_S:
308                 case PAR_Z:
309                 case PAR_O:
310                 case PAR_P:
311                         ckop(opc,FORB,MAY,FORB) ;
312                         break ;
313                 case PAR_R:
314                         ckop(opc,FORB,MAY,FORB) ;
315                         break ;
316                 case PAR_L:
317                         ckop(opc,FORB,MUST,MUST) ;
318                         break ;
319                 case PAR_W:
320                         ckop(opc,MUST,MAY,FORB) ;
321                         break ;
322                 default :
323                         error("Unknown instruction type of %s",ename(opc)) ;
324                         break ;
325                 }
326         }
327 }
328
329 chkc(flag,icode,emc,low) {
330         if ( flag&OPESC ) {
331                 if ( ecodes[icode]!=-1 ) {
332                         mess("Escaped opcode %d used by %s and %s",
333                                 icode,ename(emc),ename(ecodes[icode])) ;
334                 }
335                 ecodes[icode]=emc;
336                 eflags[icode]=flag;
337                 elows[icode]=low;
338         } else switch ( flag&OPTYPE ) {
339         default:
340                 if ( codes[icode]!=-1 ) {
341                         mess("Opcode %d used by %s and %s",
342                                 icode,ename(emc),ename(codes[icode])) ;
343                 }
344                 codes[icode]=emc;
345                 flags[icode]=flag;
346                 lows[icode]=low;
347                 break ;
348         case OP32:
349         case OP64:
350                 if ( lcodes[icode]!=-1 ) {
351                         mess("Long opcode %d used by %s and %s",
352                                 icode,ename(emc),ename(lcodes[icode])) ;
353                 }
354                 lcodes[icode]=emc;
355                 lflags[icode]=flag;
356                 llows[icode]=low;
357                 break ;
358         }
359 }
360
361 ckop(emc,zf,pf,nf) {
362         if ( zc[emc]>1 ) mess("More then one OPNO for %s",ename(emc)) ;
363         if ( posc[emc]>1 ) mess("More then one OP16(pos) for %s",ename(emc)) ;
364         if ( negc[emc]>1 ) mess("More then one OP16(neg) for %s",ename(emc)) ;
365         if ( lposc[emc]>1 ) mess("More then one OP32(pos) for %s",ename(emc)) ;
366         if ( lnegc[emc]>1 ) mess("More then one OP32(neg) for %s",ename(emc)) ;
367         switch(zf) {
368         case MUST:
369                 if ( zc[emc]==0 ) mess("No OPNO for %s",ename(emc)) ;
370                 break ;
371         case FORB:
372                 if ( zc[emc]==1 ) mess("Forbidden OPNO for %s",ename(emc)) ;
373                 break ;
374         }
375         switch(pf) {
376         case MUST:
377                 if ( posc[emc]==0 ) mess("No OP16(pos) for %s",ename(emc)) ;
378                 break ;
379         case FORB:
380                 if ( posc[emc]==1 )
381                         mess("Forbidden OP16(pos) for %s",ename(emc)) ;
382                 break ;
383         }
384         switch(nf) {
385         case MUST:
386                 if ( negc[emc]==0 ) mess("No OP16(neg) for %s",ename(emc)) ;
387                 break ;
388         case FORB:
389                 if ( negc[emc]==1 )
390                         mess("Forbidden OP16(neg) for %s",ename(emc)) ;
391                 break ;
392         }
393 }
394
395 static int pushchar ;
396 static int pushf ;
397
398 int readchar() {
399         int c ;
400
401         if ( pushf ) {
402                 pushf=0 ;
403                 c = pushchar ;
404         } else {
405                 if ( feof(stdin) ) return EOF ;
406                 c=getc(stdin) ;
407         }
408         if ( c=='\n' ) line++ ;
409         return c ;
410 }
411
412 pushback(c) {
413         if ( pushf ) {
414                 fatal("Double pushback") ;
415         }
416         pushf++ ;
417         pushchar=c ;
418         if ( c=='\n' ) line-- ;
419 }
420
421 writeout() {
422         register int i;
423
424         printf("DISPATCH1");
425         for (i = 0; i < 256;) {
426                 if (!(i % 8)) printf("\n%d", i);
427                 printf("\t%s", ename(codes[i]));
428                 if (i < 254) {
429                         prx(flags[i],lows[i],i);
430                 }
431                 i++;
432         }
433
434         printf("\nDISPATCH2");
435         for (i = 0; i < 256;) {
436                 if (ecodes[i] != -1) {
437                         if (!(i % 8)) printf("\n%d", i);
438                         printf("\t%s", ename(ecodes[i]));
439                         prx(eflags[i],elows[i],i);
440                 }
441                 else break;
442                 i++;
443         }
444
445         printf("\nDISPATCH3");
446         i = 0;
447         while (lcodes[i] != -1) {
448                 if (!(i % 8)) printf("\n%d", i);
449                 printf("\t%s", ename(lcodes[i]));
450                         prx(lflags[i],llows[i],i);
451                 i++;
452         }
453         while (i++ % 8) putchar('\t');
454         putchar('\n');
455 }
456
457 prx(flg,low,opc)
458         register int flg;
459 {
460         int arg = opc - low;
461
462         putchar('.');
463         switch(flg&OPTYPE) {
464         case OPNO:
465                 putchar('z');
466                 break;
467         case OP16U:
468                 putchar('u');
469                 break;
470         case OP16:
471                 if (flg&OP_POS) putchar('p');
472                 else if (flg&OP_NEG) putchar('n');
473                 else putchar('l');
474                 if (flg&OPWORD) putchar('w');
475                 break;
476         case OP32:
477                 if (flg&OP_POS) putchar('P');
478                 else if (flg&OP_NEG) putchar('N');
479                 else putchar('L');
480                 if (flg&OPWORD) putchar('w');
481                 break;
482         case OPSHORT:
483                 if (flg & OPWORD) putchar('w');
484                 else putchar('s');
485                 /* fall through */
486         case OPMINI:
487                 if (flg & OPNZ) arg++;
488                 if (flg & OP_NEG) arg = -arg - 1;
489                 printf("%d",arg);
490                 if((flg&OPTYPE) == OPMINI && (flg & OPWORD)) putchar('W');
491         }
492 }