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