v19i091: wacco - A C++ LL parser generator, Part04/06
Parag Patel
parag at hpsdeb.sde.hp.com
Sun May 19 04:01:45 AEST 1991
Submitted-by: Parag Patel <parag at hpsdeb.sde.hp.com>
Posting-number: Volume 19, Issue 91
Archive-name: wacco/part04
---- Cut Here and feed the following to sh ----
#!/bin/sh
# This is part 04 of wacco
# ============= wacco.w ==============
if test -f 'wacco.w' -a X"$1" != X"-c"; then
echo 'x - skipping wacco.w (File already exists)'
else
echo 'x - extracting wacco.w (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'wacco.w' &&
{
// Copyright (c) 1991 by Parag Patel. All Rights Reserved.
static const char rcs_id[] = "$Header: wacco.w,v 1.13 91/02/22 16:04:36 hmgr Exp $";
X
#undef YYTEXT_DECL
#define YYTEXT_DECL char yytext[]
X
#include "defs.h"
X
struct nodedat
{
X symbol *sym;
X union
X {
X symnode *node;
X char *alias;
X };
X nodedat *prev;
X nodedat() { sym = NULL; node = NULL; prev = NULL; }
};
X
}
X
program
X : directives { $code = NULL; } code { startcode = $code; } statlist
X ;
X
directives
X : DIRECTIVE
X {
X int argc;
X char **argv = strsep(yytext, " \t", TRUE, &argc);
X getoptions(argc, argv);
X }
X | []
X ;
X
statlist
X : statement { $code = NULL; } code { addnonterm($code); } statlist
X | []
X ;
X
statement<symbol*>
X : ID
X {
X $$ = addsymbol(yytext);
X if ($$->type == TERMINAL)
X (void)addnonterm($$);
X if (startsymbol == NULL)
X {
X startsymbol = $$;
X $$->usecount += 2;
X }
X }
X idtype
X {
X if ($$->rettype != NULL && $idtype != NULL &&
X strcmp($$->rettype, $idtype) != 0)
X scanerr("Two types defined for %s", $$->name);
X
X if ($$->rettype == NULL)
X $$->rettype = $idtype;
X else
X delete $idtype;
X }
X (<boolean> EXPORT { $$ = TRUE; } | [] { $$ = FALSE; })
X {
X if ($_)
X {
X exportedname = $$->export = TRUE;
X $$->usecount += 2;
X }
X }
X resyncset ':'
X {
X $$->list = $resyncset;
X nodedat end;
X end.sym = $concatlist.sym = $orlist.sym = $$;
X $concatlist.prev = $orlist.prev = &end;
X }
X concatlist
X {
X symnode *node = $$->node;
X if (node != NULL)
X {
X while (node->or != NULL)
X node = node->or;
X node->or = $concatlist.node;
X }
X else
X node = $$->node = $concatlist.node;
X }
X orlist
X {
X if (node == NULL)
X $$->node = $orlist.node;
X else if (node->or == NULL)
X node->or = $orlist.node;
X else
X node->or->or = $orlist.node;
X }
X ';'
X ;
X
idtype<char*>
X : '<' { $$ = readtype(); }
X | [] { $$ = NULL; }
X ;
X
concatlist<nodedat>
X : {
X $code = $exprlist.sym = $$.sym;
X $exprlist.prev = $$.prev;
X }
X code exprlist
X {
X if ($code == NULL)
X $$.node = $exprlist.node;
X else
X {
X $$.node = new symnode;
X $$.node->sym = $code;
X $$.node->next = $exprlist.node;
X }
X }
X | []
X ;
X
orlist<nodedat>
X : {
X $concatlist.sym = $orlist.sym = $$.sym;
X $concatlist.prev = $orlist.prev = $$.prev;
X }
X '|' concatlist orlist
X {
X $$.node = $concatlist.node;
X if ($$.node == NULL)
X $$.node = $orlist.node;
X else
X $$.node->or = $orlist.node;
X }
X | []
X ;
X
X
exprlist<nodedat>
X : {
X $expression.sym = $code = $exprlist.sym = $$.sym;
X $expression.prev = $exprlist.prev = $$.prev;
X }
X expression resyncset code exprlist
X {
X $$.node = new symnode;
X $$.node->sym = $expression.sym;
X $$.node->alias = $expression.alias;
X $$.node->next = $exprlist.node;
X $$.node->list = $resyncset;
X if ($code != NULL)
X {
X $$.node->next = new symnode;
X $$.node->next->sym = $code;
X $$.node->next->next = $exprlist.node;
X }
X }
X | []
X ;
X
resyncset<resynclist*>
X : '[' resynclist ']' { $$ = $resynclist; }
X | [] { $$ = NULL; }
X ;
X
resynclist<resynclist*>
X : resyncitem (',' resynclist { $$=$resynclist; } | [] { $$ = NULL; })
X {
X $$ = $resyncitem;
X $$->next = $_;
X }
X ;
X
resyncitem<resynclist*>
X : settype=first resyncid settype=follow
X {
X $$ = $resyncid;
X $$->first = $first == 0 && $follow == 0 ? 1 : $first;
X $$->follow = $follow;
X }
X ;
X
settype
X : '+' { $$ = 1; }
X | '-' { $$ = -1; }
X | [] { $$ = 0; }
X ;
X
resyncid<resynclist*>
X : ID { $$ = new resynclist(yytext); }
X | NULLSYM { $$ = new resynclist(NULL); }
X | STRING { $$ = new resynclist(yytext); }
X | CHARACTER { $$ = new resynclist(yytext); }
X | '#' count { $$ = new resynclist(NULL);
X $$->paren = $count == 0 ? 1 : $count; }
X ;
X
count
X : INT { $$ = atoi(yytext); }
X | '*' { $$ = -1; }
X | [] { $$ = 0; }
X ;
X
alias<char*>
X : '=' (ID { $$ = yytext; } | INT { $$ = yytext; })
X { $$ = strdup($_); }
X | [] { $$ = NULL; }
X ;
X
expression<nodedat>
X : ID { $$.sym = addsymbol(yytext); $$.sym->usecount++; }
X alias { $$.alias = $alias; }
X | NULLSYM { $$.sym = getsymbol(EMPTY); }
X | '#' count alias
X {
X nodedat *p = $$.prev;
X for (int i = 0; p != NULL && ($count < 0 || i < $count); i++)
X {
X $$.sym = p->sym;
X p = p->prev;
X }
X if ($count > 0 && i < $count)
X scanerr("not that many parentheses");
X $$.sym->usecount++;
X $$.alias = $alias;
X }
X | STRING
X {
X $$.sym = addsymbol(yytext);
X $$.sym->lexstr = $$.sym->name;
X gotlexstr = TRUE;
X }
X | CHARACTER
X {
X $$.sym = addsymbol(yytext);
X if ($$.sym->lexstr == NULL)
X {
X char *s = strdup(yytext);
X s[0] = s[strlen(s) - 1] = '"';
X $$.sym->lexstr = s;
X }
X }
X | '(' idtype
X {
X char *type = $$.sym->rettype;
X char *name = $$.sym->realname;
X static int num = 1;
X
X addnonterm($$.sym = addsymbol(strbldf("_P%d", num++)));
X $$.sym->type = NONTERMINAL;
X $$.sym->rettype = $idtype == NULL ? type : $idtype;
X $$.sym->realname = name;
X $$.sym->usecount++;
X
X $concatlist.sym = $orlist.sym = $$.sym;
X $concatlist.prev = $orlist.prev = &$$;
X }
X concatlist orlist ')' alias
X {
X $$.sym->node = $concatlist.node;
X if ($$.sym->node == NULL)
X $$.sym->node = $orlist.node;
X else
X $$.sym->node->or = $orlist.node;
X $$.alias = $alias;
X }
X ;
X
code<symbol*>
X : {
X int rettype = 0;
X int line = currline();
X }
X (<char*>
X '{' { $$ = readcode(rettype); }
X | BLOCKCODE { $$ = readblockcode(rettype); }
X )
X {
X if ($$ != NULL)
X $$->usedret = rettype;
X
X $$ = new symbol;
X $$->name = "<code>";
X $$->type = CODE;
X $$->code = $_;
X $$->line = line;
X }
X | [] { $$ = NULL; }
X ;
SHAR_EOF
chmod 0444 wacco.w ||
echo 'restore of wacco.w failed'
Wc_c="`wc -c < 'wacco.w'`"
test 5585 -eq "$Wc_c" ||
echo 'wacco.w: original size 5585, current size' "$Wc_c"
fi
# ============= defs.h ==============
if test -f 'defs.h' -a X"$1" != X"-c"; then
echo 'x - skipping defs.h (File already exists)'
else
echo 'x - extracting defs.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'defs.h' &&
// Copyright (c) 1991 by Parag Patel. All Rights Reserved.
// $Header: defs.h,v 1.15 91/05/17 16:29:55 hmgr Exp $
X
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <malloc.h>
X
#include "boolean.h"
#include "darray.h"
#include "table.h"
#include "bitset.h"
X
inline char *strdup(const char *s)
X { return s == NULL ? NULL : strcpy((char*)malloc(strlen(s) + 1), s); }
inline char *strnew(size_t len) { return (char*)malloc(len + 1); }
#if FREE_TAKES_CHAR
inline void strfree(const char *s) { if (s != NULL) free((char *)s); }
#else
inline void strfree(const char *s) { if (s != NULL) free((const void *)s); }
#endif
X
// for large switch statements
#define Case break;case
#define Default break;default
X
X
const TERMINAL = 1;
const NONTERMINAL = 2;
const CODE = 3;
X
const END = 0;
const EMPTY = 1;
const START = 2;
X
X
#define RET_NONE 0x00
#define RET_VALUE 0x01
#define RET_CODE 0x02
X
X
struct symbol;
struct symnode;
struct resynclist;
X
struct Set
{
X Bitset *set;
X int id;
X
X Set(Bitset *s = NULL) { set = s; }
X operator Bitset*() { return set; }
X boolean operator==(Bitset *b) { return *set == *b; };
};
X
struct symbol
{
X char *name;
X int id;
X int parserid;
X int type;
X
X char *rettype;
X union
X {
X char *lexstr;
X char *realname;
X };
X char *code;
X
X union
X {
X int usedret;
X boolean lexdef;
X int line;
X };
X
X int usecount;
X char toempty;
X char export;
X char mkstruct;
X
X Bitset *first;
X Bitset *follow;
X union
X {
X Set *resync;
X resynclist *list;
X };
X
X symnode *node;
X
X symbol(const char *n = NULL);
X operator char *() { return name; }
X boolean operator==(const char *k) { return strcmp(name, k) == 0; }
};
X
struct symnode
{
X symbol *sym;
X char *alias;
X symnode *next;
X symnode *or;
X union
X {
X Set *resync;
X resynclist *list;
X };
X
X symnode();
};
X
struct resynclist
{
X char *name;
X char first;
X char follow;
X char paren;
X resynclist *next;
X
X resynclist(char *);
X ~resynclist() { delete name; }
};
X
X
declare_table(Settab, Setiter, Set, Bitset*);
extern Settab settab;
X
extern boolean optimize;
extern boolean dumpcode;
extern boolean statonly;
extern boolean docompare;
extern boolean casesensitive;
extern boolean dargstyle;
extern boolean genlineinfo;
extern char *headername;
extern char *scannername;
extern char *parsername;
extern void getoptions(int argc, char *argv[]);
extern FILE *makefile(char *fname);
extern void cmpandmv(char *file);
extern boolean exportedname;
X
extern int numsymbols(void);
extern symbol *getsymbol(int);
extern int numterms(void);
extern int numnonterms(void);
extern symbol *getterm(int);
extern symbol *getnonterm(int);
extern symbol *addsymbol(const char *);
extern void addterm(symbol *);
extern void addnonterm(symbol *);
extern symbol *findsymbol(const char *);
extern void initsym(void);
extern symbol *startsymbol;
extern symbol *startcode;
X
extern "C" {
X extern int w_input(void);
X extern int w_unput(int chr);
}
X
extern boolean gotlexstr;
extern void readccomment(void);
extern char *readtype(void);
extern char *readcode(int &);
extern char *readblockcode(int &);
extern char *getword(void);
X
extern void buildsets(void);
extern void check(void);
extern void gencode(char *infile);
X
extern void quit(char *fmt, ...);
extern int error(char *fmt, ...);
X
extern char **strsep(const char *str, const char *sep,
X boolean whsp = TRUE, int *num = NULL);
extern const char *strbldf(const char *fmt, ...);
X
declare_array(charbuf, char);
declare_array(charvec, char*);
SHAR_EOF
chmod 0444 defs.h ||
echo 'restore of defs.h failed'
Wc_c="`wc -c < 'defs.h'`"
test 3575 -eq "$Wc_c" ||
echo 'defs.h: original size 3575, current size' "$Wc_c"
fi
# ============= toks.h ==============
if test -f 'toks.h' -a X"$1" != X"-c"; then
echo 'x - skipping toks.h (File already exists)'
else
echo 'x - extracting toks.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'toks.h' &&
// Copyright (c) 1991 by Parag Patel. All Rights Reserved.
// $Header: toks.h,v 1.9 91/02/22 16:04:47 hmgr Exp $
X
#ifndef _T_O_K_E_N_S_
#define _T_O_K_E_N_S_
X
#ifndef NULL
#include <stdio.h>
#endif
X
#define RETOK 1
#define RETERR 0
X
enum tokenids
{
X EOI = 0,
X _EMPTY = 256, /* nothing uses this yet */
X DIRECTIVE = 257,
X ID,
X EXPORT,
X NULLSYM,
X STRING,
X CHARACTER,
X INT,
X BLOCKCODE,
};
X
#ifdef __cplusplus
extern "C" {
extern int yylex();
extern int yylook();
extern int w_input();
extern int w_unput(int);
extern void w_output(int);
}
#else
extern int yylex();
extern int yylook();
extern int w_input();
extern int w_unput();
extern void w_output();
#endif
X
extern int w_numerrors;
#ifdef __cplusplus
extern "C" {
extern int w_scanerr(const char *, ...);
extern void w_flusherrs();
extern void w_closefile();
extern int w_openfile(char *);
extern FILE *w_getfile();
extern void w_setfile(FILE *);
extern int w_currcol();
extern int w_currline();
extern char *w_getcurrline();
extern int w_gettoken();
extern int w_nexttoken();
extern void w_skiptoken();
extern char *w_tokenname(int);
}
#else
extern int w_scanerr();
extern void w_flusherrs();
extern void w_closefile();
extern int w_openfile();
extern FILE *w_getfile();
extern void w_setfile();
extern int w_currcol();
extern int w_currline();
extern char *w_getcurrline();
extern int w_gettoken();
extern int w_nexttoken();
extern void w_skiptoken();
extern char *w_tokenname();
#endif
X
#ifdef __cplusplus
extern "C" { int program(); }
#else
extern int program();
#endif
X
X
#endif /* _T_O_K_E_N_S_ */
SHAR_EOF
chmod 0444 toks.h ||
echo 'restore of toks.h failed'
Wc_c="`wc -c < 'toks.h'`"
test 1555 -eq "$Wc_c" ||
echo 'toks.h: original size 1555, current size' "$Wc_c"
fi
# ============= boolean.h ==============
if test -f 'boolean.h' -a X"$1" != X"-c"; then
echo 'x - skipping boolean.h (File already exists)'
else
echo 'x - extracting boolean.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'boolean.h' &&
// Copyright (c) 1991 by Parag Patel. All Rights Reserved.
// $Header: boolean.h,v 1.3 91/02/22 16:04:53 hmgr Exp $
X
typedef int boolean;
const boolean FALSE = 0;
const boolean TRUE = 1;
SHAR_EOF
chmod 0444 boolean.h ||
echo 'restore of boolean.h failed'
Wc_c="`wc -c < 'boolean.h'`"
test 188 -eq "$Wc_c" ||
echo 'boolean.h: original size 188, current size' "$Wc_c"
fi
# ============= bitset.h ==============
if test -f 'bitset.h' -a X"$1" != X"-c"; then
echo 'x - skipping bitset.h (File already exists)'
else
echo 'x - extracting bitset.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'bitset.h' &&
// Copyright (c) 1991 by Parag Patel. All Rights Reserved.
// $Header: bitset.h,v 1.3 91/02/22 16:04:57 hmgr Exp $
X
#define __B_S_BIT(n) ((long)(1L << (n & 0x1F)))
#define __B_S_ELT(n) (n >> 5)
X
// a set of ints (esp. enums) - also an array of bits
class Bitset
{
X int num;
X long *elts;
X
X friend class Bitsetiter;
X
X void bumpsize(int); // grow the Bitset
X // inline for speed
X void BUMPSIZE(int largest) { if (num < largest) bumpsize(largest); }
X
public:
X Bitset(int, int,...); // new element list
X Bitset(int); // new size
X Bitset(Bitset const &); // new Bitset
X Bitset() { elts = new long; num = 0; elts[0] = 0L; }
X ~Bitset() { delete elts; } // destructor
X
X Bitset& operator=(Bitset const &); // dup
X
X Bitset& add(int); // add to
X Bitset& remove(int); // delete from
X Bitset& operator+=(int e) { return add(e); }
X Bitset& operator-=(int e) { return remove(e); }
X
X int size() const; // number of elements in Bitset
X int card() const { return size(); } // for clarity?
X boolean isin(int bit) const
X { return bit >= 0 && bit <= num &&
X (elts[__B_S_ELT(bit)] & __B_S_BIT(bit)); }
X void clear(); // clear the set
X unsigned long hash() const; // return a hash number for this set
X
X Bitset& operator|=(Bitset const &); // union with
X Bitset& operator&=(Bitset const &); // intersect with
X Bitset& operator-=(Bitset const &); // difference from
X Bitset& operator^=(Bitset const &); // symmetric difference from
X Bitset& operator~(); // complement self
X
X int get(int elt) const
X { return (elt >= 0 && elt <= num &&
X (elts[__B_S_ELT(elt)] & __B_S_BIT(elt))) ? 1 : 0; }
X int operator[](int elt) const { return get(elt); }
X
X // equality testing:
X boolean operator==(Bitset const &s) const;
X boolean operator!=(Bitset const &s) const { return !(s == *this); }
X // subset and superset:
X boolean operator<=(Bitset const &s) const;
X boolean operator>=(Bitset const &s) const { return s <= *this; }
X // proper subset and proper superset:
X boolean operator<(Bitset const &s) const
X { return *this != s && *this <= s; }
X boolean operator>(Bitset const &s) const { return s < *this; }
};
X
// iterator over a Bitset
class Bitsetiter
{
X int elt, len;
X int *arr;
X
public:
X Bitsetiter(Bitset const &); // creator - iterate over a set
X ~Bitsetiter() { delete arr; }
X // get next element in set
X int operator()() { return elt >= len ? elt = 0, -1 : arr[elt++]; }
};
X
#undef __B_S_ELT
#undef __B_S_BIT
SHAR_EOF
chmod 0444 bitset.h ||
echo 'restore of bitset.h failed'
Wc_c="`wc -c < 'bitset.h'`"
test 2537 -eq "$Wc_c" ||
echo 'bitset.h: original size 2537, current size' "$Wc_c"
fi
# ============= darray.h ==============
if test -f 'darray.h' -a X"$1" != X"-c"; then
echo 'x - skipping darray.h (File already exists)'
else
echo 'x - extracting darray.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'darray.h' &&
// Copyright (c) 1991 by Parag Patel. All Rights Reserved.
// $Header: darray.h,v 1.3 91/02/22 16:05:04 hmgr Exp $
X
// Handle simple dynamic arrays of arbitrary type and range.
// They are automatically grown to fit any array-like reference.
// by Parag Patel
X
X
// this is used to create an ARRAY of a TYPE
#define declare_array(ARRAY, TYPE) \
class ARRAY \
{ \
X long len; \
X long max; \
X TYPE *arr; \
X TYPE &bumpsize(long); \
public: \
X ARRAY() { arr = 0; max = len = 0; } \
X ARRAY(long siz) \
X { arr = 0; max = len = 0; if (siz > 0) bumpsize(siz-1); } \
X ARRAY(const ARRAY &); \
X ~ARRAY() { delete[max] arr; } \
X ARRAY &operator=(const ARRAY &); \
X long size() const { return len; } \
X void reset(long l = 0) { bumpsize(l); len = l; } \
X TYPE &operator[](long e) \
X { if (e < len) return arr[e]; else return bumpsize(e); } \
X TYPE *getarr() { return arr; } \
};
X
X
// this implements an ARRAY of a TYPE
#define implement_array(ARRAY, TYPE) \
TYPE &ARRAY::bumpsize(long elt) \
{ \
X if (elt < 0) \
X elt = 0; \
X if (elt >= max) \
X { \
X long omax = max; \
X if (max <= 0) \
X max = 1; \
X TYPE *narr = new TYPE[max = elt + (max > 1024 ? 1024 : max)]; \
X for (long i = 0; i < len; i++) \
X narr[i] = arr[i]; \
X delete[omax] arr; \
X arr = narr; \
X } \
X if (elt >= len) \
X len = elt + 1; \
X return arr[elt]; \
} \
ARRAY &ARRAY::operator=(const ARRAY &a) \
{ \
X if (&a == this) \
X return *this; \
X if (a.len > len) \
X bumpsize(a.len); \
X len = a.len; \
X for (long i = 0; i < len; i++) \
X arr[i] = a.arr[i]; \
X return *this; \
} \
ARRAY::ARRAY(const ARRAY &t) \
{ \
X arr = 0; \
X max = len = 0; \
X *this = t; \
}
SHAR_EOF
chmod 0444 darray.h ||
echo 'restore of darray.h failed'
Wc_c="`wc -c < 'darray.h'`"
test 1624 -eq "$Wc_c" ||
echo 'darray.h: original size 1624, current size' "$Wc_c"
fi
# ============= table.h ==============
if test -f 'table.h' -a X"$1" != X"-c"; then
echo 'x - skipping table.h (File already exists)'
else
echo 'x - extracting table.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'table.h' &&
// Copyright (c) 1991 by Parag Patel. All Rights Reserved.
// $Header: table.h,v 1.5 91/05/17 16:30:00 hmgr Exp $
X
#ifndef GENERICH
#include <generic.h>
#endif
X
#include <stddef.h>
X
#define table_node(table) name2(table,node)
#define table_key(table) name2(table,key)
X
typedef unsigned TABLE_BUMP(unsigned);
extern unsigned table_bump(unsigned);
X
X
#define declare_table(table,iterator,symbol,key) \
typedef key table_key(table); \
struct table_node(table) \
{ \
X table_node(table) *next; \
X symbol sym; \
X table_node(table)(key k, table_node(table) *tail) \
X : sym(k) { next = tail; } \
X table_node(table)(symbol &s, table_node(table) *tail) \
X : sym(s) { next = tail; } \
}; \
class table \
{ \
X unsigned hash_size; \
X unsigned threshold; \
X unsigned numnode; \
X table_node(table) **vec; \
X table_node(table) *curr; \
X friend class iterator; \
X unsigned (*bump)(unsigned); \
X void resize(unsigned =0); \
X void delnode(table_node(table) **); \
X boolean insertsym(symbol&); \
public: \
X table(unsigned hs =0, TABLE_BUMP *bump_function =NULL); \
X table(table&); \
X ~table(); \
X boolean find(key); \
X boolean insert(key); \
X boolean remove(key); \
X boolean operator+=(key k) { return insert(k); } \
X boolean operator-=(key k) { return remove(k); } \
X boolean operator==(key k) { return find(k); } \
X boolean operator!=(key k) { return !find(k); } \
X symbol &operator[](key); \
X symbol &get(); \
X symbol &operator()(); \
X symbol &operator*(); \
X symbol *operator->(); \
X table& clear(); \
X table& operator=(table&); \
X boolean operator==(table&); \
X table& operator+=(table&); \
X table& operator-=(table&); \
X table& operator&=(table&); \
X unsigned size(); \
}; \
class iterator \
{ \
X table *parent; \
X table_node(table) *curr; \
X unsigned index; \
X void transfer(table *); \
X friend class table; \
public: \
X iterator(); \
X iterator(table &); \
X ~iterator(); \
X table &operator=(table &); \
X boolean operator==(iterator &); \
X boolean operator!=(iterator &); \
X operator boolean(); \
X symbol &get(); \
X symbol &operator()(); \
X symbol &operator*(); \
X symbol *operator->(); \
X symbol &operator++(); \
X void remove(); \
}; \
inline symbol &table::operator[](key k) \
{ \
X void(insert(k)); \
X return curr->sym; \
} \
inline symbol &table::get() \
{ \
X if (curr != NULL) \
X return curr->sym; \
X else \
X return *(symbol *)NULL; \
} \
inline symbol &table::operator()() { return get(); } \
inline symbol &table::operator*() { return get(); } \
inline symbol *table::operator->() { return &get(); } \
inline unsigned table::size() \
{ \
X return numnode; \
} \
inline iterator::iterator() \
{ \
X parent = NULL; \
X curr = NULL; \
} \
inline iterator::iterator(table &t) \
{ \
X parent = NULL; \
X this->transfer(&t); \
} \
inline iterator::~iterator() \
{ \
X this->transfer(NULL); \
} \
inline table &iterator::operator=(table &t) \
{ \
X this->transfer(&t); \
X return t; \
} \
inline boolean iterator::operator==(iterator &i) \
{ \
X return (curr == i.curr); \
} \
inline boolean iterator::operator!=(iterator &i) \
{ \
X return (curr != i.curr); \
} \
inline iterator::operator boolean() \
{ \
X return (curr != NULL); \
} \
inline symbol &iterator::get() \
{ \
X if (curr != NULL) \
X return curr->sym; \
X else \
X return *(symbol *)NULL; \
} \
inline symbol &iterator::operator()() { return get(); } \
inline symbol &iterator::operator*() { return get(); } \
inline symbol *iterator::operator->() { return &get(); } \
X
X
X
#define implement_table(table,iterator,symbol,key,hash_func) \
table::table(unsigned hs, TABLE_BUMP *bump_function) \
{ \
X hash_size = 0; \
X numnode = 0; \
X vec = NULL; \
X curr = NULL; \
X bump = (bump_function == NULL) ? &table_bump : bump_function; \
X resize(hs); \
} \
table::table(table& h) \
{ \
X hash_size = 0; \
X numnode = 0; \
X vec = NULL; \
X curr = NULL; \
X bump = h.bump; \
X resize(h.hash_size); \
X *this = h; \
} \
table::~table() \
{ \
X clear(); \
X delete vec; \
} \
boolean table::find(key k) \
{ \
X register table_node(table) *p = vec[hash_func(k) % hash_size]; \
X for (; p != NULL; p = p->next) \
X if (p->sym == k) \
X { \
X curr = p; \
X return TRUE; \
X } \
X curr = NULL; \
X return FALSE; \
} \
boolean table::insert(key k) \
{ \
X if (numnode >= threshold) \
X resize(); \
X register table_node(table) **q = vec + hash_func(k) % hash_size; \
X register table_node(table) *p = *q; \
X for (; p != NULL; p = p->next) \
X if (p->sym == k) \
X { \
X curr = p; \
X return FALSE; \
X } \
X curr = *q = new table_node(table)(k, *q); \
X numnode++; \
X return TRUE; \
} \
boolean table::insertsym(symbol &s) \
{ \
X if (numnode >= threshold) \
X resize(); \
X register table_node(table) **q = vec + \
X hash_func((table_key(table))s) % hash_size; \
X register table_node(table) *p = *q; \
X for (; p != NULL; p = p->next) \
X if (p->sym == (table_key(table))s) \
X { \
X curr = p; \
X return FALSE; \
X } \
X curr = *q = new table_node(table)(s, *q); \
X numnode++; \
X return TRUE; \
} \
boolean table::remove(key k) \
{ \
X register table_node(table) **p = vec + hash_func(k) % hash_size; \
X curr = NULL; \
X for (; (*p) != NULL; p = &((**p).next)) \
X if ((**p).sym == k) \
X { \
X delnode(p); \
X return TRUE; \
X } \
X return FALSE; \
} \
void table::delnode(table_node(table) **p) \
{ \
X table_node(table) *next = (**p).next; \
X delete *p; \
X *p = next; \
X --numnode; \
} \
void table::resize(unsigned hs) \
{ \
X register table_node(table) **pos, **endpos; \
X table_node(table) *chain = NULL; \
X unsigned new_hash_size = (hs == 0) ? bump(hash_size) : hs; \
X if (new_hash_size == 0) \
X new_hash_size = 1; \
X if (new_hash_size <= hash_size) \
X return; \
X if (vec != NULL) \
X { \
X pos = vec; \
X endpos = pos + hash_size; \
X for (; pos < endpos; pos++) \
X { \
X table_node(table) *p = *pos; \
X if (p != NULL) \
X { \
X while (p->next != NULL) \
X p = p->next; \
X p->next = chain; \
X chain = *pos; \
X } \
X } \
X } \
X hash_size = new_hash_size; \
X threshold = hash_size + (hash_size >> 2); \
X delete vec; \
X pos = vec = new table_node(table) *[hash_size]; \
X endpos = pos + hash_size; \
X while (pos < endpos) \
X *(pos++) = NULL; \
X while (chain != NULL) \
X { \
X table_node(table) *entry = chain; \
X chain = entry->next; \
X pos = vec + \
X hash_func((table_key(table))entry->sym) \
X % hash_size; \
X entry->next = *pos; \
X *pos = entry; \
X } \
} \
table& table::clear() \
{ \
X for (int i = 0; i < hash_size; i++) \
X { \
X table_node(table) *p = vec[i]; \
X while (p != NULL) \
X { \
X table_node(table) *next = p->next; \
X delete p; \
X p = next; \
X } \
X vec[i] = NULL; \
X } \
X numnode = 0; \
X curr = NULL; \
X return *this; \
} \
table& table::operator=(table& h) \
{ \
X if (this == &h) \
X return *this; \
X clear(); \
X for (iterator i = h; i; i++) \
X insertsym(i()); \
X return *this; \
} \
boolean table::operator==(table& h) \
{ \
X if (this == &h) \
X return TRUE; \
X if (size() != h.size()) \
X return FALSE; \
X for (iterator i = h; i; i++) \
X if (!find((table_key(table))i())) \
X return FALSE; \
X return TRUE; \
} \
table& table::operator+=(table& h) \
{ \
X if (this == &h) \
X return *this; \
X for (iterator i = h; i; i++) \
X insert((table_key(table))i()); \
X return *this; \
} \
table& table::operator-=(table& h) \
{ \
X if (this == &h) \
X return clear(); \
X for (iterator i = h; i; i++) \
X remove((table_key(table))i()); \
X return *this; \
} \
table& table::operator&=(table& h) \
{ \
X if (this == &h) \
X return *this; \
X for (iterator i = *this; i; ) \
X if (h.find((table_key(table))i())) \
X i++; \
X else \
X i.remove(); \
X return *this; \
} \
symbol &iterator::operator++() \
{ \
X if (curr != NULL) \
X { \
X table_node(table) *prev = curr; \
X for (curr = curr->next; \
X curr == NULL && ++index < parent->hash_size; \
X curr = parent->vec[index]) \
X ; \
X return prev->sym; \
X } \
X else \
X { \
X return *(symbol *)NULL; \
X } \
} \
void iterator::remove() \
{ \
X if (curr != NULL) \
X { \
X register table_node(table) **p = parent->vec + index; \
X for (; (*p) != curr; p = &((**p).next)) \
X ; \
X parent->delnode(p); \
X } \
} \
void iterator::transfer(table *newparent) \
{ \
X if ((parent = newparent) != NULL) \
X { \
X for (index = 0, curr = parent->vec[0]; \
X curr == NULL && ++index < parent->hash_size; \
X curr = parent->vec[index]) \
X ; \
X } \
X else \
X curr = NULL; \
}
SHAR_EOF
chmod 0444 table.h ||
echo 'restore of table.h failed'
Wc_c="`wc -c < 'table.h'`"
test 8290 -eq "$Wc_c" ||
echo 'table.h: original size 8290, current size' "$Wc_c"
fi
# ============= bitset.C ==============
if test -f 'bitset.C' -a X"$1" != X"-c"; then
echo 'x - skipping bitset.C (File already exists)'
else
echo 'x - extracting bitset.C (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'bitset.C' &&
// Copyright (c) 1991 by Parag Patel. All Rights Reserved.
// $Header: bitset.C,v 1.3 91/02/22 16:05:27 hmgr Exp $
X
// A set of ints (or an array of bits) is implemented by matching
// each element in the set with its corresponding bit position in
// a word of infinite size. The word is implemented as an array
// of "long" that is grown in size as necessary. Thus this set of
// ints is not limited in size, like most Pascal implementations.
//
// By Parag Patel
X
#include <stdio.h>
#include <stdarg.h>
#include "boolean.h"
#include "bitset.h"
X
X
// the following are machine-dependant - change them if necessary
// sizeof long == 32 bits == 2**5 --> 5, therefore ...
const int NUM = 32;
const int SHIFT = 5;
const int MASK = 0x1F;
const long EMPTY = 0;
X
X
// generic minimum function
static inline int MIN(int i1, int i2)
{
X return i1 < i2 ? i1 : i2;
}
X
// this determines which particular "long" in the array has this element
static inline int ELT(int e)
{
X return e >> SHIFT;
}
X
// this gets the bit position in a "long" for this set element
static inline long BIT(int e)
{
X return ((long)(1L << (e & MASK)));
}
X
// this adds an element to an array of longs
static inline void ADD(long *elts, int e)
{
X elts[ELT(e)] |= BIT(e);
}
X
X
// return a new set of elts - clear it
static long *newelts(int largest)
{
X register long *elts = new long[ELT(largest) + 1];
X
X for (register int i = ELT(largest); i >= 0; i--)
X elts[i] = EMPTY;
X return elts;
}
X
// bump the size of a set
void Bitset::bumpsize(int largest)
{
X if (largest <= num)
X return;
X
X // only re-allocate our array if we are out of ELTs
X if (ELT(largest) != ELT(num))
X {
X register long *ne = newelts(largest);
X for (register int i = ELT(num); i >= 0; i--)
X ne[i] = elts[i];
X delete elts;
X elts = ne;
X }
X num = largest;
}
X
// various constructors:
X
// construct a set from a list of elements
Bitset::Bitset(int e1, int e2 ...)
{
X // if the first element is < 0, we ignore the rest
X if (e1 < 0)
X {
X elts = new long;
X num = 0;
X elts[0] = 0L;
X return;
X }
X
X // the largest element in our list for determining the initial
X // Bitset size
X register int largest = e1 > e2 ? e1 : e2;
X va_list ap;
X register int t;
X
X // if we have more than 3 elements, we need to use varargs
X if (e2 >= 0)
X {
X // find the largest element to be put in the set
X va_start(ap, e2);
X while ((t = va_arg(ap, int)) >= 0)
X if (t > largest)
X largest = t;
X va_end(ap);
X }
X
X // allocate the space for this set
X elts = newelts(num = largest);
X
X // add all the elements to the set
X ADD(elts, e1);
X if (e2 >= 0)
X {
X ADD(elts, e2);
X va_start(ap, e2);
X while ((t = va_arg(ap, int)) >= 0)
X ADD(elts, t);
X va_end(ap);
X }
}
X
// make a new set of the specified size
Bitset::Bitset(int size)
{
X if (size <= 1)
X size = 1;
X elts = newelts(num = size - 1);
}
X
// dup a set
Bitset::Bitset(const Bitset &s)
{
X elts = newelts(num = s.num);
X for (register int i = ELT(s.num); i >= 0; i--)
X elts[i] = s.elts[i];
}
X
// assign a set to a set - also a dup
Bitset &Bitset::operator=(const Bitset &s)
{
X register int i, t;
X
X BUMPSIZE(s.num);
X for (i = t = ELT(s.num); i >= 0; i--)
X elts[i] = s.elts[i];
X for (i = ELT(num); i > t; i--)
X elts[i] = EMPTY;
X return *this;
}
X
X
// add an element to a set
Bitset &Bitset::add(int elt)
{
X if (elt < 0)
X return *this;
X BUMPSIZE(elt);
X elts[ELT(elt)] |= BIT(elt);
X return *this;
}
X
// delete an element from a set
Bitset &Bitset::remove(int elt)
{
X if (elt < 0)
X return *this;
X elts[ELT(elt)] &= ~BIT(elt);
X return *this;
}
X
// union with set
Bitset &Bitset::operator|=(const Bitset &s)
{
X BUMPSIZE(s.num);
X for (register int i = ELT(s.num); i >= 0; i--)
X elts[i] |= s.elts[i];
X return *this;
}
X
// intersect with set
Bitset &Bitset::operator&=(const Bitset &s)
{
X register int t = ELT(s.num);
X
X BUMPSIZE(s.num);
X for (register int i = ELT(num); i >= 0; i--)
X elts[i] &= i <= t ? s.elts[i] : EMPTY;
X return *this;
}
X
// difference from set
Bitset &Bitset::operator-=(const Bitset &s)
{
X for (register int i = MIN(ELT(num), ELT(s.num)); i >= 0; i--)
X elts[i] &= ~s.elts[i];
X return *this;
}
X
// symmetric difference (xor) from set
Bitset &Bitset::operator^=(const Bitset &s)
{
X BUMPSIZE(s.num);
X for (register int i = ELT(s.num); i >= 0; i--)
X elts[i] ^= s.elts[i];
X return *this;
}
X
// complement set
Bitset &Bitset::operator~()
{
X register int i = ELT(num);
X
X elts[i] = ((BIT(num) << 1) - 1) & ~elts[i];
X for (i--; i >= 0; i--)
X elts[i] = ~elts[i];
X return *this;
}
X
// is set a subset of s?
boolean Bitset::operator<=(const Bitset &s) const
{
X register int i = MIN(num, s.num);
X
X for (i = ELT(i); i >= 0; i--)
X if ((elts[i] & s.elts[i]) != elts[i])
X return FALSE;
X if (num <= s.num)
X return TRUE;
X
X register int t = ELT(s.num);
X for (i = ELT(num); i > t; i--)
X if (elts[i])
X return FALSE;
X return TRUE;
}
X
// is set same as s?
boolean Bitset::operator==(const Bitset &s) const
{
X register int i = MIN(num, s.num);
X
X for (i = ELT(i); i >= 0; i--)
X if (elts[i] != s.elts[i])
X return FALSE;
X if (num == s.num)
X return TRUE;
X
X register int t;
X if (num < s.num)
X {
X for (t = ELT(num), i = ELT(s.num); i > t; i--)
X if (s.elts[i])
X return FALSE;
X }
X else
X {
X for (t = ELT(s.num), i = ELT(num); i > t; i--)
X if (elts[i])
X return FALSE;
X }
X return TRUE;
}
X
X
// return the number of elements in the set (cardinality)
int Bitset::size() const
{
X register int n = 0;
X
X for (register int i = ELT(num); i >= 0; i--)
X for (register long m = 1; m; m <<= 1)
X if (elts[i] & m)
X n++;
X return n;
}
X
// clear the set of all elements
void Bitset::clear()
{
X for (register int i = ELT(num); i >= 0; i--)
X elts[i] = EMPTY;
}
X
// return a hash number for this set
unsigned long Bitset::hash() const
{
X register int i = ELT(num);
X
X // skip over null elements in array to make
X // hash value independent of size
X while (i >= 0 && elts[i] == 0)
X i--;
X
X // now we can hash safely...
X register unsigned long h = 0;
X for (; i >= 0; i--)
X {
X // "+" moves around the bits a lot better than "^"
X h += elts[i];
X // rotate "h" left by 3 bits, just to mix things up
X h = (h << 3) | (h >> (NUM - 3));
X }
X
X return h;
}
X
X
X
// set iterator class:
X
// creator
Bitsetiter::Bitsetiter(const Bitset &s)
{
X int i, e;
X int num = 0;
X
X arr = new int[len = s.size()];
X int t = ELT(s.num);
X for (e = 0, i = 0; i <= t; i++)
X for (long m = 1; m; e++, m <<= 1)
X if (s.elts[i] & m)
X arr[num++] = e;
X elt = 0;
}
SHAR_EOF
chmod 0444 bitset.C ||
echo 'restore of bitset.C failed'
Wc_c="`wc -c < 'bitset.C'`"
test 6447 -eq "$Wc_c" ||
echo 'bitset.C: original size 6447, current size' "$Wc_c"
fi
# ============= tgram.w ==============
if test -f 'tgram.w' -a X"$1" != X"-c"; then
echo 'x - skipping tgram.w (File already exists)'
else
echo 'x - extracting tgram.w (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'tgram.w' &&
// Copyright (c) 1991 by Parag Patel. All Rights Reserved.
// $Header: tgram.w,v 1.5 91/02/22 16:05:33 hmgr Exp $
X
{
#include <stdio.h>
}
X
program
X : "program" ID '(' idlist ')' semi
X declarations subprogdecls compoundstat '.'
X ;
X
semi
X : ';'[semi+]
X ;
X
idlist
X : ID (',' ID | [])
X ;
X
declarations
X : "var" (decllist | semi)
X | []
X ;
X
decllist
X : idlist ':' type semi (decllist | [])
X ;
X
type
X : "integer"
X | "array" '[' INT ".." INT ']' "of" "integer"
X ;
X
subprogdecls
X : subproghead declarations subprogdecls
X compoundstat semi subprogdecls
X | []
X ;
X
subproghead
X : "function" ID arguments ':' "integer" semi
X | "procedure" ID arguments semi
X ;
X
arguments
X : '(' paramlist ')'
X | []
X ;
X
paramlist
X : idlist ':' type (semi paramlist | [])
X ;
X
compoundstat
X : "begin" statlist "end"[+semi+]
X ;
X
statlist
X : statement semi statlist
X | []
X ;
X
statement
X : ID assignment
X | compoundstat
X | "if" expression "then" statement ("else" statement | [])
X | "while" expression "do" statement
X | "for" varref ":=" expression ("to" | "downto")
X expression "do" statement
X ;
X
assignment
X : '[' expression ']' ":=" expression
X | '(' exprlist ')'
X | ":=" expression
X | []
X ;
X
varref
X : ID ('[' expression ']' | [])
X ;
X
exprlist
X : expression (',' exprlist | [])
X ;
X
expression
X : term (('+'|'-') expression | [])
X ;
X
term
X : expr (('*'|'/') term | [])
X ;
X
expr
X : ID ('(' exprlist ')' | '[' expression ']' [')'] | [])
X | INT
X | '(' expression ')'
X | "not" expression
X | ('+'|'-') expression
X ;
X
{
X int main()
X {
X w_setfile(stdin);
X
X if (!program())
X return 1;
X
X return 0;
X }
}
X
$$
X
D [0-9]
L [A-Za-z_$]
X
%%
X
$ID {L}({L}|{D})*
$INT {D}+
X
[ \t\v\n\f] ;
. { w_scanerr("Illegal character %d (%c)", yytext[0], yytext[0]); }
SHAR_EOF
chmod 0444 tgram.w ||
echo 'restore of tgram.w failed'
Wc_c="`wc -c < 'tgram.w'`"
test 1739 -eq "$Wc_c" ||
echo 'tgram.w: original size 1739, current size' "$Wc_c"
fi
# ============= tgram.good ==============
if test -f 'tgram.good' -a X"$1" != X"-c"; then
echo 'x - skipping tgram.good (File already exists)'
else
echo 'x - extracting tgram.good (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'tgram.good' &&
program test(input);
X
var
X x, a: integer;
X ara: array [1..10] of integer;
X
procedure try(a:integer);
X var u,v:integer;
X begin
X if not a then try:=u+3 else try:=a;
X end;
X
begin
X while a do
X begin
X x := a-1;
X a:=5*a;
X end;
end.
SHAR_EOF
chmod 0444 tgram.good ||
echo 'restore of tgram.good failed'
Wc_c="`wc -c < 'tgram.good'`"
test 229 -eq "$Wc_c" ||
echo 'tgram.good: original size 229, current size' "$Wc_c"
fi
# ============= tgram.bad ==============
if test -f 'tgram.bad' -a X"$1" != X"-c"; then
echo 'x - skipping tgram.bad (File already exists)'
else
echo 'x - extracting tgram.bad (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'tgram.bad' &&
program test(input);
X
var
X x a: integer;
X ara: array [1...10] of integer;
X
procedure try(a:integer):result integer;
X u,v:integer;
X begin
if not not a try:=u+ else try:=a;
X end
X end
X
begin
X while not x a do
X x = a-1;
X a2:=5**a;
X x:= ara[3]*(ara[x+x)
X end
end
SHAR_EOF
chmod 0444 tgram.bad ||
echo 'restore of tgram.bad failed'
Wc_c="`wc -c < 'tgram.bad'`"
test 261 -eq "$Wc_c" ||
echo 'tgram.bad: original size 261, current size' "$Wc_c"
fi
# ============= main.C ==============
if test -f 'main.C' -a X"$1" != X"-c"; then
echo 'x - skipping main.C (File already exists)'
else
echo 'x - extracting main.C (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'main.C' &&
// Copyright (c) 1991 by Parag Patel. All Rights Reserved.
static const char rcs_id[] = "$Header: main.C,v 1.22 91/02/22 16:05:39 hmgr Exp $";
X
#include "version.C"
X
#include "defs.h"
#include "toks.h"
#include <osfcn.h>
#include <stdarg.h>
X
#ifdef BSD
#include <sys/wait.h>
#endif
X
// externs for getopt()
extern char *optarg;
extern int optind;
X
// These vars are modified from the command line
boolean optimize = TRUE;
boolean dumpcode = TRUE;
boolean statonly = FALSE;
boolean docompare = TRUE;
boolean casesensitive = FALSE;
boolean dargstyle = TRUE;
boolean genlineinfo = TRUE;
char *headername = "tokens.h";
char *scannername = "scanner.l";
char *parsername = "parser.C";
X
// just other globals here
boolean exportedname = FALSE;
X
implement_array(charbuf, char);
implement_array(charvec, char*);
X
X
static charbuf buf;
static charvec vec;
X
#define issep(c) (strchr(sep, (c)) != NULL)
#define notsep(c) (strchr(sep, (c)) == NULL)
X
char **strsep(const char *str, const char *sep, int whsp, int *retnum)
{
X buf.reset(strlen(str) + 1);
X register char *s = buf.getarr();
X strcpy(s, str);
X
X register int num = 0;
X while (*s != '\0')
X {
X if (whsp) // skip leading separators?
X while (*s != '\0' && issep(*s))
X s++;
X
X vec[num++] = s;
X
X // find next separator
X while (*s != '\0' && notsep(*s))
X s++;
X if (*s != '\0')
X *s++ = '\0';
X }
X
X vec[num] = NULL;
X
X if (retnum != NULL)
X *retnum = num;
X
X return &vec[0];
}
X
const char *
strbldf(const char *format, ...)
{
X static char buff[4][1024];
X static int curr = 0;
X if (++curr > 3)
X curr = 0;
X
X va_list ap;
X va_start(ap, format);
X vsprintf(buff[curr], (char*)format, ap);
X va_end(ap);
X return buff[curr];
}
X
X
int error(char *fmt, ...)
{
X va_list ap;
X
X w_numerrors++;
X va_start(ap, fmt);
X vfprintf(stderr, fmt, ap);
X fprintf(stderr, ".\n");
X va_end(ap);
X return RETERR;
}
X
void quit(char *fmt, ...)
{
X va_list ap;
X
X va_start(ap, fmt);
X vfprintf(stderr, fmt, ap);
X fprintf(stderr, "!\n");
X va_end(ap);
X exit(1);
}
X
X
static unsigned prime[] =
{
X 11,
X 23,
X 47,
X 97,
X 197,
X 397,
X 797,
X 1597,
X 3203,
X 6421,
X 12853,
X 25717,
X 51437,
X 102877,
X 205759,
X 411527,
X 823117,
X 1646237,
X 3292489,
X 6584983,
X 13169977,
X 26339969,
X 52679969,
X 105359939,
X 210719881,
X 421439783,
X 842879579
};
const N = sizeof prime/sizeof *prime;
X
unsigned table_bump(unsigned hs)
{
X if (hs < prime[N - 2])
X for (int i = 0; i < N; i++)
X if (prime[i] > 2 * hs)
X return prime[i];
X
X return prime[N - 1];
}
X
X
static void dumpset(Bitset &set)
{
X Bitsetiter si(set);
X symbol *s;
X int id;
X
X printf("(");
X while ((id = si()) >= 0)
X {
X if (id == END || id == EMPTY)
X continue;
X s = getsymbol(id);
X printf(" %s", s->name);
X }
X if (set.isin(EMPTY))
X printf(" []");
X else if (set.isin(END))
X printf(" $");
X printf(" )\n");
}
X
static void dump(void)
{
X symbol *sym;
X symnode *n1, *n2;
X int i;
X char *s;
X
X for (i = START; i < numsymbols(); i++)
X {
X sym = getsymbol(i);
X if (sym->type == NONTERMINAL)
X {
X if (sym->lexstr == NULL)
X printf("%s", sym->name);
X else
X printf("%s (%s)", sym->lexstr, sym->name);
X if (sym->rettype != NULL)
X printf("<%s>", sym->rettype);
X printf(" use=%d usedret=%d", sym->usecount, sym->usedret);
X if (sym->toempty)
X printf(" ==> []");
X printf("\n");
X s = "\t:";
X for (n1 = sym->node; n1 != NULL; n1 = n1->or)
X {
X for (n2 = n1; n2 != NULL; n2 = n2->next)
X {
X if (n2->sym->type == CODE)
X printf("%s {%s}\n", s, n2->sym->code);
X else
X {
X printf("%s %s[%d] = ", s, n2->sym->name,
X n2->resync->id);
X dumpset(*n2->resync->set);
X }
X s = "\t ";
X }
X s = "\t|";
X }
X printf("\t;\n");
X }
X else if (sym->type == TERMINAL)
X {
X printf("[%s]", sym->name);
X if (sym->lexstr != NULL)
X printf(" == %s", sym->lexstr);
X printf("\n");
X }
X else
X {
X printf("%s == {%s}\n", sym->name, sym->code);
X continue;
X }
X
X printf("FIRST(%s) = ", sym->name);
X dumpset(*sym->first);
X
X printf("FOLLOW(%s) = ", sym->name);
X dumpset(*sym->follow);
X
X if (sym->resync != NULL)
X {
X printf("SKIP-SET(%s[%d]) = ", sym->name, sym->resync->id);
X dumpset(*sym->resync->set);
X }
X
X printf("\n");
X }
}
X
X
static char *tmpname = ".wacco.tmp";
X
FILE *makefile(char *fname)
{
X if (docompare)
X fname = tmpname;
X FILE *fp = fopen(fname, "w");
X if (fp == NULL)
X quit("Cannot open %s for writing!", fname);
X return fp;
}
X
void cmpandmv(char *file)
{
X if (!docompare)
X return;
X
#ifdef BSD
X int pid = fork();
#else
X pid_t pid = fork();
#endif
X if (pid == 0)
X {
X execlp("cmp", "cmp", "-s", file, tmpname, NULL);
X exit(-1);
X }
X
#ifdef BSD
X union wait stat;
X int w;
#else
X int stat;
X pid_t w;
#endif
X do
X w = wait(&stat);
X while (w != pid && w >= 0);
X
#ifdef BSD
X if (stat.w_termsig == 0 && stat.w_retcode == 0)
X return;
#else
X if (stat == 0)
X return;
#endif
X
X unlink(file);
X if (link(tmpname, file) < 0)
X quit("Cannot link %s to %s", tmpname, file);
X unlink(tmpname);
}
X
X
void getoptions(int argc, char *argv[])
{
X int opt;
X
X while ((opt = getopt(argc, argv, "dciah:s:p:OCL")) != EOF)
X switch (opt)
X {
X Case 'd':
X statonly = TRUE;
X
X Case 'c':
X docompare = FALSE;
X
X Case 'i':
X casesensitive = TRUE;
X
X Case 'a':
X dargstyle = FALSE;
X
X Case 'h':
X headername = strdup(optarg);
X
X Case 's':
X scannername = strdup(optarg);
X
X Case 'p':
X parsername = strdup(optarg);
X
X Case 'O':
X optimize = FALSE;
X
X Case 'C':
X dumpcode = FALSE;
X
X Case 'L':
X genlineinfo = FALSE;
X
X Default:
X quit(
"Usage: %s [-dlciOCL] [-h header] [-p parser] [-s scanner] [file]", argv[0]);
X }
}
X
X
int main(int argc, char *argv[])
{
X getoptions(argc, argv);
X
X initsym();
X
X char *infile = NULL;
X FILE *fp = stdin;
X if (optind < argc)
X {
X fp = fopen(infile = argv[optind], "r");
X if (fp == NULL)
X quit("Cannot open file %s for reading", argv[optind]);
X }
X w_setfile(fp);
X
X if (!program())
X return 1;
X
X if (startsymbol == NULL && !exportedname)
X quit("No start symbol defined");
X
X buildsets();
X check();
X
X if (w_numerrors > 0)
X quit("Not generating any w_output files");
X
X if (statonly)
X {
X dump();
X return 0;
X }
X
X gencode(infile);
X if (docompare)
X unlink(tmpname);
X return 0;
}
SHAR_EOF
chmod 0444 main.C ||
echo 'restore of main.C failed'
Wc_c="`wc -c < 'main.C'`"
test 6362 -eq "$Wc_c" ||
echo 'main.C: original size 6362, current size' "$Wc_c"
fi
# ============= sym.C ==============
if test -f 'sym.C' -a X"$1" != X"-c"; then
echo 'x - skipping sym.C (File already exists)'
else
echo 'x - extracting sym.C (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'sym.C' &&
// Copyright (c) 1991 by Parag Patel. All Rights Reserved.
static const char rcs_id[] = "$Header: sym.C,v 1.14 91/02/22 16:06:42 hmgr Exp $";
X
#include "defs.h"
#ifdef BSD
# define BITSPERBYTE 8
# define BITS(type) (BITSPERBYTE * (int)sizeof(type))
#else
# include <values.h>
#endif
X
inline static unsigned sethash(Bitset *key)
{
X return key->hash();
}
X
// This is from the "dragon" Compilers book.
// It is much better than the above but somewhat slower.
//
static unsigned strhash(register const char *p)
{
X register unsigned h = 0;
X register g;
X while (*p != '\0')
X {
X h = (h << 4) + (unsigned)*p++;
X if (g = h & (0xF << BITS(unsigned) - 4))
X {
X h ^= g >> BITS(unsigned) - 4;
X h ^= g;
X }
X }
X return h;
}
X
X
typedef Bitset *Bitsetptr;
implement_table(Settab, Setiter, Set, Bitsetptr, sethash);
Settab settab;
X
X
typedef const char *charptr;
declare_table(symtab, symiter, symbol, charptr);
implement_table(symtab, symiter, symbol, charptr, strhash);
X
typedef symbol *symptr;
declare_array(symptrarr,symptr);
implement_array(symptrarr, symptr);
X
symbol *startsymbol = NULL;
symbol *startcode = NULL;
X
static symtab symlist;
static symptrarr symids, nonterms, terms;
X
X
symbol::symbol(const char *n)
{
X name = strdup(n);
X type = TERMINAL;
X
X rettype = NULL;
X lexstr = NULL; // realname
X code = NULL;
X
X usedret = 0; // lexdef, line
X
X toempty = FALSE;
X usecount = 0;
X export = FALSE;
X mkstruct = FALSE;
X
X first = new Bitset;
X follow = new Bitset;
X resync = NULL; // list
X
X node = NULL;
}
X
X
symnode::symnode()
{
X sym = NULL;
X alias = NULL;
X next = NULL;
X or = NULL;
X resync = NULL; // list
}
X
resynclist::resynclist(char *n)
{
X if (n == NULL)
X name = NULL;
X else
X name = strdup(n);
X first = follow = 0;
X paren = 0;
X next = NULL;
}
X
X
int
numsymbols()
{
X return symlist.size();
}
X
symbol *
getsymbol(int id)
{
X if (id < 0 || id >= symids.size())
X return NULL;
X return symids[id];
}
X
int
numterms()
{
X return terms.size();
}
X
int
numnonterms()
{
X return nonterms.size();
}
X
symbol *
getterm(int id)
{
X if (id < 0 || id >= terms.size())
X return NULL;
X return terms[id];
}
X
symbol *
getnonterm(int id)
{
X if (id < 0 || id >= nonterms.size())
X return NULL;
X return nonterms[id];
}
X
X
symbol *
addsymbol(const char *name)
{
X if (!symlist.insert(name))
X return &symlist();
X
X symbol & s = symlist();
X static int idnum = 0;
X s.id = idnum;
X symids[idnum++] = &s;
X s.first = new Bitset;
X s.follow = new Bitset;
X return &s;
}
X
void addterm(symbol *s)
{
X if (s == NULL)
X return;
X
X terms[s->parserid = (int)terms.size()] = s;
}
X
void addnonterm(symbol *s)
{
X if (s == NULL)
X return;
X
X nonterms[s->parserid = (int)nonterms.size()] = s;
X s->parserid = -1 - s->parserid;
X if (s->type == TERMINAL)
X {
X s->type = NONTERMINAL;
X s->realname = s->name;
X }
}
X
symbol *
findsymbol(const char *name)
{
X if (symlist.find(name))
X return &symlist();
X return NULL;
}
X
void initsym()
{
X symbol *s;
X
X s = addsymbol("$ END"); // id == 0 == END
X s = addsymbol("[]"); // id == 1 == EMPTY
}
SHAR_EOF
chmod 0444 sym.C ||
echo 'restore of sym.C failed'
Wc_c="`wc -c < 'sym.C'`"
test 3130 -eq "$Wc_c" ||
echo 'sym.C: original size 3130, current size' "$Wc_c"
fi
true || echo 'restore of parse.C failed'
echo End of part 4, continue with part 5
exit 0
exit 0 # Just in case...
--
Kent Landfield INTERNET: kent at 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 at uunet.uu.net.
More information about the Comp.sources.misc
mailing list