[comp.sources.misc] REPOST: v19i088: wacco - A C++ LL parser generator, Part01/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 88
Archive-name: wacco/part01

This is version 1.1 of Wacco, basically an LL(1) parser generator.
Wacco generates recursive-descent C++ code from an input file.  The
wacco file.w looks a lot like a yacc(1) input file, but with a lot more
syntactic sugar added.  Since the parser generated recurses, you can
do attribute-driven parsing easily and even pass information into rules
which could alter the parse.

Wacco should port and run easily on most C++ systems.  It does need C++
2.0 of some flavor.  It's been successfully built on HP-UX s300 and s800
systems, Sparc, and 4.3BSD running on HP hardware.  

The code is somewhat commented.  Feel free to hack away, add new
features, or fix my screwups.  If you make mods you feel are useful, or
fix some bug, please send me the cdiffs so I can make them available to
others too.

Parag Patel <parag@sde.hp.com
----
#!/bin/sh
# This is a shell archive (produced by shar 3.49)
# To extract the files from this archive, save it to a file, remove
# everything above the "!/bin/sh" line above, and type "sh file_name".
#
# made 05/19/1991 05:17 UTC by kent@sparky.IMD.Sterling.COM
# Source directory /u1/csm/queue/.junked/wacco/test
#
# existing files will NOT be overwritten unless -c is specified
#
# This is part 1 of a multipart archive                                    
# do not concatenate these parts, unpack them in order with /bin/sh        
#
# This shar contains:
# length  mode       name
# ------ ---------- ------------------------------------------
#   1967 -r--r--r-- Makefile
#   2899 -r--r--r-- README
#   6447 -r--r--r-- bitset.C
#   2537 -r--r--r-- bitset.h
#    188 -r--r--r-- boolean.h
#   5614 -r--r--r-- build.C
#   2302 -r--r--r-- check.C
#   1624 -r--r--r-- darray.h
#   3575 -r--r--r-- defs.h
#  18803 -r--r--r-- gen.C
#   3832 -r--r--r-- io.C
#   6362 -r--r--r-- main.C
#  18403 -r--r--r-- parse.C
#   3603 -r--r--r-- read.C
#   3884 -r--r--r-- scan.C
#   3130 -r--r--r-- sym.C
#   8290 -r--r--r-- table.h
#    261 -r--r--r-- tgram.bad
#    229 -r--r--r-- tgram.good
#   1739 -r--r--r-- tgram.w
#   1555 -r--r--r-- toks.h
#    120 -r--r--r-- version.C
#   4588 -r--r--r-- wacco.1
#  15987 -r--r--r-- wacco.doc
#  42897 -r--r--r-- wacco.doc.iw
#  98569 -r-xr-xr-x wacco.doc.ps
#   5585 -r--r--r-- wacco.w
#
if test -r _shar_seq_.tmp; then
	echo 'Must unpack archives in sequence!'
	echo Please unpack part `cat _shar_seq_.tmp` next
	exit 1
fi
# ============= Makefile ==============
if test -f 'Makefile' -a X"$1" != X"-c"; then
	echo 'x - skipping Makefile (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting Makefile (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'Makefile' &&
# Copyright (c) 1991 by Parag Patel.  All Rights Reserved.
# $Header: Makefile,v 1.27 91/05/17 16:29:50 hmgr Exp $
X
CXX = CC
.SUFFIXES: .C
.C.o:
X	$(CXX) $(CFLAGS) -c $<
X
# system-dependent options - use any appropriate -D<sys> macros
# -DBSD		 	for a BSD derivative (Sun)
# -Dpid_t=long		if your headers don't define a pid_t type
# -DFREE_TAKES_CHAR	if you have a free(char*) instead of free(void*) (Sun)
CFLAGS = -g
LIBS = libwacco.a
X
SRCS =	README Makefile wacco.1 wacco.doc wacco.doc.iw wacco.doc.ps wacco.w \
X	defs.h toks.h boolean.h bitset.h darray.h table.h \
X	bitset.C tgram.w tgram.good tgram.bad \
X	main.C sym.C parse.C scan.C build.C check.C read.C gen.C \
X	io.C version.C
X
OBJS =	main.o sym.o parse.o scan.o build.o check.o read.o gen.o bitset.o
X
wacco : $(OBJS) libwacco.a
X	$(CXX) $(CFLAGS) -o wacco $(OBJS) $(LIBS)
X
libwacco.a : io.o version.o
X	 ar ru libwacco.a $(?)
X	 -[ -x /usr/bin/ranlib ] && ranlib libwacco.a
X
tst: parser.o scanner.o
X	$(CXX) $(CFLAGS) -o tst parser.o scanner.o $(LIBS) $(LFLAGS) -ll
X	-./tst <tgram.bad
X	./tst <tgram.good
X
parser.C scanner.l: tgram.w wacco
X	./wacco tgram.w
X
tar: $(SRCS)
X	tar -cvf - $(SRCS) | compress >wacco.tar.Z 
X
shar: $(SRCS)
X	shar -ac -nwacco -l50 -owacco-shar $(SRCS)
X
clean:
X	rm -f wacco *.o libwacco.a wacco.tar.Z* wacch.shar* tst parser.C scanner.l
X
files:
X	@echo $(SRCS)
X
main.o : main.C toks.h defs.h boolean.h darray.h table.h bitset.h
sym.o : sym.C defs.h boolean.h darray.h table.h bitset.h
parse.o : parse.C toks.h defs.h boolean.h darray.h table.h bitset.h
scan.o : scan.C toks.h defs.h boolean.h darray.h table.h bitset.h
build.o : build.C defs.h boolean.h darray.h table.h bitset.h
check.o : check.C defs.h boolean.h darray.h table.h bitset.h
read.o : read.C toks.h defs.h boolean.h darray.h table.h bitset.h
gen.o : gen.C toks.h defs.h boolean.h darray.h table.h bitset.h
io.o : io.C toks.h defs.h boolean.h darray.h table.h bitset.h
version.o : version.C
bitset.o : bitset.C bitset.h boolean.h
SHAR_EOF
chmod 0444 Makefile ||
echo 'restore of Makefile failed'
Wc_c="`wc -c < 'Makefile'`"
test 1967 -eq "$Wc_c" ||
	echo 'Makefile: original size 1967, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= README ==============
