[comp.sources.misc] REPOST: v19i089: wacco - A C++ LL parser generator, Part02/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 89
Archive-name: wacco/part02

#!/bin/sh
# do not concatenate these parts, unpack them in order with /bin/sh
# file gen.C continued
#
if test ! -r _shar_seq_.tmp; then
	echo 'Please unpack part 1 first!'
	exit 1
fi
(read Scheck
 if test "$Scheck" != 2; then
	echo Please unpack part "$Scheck" next!
	exit 1
 else
	exit 0
 fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
	echo 'x - still skipping gen.C'
else
echo 'x - continuing file gen.C'
sed 's/^X//' << 'SHAR_EOF' >> 'gen.C' &&
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
echo 'File gen.C is complete' &&
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"
rm -f _shar_wnt_.tmp
fi
# ============= io.C ==============
if test -f 'io.C' -a X"$1" != X"-c"; then
	echo 'x - skipping io.C (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
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"
rm -f _shar_wnt_.tmp
fi
# ============= main.C ==============
if test -f 'main.C' -a X"$1" != X"-c"; then
	echo 'x - skipping main.C (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting main.C (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'main.C' &&
// Copyright (c) 1991 by Parag Patel.  All Rights Reserved.
static const char rcs_id[] = "$Header: main.C,v 1.22 91/02/22 16:05:39 hmgr Exp $";
X
#include "version.C"
X
#include "defs.h"
#include "toks.h"
#include <osfcn.h>
#include <stdarg.h>
X
#ifdef BSD
#include <sys/wait.h>
#endif
X
// externs for getopt()
extern char *optarg;
extern int optind;
X
// These vars are modified from the command line
boolean optimize = TRUE;
boolean dumpcode = TRUE;
boolean statonly = FALSE;
boolean docompare = TRUE;
boolean casesensitive = FALSE;
boolean dargstyle = TRUE;
boolean genlineinfo = TRUE;
char *headername = "tokens.h";
char *scannername = "scanner.l";
char *parsername = "parser.C";
X
// just other globals here
boolean exportedname = FALSE;
X
implement_array(charbuf, char);
implement_array(charvec, char*);
X
X
static charbuf buf;
static charvec vec;
X
#define issep(c) (strchr(sep, (c)) != NULL)
#define notsep(c) (strchr(sep, (c)) == NULL)
X
char **strsep(const char *str, const char *sep, int whsp, int *retnum)
{
X    buf.reset(strlen(str) + 1);
X    register char *s = buf.getarr();
X    strcpy(s, str);
X
X    register int num = 0;
X    while (*s != '\0')
X    {
X	if (whsp)		// skip leading separators?
X	    while (*s != '\0' && issep(*s))
X		s++;
X
X	vec[num++] = s;
X
X	// find next separator
X	while (*s != '\0' && notsep(*s))
X	    s++;
X	if (*s != '\0')
X	    *s++ = '\0';
X    }
X
X    vec[num] = NULL;
X
X    if (retnum != NULL)
X	*retnum = num;
X
X    return &vec[0];
}
X
const char *
strbldf(const char *format, ...)
{
X    static char buff[4][1024];
X    static int curr = 0;
X    if (++curr > 3)
X	curr = 0;
X
X    va_list ap;
X    va_start(ap, format);
X    vsprintf(buff[curr], (char*)format, ap);
X    va_end(ap);
X    return buff[curr];
}
X
X
int error(char *fmt, ...)
{
X    va_list ap;
X
X    w_numerrors++;
X    va_start(ap, fmt);
X    vfprintf(stderr, fmt, ap);
X    fprintf(stderr, ".\n");
X    va_end(ap);
X    return RETERR;
}
X
void quit(char *fmt, ...)
{
X    va_list ap;
X
X    va_start(ap, fmt);
X    vfprintf(stderr, fmt, ap);
X    fprintf(stderr, "!\n");
X    va_end(ap);
X    exit(1);
}
X
X
static unsigned prime[] =
{
X	11,
X	23,
X	47,
X	97,
X	197,
X	397,
X	797,
X	1597,
X	3203,
X	6421,
X	12853,
X	25717,
X	51437,
X	102877,
X	205759,
X	411527,
X	823117,
X	1646237,
X	3292489,
X	6584983,
X	13169977,
X	26339969,
X	52679969,
X	105359939,
X	210719881,
X	421439783,
X	842879579
};
const N = sizeof prime/sizeof *prime;
X
unsigned table_bump(unsigned hs)
{
X	if (hs < prime[N - 2])
X		for (int i = 0; i < N; i++)
X			if (prime[i] > 2 * hs)
X				return prime[i];
X
X	return prime[N - 1];
}
X
X
static void dumpset(Bitset &set)
{
X    Bitsetiter si(set);
X    symbol *s;
X    int id;
X
X    printf("(");
X    while ((id = si()) >= 0)
X    {
X	if (id == END || id == EMPTY)
X	    continue;
X	s = getsymbol(id);
X	printf(" %s", s->name);
X    }
X    if (set.isin(EMPTY))
X	printf(" []");
X    else if (set.isin(END))
X	printf(" $");
X    printf(" )\n");
}
X
static void dump(void)
{
X    symbol *sym;
X    symnode *n1, *n2;
X    int i;
X    char *s;
X
X    for (i = START; i < numsymbols(); i++)
X    {
X	sym = getsymbol(i);
X	if (sym->type == NONTERMINAL)
X	{
X	    if (sym->lexstr == NULL)
X		printf("%s", sym->name);
X	    else
X		printf("%s (%s)", sym->lexstr, sym->name);
X	    if (sym->rettype != NULL)
X		printf("<%s>", sym->rettype);
X	    printf(" use=%d usedret=%d", sym->usecount, sym->usedret);
X	    if (sym->toempty)
X		printf(" ==> []");
X	    printf("\n");
X	    s = "\t:";
X	    for (n1 = sym->node; n1 != NULL; n1 = n1->or)
X	    {
X		for (n2 = n1; n2 != NULL; n2 = n2->next)
X		{
X		    if (n2->sym->type == CODE)
X			printf("%s {%s}\n", s, n2->sym->code);
X		    else
X		    {
X			printf("%s %s[%d] = ", s, n2->sym->name,
X				n2->resync->id);
X			dumpset(*n2->resync->set);
X		    }
X		    s = "\t ";
X		}
X		s = "\t|";
X	    }
X	    printf("\t;\n");
X	}
X	else if (sym->type == TERMINAL)
X	{
X	    printf("[%s]", sym->name);
X	    if (sym->lexstr != NULL)
X		printf(" == %s", sym->lexstr);
X	    printf("\n");
X	}
X	else
X	{
X	    printf("%s == {%s}\n", sym->name, sym->code);
X	    continue;
X	}
X
X	printf("FIRST(%s)  = ", sym->name);
X	dumpset(*sym->first);
X
X	printf("FOLLOW(%s) = ", sym->name);
X	dumpset(*sym->follow);
X
X	if (sym->resync != NULL)
X	{
X	    printf("SKIP-SET(%s[%d])  = ", sym->name, sym->resync->id);
X	    dumpset(*sym->resync->set);
X	}
X
X	printf("\n");
X    }
}
X
X
static char *tmpname = ".wacco.tmp";
X
FILE *makefile(char *fname)
{
X    if (docompare)
X	fname = tmpname;
X    FILE *fp = fopen(fname, "w");
X    if (fp == NULL)
X	quit("Cannot open %s for writing!", fname);
X    return fp;
}
X
void cmpandmv(char *file)
{
X    if (!docompare)
X	return;
X
#ifdef BSD
X    int pid = fork();
#else
X    pid_t pid = fork();
#endif
X    if (pid == 0)
X    {
X	execlp("cmp", "cmp", "-s", file, tmpname, NULL);
X	exit(-1);
X    }
X
#ifdef BSD
X    union wait stat;
X    int w;
#else
X    int stat;
X    pid_t w;
#endif
X    do
X	w = wait(&stat);
X    while (w != pid && w >= 0);
X
#ifdef BSD
X    if (stat.w_termsig == 0 && stat.w_retcode == 0)
X	return;
#else
X    if (stat == 0)
X	return;
#endif
X
X    unlink(file);
X    if (link(tmpname, file) < 0)
X	quit("Cannot link %s to %s", tmpname, file);
X    unlink(tmpname);
}
X
X
void getoptions(int argc, char *argv[])
{
X    int opt;
X
X    while ((opt = getopt(argc, argv, "dciah:s:p:OCL")) != EOF)
X	switch (opt)
X	{
X	Case 'd': 
X	    statonly = TRUE;
X
X	Case 'c': 
X	    docompare = FALSE;
X
X	Case 'i': 
X	    casesensitive = TRUE;
X
X	Case 'a': 
X	    dargstyle = FALSE;
X
X	Case 'h': 
X	    headername = strdup(optarg);
X
X	Case 's': 
X	    scannername = strdup(optarg);
X
X	Case 'p': 
X	    parsername = strdup(optarg);
X
X	Case 'O': 
X	    optimize = FALSE;
X
X	Case 'C': 
X	    dumpcode = FALSE;
X	
X	Case 'L':
X	    genlineinfo = FALSE;
X
X	Default: 
X	    quit(
"Usage: %s [-dlciOCL] [-h header] [-p parser] [-s scanner] [file]", argv[0]);
X	}
}
X
X
int main(int argc, char *argv[])
{
X    getoptions(argc, argv);
X
X    initsym();
X
X    char *infile = NULL;
X    FILE *fp = stdin;
X    if (optind < argc)
X    {
X	fp = fopen(infile = argv[optind], "r");
X	if (fp == NULL)
X	    quit("Cannot open file %s for reading", argv[optind]);
X    }
X    w_setfile(fp);
X
X    if (!program())
X	return 1;
X
X    if (startsymbol == NULL && !exportedname)
X	quit("No start symbol defined");
X
X    buildsets();
X    check();
X
X    if (w_numerrors > 0)
X	quit("Not generating any w_output files");
X
X    if (statonly)
X    {
X	dump();
X	return 0;
X    }
X
X    gencode(infile);
X    if (docompare)
X	unlink(tmpname);
X    return 0;
}
SHAR_EOF
chmod 0444 main.C ||
echo 'restore of main.C failed'
Wc_c="`wc -c < 'main.C'`"
test 6362 -eq "$Wc_c" ||
	echo 'main.C: original size 6362, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= parse.C ==============
if test -f 'parse.C' -a X"$1" != X"-c"; then
	echo 'x - skipping parse.C (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting parse.C (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'parse.C' &&
#line 1 "wacco.w"
// Copyright (c) 1991 by Parag Patel.  All Rights Reserved.
static const char rcs_id[] = "$Header: parse.C,v 1.9 91/02/22 16:06:58 hmgr Exp $";
X
#define YYTEXT_DECL unsigned char yytext[]
X
#line 1
X
#undef YYTEXT_DECL
#define YYTEXT_DECL char yytext[]
X
#include "defs.h"
X
struct nodedat
{
X	symbol *sym;
X	union
X	{
X		symnode *node;
X		char *alias;
X	};
X	nodedat *prev;
X	nodedat() { sym = NULL; node = NULL; prev = NULL; }
};
X
;
X
#include "toks.h"
X
extern YYTEXT_DECL;
int w_numerrors = 0;
X
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; }
};
static _fprogram(resynclink &, int *);
static _fstatlist(resynclink &, int *);
static _fidtype(resynclink &, int *, char* &);
static _fconcatlist(resynclink &, int *, nodedat &);
static _forlist(resynclink &, int *, nodedat &);
static _fexprlist(resynclink &, int *, nodedat &);
static _fresyncset(resynclink &, int *, resynclist* &);
static _fresynclist(resynclink &, int *, resynclist* &);
static _fsettype(resynclink &, int *, int &);
static _fcount(resynclink &, int *, int &);
static _falias(resynclink &, int *, char* &);
static _fcode(resynclink &, int *, symbol* &);
X
static char *_toknams[] =
{
X	"[]",
X	"DIRECTIVE",
X	"ID",
X	"EXPORT",
X	"NULLSYM",
X	"STRING",
X	"CHARACTER",
X	"INT",
X	"BLOCKCODE",
};
X
char *w_tokenname(int tok)
{
X	static char buf[6];
X
X	if (tok > 255)
X		return _toknams[tok - 256];
X	if (tok == 0)
X		return "EOI";
X	buf[0] = '`'; buf[1] = tok; buf[2] = '\'';
X	return buf;
}
X
static int tok = -1;
X
int w_nexttoken()
{
X	if (tok < 0)
X		tok = w_gettoken();
X	return tok;
}
X
void w_skiptoken()
{
X	tok = -1;
}
X
static int scantoken(int expect, resynclink &lnk, int *resync)
{
X	resynclink rlink(lnk, resync);
X	resynclink *link;
X
X	if (tok < 0)
X		tok = w_gettoken();
X	if (expect >= 0 && tok != expect)
X		w_scanerr("expected %s", w_tokenname(expect));
X	int level = 1;
X	while (tok != expect)
X	{
X		int l = level;
X		for (link = &rlink; link != NULL && l-- > 0; link = link->prev)
X			for (int i = 0; link->resync[i] >= 0; i++)
X				if (tok == link->resync[i])
X					return -1;
X
X		w_scanerr(NULL);
X		tok = w_gettoken();
X		if (tok == expect)
X			break;
X		level++;
X	}	
X	tok = -1;
X	return expect;
}
X
int program()
{
X	resynclink _link;
X	static _follow[] = { EOI, -1 };
X	int rval;
X	int savnum = w_numerrors;
X
X	w_numerrors = 0;
X	rval = _fprogram(_link, _follow);
X	switch (w_nexttoken())
X	{
X	case EOI:
X		break;
X	default:
X		rval = w_scanerr("expected end of program");
X	}
X	if (w_numerrors > 0) rval = RETERR;
X	w_numerrors += savnum;
X	w_scanerr(NULL);
X	return rval;
}
X
X
static _resync1[] = { _EMPTY, ID, '|', NULLSYM, STRING, CHARACTER, '#', '=', '(', ')', '{', BLOCKCODE, -1 };
static _resync2[] = { _EMPTY, INT, '*', '=', -1 };
static _resync3[] = { -1 };
static _resync4[] = { ']', -1 };
static _resync5[] = { _EMPTY, ID, '{', BLOCKCODE, -1 };
static _resync6[] = { _EMPTY, '|', -1 };
static _resync7[] = { _EMPTY, ID, '[', NULLSYM, STRING, CHARACTER, '#', '(', '{', BLOCKCODE, -1 };
static _resync8[] = { _EMPTY, '+', '-', -1 };
static _resync9[] = { _EMPTY, '=', ')', -1 };
static _resync10[] = { _EMPTY, ID, ':', NULLSYM, STRING, CHARACTER, '#', '(', '{', BLOCKCODE, -1 };
static _resync11[] = { ID, INT, -1 };
static _resync12[] = { STRING, -1 };
static _resync13[] = { _EMPTY, EXPORT, ':', '[', -1 };
static _resync14[] = { '{', -1 };
static _resync15[] = { _EMPTY, '|', '=', ')', -1 };
static _resync16[] = { _EMPTY, INT, '*', -1 };
static _resync17[] = { _EMPTY, ID, '+', '-', NULLSYM, STRING, CHARACTER, '#', -1 };
static _resync18[] = { _EMPTY, ',', -1 };
static _resync19[] = { _EMPTY, ID, '|', NULLSYM, STRING, CHARACTER, '#', '(', ')', '{', BLOCKCODE, -1 };
static _resync20[] = { _EMPTY, ID, ']', '+', '-', NULLSYM, STRING, CHARACTER, '#', -1 };
static _resync21[] = { _EMPTY, ID, '<', -1 };
static _resync22[] = { _EMPTY, ID, NULLSYM, STRING, CHARACTER, '#', '(', -1 };
static _resync23[] = { _EMPTY, ID, '=', -1 };
static _resync24[] = { CHARACTER, -1 };
static _resync25[] = { '+', -1 };
static _resync26[] = { DIRECTIVE, -1 };
static _resync27[] = { BLOCKCODE, -1 };
static _resync28[] = { _EMPTY, ID, ',', '+', '-', NULLSYM, STRING, CHARACTER, '#', -1 };
static _resync29[] = { ';', -1 };
static _resync30[] = { _EMPTY, EXPORT, '<', -1 };
static _resync31[] = { _EMPTY, ID, ':', '[', NULLSYM, STRING, CHARACTER, '#', '(', '{', BLOCKCODE, -1 };
static _resync32[] = { '*', -1 };
static _resync33[] = { ID, -1 };
static _resync34[] = { NULLSYM, -1 };
static _resync35[] = { _EMPTY, ID, -1 };
static _resync36[] = { _EMPTY, ID, '[', ']', '+', '-', NULLSYM, STRING, CHARACTER, '#', -1 };
static _resync37[] = { _EMPTY, ';', '|', -1 };
static _resync38[] = { EXPORT, -1 };
static _resync39[] = { '{', BLOCKCODE, -1 };
static _resync40[] = { _EMPTY, ':', '[', -1 };
static _resync41[] = { _EMPTY, ID, '<', NULLSYM, STRING, CHARACTER, '#', '(', '{', BLOCKCODE, -1 };
static _resync42[] = { _EMPTY, ID, '<', '|', NULLSYM, STRING, CHARACTER, '#', '(', '{', BLOCKCODE, -1 };
static _resync43[] = { _EMPTY, '#', INT, '*', '=', -1 };
static _resync44[] = { INT, -1 };
static _resync45[] = { '-', -1 };
static _resync46[] = { '<', -1 };
static _resync47[] = { _EMPTY, '=', -1 };
static _resync48[] = { _EMPTY, ID, NULLSYM, STRING, CHARACTER, '#', '(', '{', BLOCKCODE, -1 };
static _resync49[] = { _EMPTY, EXPORT, '[', -1 };
static _resync50[] = { _EMPTY, '#', INT, '*', -1 };
static _resync51[] = { _EMPTY, ID, '|', NULLSYM, STRING, CHARACTER, '#', '(', '{', BLOCKCODE, -1 };
static _resync52[] = { ID, INT, '=', -1 };
static _resync53[] = { _EMPTY, DIRECTIVE, '{', BLOCKCODE, -1 };
X
static _fprogram(resynclink &_lnk, int *_resync)
{
X	resynclink _link(_lnk, _resync);
X
X	symbol* _rvcode;
X	{
X
X	resynclink &_lnk = _link;
X	resynclink _link(_lnk, _resync53);
X
X	switch (w_nexttoken())
X	{
X	case DIRECTIVE:
X		{
X			(void)scantoken(DIRECTIVE, _link, _resync26);
#line 27
X			
X			int argc;
X			char **argv = strsep(yytext, " \t", TRUE, &argc);
X			getoptions(argc, argv);
X		;
X		}
X		break;
X		default:
X		break;
X	} }
#line 22
X	 _rvcode = NULL; ;
X	(void)_fcode(_link, _resync5, _rvcode);
#line 22
X	 startcode = _rvcode; ;
X	(void)_fstatlist(_link, _resync35);
X
X	return RETOK;
}
X
static _fstatlist(resynclink &_lnk, int *_resync)
{
X	resynclink _link(_lnk, _resync);
X
X	switch (w_nexttoken())
X	{
X	case ID:
X		{
X			symbol* _rvstatement;
X			symbol* _rvcode;
X			{
X			symbol* &_rr = _rvstatement;
X			resynclink &_lnk = _link;
X			resynclink _link(_lnk, _resync5);
X
X			char* _rvidtype;
X			boolean _rv_;
X			resynclist* _rvresyncset;
X			nodedat _rvconcatlist;
X			nodedat _rvorlist;
X			(void)scantoken(ID, _link, _resync21);
#line 42
X			
X			_rr = addsymbol(yytext);
X			if (_rr->type == TERMINAL)
X				(void)addnonterm(_rr);
X			if (startsymbol == NULL) 
X			{
X				startsymbol = _rr;
X				_rr->usecount += 2;
X			}
X		;
X			(void)_fidtype(_link, _resync30, _rvidtype);
#line 53
X			
X			if (_rr->rettype != NULL && _rvidtype != NULL &&
X					strcmp(_rr->rettype, _rvidtype) != 0)
X				w_scanerr("Two types defined for %s", _rr->name);
X
X			if (_rr->rettype == NULL)
X				_rr->rettype = _rvidtype;
X			else
X				delete _rvidtype;
X		;
X			{
X			boolean &_rr = _rv_;
X			resynclink &_lnk = _link;
X			resynclink _link(_lnk, _resync13);
X
X			switch (w_nexttoken())
X	{
X	case EXPORT:
X		{
X			(void)scantoken(EXPORT, _link, _resync38);
#line 63
X			 _rr = TRUE; ;
X		}
X		break;
X				default:
#line 63
X		 _rr = FALSE; ;
X		break;
X			} }
#line 64
X			
X			if (_rv_)
X			{
X				exportedname = _rr->export = TRUE;
X				_rr->usecount += 2;
X			}
X		;
X			(void)_fresyncset(_link, _resync31, _rvresyncset);
X			(void)scantoken(':', _link, _resync10);
#line 72
X			
X			_rr->list = _rvresyncset;
X			nodedat end;
X			end.sym = _rvconcatlist.sym = _rvorlist.sym = _rr;
X			_rvconcatlist.prev = _rvorlist.prev = &end;
X		;
X			(void)_fconcatlist(_link, _resync51, _rvconcatlist);
#line 79
X			
X			symnode *node = _rr->node;
X			if (node != NULL)
X			{
X				while (node->or != NULL)
X					node = node->or;
X				node->or = _rvconcatlist.node;
X			}
X			else
X				node = _rr->node = _rvconcatlist.node;
X		;
X			(void)_forlist(_link, _resync37, _rvorlist);
#line 91
X			
X			if (node == NULL)
X				_rr->node = _rvorlist.node;
X			else if (node->or == NULL)
X				node->or = _rvorlist.node;
X			else
X				node->or->or = _rvorlist.node;
X		;
X			(void)scantoken(';', _link, _resync29);
X
X			}
X
#line 36
X			 _rvcode = NULL; ;
X			(void)_fcode(_link, _resync5, _rvcode);
#line 36
X			 addnonterm(_rvcode); ;
X			(void)_fstatlist(_link, _resync35);
X		}
X		break;
X	default:
X		break;
X	}
X	return RETOK;
}
X
static _fidtype(resynclink &_lnk, int *_resync, char* &_rr)
{
X	resynclink _link(_lnk, _resync);
X
X	switch (w_nexttoken())
X	{
X	case '<':
X		{
X			(void)scantoken('<', _link, _resync46);
#line 103
X			 _rr = readtype(); ;
X		}
X		break;
X	default:
#line 104
X		 _rr = NULL; ;
X		break;
X	}
X	return RETOK;
}
X
static _fconcatlist(resynclink &_lnk, int *_resync, nodedat &_rr)
{
X	resynclink _link(_lnk, _resync);
X
X	switch (w_nexttoken())
X	{
X	case ID:
X	case NULLSYM:
X	case STRING:
X	case CHARACTER:
X	case '#':
X	case '(':
X	case '{':
X	case BLOCKCODE:
X		{
X			symbol* _rvcode;
X			nodedat _rvexprlist;
#line 108
X			
X			_rvcode = _rvexprlist.sym = _rr.sym;
X			_rvexprlist.prev = _rr.prev;
X		;
X			(void)_fcode(_link, _resync48, _rvcode);
X			(void)_fexprlist(_link, _resync22, _rvexprlist);
#line 113
X			
X			if (_rvcode == NULL)
X				_rr.node = _rvexprlist.node;
X			else
X			{
X				_rr.node = new symnode;
X				_rr.node->sym = _rvcode;
X				_rr.node->next = _rvexprlist.node;
X			}
X		;
X		}
X		break;
X	default:
X		break;
X	}
X	return RETOK;
}
X
static _forlist(resynclink &_lnk, int *_resync, nodedat &_rr)
{
X	resynclink _link(_lnk, _resync);
X
X	switch (w_nexttoken())
X	{
X	case '|':
X		{
X			nodedat _rvconcatlist;
X			nodedat _rvorlist;
#line 127
X			
X			_rvconcatlist.sym = _rvorlist.sym = _rr.sym;
X			_rvconcatlist.prev = _rvorlist.prev = _rr.prev;
X		;
X			(void)scantoken('|', _link, _resync51);
X			(void)_fconcatlist(_link, _resync51, _rvconcatlist);
X			(void)_forlist(_link, _resync6, _rvorlist);
#line 132
X			
X			_rr.node = _rvconcatlist.node;
X			if (_rr.node == NULL)
X				_rr.node = _rvorlist.node;
X			else
X				_rr.node->or = _rvorlist.node;
X		;
X		}
X		break;
X	default:
X		break;
X	}
X	return RETOK;
}
X
static _fexprlist(resynclink &_lnk, int *_resync, nodedat &_rr)
{
X	resynclink _link(_lnk, _resync);
X
X	switch (w_nexttoken())
X	{
X	case ID:
X	case NULLSYM:
X	case STRING:
X	case CHARACTER:
X	case '#':
X	case '(':
X		{
X			nodedat _rvexpression;
X			resynclist* _rvresyncset;
X			symbol* _rvcode;
X			nodedat _rvexprlist;
#line 144
X			
X			_rvexpression.sym = _rvcode = _rvexprlist.sym = _rr.sym;
X			_rvexpression.prev = _rvexprlist.prev = _rr.prev;
X		;
X			{
X			nodedat &_rr = _rvexpression;
X			resynclink &_lnk = _link;
X			resynclink _link(_lnk, _resync7);
X
X			switch (w_nexttoken())
X	{
X	case ID:
X		{
X			char* _rvalias;
X			(void)scantoken(ID, _link, _resync23);
#line 215
X			 _rr.sym = addsymbol(yytext);  _rr.sym->usecount++; ;
X			(void)_falias(_link, _resync47, _rvalias);
#line 216
X			 _rr.alias = _rvalias; ;
X		}
X		break;
X	case NULLSYM:
X		{
X			(void)scantoken(NULLSYM, _link, _resync34);
#line 217
X			 _rr.sym = getsymbol(EMPTY); ;
X		}
X		break;
X	case '#':
X		{
X			int _rvcount;
X			char* _rvalias;
X			(void)scantoken('#', _link, _resync43);
X			(void)_fcount(_link, _resync2, _rvcount);
X			(void)_falias(_link, _resync47, _rvalias);
#line 219
X			
X			nodedat *p = _rr.prev;
X			for (int i = 0; p != NULL && (_rvcount < 0 || i < _rvcount); i++)
X			{
X				_rr.sym = p->sym;
X				p = p->prev;
X			}
X			if (_rvcount > 0 && i < _rvcount)
X				w_scanerr("not that many parentheses");
X			_rr.sym->usecount++;
X			_rr.alias = _rvalias;
X		;
X		}
X		break;
X	case STRING:
X		{
X			(void)scantoken(STRING, _link, _resync12);
#line 232
X			
X			_rr.sym = addsymbol(yytext);
X			_rr.sym->lexstr = _rr.sym->name;
X			gotlexstr = TRUE;
X		;
X		}
X		break;
X	case CHARACTER:
X		{
X			(void)scantoken(CHARACTER, _link, _resync24);
#line 238
X			
X			_rr.sym = addsymbol(yytext);
X			if (_rr.sym->lexstr == NULL)
X			{
X				char *s = strdup(yytext);
X				s[0] = s[strlen(s) - 1] = '"';
X				_rr.sym->lexstr = s;
X			}
X		;
X		}
X		break;
X	case '(':
X		{
X			char* _rvidtype;
X			nodedat _rvconcatlist;
X			nodedat _rvorlist;
X			char* _rvalias;
X			(void)scantoken('(', _link, _resync41);
X			(void)_fidtype(_link, _resync42, _rvidtype);
#line 248
X			
X			char *type = _rr.sym->rettype;
X			char *name = _rr.sym->realname;
X			static int num = 1;
X
X			addnonterm(_rr.sym = addsymbol(strbldf("_P%d", num++)));
X			_rr.sym->type = NONTERMINAL;
X			_rr.sym->rettype = _rvidtype == NULL ? type : _rvidtype;
X			_rr.sym->realname = name;
X			_rr.sym->usecount++;
X
X			_rvconcatlist.sym = _rvorlist.sym = _rr.sym;
X			_rvconcatlist.prev = _rvorlist.prev = &_rr;
X		;
X			(void)_fconcatlist(_link, _resync1, _rvconcatlist);
X			(void)_forlist(_link, _resync15, _rvorlist);
X			(void)scantoken(')', _link, _resync9);
X			(void)_falias(_link, _resync47, _rvalias);
#line 263
X			
X			_rr.sym->node = _rvconcatlist.node;
X			if (_rr.sym->node == NULL)
X				_rr.sym->node = _rvorlist.node;
X			else
X				_rr.sym->node->or = _rvorlist.node;
X			_rr.alias = _rvalias;
X		;
X		}
X		break;
X				default:
X					w_scanerr("illegal expression");
X			} }
X			(void)_fresyncset(_link, _resync7, _rvresyncset);
X			(void)_fcode(_link, _resync48, _rvcode);
X			(void)_fexprlist(_link, _resync22, _rvexprlist);
#line 149
X			
X			_rr.node = new symnode;
X			_rr.node->sym = _rvexpression.sym;
X			_rr.node->alias = _rvexpression.alias;
X			_rr.node->next = _rvexprlist.node;
X			_rr.node->list = _rvresyncset;
X			if (_rvcode != NULL)
X			{
X				_rr.node->next = new symnode;
X				_rr.node->next->sym = _rvcode;
X				_rr.node->next->next = _rvexprlist.node;
X			}
X		;
X		}
X		break;
X	default:
X		break;
X	}
X	return RETOK;
}
X
static _fresyncset(resynclink &_lnk, int *_resync, resynclist* &_rr)
{
X	resynclink _link(_lnk, _resync);
X
X	switch (w_nexttoken())
X	{
X	case '[':
X		{
X			resynclist* _rvresynclist;
X			(void)scantoken('[', _link, _resync36);
X			(void)_fresynclist(_link, _resync20, _rvresynclist);
X			(void)scantoken(']', _link, _resync4);
#line 166
X			 _rr = _rvresynclist; ;
X		}
X		break;
X	default:
#line 167
X		 _rr = NULL; ;
X		break;
X	}
X	return RETOK;
}
X
static _fresynclist(resynclink &_lnk, int *_resync, resynclist* &_rr)
{
X	resynclink _link(_lnk, _resync);
X
X	resynclist* _rvresyncitem;
X	resynclist* _rv_;
X	{
X	resynclist* &_rr = _rvresyncitem;
X	resynclink &_lnk = _link;
X	resynclink _link(_lnk, _resync28);
X
X			int _rvfirst;
X			resynclist* _rvresyncid;
X			int _rvfollow;
X			(void)_fsettype(_link, _resync17, _rvfirst);
X			{
X			resynclist* &_rr = _rvresyncid;
X			resynclink &_lnk = _link;
X			resynclink _link(_lnk, _resync17);
X
X			switch (w_nexttoken())
X	{
X	case ID:
X		{
X			(void)scantoken(ID, _link, _resync33);
#line 194
X			 _rr = new resynclist(yytext); ;
X		}
X		break;
X	case NULLSYM:
X		{
X			(void)scantoken(NULLSYM, _link, _resync34);
#line 195
X			 _rr = new resynclist(NULL); ;
X		}
X		break;
X	case STRING:
X		{
X			(void)scantoken(STRING, _link, _resync12);
#line 196
X			 _rr = new resynclist(yytext); ;
X		}
X		break;
X	case CHARACTER:
X		{
X			(void)scantoken(CHARACTER, _link, _resync24);
#line 197
X			 _rr = new resynclist(yytext); ;
X		}
X		break;
X	case '#':
X		{
X			int _rvcount;
X			(void)scantoken('#', _link, _resync50);
X			(void)_fcount(_link, _resync16, _rvcount);
#line 198
X			 _rr = new resynclist(NULL);
X						_rr->paren = _rvcount == 0 ? 1 : _rvcount; ;
X		}
X		break;
X				default:
X					w_scanerr("illegal resyncid");
X			} }
X			(void)_fsettype(_link, _resync8, _rvfollow);
#line 180
X			
X			_rr = _rvresyncid;
X			_rr->first = _rvfirst == 0 && _rvfollow == 0 ? 1 : _rvfirst;
X			_rr->follow = _rvfollow;
X		;
X
X	}
X
X	{
X	resynclist* &_rr = _rv_;
X	resynclink &_lnk = _link;
X	resynclink _link(_lnk, _resync18);
X
X	switch (w_nexttoken())
X	{
X	case ',':
X		{
X			resynclist* _rvresynclist;
X			(void)scantoken(',', _link, _resync28);
X			(void)_fresynclist(_link, _resync17, _rvresynclist);
#line 171
X			 _rr=_rvresynclist; ;
X		}
X		break;
X		default:
#line 171
X		 _rr = NULL; ;
X		break;
X	} }
#line 172
X	
X				_rr = _rvresyncitem;
X				_rr->next = _rv_;
X			;
X
X	return RETOK;
}
X
static _fsettype(resynclink &_lnk, int *_resync, int &_rr)
{
X	resynclink _link(_lnk, _resync);
X
X	switch (w_nexttoken())
X	{
X	case '+':
X		{
X			(void)scantoken('+', _link, _resync25);
#line 188
X			 _rr = 1; ;
X		}
X		break;
X	case '-':
X		{
X			(void)scantoken('-', _link, _resync45);
#line 189
X			 _rr = -1; ;
X		}
X		break;
X	default:
#line 190
X		 _rr = 0; ;
X		break;
X	}
X	return RETOK;
}
X
static _fcount(resynclink &_lnk, int *_resync, int &_rr)
{
X	resynclink _link(_lnk, _resync);
X
X	switch (w_nexttoken())
X	{
X	case INT:
X		{
X			(void)scantoken(INT, _link, _resync44);
#line 203
X			 _rr = atoi(yytext); ;
X		}
X		break;
X	case '*':
X		{
X			(void)scantoken('*', _link, _resync32);
#line 204
X			 _rr = -1; ;
X		}
X		break;
X	default:
#line 205
X		 _rr = 0; ;
X		break;
X	}
X	return RETOK;
}
X
static _falias(resynclink &_lnk, int *_resync, char* &_rr)
{
X	resynclink _link(_lnk, _resync);
X
X	switch (w_nexttoken())
X	{
X	case '=':
X		{
X			char* _rv_;
X			(void)scantoken('=', _link, _resync52);
X			{
X			char* &_rr = _rv_;
X			resynclink &_lnk = _link;
X			resynclink _link(_lnk, _resync11);
X
X			switch (w_nexttoken())
X	{
X	case ID:
X		{
X			(void)scantoken(ID, _link, _resync33);
#line 209
X			 _rr = yytext; ;
X		}
X		break;
X	case INT:
X		{
X			(void)scantoken(INT, _link, _resync44);
#line 209
X			 _rr = yytext; ;
X		}
X		break;
X				default:
X					w_scanerr("illegal alias");
X			} }
#line 210
X			 _rr = strdup(_rv_); ;
X		}
X		break;
X	default:
#line 211
X		 _rr = NULL; ;
X		break;
X	}
X	return RETOK;
}
X
static _fcode(resynclink &_lnk, int *_resync, symbol* &_rr)
{
X	resynclink _link(_lnk, _resync);
X
X	switch (w_nexttoken())
X	{
X	case '{':
X	case BLOCKCODE:
X		{
X			char* _rv_;
#line 274
X			
X			int rettype = 0;
X			int line = w_currline();
X		;
X			{
X			char* &_rr = _rv_;
X			resynclink &_lnk = _link;
X			resynclink _link(_lnk, _resync39);
X
X			switch (w_nexttoken())
X	{
X	case '{':
X		{
X			(void)scantoken('{', _link, _resync14);
#line 279
X			 _rr = readcode(rettype); ;
X		}
X		break;
X	case BLOCKCODE:
X		{
X			(void)scantoken(BLOCKCODE, _link, _resync27);
#line 280
X			 _rr = readblockcode(rettype); ;
X		}
X		break;
X				default:
X					w_scanerr("illegal code");
X			} }
#line 282
X			
X			if (_rr != NULL)
X				_rr->usedret = rettype;
X
X			_rr = new symbol;
X			_rr->name = "<code>";
X			_rr->type = CODE;
X			_rr->code = _rv_;
X			_rr->line = line;
X		;
X		}
X		break;
X	default:
#line 292
X		 _rr = NULL; ;
X		break;
X	}
X	return RETOK;
}
X
SHAR_EOF
chmod 0444 parse.C ||
echo 'restore of parse.C failed'
Wc_c="`wc -c < 'parse.C'`"
test 18403 -eq "$Wc_c" ||
	echo 'parse.C: original size 18403, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= read.C ==============
