[comp.sources.misc] v19i093: wacco - A C++ LL parser generator, Part06/06

parag@hpsdeb.sde.hp.com (Parag Patel) (05/19/91)

Submitted-by: Parag Patel <parag@hpsdeb.sde.hp.com>
Posting-number: Volume 19, Issue 93
Archive-name: wacco/part06

---- Cut Here and feed the following to sh ----
#!/bin/sh
# This is part 06 of wacco
# ============= gen.C ==============
if test -f 'gen.C' -a X"$1" != X"-c"; then
	echo 'x - skipping gen.C (File already exists)'
else
echo 'x - extracting gen.C (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'gen.C' &&
// 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 $";
X
#include "defs.h"
#include "toks.h"
#include <stdarg.h>
X
X
static FILE *fp = NULL;
static long curr_lineno = 1;
static const char *currfile = NULL;
static const char *inputfile = NULL;
X
static void putf(char *fmt, ...)
{
X    va_list ap;
X    char buf[1024];
X
X    va_start(ap, fmt);
X    vsprintf(buf, fmt, ap);
X    va_end(ap);
X    int nl = 0;
X    for (char *s = buf; *s != '\0'; s++)
X	if (*s == '\n')
X	    nl++;
X    curr_lineno += nl;
X    fputs(buf, fp);
}
X
inline static void put(int ch)
{
X    putc(ch, fp);
X    if (ch == '\n')
X	curr_lineno++;
}
X
X
static boolean saveret = FALSE;
static char *mkretcode(symbol *s)
{
X	s = NULL;
X	return saveret ? "_rc = " : "(void)";
}
X
static const char *mkname(symbol *sym)
{
X	if (*sym->name != '"')
X		return sym->name;
X	if (*sym->name == '\'' && sym->type == TERMINAL)
X		return sym->name;
X	return strbldf("_S%d/*%s*/", sym->id, sym->name);
}
X
static const char *mkerrname(symbol *sym)
{
X	if (sym->type == NONTERMINAL && sym->realname != NULL)
X		return sym->realname;
X	return mkname(sym);
}
X
X
static void printset(const char *name, Bitset &set)
{
X	Bitsetiter si(set);
X	symbol *s;
X	int id;
X	char *pre = "";
X
X	putf("static %s[] = { ", name);
X	while ((id = si()) >= 0)
X	{
X		if (id == EMPTY)
X			putf("%s_EMPTY", pre);
X			// continue;
X		else if (id == END)
X			putf("%sEOI", pre);
X		else
X		{
X			s = getsymbol(id);
X			putf("%s%s", pre, mkname(s));
X		}
X		pre = ", ";
X	} 
X	putf("%s-1 };\n", pre);
}
X
static void printcase(char *pre, Bitset &set)
{
X	Bitsetiter si(set);
X	symbol *s;
X	int id;
X
X	while ((id = si()) >= 0)
X	{
X		if (id == EMPTY)
X			continue;
X
X		putf("%scase ", pre);
X		if (id == END)
X			putf("EOI");
X		else
X		{
X			s = getsymbol(id);
X			putf("%s", mkname(s));
X		}
X		putf(":\n");
X	} 
}
X
inline static boolean dotype(symbol *sym)
{
X	if ((sym->usedret & RET_VALUE) || sym->rettype != NULL)
X		return TRUE;
X	else
X		return FALSE;
}
X
static const char *mktype(symbol *sym, char *pre = "", char *post = NULL)
{
X    if (!dotype(sym))
X	return "";
X    char *name;
X    if (sym->rettype == NULL)
X	name = "int";
X    else
X    {
X	name = sym->rettype;
X	if (sym->mkstruct)
X	{
X	    if (sym->realname != NULL && sym->realname != sym->name
X		    && sym->rettype == findsymbol(sym->realname)->rettype)
X		return strbldf("%s_T%s%s", pre, sym->realname, post);
X	    return strbldf("%s_T%s%s", pre, sym->name, post);
X	}
X    }
X    return strbldf("%s%s%s", pre, name, post);
}
X
static const char *mkvoidtype(symbol *sym, char *pre = "", char *post = NULL)
{
X    const char *type = mktype(sym, pre, post);
X    if (*type == '\0')
X	type = "void";
X    return type;
}
X
static void mkstruct(symbol *sym)
{
X	if (!dotype(sym) || !sym->mkstruct)
X		return;
X	char *name = sym->name;
X	if (sym->realname != NULL && sym->realname != sym->name)
X	{
X		symbol *real = findsymbol(sym->realname);
X		if (real->rettype == sym->rettype)
X		{
X			if (dotype(real))
X				return;
X			name = sym->realname;
X		}
X	}
X	putf("\nstruct _T%s\n{\n", name);
X	putf("\t%s;\n};\n", sym->rettype);
}
X
static void mkcode(char *pre, symbol *code)
{
X	if (code == NULL || code->code == NULL)
X		return;
X
X	if (genlineinfo)
X		putf("#line %d \"%s\"\n", code->line, inputfile);
X	else
X		putf("/* #line %d */\n", code->line);
X	putf("%s%s;\n", pre, code->code);
X	if (genlineinfo)
X		putf("#line %d \"%s\"\n", curr_lineno + 1, currfile);
}
X
static const char *mkvarname(symnode *start, symnode *node)
{
X	if (node->alias != NULL)
X		return node->alias;
X
X	int count = 0;
X	boolean addnum = FALSE;
X	char *name = node->sym->name;
X
X	if (node->sym->realname != NULL && node->sym->name != node->sym->realname)
X	{
X		name = "_";
X		for (symnode *n = start; n != node; n = n->next)
X			if (n->sym->type == NONTERMINAL && n->sym->realname != NULL 
X					&& n->sym->name != n->sym->realname)
X				count++;
X		for (n = n->next; n != NULL; n = n->next)
X			if (n->sym->type == NONTERMINAL && n->sym->realname != NULL 
X					&& n->sym->name != n->sym->realname)
X				addnum = TRUE;
X	}
X	else
X	{
X		for (symnode *n = start; n != node; n = n->next)
X			if (n->sym == node->sym)
X				count++;
X		for (n = n->next; n != NULL; n = n->next)
X			if (n->sym == node->sym)
X				addnum = TRUE;
X	}
X	if (addnum || count > 0)
X		return strbldf("%s%d", name, count + 1);
X	return name;
}
X
X
static void genstmt(char *pre, symnode *node)
{
X	symbol *s;
X	symnode *n;
X
X	for (n = node; n != NULL; n = n->next)
X	{
X		if (n->sym->type != NONTERMINAL || n->sym->id == EMPTY
X				|| !dotype(n->sym))
X			continue;
X		putf("%s%s _rv%s;\n", pre, mktype(n->sym), mkvarname(node, n));
X	}
X
X	for (n = node; n != NULL; n = n->next)
X	{
X		s = n->sym;
X		if (s->type == CODE)
X		{
X			if (dumpcode)
X				mkcode(pre, s);
X			continue;
X		}
X		if (s->id == EMPTY)
X			continue;
X
X		if (s->type == TERMINAL)
X			putf("%s%sscantoken(%s, _link, _resync%d);\n",
X					pre, mkretcode(s), mkname(s), n->resync->id);
X		else if (optimize && s->usecount == 1 && !s->export)
X		{
X			symbol *sym = s;
X			symnode *nn = n;
X			Bitset set(numsymbols());
X
X			putf("%s{\n", pre);
X			if (dotype(s))
X				putf("%s = _rv%s;\n", mktype(sym, pre, " &_rr"),
X						mkvarname(node, nn));
X			else
X				putf("%s\n", mktype(sym, pre, " _rr;"));
X			putf("%sresynclink &_lnk = _link;\n", pre);
X			putf("%sresynclink _link(_lnk, _resync%d);\n\n",
X					pre, nn->resync->id);
X
X			if (sym->resync != NULL)
X				putf("%s (void)scantoken(-1, _link, _resync%d);\n\n",
X						pre, sym->resync->id);
X
X			if (sym->node != NULL && sym->node->or == NULL)
X			{
X				genstmt("\t\t\t", sym->node);
X				putf("\n%s}\n\n", pre);
X				// putf("\n%sreturn RETOK;\n}\n\n", pre);
X				continue;
X			}
X
X			boolean donedefault = FALSE;
X			putf("%sswitch (w_nexttoken())\n\t{\n", pre);
X			for (symnode *n = sym->node; n != NULL; n = n->or)
X			{
X				set.clear();
X				for (symnode *s = n; s != NULL; s = s->next)
X				{
X					if (s->sym->type == CODE)
X						continue;
X					set |= *s->sym->first;
X					if (!s->sym->first->isin(EMPTY))
X						break;
X				}
X
X				if (set.size() == 0 || (set.size() == 1 && set.isin(EMPTY)))
X				{
X					donedefault = TRUE;
X					putf("%s\tdefault:\n", pre);
X					genstmt("\t\t", n);
X					if (!sym->first->isin(EMPTY))
X						putf("%s\t\tw_scanerr(\"illegal %s\");\n",
X								pre, mkerrname(sym));
X				}
X				else
X				{
X					printcase("\t", set);
X					putf("\t\t{\n");
X					genstmt("\t\t\t", n);
X					putf("\t\t}\n");
X				}
X				putf("\t\tbreak;\n");
X			}
X
X			if (!donedefault && !sym->first->isin(EMPTY))
X			{
X				putf("%s\tdefault:\n", pre);
X				putf("%s\t\tw_scanerr(\"illegal %s\");\n",
X						pre, mkerrname(sym));
X			}
X			putf("%s}", pre);
X			putf(" }\n");
X		}
X		else if (dotype(s))
X			putf("%s%s_f%s(_link, _resync%d, _rv%s);\n",
X					pre, mkretcode(s), mkname(s),
X					n->resync->id, mkvarname(node, n));
X		else
X			putf("%s%s_f%s(_link, _resync%d);\n",
X					pre, mkretcode(s), mkname(s), n->resync->id);
X		// putf(" }\n");
X	}
}
X
X
static void genheader(void)
{
X    symbol *sym;
X    int i;
X
X    putf("#ifndef _T_O_K_E_N_S_\n#define _T_O_K_E_N_S_\n\n");
X
X    putf("#ifndef NULL\n#include <stdio.h>\n#endif\n\n");
X    putf("#define RETOK 1\n");
X    putf("#define RETERR 0\n\n");
X
X    putf("enum tokenids\n{\n");
X    putf("\tEOI = 0,\n");
X    putf("\t_EMPTY = 256, /* nothing uses this yet */\n");
X    boolean doid = TRUE;
X    for (i = START; i < numsymbols(); i++)
X    {
X	sym = getsymbol(i);
X	if (sym->type != TERMINAL || *sym->name == '\'')
X	    continue;
X	if (doid)
X	    putf("\t%s = 257,\n", mkname(sym));
X	else
X	    putf("\t%s,\n", mkname(sym));
X	doid = FALSE;
X    }
X    putf("};\n\n");
X
X    if (gotlexstr)
X    {
X	putf("#ifdef __cplusplus\n");
X	putf("extern \"C\" {\n");
X	putf("extern int yylex(void);\n");
X	putf("}\n");
X	putf("#else\n");
X	putf("extern int yylex();\n");
X	putf("#endif\n\n");
X
X	putf("#ifdef FLEX_SCANNER\n");
X	putf("#   undef YY_INPUT\n");
X	putf("#   define YY_INPUT(buf,result,max_size) \\\n");
X	putf("        result = (buf[0] = w_input()) == EOI ? YY_NULL : 1;\n");
X	putf("#else\n");
X	putf("#   undef input\n");
X	putf("#   define input w_input\n");
X	putf("#   undef unput\n");
X	putf("#   define unput w_unput\n");
X	putf("#endif\n\n");
X
X    }
X
X    putf("extern int w_numerrors;\n");
X    putf("#ifdef __cplusplus\n");
X    putf("extern \"C\" {\n");
X    putf("extern int w_scanerr(const char *, ...);\n");
X    putf("extern void w_flusherrs(void);\n");
X    putf("extern void w_closefile(void);\n");
X    putf("extern int w_openfile(char *);\n");
X    putf("extern FILE *w_getfile(void);\n");
X    putf("extern void w_setfile(FILE *);\n");
X    putf("extern int w_currcol(void);\n");
X    putf("extern int w_currline(void);\n");
X    putf("extern char *w_getcurrline(void);\n");
X    putf("extern int w_input(void);\n");
X    putf("extern int w_unput(int);\n");
X    putf("extern void w_output(int);\n");
X    putf("extern int w_gettoken(void);\n");
X    putf("extern int w_nexttoken(void);\n");
X    putf("extern void w_skiptoken(void);\n");
X    putf("extern char *w_tokenname(int);\n");
X    putf("}\n");
X    putf("#else\n");
X    putf("extern int w_scanerr();\n");
X    putf("extern void w_flusherrs();\n");
X    putf("extern void w_closefile();\n");
X    putf("extern int w_openfile();\n");
X    putf("extern FILE *w_getfile();\n");
X    putf("extern void w_setfile();\n");
X    putf("extern int w_currcol();\n");
X    putf("extern int w_currline();\n");
X    putf("extern char *w_getcurrline();\n");
X    putf("extern int w_input();\n");
X    putf("extern int w_unput();\n");
X    putf("extern void w_output();\n");
X    putf("extern int w_gettoken();\n");
X    putf("extern int w_nexttoken();\n");
X    putf("extern void w_skiptoken();\n");
X    putf("extern char *w_tokenname();\n");
X    putf("#endif\n\n");
X
X    if (exportedname)
X    {
X	for (i = 0; i < numnonterms(); i++)
X	{
X	    sym = getnonterm(i);
X	    if (sym->type != NONTERMINAL || !sym->export)
X		continue;
X	    mkstruct(sym);
X	    putf("#ifdef __cplusplus\n");
X	    putf("extern \"C\" { int %s(%s); }\n", mkname(sym),
X		    mkvoidtype(sym, "", " &"));
X	    putf("#else\n");
X	    putf("extern int %s();\n", mkname(sym));
X	    putf("#endif\n");
X	}
X    }
X    else
X    {
X	mkstruct(startsymbol);
X	putf("#ifdef __cplusplus\n");
X	putf("extern \"C\" { int %s(%s); }\n", mkname(startsymbol),
X		mkvoidtype(startsymbol, "", " &"));
X	putf("#else\n");
X	putf("extern int %s();\n", mkname(startsymbol));
X	putf("#endif\n");
X    }
X
X    putf("\n\n#endif /* _T_O_K_E_N_S_ */\n");
}
X
X
static void genscanner(char *header)
{
X	symbol *sym;
X	int i, c;
X	boolean nl = TRUE;
X
X	// scan past the definition section
X	while ((c = w_input()) != END)
X	{
X		if (nl && c == '%')
X		{
X			int t = w_input();
X			if (t == '%')
X				break;
X			put(c);
X			c = t;
X		}
X		put(c);
X		nl = c == '\n';
X	}
X
X	// dump out our header stuff here
X	putf("%%{\n");
X	putf("#include \"%s\"\n", header);
X	putf("%%}\n");
X
X	putf("%%%%\n");
X
X	// print the lexical values from the grammer
X	for (i = START; i < numsymbols(); i++)
X	{
X		symbol *sym = getsymbol(i);
X		if (sym->type != TERMINAL || sym->lexdef || sym->lexstr == NULL)
X			continue;
X		if (casesensitive || sym->name[0] != '"')
X			putf("%s", sym->lexstr);
X		else
X		{
X			for (char *s = sym->lexstr + 1;
X					*s != '\0' && !(*s == '"' && *(s + 1) == '\0');
X					s++)
X				if (isalpha(*s))
X					putf("[%c%c]",
X					    islower(*s) ? toupper(*s) : *s,
X					    isupper(*s) ? tolower(*s) : *s);
X				else if (*s == '\\' && *(s+1) == '"')
X					;
X				else
X					putf("\\%c", *s);
X		}
X		putf("\t{ return (int)%s; }\n", mkname(sym));
X		sym->lexdef = TRUE;
X	}
X
X	// now add the rules at the bottom of the source
X	if (c != END)
X		while ((c = w_input()) != END)
X		{
X			if (nl && c == '%')
X			{
X				int t = w_input();
X				if (t == '%')
X					break;
X				put(c);
X				c = t;
X			}
X			else if (nl && c == '$')
X			{
X				char *name = getword();
X				if (name == NULL)
X					quit("Unexpected end-of-w_input");
X				sym = findsymbol(name);
X
X				if (sym == NULL)
X					error("Symbol %s not in grammer", name);
X				if (sym->lexstr != NULL)
X					error("Symbol %s lexical string redefined in lex section",
X							name);
X
X				while ((c = w_input()) == ' ' || c == '\t')
X					;
X				if (c == '\n' || c == END)
X					putf("\n");
X				else
X				{
X					for (; c != END && c != '\n'; c = w_input())
X						put(c);
X					putf("\t{ return (int)%s; }", name);
X				}
X				sym->lexdef = TRUE;
X			}
X			put(c);
X			nl = c == '\n';
X		}
X
X	// check for missing tokens
X	for (i = START; i < numsymbols(); i++)
X	{
X		sym = getsymbol(i);
X		if (sym->type != TERMINAL || sym->lexdef)
X			continue;
X		if (sym->lexstr == NULL)
X			error("Lexical value for symbol %s is not defined", mkname(sym));
X	}
X
X	putf("%%%%\n");
X
X	// now copy the rest (user code)
X	if (c != END)
X		while ((c = w_input()) != END)
X			put(c);
}
X
X
static void dumpexport(symbol *sym)
{
X	putf("int %s(%s)\n{\n", mkname(sym),
X		mkvoidtype(sym, "", " &ret"));
X	putf("\tresynclink _link;\n\t");
X	printset("_follow", *sym->follow);
X	putf("\tint _rval;\n");
X	putf("\tint _savnum = w_numerrors;\n\n");
X	putf("\tw_numerrors = 0;\n");
X	putf("\t_rval = _f%s(_link, _follow%s);\n",
X			mkname(sym), dotype(sym) ? ", ret" : "");
X	putf("\tswitch (w_nexttoken())\n\t{\n");
X	printcase("\t", *sym->follow);
X	putf("\t\tbreak;\n");
X	putf("\tdefault:\n");
X	putf("\t\t_rval = w_scanerr(\"expected end of %s\");\n",
X			mkname(sym));
X	putf("\t}\n");
X	putf("\tif (w_numerrors > 0) _rval = RETERR;\n");
X	putf("\tw_numerrors += _savnum;\n");
X	putf("\tw_scanerr(NULL);\n");
X	putf("\treturn _rval;\n");
X	putf("}\n\n");
}
X
X
static void genparser(char *header)
{
X	symbol *sym;
X	symnode *n;
X	int i;
X
X	putf("#define YYTEXT_DECL unsigned char yytext[]\n\n");
X	mkcode("", startcode);
X	putf("\n#include \"%s\"\n\n", header);
X	putf("extern YYTEXT_DECL;\n");
X	putf("int w_numerrors = 0;\n\n");
X
X	putf("\nstruct resynclink\n{\n\tresynclink *prev;\n");
X	putf("\tint *resync;\n");
X	putf("\tresynclink() { prev = 0; resync = 0; }\n");
X	putf("\tresynclink(resynclink &p, int *s)");
X	putf(" { prev = &p; resync = s; }\n");
X	putf("};\n");
X
X	for (i = 0; i < numnonterms(); i++)
X	{
X		sym = getnonterm(i);
X		if (sym->type != NONTERMINAL)
X			continue;
X		if (!sym->export)
X			mkstruct(sym);
X		if (optimize && sym->usecount == 1 && !sym->export)
X			continue;
X		putf("static _f%s(resynclink &, int *%s);\n", mkname(sym),
X				mktype(sym, ", ", " &"));
X	}
X	putf("\n");
X
X	putf("static char *_toknams[] =\n{\n");
X	putf("\t\"[]\",\n");
X	for (i = START; i < numsymbols(); i++)
X	{
X		sym = getsymbol(i);
X		if (sym->type != TERMINAL || *sym->name == '\'')
X			continue;
X		char *str = sym->lexstr;
X
X		if (str == NULL)
X			putf("\t\"%s\",\n", mkname(sym));
X		else if (isalpha(*str))
X			putf("\t\"%s\",\n", str);
X		else if (*str == '"' && str[strlen(str) - 1] == '"')
X			putf("\t%s,\n", sym->lexstr);
X		else
X			putf("\t\"%s\",\n", mkname(sym));
X	}
X	putf("};\n\n");
X
X	putf("char *w_tokenname(int tok)\n{\n");
X	putf("\tstatic char buf[6];\n\n");
X	putf("\tif (tok > 255)\n");
X	putf("\t\treturn _toknams[tok - 256];\n");
X	putf("\tif (tok == 0)\n");
X	putf("\t\treturn \"EOI\";\n");
X	putf("\tbuf[0] = '`'; buf[1] = tok; buf[2] = '\\\'';\n");
X	putf("\treturn buf;\n");
X	putf("}\n\n");
X
X	putf("static int tok = -1;\n\n");
X
X	putf("int w_nexttoken()\n");
X	putf("{\n\tif (tok < 0)\n\t\ttok = w_gettoken();\n");
X	putf("\treturn tok;\n}\n\n");
X
X	putf("void w_skiptoken()\n{\n\ttok = -1;\n}\n\n");
X
X	putf("static int scantoken(int expect, resynclink &lnk, int *resync)\n");
X	putf("{\n\tresynclink rlink(lnk, resync);\n\tresynclink *link;\n\n");
X	putf("\tif (tok < 0)\n\t\ttok = w_gettoken();\n");
X	putf("\tif (expect >= 0 && tok != expect)\n");
X	putf("\t\tw_scanerr(\"expected %%s\", w_tokenname(expect));\n");
X	putf("\tint level = 1;\n");
X	putf("\twhile (tok != expect)\n\t{\n");
X	putf("\t\tint l = level;\n");
X	putf("\t\tfor (link = &rlink; link != NULL && l-- > 0;");
X	putf(" link = link->prev)\n");
X	putf("\t\t\tfor (int i = 0; link->resync[i] >= 0; i++)\n");
X	putf("\t\t\t\tif (tok == link->resync[i])\n");
X	putf("\t\t\t\t\treturn -1;\n\n");
X	putf("\t\tw_scanerr(NULL);\n");
X	putf("\t\ttok = w_gettoken();\n");
X	putf("\t\tif (tok == expect)\n\t\t\tbreak;\n\t\tlevel++;\n");
X	putf("\t}\t\n\ttok = -1;\n\treturn expect;\n}\n\n");
X
X	if (exportedname)
X		for (i = 0; i < numnonterms(); i++)
X		{
X			sym = getnonterm(i);
X			if (sym->type != NONTERMINAL || !sym->export)
X				continue;
X			dumpexport(sym);
X		}
X	else
X		dumpexport(startsymbol);
X	putf("\n");
X
X	i = 1;
X	for (Setiter setiter(settab); setiter; setiter++)
X	{
X		Set &set = setiter();
X		printset(strbldf("_resync%d", set.id = i++), *set.set);
X	}
X	putf("\n");
X
X	Bitset set(numsymbols());
X	for (i = 0; i < numnonterms(); i++)
X	{
X		sym = getnonterm(i);
X		if (sym->type != NONTERMINAL)
X		{
X			if (dumpcode)
X				mkcode("", sym);
X			continue;
X		}
X		if (optimize && sym->usecount < 2 && !sym->export)
X		{
X			if (sym->usecount != 1)
X				error("Warning - non-terminal %s is never used", sym->name);
X			continue;
X		}
X
X		putf("static _f%s(resynclink &_lnk, int *_resync%s)\n",
X				mkname(sym), mktype(sym, ", ", " &_rr"));
X		putf("{\n\tresynclink _link(_lnk, _resync);\n");
X		if ((saveret = (sym->usedret & RET_CODE) ? TRUE : FALSE))
X			putf("\tint _rc;\n");
X		putf("\n");
X
X		if (sym->resync != NULL)
X		{
X			putf("\t{ ");
X			//printset("_skip", *sym->resync);
X			putf("\t  (void)scantoken(-1, _link, _resync%d); }\n\n",
X					sym->resync->id);
X		}
X
X		if (sym->node != NULL && sym->node->or == NULL)
X		{
X			genstmt("\t", sym->node);
X			putf("\n\treturn RETOK;\n}\n\n");
X			continue;
X		}
X
X		boolean donedefault = FALSE;
X		putf("\tswitch (w_nexttoken())\n\t{\n");
X		for (n = sym->node; n != NULL; n = n->or)
X		{
X			set.clear();
X			for (symnode *s = n; s != NULL; s = s->next)
X			{
X				if (s->sym->type == CODE)
X					continue;
X				set |= *s->sym->first;
X				if (!s->sym->first->isin(EMPTY))
X					break;
X			}
X
X			if (set.size() == 0 || (set.size() == 1 && set.isin(EMPTY)))
X			{
X				donedefault = TRUE;
X				putf("\tdefault:\n");
X				genstmt("\t\t", n);
X				if (!sym->first->isin(EMPTY))
X					putf("\t\treturn w_scanerr(\"illegal %s\");\n",
X							mkerrname(sym));
X			}
X			else
X			{
X				printcase("\t", set);
X				putf("\t\t{\n");
X				genstmt("\t\t\t", n);
X				putf("\t\t}\n");
X			}
X			putf("\t\tbreak;\n");
X		}
X
X		if (!donedefault && !sym->first->isin(EMPTY))
X		{
X			putf("\tdefault:\n");
X			putf("\t\treturn w_scanerr(\"illegal %s\");\n",
X					mkerrname(sym));
X		}
X
X		putf("\t}\n\treturn RETOK;\n}\n\n");
X	}
}
X
X
void gencode(char *infile)
{
X    inputfile = infile;
X
X    fp = makefile(headername);
X    currfile = headername;
X    curr_lineno = 1;
X    genheader();
X    fclose(fp);
X    cmpandmv(headername);
X
X    fp = makefile(parsername);
X    currfile = parsername;
X    curr_lineno = 1;
X    genparser(headername);
X    fclose(fp);
X    cmpandmv(parsername);
X
X    if (!gotlexstr)
X	return;
X
X    fp = makefile(scannername);
X    currfile = scannername;
X    curr_lineno = 1;
X    genscanner(headername);
X    fclose(fp);
X    cmpandmv(scannername);
}
SHAR_EOF
chmod 0444 gen.C ||
echo 'restore of gen.C failed'
Wc_c="`wc -c < 'gen.C'`"
test 18803 -eq "$Wc_c" ||
	echo 'gen.C: original size 18803, current size' "$Wc_c"