if test -f 'README' -a X"$1" != X"-c"; then
	echo 'x - skipping README (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting README (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'README' &&
$Header: README,v 1.7 91/05/17 16:29:53 hmgr Exp $
X
Copyright (c) 1991 by Parag Patel.  All Rights Reserved.
You can do what you wish with this as long as
X    (1) you do not claim it or any part of it as yours and
X    (2) you do not remove or alter my copyright in any file.
This software is provided "AS IS" without any implied or express warranty
as to its performance or to the results that may be obtained by using this
software.  It is completely unsupported.  You're on your own.
X
X
This is version 1.1 of Wacco, basically an LL(1) parser generator.
Why Another Compiler COmpiler?  Why not?!?
X
Wacco generates recursive-descent C++ code from an input file.  The
wacco file.w looks a lot like a yacc(1) input file, but with a lot more
syntactic sugar added.  Since it the parser generated recurses, you can
do attribute-driven parsing easily and even pass information into rules
which could alter the parse.
X
I wrote wacco to give me a platform for experiment with various error
recovery schemes.  A fairly cheesy first/follow set scheme is currently
implemented.  Wacco turned out to be useful in its own right and I never
did get around to serious experimenting.
X
Wacco is written in itself.  The file "wacco.w" describes its own format
and was used to manually generate "parse.C" and "toks.h".  (The original
bootstrap version no longer exists.  Wacco has evolved considerably from
a much simpler version to the current implementation, so the old code
would be useless anyway.)  The files "parse.C" and "toks.h" are always
shipped since there's no other way to build a working wacco.
X
The file "wacco.doc" describes the wacco file format in a tty-readable
form.  "Wacco.doc.iw" is the much prettier IslandWrite version of the
document.  "Wacco.doc.ps" is the Postscript output from IslandWrite.
Wacco.1 describes only the command-line options.
X
There are few comments and lots of ugly non-OO code throughout wacco.
It had evolved from a straight C implementation and I never got around
to cleaning it up.  Sorry.
X
Wacco should port and run easily on most C++ systems.  It does need C++
2.0 of some flavor.  It's been successfully built on HP-UX s300 and s800
systems, Sparc, and 4.3BSD running on HP hardware.  You may need to
tweak some -D defines in the Makefile.  If sizeof(long) is NOT 32 bits,
you may have to perform major surgery on bitset.h and bitset.C.
X
All you should need to do is modify CFLAGS in the Makefile, then type
"make".  The Makefile should come setup for HP-UX systems.  Type "make
tst" to build a simple test program using "tgram.w".  The files to
be installed wherever you prefer are "wacco" and "wacco.1".
X
The code is somewhat commented.  Feel free to hack away, add new
features, or fix my screwups.  If you make mods you feel are useful, or
fix some bug, please send me the cdiffs so I can make them available to
others too.
X
X
X
X	-- Parag Patel <parag@sde.hp.com>
SHAR_EOF
chmod 0444 README ||
echo 'restore of README failed'
Wc_c="`wc -c < 'README'`"
test 2899 -eq "$Wc_c" ||
	echo 'README: original size 2899, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= bitset.C ==============
if test -f 'bitset.C' -a X"$1" != X"-c"; then
	echo 'x - skipping bitset.C (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
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"
rm -f _shar_wnt_.tmp
fi
# ============= bitset.h ==============
if test -f 'bitset.h' -a X"$1" != X"-c"; then
	echo 'x - skipping bitset.h (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
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"
rm -f _shar_wnt_.tmp
fi
# ============= boolean.h ==============
if test -f 'boolean.h' -a X"$1" != X"-c"; then
	echo 'x - skipping boolean.h (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
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"
rm -f _shar_wnt_.tmp
fi
# ============= build.C ==============
if test -f 'build.C' -a X"$1" != X"-c"; then
	echo 'x - skipping build.C (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting build.C (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'build.C' &&
