[comp.sources.misc] v19i091: wacco - A C++ LL parser generator, Part04/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 91
Archive-name: wacco/part04

---- Cut Here and feed the following to sh ----
#!/bin/sh
# This is part 04 of wacco
# ============= wacco.w ==============
if test -f 'wacco.w' -a X"$1" != X"-c"; then
	echo 'x - skipping wacco.w (File already exists)'
else
echo 'x - extracting wacco.w (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'wacco.w' &&
{
// Copyright (c) 1991 by Parag Patel.  All Rights Reserved.
static const char rcs_id[] = "$Header: wacco.w,v 1.13 91/02/22 16:04:36 hmgr Exp $";
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
program
X	: directives { $code = NULL; } code { startcode = $code; } statlist
X	;
X
directives
X	: DIRECTIVE
X		{
X			int argc;
X			char **argv = strsep(yytext, " \t", TRUE, &argc);
X			getoptions(argc, argv);
X		}
X	| []
X	;
X
statlist
X	: statement { $code = NULL; } code { addnonterm($code); } statlist 
X	| []
X	;
X
statement<symbol*>
X	:	ID
X		{
X			$$ = addsymbol(yytext);
X			if ($$->type == TERMINAL)
X				(void)addnonterm($$);
X			if (startsymbol == NULL) 
X			{
X				startsymbol = $$;
X				$$->usecount += 2;
X			}
X		}
X		idtype
X		{
X			if ($$->rettype != NULL && $idtype != NULL &&
X					strcmp($$->rettype, $idtype) != 0)
X				scanerr("Two types defined for %s", $$->name);
X
X			if ($$->rettype == NULL)
X				$$->rettype = $idtype;
X			else
X				delete $idtype;
X		}
X		(<boolean> EXPORT { $$ = TRUE; } | [] { $$ = FALSE; })
X		{
X			if ($_)
X			{
X				exportedname = $$->export = TRUE;
X				$$->usecount += 2;
X			}
X		}
X		resyncset ':'
X		{
X			$$->list = $resyncset;
X			nodedat end;
X			end.sym = $concatlist.sym = $orlist.sym = $$;
X			$concatlist.prev = $orlist.prev = &end;
X		}
X		concatlist
X		{
X			symnode *node = $$->node;
X			if (node != NULL)
X			{
X				while (node->or != NULL)
X					node = node->or;
X				node->or = $concatlist.node;
X			}
X			else
X				node = $$->node = $concatlist.node;
X		}
X		orlist
X		{
X			if (node == NULL)
X				$$->node = $orlist.node;
X			else if (node->or == NULL)
X				node->or = $orlist.node;
X			else
X				node->or->or = $orlist.node;
X		}
X		';'
X	;
X
idtype<char*>
X	: '<'	{ $$ = readtype(); }
X	| []	{ $$ = NULL; }
X	;
X
concatlist<nodedat>
X	:	{
X			$code = $exprlist.sym = $$.sym;
X			$exprlist.prev = $$.prev;
X		} 
X		code exprlist
X		{
X			if ($code == NULL)
X				$$.node = $exprlist.node;
X			else
X			{
X				$$.node = new symnode;
X				$$.node->sym = $code;
X				$$.node->next = $exprlist.node;
X			}
X		}
X	| []
X	;
X
orlist<nodedat>
X	:	{
X			$concatlist.sym = $orlist.sym = $$.sym;
X			$concatlist.prev = $orlist.prev = $$.prev;
X		}
X		'|' concatlist orlist
X		{
X			$$.node = $concatlist.node;
X			if ($$.node == NULL)
X				$$.node = $orlist.node;
X			else
X				$$.node->or = $orlist.node;
X		}
X	| []
X	;
X
X
exprlist<nodedat>
X	:	{
X			$expression.sym = $code = $exprlist.sym = $$.sym;
X			$expression.prev = $exprlist.prev = $$.prev;
X		}
X		expression resyncset code exprlist
X		{
X			$$.node = new symnode;
X			$$.node->sym = $expression.sym;
X			$$.node->alias = $expression.alias;
X			$$.node->next = $exprlist.node;
X			$$.node->list = $resyncset;
X			if ($code != NULL)
X			{
X				$$.node->next = new symnode;
X				$$.node->next->sym = $code;
X				$$.node->next->next = $exprlist.node;
X			}
X		}
X	| []
X	;
X
resyncset<resynclist*>
X	: '[' resynclist ']'	{ $$ = $resynclist; }
X	| []					{ $$ = NULL; }
X	;
X
resynclist<resynclist*>
X	: resyncitem (',' resynclist { $$=$resynclist; } | [] { $$ = NULL; })
X			{
X				$$ = $resyncitem;
X				$$->next = $_;
X			}
X	;
X
resyncitem<resynclist*>
X	: settype=first resyncid settype=follow
X		{
X			$$ = $resyncid;
X			$$->first = $first == 0 && $follow == 0 ? 1 : $first;
X			$$->follow = $follow;
X		}
X	;
X
settype
X	: '+'	{ $$ = 1; }
X	| '-'	{ $$ = -1; }
X	| []	{ $$ = 0; }
X	;
X
resyncid<resynclist*>
X	: ID			{ $$ = new resynclist(yytext); }
X	| NULLSYM		{ $$ = new resynclist(NULL); }
X	| STRING		{ $$ = new resynclist(yytext); }
X	| CHARACTER		{ $$ = new resynclist(yytext); }
X	| '#' count		{ $$ = new resynclist(NULL);
X						$$->paren = $count == 0 ? 1 : $count; }
X	;
X
count
X	: INT	{ $$ = atoi(yytext); }
X	| '*'	{ $$ = -1; }
X	| []	{ $$ = 0; }
X	;
X
alias<char*>
X	: '=' (ID { $$ = yytext; } | INT { $$ = yytext; })
X			{ $$ = strdup($_); }
X	| []	{ $$ = NULL; }
X	;
X
expression<nodedat>
X	: ID		{ $$.sym = addsymbol(yytext);  $$.sym->usecount++; }
X		alias	{ $$.alias = $alias; }
X	| NULLSYM	{ $$.sym = getsymbol(EMPTY); }
X	| '#' count alias
X		{
X			nodedat *p = $$.prev;
X			for (int i = 0; p != NULL && ($count < 0 || i < $count); i++)
X			{
X				$$.sym = p->sym;
X				p = p->prev;
X			}
X			if ($count > 0 && i < $count)
X				scanerr("not that many parentheses");
X			$$.sym->usecount++;
X			$$.alias = $alias;
X		}
X	| STRING
X		{
X			$$.sym = addsymbol(yytext);
X			$$.sym->lexstr = $$.sym->name;
X			gotlexstr = TRUE;
X		}
X	| CHARACTER
X		{
X			$$.sym = addsymbol(yytext);
X			if ($$.sym->lexstr == NULL)
X			{
X				char *s = strdup(yytext);
X				s[0] = s[strlen(s) - 1] = '"';
X				$$.sym->lexstr = s;
X			}
X		}
X	| '(' idtype
X		{
X			char *type = $$.sym->rettype;
X			char *name = $$.sym->realname;
X			static int num = 1;
X
X			addnonterm($$.sym = addsymbol(strbldf("_P%d", num++)));
X			$$.sym->type = NONTERMINAL;
X			$$.sym->rettype = $idtype == NULL ? type : $idtype;
X			$$.sym->realname = name;
X			$$.sym->usecount++;
X
X			$concatlist.sym = $orlist.sym = $$.sym;
X			$concatlist.prev = $orlist.prev = &$$;
X		}
X		concatlist orlist ')' alias
X		{
X			$$.sym->node = $concatlist.node;
X			if ($$.sym->node == NULL)
X				$$.sym->node = $orlist.node;
X			else
X				$$.sym->node->or = $orlist.node;
X			$$.alias = $alias;
X		}
X	;
X
code<symbol*>
X	:	{
X			int rettype = 0;
X			int line = currline();
X		}
X		(<char*>
X			'{'		{ $$ = readcode(rettype); }
X			| BLOCKCODE	{ $$ = readblockcode(rettype); }
X		)
X		{
X			if ($$ != NULL)
X				$$->usedret = rettype;
X
X			$$ = new symbol;
X			$$->name = "<code>";
X			$$->type = CODE;
X			$$->code = $_;
X			$$->line = line;
X		}
X	| []	{ $$ = NULL; }
X	;
SHAR_EOF
chmod 0444 wacco.w ||
echo 'restore of wacco.w failed'
Wc_c="`wc -c < 'wacco.w'`"
test 5585 -eq "$Wc_c" ||
	echo 'wacco.w: original size 5585, current size' "$Wc_c"
fi
# ============= defs.h ==============
if test -f 'defs.h' -a X"$1" != X"-c"; then
	echo 'x - skipping defs.h (File already exists)'
else
echo 'x - extracting defs.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'defs.h' &&
// Copyright (c) 1991 by Parag Patel.  All Rights Reserved.
// $Header: defs.h,v 1.15 91/05/17 16:29:55 hmgr Exp $
X
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <malloc.h>
X
#include "boolean.h"
#include "darray.h"
#include "table.h"
#include "bitset.h"
X
inline char *strdup(const char *s)
X	{ return s == NULL ? NULL : strcpy((char*)malloc(strlen(s) + 1), s); }
inline char *strnew(size_t len) { return (char*)malloc(len + 1); }
#if FREE_TAKES_CHAR
inline void strfree(const char *s) { if (s != NULL) free((char *)s); }
#else
inline void strfree(const char *s) { if (s != NULL) free((const void *)s); }
#endif
X
// for large switch statements
#define Case break;case
#define Default break;default
X
X
const TERMINAL 		= 1;
const NONTERMINAL	= 2;
const CODE		= 3;
X
const END		= 0;
const EMPTY		= 1;
const START		= 2;
X
X
#define RET_NONE	0x00
#define RET_VALUE	0x01
#define RET_CODE	0x02
X
X
struct symbol;
struct symnode;
struct resynclist;
X
struct Set
{
X    Bitset *set;
X    int id;
X
X    Set(Bitset *s = NULL) { set = s; }
X    operator Bitset*() { return set; }
X    boolean operator==(Bitset *b) { return *set == *b; };
};
X
struct symbol
{
X    char *name;
X    int id;
X    int parserid;
X    int type;
X
X    char *rettype;
X    union
X    {
X	char *lexstr;
X	char *realname;
X    };
X    char *code;
X
X    union
X    {
X	int usedret;
X	boolean lexdef;
X	int line;
X    };
X
X    int usecount;
X    char toempty;
X    char export;
X    char mkstruct;
X
X    Bitset *first;
X    Bitset *follow;
X    union
X    {
X	Set *resync;
X	resynclist *list;
X    };
X
X    symnode *node;
X
X    symbol(const char *n = NULL);
X    operator char *() { return name; }
X    boolean operator==(const char *k) { return strcmp(name, k) == 0; }
};
X
struct symnode
{
X    symbol *sym;
X    char *alias;
X    symnode *next;
X    symnode *or;
X    union
X    {
X	Set *resync;
X	resynclist *list;
X    };
X
X    symnode();
};
X
struct resynclist
{
X    char *name;
X    char first;
X    char follow;
X    char paren;
X    resynclist *next;
X
X    resynclist(char *);
X    ~resynclist() { delete name; }
};
X
X
declare_table(Settab, Setiter, Set, Bitset*);
extern Settab settab;
X
extern boolean optimize;
extern boolean dumpcode;
extern boolean statonly;
extern boolean docompare;
extern boolean casesensitive;
extern boolean dargstyle;
extern boolean genlineinfo;
extern char *headername;
extern char *scannername;
extern char *parsername;
extern void getoptions(int argc, char *argv[]);
extern FILE *makefile(char *fname);
extern void cmpandmv(char *file);
extern boolean exportedname;
X
extern int numsymbols(void);
extern symbol *getsymbol(int);
extern int numterms(void);
extern int numnonterms(void);
extern symbol *getterm(int);
extern symbol *getnonterm(int);
extern symbol *addsymbol(const char *);
extern void addterm(symbol *);
extern void addnonterm(symbol *);
extern symbol *findsymbol(const char *);
extern void initsym(void);
extern symbol *startsymbol;
extern symbol *startcode;
X
extern "C" {
X    extern int w_input(void);
X    extern int w_unput(int chr);
}
X
extern boolean gotlexstr;
extern void readccomment(void);
extern char *readtype(void);
extern char *readcode(int &);
extern char *readblockcode(int &);
extern char *getword(void);
X
extern void buildsets(void);
extern void check(void);
extern void gencode(char *infile);
X
extern void quit(char *fmt, ...);
extern int error(char *fmt, ...);
X
extern char **strsep(const char *str, const char *sep,
X	boolean whsp = TRUE, int *num = NULL);
extern const char *strbldf(const char *fmt, ...);
X
declare_array(charbuf, char);
declare_array(charvec, char*);
SHAR_EOF
chmod 0444 defs.h ||
echo 'restore of defs.h failed'
Wc_c="`wc -c < 'defs.h'`"
test 3575 -eq "$Wc_c" ||
	echo 'defs.h: original size 3575, current size' "$Wc_c"
fi
# ============= toks.h ==============
if test -f 'toks.h' -a X"$1" != X"-c"; then
	echo 'x - skipping toks.h (File already exists)'
else
echo 'x - extracting toks.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'toks.h' &&
// Copyright (c) 1991 by Parag Patel.  All Rights Reserved.
// $Header: toks.h,v 1.9 91/02/22 16:04:47 hmgr Exp $
X
#ifndef _T_O_K_E_N_S_
#define _T_O_K_E_N_S_
X
#ifndef NULL
#include <stdio.h>
#endif
X
#define RETOK 1
#define RETERR 0
X
enum tokenids
{
X	EOI = 0,
X	_EMPTY = 256, /* nothing uses this yet */
X	DIRECTIVE = 257,
X	ID,
X	EXPORT,
X	NULLSYM,
X	STRING,
X	CHARACTER,
X	INT,
X	BLOCKCODE,
};
X
#ifdef __cplusplus
extern "C" {
extern int yylex();
extern int yylook();
extern int w_input();
extern int w_unput(int);
extern void w_output(int);
}
#else
extern int yylex();
extern int yylook();
extern int w_input();
extern int w_unput();
extern void w_output();
#endif
X
extern int w_numerrors;
#ifdef __cplusplus
extern "C" {
extern int w_scanerr(const char *, ...);
extern void w_flusherrs();
extern void w_closefile();
extern int w_openfile(char *);
extern FILE *w_getfile();
extern void w_setfile(FILE *);
extern int w_currcol();
extern int w_currline();
extern char *w_getcurrline();
extern int w_gettoken();
extern int w_nexttoken();
extern void w_skiptoken();
extern char *w_tokenname(int);
}
#else
extern int w_scanerr();
extern void w_flusherrs();
extern void w_closefile();
extern int w_openfile();
extern FILE *w_getfile();
extern void w_setfile();
extern int w_currcol();
extern int w_currline();
extern char *w_getcurrline();
extern int w_gettoken();
extern int w_nexttoken();
extern void w_skiptoken();
extern char *w_tokenname();
#endif
X
#ifdef __cplusplus
extern "C" { int program(); }
#else
extern int program();
#endif
X
X
#endif /* _T_O_K_E_N_S_ */
SHAR_EOF
chmod 0444 toks.h ||
echo 'restore of toks.h failed'
Wc_c="`wc -c < 'toks.h'`"
test 1555 -eq "$Wc_c" ||
	echo 'toks.h: original size 1555, current size' "$Wc_c"
fi
# ============= boolean.h ==============
if test -f 'boolean.h' -a X"$1" != X"-c"; then
	echo 'x - skipping boolean.h (File already exists)'
else
echo 'x - extracting boolean.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'boolean.h' &&
// Copyright (c) 1991 by Parag Patel.  All Rights Reserved.
// $Header: boolean.h,v 1.3 91/02/22 16:04:53 hmgr Exp $
X
typedef int boolean;
const boolean FALSE = 0;
const boolean TRUE = 1;
SHAR_EOF
chmod 0444 boolean.h ||
echo 'restore of boolean.h failed'
Wc_c="`wc -c < 'boolean.h'`"
test 188 -eq "$Wc_c" ||
	echo 'boolean.h: original size 188, current size' "$Wc_c"
fi
# ============= bitset.h ==============
if test -f 'bitset.h' -a X"$1" != X"-c"; then
	echo 'x - skipping bitset.h (File already exists)'
else
echo 'x - extracting bitset.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'bitset.h' &&
// Copyright (c) 1991 by Parag Patel.  All Rights Reserved.
// $Header: bitset.h,v 1.3 91/02/22 16:04:57 hmgr Exp $
X
#define __B_S_BIT(n) ((long)(1L << (n & 0x1F)))
#define __B_S_ELT(n) (n >> 5)
X
// a set of ints (esp. enums) - also an array of bits
class Bitset
{
X    int num;
X    long *elts;
X
X    friend class Bitsetiter;
X
X    void bumpsize(int);		// grow the Bitset
X    // inline for speed
X    void BUMPSIZE(int largest) { if (num < largest) bumpsize(largest); }
X
public: 
X    Bitset(int, int,...);	// new element list
X    Bitset(int);		// new size
X    Bitset(Bitset const &);	// new Bitset
X    Bitset() { elts = new long; num = 0; elts[0] = 0L; }
X    ~Bitset() { delete elts; }	// destructor
X
X    Bitset& operator=(Bitset const &);   // dup
X
X    Bitset& add(int);		// add to
X    Bitset& remove(int);	// delete from
X    Bitset& operator+=(int e) { return add(e); }
X    Bitset& operator-=(int e) { return remove(e); }
X
X    int size() const;			// number of elements in Bitset
X    int card() const { return size(); }	// for clarity?
X    boolean isin(int bit) const
X	{ return bit >= 0 && bit <= num &&
X		(elts[__B_S_ELT(bit)] & __B_S_BIT(bit)); }
X    void clear();		// clear the set
X    unsigned long hash() const;	// return a hash number for this set
X
X    Bitset& operator|=(Bitset const &);  // union with
X    Bitset& operator&=(Bitset const &);  // intersect with
X    Bitset& operator-=(Bitset const &);  // difference from
X    Bitset& operator^=(Bitset const &);  // symmetric difference from
X    Bitset& operator~();	// complement self
X
X    int get(int elt) const
X	    { return (elt >= 0 && elt <= num &&
X		    (elts[__B_S_ELT(elt)] & __B_S_BIT(elt))) ? 1 : 0; }
X    int operator[](int elt) const { return get(elt); }
X
X    // equality testing:
X    boolean operator==(Bitset const &s) const;
X    boolean operator!=(Bitset const &s) const { return !(s == *this); }
X    // subset and superset:
X    boolean operator<=(Bitset const &s) const;
X    boolean operator>=(Bitset const &s) const { return s <= *this; }
X    // proper subset and proper superset:
X    boolean operator<(Bitset const &s) const 
X	    { return *this != s && *this <= s; }
X    boolean operator>(Bitset const &s) const { return s < *this; }
};
X
// iterator over a Bitset
class Bitsetiter
{
X    int elt, len;
X    int *arr;
X
public: 
X    Bitsetiter(Bitset const &);	// creator - iterate over a set
X    ~Bitsetiter() { delete arr; }
X    // get next element in set
X    int operator()() { return elt >= len ? elt = 0, -1 : arr[elt++]; }
};
X
#undef __B_S_ELT
#undef __B_S_BIT
SHAR_EOF
chmod 0444 bitset.h ||
echo 'restore of bitset.h failed'
Wc_c="`wc -c < 'bitset.h'`"
test 2537 -eq "$Wc_c" ||
	echo 'bitset.h: original size 2537, current size' "$Wc_c"
fi
# ============= darray.h ==============
if test -f 'darray.h' -a X"$1" != X"-c"; then
	echo 'x - skipping darray.h (File already exists)'
else
echo 'x - extracting darray.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'darray.h' &&
// Copyright (c) 1991 by Parag Patel.  All Rights Reserved.
// $Header: darray.h,v 1.3 91/02/22 16:05:04 hmgr Exp $
X
// Handle simple dynamic arrays of arbitrary type and range.
// They are automatically grown to fit any array-like reference.
// by Parag Patel
X
X
// this is used to create an ARRAY of a TYPE
#define declare_array(ARRAY, TYPE) \
class ARRAY \
{ \
X	long len; \
X	long max; \
X	TYPE *arr; \
X	TYPE &bumpsize(long); \
public: \
X	ARRAY() { arr = 0; max = len = 0; } \
X	ARRAY(long siz) \
X		{ arr = 0; max = len = 0; if (siz > 0) bumpsize(siz-1); } \
X	ARRAY(const ARRAY &); \
X	~ARRAY() { delete[max] arr; } \
X	ARRAY &operator=(const ARRAY &); \
X	long size() const { return len; } \
X	void reset(long l = 0) { bumpsize(l); len = l; } \
X	TYPE &operator[](long e) \
X		{ if (e < len) return arr[e]; else return bumpsize(e); } \
X	TYPE *getarr() { return arr; } \
};
X
X
// this implements an ARRAY of a TYPE
#define implement_array(ARRAY, TYPE) \
TYPE &ARRAY::bumpsize(long elt) \
{ \
X	if (elt < 0) \
X	    elt = 0; \
X	if (elt >= max) \
X	{ \
X		long omax = max; \
X		if (max <= 0) \
X			max = 1; \
X		TYPE *narr = new TYPE[max = elt + (max > 1024 ? 1024 : max)]; \
X		for (long i = 0; i < len; i++) \
X			narr[i] = arr[i]; \
X		delete[omax] arr; \
X		arr = narr; \
X	} \
X	if (elt >= len) \
X		len = elt + 1; \
X	return arr[elt]; \
} \
ARRAY &ARRAY::operator=(const ARRAY &a) \
{ \
X	if (&a == this) \
X	    return *this; \
X	if (a.len > len) \
X		bumpsize(a.len); \
X	len = a.len; \
X	for (long i = 0; i < len; i++) \
X		arr[i] = a.arr[i]; \
X	return *this; \
} \
ARRAY::ARRAY(const ARRAY &t) \
{ \
X	arr = 0; \
X	max = len = 0; \
X	*this = t; \
}
SHAR_EOF
chmod 0444 darray.h ||
echo 'restore of darray.h failed'
Wc_c="`wc -c < 'darray.h'`"
test 1624 -eq "$Wc_c" ||
	echo 'darray.h: original size 1624, current size' "$Wc_c"
fi
# ============= table.h ==============
if test -f 'table.h' -a X"$1" != X"-c"; then
	echo 'x - skipping table.h (File already exists)'
else
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() \
{ \
X	this->transfer(NULL); \
} \
inline table &iterator::operator=(table &t) \
{ \
X	this->transfer(&t); \
X	return t; \
} \
inline boolean iterator::operator==(iterator &i) \
{ \
X	return (curr == i.curr); \
} \
inline boolean iterator::operator!=(iterator &i) \
{ \
X	return (curr != i.curr); \
} \
inline iterator::operator boolean() \
{ \
X	return (curr != NULL); \
} \
inline symbol &iterator::get() \
{ \
X	if (curr != NULL) \
X		return curr->sym; \
X	else \
X		return *(symbol *)NULL; \
} \
inline symbol &iterator::operator()() { return get(); } \
inline symbol &iterator::operator*() { return get(); } \
inline symbol *iterator::operator->() { return &get(); } \
X
X
X
#define implement_table(table,iterator,symbol,key,hash_func) \
table::table(unsigned hs, TABLE_BUMP *bump_function) \
{ \
X	hash_size = 0; \
X	numnode = 0; \
X	vec = NULL; \
X	curr = NULL; \
X	bump = (bump_function == NULL) ? &table_bump : bump_function; \
X	resize(hs); \
} \
table::table(table& h) \
{ \
X	hash_size = 0; \
X	numnode = 0; \
X	vec = NULL; \
X	curr = NULL; \
X	bump = h.bump; \
X	resize(h.hash_size); \
X	*this = h; \
} \
table::~table() \
{ \
X	clear(); \
X	delete vec; \
} \
boolean table::find(key k) \
{ \
X	register table_node(table) *p = vec[hash_func(k) % hash_size]; \
X	for (; p != NULL; p = p->next) \
X		if (p->sym == k) \
X		{ \
X			curr = p; \
X			return TRUE; \
X		} \
X	curr = NULL; \
X	return FALSE; \
} \
boolean table::insert(key k) \
{ \
X	if (numnode >= threshold) \
X		resize(); \
X	register table_node(table) **q = vec + hash_func(k) % hash_size; \
X	register table_node(table) *p = *q; \
X	for (; p != NULL; p = p->next) \
X		if (p->sym == k) \
X		{ \
X			curr = p; \
X			return FALSE; \
X		} \
X	curr = *q = new table_node(table)(k, *q); \
X	numnode++; \
X	return TRUE; \
} \
boolean table::insertsym(symbol &s) \
{ \
X	if (numnode >= threshold) \
X		resize(); \
X	register table_node(table) **q = vec + \
X		hash_func((table_key(table))s) % hash_size; \
X	register table_node(table) *p = *q; \
X	for (; p != NULL; p = p->next) \
X		if (p->sym == (table_key(table))s) \
X		{ \
X			curr = p; \
X			return FALSE; \
X		} \
X	curr = *q = new table_node(table)(s, *q); \
X	numnode++; \
X	return TRUE; \
} \
boolean table::remove(key k) \
{ \
X	register table_node(table) **p = vec + hash_func(k) % hash_size; \
X	curr = NULL; \
X	for (; (*p) != NULL; p = &((**p).next)) \
X		if ((**p).sym == k) \
X		{ \
X			delnode(p); \
X			return TRUE; \
X		} \
X	return FALSE; \
} \
void table::delnode(table_node(table) **p) \
{ \
X	table_node(table) *next = (**p).next; \
X	delete *p; \
X	*p = next; \
X	--numnode; \
} \
void table::resize(unsigned hs) \
{ \
X	register table_node(table) **pos, **endpos; \
X	table_node(table) *chain = NULL; \
X	unsigned new_hash_size = (hs == 0) ? bump(hash_size) : hs; \
X	if (new_hash_size == 0) \
X		new_hash_size = 1; \
X	if (new_hash_size <= hash_size) \
X		return; \
X	if (vec != NULL) \
X	{ \
X		pos = vec; \
X		endpos = pos + hash_size; \
X		for (; pos < endpos; pos++) \
X		{ \
X			table_node(table) *p = *pos; \
X			if (p != NULL) \
X			{ \
X				while (p->next != NULL) \
X					p = p->next; \
X				p->next = chain; \
X				chain = *pos; \
X			} \
X		} \
X	} \
X	hash_size = new_hash_size; \
X	threshold = hash_size + (hash_size >> 2); \
X	delete vec; \
X	pos = vec = new table_node(table) *[hash_size]; \
X	endpos = pos + hash_size; \
X	while (pos < endpos) \
X		*(pos++) = NULL; \
X	while (chain != NULL) \
X	{ \
X		table_node(table) *entry = chain; \
X		chain = entry->next; \
X		pos = vec + \
X				hash_func((table_key(table))entry->sym) \
X				% hash_size; \
X		entry->next = *pos; \
X		*pos = entry; \
X	} \
} \
table& table::clear() \
{ \
X	for (int i = 0; i < hash_size; i++) \
X	{ \
X		table_node(table) *p = vec[i]; \
X		while (p != NULL) \
X		{ \
X			table_node(table) *next = p->next; \
X			delete p; \
X			p = next; \
X		} \
X		vec[i] = NULL; \
X	} \
X	numnode = 0; \
X	curr = NULL; \
X	return *this; \
} \
table& table::operator=(table& h) \
{ \
X	if (this == &h) \
X	    return *this; \
X	clear(); \
X	for (iterator i = h; i; i++) \
X		insertsym(i()); \
X	return *this; \
} \
boolean table::operator==(table& h) \
{ \
X	if (this == &h) \
X	    return TRUE; \
X	if (size() != h.size()) \
X	    return FALSE; \
X	for (iterator i = h; i; i++) \
X	    if (!find((table_key(table))i())) \
X		return FALSE; \
X	return TRUE; \
} \
table& table::operator+=(table& h) \
{ \
X	if (this == &h) \
X	    return *this; \
X	for (iterator i = h; i; i++) \
X		insert((table_key(table))i()); \
X	return *this; \
} \
table& table::operator-=(table& h) \
{ \
X	if (this == &h) \
X	    return clear(); \
X	for (iterator i = h; i; i++) \
X		remove((table_key(table))i()); \
X	return *this; \
} \
table& table::operator&=(table& h) \
{ \
X	if (this == &h) \
X	    return *this; \
X	for (iterator i = *this; i; ) \
X	    if (h.find((table_key(table))i())) \
X		i++; \
X	    else \
X		i.remove(); \
X	return *this; \
} \
symbol &iterator::operator++() \
{ \
X	if (curr != NULL) \
X	{ \
X		table_node(table) *prev = curr; \
X		for (curr = curr->next; \
X				curr == NULL && ++index < parent->hash_size; \
X				curr = parent->vec[index]) \
X			; \
X		return prev->sym; \
X	} \
X	else \
X	{ \
X		return *(symbol *)NULL; \
X	} \
} \
void iterator::remove() \
{ \
X	if (curr != NULL) \
X	{ \
X		register table_node(table) **p = parent->vec + index; \
X		for (; (*p) != curr; p = &((**p).next)) \
X			; \
X		parent->delnode(p); \
X	} \
} \
void iterator::transfer(table *newparent) \
{ \
X	if ((parent = newparent) != NULL) \
X	{ \
X		for (index = 0, curr = parent->vec[0]; \
X				curr == NULL && ++index < parent->hash_size; \
X				curr = parent->vec[index]) \
X			; \
X	} \
X	else \
X		curr = NULL; \
}
SHAR_EOF
chmod 0444 table.h ||
echo 'restore of table.h failed'
Wc_c="`wc -c < 'table.h'`"
test 8290 -eq "$Wc_c" ||
	echo 'table.h: original size 8290, current size' "$Wc_c"
fi
# ============= bitset.C ==============
if test -f 'bitset.C' -a X"$1" != X"-c"; then
	echo 'x - skipping bitset.C (File already exists)'
else
echo 'x - extracting bitset.C (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'bitset.C' &&
// Copyright (c) 1991 by Parag Patel.  All Rights Reserved.
// $Header: bitset.C,v 1.3 91/02/22 16:05:27 hmgr Exp $
X
// A set of ints (or an array of bits) is implemented by matching
// each element in the set with its corresponding bit position in
// a word of infinite size.  The word is implemented as an array
// of "long" that is grown in size as necessary.  Thus this set of
// ints is not limited in size, like most Pascal implementations.
//
// By  Parag Patel
X
#include <stdio.h>
#include <stdarg.h>
#include "boolean.h"
#include "bitset.h"
X
X
// the following are machine-dependant - change them if necessary
// sizeof long == 32 bits == 2**5 --> 5, therefore ...
const int NUM = 32;
const int SHIFT = 5;
const int MASK = 0x1F;
const long EMPTY = 0;
X
X
// generic minimum function
static inline int MIN(int i1, int i2)
{
X	return i1 < i2 ? i1 : i2;
}
X
// this determines which particular "long" in the array has this element
static inline int ELT(int e)
{
X	return e >> SHIFT;
}
X
// this gets the bit position in a "long" for this set element
static inline long BIT(int e)
{
X	return ((long)(1L << (e & MASK)));
}
X
// this adds an element to an array of longs
static inline void ADD(long *elts, int e)
{
X	elts[ELT(e)] |= BIT(e);
}
X
X
// return a new set of elts - clear it
static long *newelts(int largest)
{
X	register long *elts = new long[ELT(largest) + 1];
X
X	for (register int i = ELT(largest); i >= 0; i--)
X		elts[i] = EMPTY;
X	return elts;
}
X
// bump the size of a set
void Bitset::bumpsize(int largest)
{
X	if (largest <= num)
X		return;
X
X	// only re-allocate our array if we are out of ELTs
X	if (ELT(largest) != ELT(num))
X	{
X	    register long *ne = newelts(largest);
X	    for (register int i = ELT(num); i >= 0; i--)
X		    ne[i] = elts[i];
X	    delete elts;
X	    elts = ne;
X	}
X	num = largest;
}
X
// various constructors:
X
// construct a set from a list of elements
Bitset::Bitset(int e1, int e2 ...)
{
X    // if the first element is < 0, we ignore the rest
X    if (e1 < 0)
X    {
X	elts = new long;
X	num = 0;
X	elts[0] = 0L;
X	return;
X    }
X
X    // the largest element in our list for determining the initial
X    // Bitset size
X    register int largest = e1 > e2 ? e1 : e2;
X    va_list ap;
X    register int t;
X
X    // if we have more than 3 elements, we need to use varargs
X    if (e2 >= 0)
X    {
X	// find the largest element to be put in the set
X	va_start(ap, e2);
X	while ((t = va_arg(ap, int)) >= 0)
X	if (t > largest)
X	    largest = t;
X	va_end(ap);
X    }
X
X    // allocate the space for this set
X    elts = newelts(num = largest);
X
X    // add all the elements to the set
X    ADD(elts, e1);
X    if (e2 >= 0)
X    {
X	ADD(elts, e2);
X	va_start(ap, e2);
X	while ((t = va_arg(ap, int)) >= 0)
X	    ADD(elts, t);
X	va_end(ap);
X    }
}
X
// make a new set of the specified size
Bitset::Bitset(int size)
{
X	if (size <= 1)
X		size = 1;
X	elts = newelts(num = size - 1);
}
X
// dup a set
Bitset::Bitset(const Bitset &s)
{
X	elts = newelts(num = s.num);
X	for (register int i = ELT(s.num); i >= 0; i--)
X		elts[i] = s.elts[i];
}
X
// assign a set to a set - also a dup
Bitset &Bitset::operator=(const Bitset &s)
{
X	register int i, t;
X
X	BUMPSIZE(s.num);
X	for (i = t = ELT(s.num); i >= 0; i--)
X		elts[i] = s.elts[i];
X	for (i = ELT(num); i > t; i--)
X		elts[i] = EMPTY;
X	return *this;
}
X
X
// add an element to a set
Bitset &Bitset::add(int elt)
{
X	if (elt < 0)
X	    return *this;
X	BUMPSIZE(elt);
X	elts[ELT(elt)] |= BIT(elt);
X	return *this;
}
X
// delete an element from a set
Bitset &Bitset::remove(int elt)
{
X	if (elt < 0)
X	    return *this;
X	elts[ELT(elt)] &= ~BIT(elt);
X	return *this;
}
X
// union with set
Bitset &Bitset::operator|=(const Bitset &s)
{
X	BUMPSIZE(s.num);
X	for (register int i = ELT(s.num); i >= 0; i--)
X		elts[i] |= s.elts[i];
X	return *this;
}
X
// intersect with set
Bitset &Bitset::operator&=(const Bitset &s)
{
X	register int t = ELT(s.num);
X
X	BUMPSIZE(s.num);
X	for (register int i = ELT(num); i >= 0; i--)
X		elts[i] &= i <= t ? s.elts[i] : EMPTY;
X	return *this;
}
X
// difference from set
Bitset &Bitset::operator-=(const Bitset &s)
{
X	for (register int i = MIN(ELT(num), ELT(s.num)); i >= 0; i--)
X		elts[i] &= ~s.elts[i];
X	return *this;
}
X
// symmetric difference (xor) from set
Bitset &Bitset::operator^=(const Bitset &s)
{
X	BUMPSIZE(s.num);
X	for (register int i = ELT(s.num); i >= 0; i--)
X		elts[i] ^= s.elts[i];
X	return *this;
}
X
// complement set
Bitset &Bitset::operator~()
{
X	register int i = ELT(num);
X
X	elts[i] = ((BIT(num) << 1) - 1) & ~elts[i];
X	for (i--; i >= 0; i--)
X		elts[i] = ~elts[i];
X	return *this;
}
X
// is set a subset of s?
boolean Bitset::operator<=(const Bitset &s) const
{
X	register int i = MIN(num, s.num);
X
X	for (i = ELT(i); i >= 0; i--)
X		if ((elts[i] & s.elts[i]) != elts[i])
X			return FALSE;
X	if (num <= s.num)
X		return TRUE;
X
X	register int t = ELT(s.num);
X	for (i = ELT(num); i > t; i--)
X		if (elts[i])
X			return FALSE;
X	return TRUE;
}
X
// is set same as s?
boolean Bitset::operator==(const Bitset &s) const
{
X	register int i = MIN(num, s.num);
X
X	for (i = ELT(i); i >= 0; i--)
X		if (elts[i] != s.elts[i])
X			return FALSE;
X	if (num == s.num)
X		return TRUE;
X
X	register int t;
X	if (num < s.num)
X	{
X		for (t = ELT(num), i = ELT(s.num); i > t; i--)
X			if (s.elts[i])
X				return FALSE;
X	}
X	else
X	{
X		for (t = ELT(s.num), i = ELT(num); i > t; i--)
X			if (elts[i])
X				return FALSE;
X	}
X	return TRUE;
}
X
X
// return the number of elements in the set (cardinality)
int Bitset::size() const
{
X	register int n = 0;
X
X	for (register int i = ELT(num); i >= 0; i--)
X		for (register long m = 1; m; m <<= 1)
X			if (elts[i] & m)
X				n++;
X	return n;
}
X
// clear the set of all elements
void Bitset::clear()
{
X	for (register int i = ELT(num); i >= 0; i--)
X		elts[i] = EMPTY;
}
X
// return a hash number for this set
unsigned long Bitset::hash() const
{
X	register int i = ELT(num);
X
X	// skip over null elements in array to make
X	// hash value independent of size
X	while (i >= 0 && elts[i] == 0)
X		i--;
X
X	// now we can hash safely...
X	register unsigned long h = 0;
X	for (; i >= 0; i--)
X	{
X		// "+" moves around the bits a lot better than "^"
X		h += elts[i];
X		// rotate "h" left by 3 bits, just to mix things up
X		h = (h << 3) | (h >> (NUM - 3));
X	}
X
X	return h;
}
X
X
X
// set iterator class:
X
// creator
Bitsetiter::Bitsetiter(const Bitset &s)
{
X	int i, e;
X	int num = 0;
X
X	arr = new int[len = s.size()];
X	int t = ELT(s.num);
X	for (e = 0, i = 0; i <= t; i++)
X		for (long m = 1; m; e++, m <<= 1)
X			if (s.elts[i] & m)
X				arr[num++] = e;
X	elt = 0;
}
SHAR_EOF
chmod 0444 bitset.C ||
echo 'restore of bitset.C failed'
Wc_c="`wc -c < 'bitset.C'`"
test 6447 -eq "$Wc_c" ||
	echo 'bitset.C: original size 6447, current size' "$Wc_c"
fi
# ============= tgram.w ==============
if test -f 'tgram.w' -a X"$1" != X"-c"; then
	echo 'x - skipping tgram.w (File already exists)'
else
echo 'x - extracting tgram.w (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'tgram.w' &&
// Copyright (c) 1991 by Parag Patel.  All Rights Reserved.
// $Header: tgram.w,v 1.5 91/02/22 16:05:33 hmgr Exp $
X
{
#include <stdio.h>
}
X
program
X	: "program" ID '(' idlist ')' semi
X			declarations subprogdecls compoundstat '.'
X	;
X
semi
X	: ';'[semi+]
X	;
X
idlist
X	: ID (',' ID | [])
X	;
X
declarations
X	: "var" (decllist | semi)
X	| []
X	;
X
decllist
X	: idlist ':' type semi (decllist | [])
X	;
X
type
X	: "integer"
X	| "array" '[' INT ".." INT ']' "of" "integer"
X	;
X
subprogdecls
X	: subproghead declarations subprogdecls
X			compoundstat semi subprogdecls
X	| []
X	;
X
subproghead
X	: "function" ID arguments ':' "integer" semi
X	| "procedure" ID arguments semi
X	;
X
arguments
X	: '(' paramlist ')'
X	| []
X	;
X
paramlist
X	: idlist ':' type (semi paramlist | [])
X	;
X
compoundstat
X	: "begin" statlist "end"[+semi+]
X	;
X
statlist
X	: statement semi statlist
X	| []
X	;
X
statement
X	: ID assignment
X	| compoundstat
X	| "if" expression "then" statement ("else" statement | [])
X	| "while" expression "do" statement
X	| "for" varref ":=" expression ("to" | "downto")
X			expression "do" statement
X	;
X
assignment
X	: '[' expression ']' ":=" expression
X	| '(' exprlist ')'
X	| ":=" expression
X	| []
X	;
X
varref
X	: ID ('[' expression ']' | [])
X	;
X
exprlist
X	: expression (',' exprlist | [])
X	;
X
expression
X	: term (('+'|'-') expression | [])
X	;
X
term
X	: expr (('*'|'/') term | [])
X	;
X
expr
X	: ID ('(' exprlist ')' | '[' expression ']' [')'] | [])
X	| INT
X	| '(' expression ')'
X	| "not" expression
X	| ('+'|'-') expression
X	;
X
{
X    int main()
X    {
X	    w_setfile(stdin);
X
X	    if (!program())
X		    return 1;
X
X	    return 0;
X    }
}
X
$$
X
D	[0-9]
L	[A-Za-z_$]
X
%%
X
$ID		{L}({L}|{D})*
$INT	{D}+
X
[ \t\v\n\f]	;
.			{ w_scanerr("Illegal character %d (%c)", yytext[0], yytext[0]); }
SHAR_EOF
chmod 0444 tgram.w ||
echo 'restore of tgram.w failed'
Wc_c="`wc -c < 'tgram.w'`"
test 1739 -eq "$Wc_c" ||
	echo 'tgram.w: original size 1739, current size' "$Wc_c"
fi
# ============= tgram.good ==============
if test -f 'tgram.good' -a X"$1" != X"-c"; then
	echo 'x - skipping tgram.good (File already exists)'
else
echo 'x - extracting tgram.good (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'tgram.good' &&
program test(input);
X
var
X	x, a: integer;
X	ara: array [1..10] of integer;
X
procedure try(a:integer);
X	var u,v:integer;
X	begin
X		if not a then try:=u+3 else try:=a;
X	end;
X
begin
X	while a do
X	begin
X		x := a-1;
X		a:=5*a;
X	end;
end.
SHAR_EOF
chmod 0444 tgram.good ||
echo 'restore of tgram.good failed'
Wc_c="`wc -c < 'tgram.good'`"
test 229 -eq "$Wc_c" ||
	echo 'tgram.good: original size 229, current size' "$Wc_c"
fi
# ============= tgram.bad ==============
if test -f 'tgram.bad' -a X"$1" != X"-c"; then
	echo 'x - skipping tgram.bad (File already exists)'
else
echo 'x - extracting tgram.bad (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'tgram.bad' &&
program test(input);
X
var
X	x a: integer;
X	ara: array [1...10] of integer;
X
procedure try(a:integer):result integer;
X	u,v:integer;
X	begin
if not not a try:=u+ else try:=a;
X	end
X	end
X
begin
X	while not x a do
X		x = a-1;
X		a2:=5**a;
X		x:= ara[3]*(ara[x+x)
X	end
end
SHAR_EOF
chmod 0444 tgram.bad ||
echo 'restore of tgram.bad failed'
Wc_c="`wc -c < 'tgram.bad'`"
test 261 -eq "$Wc_c" ||
	echo 'tgram.bad: original size 261, current size' "$Wc_c"
fi
# ============= main.C ==============
if test -f 'main.C' -a X"$1" != X"-c"; then
	echo 'x - skipping main.C (File already exists)'
else
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"
fi
# ============= sym.C ==============
if test -f 'sym.C' -a X"$1" != X"-c"; then
	echo 'x - skipping sym.C (File already exists)'
else
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"
fi
true || echo 'restore of parse.C failed'
echo End of part 4, continue with part 5
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.