if test -f 'read.C' -a X"$1" != X"-c"; then
	echo 'x - skipping read.C (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting read.C (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'read.C' &&
// Copyright (c) 1991 by Parag Patel.  All Rights Reserved.
static const char rcs_id[] = "$Header: read.C,v 1.9 91/02/22 16:07:28 hmgr Exp $";
X
#include "defs.h"
#include "toks.h"
X
boolean gotlexstr = FALSE;
X
static charbuf codebuf;
X
X
void readccomment()
{
X	int	c, t;
X
X	c = w_input();
X	while (c != END)
X		if (c == '*')
X		{
X			t = w_input();
X			if (t == '/')
X				break;
X			c = t;
X		}
X		else
X			c = w_input();
X	if (c == END)
X		w_scanerr("expected \"*/\"");
}
X
X
char *readtype()
{
X	int len = 0;
X	int c, t;
X	int count = 0;
X
X	while ((c = w_input()) != END)
X	{
X		switch (c)
X		{
X		case '"':
X		case '\'':
X			codebuf[len++] = c;
X			while ((t = w_input()) != c && c != END)
X			{
X				codebuf[len++] = t;
X				if (t == '\\')
X					codebuf[len++] = w_input();
X			}
X			break;
X
X		case '<':
X			count++;
X			break;
X		case '>':
X			count--;
X			break;
X		default:
X			;
X		}
X
X		if (count < 0)
X			break;
X		codebuf[len++] = c;
X	}
X	if (c == END)
X		w_scanerr("expected \">\"");
X	
X	char *usercode = strnew(len);
X	for (int i = 0; i < len; i++)
X		usercode[i] = codebuf[i];
X	usercode[len] = '\0';
X
X	return usercode;
}
X
X
char *readcode(int &usedret)
{
X    int len = 0;
X    int c, t;
X    int count = 0;
X
X    while ((c = w_input()) != END)
X    {
X	switch (c)
X	{
X	case '/': 
X	    codebuf[len++] = c;
X	    c = w_input();
X
X	    if (c == '/')
X	    {
X		codebuf[len++] = c;
X		while ((c = w_input()) != '\n' && c != END)
X		    codebuf[len++] = c;
X	    }
X	    else if (c == '*')
X	    {
X		codebuf[len++] = c;
X		t = w_input();
X		while (t != END)
X		{
X		    codebuf[len++] = t;
X		    c = w_input();
X		    if (t == '*' && c == '/')
X			break;
X		    t = c;
X		}
X	    }
X	    break;
X
X	case '"': 
X	case '\'': 
X	    codebuf[len++] = c;
X	    while ((t = w_input()) != c && c != END)
X	    {
X		codebuf[len++] = t;
X		if (t == '\\')
X		    codebuf[len++] = w_input();
X	    }
X	    break;
X
X	case '$': 
X	    c = w_input();
X	    if (c == '$')
X		usedret |= RET_VALUE;
X	    else if (c == '?')
X	    {
X		usedret |= RET_CODE;
X		optimize = FALSE;
X	    }
X	    codebuf[len++] = '_';
X	    codebuf[len++] = 'r';
X	    if (c == '$' || c == '?')
X		c = (c == '$' ? 'r' : 'c');
X	    else
X		codebuf[len++] = 'v';
X	    break;
X
X	case '{': 
X	    count++;
X	    break;
X	case '}': 
X	    count--;
X	    break;
X	default: 
X	    ;
X	}
X
X	if (count < 0)
X	    break;
X	codebuf[len++] = c;
X    }
X    if (c == END)
X	w_scanerr(/*{*/ "expected \"}\"");
X
X    char *usercode = strnew(len);
X    for (int i = 0; i < len; i++)
X	usercode[i] = codebuf[i];
X    usercode[len] = '\0';
X
X    return usercode;
}
X
char *readblockcode(int &usedret)
{
X    int len = 0;
X    int c;
X    boolean done = FALSE;
X
X    while ((c = w_input()) != END)
X    {
X	switch (c)
X	{
X	case '$': 
X	    c = w_input();
X	    if (c == '$')
X		usedret |= RET_VALUE;
X	    else if (c == '?')
X	    {
X		usedret |= RET_CODE;
X		optimize = FALSE;
X	    }
X	    codebuf[len++] = '_';
X	    codebuf[len++] = 'r';
X	    if (c == '$' || c == '?')
X		c = (c == '$' ? 'r' : 'c');
X	    else
X		codebuf[len++] = 'v';
X	    break;
X
X	case '%':
X	    c = w_input();
X	    if (c == '}')
X		done = TRUE;
X	    else
X		codebuf[len++] = '%';
X
X	default: 
X	    ;
X	}
X
X	if (done)
X	    break;
X	codebuf[len++] = c;
X    }
X    if (c == END)
X	w_scanerr(/*{*/ "expected \"%%}\"");
X
X    char *usercode = strnew(len);
X    for (int i = 0; i < len; i++)
X	usercode[i] = codebuf[i];
X    usercode[len] = '\0';
X
X    return usercode;
}
X
X
char *getword()
{
X	int c;
X	char *s;
X	static char buf[100];
X
X	c = w_input();
X	while (isspace(c))
X		c = w_input();
X	if (c == END)
X		return NULL;
X
X	*(s = buf) = '\0';
X
X	for (; c != END && !isspace(c); c = w_input())
X		*s++ = c;
X	w_unput(c);
X
X	*s = '\0';
X	return buf;
}
SHAR_EOF
chmod 0444 read.C ||
echo 'restore of read.C failed'
Wc_c="`wc -c < 'read.C'`"
test 3603 -eq "$Wc_c" ||
	echo 'read.C: original size 3603, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= scan.C ==============
