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.