Various cleanups to fix compiler warnings.
[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 /*
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 1024            /* state table size */
44 #define NSTRINGS 500            /* 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 int main(int argc, char **argv) {
92         register int i, /*j,*/ k, w;
93         char *s, *s1;
94         int found1;
95         int valid = 0;
96         //int base;
97         int state;
98
99         if (argc != 2)
100         {
101                 panic("bad commandline");
102         }
103
104         basename = argv[1];
105         for (s = basename, s1 = uppername; *s; ++s, ++s1)
106                 *s1 = (char)toupper(*s);
107         *s1 = EOS;
108
109         /*
110          *  init tables
111          */
112         for (i = 0; i < TABSIZE; ++i)
113         {
114                 ktab[i] = -1;
115                 kcheck[i] = -1;
116                 kaccept[i] = -1;
117         }
118         nstates = 0;
119
120         /*
121          *  read keyword list
122          *
123          */
124         s = strpool;
125
126 //      while (gets(s) != NULL)
127         while (fgets(s, STRPOOLSIZ, stdin) != NULL)
128         {
129                 if (*s == '#' || !*s)   /* ignore comment and empty lines */
130                         continue;
131
132                 namtab[nnames].nstr = s;
133                 while (*s && !isspace(*s))
134                         ++s;
135
136                 if (!*s)
137                 {
138                         ++s;
139                         goto empty;
140                 }
141
142                 if (*s && isspace(*s))
143                         *s++ = '\0';
144
145                 s1 = s;
146                 while (*s1 && isspace(*s1))
147                         ++s1;
148
149                 if (!*s1)
150                 {
151 empty:                  /* use previous entry + 1 */
152                         if (!nnames)            /* complain if no previous entry */
153                                 namtab[nnames].nval = 0;
154                         else namtab[nnames].nval = namtab[nnames-1].nval + 1;
155                 }
156                 else if (isdigit(*s1))
157                         namtab[nnames].nval = atoi(s1);
158                 else if (*s1 == '\'')
159                         namtab[nnames].nval = *++s1;
160                 else if (*s1 == '=')
161                 {                       /* same as previous entry */
162                         if (!nnames)            /* zero for first entry */
163                                 namtab[nnames].nval = 0;
164                         else namtab[nnames].nval = namtab[nnames-1].nval;
165                 }
166                 else
167                 {
168                         fprintf(stderr, "bad expression at '%s'\n", namtab[nnames].nstr);
169                         exit(1);
170                 }
171
172                 ++nnames;
173                 if (nnames >= NSTRINGS)
174                         panic("name table overflow");
175                 if (s >= &strpool[STRPOOLSIZ-100])
176                         panic("string table overflow");
177         }
178
179         qsort(namtab, nnames, sizeof(struct name_entry), comp_entry);
180
181         /*
182          *  compute table start indices
183          */
184         found1 = 1;
185
186         for (k = 1; found1; ++k)
187         {
188                 found1 = 0;
189
190                 for (w = 0; w <= nnames; ++w)
191                 {
192                         if (w == 0 ||
193                                   w == nnames ||
194                                   !nmatch(k-1, namtab[w].nstr, namtab[w-1].nstr))
195                         {
196                                 if (w != 0 &&
197                                           valid != 0)
198                                 {
199                                         wiredown();
200
201                                         if (k > 1)
202                                         {
203                                                 state = 0;
204                                                 for (i = 0; i < k-2; ++i)
205                                                 {
206                                                         if (ktab[kbase[state] + *(namtab[w-1].nstr + i)] < 0)
207                                                                 panic("table build error");
208                                                         else state = ktab[kbase[state] +
209                                                                                           *(namtab[w-1].nstr + i)];
210                                                 }
211
212                                                 ktab[kbase[state] + *(namtab[w-1].nstr + k-2)] = nstates;
213                                         }
214                                         ++nstates;
215                                         found1 = 1;
216                                 }
217
218                                 for (i = 0; i < 128; ++i)
219                                 {
220                                         tab[i] = UNUSED;
221                                         accept[i] = -1;
222                                 }
223
224                                 valid = 0;
225                         }
226
227                         if ( w >= nnames ||
228                                  (int)strlen(namtab[w].nstr) < k)
229                         {
230                                 continue;
231                         }
232
233                         tab[*(namtab[w].nstr + k-1)] = MARKED;
234                         if (*(namtab[w].nstr + k) == '\0')
235                         {
236                                 accept[*(namtab[w].nstr + k-1)] = namtab[w].nval;
237                         }
238                         valid = 1;
239                 }
240         }
241
242         traverse(0);
243         print_tables();
244
245         return 0;
246 }
247
248
249 /*
250  *  find position for set of characters;
251  *
252  */
253 void wiredown(void) {
254         register int base;
255         register int i;
256
257         for (base = 0; base < TABSIZE-128; ++base)
258         {
259                 for (i = 0; i < 128; ++i)
260                         if (ktab[base+i] != UNUSED &&
261                                   tab[i] == MARKED)
262                                 break;
263                 if (i >= 128)
264                         break;
265         }
266
267         if (base >= TABSIZE-128)
268                 panic("Cannot build table (won't fit in tables)\n");
269
270         for (i = 0; i < 128; ++i)
271                 if (tab[i] == MARKED)
272                 {
273                         ktab[base + i] = MARKED;
274                         kaccept[base + i] = accept[i];
275                         kcheck[base + i] = nstates;
276                 }
277         kbase[nstates] = base;
278
279         if (kmax < base)
280                 kmax = base;
281 }
282
283
284 void print_tables(void) {
285 //      int i;
286
287         printf("\n#ifdef DECL_%s\n", uppername);
288         printf("/*\n *  keyword state-machine tables\n *\n */\n");
289         dumptab("base", basename, kbase, nstates);
290         dumptab("tab", basename, ktab, kmax + 128);
291         dumptab("check", basename, kcheck, kmax + 128);
292         dumptab("accept", basename, kaccept, kmax + 128);
293         printf("#endif\n");
294 }
295
296
297 void dumptab(char *tabname, char *tabprefix, int *table, int tabsize) {
298         int i, j;
299
300         printf("\nint %s%s[%d] = {\n",
301                    tabprefix, tabname, tabsize);
302
303         for (i = j = 0; i < tabsize; ++i)
304         {
305                 printf(" %d", table[i]);
306                 if (i != tabsize-1)
307                         putchar(',');
308                 if (++j == 8)
309                 {
310                         j = 0;
311                         putchar('\n');
312                 }
313         }
314         if (j)
315                 putchar('\n');
316         printf("};\n");
317 }
318
319
320 int comp_entry(struct name_entry *ent1, struct name_entry *ent2) {
321         return strcmp(ent1->nstr, ent2->nstr);
322 }
323
324
325 int nmatch(int len, char *s1, char *s2) {
326         while (len--)
327                 if (*s1++ != *s2++)
328                         return 0;
329         return 1;
330 }
331
332
333 char nam[128];
334 char *pnam;
335
336 void traverse(int state) {
337         register int base, i;//, j;
338         char *s, c;
339
340         if (state == 0)
341         {
342                 printf("#ifdef DEF_%s\n", uppername);
343                 printf("/*\n *  Keyword definitions\n */\n");
344                 pnam = nam;
345                 *pnam = 0;
346         }
347
348         base = kbase[state];
349         for (i = 0; i < 128; ++i)
350                 if (kcheck[base + i] == state)
351                 {
352                         *pnam++ = (char)i;
353                         *pnam = '\0';
354
355                         for (s = nam; *s; ++s)
356                                 if (isupper(*s))
357                                         break;
358
359                         if (kaccept[base + i] >= 0 &&
360                                   !isupper(*s))
361                         {
362                                 printf("#define\t%s_", uppername);
363                                 for (s = nam; (c = *s); ++s)
364                                 {
365                                         if (c == '.')
366                                                 c = '_';
367                                         else if ((c >= 'a') && (c <= 'z'))
368                                                 c -= 32;
369                                         printf("%c", c);
370                                 }
371                                 printf("\t%d\n", kaccept[base + i]);
372                         }
373
374                         if (ktab[base + i] >= 0)
375                                 traverse(ktab[base + i]);
376                         *--pnam = '\0';
377                 }
378
379         if (state == 0)
380                 printf("#endif\n");
381 }
382
383
384 void panic(char *s) {
385         fprintf(stderr, "Panic: %s\n", s);
386         exit(1);
387 }