home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
misc
/
volume19
/
wacco
/
part01
/
gen.C
< prev
next >
Wrap
C/C++ Source or Header
|
1991-05-19
|
16KB
|
672 lines
// Copyright (c) 1991 by Parag Patel. All Rights Reserved.
static const char rcs_id[] = "$Header: gen.C,v 1.29 91/02/22 16:08:02 hmgr Exp $";
#include "defs.h"
#include "toks.h"
#include <stdarg.h>
static FILE *fp = NULL;
static long curr_lineno = 1;
static const char *currfile = NULL;
static const char *inputfile = NULL;
static void putf(char *fmt, ...)
{
va_list ap;
char buf[1024];
va_start(ap, fmt);
vsprintf(buf, fmt, ap);
va_end(ap);
int nl = 0;
for (char *s = buf; *s != '\0'; s++)
if (*s == '\n')
nl++;
curr_lineno += nl;
fputs(buf, fp);
}
inline static void put(int ch)
{
putc(ch, fp);
if (ch == '\n')
curr_lineno++;
}
static boolean saveret = FALSE;
static char *mkretcode(symbol *s)
{
s = NULL;
return saveret ? "_rc = " : "(void)";
}
static const char *mkname(symbol *sym)
{
if (*sym->name != '"')
return sym->name;
if (*sym->name == '\'' && sym->type == TERMINAL)
return sym->name;
return strbldf("_S%d/*%s*/", sym->id, sym->name);
}
static const char *mkerrname(symbol *sym)
{
if (sym->type == NONTERMINAL && sym->realname != NULL)
return sym->realname;
return mkname(sym);
}
static void printset(const char *name, Bitset &set)
{
Bitsetiter si(set);
symbol *s;
int id;
char *pre = "";
putf("static %s[] = { ", name);
while ((id = si()) >= 0)
{
if (id == EMPTY)
putf("%s_EMPTY", pre);
// continue;
else if (id == END)
putf("%sEOI", pre);
else
{
s = getsymbol(id);
putf("%s%s", pre, mkname(s));
}
pre = ", ";
}
putf("%s-1 };\n", pre);
}
static void printcase(char *pre, Bitset &set)
{
Bitsetiter si(set);
symbol *s;
int id;
while ((id = si()) >= 0)
{
if (id == EMPTY)
continue;
putf("%scase ", pre);
if (id == END)
putf("EOI");
else
{
s = getsymbol(id);
putf("%s", mkname(s));
}
putf(":\n");
}
}
inline static boolean dotype(symbol *sym)
{
if ((sym->usedret & RET_VALUE) || sym->rettype != NULL)
return TRUE;
else
return FALSE;
}
static const char *mktype(symbol *sym, char *pre = "", char *post = NULL)
{
if (!dotype(sym))
return "";
char *name;
if (sym->rettype == NULL)
name = "int";
else
{
name = sym->rettype;
if (sym->mkstruct)
{
if (sym->realname != NULL && sym->realname != sym->name
&& sym->rettype == findsymbol(sym->realname)->rettype)
return strbldf("%s_T%s%s", pre, sym->realname, post);
return strbldf("%s_T%s%s", pre, sym->name, post);
}
}
return strbldf("%s%s%s", pre, name, post);
}
static const char *mkvoidtype(symbol *sym, char *pre = "", char *post = NULL)
{
const char *type = mktype(sym, pre, post);
if (*type == '\0')
type = "void";
return type;
}
static void mkstruct(symbol *sym)
{
if (!dotype(sym) || !sym->mkstruct)
return;
char *name = sym->name;
if (sym->realname != NULL && sym->realname != sym->name)
{
symbol *real = findsymbol(sym->realname);
if (real->rettype == sym->rettype)
{
if (dotype(real))
return;
name = sym->realname;
}
}
putf("\nstruct _T%s\n{\n", name);
putf("\t%s;\n};\n", sym->rettype);
}
static void mkcode(char *pre, symbol *code)
{
if (code == NULL || code->code == NULL)
return;
if (genlineinfo)
putf("#line %d \"%s\"\n", code->line, inputfile);
else
putf("/* #line %d */\n", code->line);
putf("%s%s;\n", pre, code->code);
if (genlineinfo)
putf("#line %d \"%s\"\n", curr_lineno + 1, currfile);
}
static const char *mkvarname(symnode *start, symnode *node)
{
if (node->alias != NULL)
return node->alias;
int count = 0;
boolean addnum = FALSE;
char *name = node->sym->name;
if (node->sym->realname != NULL && node->sym->name != node->sym->realname)
{
name = "_";
for (symnode *n = start; n != node; n = n->next)
if (n->sym->type == NONTERMINAL && n->sym->realname != NULL
&& n->sym->name != n->sym->realname)
count++;
for (n = n->next; n != NULL; n = n->next)
if (n->sym->type == NONTERMINAL && n->sym->realname != NULL
&& n->sym->name != n->sym->realname)
addnum = TRUE;
}
else
{
for (symnode *n = start; n != node; n = n->next)
if (n->sym == node->sym)
count++;
for (n = n->next; n != NULL; n = n->next)
if (n->sym == node->sym)
addnum = TRUE;
}
if (addnum || count > 0)
return strbldf("%s%d", name, count + 1);
return name;
}
static void genstmt(char *pre, symnode *node)
{
symbol *s;
symnode *n;
for (n = node; n != NULL; n = n->next)
{
if (n->sym->type != NONTERMINAL || n->sym->id == EMPTY
|| !dotype(n->sym))
continue;
putf("%s%s _rv%s;\n", pre, mktype(n->sym), mkvarname(node, n));
}
for (n = node; n != NULL; n = n->next)
{
s = n->sym;
if (s->type == CODE)
{
if (dumpcode)
mkcode(pre, s);
continue;
}
if (s->id == EMPTY)
continue;
if (s->type == TERMINAL)
putf("%s%sscantoken(%s, _link, _resync%d);\n",
pre, mkretcode(s), mkname(s), n->resync->id);
else if (optimize && s->usecount == 1 && !s->export)
{
symbol *sym = s;
symnode *nn = n;
Bitset set(numsymbols());
putf("%s{\n", pre);
if (dotype(s))
putf("%s = _rv%s;\n", mktype(sym, pre, " &_rr"),
mkvarname(node, nn));
else
putf("%s\n", mktype(sym, pre, " _rr;"));
putf("%sresynclink &_lnk = _link;\n", pre);
putf("%sresynclink _link(_lnk, _resync%d);\n\n",
pre, nn->resync->id);
if (sym->resync != NULL)
putf("%s (void)scantoken(-1, _link, _resync%d);\n\n",
pre, sym->resync->id);
if (sym->node != NULL && sym->node->or == NULL)
{
genstmt("\t\t\t", sym->node);
putf("\n%s}\n\n", pre);
// putf("\n%sreturn RETOK;\n}\n\n", pre);
continue;
}
boolean donedefault = FALSE;
putf("%sswitch (w_nexttoken())\n\t{\n", pre);
for (symnode *n = sym->node; n != NULL; n = n->or)
{
set.clear();
for (symnode *s = n; s != NULL; s = s->next)
{
if (s->sym->type == CODE)
continue;
set |= *s->sym->first;
if (!s->sym->first->isin(EMPTY))
break;
}
if (set.size() == 0 || (set.size() == 1 && set.isin(EMPTY)))
{
donedefault = TRUE;
putf("%s\tdefault:\n", pre);
genstmt("\t\t", n);
if (!sym->first->isin(EMPTY))
putf("%s\t\tw_scanerr(\"illegal %s\");\n",
pre, mkerrname(sym));
}
else
{
printcase("\t", set);
putf("\t\t{\n");
genstmt("\t\t\t", n);
putf("\t\t}\n");
}
putf("\t\tbreak;\n");
}
if (!donedefault && !sym->first->isin(EMPTY))
{
putf("%s\tdefault:\n", pre);
putf("%s\t\tw_scanerr(\"illegal %s\");\n",
pre, mkerrname(sym));
}
putf("%s}", pre);
putf(" }\n");
}
else if (dotype(s))
putf("%s%s_f%s(_link, _resync%d, _rv%s);\n",
pre, mkretcode(s), mkname(s),
n->resync->id, mkvarname(node, n));
else
putf("%s%s_f%s(_link, _resync%d);\n",
pre, mkretcode(s), mkname(s), n->resync->id);
// putf(" }\n");
}
}
static void genheader(void)
{
symbol *sym;
int i;
putf("#ifndef _T_O_K_E_N_S_\n#define _T_O_K_E_N_S_\n\n");
putf("#ifndef NULL\n#include <stdio.h>\n#endif\n\n");
putf("#define RETOK 1\n");
putf("#define RETERR 0\n\n");
putf("enum tokenids\n{\n");
putf("\tEOI = 0,\n");
putf("\t_EMPTY = 256, /* nothing uses this yet */\n");
boolean doid = TRUE;
for (i = START; i < numsymbols(); i++)
{
sym = getsymbol(i);
if (sym->type != TERMINAL || *sym->name == '\'')
continue;
if (doid)
putf("\t%s = 257,\n", mkname(sym));
else
putf("\t%s,\n", mkname(sym));
doid = FALSE;
}
putf("};\n\n");
if (gotlexstr)
{
putf("#ifdef __cplusplus\n");
putf("extern \"C\" {\n");
putf("extern int yylex(void);\n");
putf("}\n");
putf("#else\n");
putf("extern int yylex();\n");
putf("#endif\n\n");
putf("#ifdef FLEX_SCANNER\n");
putf("# undef YY_INPUT\n");
putf("# define YY_INPUT(buf,result,max_size) \\\n");
putf(" result = (buf[0] = w_input()) == EOI ? YY_NULL : 1;\n");
putf("#else\n");
putf("# undef input\n");
putf("# define input w_input\n");
putf("# undef unput\n");
putf("# define unput w_unput\n");
putf("#endif\n\n");
}
putf("extern int w_numerrors;\n");
putf("#ifdef __cplusplus\n");
putf("extern \"C\" {\n");
putf("extern int w_scanerr(const char *, ...);\n");
putf("extern void w_flusherrs(void);\n");
putf("extern void w_closefile(void);\n");
putf("extern int w_openfile(char *);\n");
putf("extern FILE *w_getfile(void);\n");
putf("extern void w_setfile(FILE *);\n");
putf("extern int w_currcol(void);\n");
putf("extern int w_currline(void);\n");
putf("extern char *w_getcurrline(void);\n");
putf("extern int w_input(void);\n");
putf("extern int w_unput(int);\n");
putf("extern void w_output(int);\n");
putf("extern int w_gettoken(void);\n");
putf("extern int w_nexttoken(void);\n");
putf("extern void w_skiptoken(void);\n");
putf("extern char *w_tokenname(int);\n");
putf("}\n");
putf("#else\n");
putf("extern int w_scanerr();\n");
putf("extern void w_flusherrs();\n");
putf("extern void w_closefile();\n");
putf("extern int w_openfile();\n");
putf("extern FILE *w_getfile();\n");
putf("extern void w_setfile();\n");
putf("extern int w_currcol();\n");
putf("extern int w_currline();\n");
putf("extern char *w_getcurrline();\n");
putf("extern int w_input();\n");
putf("extern int w_unput();\n");
putf("extern void w_output();\n");
putf("extern int w_gettoken();\n");
putf("extern int w_nexttoken();\n");
putf("extern void w_skiptoken();\n");
putf("extern char *w_tokenname();\n");
putf("#endif\n\n");
if (exportedname)
{
for (i = 0; i < numnonterms(); i++)
{
sym = getnonterm(i);
if (sym->type != NONTERMINAL || !sym->export)
continue;
mkstruct(sym);
putf("#ifdef __cplusplus\n");
putf("extern \"C\" { int %s(%s); }\n", mkname(sym),
mkvoidtype(sym, "", " &"));
putf("#else\n");
putf("extern int %s();\n", mkname(sym));
putf("#endif\n");
}
}
else
{
mkstruct(startsymbol);
putf("#ifdef __cplusplus\n");
putf("extern \"C\" { int %s(%s); }\n", mkname(startsymbol),
mkvoidtype(startsymbol, "", " &"));
putf("#else\n");
putf("extern int %s();\n", mkname(startsymbol));
putf("#endif\n");
}
putf("\n\n#endif /* _T_O_K_E_N_S_ */\n");
}
static void genscanner(char *header)
{
symbol *sym;
int i, c;
boolean nl = TRUE;
// scan past the definition section
while ((c = w_input()) != END)
{
if (nl && c == '%')
{
int t = w_input();
if (t == '%')
break;
put(c);
c = t;
}
put(c);
nl = c == '\n';
}
// dump out our header stuff here
putf("%%{\n");
putf("#include \"%s\"\n", header);
putf("%%}\n");
putf("%%%%\n");
// print the lexical values from the grammer
for (i = START; i < numsymbols(); i++)
{
symbol *sym = getsymbol(i);
if (sym->type != TERMINAL || sym->lexdef || sym->lexstr == NULL)
continue;
if (casesensitive || sym->name[0] != '"')
putf("%s", sym->lexstr);
else
{
for (char *s = sym->lexstr + 1;
*s != '\0' && !(*s == '"' && *(s + 1) == '\0');
s++)
if (isalpha(*s))
putf("[%c%c]",
islower(*s) ? toupper(*s) : *s,
isupper(*s) ? tolower(*s) : *s);
else if (*s == '\\' && *(s+1) == '"')
;
else
putf("\\%c", *s);
}
putf("\t{ return (int)%s; }\n", mkname(sym));
sym->lexdef = TRUE;
}
// now add the rules at the bottom of the source
if (c != END)
while ((c = w_input()) != END)
{
if (nl && c == '%')
{
int t = w_input();
if (t == '%')
break;
put(c);
c = t;
}
else if (nl && c == '$')
{
char *name = getword();
if (name == NULL)
quit("Unexpected end-of-w_input");
sym = findsymbol(name);
if (sym == NULL)
error("Symbol %s not in grammer", name);
if (sym->lexstr != NULL)
error("Symbol %s lexical string redefined in lex section",
name);
while ((c = w_input()) == ' ' || c == '\t')
;
if (c == '\n' || c == END)
putf("\n");
else
{
for (; c != END && c != '\n'; c = w_input())
put(c);
putf("\t{ return (int)%s; }", name);
}
sym->lexdef = TRUE;
}
put(c);
nl = c == '\n';
}
// check for missing tokens
for (i = START; i < numsymbols(); i++)
{
sym = getsymbol(i);
if (sym->type != TERMINAL || sym->lexdef)
continue;
if (sym->lexstr == NULL)
error("Lexical value for symbol %s is not defined", mkname(sym));
}
putf("%%%%\n");
// now copy the rest (user code)
if (c != END)
while ((c = w_input()) != END)
put(c);
}
static void dumpexport(symbol *sym)
{
putf("int %s(%s)\n{\n", mkname(sym),
mkvoidtype(sym, "", " &ret"));
putf("\tresynclink _link;\n\t");
printset("_follow", *sym->follow);
putf("\tint _rval;\n");
putf("\tint _savnum = w_numerrors;\n\n");
putf("\tw_numerrors = 0;\n");
putf("\t_rval = _f%s(_link, _follow%s);\n",
mkname(sym), dotype(sym) ? ", ret" : "");
putf("\tswitch (w_nexttoken())\n\t{\n");
printcase("\t", *sym->follow);
putf("\t\tbreak;\n");
putf("\tdefault:\n");
putf("\t\t_rval = w_scanerr(\"expected end of %s\");\n",
mkname(sym));
putf("\t}\n");
putf("\tif (w_numerrors > 0) _rval = RETERR;\n");
putf("\tw_numerrors += _savnum;\n");
putf("\tw_scanerr(NULL);\n");
putf("\treturn _rval;\n");
putf("}\n\n");
}
static void genparser(char *header)
{
symbol *sym;
symnode *n;
int i;
putf("#define YYTEXT_DECL unsigned char yytext[]\n\n");
mkcode("", startcode);
putf("\n#include \"%s\"\n\n", header);
putf("extern YYTEXT_DECL;\n");
putf("int w_numerrors = 0;\n\n");
putf("\nstruct resynclink\n{\n\tresynclink *prev;\n");
putf("\tint *resync;\n");
putf("\tresynclink() { prev = 0; resync = 0; }\n");
putf("\tresynclink(resynclink &p, int *s)");
putf(" { prev = &p; resync = s; }\n");
putf("};\n");
for (i = 0; i < numnonterms(); i++)
{
sym = getnonterm(i);
if (sym->type != NONTERMINAL)
continue;
if (!sym->export)
mkstruct(sym);
if (optimize && sym->usecount == 1 && !sym->export)
continue;
putf("static _f%s(resynclink &, int *%s);\n", mkname(sym),
mktype(sym, ", ", " &"));
}
putf("\n");
putf("static char *_toknams[] =\n{\n");
putf("\t\"[]\",\n");
for (i = START; i < numsymbols(); i++)
{
sym = getsymbol(i);
if (sym->type != TERMINAL || *sym->name == '\'')
continue;
char *str = sym->lexstr;
if (str == NULL)
putf("\t\"%s\",\n", mkname(sym));
else if (isalpha(*str))
putf("\t\"%s\",\n", str);
else if (*str == '"' && str[strlen(str) - 1] == '"')
putf("\t%s,\n", sym->lexstr);
else
putf("\t\"%s\",\n", mkname(sym));
}
putf("};\n\n");
putf("char *w_tokenname(int tok)\n{\n");
putf("\tstatic char buf[6];\n\n");
putf("\tif (tok > 255)\n");
putf("\t\treturn _toknams[tok - 256];\n");
putf("\tif (tok == 0)\n");
putf("\t\treturn \"EOI\";\n");
putf("\tbuf[0] = '`'; buf[1] = tok; buf[2] = '\\\'';\n");
putf("\treturn buf;\n");
putf("}\n\n");
putf("static int tok = -1;\n\n");
putf("int w_nexttoken()\n");
putf("{\n\tif (tok < 0)\n\t\ttok = w_gettoken();\n");
putf("\treturn tok;\n}\n\n");
putf("void w_skiptoken()\n{\n\ttok = -1;\n}\n\n");
putf("static int scantoken(int expect, resynclink &lnk, int *resync)\n");
putf("{\n\tresynclink rlink(lnk, resync);\n\tresynclink *link;\n\n");
putf("\tif (tok < 0)\n\t\ttok = w_gettoken();\n");
putf("\tif (expect >= 0 && tok != expect)\n");
putf("\t\tw_scanerr(\"expected %%s\", w_tokenname(expect));\n");
putf("\tint level = 1;\n");
putf("\twhile (tok != expect)\n\t{\n");
putf("\t\tint l = level;\n");
putf("\t\tfor (link = &rlink; link != NULL && l-- > 0;");
putf(" link = link->prev)\n");
putf("\t\t\tfor (int i = 0; link->resync[i] >= 0; i++)\n");
putf("\t\t\t\tif (tok == link->resync[i])\n");
putf("\t\t\t\t\treturn -1;\n\n");
putf("\t\tw_scanerr(NULL);\n");