rmac/kwgen.c

425 lines
7.4 KiB
C

//
// RMAC - Renamed Macro Assembler for all Atari computers
// KWGEN.C - Keyword & Mnemonic Definition and State Machine Creation Tool
// Copyright (C) 199x Landon Dyer, 2011-2021 Reboot and Friends
// RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
// Source utilised with the kind permission of Landon Dyer
//
/*
* keyword transition-table generation utility
*
*
*----------------
*
* SYNOPSIS: kw basename <file1 >file2
*
* `-d' turns on debugging messages
*
* Accepts a list of keywords and corresponding values. Lines
* beginning with '#' are comments. Values may be empty (resulting
* in a default value of the previous item's value plus 1, or zero
* if there is no previous item), decimal numbers, or characters
* enclosed between single quotes.
*
* # this is a comment
* .byte 34
* .word 'A'
* .long
*
* The `basename' is a string prepended to the beginning of each of
* the output array names, and should be one or two characters.
*
*/
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
/*
* Tunable definitions
*
*/
#define TABSIZE 2048 /* state table size */
#define NSTRINGS 1024 /* maximum number of keywords */
#define STRPOOLSIZ (NSTRINGS * 10) /* size of string pool */
/*
* Do not change these
*/
#define EOS '\0' /* null */
#define UNUSED -1 /* slot in ktab[] is unused */
#define MARKED -2 /* slot in ktab[] is used, not assigned yet */
/*
* Table-building tables
*/
int kmax = 0; /* largest index into ktab */
int ktab[TABSIZE]; /* next state number (or -1) */
int kcheck[TABSIZE]; /* check state number (or -1) */
int kaccept[TABSIZE]; /* accept (or -1) */
int kbase[TABSIZE]; /* ktab[] index for a state `i' */
int nstates; /* number of states in kbase[] */
/*
* Temporary tables
*/
int tab[128]; /* tmp table for building ktab[] */
int accept[128]; /* tmp table for building accept[] */
struct name_entry {
char *nstr; /* -> name string */
int nval; /* = name's value */
} namtab[NSTRINGS];
int nnames; /* number of keywords */
char strpool[STRPOOLSIZ]; /* pool for keyword text */
char *basename; /* -> string to prepend to array names */
char uppername[100]; /* all-uppercase version of basename */
int debug = 0; /* 1, enable debugging messages */
int comp_entry();
void panic(char *);
int nmatch(int, char *, char *);
void wiredown(void);
void print_tables(void);
void dumptab(char *, char *, int *, int);
void traverse(int);
int main(int argc, char ** argv)
{
register int i, /*j,*/ k, w;
char *s, *s1;
int found1;
int valid = 0;
//int base;
int state;
if (argc != 2)
{
panic("bad commandline");
}
basename = argv[1];
for(s=basename, s1=uppername; *s; ++s, ++s1)
*s1 = (char)toupper(*s);
*s1 = EOS;
/*
* init tables
*/
for(i=0; i<TABSIZE; ++i)
{
ktab[i] = -1;
kcheck[i] = -1;
kaccept[i] = -1;
}
nstates = 0;
/*
* read keyword list
*
*/
s = strpool;
// while (gets(s) != NULL)
while (fgets(s, STRPOOLSIZ, stdin) != NULL)
{
if (*s == '#' || !*s) /* ignore comment and empty lines */
continue;
namtab[nnames].nstr = s;
while (*s && !isspace(*s))
++s;
if (!*s)
{
++s;
goto empty;
}
if (*s && isspace(*s))
*s++ = '\0';
s1 = s;
while (*s1 && isspace(*s1))
++s1;
if (!*s1)
{
empty: /* use previous entry + 1 */
if (!nnames) /* complain if no previous entry */
namtab[nnames].nval = 0;
else
namtab[nnames].nval = namtab[nnames-1].nval + 1;
}
else if (isdigit(*s1))
namtab[nnames].nval = atoi(s1);
else if (*s1 == '\'')
namtab[nnames].nval = *++s1;
else if (*s1 == '=')
{ /* same as previous entry */
if (!nnames) /* zero for first entry */
namtab[nnames].nval = 0;
else
namtab[nnames].nval = namtab[nnames-1].nval;
}
else
{
fprintf(stderr, "bad expression at '%s'\n", namtab[nnames].nstr);
exit(1);
}
++nnames;
if (nnames >= NSTRINGS)
panic("name table overflow");
if (s >= &strpool[STRPOOLSIZ-100])
panic("string table overflow");
}
qsort(namtab, nnames, sizeof(struct name_entry), comp_entry);
/*
* compute table start indices
*/
found1 = 1;
for(k=1; found1; ++k)
{
found1 = 0;
for(w=0; w<=nnames; ++w)
{
if (w == 0 || w == nnames
|| !nmatch(k-1, namtab[w].nstr, namtab[w-1].nstr))
{
if (w != 0 && valid != 0)
{
wiredown();
if (k > 1)
{
state = 0;
for(i=0; i<k-2; ++i)
{
if (ktab[kbase[state] + *(namtab[w-1].nstr + i)] < 0)
panic("table build error");
else
state = ktab[kbase[state] + *(namtab[w-1].nstr + i)];
}
ktab[kbase[state] + *(namtab[w-1].nstr + k-2)] = nstates;
}
++nstates;
found1 = 1;
}
for(i=0; i<128; ++i)
{
tab[i] = UNUSED;
accept[i] = -1;
}
valid = 0;
}
if (w >= nnames || (int)strlen(namtab[w].nstr) < k)
{
continue;
}
tab[*(namtab[w].nstr + k-1)] = MARKED;
if (*(namtab[w].nstr + k) == '\0')
{
accept[*(namtab[w].nstr + k-1)] = namtab[w].nval;
}
valid = 1;
}
}
traverse(0);
print_tables();
return 0;
}
/*
* find position for set of characters;
*
*/
void wiredown(void)
{
register int base;
register int i;
for(base=0; base<TABSIZE-128; ++base)
{
for(i=0; i<128; ++i)
if (ktab[base+i] != UNUSED && tab[i] == MARKED)
break;
if (i >= 128)
break;
}
if (base >= TABSIZE-128)
panic("Cannot build table (won't fit in tables)\n");
for(i=0; i<128; ++i)
{
if (tab[i] == MARKED)
{
ktab[base + i] = MARKED;
kaccept[base + i] = accept[i];
kcheck[base + i] = nstates;
}
}
kbase[nstates] = base;
if (kmax < base)
kmax = base;
}
void print_tables(void)
{
// int i;
printf("\n#ifdef DECL_%s\n", uppername);
printf("/*\n * keyword state-machine tables\n *\n */\n");
dumptab("base", basename, kbase, nstates);
dumptab("tab", basename, ktab, kmax + 128);
dumptab("check", basename, kcheck, kmax + 128);
dumptab("accept", basename, kaccept, kmax + 128);
printf("#endif\n");
}
void dumptab(char * tabname, char * tabprefix, int * table, int tabsize)
{
int i, j;
printf("\nint %s%s[%d] = {\n", tabprefix, tabname, tabsize);
for(i=j=0; i<tabsize; ++i)
{
printf(" %d", table[i]);
if (i != tabsize-1)
putchar(',');
if (++j == 8)
{
j = 0;
putchar('\n');
}
}
if (j)
putchar('\n');
printf("};\n");
}
int comp_entry(struct name_entry * ent1, struct name_entry * ent2)
{
return strcmp(ent1->nstr, ent2->nstr);
}
int nmatch(int len, char * s1, char * s2)
{
while (len--)
{
if (*s1++ != *s2++)
return 0;
}
return 1;
}
char nam[128];
char * pnam;
void traverse(int state)
{
register int base, i;//, j;
char * s, c;
if (state == 0)
{
printf("#ifdef DEF_%s\n", uppername);
printf("/*\n * Keyword definitions\n */\n");
pnam = nam;
*pnam = 0;
}
base = kbase[state];
for(i=0; i<128; ++i)
{
if (kcheck[base + i] == state)
{
*pnam++ = (char)i;
*pnam = '\0';
for(s=nam; *s; ++s)
{
if (isupper(*s))
break;
}
if (kaccept[base + i] >= 0 && !isupper(*s))
{
printf("#define\t%s_", uppername);
for(s=nam; (c=*s); ++s)
{
if (c == '.')
c = '_';
else if ((c >= 'a') && (c <= 'z'))
c -= 32;
printf("%c", c);
}
printf("\t%d\n", kaccept[base + i]);
}
if (ktab[base + i] >= 0)
traverse(ktab[base + i]);
*--pnam = '\0';
}
}
if (state == 0)
printf("#endif\n");
}
void panic(char * s)
{
fprintf(stderr, "Panic: %s\n", s);
exit(1);
}