if test -f 'scan.C' -a X"$1" != X"-c"; then
	echo 'x - skipping scan.C (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting scan.C (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'scan.C' &&
// Copyright (c) 1991 by Parag Patel.  All Rights Reserved.
static const char rcs_id[] = "$Header: scan.C,v 1.7 91/02/22 16:07:07 hmgr Exp $";
X
#include "defs.h"
#include "toks.h"
X
#define isvalpha(c) (isalpha(c) || (c) == '_')
#define isodigit(c) (isdigit(c) && (c) < '8')
X
X
#define TEXTSIZE 1024
char yytext[TEXTSIZE];
char *text = NULL;
X
X
static void
blockcomment()
{
X	register char c = w_input();
X
loop:
X	while (c != '*' && c != END)
X		c = w_input();
X	if (c != END)
X		c = w_input();
X	if (c != '/' && c != END)
X		goto loop;
}
X
static void
linecomment()
{
X	for (register char c = w_input(); c != '\n' && c != END; c = w_input())
X		;
}
X
static void
docomment()
{
X	register char c = w_input();
X	if (c == '/')
X		linecomment();
X	else if (c == '*')
X		blockcomment();
X	else
X	{
X		w_unput(c);
X		error("ERROR:  comment expected here");
X	}
}
X
static int
doident(register int c)
{
X	for (; isvalpha(c) || isdigit(c); c = w_input())
X		*text++ = c;
X	w_unput(c);
X	return ID;
}
X
X
static int
donum(register int c)
{
X	for (; isdigit(c); c = w_input())
X		*text++ = c;
X	w_unput(c);
X	return INT;
}
X
X
static int
doquote()
{
X	register int c = w_input();
X	if (isodigit(c))
X	{
X		register int c2 = c;
X		for (c = 0; isodigit(c2); c2 = w_input())
X			c = (c << 3) | (c2 - '0');
X		w_unput(c2);
X	}
X	else
X		switch (c)
X		{
X		Case 'n':
X			c = '\n';
X		Case 't':
X			c = '\t';
X		Case 'v':
X			c = '\v';
X		Case 'b':
X			c = '\b';
X		Case 'r':
X			c = '\r';
X		Case 'f':
X			c = '\f';
X		Case '\\':
X			c = '\\';
X		Case '\'':
X			c = '\'';
X
X		Case 'e':
X			c = '\033';
X		Case '?':
X			c = '\177';
X		Case '^':
X			c = w_input();
X			if (c == '?')
X				c = '\177';
X			else if (islower(c))
X				c -= 'a' + 1;
X			else if (c >= '@' && c <= '_')
X				c -= '@';
X			else
X			{
X				w_unput(c);
X				c = '^';
X			}
X
X		Default:
X			;
X		}
X	return c;
}
X
X
static int
dochar()
{
X	register int c;
X
X	*text++ = '\'';
X	c = w_input();
X	if (c == '\\')
X		c = doquote();
X	if (c == '\'' || c == '"')
X	    *text++ = '\\';
X	*text++ = c;
X	if (w_input() != '\'')
X		error("ERROR:  \' expected here");
X	*text++ = '\'';
X	return CHARACTER;
}
X
X
static int
dostr()
{
X	register int c;
X
X	*text++ = '"';
X	for (c = w_input(); c != '"' && c != END; c = w_input())
X	{
X		if (c == '\\')
X			c = doquote();
X		if (c == '"')
X		    *text++ = '\\';
X		*text++ = c;
X	}
X	if (c != '"')
X		error("ERROR:  \" expected here");
X	*text++ = '"';
X	return STRING;
}
X
static int
doopt()
{
X	int c = w_input();
X	if (c == '{') /*}*/
X		return BLOCKCODE;
X
X	(void)doident(c);
X	*text = '\0';
X	if (strcmp(yytext, "opt") == 0)
X	{
X		*text++ = ' ';
X		register char c = w_input();
X		while (isspace(c))
X			c = w_input();
X		for (; c != '\n' && c != END; c = w_input())
X			*text++ = c;
X		return DIRECTIVE;
X	}
X	else if (strcmp(yytext, "export") == 0)
X		return EXPORT;
X	//else if (strcmp(yytext, "scan") == 0)
X	//	return SCANNER;
X	else
X	{
X		error("ERROR:  illegal %% char");
X		return ID;
X	}
}
X
int
yylex()
{
X	register int c;
X	int ret;
X
X	while ((c = w_input()) != END)
X	{
X		while (isspace(c))
X			c = w_input();
X		text = yytext;
X
X		if (isvalpha(c))
X			ret = doident(c);
X		else if (isdigit(c))
X			ret = donum(c);
X		else switch (c)
X		{
X		case '[':
X			c = w_input();
X			if (c == ']')
X				ret = NULLSYM;
X			else
X			{
X				w_unput(c);
X				ret = '[';
X			}
X			break;
X		case '$':
X			c = w_input();
X			if (c != '$')
X			{
X				w_unput(c);
X				error("ERROR:  expected $$ here");
X				continue;
X			}
X			gotlexstr = TRUE;
X			ret = EOI;
X			break;
X		case ']': case '<': case '{':
X		case '#': case '*': case '=': 
X		case '(': case ')': case ':': case ';':
X		case '|': case ',': case '+': case '-':
X			ret = c;
X			break;
X		case '/':
X			docomment();
X			continue;
X		case '%':
X			ret = doopt();
X			break;
X		case '\'':
X			ret = dochar();
X			break;
X		case '"':
X			ret = dostr();
X			break;
X		case END:
X			ret = EOI;
X			break;
X		default:
X			error("Illegal character 0x%X in file (ignored).", c);
X		}
X
X		*text = '\0';
X		return ret;
X	}
X	return EOI;
}
SHAR_EOF
chmod 0444 scan.C ||
echo 'restore of scan.C failed'
Wc_c="`wc -c < 'scan.C'`"
test 3884 -eq "$Wc_c" ||
	echo 'scan.C: original size 3884, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= sym.C ==============
