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