]> pd.if.org Git - pccts/blobdiff - support/sym/sym.c
auto commit for import
[pccts] / support / sym / sym.c
diff --git a/support/sym/sym.c b/support/sym/sym.c
new file mode 100755 (executable)
index 0000000..29340d8
--- /dev/null
@@ -0,0 +1,366 @@
+/*
+ * Simple symbol table manager using coalesced chaining to resolve collisions
+ *
+ * Doubly-linked lists are used for fast removal of entries.
+ *
+ * 'sym.h' must have a definition for typedef "Sym".  Sym must include at
+ * minimum the following fields:
+ *
+ *             ...
+ *             char *symbol;
+ *             struct ... *next, *prev, **head, *scope;
+ *             unsigned int hash;
+ *             ...
+ *
+ * 'template.h' can be used as a template to create a 'sym.h'.
+ *
+ * 'head' is &(table[hash(itself)]).
+ * The hash table is not resizable at run-time.
+ * The scope field is used to link all symbols of a current scope together.
+ * Scope() sets the current scope (linked list) to add symbols to.
+ * Any number of scopes can be handled.  The user passes the address of
+ * a pointer to a symbol table
+ * entry (INITIALIZED TO NULL first time).
+ *
+ * Available Functions:
+ *
+ *     zzs_init(s1,s2) --      Create hash table with size s1, string table size s2.
+ *     zzs_done()              --      Free hash and string table created with zzs_init().
+ *     zzs_add(key,rec)--      Add 'rec' with key 'key' to the symbol table.
+ *     zzs_newadd(key) --      create entry; add using 'key' to the symbol table.
+ *     zzs_get(key)    --      Return pointer to last record entered under 'key'
+ *                                             Else return NULL
+ *     zzs_del(p)              --      Unlink the entry associated with p.  This does
+ *                                             NOT free 'p' and DOES NOT remove it from a scope
+ *                                             list.  If it was a part of your intermediate code
+ *                                             tree or another structure.  It will still be there.
+ *                                             It is only removed from further consideration
+ *                                             by the symbol table.
+ *     zzs_keydel(s)   --      Unlink the entry associated with key s.
+ *                                             Calls zzs_del(p) to unlink.
+ *     zzs_scope(sc)   --      Specifies that everything added to the symbol
+ *                                             table with zzs_add() is added to the list (scope)
+ *                                             'sc'.  'sc' is of 'Sym **sc' type and must be
+ *                                             initialized to NULL before trying to add anything
+ *                                             to it (passing it to zzs_scope()).  Scopes can be
+ *                                         switched at any time and merely links a set of
+ *                                             symbol table entries.  If a NULL pointer is
+ *                                             passed, the current scope is returned.
+ *     zzs_rmscope(sc) --      Remove (zzs_del()) all elements of scope 'sc'
+ *                                             from the symbol table.  The entries are NOT
+ *                                             free()'d.  A pointer to the first
+ *                                             element in the "scope" is returned.  The user
+ *                                             can then manipulate the list as he/she chooses
+ *                                             (such as freeing them all). NOTE that this
+ *                                             function sets your scope pointer to NULL,
+ *                                             but returns a pointer to the list for you to use.
+ *     zzs_stat()              --      Print out the symbol table and some relevant stats.
+ *     zzs_new(key)    --      Create a new record with calloc() of type Sym.
+ *                                             Add 'key' to the string table and make the new
+ *                                             records 'symbol' pointer point to it.
+ *     zzs_strdup(s)   --      Add s to the string table and return a pointer
+ *                                             to it.  Very fast allocation routine
+ *                                             and does not require strlen() nor calloc().
+ *
+ * Example:
+ *
+ *     #include <stdio.h>
+ *     #include "sym.h"
+ *
+ *     main()
+ *     {
+ *         Sym *scope1=NULL, *scope2=NULL, *a, *p;
+ *     
+ *         zzs_init(101, 100);
+ *     
+ *         a = zzs_new("Apple");       zzs_add(a->symbol, a);  -- No scope
+ *         zzs_scope( &scope1 );       -- enter scope 1
+ *         a = zzs_new("Plum");        zzs_add(a->symbol, a);
+ *         zzs_scope( &scope2 );       -- enter scope 2
+ *         a = zzs_new("Truck");       zzs_add(a->symbol, a);
+ *     
+ *     p = zzs_get("Plum");
+ *     if ( p == NULL ) fprintf(stderr, "Hmmm...Can't find 'Plum'\n");
+ *     
+ *     p = zzs_rmscope(&scope1)
+ *     for (; p!=NULL; p=p->scope) {printf("Scope1:  %s\n", p->symbol);}
+ *     p = zzs_rmscope(&scope2)
+ *     for (; p!=NULL; p=p->scope) {printf("Scope2:  %s\n", p->symbol);}
+ * }
+ *
+ * Terence Parr
+ * Purdue University
+ * February 1990
+ *
+ * CHANGES
+ *
+ *     Terence Parr
+ *     May 1991
+ *             Renamed functions to be consistent with ANTLR
+ *             Made HASH macro
+ *             Added zzs_keydel()
+ *             Added zzs_newadd()
+ *             Fixed up zzs_stat()
+ *
+ *     July 1991
+ *             Made symbol table entry save its hash code for fast comparison
+ *                     during searching etc...
+ */
+
+#include <stdio.h>
+#if __STDC__ == 1
+#include <string.h>
+#include <stdlib.h>
+#else
+#include "malloc.h"
+#endif
+#ifdef MEMCHK
+#include "trax.h"
+#endif
+#include "sym.h"
+
+#define StrSame                0
+
+static Sym **CurScope = NULL;
+static unsigned size = 0;
+static Sym **table=NULL;
+static char *strings;
+static char *strp;
+static int strsize = 0;
+
+void
+zzs_init(sz, strs)
+int sz, strs;
+{
+       if ( sz <= 0 || strs <= 0 ) return;
+       table = (Sym **) calloc(sz, sizeof(Sym *));
+       if ( table == NULL )
+       {
+               fprintf(stderr, "Cannot allocate table of size %d\n", sz);
+               exit(1);
+       }
+       strings = (char *) calloc(strs, sizeof(char));
+       if ( strings == NULL )
+       {
+               fprintf(stderr, "Cannot allocate string table of size %d\n", strs);
+               exit(1);
+       }
+       size = sz;
+       strsize = strs;
+       strp = strings;
+}
+
+void
+zzs_done()
+{
+       if ( table != NULL ) free( table );
+       if ( strings != NULL ) free( strings );
+}
+
+void
+zzs_add(key, rec)
+char *key;
+register Sym *rec;
+{
+       register unsigned int h=0;
+       register char *p=key;
+       extern Sym *Globals;
+       
+       HASH(p, h);
+       rec->hash = h;                                  /* save hash code for fast comp later */
+       h %= size;
+       
+       if ( CurScope != NULL ) {rec->scope = *CurScope; *CurScope = rec;}
+       rec->next = table[h];                   /* Add to doubly-linked list */
+       rec->prev = NULL;
+       if ( rec->next != NULL ) (rec->next)->prev = rec;
+       table[h] = rec;
+       rec->head = &(table[h]);
+}
+
+Sym *
+zzs_get(key)
+char *key;
+{
+       register unsigned int h=0;
+       register char *p=key;
+       register Sym *q;
+       
+       HASH(p, h);
+       
+       for (q = table[h%size]; q != NULL; q = q->next)
+       {
+               if ( q->hash == h )             /* do we even have a chance of matching? */
+                       if ( strcmp(key, q->symbol) == StrSame ) return( q );
+       }
+       return( NULL );
+}
+
+/*
+ * Unlink p from the symbol table.  Hopefully, it's actually in the
+ * symbol table.
+ *
+ * If p is not part of a bucket chain of the symbol table, bad things
+ * will happen.
+ *
+ * Will do nothing if all list pointers are NULL
+ */
+void
+zzs_del(p)
+register Sym *p;
+{
+       if ( p == NULL ) {fprintf(stderr, "zzs_del(NULL)\n"); exit(1);}
+       if ( p->prev == NULL )  /* Head of list */
+       {
+               register Sym **t = p->head;
+               
+               if ( t == NULL ) return;        /* not part of symbol table */
+               (*t) = p->next;
+               if ( (*t) != NULL ) (*t)->prev = NULL;
+       }
+       else
+       {
+               (p->prev)->next = p->next;
+               if ( p->next != NULL ) (p->next)->prev = p->prev;
+       }
+       p->next = p->prev = NULL;       /* not part of symbol table anymore */
+       p->head = NULL;
+}
+
+void
+zzs_keydel(key)
+char *key;
+{
+       Sym *p = zzs_get(key);
+
+       if ( p != NULL ) zzs_del( p );
+}
+
+/* S c o p e  S t u f f */
+
+/* Set current scope to 'scope'; return current scope if 'scope' == NULL */
+Sym **
+zzs_scope(scope)
+Sym **scope;
+{
+       if ( scope == NULL ) return( CurScope );
+       CurScope = scope;
+       return( scope );
+}
+
+/* Remove a scope described by 'scope'.  Return pointer to 1st element in scope */
+Sym *
+zzs_rmscope(scope)
+register Sym **scope;
+{
+       register Sym *p;
+       Sym *start;
+
+       if ( scope == NULL ) return(NULL);
+       start = p = *scope;
+       for (; p != NULL; p=p->scope) { zzs_del( p ); }
+       *scope = NULL;
+       return( start );
+}
+
+void
+zzs_stat()
+{
+       static unsigned short count[20];
+       unsigned int i,n=0,low=0, hi=0;
+       register Sym **p;
+       float avg=0.0;
+       
+       for (i=0; i<20; i++) count[i] = 0;
+       for (p=table; p<&(table[size]); p++)
+       {
+               register Sym *q = *p;
+               unsigned int len;
+               
+               if ( q != NULL && low==0 ) low = p-table;
+               len = 0;
+               if ( q != NULL ) printf("[%d]", p-table);
+               while ( q != NULL )
+               {
+                       len++;
+                       n++;
+                       printf(" %s", q->symbol);
+                       q = q->next;
+                       if ( q == NULL ) printf("\n");
+               }
+               if ( len>=20 ) printf("zzs_stat: count table too small\n");
+               else count[len]++;
+               if ( *p != NULL ) hi = p-table;
+       }
+
+       printf("Storing %d recs used %d hash positions out of %d\n",
+                       n, size-count[0], size);
+       printf("%f %% utilization\n",
+                       ((float)(size-count[0]))/((float)size));
+       for (i=0; i<20; i++)
+       {
+               if ( count[i] != 0 )
+               {
+                       avg += (((float)(i*count[i]))/((float)n)) * i;
+                       printf("Buckets of len %d == %d (%f %% of recs)\n",
+                                       i, count[i], 100.0*((float)(i*count[i]))/((float)n));
+               }
+       }
+       printf("Avg bucket length %f\n", avg);
+       printf("Range of hash function: %d..%d\n", low, hi);
+}
+
+/*
+ * Given a string, this function allocates and returns a pointer to a
+ * symbol table record whose "symbol" pointer is reset to a position
+ * in the string table.
+ */
+Sym *
+zzs_new(text)
+char *text;
+{
+       Sym *p;
+       char *zzs_strdup();
+       
+       if ( (p = (Sym *) calloc(1,sizeof(Sym))) == 0 )
+       {
+               fprintf(stderr,"Out of memory\n");
+               exit(1);
+       }
+       p->symbol = zzs_strdup(text);
+       
+       return p;
+}
+
+/* create a new symbol table entry and add it to the symbol table */
+Sym *
+zzs_newadd(text)
+char *text;
+{
+       Sym *p = zzs_new(text);
+       if ( p != NULL ) zzs_add(text, p);
+       return p;
+}
+
+/* Add a string to the string table and return a pointer to it.
+ * Bump the pointer into the string table to next avail position.
+ */
+char *
+zzs_strdup(s)
+register char *s;
+{
+       register char *start=strp;
+
+       while ( *s != '\0' )
+       {
+               if ( strp >= &(strings[strsize-2]) )
+               {
+                       fprintf(stderr, "sym: string table overflow (%d chars)\n", strsize);
+                       exit(-1);
+               }
+               *strp++ = *s++;
+       }
+       *strp++ = '\0';
+
+       return( start );
+}