if test -f 'sym.C' -a X"$1" != X"-c"; then
	echo 'x - skipping sym.C (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting sym.C (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'sym.C' &&
// Copyright (c) 1991 by Parag Patel.  All Rights Reserved.
static const char rcs_id[] = "$Header: sym.C,v 1.14 91/02/22 16:06:42 hmgr Exp $";
X
#include "defs.h"
#ifdef BSD
#  define BITSPERBYTE     8
#  define BITS(type)      (BITSPERBYTE * (int)sizeof(type))
#else
#  include <values.h>
#endif
X
inline static unsigned sethash(Bitset *key)
{
X	return key->hash();
}
X
// This is from the "dragon" Compilers book.
// It is much better than the above but somewhat slower.
//
static unsigned strhash(register const char *p)
{
X	register unsigned h = 0;
X	register g;
X	while (*p != '\0')
X	{
X		h = (h << 4) + (unsigned)*p++;
X		if (g = h & (0xF << BITS(unsigned) - 4))
X		{
X			h ^= g >> BITS(unsigned) - 4;
X			h ^= g;
X		}
X	}
X	return h;
}
X
X
typedef Bitset *Bitsetptr;
implement_table(Settab, Setiter, Set, Bitsetptr, sethash);
Settab settab;
X
X
typedef const char *charptr;
declare_table(symtab, symiter, symbol, charptr);
implement_table(symtab, symiter, symbol, charptr, strhash);
X
typedef symbol *symptr;
declare_array(symptrarr,symptr);
implement_array(symptrarr, symptr);
X
symbol *startsymbol = NULL;
symbol *startcode = NULL;
X
static symtab symlist;
static symptrarr symids, nonterms, terms;
X
X
symbol::symbol(const char *n)
{
X    name = strdup(n);
X    type = TERMINAL;
X
X    rettype = NULL;
X    lexstr = NULL;	// realname
X    code = NULL;
X
X    usedret = 0;	// lexdef, line
X
X    toempty = FALSE;
X    usecount = 0;
X    export = FALSE;
X    mkstruct = FALSE;
X
X    first = new Bitset;
X    follow = new Bitset;
X    resync = NULL;	// list
X
X    node = NULL;
}
X
X
symnode::symnode()
{
X    sym = NULL;
X    alias = NULL;
X    next = NULL;
X    or = NULL;
X    resync = NULL;	// list
}
X
resynclist::resynclist(char *n)
{
X    if (n == NULL)
X	name = NULL;
X    else
X	name = strdup(n);
X    first = follow = 0;
X    paren = 0;
X    next = NULL;
}
X
X
int
numsymbols()
{
X    return symlist.size();
}
X
symbol *
getsymbol(int id)
{
X    if (id < 0 || id >= symids.size())
X	return NULL;
X    return symids[id];
}
X
int
numterms()
{
X    return terms.size();
}
X
int
numnonterms()
{
X    return nonterms.size();
}
X
symbol *
getterm(int id)
{
X    if (id < 0 || id >= terms.size())
X	return NULL;
X    return terms[id];
}
X
symbol *
getnonterm(int id)
{
X    if (id < 0 || id >= nonterms.size())
X	return NULL;
X    return nonterms[id];
}
X
X
symbol *
addsymbol(const char *name)
{
X    if (!symlist.insert(name))
X	return &symlist();
X
X    symbol & s = symlist();
X    static int idnum = 0;
X    s.id = idnum;
X    symids[idnum++] = &s;
X    s.first = new Bitset;
X    s.follow = new Bitset;
X    return &s;
}
X
void addterm(symbol *s)
{
X    if (s == NULL)
X	return;
X
X    terms[s->parserid = (int)terms.size()] = s;
}
X
void addnonterm(symbol *s)
{
X    if (s == NULL)
X	return;
X
X    nonterms[s->parserid = (int)nonterms.size()] = s;
X    s->parserid = -1 - s->parserid;
X    if (s->type == TERMINAL)
X    {
X	s->type = NONTERMINAL;
X	s->realname = s->name;
X    }
}
X
symbol *
findsymbol(const char *name)
{
X    if (symlist.find(name))
X	return &symlist();
X    return NULL;
}
X
void initsym()
{
X    symbol *s;
X
X    s = addsymbol("$ END");	// id == 0 == END
X    s = addsymbol("[]");	// id == 1 == EMPTY
}
SHAR_EOF
chmod 0444 sym.C ||
echo 'restore of sym.C failed'
Wc_c="`wc -c < 'sym.C'`"
test 3130 -eq "$Wc_c" ||
	echo 'sym.C: original size 3130, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= table.h ==============
