347 lines
8.5 KiB
C
347 lines
8.5 KiB
C
/* symbol.c
|
|
*
|
|
* $Id$
|
|
*
|
|
* Copyright 1990, 1991, 1992, 1993, 1994, 1995, Oliver Laumann, Berlin
|
|
* Copyright 2002, 2003 Sam Hocevar <sam@zoy.org>, Paris
|
|
*
|
|
* This software was derived from Elk 1.2, which was Copyright 1987, 1988,
|
|
* 1989, Nixdorf Computer AG and TELES GmbH, Berlin (Elk 1.2 has been written
|
|
* by Oliver Laumann for TELES Telematic Services, Berlin, in a joint project
|
|
* between TELES and Nixdorf Microprocessor Engineering, Berlin).
|
|
*
|
|
* Oliver Laumann, TELES GmbH, Nixdorf Computer AG and Sam Hocevar, as co-
|
|
* owners or individual owners of copyright in this software, grant to any
|
|
* person or company a worldwide, royalty free, license to
|
|
*
|
|
* i) copy this software,
|
|
* ii) prepare derivative works based on this software,
|
|
* iii) distribute copies of this software or derivative works,
|
|
* iv) perform this software, or
|
|
* v) display this software,
|
|
*
|
|
* provided that this notice is not removed and that neither Oliver Laumann
|
|
* nor Teles nor Nixdorf are deemed to have made any representations as to
|
|
* the suitability of this software for any purpose nor are held responsible
|
|
* for any defects of this software.
|
|
*
|
|
* THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE.
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <ctype.h>
|
|
#include <string.h>
|
|
|
|
#include "kernel.h"
|
|
|
|
int Hash (char const *, int);
|
|
|
|
Object Obarray;
|
|
|
|
Object Null,
|
|
True,
|
|
False,
|
|
False2,
|
|
Unbound,
|
|
Special,
|
|
Void,
|
|
Newline,
|
|
Eof,
|
|
Zero,
|
|
One;
|
|
|
|
void Init_Symbol () {
|
|
SET(Null, T_Null, 0);
|
|
SET(True, T_Boolean, 1);
|
|
SET(False, T_Boolean, 0);
|
|
False2 = False;
|
|
SET(Unbound, T_Unbound, 0);
|
|
SET(Special, T_Special, 0);
|
|
SET(Eof, T_End_Of_File, 0);
|
|
Newline = Make_Char ('\n');
|
|
Zero = Make_Integer (0);
|
|
One = Make_Integer (1);
|
|
Obarray = Make_Vector (OBARRAY_SIZE, Null);
|
|
Global_GC_Link (Obarray);
|
|
Define_Symbol (&Void, "");
|
|
}
|
|
|
|
Object Make_Symbol (Object name) {
|
|
Object sym;
|
|
register struct S_Symbol *sp;
|
|
GC_Node;
|
|
|
|
GC_Link (name);
|
|
sym = Alloc_Object (sizeof (struct S_Symbol), T_Symbol, 0);
|
|
sp = SYMBOL(sym);
|
|
sp->name = name;
|
|
sp->value = Unbound;
|
|
sp->plist = Null;
|
|
GC_Unlink;
|
|
return sym;
|
|
}
|
|
|
|
Object P_Symbolp (Object x) {
|
|
return TYPE(x) == T_Symbol ? True : False;
|
|
}
|
|
|
|
Object P_Symbol_To_String (Object x) {
|
|
Check_Type (x, T_Symbol);
|
|
return SYMBOL(x)->name;
|
|
}
|
|
|
|
Object Obarray_Lookup (register char const *str, register int len) {
|
|
register int h;
|
|
register struct S_String *s;
|
|
register struct S_Symbol *sym;
|
|
Object p;
|
|
|
|
h = Hash (str, len) % OBARRAY_SIZE;
|
|
for (p = VECTOR(Obarray)->data[h]; !Nullp (p); p = sym->next) {
|
|
sym = SYMBOL(p);
|
|
s = STRING(sym->name);
|
|
if (s->size == len && bcmp (s->data, str, len) == 0)
|
|
return p;
|
|
}
|
|
return Make_Integer (h);
|
|
}
|
|
|
|
Object CI_Intern (char const *str) {
|
|
Object s, *p, sym, ostr;
|
|
register int len;
|
|
register char const *src;
|
|
char *dst;
|
|
char buf[128];
|
|
Alloca_Begin;
|
|
|
|
len = strlen (str);
|
|
if (len > sizeof (buf)) {
|
|
Alloca (dst, char*, len);
|
|
} else
|
|
dst = buf;
|
|
src = str;
|
|
str = dst;
|
|
for ( ; *src; src++, dst++)
|
|
*dst = isupper (*src) ? tolower (*src) : *src;
|
|
s = Obarray_Lookup (str, len);
|
|
if (TYPE(s) != T_Fixnum) {
|
|
Alloca_End;
|
|
return s;
|
|
}
|
|
ostr = Make_Const_String (str, len);
|
|
sym = Make_Symbol (ostr);
|
|
p = &VECTOR(Obarray)->data[FIXNUM(s)];
|
|
SYMBOL(sym)->next = *p;
|
|
Alloca_End;
|
|
*p = sym;
|
|
return sym;
|
|
}
|
|
|
|
Object Intern (char const *str) {
|
|
Object s, *p, sym, ostr;
|
|
register int len;
|
|
|
|
if (Case_Insensitive)
|
|
return CI_Intern (str);
|
|
len = strlen (str);
|
|
s = Obarray_Lookup (str, len);
|
|
if (TYPE(s) != T_Fixnum)
|
|
return s;
|
|
ostr = Make_Const_String (str, len);
|
|
sym = Make_Symbol (ostr);
|
|
p = &VECTOR(Obarray)->data[FIXNUM(s)];
|
|
SYMBOL(sym)->next = *p;
|
|
*p = sym;
|
|
return sym;
|
|
}
|
|
|
|
Object P_String_To_Symbol (Object str) {
|
|
Object s, *p, sym;
|
|
|
|
Check_Type (str, T_String);
|
|
s = Obarray_Lookup (STRING(str)->data, STRING(str)->size);
|
|
if (TYPE(s) != T_Fixnum)
|
|
return s;
|
|
str = Make_String (STRING(str)->data, STRING(str)->size);
|
|
sym = Make_Symbol (str);
|
|
p = &VECTOR(Obarray)->data[FIXNUM(s)];
|
|
SYMBOL(sym)->next = *p;
|
|
*p = sym;
|
|
return sym;
|
|
}
|
|
|
|
Object P_Oblist () {
|
|
register int i;
|
|
Object p, list, bucket;
|
|
GC_Node2;
|
|
|
|
p = list = Null;
|
|
GC_Link2 (p, list);
|
|
for (i = 0; i < OBARRAY_SIZE; i++) {
|
|
bucket = Null;
|
|
for (p = VECTOR(Obarray)->data[i]; !Nullp (p); p = SYMBOL(p)->next)
|
|
bucket = Cons (p, bucket);
|
|
if (!Nullp (bucket))
|
|
list = Cons (bucket, list);
|
|
}
|
|
GC_Unlink;
|
|
return list;
|
|
}
|
|
|
|
Object P_Put (int argc, Object *argv) {
|
|
Object sym, key, last, tail, prop;
|
|
GC_Node3;
|
|
|
|
sym = argv[0];
|
|
key = argv[1];
|
|
Check_Type (sym, T_Symbol);
|
|
Check_Type (key, T_Symbol);
|
|
last = Null;
|
|
for (tail = SYMBOL(sym)->plist; !Nullp (tail); tail = Cdr (tail)) {
|
|
prop = Car (tail);
|
|
if (EQ(Car (prop), key)) {
|
|
if (argc == 3)
|
|
Cdr (prop) = argv[2];
|
|
else if (Nullp (last))
|
|
SYMBOL(sym)->plist = Cdr (tail);
|
|
else
|
|
Cdr (last) = Cdr (tail);
|
|
return key;
|
|
}
|
|
last = tail;
|
|
}
|
|
if (argc == 2)
|
|
return False;
|
|
GC_Link3 (sym, last, key);
|
|
tail = Cons (key, argv[2]);
|
|
tail = Cons (tail, Null);
|
|
if (Nullp (last))
|
|
SYMBOL(sym)->plist = tail;
|
|
else
|
|
Cdr (last) = tail;
|
|
GC_Unlink;
|
|
return key;
|
|
}
|
|
|
|
Object P_Get (Object sym, Object key) {
|
|
Object prop;
|
|
|
|
Check_Type (sym, T_Symbol);
|
|
Check_Type (key, T_Symbol);
|
|
prop = Assq (key, SYMBOL(sym)->plist);
|
|
if (!Truep (prop))
|
|
return False;
|
|
/*
|
|
* Do we want to signal an error or return #f?
|
|
*
|
|
* Primitive_Error ("~s has no such property: ~s", sym, key);
|
|
*/
|
|
return Cdr (prop);
|
|
}
|
|
|
|
Object P_Symbol_Plist (Object sym) {
|
|
Check_Type (sym, T_Symbol);
|
|
return Copy_List (SYMBOL(sym)->plist);
|
|
}
|
|
|
|
int Hash (char const *str, int len) {
|
|
register int h;
|
|
register char const *p, *ep;
|
|
|
|
h = 5 * len;
|
|
if (len > 5)
|
|
len = 5;
|
|
for (p = str, ep = p+len; p < ep; ++p)
|
|
h = (h << 2) ^ *p;
|
|
return h & 017777777777;
|
|
}
|
|
|
|
void Define_Symbol (Object *sym, char const *name) {
|
|
*sym = Intern (name);
|
|
Func_Global_GC_Link (sym);
|
|
}
|
|
|
|
void Define_Variable (Object *var, char const *name, Object init) {
|
|
Object frame, sym;
|
|
GC_Node;
|
|
|
|
GC_Link (init);
|
|
sym = Intern (name);
|
|
SYMBOL(sym)->value = init;
|
|
frame = Add_Binding (Car (The_Environment), sym, init);
|
|
*var = Car (frame);
|
|
Car (The_Environment) = frame;
|
|
Func_Global_GC_Link (var);
|
|
GC_Unlink;
|
|
}
|
|
|
|
Object Var_Get (Object var) {
|
|
return Cdr (var);
|
|
}
|
|
|
|
void Var_Set (Object var, Object val) {
|
|
Cdr (var) = val;
|
|
SYMBOL (Car (var))->value = val;
|
|
}
|
|
|
|
int Var_Is_True (Object var) {
|
|
var = Var_Get (var);
|
|
return Truep (var);
|
|
}
|
|
|
|
unsigned long int Symbols_To_Bits (Object x, int mflag, SYMDESCR *stab) {
|
|
register SYMDESCR *syms;
|
|
register unsigned long int mask = 0;
|
|
Object l, s;
|
|
register char *p;
|
|
register int n;
|
|
|
|
if (!mflag) Check_Type (x, T_Symbol);
|
|
for (l = x; !Nullp (l); l = Cdr (l)) {
|
|
if (mflag) {
|
|
Check_Type (l, T_Pair);
|
|
x = Car (l);
|
|
}
|
|
Check_Type (x, T_Symbol);
|
|
s = SYMBOL(x)->name;
|
|
p = STRING(s)->data;
|
|
n = STRING(s)->size;
|
|
for (syms = stab; syms->name; syms++)
|
|
if (n && strncmp (syms->name, p, n) == 0) break;
|
|
if (syms->name == 0)
|
|
Primitive_Error ("invalid argument: ~s", x);
|
|
mask |= syms->val;
|
|
if (!mflag) break;
|
|
}
|
|
return mask;
|
|
}
|
|
|
|
Object Bits_To_Symbols (unsigned long int x, int mflag, SYMDESCR *stab) {
|
|
register SYMDESCR *syms;
|
|
Object list, tail, cell;
|
|
GC_Node2;
|
|
|
|
if (mflag) {
|
|
GC_Link2 (list, tail);
|
|
for (list = tail = Null, syms = stab; syms->name; syms++)
|
|
if ((x & syms->val) && syms->val != ~0) {
|
|
Object z;
|
|
|
|
z = Intern (syms->name);
|
|
cell = Cons (z, Null);
|
|
if (Nullp (list))
|
|
list = cell;
|
|
else
|
|
P_Set_Cdr (tail, cell);
|
|
tail = cell;
|
|
}
|
|
GC_Unlink;
|
|
return list;
|
|
}
|
|
for (syms = stab; syms->name; syms++)
|
|
if (syms->val == x)
|
|
return Intern (syms->name);
|
|
return Null;
|
|
}
|