// Copyright (c) 1991 by Parag Patel.  All Rights Reserved.
static const char rcs_id[] = "$Header: build.C,v 1.5 91/02/22 16:07:15 hmgr Exp $";
X
#include "defs.h"
X
X
static void markempty()
{
X	symbol *sym, *s;
X	symnode *or, *next, *node;
X	int i, num;
X	boolean done;
X
X	num = numsymbols();
X	do
X	{
X		done = TRUE;
X		for (i = START; i < num; i++)
X		{
X			sym = getsymbol(i);
X			if (sym->type != NONTERMINAL)
X				continue;
X
X			for (or = sym->node; or != NULL; or = or->or)
X			{
X				for (node = or; node != NULL; node = node->next)
X					if (node->sym->type != CODE)
X						break;
X				if (node == NULL)
X					continue;
X
X				s = node->sym;
X				if (s->id == EMPTY && !sym->toempty)
X				{
X					sym->toempty = TRUE;
X					done = FALSE;
X				}
X
X				for (next = node; next != NULL; next = next->next)
X					if (next->sym->type != CODE && !next->sym->toempty)
X						break;
X
X				if (next == NULL && !sym->toempty)
X				{
X					sym->toempty = TRUE;
X					done = FALSE;
X				}
X			}
X		}
X	} while (!done);
}
X
X
static void first()
{
X	symbol *sym, *s;
X	symnode *or, *next, *node;
X	int i, num;
X	boolean done;
X
X	num = numsymbols();
X	do
X	{
X		done = TRUE;
X		for (i = START; i < num; i++)
X		{
X			sym = getsymbol(i);
X			if (sym->type == CODE)
X				continue;
X
X			if (sym->type == TERMINAL)
X			{
X				if (sym->first->isin(sym->id))
X					continue;
X				*sym->first += sym->id;
X				done = FALSE;
X				continue;
X			}
X
X			for (or = sym->node; or != NULL; or = or->or)
X			{
X				for (node = or; node != NULL; node = node->next)
X					if (node->sym->type != CODE)
X						break;
X				if (node == NULL)
X					continue;
X
X				s = node->sym;
X				if (s->id == EMPTY)
X				{
X					if (!sym->first->isin(EMPTY))
X					{
X						*sym->first += EMPTY;
X						done = FALSE;
X					}
X					continue;
X				}
X
X				for (next = node; next != NULL; next = next->next)
X				{
X					s = next->sym;
X					if (s->type == CODE)
X						continue;
X
X					if (!(*s->first <= *sym->first))
X					{
X						*sym->first |= *s->first;
X						done = FALSE;
X					}
X					if (!s->toempty)
X						break;
X				}
X			}
X		}
X	} while (!done);
}
X
X
static void follow()
{
X	symbol *sym, *s;
X	symnode *or, *node, *next, *n;
X	int i, num;
X	boolean done;
X	Bitset set;
X
X	num = numsymbols();
X	*startsymbol->follow += END;
X	do
X	{
X		done = TRUE;
X		for (i = START; i < num; i++)
X		{
X			sym = getsymbol(i);
X			if (sym->type != NONTERMINAL)
X				continue;
X
X			for (or = sym->node; or != NULL; or = or->or)
X			{
X				for (node = or; node != NULL; node = node->next)
X				{
X					s = node->sym;
X					if (s->type == CODE)
X						continue;
X
X					for (next = node->next; next != NULL; next = next->next)
X						if (next->sym->type != CODE)
X							break;
X
X					for (n = next; n != NULL; n = n->next)
X						if (n->sym->type != CODE && !n->sym->toempty)
X							break;
X
X					if (n == NULL)
X					{
X						if (*sym->follow <= *s->follow)
X							continue;
X						*s->follow |= *sym->follow;
X						done = FALSE;
X					}
X
X					if (next != NULL)
X					{
X						set = *next->sym->first;
X						set -= EMPTY;
X						if (!(set <= *s->follow))
X						{
X							*s->follow |= set;
X							done = FALSE;
X						}
X					}
X				}
X			}
X		}
X	} while (!done);
}
X
X
static void mksymresync(symbol *sym)
{
X	if (sym->list == NULL)
X		return;
X
X	Bitset *set = new Bitset;
X
X	resynclist *x;
X	for (resynclist *r = sym->list; r != NULL; x = r, r = r->next, delete x)
X	{
X		symbol *s;
X		if (r->name != NULL)
X		{
X			s = findsymbol(r->name);
X			if (s == NULL)
X			{
X				error("Symbol \"%s\" doesn't exist for \"%s\" resync set",
X						r->name, sym->name);
X				continue;
X			}
X		}
X		else if (r->paren == 0)
X			s = getsymbol(EMPTY);
X		else
X		{
X			error("Cannot handle paren groups in skip-set for \"%s\"",
X					sym->name);
X			continue;
X		}
X
X		if (r->first > 0 || (r->first == 0 && r->follow == 0))
X			*set |= *s->first;
X		else if (r->first < 0)
X			*set -= *s->first;
X
X		if (r->follow > 0)
X			*set |= *s->follow;
X		else if (r->follow < 0)
X			*set -= *s->follow;
X	}
X	sym->resync = &settab[set];
}
X
X
static void mkresync(symbol *sym, symnode *start, symnode *n)
{
X	Bitset *set = new Bitset;
X
X	symnode *t = n;
X	for (int i = 0; t != NULL && i <= 3; t = t->next, i++)
X		*set |= *t->sym->first;
X
X	resynclist *x;
X	for (resynclist *r = n->list; r != NULL; x = r, r = r->next, delete x)
X	{
X		symbol *s;
X		if (r->name != NULL)
X		{
X			s = findsymbol(r->name);
X			if (s == NULL)
X			{
X				for (symnode *t = start; t != NULL; t = t->next)
X					if (t->alias != NULL && strcmp(t->alias, r->name) == 0)
X						break;
X				if (t != NULL)
X					s = t->sym;
X			}
X			if (s == NULL)
X			{
X				error("Symbol \"%s\" doesn't exist for \"%s\" resync set",
X						r->name, sym->name);
X				continue;
X			}
X		}
X		else if (r->paren == 0)
X			s = getsymbol(EMPTY);
X		else
X		{
X			for (symnode *t = start; t != NULL; t = t->next)
X				if (t->sym->realname != NULL 
X						&& t->sym->realname != t->sym->name)
X					if (--(*r).paren <= 0)
X						break;
X			if (t == NULL)
X			{
X				error("Paren group %d does not exist in rule for \"%s\"",
X						r->paren, sym->name);
X				continue;
X			}
X			s = t->sym;
X		}
X
X		if (r->first > 0 || (r->first == 0 && r->follow == 0))
X			*set |= *s->first;
X		else if (r->first < 0)
X			*set -= *s->first;
X
X		if (r->follow > 0)
X			*set |= *s->follow;
X		else if (r->follow < 0)
X			*set -= *s->follow;
X	}
X	n->resync = &settab[set];
}
X
static void resync()
{
X	int i;
X	symbol *sym;
X	int num = numsymbols();
X	symnode *or;
X
X	for (i = START; i < num; i++)
X	{
X		sym = getsymbol(i);
X		if (sym->type == CODE)
X			continue;
X
X		mksymresync(sym);
X		for (or = sym->node; or != NULL; or = or->or)
X			for (symnode *n = or; n != NULL; n = n->next)
X				mkresync(sym, or, n);
X	}
}
X
X
void buildsets()
{
X	markempty();
X	first();
X	follow();
X	resync();
}
SHAR_EOF
chmod 0444 build.C ||
echo 'restore of build.C failed'
Wc_c="`wc -c < 'build.C'`"
test 5614 -eq "$Wc_c" ||
	echo 'build.C: original size 5614, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= check.C ==============