if test -f 'table.h' -a X"$1" != X"-c"; then
	echo 'x - skipping table.h (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting table.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'table.h' &&
// Copyright (c) 1991 by Parag Patel.  All Rights Reserved.
// $Header: table.h,v 1.5 91/05/17 16:30:00 hmgr Exp $
X
#ifndef GENERICH
#include <generic.h>
#endif
X
#include <stddef.h>
X
#define table_node(table) name2(table,node)
#define table_key(table) name2(table,key)
X
typedef unsigned TABLE_BUMP(unsigned);
extern unsigned table_bump(unsigned);
X
X
#define declare_table(table,iterator,symbol,key) \
typedef key table_key(table); \
struct table_node(table) \
{ \
X	table_node(table) *next; \
X	symbol sym; \
X	table_node(table)(key k, table_node(table) *tail) \
X		: sym(k) { next = tail; } \
X	table_node(table)(symbol &s, table_node(table) *tail) \
X		: sym(s) { next = tail; } \
}; \
class table \
{ \
X	unsigned hash_size; \
X	unsigned threshold; \
X	unsigned numnode; \
X	table_node(table) **vec; \
X	table_node(table) *curr; \
X	friend class iterator; \
X	unsigned (*bump)(unsigned); \
X	void resize(unsigned =0); \
X	void delnode(table_node(table) **); \
X	boolean insertsym(symbol&); \
public: \
X	table(unsigned hs =0, TABLE_BUMP *bump_function =NULL); \
X	table(table&); \
X	~table(); \
X	boolean find(key); \
X	boolean insert(key); \
X	boolean remove(key); \
X	boolean operator+=(key k) { return insert(k); } \
X	boolean operator-=(key k) { return remove(k); } \
X	boolean operator==(key k) { return find(k); } \
X	boolean operator!=(key k) { return !find(k); } \
X	symbol &operator[](key); \
X	symbol &get(); \
X	symbol &operator()(); \
X	symbol &operator*(); \
X	symbol *operator->(); \
X	table& clear(); \
X	table& operator=(table&); \
X	boolean operator==(table&); \
X	table& operator+=(table&); \
X	table& operator-=(table&); \
X	table& operator&=(table&); \
X	unsigned size(); \
}; \
class iterator \
{ \
X	table *parent; \
X	table_node(table) *curr; \
X	unsigned index; \
X	void transfer(table *); \
X	friend class table; \
public: \
X	iterator(); \
X	iterator(table &); \
X	~iterator(); \
X	table &operator=(table &); \
X	boolean operator==(iterator &); \
X	boolean operator!=(iterator &); \
X	operator boolean(); \
X	symbol &get(); \
X	symbol &operator()(); \
X	symbol &operator*(); \
X	symbol *operator->(); \
X	symbol &operator++(); \
X	void remove(); \
}; \
inline symbol &table::operator[](key k) \
{ \
X	void(insert(k)); \
X	return curr->sym; \
} \
inline symbol &table::get() \
{ \
X	if (curr != NULL) \
X		return curr->sym; \
X	else \
X		return *(symbol *)NULL; \
} \
inline symbol &table::operator()() { return get(); } \
inline symbol &table::operator*() { return get(); } \
inline symbol *table::operator->() { return &get(); } \
inline unsigned table::size() \
{ \
X	return numnode; \
} \
inline iterator::iterator() \
{ \
X	parent = NULL; \
X	curr = NULL; \
} \
inline iterator::iterator(table &t) \
{ \
X	parent = NULL; \
X	this->transfer(&t); \
} \
inline iterator::~iterator() \
SHAR_EOF
true || echo 'restore of table.h failed'
fi
echo 'End of  part 2'
echo 'File table.h is continued in part 3'
echo 3 > _shar_seq_.tmp
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.