aboutsummaryrefslogtreecommitdiff
path: root/sys/symtab
diff options
context:
space:
mode:
Diffstat (limited to 'sys/symtab')
-rw-r--r--sys/symtab/README126
-rw-r--r--sys/symtab/mkpkg30
-rw-r--r--sys/symtab/stalloc.x33
-rw-r--r--sys/symtab/stclose.x16
-rw-r--r--sys/symtab/stenter.x59
-rw-r--r--sys/symtab/stfind.x74
-rw-r--r--sys/symtab/stfindall.x81
-rw-r--r--sys/symtab/stfree.x44
-rw-r--r--sys/symtab/sthash.x37
-rw-r--r--sys/symtab/sthead.x17
-rw-r--r--sys/symtab/stinfo.x142
-rw-r--r--sys/symtab/stmark.x25
-rw-r--r--sys/symtab/stname.x15
-rw-r--r--sys/symtab/stnext.x26
-rw-r--r--sys/symtab/stnsym.x23
-rw-r--r--sys/symtab/stopen.x60
-rw-r--r--sys/symtab/stpstr.x45
-rw-r--r--sys/symtab/strefsbuf.x14
-rw-r--r--sys/symtab/strefstab.x14
-rw-r--r--sys/symtab/strestore.x69
-rw-r--r--sys/symtab/stsave.x41
-rw-r--r--sys/symtab/stsize.x21
-rw-r--r--sys/symtab/stsqueeze.x25
-rw-r--r--sys/symtab/symtab.h54
-rw-r--r--sys/symtab/zzdebug.x283
25 files changed, 1374 insertions, 0 deletions
diff --git a/sys/symtab/README b/sys/symtab/README
new file mode 100644
index 00000000..2fb705a0
--- /dev/null
+++ b/sys/symtab/README
@@ -0,0 +1,126 @@
+SYMTAB -- General package for managing symbol tables. The logical view of a
+symbol table is a collection of symbol structures. The contents of a symbol
+description structure are user defined, but the size of the structure is fixed.
+The symbol name is a character string of arbitrary size, all characters of
+which are significant. The storage semantics of the symbol table are those
+of a lifo stack, i.e., those symbols most recently defined must be the first
+deleted. There is no fixed limit on the size of a symbol table; additional
+space will be dynamically allocated at run time if necessary.
+
+
+ stp = stopen (name, len_index, len_stab, sz_sbuf)
+ stclose (stp)
+ stmark (stp, marker) # mark storage
+ stfree (stp, marker) # free to marked state
+ nsym = stnsymbols (stp, marker) # number of symbols in table
+ stinfo (stp, outfd) # print info about symbol table
+
+ sym = stenter (stp, key, symlen) # enter new symbol in table
+ sym = stfind (stp, key) # search table for symbol
+ nsym = stfindall (stp, key, sym, maxsym) # find all occurrences of symbol
+ sym = sthead (stp) # last symbol entered into table
+ sym = stnext (stp, sym) # next symbol on global list
+ charp = stname (stp, sym) # access key name string
+
+ offset = stpstr (stp, str, minchars) # put string in string buffer
+ offset = stalloc (stp, nints) # alloc space in STAB
+ charp = strefsbuf (stp, offset) # convert sbuf offset into charp
+ intp = strefstab (stp, offset) # convert stab offset into intp
+
+ stsave (stp, fd) # save symbol table in a file
+ stp = strestore (fd) # restore symbol table from file
+ stsqueeze (stp) # return unused storage
+ chars = stsize (stp) # chars req'd to store table
+
+
+The symbol table is maintained as a multi-threaded linked list. This provides
+the efficiency of a hash table plus stack like semantics for redefinitions and
+for freeing blocks of variables. There are three primary data structures
+internally, an array of pointers to the heads of the threads (the index),
+a buffer containing the list elements (the symbol table), and a string buffer.
+These data structures are dynamically allocated and will be automatically
+reallocated at runtime if overflow occurs. The number of threads is fixed at
+table open time and determines the efficiency of table lookup. The expected
+running time is O(1) for well conditioned tables, i.e., tables with a sparse
+index. The worst case running time is O(N), i.e., the same as a linear search,
+but of course the worst case is very unlikely to occur. Symbol entry and
+storage reclamation are especially efficient due to the use of a stack rather
+than a heap for symbol storage.
+
+ symtab descriptor
+ index (integer array, size fixed at open time)
+ sbuf (char array, dynamic)
+ stab (list of symstructs, dynamic)
+
+Each symbol consists of a variable size structure (symstruct) in STAB containing
+references to one or more associated strings in SBUF. A symstruct consists of
+a fixed size SYMTAB header followed by a user defined structure, the size of
+which is fixed at STENTER time. Each symstruct is linked on two lists,
+a global list and a hash list. All symstructs are linked on the global list
+which is ordered with the most recently entered symbol at the head of the list.
+For a well conditioned table each hash list will typically contain zero or one
+symbols, more when there are redefinitions or when identifiers happen to hash
+to the same thread. Often it is useful to store different types of entries
+in the same symbol table; since symstructs may vary in size this may be done
+efficiently.
+
+The STOPEN procedure is used to create a new symbol table. The 'name' argument
+may be any string and is used for documentation purposes only. The index
+length argument sets the size of the hash index which is fixed for the
+lifetime of the table. The remaining two arguments specify the amount of
+symbol table space and string storage space to be initially allocated for the
+table. The actual table may grow larger at runtime, but reallocation can be
+expensive hence it is desirable to preallocate a large space if it is known
+that the table will be large.
+
+The STMARK and STFREE procedures mark and free storage on the symbol table
+stack. All symbols defined or redefined after a call to STMARK will be deleted
+and storage freed by a call to STFREE. If a redef is freed the next most
+recent definition becomes current. STFREE returns as its function value the
+number of redefined variables uncovered by the free operation. The calling
+program must mark and free in the correct order or the symbol table may be
+trashed. The argument to STMARK is a magic integer which currently references
+a marker record in the STAB containing the information necessary to mark and
+free storage (an integer is not large enough to hold all of the necessary
+information).
+
+STENTER is used to enter a new symbol into the symbol table. If the named
+symbol is already present the new entry will nondestructively supercede the
+old, which may be recovered by a subsequent STFREE (this is especially useful
+for defining local contexts, e.g., when parsing a block structured language).
+STENTER returns a pointer to the newly allocated symbol structure. This pointer
+may be invalidated if the symbol table buffer has to be reallocated in a
+subsequent call to STENTER. STFIND searches the symbol table for the named
+key (symbol), returning a pointer to the most recently defined entry or NULL.
+Once again, this pointer may be invalidated by a subsquent call which adds
+to or removes symbols from the table. STFINDALL finds all occurrences (or
+some maximum number of occurrences), returning an array of symstruct pointers
+ordered with the most recently defined symbols at the left. STHEAD and STNEXT
+are used to scan symbols in the reverse of the order in which they were
+entered, e.g., for unkeyed symbol table searches.
+
+The symbol table uses an associated string buffer for string storage. Keys
+(symbol names) are automatically added to the string buffer by STENTER.
+The string buffer is maintained as a stack, with STMARK and STFREE marking
+and freeing storage in the string buffer as well as in the symbol table buffer.
+The user may store data in either the string buffer or the symbol table
+provided the stack semantics are observed when marking and freeing storage.
+To permit dynamic reallocation, storage is referenced by offset rather than
+by pointer. Only offsets into SBUF or STAB should be stored in symbol table
+entries. String storage is allocated in SBUF with STPSTR (which also deposits
+the string). Integer aligned storage is allocated in STAB with STALLOC.
+The offset of a string stored in SBUF may be converted to a char pointer
+with STREFSBUF. The offset of a storage area in STAB may be converted into
+an integer pointer with STREFSTAB. Pointer conversions such as these should
+not be done in the calling program since doing so requires knowledge of the
+internal SYMTAB data structures (in particular, that symbol table storage
+is contiguous).
+
+A symbol table may be saved in a binary file using STSAVE. The space which
+will be required to store the symbol table may be queried in advance with
+STSIZE. The internal SYMTAB data structures are simply appended to the file.
+The symbol table itself is not affected. A saved symbol table may be restored
+to memory with STRESTORE, which is used in place of STOPEN. The file must be
+opened and positioned to the correct offset before STRESTORE is called.
+It may be desirable to call STSQUEEZE before calling STSAVE or STSIZE,
+to minimize the file storage required to store the symbol table.
diff --git a/sys/symtab/mkpkg b/sys/symtab/mkpkg
new file mode 100644
index 00000000..7ce7d3bc
--- /dev/null
+++ b/sys/symtab/mkpkg
@@ -0,0 +1,30 @@
+# Make the SYMTAB general symbol table package.
+
+$checkout libsys.a lib$
+$update libsys.a
+$checkin libsys.a lib$
+$exit
+
+libsys.a:
+ stalloc.x symtab.h
+ stclose.x symtab.h
+ stenter.x symtab.h
+ stfind.x symtab.h
+ stfindall.x symtab.h
+ stfree.x symtab.h
+ sthash.x
+ sthead.x symtab.h
+ stinfo.x symtab.h
+ stmark.x symtab.h
+ stname.x symtab.h
+ stnext.x symtab.h
+ stnsym.x symtab.h
+ stopen.x symtab.h
+ stpstr.x symtab.h
+ strefsbuf.x symtab.h
+ strefstab.x symtab.h
+ strestore.x symtab.h
+ stsave.x symtab.h
+ stsize.x symtab.h <mii.h>
+ stsqueeze.x symtab.h
+ ;
diff --git a/sys/symtab/stalloc.x b/sys/symtab/stalloc.x
new file mode 100644
index 00000000..1300953b
--- /dev/null
+++ b/sys/symtab/stalloc.x
@@ -0,0 +1,33 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include "symtab.h"
+
+# STALLOC -- Allocate a block of double aligned storage in the symbol table.
+# Increase the size of STAB if overflow occurs.
+
+int procedure stalloc (stp, blklen)
+
+pointer stp # symtab descriptor
+int blklen # number of integer units of storage
+int offset, buflen
+
+begin
+ offset = (ST_STABOP(stp) + 1) / 2 * 2
+ buflen = ST_STABLEN(stp)
+
+ if (offset + blklen > buflen) {
+ # Overflow has occurred. Allocate a larger buffer; if overflow
+ # continues to occur the increments grow successively larger to
+ # minimize reallocation.
+
+ buflen = buflen + max (blklen, ST_STABINC(stp))
+ ST_STABINC(stp) = min (MAX_INCREMENT, ST_STABINC(stp) * INC_GROW)
+ ST_STABLEN(stp) = buflen
+ ST_STABNGROW(stp) = ST_STABNGROW(stp) + 1
+
+ call realloc (ST_STABP(stp), buflen, TY_STRUCT)
+ }
+
+ ST_STABOP(stp) = offset + ((blklen + 1) / 2 * 2)
+ return (offset)
+end
diff --git a/sys/symtab/stclose.x b/sys/symtab/stclose.x
new file mode 100644
index 00000000..dc0991ed
--- /dev/null
+++ b/sys/symtab/stclose.x
@@ -0,0 +1,16 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include "symtab.h"
+
+# STCLOSE -- Return all storage used by a symbol table.
+
+procedure stclose (stp)
+
+pointer stp # symbol table descriptor
+
+begin
+ call mfree (ST_STABP(stp), TY_STRUCT)
+ call mfree (ST_SBUFP(stp), TY_CHAR)
+ call mfree (ST_INDEX(stp), TY_INT)
+ call mfree (stp, TY_STRUCT)
+end
diff --git a/sys/symtab/stenter.x b/sys/symtab/stenter.x
new file mode 100644
index 00000000..04294c97
--- /dev/null
+++ b/sys/symtab/stenter.x
@@ -0,0 +1,59 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include "symtab.h"
+
+# STENTER -- Add a symbol to the symbol table. If the named symbol is already
+# present in the table it will be redefined until STFREE is called to return
+# the storage allocated for the current symbol. A pointer to the user part
+# of the symstruct is returned as the function value.
+
+pointer procedure stenter (stp, key, u_symlen)
+
+pointer stp # symbol table descriptor
+char key[ARB] # symbol name
+int u_symlen # length of user part of symstruct (su)
+
+long sum
+pointer el, tp
+int symlen, new_symbol, thread, ip
+int stpstr(), stalloc()
+errchk stalloc, stpstr
+
+begin
+ if (key[1] == EOS)
+ call error (1, "stenter: null key string")
+
+ # Hash the key onto a thread in the index.
+ sum = 0
+ do ip = 1, MAX_HASHCHARS {
+ if (key[ip] == EOS)
+ break
+ sum = sum + (sum + key[ip])
+ }
+
+ thread = mod (sum, ST_INDEXLEN(stp))
+ tp = ST_INDEX(stp) + thread
+
+ # Allocate space in STAB.
+ symlen = LEN_SYMSTRUCT + u_symlen
+ new_symbol = stalloc (stp, symlen)
+
+ # Initialize symstruct.
+ el = ST_STABP(stp) + new_symbol
+ E_NEXTHASH(el) = Memi[tp]
+ E_NEXTGLOB(el) = ST_LASTSYMBOL(stp)
+ E_THREAD(el) = thread
+ E_KEY(el) = stpstr (stp, key, 0)
+
+ # Set the head of thread list and the head of the global list to
+ # point to the new symbol. Flag the first key character (used to
+ # quickly determine that a key beginning with a certain character
+ # is not present in the table).
+
+ Memi[tp] = new_symbol
+ ST_LASTSYMBOL(stp) = new_symbol
+ ST_NSYMBOLS(stp) = ST_NSYMBOLS(stp) + 1
+ ST_ASCII(stp,key[1]) = 1
+
+ return (E_USERFIELDS(el))
+end
diff --git a/sys/symtab/stfind.x b/sys/symtab/stfind.x
new file mode 100644
index 00000000..5ea75f77
--- /dev/null
+++ b/sys/symtab/stfind.x
@@ -0,0 +1,74 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include "symtab.h"
+
+# STFIND -- Search the symbol table for the named key and return a pointer to
+# the symstruct or NULL. This is the main table lookup procedure. If the
+# thread is empty NULL is returned after only a hash function call. If there
+# is only one element on a thread (common for well conditioned symbol tables)
+# the expense is essentialy two traversals of the key string plus procedure
+# overhead (pointer calculations, etc.).
+
+pointer procedure stfind (stp, key)
+
+pointer stp # symbol table descriptor
+char key[ARB] # symbol name
+
+long sum
+char first_char
+int head, ip, thread
+pointer el, cp, stab, sbuf
+
+begin
+ # When a symbol is entered in the table a flag is set in the ST_ASCII
+ # array to flag that the symbol table contains at least one key
+ # beginning with that character. If the flag is not set we can thus
+ # determine very quickly that the symbol is not present. This is
+ # important for applications such as mapping identifiers for macro
+ # expansion, where most macros have upper case keys but most program
+ # identifiers have lower case keys. (Subtle note: since the first
+ # element of ST_ASCII is for ascii value 0=EOS, the following also
+ # serves to detect null keys).
+
+ if (ST_ASCII(stp,key[1]) == 0)
+ return (NULL)
+
+ # Hash the key onto a thread in the index.
+ sum = 0
+ do ip = 1, MAX_HASHCHARS {
+ if (key[ip] == EOS)
+ break
+ sum = sum + (sum + key[ip])
+ }
+
+ thread = mod (sum, ST_INDEXLEN(stp))
+ head = Memi[ST_INDEX(stp)+thread]
+
+ # If thread is not empty search down it for the named key and return
+ # the symbol pointer if found. Note that the value of the E_NEXTHASH
+ # pointer is given as an integer offset to facilitate reallocation
+ # upon overflow.
+
+ if (head != NULL) {
+ first_char = key[1]
+ sbuf = ST_SBUFP(stp)
+ stab = ST_STABP(stp)
+
+ for (el=stab+head; el > stab; el=stab+E_NEXTHASH(el)) {
+ cp = sbuf + E_KEY(el)
+ if (Memc[cp] != first_char)
+ next
+
+ # Compare target key to symbol key.
+ do ip = 1, MAX_SZKEY {
+ if (key[ip] != Memc[cp])
+ break
+ if (key[ip] == EOS)
+ return (E_USERFIELDS(el)) # found key
+ cp = cp + 1
+ }
+ }
+ }
+
+ return (NULL)
+end
diff --git a/sys/symtab/stfindall.x b/sys/symtab/stfindall.x
new file mode 100644
index 00000000..d0477c5a
--- /dev/null
+++ b/sys/symtab/stfindall.x
@@ -0,0 +1,81 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include "symtab.h"
+
+# STFINDALL -- Search the symbol table for the named key and return an array
+# of symstruct pointers to all symbols with the given key. The array is
+# ordered with the most recently entered symbols at the beginning. The number
+# of symbols found is returned as the function value.
+
+int procedure stfindall (stp, key, symbols, max_symbols)
+
+pointer stp # symbol table descriptor
+char key[ARB] # symbol name
+pointer symbols[max_symbols] # pointers to the symstructs
+int max_symbols
+
+long sum
+char first_char
+int head, ip, nsym, thread
+pointer el, cp, stab, sbuf
+
+begin
+ # When a symbol is entered in the table a flag is set in the ST_ASCII
+ # array to flag that the symbol table contains at least one key
+ # beginning with that character. If the flag is not set we can thus
+ # determine very quickly that the symbol is not present. This is
+ # important for applications such as mapping identifiers for macro
+ # expansion, where most macros have upper case keys but most program
+ # identifiers have lower case keys. (Subtle note: since the first
+ # element of ST_ASCII is for ascii value 0=EOS, the following also
+ # serves to detect null keys).
+
+ if (ST_ASCII(stp,key[1]) == 0)
+ return (NULL)
+
+ # Hash the key onto a thread in the index.
+ sum = 0
+ do ip = 1, MAX_HASHCHARS {
+ if (key[ip] == EOS)
+ break
+ sum = sum + (sum + key[ip])
+ }
+
+ thread = mod (sum, ST_INDEXLEN(stp))
+ head = Memi[ST_INDEX(stp)+thread]
+
+ # If thread is not empty search down it for the named key and return
+ # pointers to all occurrences of the symbol.
+
+ nsym = 0
+
+ if (head != NULL && max_symbols > 0) {
+ first_char = key[1]
+ sbuf = ST_SBUFP(stp)
+ stab = ST_STABP(stp)
+
+ for (el=stab+head; el > stab; el=stab+E_NEXTHASH(el)) {
+ cp = sbuf + E_KEY(el)
+ if (Memc[cp] != first_char)
+ next
+
+ # If the first character of the key matches compare the full
+ # string and output a symstruct pointer if we have a match.
+
+ do ip = 1, MAX_SZKEY {
+ if (key[ip] != Memc[cp])
+ break
+ if (key[ip] == EOS) {
+ nsym = nsym + 1
+ symbols[nsym] = E_USERFIELDS(el)
+ if (nsym >= max_symbols)
+ return (max_symbols)
+ break
+ }
+ cp = cp + 1
+ }
+ }
+ }
+
+ return (nsym)
+end
diff --git a/sys/symtab/stfree.x b/sys/symtab/stfree.x
new file mode 100644
index 00000000..1a960fe5
--- /dev/null
+++ b/sys/symtab/stfree.x
@@ -0,0 +1,44 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include "symtab.h"
+
+# STFREE -- Free storage back to the last marker. No storage is actually
+# returned to the system, rather the storage is made available for reuse
+# by SYMTAB (the stacks are pruned).
+
+procedure stfree (stp, marker)
+
+pointer stp # symtab descriptor
+int marker # magic marker
+
+int el
+pointer index, stab, ep, mp
+
+begin
+ index = ST_INDEX(stp)
+ stab = ST_STABP(stp)
+ mp = stab + marker
+ ep = NULL
+
+ # Ignore requests with out of range markers.
+ if (marker <= 0 || marker >= ST_STABOP(stp))
+ return
+
+ # Descend the global (time ordered) list, unlinking each symbol until
+ # the marker position is reached.
+
+ for (el = ST_LASTSYMBOL(stp); el > marker; el = E_NEXTGLOB(ep)) {
+ ep = stab + el
+ Memi[index+E_THREAD(ep)] = E_NEXTHASH(ep)
+ }
+
+ # Reset the stack pointers and set the head of the global list to
+ # point to the symbol immediately preceding the marker.
+
+ ST_NSYMBOLS(stp) = M_NSYMBOLS(mp)
+ ST_SBUFOP(stp) = M_SBUFOP(mp)
+ ST_STABOP(stp) = marker
+
+ if (ep != NULL)
+ ST_LASTSYMBOL(stp) = E_NEXTGLOB(ep)
+end
diff --git a/sys/symtab/sthash.x b/sys/symtab/sthash.x
new file mode 100644
index 00000000..c9cd00b9
--- /dev/null
+++ b/sys/symtab/sthash.x
@@ -0,0 +1,37 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+define MAX_HASHCHARS 18
+
+# STHASH -- Compute the hash index of a key, i.e., the index of a thread in
+# the symbol table index. Multiple keys may hash to the same thread. The
+# ideal hash function will uniformly map keys into index space, both when the
+# keys are selected randomly and when the keys form patterns, e.g., when keys
+# share a common prefix. The SYMTAB package uses a simple hash function which
+# is computed inline. The STHASH function is NOT used at present, but is
+# included in the library anyway for use in other packages and because this
+# is a slightly better (more uniform) hashing function than the simple inline
+# version used in SYMTAB.
+
+int procedure sthash (key, modulus)
+
+char key[ARB] # character string serving as a key
+int modulus # number of possible output values
+
+int i
+long sum
+int primes[MAX_HASHCHARS]
+data (primes(i),i=1,9) /101,103,107,109,113,127,131,137,139/
+data (primes(i),i=10,18) /149,151,157,163,167,173,179,181,191/
+
+begin
+ sum = 0
+
+ # Hash up to len(primes)=18 characters from the key.
+ do i = 1, MAX_HASHCHARS {
+ if (key[i] == EOS)
+ break
+ sum = sum + (key[i] * primes[i])
+ }
+
+ return (mod (sum, modulus) + 1)
+end
diff --git a/sys/symtab/sthead.x b/sys/symtab/sthead.x
new file mode 100644
index 00000000..f341c934
--- /dev/null
+++ b/sys/symtab/sthead.x
@@ -0,0 +1,17 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include "symtab.h"
+
+# STHEAD -- Return a symstruct pointer to the last symbol entered into the
+# table. The NULL pointer is returned when the symbol table is empty.
+
+pointer procedure sthead (stp)
+
+pointer stp # symtab descriptor
+
+begin
+ if (ST_LASTSYMBOL(stp) == NULL)
+ return (NULL)
+ else
+ return (E_USERFIELDS (ST_STABP(stp) + ST_LASTSYMBOL(stp)))
+end
diff --git a/sys/symtab/stinfo.x b/sys/symtab/stinfo.x
new file mode 100644
index 00000000..cbc2f441
--- /dev/null
+++ b/sys/symtab/stinfo.x
@@ -0,0 +1,142 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include "symtab.h"
+
+# STINFO -- Print interesting information on the inner workings and contents
+# of the symbol table.
+
+procedure stinfo (stp, fd, verbose)
+
+pointer stp # symtab descriptor
+int fd # output file
+int verbose # if YES, trace each thread
+
+pointer index, stab, sbuf, ep
+int keylen, min_keylen, max_keylen, nsymbols, el, i, head
+int nthreads, max_threadlen, nonnull_threads, nsym
+real sum, mean_hash_index, avg_keylen, avg_threadlen
+int strlen()
+
+begin
+ index = ST_INDEX(stp)
+ stab = ST_STABP(stp)
+ sbuf = ST_SBUFP(stp)
+
+ # Print the symbol table name.
+ ep = sbuf + ST_NAME(stp)
+ call fprintf (fd, "name: %s\n")
+ if (Memc[ep] == EOS)
+ call pargstr ("(none given)")
+ else
+ call pargstr (Memc[ep])
+
+ # Print information on memory usage.
+ call fprintf (fd,
+ "index=(%x,%d), stab=(%x,%d,%d%%), sbuf=(%x,%d,%d%%)\n")
+ call pargi (index)
+ call pargi (ST_INDEXLEN(stp))
+ call pargi (stab)
+ call pargi (ST_STABLEN(stp))
+ call pargr (ST_STABOP(stp) * 100.0 / ST_STABLEN(stp))
+ call pargi (sbuf)
+ call pargi (ST_SBUFLEN(stp))
+ call pargr (ST_SBUFOP(stp) * 100.0 / ST_SBUFLEN(stp))
+
+ call fprintf (fd,
+ "sbuf reallocated %d times, stab reallocated %d times\n")
+ call pargi (ST_SBUFNGROW(stp))
+ call pargi (ST_STABNGROW(stp))
+
+ # Scan the symbols and compute the min, max, and mean key lengths.
+ # Count the number of symbols.
+
+ min_keylen = MAX_SZKEY
+ max_keylen = 0
+ avg_keylen = 0
+ nsymbols = 0
+ sum = 0
+
+ for (el = ST_LASTSYMBOL(stp); el != NULL; el = E_NEXTGLOB(ep)) {
+ nsymbols = nsymbols + 1
+ ep = stab + el
+
+ keylen = strlen (Memc[sbuf+E_KEY(ep)])
+ min_keylen = min (min_keylen, keylen)
+ max_keylen = max (max_keylen, keylen)
+ sum = sum + keylen
+ }
+
+ if (nsymbols > 0)
+ avg_keylen = sum / nsymbols
+ else
+ min_keylen = 0
+
+ call fprintf (fd,
+ "nsymbols=%d, minkeylen=%d, maxkeylen=%d, avgkeylen=%.1f\n")
+ call pargi (nsymbols)
+ call pargi (min_keylen)
+ call pargi (max_keylen)
+ call pargr (avg_keylen)
+
+ # Scan the index and compute the number of nonnull threads, the
+ # mean and max thread lengths, and the mean hash index, which should
+ # be near the center of the index.
+
+ nthreads = ST_INDEXLEN(stp)
+ mean_hash_index = 0
+ nonnull_threads = 0
+ max_threadlen = 0
+ avg_threadlen = 0
+ sum = 0
+
+ if (verbose == YES)
+ call fprintf (fd, "----------- threads ----------\n")
+
+ do i = 1, nthreads {
+ if (verbose == YES) {
+ call fprintf (fd, "[%4d] ")
+ call pargi (i)
+ }
+
+ head = Memi[index+i-1]
+ if (head != NULL) {
+ nonnull_threads = nonnull_threads + 1
+
+ # Count the number of symbols on the thread.
+ nsym = 0
+ for (el=head; el != NULL; el=E_NEXTHASH(ep)) {
+ nsym = nsym + 1
+ ep = stab + el
+
+ if (verbose == YES) {
+ call fprintf (fd, "%s ")
+ call pargstr (Memc[sbuf+E_KEY(ep)])
+ }
+ }
+
+
+ max_threadlen = max (max_threadlen, nsym)
+ sum = sum + (nsym * i)
+ }
+
+ if (verbose == YES)
+ call fprintf (fd, "\n")
+ }
+
+ if (nonnull_threads > 0) {
+ avg_threadlen = real(nsymbols) / nonnull_threads
+ mean_hash_index = sum / nsymbols
+ }
+
+ if (verbose == YES)
+ call fprintf (fd, "---------------------\n")
+
+ call fprintf (fd,
+ "nthreads=%d, maxlen=%d, avglen=%.1f, meanindex=%.1f\n")
+ call pargi (nonnull_threads)
+ call pargi (max_threadlen)
+ call pargr (avg_threadlen)
+ call pargr (mean_hash_index)
+
+ call flush (fd)
+end
diff --git a/sys/symtab/stmark.x b/sys/symtab/stmark.x
new file mode 100644
index 00000000..1caeecb0
--- /dev/null
+++ b/sys/symtab/stmark.x
@@ -0,0 +1,25 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include "symtab.h"
+
+# STMARK -- Mark the top of the STAB and SBUF stacks so that storage may
+# later be returned with STFREE. Since two integers of storage are required
+# for the mark, the extra information is saved at the current position in STAB.
+# The location of this entry in STAB marks the position to which STAB is later
+# to be restored.
+
+procedure stmark (stp, marker)
+
+pointer stp # symtab descriptor
+int marker # magic marker
+
+pointer mp
+int stalloc()
+
+begin
+ marker = stalloc (stp, LEN_MARKER)
+ mp = ST_STABP(stp) + marker
+
+ M_SBUFOP(mp) = ST_SBUFOP(stp)
+ M_NSYMBOLS(mp) = ST_NSYMBOLS(stp)
+end
diff --git a/sys/symtab/stname.x b/sys/symtab/stname.x
new file mode 100644
index 00000000..9e10617e
--- /dev/null
+++ b/sys/symtab/stname.x
@@ -0,0 +1,15 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include "symtab.h"
+
+# STNAME -- Return a char pointer to the key string (symbol name) of a symbol
+# table entry, given a pointer to the symbol structure.
+
+pointer procedure stname (stp, sym)
+
+pointer stp # symtab descriptor
+pointer sym # pointer to 'current' symstruct
+
+begin
+ return (ST_SBUFP(stp) + E_KEY(E_BASE(sym)))
+end
diff --git a/sys/symtab/stnext.x b/sys/symtab/stnext.x
new file mode 100644
index 00000000..2304f00c
--- /dev/null
+++ b/sys/symtab/stnext.x
@@ -0,0 +1,26 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include "symtab.h"
+
+# STNEXT -- Return a symstruct pointer to the next most recently entered
+# symbol in the table, given a pointer to some symbol. Use to walk down
+# the global symbol table list in the reverse of the order in which symbols
+# were entered.
+
+pointer procedure stnext (stp, sym)
+
+pointer stp # symtab descriptor
+pointer sym # pointer to 'current' symstruct
+int el
+
+begin
+ if (sym == NULL)
+ return (NULL)
+ else {
+ el = E_NEXTGLOB (E_BASE(sym))
+ if (el == NULL)
+ return (NULL)
+ else
+ return (E_USERFIELDS (ST_STABP(stp) + el))
+ }
+end
diff --git a/sys/symtab/stnsym.x b/sys/symtab/stnsym.x
new file mode 100644
index 00000000..f3d0f8e1
--- /dev/null
+++ b/sys/symtab/stnsym.x
@@ -0,0 +1,23 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include "symtab.h"
+
+# STNSYMBOLS -- Return the number of symbols in the symbol table or in a
+# marked segment, i.e., the number of symbols added to the table since the
+# mark was made.
+
+int procedure stnsymbols (stp, marker)
+
+pointer stp # symbol table pointer
+int marker # stmark marker or 0 for entire table
+
+pointer mp
+
+begin
+ if (marker <= 0)
+ return (ST_NSYMBOLS(stp))
+ else {
+ mp = ST_STABP(stp) + marker
+ return (ST_NSYMBOLS(stp) - M_NSYMBOLS(mp))
+ }
+end
diff --git a/sys/symtab/stopen.x b/sys/symtab/stopen.x
new file mode 100644
index 00000000..ede4f727
--- /dev/null
+++ b/sys/symtab/stopen.x
@@ -0,0 +1,60 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include "symtab.h"
+
+# STOPEN -- Create and initialize a new symbol table. The size of the table
+# and the size of the hash index are user defined. Any number of symbol
+# tables may be open simultaneously. LEN_SYMBTAB is the initial length of
+# the symbol table in struct units. LEN_INDEX is the number of hash threads;
+# a good choice for this value is twice the expected number of symbols in the
+# table, but good performance can be expected even if the number of symbols
+# is several times the size of the index. The index consumes SZ_INT chars per
+# index element.
+
+pointer procedure stopen (name, len_index, len_stab, sz_sbuf)
+
+char name[ARB] # symbol table name (optional)
+int len_index # number of hash threads in index
+int len_stab # initial length of STAB
+int sz_sbuf # initial size of string buffer
+
+pointer stp
+int stpstr()
+
+begin
+ # Allocate symtab descriptor.
+ call calloc (stp, LEN_SYMTAB, TY_STRUCT)
+ ST_MAGIC(stp) = MAGIC
+
+ # Allocate index.
+ call calloc (ST_INDEX(stp), len_index, TY_INT)
+ ST_INDEXLEN(stp) = len_index
+
+ # Allocate string buffer. The first char of storage, at offset 0,
+ # is set to EOS so that offset 0 may be used to reference the null
+ # string.
+
+ call malloc (ST_SBUFP(stp), sz_sbuf, TY_CHAR)
+ ST_SBUFINC(stp) = max (1, nint (sz_sbuf * INC_START))
+ ST_SBUFLEN(stp) = sz_sbuf
+ ST_SBUFOP(stp) = 1
+ ST_SBUFNGROW(stp) = 0
+ Memc[ST_SBUFP(stp)] = EOS
+
+ # Allocate symbol table. The initial STABOP (offset into STAB) is set
+ # to 1 rather than 0 since 0 as an STAB offset is used to mark the end
+ # of a list.
+
+ call malloc (ST_STABP(stp), len_stab, TY_STRUCT)
+ ST_STABINC(stp) = max (1, nint (len_stab * INC_START))
+ ST_STABLEN(stp) = len_stab
+ ST_STABOP(stp) = 1
+ ST_STABNGROW(stp) = 0
+
+ # Save the symbol table name in the string buffer. This name is
+ # for documentation purposes only (it is printed by STINFO).
+
+ ST_NAME(stp) = stpstr (stp, name, 0)
+
+ return (stp)
+end
diff --git a/sys/symtab/stpstr.x b/sys/symtab/stpstr.x
new file mode 100644
index 00000000..2de04a60
--- /dev/null
+++ b/sys/symtab/stpstr.x
@@ -0,0 +1,45 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include "symtab.h"
+
+# STPSTR -- Append a string to the string buffer. The offset of the string
+# in the string buffer is returned as the function value. More storage is
+# allocated if we run out of room in the buffer. The number of chars of
+# storage allocated (excluding space for the EOS) is strlen(str) or MINCHARS,
+# whichever is larger. To allocate but not initialize space STR may be passed
+# as the null string. To allocate precisely the amount of space required to
+# store a string constant MINCHARS should be set to zero.
+
+int procedure stpstr (stp, str, minchars)
+
+pointer stp # symtab descriptor
+char str[ARB] # string to be moved into storage
+int minchars # minimum number of chars to reserve
+
+int offset, buflen, blklen
+int strlen()
+errchk realloc
+
+begin
+ offset = ST_SBUFOP(stp)
+ buflen = ST_SBUFLEN(stp)
+ blklen = max (strlen(str), minchars) + 1
+
+ if (offset + blklen > buflen) {
+ # Overflow has occurred. Allocate a larger buffer; if overflow
+ # continues to occur the increments grow successively larger to
+ # minimize reallocation.
+
+ buflen = buflen + max (blklen, ST_SBUFINC(stp))
+ ST_SBUFINC(stp) = min (MAX_INCREMENT, ST_SBUFINC(stp) * INC_GROW)
+ ST_SBUFLEN(stp) = buflen
+ ST_SBUFNGROW(stp) = ST_SBUFNGROW(stp) + 1
+
+ call realloc (ST_SBUFP(stp), buflen, TY_CHAR)
+ }
+
+ ST_SBUFOP(stp) = ST_SBUFOP(stp) + blklen
+ call strcpy (str, Memc[ST_SBUFP(stp)+offset], blklen)
+
+ return (offset)
+end
diff --git a/sys/symtab/strefsbuf.x b/sys/symtab/strefsbuf.x
new file mode 100644
index 00000000..d0be6437
--- /dev/null
+++ b/sys/symtab/strefsbuf.x
@@ -0,0 +1,14 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include "symtab.h"
+
+# STREFSBUF -- Convert an offset into SBUF into a pointer to char.
+
+pointer procedure strefsbuf (stp, offset)
+
+pointer stp # symtab descriptor
+int offset # offset into SBUF
+
+begin
+ return (ST_SBUFP(stp) + offset)
+end
diff --git a/sys/symtab/strefstab.x b/sys/symtab/strefstab.x
new file mode 100644
index 00000000..c55473af
--- /dev/null
+++ b/sys/symtab/strefstab.x
@@ -0,0 +1,14 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include "symtab.h"
+
+# STREFSTAB -- Convert an offset into STAB into a pointer to int.
+
+pointer procedure strefstab (stp, offset)
+
+pointer stp # symtab descriptor
+int offset # offset into STAB
+
+begin
+ return (ST_STABP(stp) + offset)
+end
diff --git a/sys/symtab/strestore.x b/sys/symtab/strestore.x
new file mode 100644
index 00000000..b3989d2b
--- /dev/null
+++ b/sys/symtab/strestore.x
@@ -0,0 +1,69 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include "symtab.h"
+
+# STRESTORE -- Restore to memory a symbol table previously saved in a file
+# with STSAVE. The file must be positioned to the correct offset before
+# we are called. STRESTORE is called in place of STOPEN and returns a
+# symtab descriptor pointer as the function value. The symbol table is
+# restored to exactly the state it was in when STSAVE was called. Note
+# that since SYMTAB symbol tables use only relative offsets internally,
+# the data structures may be relocated anywhere in memory when they are
+# read back from the file. The symbol table is stored externally in a
+# machine independent binary file.
+
+pointer procedure strestore (fd)
+
+int fd # file from which symbol table is to be read
+
+int nelem
+pointer stp, stab, sbuf, index
+int miireadc(), miireadi()
+errchk miireadc, miireadi
+define readerr_ 91
+
+begin
+ index = NULL
+ stab = NULL
+ sbuf = NULL
+
+ # Read symbol table descriptor.
+ call malloc (stp, LEN_SYMTAB, TY_STRUCT)
+ if (miireadi (fd, Memi[stp], LEN_SYMTAB) < LEN_SYMTAB)
+ goto readerr_
+
+ if (ST_MAGIC(stp) != MAGIC)
+ call error (1, "strestore: bad magic in save file")
+
+ # Read the hash table index.
+ nelem = ST_INDEXLEN(stp)
+ call malloc (index, nelem, TY_INT)
+ if (miireadi (fd, Memi[index], nelem) < nelem)
+ goto readerr_
+
+ # Read the symbol table data.
+ nelem = ST_STABLEN(stp)
+ call malloc (stab, nelem, TY_STRUCT)
+ if (miireadi (fd, Memi[stab], nelem) < nelem)
+ goto readerr_
+
+ # Read the string buffer.
+ nelem = ST_SBUFLEN(stp)
+ call malloc (sbuf, nelem, TY_CHAR)
+ if (miireadc (fd, Memc[sbuf], nelem) < nelem)
+ goto readerr_
+
+ ST_INDEX(stp) = index
+ ST_SBUFP(stp) = sbuf
+ ST_STABP(stp) = stab
+
+ return (stp)
+
+readerr_
+ call mfree (sbuf, TY_CHAR)
+ call mfree (stab, TY_STRUCT)
+ call mfree (index, TY_INT)
+ call mfree (stp, TY_STRUCT)
+
+ call error (2, "strestore: unexpected EOF")
+end
diff --git a/sys/symtab/stsave.x b/sys/symtab/stsave.x
new file mode 100644
index 00000000..a77d710f
--- /dev/null
+++ b/sys/symtab/stsave.x
@@ -0,0 +1,41 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include "symtab.h"
+
+define SZ_BLOCK 2048
+
+
+# STSAVE -- Save the symbol table in an external binary file in a machine
+# independent format. This works provided only integer and character data
+# is stored in the symbol table.
+
+procedure stsave (stp, fd)
+
+pointer stp # symtab descriptor
+int fd # output file
+
+int nelem
+int ip, itop
+errchk miiwritei, miiwritec
+
+begin
+ call miiwritei (fd, Memi[stp], LEN_SYMTAB)
+ call miiwritei (fd, Memi[ST_INDEX(stp)], ST_INDEXLEN(stp))
+
+ # Since the symbol table can be very large, write it out in chunks
+ # of a reasonable size to avoid allocating large buffers.
+
+ itop = ST_STABP(stp) + ST_STABLEN(stp)
+ for (ip=ST_STABP(stp); ip < itop; ip=ip+nelem) {
+ nelem = min (SZ_BLOCK, itop - ip)
+ call miiwritei (fd, Memi[ip], nelem)
+ }
+
+ # Ditto for the string buffer.
+
+ itop = ST_SBUFP(stp) + ST_SBUFLEN(stp)
+ for (ip=ST_SBUFP(stp); ip < itop; ip=ip+nelem) {
+ nelem = min (SZ_BLOCK, itop - ip)
+ call miiwritec (fd, Memc[ip], nelem)
+ }
+end
diff --git a/sys/symtab/stsize.x b/sys/symtab/stsize.x
new file mode 100644
index 00000000..3ccc6d0d
--- /dev/null
+++ b/sys/symtab/stsize.x
@@ -0,0 +1,21 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mii.h>
+include "symtab.h"
+
+# STSIZE -- Compute the file storage space in chars required to store the
+# symbol table, e.g., in a subsequent call to STSAVE.
+
+int procedure stsize (stp)
+
+pointer stp # symbol table descriptor
+
+int size
+int miipksize()
+
+begin
+ size = miipksize (LEN_SYMTAB + ST_INDEXLEN(stp) + ST_STABLEN(stp),
+ MII_LONG) + miipksize (ST_SBUFLEN(stp), MII_BYTE)
+
+ return (size)
+end
diff --git a/sys/symtab/stsqueeze.x b/sys/symtab/stsqueeze.x
new file mode 100644
index 00000000..47f7b227
--- /dev/null
+++ b/sys/symtab/stsqueeze.x
@@ -0,0 +1,25 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include "symtab.h"
+
+# STSQUEEZE -- Return any unused storage in a symbol table. This is useful
+# when it is known that no more symbols will be entered in a table, or before
+# saving a symbol table in a save file.
+
+procedure stsqueeze (stp)
+
+pointer stp # symtab descriptor
+
+begin
+ if (ST_STABLEN(stp) > ST_STABOP(stp)) {
+ ST_STABLEN(stp) = ST_STABOP(stp)
+ ST_STABINC(stp) = min (MAX_INCREMENT, ST_STABLEN(stp))
+ call realloc (ST_STABP(stp), ST_STABLEN(stp), TY_STRUCT)
+ }
+
+ if (ST_SBUFLEN(stp) > ST_SBUFOP(stp)) {
+ ST_SBUFLEN(stp) = ST_SBUFOP(stp)
+ ST_SBUFINC(stp) = min (MAX_INCREMENT, ST_SBUFLEN(stp))
+ call realloc (ST_SBUFP(stp), ST_SBUFLEN(stp), TY_CHAR)
+ }
+end
diff --git a/sys/symtab/symtab.h b/sys/symtab/symtab.h
new file mode 100644
index 00000000..25f30ace
--- /dev/null
+++ b/sys/symtab/symtab.h
@@ -0,0 +1,54 @@
+# SYMTAB definitions.
+
+define MAX_HASHCHARS 18 # max characters used in hash function
+define SZ_ASCII 128 # max possible character values
+define INC_START 0.50 # used in overflow algorithm
+define INC_GROW 2 # growing factor for increment
+define MAX_INCREMENT 32768 # max sbuf or stab increment
+define MAX_SZKEY 256 # arbitrarily large number
+
+# Symbol table descriptor.
+
+define LEN_SYMTAB 256
+define MAGIC 0123124B
+
+define ST_MAGIC Memi[$1] # for error checking
+define ST_NAME Memi[$1+1] # optional name for symbol table
+define ST_LASTSYMBOL Memi[$1+2] # last element entered
+define ST_NSYMBOLS Memi[$1+3] # number of symbols in table
+ # (extra space)
+define ST_INDEX Memi[$1+5] # pointer to buffer of thread indices
+define ST_INDEXLEN Memi[$1+6] # length of index
+ # (extra space)
+define ST_SBUFP Memi[$1+10] # string buffer
+define ST_SBUFLEN Memi[$1+11] # current size of string buffer
+define ST_SBUFOP Memi[$1+12] # next location in string buffer
+define ST_SBUFINC Memi[$1+13] # increment if overflow occurs
+define ST_SBUFNGROW Memi[$1+14] # number of reallocs of sbuf
+ # (extra space)
+define ST_STABP Memi[$1+20] # symbol table
+define ST_STABLEN Memi[$1+21] # symbol table length
+define ST_STABOP Memi[$1+22] # next location in symbol table
+define ST_STABINC Memi[$1+23] # increment if overflow occurs
+define ST_STABNGROW Memi[$1+24] # number of reallocs of stab
+ # (extra space)
+define ST_ASCII Memi[($1+30)+$2]
+
+# Symstruct. STAB contains an array of these, each of which is linked both
+# on a thread and on the global lifo list.
+
+define LEN_SYMSTRUCT 4
+
+define E_NEXTHASH Memi[$1] # next element on thread
+define E_NEXTGLOB Memi[$1+1] # next element on global list
+define E_THREAD Memi[$1+2] # index of thread in INDEX array
+define E_KEY Memi[$1+3] # index of key name
+
+define E_USERFIELDS ($1+LEN_SYMSTRUCT)
+define E_BASE ($1-LEN_SYMSTRUCT)
+
+# Magic marker structure (for mark/free).
+
+define LEN_MARKER 2
+define M_SBUFOP Memi[$1] # saved string buffer offset
+define M_NSYMBOLS Memi[$1+1] # nsymbols in table below marker
diff --git a/sys/symtab/zzdebug.x b/sys/symtab/zzdebug.x
new file mode 100644
index 00000000..a113a4e9
--- /dev/null
+++ b/sys/symtab/zzdebug.x
@@ -0,0 +1,283 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <ctotok.h>
+include <error.h>
+include <ctype.h>
+
+task sym = t_sym
+
+define LOOKUP 1
+define ENTER 2
+define MARK 3
+define FREE 4
+define LISTALL 5
+define SQUEEZE 6
+define SAVE 7
+define RESTORE 8
+define INFO 9
+define SCANFILE 10
+define HELP 11
+
+
+# SYM -- Test symbol entry and retrieval using the SYMTAB package.
+
+procedure t_sym()
+
+bool timeit
+pointer stp, sym
+long svtime[2]
+char lbuf[SZ_LINE], key[SZ_FNAME]
+int ip, lp, stmt, marker, fd, indexlen, stablen, sbuflen, junk
+
+bool clgetb()
+int ctowrd(), strlen(), getline(), strmatch()
+int stpstr(), sthead(), stnext(), open(), clgeti()
+pointer stopen(), stfind(), stenter(), strestore()
+
+begin
+ indexlen = clgeti ("indexlen")
+ stablen = clgeti ("stablen")
+ sbuflen = clgeti ("sbuflen")
+ timeit = clgetb ("timeit")
+
+ stp = stopen ("symtab.zzdebug test symbol table",
+ indexlen, stablen, sbuflen)
+
+ repeat {
+ call printf ("* ")
+ call flush (STDOUT)
+ if (getline (STDIN, lbuf) == EOF) {
+ call printf ("\n")
+ break
+ } else if (strmatch (lbuf, "^bye") > 0)
+ break
+
+ for (ip=1; IS_WHITE(lbuf[ip]); ip=ip+1)
+ ;
+
+ # Determine type of statement.
+ switch (lbuf[ip]) {
+ case '\n':
+ next
+ case '=':
+ ip = ip + 1
+ stmt = LOOKUP
+ default:
+ if (strmatch (lbuf[ip], "^.mark") > 0) {
+ stmt = MARK
+ } else if (strmatch (lbuf[ip], "^.free") > 0) {
+ stmt = FREE
+ } else if (strmatch (lbuf[ip], "^.list") > 0) {
+ stmt = LISTALL
+ } else if (strmatch (lbuf[ip], "^.squeeze") > 0) {
+ stmt = SQUEEZE
+ } else if (strmatch (lbuf[ip], "^.save") > 0) {
+ stmt = SAVE
+ ip = ip + 5
+ } else if (strmatch (lbuf[ip], "^.restore") > 0) {
+ stmt = RESTORE
+ ip = ip + 8
+ } else if (strmatch (lbuf[ip], "^.info") > 0) {
+ stmt = INFO
+ ip = ip + 5
+ } else if (strmatch (lbuf[ip], "^.scanfile") > 0) {
+ stmt = SCANFILE
+ ip = ip + 9
+ } else if (strmatch (lbuf[ip], "^.help") > 0) {
+ stmt = HELP
+ ip = ip + 5
+ } else
+ stmt = ENTER
+ }
+
+ # Extract key name (or filename).
+ junk = ctowrd (lbuf, ip, key, SZ_FNAME)
+
+ if (timeit)
+ call sys_mtime (svtime)
+
+ switch (stmt) {
+ case LOOKUP:
+ # Lookup symbol in table.
+ sym = stfind (stp, key)
+
+ if (sym == NULL) {
+ call eprintf ("`%s' not found\n")
+ call pargstr (key)
+ next
+ }
+
+ # Print keyword = value.
+ call psym (stp, sym)
+
+ case ENTER:
+ # Enter symbol in table.
+ sym = stenter (stp, key, 1)
+
+ # Get offset of value string.
+ ip = strmatch (lbuf, "=")
+ if (ip == 0)
+ ip = strlen(lbuf) + 1
+ else {
+ while (IS_WHITE (lbuf[ip]))
+ ip = ip + 1
+ }
+
+ # Step on the newline.
+ for (lp=ip; lbuf[lp] != EOS; lp=lp+1)
+ if (lbuf[lp] == '\n') {
+ lbuf[lp] = EOS
+ break
+ }
+
+ # Deposit value string in symbol table string buffer and save
+ # offset in symstruct.
+
+ Memi[sym] = -stpstr (stp, lbuf[ip], 0)
+
+ case MARK:
+ call stmark (stp, marker)
+
+ case FREE:
+ call stfree (stp, marker)
+
+ case LISTALL:
+ for (sym=sthead(stp); sym != NULL; sym=stnext(stp,sym))
+ call psym (stp, sym)
+
+ case SQUEEZE:
+ call stsqueeze (stp)
+
+ case SAVE:
+ # In this case 'key' contains the savefile filename.
+ iferr (call delete (key))
+ ;
+ iferr (fd = open (key, NEW_FILE, BINARY_FILE)) {
+ call erract (EA_WARN)
+ next
+ }
+
+ call stsave (stp, fd)
+ call close (fd)
+
+ case RESTORE:
+ # In this case 'key' contains the savefile filename.
+
+ iferr (fd = open (key, READ_ONLY, BINARY_FILE)) {
+ call erract (EA_WARN)
+ next
+ }
+
+ call stclose (stp)
+ stp = strestore (fd)
+ call close (fd)
+
+ case INFO:
+ if (key[1] == 'v')
+ call stinfo (stp, STDOUT, YES)
+ else
+ call stinfo (stp, STDOUT, NO)
+
+ case SCANFILE:
+ call scanfile (key, stp)
+
+ case HELP:
+ call zz_help (STDOUT)
+ default:
+ call eprintf ("syntax error\n")
+ }
+
+ if (timeit)
+ call sys_ptime (STDOUT, key, svtime)
+ }
+
+ call stclose (stp)
+end
+
+
+# SCANFILE -- Scan a text file, breaking the input up into a series of tokens.
+# Place each new integer token in the symbol table. If the token is already
+# present in the table, increment its count field.
+
+procedure scanfile (fname, stp)
+
+char fname[ARB] # file to be scanned
+pointer stp # symtab descriptor
+
+char lbuf[SZ_LINE], tokbuf[SZ_FNAME]
+int fd, ip, token
+pointer sym
+int open(), getline(), ctotok()
+pointer stenter(), stfind()
+errchk open, stenter
+
+begin
+ fd = open (fname, READ_ONLY, TEXT_FILE)
+
+ while (getline (fd, lbuf) != EOF) {
+ ip = 1
+ repeat {
+ token = ctotok (lbuf, ip, tokbuf, SZ_FNAME)
+ if (token == TOK_IDENTIFIER) {
+ sym = stfind (stp, tokbuf)
+ if (sym == NULL) {
+ sym = stenter (stp, tokbuf, 1)
+ Memi[sym] = 1
+ } else
+ Memi[sym] = Memi[sym] + 1
+ }
+ } until (token == TOK_NEWLINE || token == TOK_EOS)
+ }
+
+ call close (fd)
+end
+
+
+# PSYM -- Print the name and value of a symbol in the form "key = value".
+# There are two types of values, string and count. A string operand is
+# flagged as negative.
+
+procedure psym (stp, sym)
+
+pointer stp # symtab descriptor
+pointer sym # pointer to symbol
+
+int val
+pointer vp
+pointer strefsbuf(), stname()
+
+begin
+ val = Memi[sym]
+ if (val < 0) {
+ vp = strefsbuf (stp, -val)
+ call printf ("%s = %s\n")
+ call pargstr (Memc[stname(stp,sym)])
+ call pargstr (Memc[vp])
+ } else {
+ call printf ("%s = %d\n")
+ call pargstr (Memc[stname(stp,sym)])
+ call pargi (val)
+ }
+end
+
+
+# ZZ_HELP -- Print command dictionary for interpreter.
+
+procedure zz_help (fd)
+
+int fd
+
+begin
+ call fprintf (fd, ".mark mark top of symbol table\n")
+ call fprintf (fd, ".free free back to last mark\n")
+ call fprintf (fd, ".list list all symbols in table\n")
+ call fprintf (fd, ".squeeze minimize storage\n")
+ call fprintf (fd, ".save <fname> save table in a file\n")
+ call fprintf (fd, ".restore <fname> restore table from a file\n")
+ call fprintf (fd, ".info print info on table\n")
+ call fprintf (fd, ".scanfile <fname> enter symbols from file\n")
+ call fprintf (fd, "keyword = value enter a symbol in table\n")
+ call fprintf (fd, "= keyword print value of named symbol\n")
+ call fprintf (fd, "bye exit\n")
+ call flush (fd)
+end