fi
# ============= io.C ==============
if test -f 'io.C' -a X"$1" != X"-c"; then
	echo 'x - skipping io.C (File already exists)'
else
echo 'x - extracting io.C (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'io.C' &&
// Copyright (c) 1991 by Parag Patel.  All Rights Reserved.
static const char rcs_id[] = "$Header: io.C,v 1.13 91/02/22 16:08:20 hmgr Exp $";
X
#include "defs.h"
#include "toks.h"
#include <stdarg.h>
X
X
#define UNPUT	300
#define MAXERR  36
X
X
struct errstack
{
X	int col;
X	boolean skip;
X	char *err;
X	errstack() { col = -1; skip = FALSE; err = NULL; }
};
X
/***********
struct resynclink
{
X	resynclink *prev;
X	int *resync;
X	resynclink() { prev = 0; resync = 0; }
X	resynclink(resynclink &p, int *s) { prev = &p; resync = s; }
};
***********/
X
X
extern char yytext[];
extern int yylex();
X
static char filename[100];
static FILE *fp = stdin;
X
static int line = -1;
static int col = 0;
static char linebuf[200] = { '\0' };
static int lineloc = 0;
static int ubuf[UNPUT];
static int top = 0;
X
static int tokcol = 0;
static errstack errstk[MAXERR];
static int numerrs = 0;
X
X
void w_flusherrs()
{
X    line++;
X    if (numerrs <= 0)
X	return;
X
X    fprintf(stderr, "%d:\t%s", line, linebuf);
X    if (linebuf[strlen(linebuf) - 1] != '\n')
X	fprintf(stderr, "\n");
X    fprintf(stderr, "\t");
X
X    int i;
X    int pcol = 0;
X    for (i = 0; i < numerrs; i++)
X    {
X	for (; pcol < errstk[i].col - 1; pcol++)
X	    fprintf(stderr, linebuf[pcol] == '\t' ? "\t" :
X		    (errstk[i].skip ? "*" : " "));
X
X	if (i > 0 && errstk[i].col == errstk[i - 1].col)
X	    continue;
X
X	if (linebuf[pcol++] == '\t')
X	    fprintf(stderr, "\t");
X
X	fprintf(stderr, errstk[i].skip ? "*" : "^");
X    }
X    fprintf(stderr, "\n");
X
X    int last = -1;
X    for (i = 0; i < numerrs; i++)
X    {
X	if (errstk[i].skip)
X	    continue;
X	/* ** if (last >= 0 && errstk[i].col == errstk[last].col &&
X	   strncmp(errstk[i].err, errstk[last].err, 5) == 0) continue;
X	   last = i; ** */
X
X	fprintf(stderr, "\t");
X	for (int j = 0; j < errstk[i].col - 1; j++)
X	    fprintf(stderr, linebuf[j] == '\t' ? "\t" : " ");
X
X	if (linebuf[j] == '\t')
X	    fprintf(stderr, "\t");
X	fprintf(stderr, "%s\n", errstk[i].err);
X    }
X
X    numerrs = 0;
}
X
X
extern int w_numerrors;
extern "C" int w_vscanerr(const char *fmt, va_list ap);
int w_vscanerr(const char *fmt, va_list ap)
{
X    w_numerrors++;
X
X    if (numerrs >= MAXERR)
X    {
X	w_flusherrs();
X	line--;
X    }
X
X    if (errstk[numerrs].err == NULL)
X	errstk[numerrs].err = strnew(150);
X
X    if (fmt == NULL)
X    {
X	errstk[numerrs].skip = TRUE;
X	errstk[numerrs].col = col;
X    }
X    else
X    {
X	errstk[numerrs].skip = FALSE;
X	errstk[numerrs].col = tokcol;
X	vsprintf(errstk[numerrs].err, (char *)fmt, ap);
X    }
X    numerrs++;
X    return RETERR;
}
X
int w_scanerr(const char *fmt, ...)
{
X    if (fmt == NULL)
X    {
X	w_flusherrs();
X	return RETERR;
X    }
X
X    va_list ap;
X    va_start(ap, fmt);
X    w_vscanerr(fmt, ap);
X    va_end(ap);
X    return RETERR;
}
X
X
int w_input()
{
X    int c;
X
X    if (top > 0)
X	return ubuf[--top];
X    c = linebuf[lineloc++];
X    while (c == '\0')
X    {
X	w_flusherrs();
X	lineloc = 0;
X	tokcol = col = 0;
X	*linebuf = '\0';
X	if (fgets(linebuf, sizeof linebuf - 2, fp) == NULL)
X	    return END;
X	c = linebuf[lineloc++];
X    }
X    col++;
X    return c;
}
X
X
int w_unput(int c)
{
X    if (top >= UNPUT)
X    {
X	fprintf(stderr, "Cannot w_unput any more characters");
X	exit(11);
X    }
X    ubuf[top++] = c;
X    return 0;
}
X
X
void w_output(int c)
{
X    putchar(c);
}
X
X
void w_closefile()
{
X    if (fp == NULL)
X	return;
X    fclose(fp);
}
X
X
int w_openfile(char *fname)
{
X    if (fp != NULL)
X	w_closefile();
X    if ((fp = fopen(fname, "r")) == NULL)
X	return RETERR;
X    strncpy(filename, fname, sizeof filename - 1);
X    return RETOK;
}
X
X
FILE *w_getfile()
{
X    return fp;
}
X
void w_setfile(FILE *f)
{
X    fp = f;
X    *filename = '\0';
}
X
int w_currcol()
{
X    return col;
}
X
int w_currline()
{
X    return line + 1;
}
X
char *w_getcurrline()
{
X    return linebuf;
}
X
X
int w_gettoken()
{
X    int ret = yylex();
X    tokcol = col - strlen(yytext);
X    return ret;
}
SHAR_EOF
chmod 0444 io.C ||
echo 'restore of io.C failed'
Wc_c="`wc -c < 'io.C'`"
test 3832 -eq "$Wc_c" ||
	echo 'io.C: original size 3832, current size' "$Wc_c"
fi
# ============= version.C ==============
if test -f 'version.C' -a X"$1" != X"-c"; then
	echo 'x - skipping version.C (File already exists)'
else
echo 'x - extracting version.C (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'version.C' &&
// Copyright (c) 1991 by Parag Patel.  All Rights Reserved.
X
static char *const whatid = "@(#)wacco 1.1 (17 May 1991)";
SHAR_EOF
chmod 0444 version.C ||
echo 'restore of version.C failed'
Wc_c="`wc -c < 'version.C'`"
test 120 -eq "$Wc_c" ||
	echo 'version.C: original size 120, current size' "$Wc_c"
fi
exit 0

exit 0 # Just in case...
-- 
Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
Sterling Software, IMD           UUCP:     uunet!sparky!kent
Phone:    (402) 291-8300         FAX:      (402) 291-4362
Please send comp.sources.misc-related mail to kent@uunet.uu.net.