Version bump for last commit; now at v2.0.23.
[rmac] / kwgen.c
1 //
2 // RMAC - Reboot's Macro Assembler for all Atari computers
3 // KWGEN.C - Keyword & Mnemonic Definition and State Machine Creation Tool
4 // Copyright (C) 199x Landon Dyer, 2011-2020 Reboot and Friends
5 // RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
6 // Source utilised with the kind permission of Landon Dyer
7 //
8
9 /*
10  *  keyword transition-table generation utility
11  *
12  *
13  *----------------
14  *
15  * SYNOPSIS:    kw basename <file1 >file2
16  *
17  *  `-d' turns on debugging messages
18  *
19  *  Accepts a list of keywords and corresponding values.  Lines
20  *  beginning with '#' are comments.  Values may be empty (resulting
21  *  in a default value of the previous item's value plus 1, or zero
22  *  if there is no previous item), decimal numbers, or characters
23  *  enclosed between single quotes.
24  *
25  *      # this is a comment
26  *      .byte 34
27  *      .word 'A'
28  *      .long
29  *
30  *  The `basename' is a string prepended to the beginning of each of
31  *  the output array names, and should be one or two characters.
32  *
33  */
34 #include <stdio.h>
35 #include <ctype.h>
36 #include <stdlib.h>
37 #include <string.h>
38
39 /*
40  *  Tunable definitions
41  *
42  */
43 #define TABSIZE 2048            /* state table size */
44 #define NSTRINGS 1024           /* maximum number of keywords */
45 #define STRPOOLSIZ (NSTRINGS * 10) /* size of string pool */
46
47
48 /*
49  *  Do not change these
50  */
51 #define EOS     '\0'            /* null */
52 #define UNUSED  -1              /* slot in ktab[] is unused */
53 #define MARKED  -2              /* slot in ktab[] is used, not assigned yet */
54
55
56 /*
57  *  Table-building tables
58  */
59 int kmax = 0;                   /* largest index into ktab */
60 int ktab[TABSIZE];              /* next state number (or -1) */
61 int kcheck[TABSIZE];            /* check state number (or -1) */
62 int kaccept[TABSIZE];           /* accept (or -1) */
63 int kbase[TABSIZE];             /* ktab[] index for a state `i' */
64 int nstates;                    /* number of states in kbase[] */
65
66 /*
67  *  Temporary tables
68  */
69 int tab[128];                   /* tmp table for building ktab[] */
70 int accept[128];                /* tmp table for building accept[] */
71
72 struct name_entry {
73         char *nstr;                     /* -> name string */
74         int nval;                       /* = name's value */
75 } namtab[NSTRINGS];
76
77 int nnames;                     /* number of keywords */
78 char strpool[STRPOOLSIZ];       /* pool for keyword text */
79 char *basename;                 /* -> string to prepend to array names */
80 char uppername[100];            /* all-uppercase version of basename */
81 int debug = 0;                  /* 1, enable debugging messages */
82
83 int comp_entry();
84 void panic(char *);
85 int nmatch(int, char *, char *);
86 void wiredown(void);
87 void print_tables(void);
88 void dumptab(char *, char *, int *, int);
89 void traverse(int);
90
91
92 int main(int argc, char ** argv)
93 {
94         register int i, /*j,*/ k, w;
95         char *s, *s1;
96         int found1;
97         int valid = 0;
98         //int base;
99         int state;
100
101         if (argc != 2)
102         {
103                 panic("bad commandline");
104         }
105
106         basename = argv[1];
107
108         for(s=basename, s1=uppername; *s; ++s, ++s1)
109                 *s1 = (char)toupper(*s);
110
111         *s1 = EOS;
112
113         /*
114          *  init tables
115          */
116         for(i=0; i<TABSIZE; ++i)
117         {
118                 ktab[i] = -1;
119                 kcheck[i] = -1;
120                 kaccept[i] = -1;
121         }
122
123         nstates = 0;
124
125         /*
126          *  read keyword list
127          *
128          */
129         s = strpool;
130
131 //      while (gets(s) != NULL)
132         while (fgets(s, STRPOOLSIZ, stdin) != NULL)
133         {
134                 if (*s == '#' || !*s)   /* ignore comment and empty lines */
135                         continue;
136
137                 namtab[nnames].nstr = s;
138
139                 while (*s && !isspace(*s))
140                         ++s;
141
142                 if (!*s)
143                 {
144                         ++s;
145                         goto empty;
146                 }
147
148                 if (*s && isspace(*s))
149                         *s++ = '\0';
150
151                 s1 = s;
152
153                 while (*s1 && isspace(*s1))
154                         ++s1;
155
156                 if (!*s1)
157                 {
158 empty:                  /* use previous entry + 1 */
159                         if (!nnames)            /* complain if no previous entry */
160                                 namtab[nnames].nval = 0;
161                         else
162                                 namtab[nnames].nval = namtab[nnames-1].nval + 1;
163                 }
164                 else if (isdigit(*s1))
165                         namtab[nnames].nval = atoi(s1);
166                 else if (*s1 == '\'')
167                         namtab[nnames].nval = *++s1;
168                 else if (*s1 == '=')
169                 {                       /* same as previous entry */
170                         if (!nnames)            /* zero for first entry */
171                                 namtab[nnames].nval = 0;
172                         else
173                                 namtab[nnames].nval = namtab[nnames-1].nval;
174                 }
175                 else
176                 {
177                         fprintf(stderr, "bad expression at '%s'\n", namtab[nnames].nstr);
178                         exit(1);
179                 }
180
181                 ++nnames;
182
183                 if (nnames >= NSTRINGS)
184                         panic("name table overflow");
185
186                 if (s >= &strpool[STRPOOLSIZ-100])
187                         panic("string table overflow");
188         }
189
190         qsort(namtab, nnames, sizeof(struct name_entry), comp_entry);
191
192         /*
193          *  compute table start indices
194          */
195         found1 = 1;
196
197         for(k=1; found1; ++k)
198         {
199                 found1 = 0;
200
201                 for(w=0; w<=nnames; ++w)
202                 {
203                         if (w == 0 || w == nnames
204                                 || !nmatch(k-1, namtab[w].nstr, namtab[w-1].nstr))
205                         {
206                                 if (w != 0 && valid != 0)
207                                 {
208                                         wiredown();
209
210                                         if (k > 1)
211                                         {
212                                                 state = 0;
213
214                                                 for(i=0; i<k-2; ++i)
215                                                 {
216                                                         if (ktab[kbase[state] + *(namtab[w-1].nstr + i)] < 0)
217                                                                 panic("table build error");
218                                                         else
219                                                                 state = ktab[kbase[state] + *(namtab[w-1].nstr + i)];
220                                                 }
221
222                                                 ktab[kbase[state] + *(namtab[w-1].nstr + k-2)] = nstates;
223                                         }
224
225                                         ++nstates;
226                                         found1 = 1;
227                                 }
228
229                                 for(i=0; i<128; ++i)
230                                 {
231                                         tab[i] = UNUSED;
232                                         accept[i] = -1;
233                                 }
234
235                                 valid = 0;
236                         }
237
238                         if (w >= nnames || (int)strlen(namtab[w].nstr) < k)
239                         {
240                                 continue;
241                         }
242
243                         tab[*(namtab[w].nstr + k-1)] = MARKED;
244
245                         if (*(namtab[w].nstr + k) == '\0')
246                         {
247                                 accept[*(namtab[w].nstr + k-1)] = namtab[w].nval;
248                         }
249
250                         valid = 1;
251                 }
252         }
253
254         traverse(0);
255         print_tables();
256
257         return 0;
258 }
259
260
261 /*
262  *  find position for set of characters;
263  *
264  */
265 void wiredown(void)
266 {
267         register int base;
268         register int i;
269
270         for(base=0; base<TABSIZE-128; ++base)
271         {
272                 for(i=0; i<128; ++i)
273                         if (ktab[base+i] != UNUSED && tab[i] == MARKED)
274                                 break;
275
276                 if (i >= 128)
277                         break;
278         }
279
280         if (base >= TABSIZE-128)
281                 panic("Cannot build table (won't fit in tables)\n");
282
283         for(i=0; i<128; ++i)
284         {
285                 if (tab[i] == MARKED)
286                 {
287                         ktab[base + i] = MARKED;
288                         kaccept[base + i] = accept[i];
289                         kcheck[base + i] = nstates;
290                 }
291         }
292
293         kbase[nstates] = base;
294
295         if (kmax < base)
296                 kmax = base;
297 }
298
299
300 void print_tables(void)
301 {
302 //      int i;
303
304         printf("\n#ifdef DECL_%s\n", uppername);
305         printf("/*\n *  keyword state-machine tables\n *\n */\n");
306         dumptab("base", basename, kbase, nstates);
307         dumptab("tab", basename, ktab, kmax + 128);
308         dumptab("check", basename, kcheck, kmax + 128);
309         dumptab("accept", basename, kaccept, kmax + 128);
310         printf("#endif\n");
311 }
312
313
314 void dumptab(char * tabname, char * tabprefix, int * table, int tabsize)
315 {
316         int i, j;
317
318         printf("\nint %s%s[%d] = {\n", tabprefix, tabname, tabsize);
319
320         for(i=j=0; i<tabsize; ++i)
321         {
322                 printf(" %d", table[i]);
323
324                 if (i != tabsize-1)
325                         putchar(',');
326
327                 if (++j == 8)
328                 {
329                         j = 0;
330                         putchar('\n');
331                 }
332         }
333
334         if (j)
335                 putchar('\n');
336
337         printf("};\n");
338 }
339
340
341 int comp_entry(struct name_entry * ent1, struct name_entry * ent2)
342 {
343         return strcmp(ent1->nstr, ent2->nstr);
344 }
345
346
347 int nmatch(int len, char * s1, char * s2)
348 {
349         while (len--)
350         {
351                 if (*s1++ != *s2++)
352                         return 0;
353         }
354
355         return 1;
356 }
357
358
359 char nam[128];
360 char * pnam;
361
362 void traverse(int state)
363 {
364         register int base, i;//, j;
365         char * s, c;
366
367         if (state == 0)
368         {
369                 printf("#ifdef DEF_%s\n", uppername);
370                 printf("/*\n *  Keyword definitions\n */\n");
371                 pnam = nam;
372                 *pnam = 0;
373         }
374
375         base = kbase[state];
376
377         for(i=0; i<128; ++i)
378         {
379                 if (kcheck[base + i] == state)
380                 {
381                         *pnam++ = (char)i;
382                         *pnam = '\0';
383
384                         for(s=nam; *s; ++s)
385                         {
386                                 if (isupper(*s))
387                                         break;
388                         }
389
390                         if (kaccept[base + i] >= 0 && !isupper(*s))
391                         {
392                                 printf("#define\t%s_", uppername);
393
394                                 for(s=nam; (c=*s); ++s)
395                                 {
396                                         if (c == '.')
397                                                 c = '_';
398                                         else if ((c >= 'a') && (c <= 'z'))
399                                                 c -= 32;
400
401                                         printf("%c", c);
402                                 }
403
404                                 printf("\t%d\n", kaccept[base + i]);
405                         }
406
407                         if (ktab[base + i] >= 0)
408                                 traverse(ktab[base + i]);
409
410                         *--pnam = '\0';
411                 }
412         }
413
414         if (state == 0)
415                 printf("#endif\n");
416 }
417
418
419 void panic(char * s)
420 {
421         fprintf(stderr, "Panic: %s\n", s);
422         exit(1);
423 }
424