if test -f 'check.C' -a X"$1" != X"-c"; then
	echo 'x - skipping check.C (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting check.C (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'check.C' &&
// Copyright (c) 1991 by Parag Patel.  All Rights Reserved.
static const char rcs_id[] = "$Header: check.C,v 1.6 91/02/22 16:07:20 hmgr Exp $";
X
#include "defs.h"
X
X
static void dostruct(symbol *sym)
{
X	if (sym->rettype == NULL)
X		return;
X	if (dargstyle)
X	{
X		sym->mkstruct = strpbrk(sym->rettype, ",;") != NULL;
X		return;
X	}
X	for (char *s = sym->rettype; *s != '\0'; s++)
X		if (*s == ',')
X		{
X			sym->mkstruct = TRUE;
X			*s = ';';
X		}
}
X
X
void check()
{
X	int i;
X	symbol *sym;
X	symnode *n;
X	Bitset curr(numsymbols());
X	Bitset set(numsymbols());
X	Bitset t(numsymbols());
X
X	if (!exportedname && !startsymbol->export)
X		startsymbol->export = TRUE;
X
X	for (i = 0; i < numnonterms(); i++)
X	{
X		sym = getnonterm(i);
X		if (sym->type != NONTERMINAL)
X			continue;
X		
X		dostruct(sym);
X		if (sym->mkstruct && sym->export)
X			error("Non-simple type for exported non-terminal \"%s\"",
X				sym->name);
X
X		curr.clear();
X		for (n = sym->node; n != NULL; n = n->or)
X		{
X			set.clear();
X			boolean isfirst = TRUE;
X			for (symnode *s = n; s != NULL; s = s->next)
X			{
X				if (s->sym->type == CODE)
X					continue;
X				if (isfirst)
X					if (s->sym == sym)
X						if (sym->realname != NULL && sym->name != sym->realname)
X							error("Head recursion in grouped rules for \"%s\"",
X									sym->realname);
X						else
X							error("Head recursion in rules for \"%s\"",
X									sym->name);
X				isfirst = FALSE;
X				set |= *s->sym->first;
X				if (!s->sym->first->isin(EMPTY))
X					break;
X			}
X			t = curr;
X			t &= set;
X			if (t.size() == 0 || (t.size() == 1 && t.isin(EMPTY)))
X				curr |= set;
X			else if (sym->type == NONTERMINAL && sym->realname != NULL
X					&& sym->name != sym->realname)
X				error("Ambiguous [non-LL(1)] grouped rules in \"%s\"",
X						sym->realname);
X			else
X				error("Ambiguous [non-LL(1)] rules for \"%s\"", sym->name);
X		}
X
X		for (symnode *or = sym->node; or != NULL; or = or->or)
X			for (n = or; n != NULL; n = n->next)
X				if (n->sym->type == TERMINAL && n->alias != NULL)
X					if (sym->realname != NULL && sym->name != sym->realname)
X						error(
"Alias \"%s\" defined for terminal \"%s\" in grouped rules for \"%s\"",
X							n->alias, n->sym->name, sym->realname);
X					else
X						error(
"Alias \"%s\" defined for terminal \"%s\" in rules for \"%s\"",
X							n->alias, n->sym->name, sym->name);
X	}
}
SHAR_EOF
chmod 0444 check.C ||
echo 'restore of check.C failed'
Wc_c="`wc -c < 'check.C'`"
test 2302 -eq "$Wc_c" ||
	echo 'check.C: original size 2302, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= darray.h ==============
if test -f 'darray.h' -a X"$1" != X"-c"; then
	echo 'x - skipping darray.h (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
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"
rm -f _shar_wnt_.tmp
fi
# ============= defs.h ==============
if test -f 'defs.h' -a X"$1" != X"-c"; then
	echo 'x - skipping defs.h (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
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"
rm -f _shar_wnt_.tmp
fi
# ============= gen.C ==============
if test -f 'gen.C' -a X"$1" != X"-c"; then
	echo 'x - skipping gen.C (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting gen.C (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'gen.C' &&
