diff options
Diffstat (limited to 'sys/symtab')
-rw-r--r-- | sys/symtab/README | 126 | ||||
-rw-r--r-- | sys/symtab/mkpkg | 30 | ||||
-rw-r--r-- | sys/symtab/stalloc.x | 33 | ||||
-rw-r--r-- | sys/symtab/stclose.x | 16 | ||||
-rw-r--r-- | sys/symtab/stenter.x | 59 | ||||
-rw-r--r-- | sys/symtab/stfind.x | 74 | ||||
-rw-r--r-- | sys/symtab/stfindall.x | 81 | ||||
-rw-r--r-- | sys/symtab/stfree.x | 44 | ||||
-rw-r--r-- | sys/symtab/sthash.x | 37 | ||||
-rw-r--r-- | sys/symtab/sthead.x | 17 | ||||
-rw-r--r-- | sys/symtab/stinfo.x | 142 | ||||
-rw-r--r-- | sys/symtab/stmark.x | 25 | ||||
-rw-r--r-- | sys/symtab/stname.x | 15 | ||||
-rw-r--r-- | sys/symtab/stnext.x | 26 | ||||
-rw-r--r-- | sys/symtab/stnsym.x | 23 | ||||
-rw-r--r-- | sys/symtab/stopen.x | 60 | ||||
-rw-r--r-- | sys/symtab/stpstr.x | 45 | ||||
-rw-r--r-- | sys/symtab/strefsbuf.x | 14 | ||||
-rw-r--r-- | sys/symtab/strefstab.x | 14 | ||||
-rw-r--r-- | sys/symtab/strestore.x | 69 | ||||
-rw-r--r-- | sys/symtab/stsave.x | 41 | ||||
-rw-r--r-- | sys/symtab/stsize.x | 21 | ||||
-rw-r--r-- | sys/symtab/stsqueeze.x | 25 | ||||
-rw-r--r-- | sys/symtab/symtab.h | 54 | ||||
-rw-r--r-- | sys/symtab/zzdebug.x | 283 |
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 |