/* Copyright 1989 GROUPE BULL -- See license conditions in file COPYRIGHT * Copyright 1989 Massachusetts Institute of Technology */ /*********************\ * * * WOOL_OBJECT Atom * * BODY * * * \*********************/ #include "EXTERN.h" #include #include #include "wool.h" #include "wl_coll.h" #include "wl_number.h" #include "wl_list.h" #include "wl_string.h" #include "wl_pointer.h" #include "wl_active.h" #include "wl_name.h" #include "INTERN.h" #include "wl_atom.h" /* * Constructor: * Constructed via the hash table management routines. */ /* * Warning: You should NEVER call WLAtom_make, call wool_atom instead, * or your atom won't be in the hash table! */ WOOL_Atom WLAtom_make(p_name, c_val) /* makes an atom */ char *p_name; /* is COPIED to atom's p_name */ WOOL_OBJECT c_val; /* is just pointed to */ { WOOL_Quark object = (WOOL_Quark) Malloc(sizeof(struct _WOOL_Quark) + strlen(p_name)); object -> type = WLAtom; zrt_put(&(object -> type)); strcpy(object -> p_name, p_name); object -> c_val = c_val; if (c_val) increase_reference(c_val); return (WOOL_Atom) &(object -> type); } WOOL_OBJECT WLAtom_equal(a1, a2) WOOL_Atom a1, a2; { if (a2 != a1) return NIL; else if (a1 == (WOOL_Atom) NIL) return TRU; else return (WOOL_OBJECT) a1; } /************************\ * * * hash table routines * * * \************************/ /* * Hash function definition: * HASH_FUNCTION: hash function, hash = hashcode, hp = pointer on char, * hash2 = temporary for hashcode. * INITIAL_TABLE_SIZE in slots * HASH_TABLE_GROWS how hash table grows. */ /* Mock lisp function */ /* #define HASH_FUNCTION hash = (hash << 5) - hash + *hp++; #define INITIAL_HASH_SIZE 2017 #define HASH_TABLE_GROWS HashTableSize = HashTableSize * 2; */ /* aho-sethi-ullman's HPJ (sizes should be primes)*/ #define HASH_FUNCTION hash <<= 4; hash += *hp++; \ if(hash2 = hash & 0xf0000000) hash ^= (hash2 >> 24) ^ hash2; #define INITIAL_HASH_SIZE 4095 /* should be 2^n - 1 */ #define HASH_TABLE_GROWS HashTableSize = HashTableSize << 1 + 1; /* GNU emacs function */ /* #define HASH_FUNCTION hash = (hash << 3) + (hash >> 28) + *hp++; #define INITIAL_HASH_SIZE 2017 #define HASH_TABLE_GROWS HashTableSize = HashTableSize * 2; */ /* end of hash functions */ /* * The hash table is used to store atoms via their P_NAME: * * P_NAME --hash--> ATOM |--p_name--> "foo" * |--c_val--> value of the atom (result of eval) * * if c_val is UNDEFINED, symbol was undefined. If c_val is NULL, * symbol value is NIL. Parsing replaces p_names with ATOMS. */ int HashTableSize; static HashTableLimit; static HashTableUsed; static WOOL_Atom *HashTable; /* table of WLAtom objects */ /* * HashSlot gives the slot (pointer to WOOL_Atom) of a name * (slot points to NULL if it is not defined) */ WOOL_Atom * HashSlot(s) char *s; { unsigned int hash, hash2; WOOL_Atom *p; char *hp = s; char *ns; hash = 0; while (*hp) { /* computes hash function */ HASH_FUNCTION } p = HashTable + hash % HashTableSize; while (*p) { ns = (*p) -> p_name; if (ns[0] == s[0] && strcmp(ns, s) == 0) break; p--; if (p < HashTable) p = HashTable + HashTableSize - 1; } return p; } HashTableGrows() { WOOL_Atom *t, *p; int i; int OldHashTableSize = HashTableSize; t = HashTable; HASH_TABLE_GROWS HashTableLimit = HashTableSize / 3; HashTable = (WOOL_Atom *) Malloc(HashTableSize * sizeof(*HashTable)); for (p = HashTable + HashTableSize; p > HashTable;) *--p = NULL; for (i = 0; i < OldHashTableSize; i++) if (t[i]) { WOOL_Atom *ps = HashSlot(t[i] -> p_name); *ps = t[i]; } Free(t); } /* * wool_atom(name) * return an WOOL_Atom, which is the one at the slot, if present, * or is created if name didn't exist, with c_val UNDEFINED. (NULL) * This function is called by the parser for each NAME encountered. * so that the parsed expression points directly to atoms. * The reference count of the atom is set to 1. */ WOOL_Atom wool_atom(tag) char *tag; { WOOL_Atom *slot; if (HashTableUsed >= HashTableLimit) HashTableGrows(); if (!*(slot = HashSlot(tag))) { /* undefined, make a new one */ HashTableUsed++; increase_reference((*slot = WLAtom_make(tag, UNDEFINED))); } return *slot; } /* WLAtom_unbind * Removes an atom from the hash table */ WOOL_OBJECT WLAtom_unbind(obj) WOOL_Atom obj; { decrease_reference(obj -> c_val); obj -> c_val = UNDEFINED; if (obj -> reference_count == 1) decrease_reference(obj); return NIL; } /* must be called before allocating any atom */ HashTable_init() { WOOL_Atom *p; HashTableSize = INITIAL_HASH_SIZE; HashTableLimit = HashTableSize / 3; HashTable = (WOOL_Atom *) Malloc(HashTableSize * sizeof(*HashTable)); for (p = HashTable + HashTableSize; p > HashTable;) *--p = NULL; } #ifdef STATS /* * hashstats: * statistics about the hash table */ WOOL_OBJECT hashstats() { int out_of_place; wool_puts("Statistics about hash table:\n"); wool_printf(" %d slots used ", HashTableUsed); wool_printf("out of %d allocated\n", HashTableSize); out_of_place = outplacedslots(); wool_printf(" and %d slots out of place ", out_of_place); wool_printf("(%d %%)\n", (out_of_place * 100) / HashTableUsed); return NIL; } int outplacedslots() { WOOL_Atom *slot; int n = 0; for (slot = HashTable; slot < HashTable + HashTableSize; slot++) { if (*slot) { unsigned int hash, hash2; char *hp = (*slot) -> p_name; char *ns; hash = 0; while (*hp) { /* computes hash function */ HASH_FUNCTION } ns = (*(HashTable + hash % HashTableSize)) -> p_name; if (!(ns[0] == (*slot) -> p_name[0] && strcmp(ns, (*slot) -> p_name) == 0)) { n++; } } } return n; } /* * prints the whole hash table */ WOOL_OBJECT oblist() { WOOL_Atom *slot; int num = 0; for (slot = HashTable; slot < HashTable + HashTableSize; slot++) { if (*slot) { wool_printf("%s ", (*slot) -> p_name); if ((*slot) -> type == WLAtom) { if (((*slot) -> p_name[0] > ' ') && ((*slot) -> c_val)) { wool_printf("(%s): ", (((*slot) -> c_val) -> type)[0]); wool_print((*slot) -> c_val); } } else { wool_print(*slot); } num++; wool_newline(); } } return (WOOL_OBJECT) WLNumber_make(num); } #endif /* STATS */ /* * prints the names of the atoms pointing to this object (or nothing) */ print_atom_pointing_to(object) WOOL_OBJECT object; { WOOL_Atom *slot; for (slot = HashTable; slot < HashTable + HashTableSize; slot++) if (*slot) if ((*slot) -> type == WLAtom) if ((*slot) -> c_val) if ((*slot) -> c_val == object) wool_printf("%s ", (*slot) -> p_name); } #ifdef MLEAK /* * gives the atoms with prefix prefix successivly (or NULL on end); * re-initialise with a '\0' prefix */ WOOL_Atom find_next_prefixed_atom(prefix) char prefix; { WOOL_Atom *slot; static WOOL_Atom *slot0; if (prefix == '\0') { slot0 = HashTable; } else { for (slot = slot0; slot < HashTable + HashTableSize; slot++) if ((*slot) && ((*slot) -> p_name[0] == prefix) && ((*slot) -> c_val)) { slot0 = slot + 1; return (*slot); } } return NULL; } #endif /* MLEAK */ /* * XLAtom_eval: * evaluating an atom is giving a pointer to its c_val field. * an atom returns its value, or calls wool_error if undefined * (increase ref. of value) */ WOOL_OBJECT WLAtom_eval(obj) WOOL_Atom obj; { if (obj -> c_val != UNDEFINED) { return obj -> c_val; } else return wool_error(UNDEFINED_VARIABLE, obj -> p_name); } WOOL_OBJECT WLAtom_silent_eval(obj) WOOL_Atom obj; { return obj -> c_val; } /* * WLAtom_print: * printing an atom is printing the string in the p_name field. */ WOOL_OBJECT WLAtom_print(obj) WOOL_Atom obj; { wool_puts(obj -> p_name); /* perhaps () for NIL? */ return (WOOL_OBJECT) obj; } /* * WLAtom_free; * Frees the Quark of this Atom */ WOOL_OBJECT WLAtom_free(obj) WOOL_Atom obj; { WOOL_Atom *slot = HashSlot(obj -> p_name); WOOL_Atom *next_slot = slot - 1; WOOL_Atom atom; *slot = NULL; while (atom = *(next_slot = (next_slot < HashTable ? HashTable + HashTableSize - 1 : next_slot))) { *next_slot = NULL; *(HashSlot(atom -> p_name)) = atom; next_slot--; } Free((((char *) obj) - (sizeof(struct _WOOL_Quark) - sizeof(struct _WOOL_Atom)))); return NULL; } /* * WLAtom_execute: * executes the object in the C_val */ WOOL_OBJECT WLAtom_execute(obj, list) WOOL_Atom obj; WOOL_List list; { if (obj -> c_val && (obj -> c_val -> type != WLAtom)) { return WOOL_send(WOOL_execute, obj -> c_val, (obj -> c_val, list)); } else if (obj -> c_val && (obj -> c_val == NIL)) { return NIL; } else { return (wool_error(UNDEFINED_FUNCTION, obj)); } } #ifdef USER_DEBUG wool_put_spaces(n) int n; { int i; wool_printf("%d ", n); for (i = 0; i < n; i++) wool_puts(" "); } #endif /* USER_DEBUG */ /* * WLAtom_set * the normal setq routine */ WOOL_OBJECT WLAtom_set(atom, value) WOOL_Atom atom; WOOL_OBJECT value; { WOOL_OBJECT new = WOOL_send(WOOL_eval, value, (value)); decrease_reference(atom -> c_val); increase_reference(atom -> c_val = new); return new; } WOOL_OBJECT WLAtom_setq(atom, value) WOOL_Atom atom; WOOL_OBJECT value; { decrease_reference(atom -> c_val); increase_reference(atom -> c_val = value); return value; } /* * C_value of an atom: * NIL => 0 * t => 1 * oth => adress of atom itself */ int WLAtom_get_C_value(obj) WOOL_Atom obj; { if (obj == (WOOL_Atom) NIL) return 0; else if (obj == (WOOL_Atom) TRU) return 1; else return (int) obj; } void must_be_atom(atom, n) WOOL_Atom atom; int n; { if ((atom -> type != WLAtom) /* verify type of arg1 */ &&(atom -> type != WLPointer) && (atom -> type != WLActive) && (atom -> type != WLName)) bad_argument(atom, n, "symbol"); } int is_an_atom(atom) WOOL_Atom atom; { if ((atom -> type != WLAtom) /* verify type of arg1 */ &&(atom -> type != WLPointer) && (atom -> type != WLActive) && (atom -> type != WLName)) return 0; else return 1; }