// Copyright (c) 1991 by Parag Patel.  All Rights Reserved.
static const char rcs_id[] = "$Header: gen.C,v 1.29 91/02/22 16:08:02 hmgr Exp $";
X
#include "defs.h"
#include "toks.h"
#include <stdarg.h>
X
X
static FILE *fp = NULL;
static long curr_lineno = 1;
static const char *currfile = NULL;
static const char *inputfile = NULL;
X
static void putf(char *fmt, ...)
{
X    va_list ap;
X    char buf[1024];
X
X    va_start(ap, fmt);
X    vsprintf(buf, fmt, ap);
X    va_end(ap);
X    int nl = 0;
X    for (char *s = buf; *s != '\0'; s++)
X	if (*s == '\n')
X	    nl++;
X    curr_lineno += nl;
X    fputs(buf, fp);
}
X
inline static void put(int ch)
{
X    putc(ch, fp);
X    if (ch == '\n')
X	curr_lineno++;
}
X
X
static boolean saveret = FALSE;
static char *mkretcode(symbol *s)
{
X	s = NULL;
X	return saveret ? "_rc = " : "(void)";
}
X
static const char *mkname(symbol *sym)
{
X	if (*sym->name != '"')
X		return sym->name;
X	if (*sym->name == '\'' && sym->type == TERMINAL)
X		return sym->name;
X	return strbldf("_S%d/*%s*/", sym->id, sym->name);
}
X
static const char *mkerrname(symbol *sym)
{
X	if (sym->type == NONTERMINAL && sym->realname != NULL)
X		return sym->realname;
X	return mkname(sym);
}
X
X
static void printset(const char *name, Bitset &set)
{
X	Bitsetiter si(set);
X	symbol *s;
X	int id;
X	char *pre = "";
X
X	putf("static %s[] = { ", name);
X	while ((id = si()) >= 0)
X	{
X		if (id == EMPTY)
X			putf("%s_EMPTY", pre);
X			// continue;
X		else if (id == END)
X			putf("%sEOI", pre);
X		else
X		{
X			s = getsymbol(id);
X			putf("%s%s", pre, mkname(s));
X		}
X		pre = ", ";
X	} 
X	putf("%s-1 };\n", pre);
}
X
static void printcase(char *pre, Bitset &set)
{
X	Bitsetiter si(set);
X	symbol *s;
X	int id;
X
X	while ((id = si()) >= 0)
X	{
X		if (id == EMPTY)
X			continue;
X
X		putf("%scase ", pre);
X		if (id == END)
X			putf("EOI");
X		else
X		{
X			s = getsymbol(id);
X			putf("%s", mkname(s));
X		}
X		putf(":\n");
X	} 
}
X
inline static boolean dotype(symbol *sym)
{
X	if ((sym->usedret & RET_VALUE) || sym->rettype != NULL)
X		return TRUE;
X	else
X		return FALSE;
}
X
static const char *mktype(symbol *sym, char *pre = "", char *post = NULL)
{
X    if (!dotype(sym))
X	return "";
X    char *name;
X    if (sym->rettype == NULL)
X	name = "int";
X    else
X    {
X	name = sym->rettype;
X	if (sym->mkstruct)
X	{
X	    if (sym->realname != NULL && sym->realname != sym->name
X		    && sym->rettype == findsymbol(sym->realname)->rettype)
X		return strbldf("%s_T%s%s", pre, sym->realname, post);
X	    return strbldf("%s_T%s%s", pre, sym->name, post);
X	}
X    }
X    return strbldf("%s%s%s", pre, name, post);
}
X
static const char *mkvoidtype(symbol *sym, char *pre = "", char *post = NULL)
{
X    const char *type = mktype(sym, pre, post);
X    if (*type == '\0')
X	type = "void";
X    return type;
}
X
static void mkstruct(symbol *sym)
{
X	if (!dotype(sym) || !sym->mkstruct)
X		return;
X	char *name = sym->name;
X	if (sym->realname != NULL && sym->realname != sym->name)
X	{
X		symbol *real = findsymbol(sym->realname);
X		if (real->rettype == sym->rettype)
X		{
X			if (dotype(real))
X				return;
X			name = sym->realname;
X		}
X	}
X	putf("\nstruct _T%s\n{\n", name);
X	putf("\t%s;\n};\n", sym->rettype);
}
X
static void mkcode(char *pre, symbol *code)
{
X	if (code == NULL || code->code == NULL)
X		return;
X
X	if (genlineinfo)
X		putf("#line %d \"%s\"\n", code->line, inputfile);
X	else
X		putf("/* #line %d */\n", code->line);
X	putf("%s%s;\n", pre, code->code);
X	if (genlineinfo)
X		putf("#line %d \"%s\"\n", curr_lineno + 1, currfile);
}
X
static const char *mkvarname(symnode *start, symnode *node)
{
X	if (node->alias != NULL)
X		return node->alias;
X
X	int count = 0;
X	boolean addnum = FALSE;
X	char *name = node->sym->name;
X
X	if (node->sym->realname != NULL && node->sym->name != node->sym->realname)
X	{
X		name = "_";
X		for (symnode *n = start; n != node; n = n->next)
X			if (n->sym->type == NONTERMINAL && n->sym->realname != NULL 
X					&& n->sym->name != n->sym->realname)
X				count++;
X		for (n = n->next; n != NULL; n = n->next)
X			if (n->sym->type == NONTERMINAL && n->sym->realname != NULL 
X					&& n->sym->name != n->sym->realname)
X				addnum = TRUE;
X	}
X	else
X	{
X		for (symnode *n = start; n != node; n = n->next)
X			if (n->sym == node->sym)
X				count++;
X		for (n = n->next; n != NULL; n = n->next)
X			if (n->sym == node->sym)
X				addnum = TRUE;
X	}
X	if (addnum || count > 0)
X		return strbldf("%s%d", name, count + 1);
X	return name;
}
X
X
static void genstmt(char *pre, symnode *node)
{
X	symbol *s;
X	symnode *n;
X
X	for (n = node; n != NULL; n = n->next)
X	{
X		if (n->sym->type != NONTERMINAL || n->sym->id == EMPTY
X				|| !dotype(n->sym))
X			continue;
X		putf("%s%s _rv%s;\n", pre, mktype(n->sym), mkvarname(node, n));
X	}
X
X	for (n = node; n != NULL; n = n->next)
X	{
X		s = n->sym;
X		if (s->type == CODE)
X		{
X			if (dumpcode)
X				mkcode(pre, s);
X			continue;
X		}
X		if (s->id == EMPTY)
X			continue;
X
X		if (s->type == TERMINAL)
X			putf("%s%sscantoken(%s, _link, _resync%d);\n",
X					pre, mkretcode(s), mkname(s), n->resync->id);
X		else if (optimize && s->usecount == 1 && !s->export)
X		{
X			symbol *sym = s;
X			symnode *nn = n;
X			Bitset set(numsymbols());
X
X			putf("%s{\n", pre);
X			if (dotype(s))
X				putf("%s = _rv%s;\n", mktype(sym, pre, " &_rr"),
X						mkvarname(node, nn));
X			else
X				putf("%s\n", mktype(sym, pre, " _rr;"));
X			putf("%sresynclink &_lnk = _link;\n", pre);
X			putf("%sresynclink _link(_lnk, _resync%d);\n\n",
X					pre, nn->resync->id);
X
X			if (sym->resync != NULL)
X				putf("%s (void)scantoken(-1, _link, _resync%d);\n\n",
X						pre, sym->resync->id);
X
X			if (sym->node != NULL && sym->node->or == NULL)
X			{
X				genstmt("\t\t\t", sym->node);
X				putf("\n%s}\n\n", pre);
X				// putf("\n%sreturn RETOK;\n}\n\n", pre);
X				continue;
X			}
X
X			boolean donedefault = FALSE;
X			putf("%sswitch (w_nexttoken())\n\t{\n", pre);
X			for (symnode *n = sym->node; n != NULL; n = n->or)
X			{
X				set.clear();
X				for (symnode *s = n; s != NULL; s = s->next)
X				{
X					if (s->sym->type == CODE)
X						continue;
X					set |= *s->sym->first;
X					if (!s->sym->first->isin(EMPTY))
X						break;
X				}
X
X				if (set.size() == 0 || (set.size() == 1 && set.isin(EMPTY)))
X				{
X					donedefault = TRUE;
X					putf("%s\tdefault:\n", pre);
X					genstmt("\t\t", n);
X					if (!sym->first->isin(EMPTY))
X						putf("%s\t\tw_scanerr(\"illegal %s\");\n",
X								pre, mkerrname(sym));
X				}
X				else
X				{
X					printcase("\t", set);
X					putf("\t\t{\n");
X					genstmt("\t\t\t", n);
X					putf("\t\t}\n");
X				}
X				putf("\t\tbreak;\n");
X			}
X
X			if (!donedefault && !sym->first->isin(EMPTY))
X			{
X				putf("%s\tdefault:\n", pre);
X				putf("%s\t\tw_scanerr(\"illegal %s\");\n",
X						pre, mkerrname(sym));
X			}
X			putf("%s}", pre);
X			putf(" }\n");
X		}
X		else if (dotype(s))
X			putf("%s%s_f%s(_link, _resync%d, _rv%s);\n",
X					pre, mkretcode(s), mkname(s),
X					n->resync->id, mkvarname(node, n));
X		else
X			putf("%s%s_f%s(_link, _resync%d);\n",
X					pre, mkretcode(s), mkname(s), n->resync->id);
X		// putf(" }\n");
X	}
}
X
X
static void genheader(void)
{
X    symbol *sym;
X    int i;
X
X    putf("#ifndef _T_O_K_E_N_S_\n#define _T_O_K_E_N_S_\n\n");
X
X    putf("#ifndef NULL\n#include <stdio.h>\n#endif\n\n");
X    putf("#define RETOK 1\n");
X    putf("#define RETERR 0\n\n");
X
X    putf("enum tokenids\n{\n");
X    putf("\tEOI = 0,\n");
X    putf("\t_EMPTY = 256, /* nothing uses this yet */\n");
X    boolean doid = TRUE;
X    for (i = START; i < numsymbols(); i++)
X    {
X	sym = getsymbol(i);
X	if (sym->type != TERMINAL || *sym->name == '\'')
X	    continue;
X	if (doid)
X	    putf("\t%s = 257,\n", mkname(sym));
X	else
X	    putf("\t%s,\n", mkname(sym));
X	doid = FALSE;
X    }
X    putf("};\n\n");
X
X    if (gotlexstr)
X    {
X	putf("#ifdef __cplusplus\n");
X	putf("extern \"C\" {\n");
X	putf("extern int yylex(void);\n");
X	putf("}\n");
X	putf("#else\n");
X	putf("extern int yylex();\n");
X	putf("#endif\n\n");
X
X	putf("#ifdef FLEX_SCANNER\n");
X	putf("#   undef YY_INPUT\n");
X	putf("#   define YY_INPUT(buf,result,max_size) \\\n");
X	putf("        result = (buf[0] = w_input()) == EOI ? YY_NULL : 1;\n");
X	putf("#else\n");
X	putf("#   undef input\n");
X	putf("#   define input w_input\n");
X	putf("#   undef unput\n");
X	putf("#   define unput w_unput\n");
X	putf("#endif\n\n");
X
X    }
X
X    putf("extern int w_numerrors;\n");
X    putf("#ifdef __cplusplus\n");
X    putf("extern \"C\" {\n");
X    putf("extern int w_scanerr(const char *, ...);\n");
X    putf("extern void w_flusherrs(void);\n");
X    putf("extern void w_closefile(void);\n");
X    putf("extern int w_openfile(char *);\n");
X    putf("extern FILE *w_getfile(void);\n");
X    putf("extern void w_setfile(FILE *);\n");
X    putf("extern int w_currcol(void);\n");
X    putf("extern int w_currline(void);\n");
X    putf("extern char *w_getcurrline(void);\n");
X    putf("extern int w_input(void);\n");
X    putf("extern int w_unput(int);\n");
X    putf("extern void w_output(int);\n");
X    putf("extern int w_gettoken(void);\n");
X    putf("extern int w_nexttoken(void);\n");
X    putf("extern void w_skiptoken(void);\n");
X    putf("extern char *w_tokenname(int);\n");
X    putf("}\n");
X    putf("#else\n");
X    putf("extern int w_scanerr();\n");
X    putf("extern void w_flusherrs();\n");
X    putf("extern void w_closefile();\n");
X    putf("extern int w_openfile();\n");
X    putf("extern FILE *w_getfile();\n");
X    putf("extern void w_setfile();\n");
X    putf("extern int w_currcol();\n");
X    putf("extern int w_currline();\n");
X    putf("extern char *w_getcurrline();\n");
X    putf("extern int w_input();\n");
X    putf("extern int w_unput();\n");
X    putf("extern void w_output();\n");
X    putf("extern int w_gettoken();\n");
X    putf("extern int w_nexttoken();\n");
X    putf("extern void w_skiptoken();\n");
X    putf("extern char *w_tokenname();\n");
X    putf("#endif\n\n");
X
X    if (exportedname)
X    {
X	for (i = 0; i < numnonterms(); i++)
X	{
X	    sym = getnonterm(i);
X	    if (sym->type != NONTERMINAL || !sym->export)
X		continue;
X	    mkstruct(sym);
X	    putf("#ifdef __cplusplus\n");
X	    putf("extern \"C\" { int %s(%s); }\n", mkname(sym),
X		    mkvoidtype(sym, "", " &"));
X	    putf("#else\n");
X	    putf("extern int %s();\n", mkname(sym));
X	    putf("#endif\n");
X	}
X    }
X    else
X    {
X	mkstruct(startsymbol);
X	putf("#ifdef __cplusplus\n");
X	putf("extern \"C\" { int %s(%s); }\n", mkname(startsymbol),
X		mkvoidtype(startsymbol, "", " &"));
X	putf("#else\n");
X	putf("extern int %s();\n", mkname(startsymbol));
X	putf("#endif\n");
X    }
X
X    putf("\n\n#endif /* _T_O_K_E_N_S_ */\n");
}
X
X
static void genscanner(char *header)
{
X	symbol *sym;
X	int i, c;
X	boolean nl = TRUE;
X
X	// scan past the definition section
X	while ((c = w_input()) != END)
X	{
X		if (nl && c == '%')
X		{
X			int t = w_input();
X			if (t == '%')
X				break;
X			put(c);
X			c = t;
X		}
X		put(c);
X		nl = c == '\n';
X	}
X
X	// dump out our header stuff here
X	putf("%%{\n");
X	putf("#include \"%s\"\n", header);
X	putf("%%}\n");
X
X	putf("%%%%\n");
X
X	// print the lexical values from the grammer
X	for (i = START; i < numsymbols(); i++)
X	{
X		symbol *sym = getsymbol(i);
X		if (sym->type != TERMINAL || sym->lexdef || sym->lexstr == NULL)
X			continue;
X		if (casesensitive || sym->name[0] != '"')
X			putf("%s", sym->lexstr);
X		else
X		{
X			for (char *s = sym->lexstr + 1;
X					*s != '\0' && !(*s == '"' && *(s + 1) == '\0');
X					s++)
X				if (isalpha(*s))
X					putf("[%c%c]",
X					    islower(*s) ? toupper(*s) : *s,
X					    isupper(*s) ? tolower(*s) : *s);
X				else if (*s == '\\' && *(s+1) == '"')
X					;
X				else
X					putf("\\%c", *s);
X		}
X		putf("\t{ return (int)%s; }\n", mkname(sym));
X		sym->lexdef = TRUE;
X	}
X
X	// now add the rules at the bottom of the source
X	if (c != END)
X		while ((c = w_input()) != END)
X		{
X			if (nl && c == '%')
X			{
X				int t = w_input();
X				if (t == '%')
X					break;
X				put(c);
X				c = t;
X			}
X			else if (nl && c == '$')
X			{
X				char *name = getword();
X				if (name == NULL)
X					quit("Unexpected end-of-w_input");
X				sym = findsymbol(name);
X
X				if (sym == NULL)
X					error("Symbol %s not in grammer", name);
X				if (sym->lexstr != NULL)
X					error("Symbol %s lexical string redefined in lex section",
X							name);
X
X				while ((c = w_input()) == ' ' || c == '\t')
X					;
X				if (c == '\n' || c == END)
X					putf("\n");
X				else
X				{
X					for (; c != END && c != '\n'; c = w_input())
X						put(c);
X					putf("\t{ return (int)%s; }", name);
X				}
X				sym->lexdef = TRUE;
X			}
X			put(c);
X			nl = c == '\n';
X		}
X
X	// check for missing tokens
X	for (i = START; i < numsymbols(); i++)
X	{
X		sym = getsymbol(i);
X		if (sym->type != TERMINAL || sym->lexdef)
X			continue;
X		if (sym->lexstr == NULL)
X			error("Lexical value for symbol %s is not defined", mkname(sym));
X	}
X
X	putf("%%%%\n");
X
X	// now copy the rest (user code)
X	if (c != END)
X		while ((c = w_input()) != END)
X			put(c);
}
X
X
static void dumpexport(symbol *sym)
{
X	putf("int %s(%s)\n{\n", mkname(sym),
X		mkvoidtype(sym, "", " &ret"));
X	putf("\tresynclink _link;\n\t");
X	printset("_follow", *sym->follow);
X	putf("\tint _rval;\n");
X	putf("\tint _savnum = w_numerrors;\n\n");
X	putf("\tw_numerrors = 0;\n");
X	putf("\t_rval = _f%s(_link, _follow%s);\n",
X			mkname(sym), dotype(sym) ? ", ret" : "");
X	putf("\tswitch (w_nexttoken())\n\t{\n");
X	printcase("\t", *sym->follow);
X	putf("\t\tbreak;\n");
X	putf("\tdefault:\n");
X	putf("\t\t_rval = w_scanerr(\"expected end of %s\");\n",
X			mkname(sym));
X	putf("\t}\n");
X	putf("\tif (w_numerrors > 0) _rval = RETERR;\n");
X	putf("\tw_numerrors += _savnum;\n");
X	putf("\tw_scanerr(NULL);\n");
X	putf("\treturn _rval;\n");
X	putf("}\n\n");
}
X
X
static void genparser(char *header)
{
X	symbol *sym;
X	symnode *n;
X	int i;
X
X	putf("#define YYTEXT_DECL unsigned char yytext[]\n\n");
X	mkcode("", startcode);
X	putf("\n#include \"%s\"\n\n", header);
X	putf("extern YYTEXT_DECL;\n");
X	putf("int w_numerrors = 0;\n\n");
X
X	putf("\nstruct resynclink\n{\n\tresynclink *prev;\n");
X	putf("\tint *resync;\n");
X	putf("\tresynclink() { prev = 0; resync = 0; }\n");
X	putf("\tresynclink(resynclink &p, int *s)");
X	putf(" { prev = &p; resync = s; }\n");
X	putf("};\n");
X
X	for (i = 0; i < numnonterms(); i++)
X	{
X		sym = getnonterm(i);
X		if (sym->type != NONTERMINAL)
X			continue;
X		if (!sym->export)
X			mkstruct(sym);
X		if (optimize && sym->usecount == 1 && !sym->export)
X			continue;
X		putf("static _f%s(resynclink &, int *%s);\n", mkname(sym),
X				mktype(sym, ", ", " &"));
X	}
X	putf("\n");
X
X	putf("static char *_toknams[] =\n{\n");
X	putf("\t\"[]\",\n");
X	for (i = START; i < numsymbols(); i++)
X	{
X		sym = getsymbol(i);
X		if (sym->type != TERMINAL || *sym->name == '\'')
X			continue;
X		char *str = sym->lexstr;
X
X		if (str == NULL)
X			putf("\t\"%s\",\n", mkname(sym));
X		else if (isalpha(*str))
X			putf("\t\"%s\",\n", str);
X		else if (*str == '"' && str[strlen(str) - 1] == '"')
X			putf("\t%s,\n", sym->lexstr);
X		else
X			putf("\t\"%s\",\n", mkname(sym));
X	}
X	putf("};\n\n");
X
X	putf("char *w_tokenname(int tok)\n{\n");
X	putf("\tstatic char buf[6];\n\n");
X	putf("\tif (tok > 255)\n");
X	putf("\t\treturn _toknams[tok - 256];\n");
X	putf("\tif (tok == 0)\n");
X	putf("\t\treturn \"EOI\";\n");
X	putf("\tbuf[0] = '`'; buf[1] = tok; buf[2] = '\\\'';\n");
X	putf("\treturn buf;\n");
X	putf("}\n\n");
X
X	putf("static int tok = -1;\n\n");
X
X	putf("int w_nexttoken()\n");
X	putf("{\n\tif (tok < 0)\n\t\ttok = w_gettoken();\n");
X	putf("\treturn tok;\n}\n\n");
X
X	putf("void w_skiptoken()\n{\n\ttok = -1;\n}\n\n");
X
X	putf("static int scantoken(int expect, resynclink &lnk, int *resync)\n");
X	putf("{\n\tresynclink rlink(lnk, resync);\n\tresynclink *link;\n\n");
X	putf("\tif (tok < 0)\n\t\ttok = w_gettoken();\n");
X	putf("\tif (expect >= 0 && tok != expect)\n");
X	putf("\t\tw_scanerr(\"expected %%s\", w_tokenname(expect));\n");
X	putf("\tint level = 1;\n");
X	putf("\twhile (tok != expect)\n\t{\n");
X	putf("\t\tint l = level;\n");
X	putf("\t\tfor (link = &rlink; link != NULL && l-- > 0;");
X	putf(" link = link->prev)\n");
X	putf("\t\t\tfor (int i = 0; link->resync[i] >= 0; i++)\n");
X	putf("\t\t\t\tif (tok == link->resync[i])\n");
X	putf("\t\t\t\t\treturn -1;\n\n");
X	putf("\t\tw_scanerr(NULL);\n");
SHAR_EOF
true || echo 'restore of gen.C failed'
fi
echo 'End of  part 1'
echo 'File gen.C is continued in part 2'
echo 2 > _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.