rmac/kwgen.c

425 lines
7.4 KiB
C
Raw Normal View History

//
// RMAC - Renamed Macro Assembler for all Atari computers
2011-12-27 00:50:27 +02:00
// KWGEN.C - Keyword & Mnemonic Definition and State Machine Creation Tool
// Copyright (C) 199x Landon Dyer, 2011-2021 Reboot and Friends
2011-12-27 00:50:27 +02:00
// RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
// Source utilised with the kind permission of Landon Dyer
//
2011-12-27 00:50:27 +02:00
/*
* 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 */
2011-12-27 00:50:27 +02:00
#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);
2012-01-18 04:06:46 +02:00
int main(int argc, char ** argv)
{
2011-12-27 00:50:27 +02:00
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];
2012-01-18 04:06:46 +02:00
for(s=basename, s1=uppername; *s; ++s, ++s1)
2011-12-27 00:50:27 +02:00
*s1 = (char)toupper(*s);
2012-01-18 04:06:46 +02:00
2011-12-27 00:50:27 +02:00
*s1 = EOS;
/*
* init tables
*/
2012-01-18 04:06:46 +02:00
for(i=0; i<TABSIZE; ++i)
2011-12-27 00:50:27 +02:00
{
ktab[i] = -1;
kcheck[i] = -1;
kaccept[i] = -1;
}
2012-01-18 04:06:46 +02:00
2011-12-27 00:50:27 +02:00
nstates = 0;
/*
* read keyword list
*
*/
s = strpool;
// while (gets(s) != NULL)
while (fgets(s, STRPOOLSIZ, stdin) != NULL)
2011-12-27 00:50:27 +02:00
{
if (*s == '#' || !*s) /* ignore comment and empty lines */
continue;
namtab[nnames].nstr = s;
2012-01-18 04:06:46 +02:00
2011-12-27 00:50:27 +02:00
while (*s && !isspace(*s))
++s;
if (!*s)
{
++s;
goto empty;
}
if (*s && isspace(*s))
*s++ = '\0';
s1 = s;
2012-01-18 04:06:46 +02:00
2011-12-27 00:50:27 +02:00
while (*s1 && isspace(*s1))
++s1;
if (!*s1)
{
empty: /* use previous entry + 1 */
if (!nnames) /* complain if no previous entry */
namtab[nnames].nval = 0;
2012-01-18 04:06:46 +02:00
else
namtab[nnames].nval = namtab[nnames-1].nval + 1;
2011-12-27 00:50:27 +02:00
}
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;
2012-01-18 04:06:46 +02:00
else
namtab[nnames].nval = namtab[nnames-1].nval;
2011-12-27 00:50:27 +02:00
}
else
{
fprintf(stderr, "bad expression at '%s'\n", namtab[nnames].nstr);
exit(1);
}
++nnames;
2012-01-18 04:06:46 +02:00
2011-12-27 00:50:27 +02:00
if (nnames >= NSTRINGS)
panic("name table overflow");
2012-01-18 04:06:46 +02:00
2011-12-27 00:50:27 +02:00
if (s >= &strpool[STRPOOLSIZ-100])
panic("string table overflow");
}
qsort(namtab, nnames, sizeof(struct name_entry), comp_entry);
/*
* compute table start indices
*/
found1 = 1;
2012-01-18 04:06:46 +02:00
for(k=1; found1; ++k)
2011-12-27 00:50:27 +02:00
{
found1 = 0;
2012-01-18 04:06:46 +02:00
for(w=0; w<=nnames; ++w)
2011-12-27 00:50:27 +02:00
{
2012-01-18 04:06:46 +02:00
if (w == 0 || w == nnames
|| !nmatch(k-1, namtab[w].nstr, namtab[w-1].nstr))
2011-12-27 00:50:27 +02:00
{
2012-01-18 04:06:46 +02:00
if (w != 0 && valid != 0)
2011-12-27 00:50:27 +02:00
{
wiredown();
if (k > 1)
{
state = 0;
2012-01-18 04:06:46 +02:00
for(i=0; i<k-2; ++i)
2011-12-27 00:50:27 +02:00
{
if (ktab[kbase[state] + *(namtab[w-1].nstr + i)] < 0)
panic("table build error");
2012-01-18 04:06:46 +02:00
else
state = ktab[kbase[state] + *(namtab[w-1].nstr + i)];
2011-12-27 00:50:27 +02:00
}
ktab[kbase[state] + *(namtab[w-1].nstr + k-2)] = nstates;
}
2012-01-18 04:06:46 +02:00
2011-12-27 00:50:27 +02:00
++nstates;
found1 = 1;
}
2012-01-18 04:06:46 +02:00
for(i=0; i<128; ++i)
2011-12-27 00:50:27 +02:00
{
tab[i] = UNUSED;
accept[i] = -1;
}
valid = 0;
}
2012-01-18 04:06:46 +02:00
if (w >= nnames || (int)strlen(namtab[w].nstr) < k)
2011-12-27 00:50:27 +02:00
{
continue;
}
tab[*(namtab[w].nstr + k-1)] = MARKED;
2012-01-18 04:06:46 +02:00
2011-12-27 00:50:27 +02:00
if (*(namtab[w].nstr + k) == '\0')
{
accept[*(namtab[w].nstr + k-1)] = namtab[w].nval;
}
2012-01-18 04:06:46 +02:00
2011-12-27 00:50:27 +02:00
valid = 1;
}
}
traverse(0);
print_tables();
return 0;
}
/*
* find position for set of characters;
*
*/
2012-01-18 04:06:46 +02:00
void wiredown(void)
{
2011-12-27 00:50:27 +02:00
register int base;
register int i;
2012-01-18 04:06:46 +02:00
for(base=0; base<TABSIZE-128; ++base)
2011-12-27 00:50:27 +02:00
{
2012-01-18 04:06:46 +02:00
for(i=0; i<128; ++i)
if (ktab[base+i] != UNUSED && tab[i] == MARKED)
2011-12-27 00:50:27 +02:00
break;
2012-01-18 04:06:46 +02:00
2011-12-27 00:50:27 +02:00
if (i >= 128)
break;
}
if (base >= TABSIZE-128)
panic("Cannot build table (won't fit in tables)\n");
2012-01-18 04:06:46 +02:00
for(i=0; i<128; ++i)
{
2011-12-27 00:50:27 +02:00
if (tab[i] == MARKED)
{
ktab[base + i] = MARKED;
kaccept[base + i] = accept[i];
kcheck[base + i] = nstates;
}
2012-01-18 04:06:46 +02:00
}
2011-12-27 00:50:27 +02:00
kbase[nstates] = base;
if (kmax < base)
kmax = base;
}
2012-01-18 04:06:46 +02:00
void print_tables(void)
{
2011-12-27 00:50:27 +02:00
// 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");
}
2012-01-18 04:06:46 +02:00
void dumptab(char * tabname, char * tabprefix, int * table, int tabsize)
{
2011-12-27 00:50:27 +02:00
int i, j;
2012-01-18 04:06:46 +02:00
printf("\nint %s%s[%d] = {\n", tabprefix, tabname, tabsize);
2011-12-27 00:50:27 +02:00
2012-01-18 04:06:46 +02:00
for(i=j=0; i<tabsize; ++i)
2011-12-27 00:50:27 +02:00
{
printf(" %d", table[i]);
2012-01-18 04:06:46 +02:00
2011-12-27 00:50:27 +02:00
if (i != tabsize-1)
putchar(',');
2012-01-18 04:06:46 +02:00
2011-12-27 00:50:27 +02:00
if (++j == 8)
{
j = 0;
putchar('\n');
}
}
2012-01-18 04:06:46 +02:00
2011-12-27 00:50:27 +02:00
if (j)
putchar('\n');
2012-01-18 04:06:46 +02:00
2011-12-27 00:50:27 +02:00
printf("};\n");
}
2012-01-18 04:06:46 +02:00
int comp_entry(struct name_entry * ent1, struct name_entry * ent2)
{
2011-12-27 00:50:27 +02:00
return strcmp(ent1->nstr, ent2->nstr);
}
2012-01-18 04:06:46 +02:00
int nmatch(int len, char * s1, char * s2)
{
2011-12-27 00:50:27 +02:00
while (len--)
2012-01-18 04:06:46 +02:00
{
2011-12-27 00:50:27 +02:00
if (*s1++ != *s2++)
return 0;
2012-01-18 04:06:46 +02:00
}
2011-12-27 00:50:27 +02:00
return 1;
}
char nam[128];
2012-01-18 04:06:46 +02:00
char * pnam;
2011-12-27 00:50:27 +02:00
2012-01-18 04:06:46 +02:00
void traverse(int state)
{
2011-12-27 00:50:27 +02:00
register int base, i;//, j;
2012-01-18 04:06:46 +02:00
char * s, c;
2011-12-27 00:50:27 +02:00
if (state == 0)
{
printf("#ifdef DEF_%s\n", uppername);
printf("/*\n * Keyword definitions\n */\n");
pnam = nam;
*pnam = 0;
}
base = kbase[state];
2012-01-18 04:06:46 +02:00
for(i=0; i<128; ++i)
{
2011-12-27 00:50:27 +02:00
if (kcheck[base + i] == state)
{
*pnam++ = (char)i;
*pnam = '\0';
2012-01-18 04:06:46 +02:00
for(s=nam; *s; ++s)
{
2011-12-27 00:50:27 +02:00
if (isupper(*s))
break;
2012-01-18 04:06:46 +02:00
}
2011-12-27 00:50:27 +02:00
2012-01-18 04:06:46 +02:00
if (kaccept[base + i] >= 0 && !isupper(*s))
2011-12-27 00:50:27 +02:00
{
printf("#define\t%s_", uppername);
2012-01-18 04:06:46 +02:00
for(s=nam; (c=*s); ++s)
2011-12-27 00:50:27 +02:00
{
if (c == '.')
c = '_';
else if ((c >= 'a') && (c <= 'z'))
c -= 32;
2012-01-18 04:06:46 +02:00
2011-12-27 00:50:27 +02:00
printf("%c", c);
}
2012-01-18 04:06:46 +02:00
2011-12-27 00:50:27 +02:00
printf("\t%d\n", kaccept[base + i]);
}
if (ktab[base + i] >= 0)
traverse(ktab[base + i]);
2012-01-18 04:06:46 +02:00
2011-12-27 00:50:27 +02:00
*--pnam = '\0';
}
2012-01-18 04:06:46 +02:00
}
2011-12-27 00:50:27 +02:00
if (state == 0)
printf("#endif\n");
}
2012-01-18 04:06:46 +02:00
void panic(char * s)
{
2011-12-27 00:50:27 +02:00
fprintf(stderr, "Panic: %s\n", s);
exit(1);
}