home *** CD-ROM | disk | FTP | other *** search
Text File | 1996-04-15 | 69.2 KB | 1,880 lines |
- # Listenfunktionen von CLISP
- # Bruno Haible 23.5.1995
- # Marcus Daniels 8.4.1994
-
- #include "lispbibl.c"
-
- # UP: Kopiert eine Liste
- # copy_list(list)
- # > list: Liste
- # < ergebnis: Kopie der Liste
- # kann GC auslösen
- global object copy_list (object list);
- global object copy_list(old_list)
- var reg3 object old_list;
- { # Methode: (copy-list l) = (mapcar #'identity l), mapcar vorwärts
- if (atomp(old_list))
- return old_list;
- else # Liste mit mindestens einem Element
- { var reg1 object lauf;
- pushSTACK(old_list);
- #define old_list STACK_0
- { var reg2 object new_list = allocate_cons();
- lauf = old_list; # lauf läuft durch die alte Liste durch
- #undef old_list
- Car(new_list) = Car(lauf);
- STACK_0 = new_list;
- pushSTACK(new_list);
- }
- # Schleife: STACK_1 ist die Gesamtkopie, STACK_0 = LAST davon,
- # lauf = das entsprechende Cons der Original-Liste.
- while ( lauf=Cdr(lauf), consp(lauf) )
- { # es kommt noch ein Cons
- pushSTACK(lauf); # lauf retten
- {var reg1 object new_cons = allocate_cons(); # neues Cons allozieren
- lauf = popSTACK(); # lauf zurück
- Cdr(STACK_0) = new_cons; # und als CDR des LAST einhängen
- Car(new_cons) = Car(lauf); # CAR kopieren
- STACK_0 = new_cons; # das ist nun das neue LAST
- }}
- Cdr(popSTACK()) = lauf; # selben (CDR (LAST old_list)) beibehalten
- return popSTACK();
- } }
-
- # UP: Dreht eine Liste konstruktiv um.
- # reverse(list)
- # > list: Liste (x1 ... xm)
- # < ergebnis: umgedrehte Liste (xm ... x1)
- # kann GC auslösen
- global object reverse (object list);
- global object reverse(list)
- var reg2 object list;
- { pushSTACK(list); pushSTACK(NIL);
- loop
- { # Hier ist für r=0,1,...,m
- # STACK_0 = (xr ... x1), STACK_1 = list = (xr+1 ... xm)
- if atomp(list) break;
- # Hier ist für r=1,...,m:
- # STACK_0 = (xr-1 ... x1), list = (xr ... xm)
- STACK_1 = Cdr(list);
- # Hier ist für r=1,...,m:
- # STACK_0 = (xr-1 ... x1), STACK_1 = (xr+1 ... xm)
- pushSTACK(Car(list));
- {var reg1 object new_cons = allocate_cons();
- Car(new_cons) = popSTACK(); # = xr
- Cdr(new_cons) = STACK_0; # = (xr-1 ... x1)
- STACK_0 = new_cons; # = (xr ... x1)
- }
- list = STACK_1; # list := (xr+1 ... xm)
- }
- list = popSTACK(); skipSTACK(1); return(list);
- }
- #if 0
- # andere Möglichkeit:
- global object reverse(list)
- var reg2 object list;
- { pushSTACK(list); pushSTACK(NIL);
- while (mconsp(STACK_1))
- { var reg1 object new_cons = allocate_cons();
- var reg1 object old_cons = STACK_1;
- STACK_1 = Cdr(old_cons);
- Car(new_cons) = Car(old_cons);
- Cdr(new_cons) = STACK_0;
- STACK_0 = new_cons;
- }
- list = popSTACK(); skipSTACK(1); return(list);
- }
- #endif
-
- # UP: Bestimmt die Länge einer Liste
- # llength(obj)
- # > obj: Objekt
- # < uintL ergebnis: Länge von obj, als Liste aufgefaßt
- # Testet nicht auf zyklische Listen.
- global uintL llength (object obj);
- global uintL llength(list)
- var reg1 object list;
- { var reg2 uintL count = 0;
- while (consp(list)) { count++; list=Cdr(list); }
- return count;
- }
-
- # UP: Bildet eine Liste mit genau len Elementen
- # make_list(len)
- # > (STACK): Initialisierungswert für die Elemente
- # > uintL len: gewünschte Listenlänge
- # < ergebnis: Liste mit D1.L Elementen
- # kann GC auslösen
- global object make_list (uintL len);
- global object make_list(len)
- var reg2 uintL len;
- { pushSTACK(NIL);
- dotimesL(len,len,
- { # STACK_0 = bisherige Liste, STACK_1 = Initialisierungswert
- var reg1 object new_cons = allocate_cons();
- Car(new_cons) = STACK_1; Cdr(new_cons) = STACK_0;
- STACK_0 = new_cons;
- });
- return popSTACK();
- }
-
- # UP: Dreht eine Liste destruktiv um.
- # nreverse(list)
- # > list: Liste (x1 ... xm)
- # < ergebnis: Liste (xm ... x1), EQ zur alten
- global object nreverse (object list);
- global object nreverse(list)
- var reg5 object list;
- # Methode:
- # (lambda (L)
- # (cond ((atom L) L)
- # ((atom (cdr L)) L)
- # ((atom (cddr L)) (rotatef (car L) (cadr L)) L)
- # (t (let ((L1 (cdr L)))
- # (do ((L3 L1 (cdr L3))
- # (L2 nil (rplacd L3 L2)))
- # ((atom (cdr L3))
- # (setf (cdr L) L2)
- # (setf (cdr L1) L3)
- # (rotatef (car L) (car L3))
- # ) )
- # L
- # ) ) ) )
- { if (consp(list)) # (atom L) -> L
- { var reg1 object list3 = Cdr(list); # L3 := (cdr L)
- if (consp(list3)) # (atom (cdr L)) -> L
- { if (mconsp(Cdr(list3)))
- { var reg4 object list1 = list3; # mit L1 = L3 = (cdr L)
- var reg2 object list2 = NIL; # und L2 = NIL anfangen
- do { var reg3 object h = Cdr(list3); # (cdr L3) retten,
- Cdr(list3) = list2; # durch L2 ersetzen,
- list2 = list3; # L2 := altes L3
- list3 = h; # L3 := altes (cdr L3)
- }
- while (mconsp(Cdr(list3))); # (atom (cdr L3)) -> beenden
- # L3 ist das letzte und L2 das vorletzte Listen-Cons.
- Cdr(list) = list2; # (setf (cdr L) L2)
- Cdr(list1) = list3; # (setf (cdr L1) L3)
- }
- # vertausche (car list) und (car list3):
- { var reg2 object h = Car(list);
- Car(list) = Car(list3);
- Car(list3) = h;
- } } }
- return list;
- }
-
- # UP: A0 := (nreconc A0 A1)
- # nreconc(list,obj)
- # > list: Liste
- # > obj: Objekt
- # < ergebnis: (nreconc A0 A1)
- global object nreconc (object list, object obj);
- global object nreconc(list,obj)
- var reg1 object list;
- var reg2 object obj;
- { until (atomp(list))
- { var reg3 object h = Cdr(list); # (cdr L) ist nächstes L
- Cdr(list) = obj; # (setq O (rplacd L O))
- obj = list;
- list = h;
- }
- return obj;
- }
-
- # UP: Bilde (delete obj (the list list) :test #'EQ)
- # deleteq(list,obj)
- # Entferne aus der Liste list alle Elemente, die EQ zu obj sind.
- # > obj: zu streichendes Element
- # > list: Liste
- # < ergebnis: modifizierte Liste
- global object deleteq (object list, object obj);
- global object deleteq(list,obj)
- var reg1 object list;
- var reg1 object obj;
- { var reg1 object list1 = list;
- var reg1 object list2 = list;
- loop
- { # Hier ist entweder list1=list2=list oder (cdr list1) = list2.
- if (atomp(list2)) break;
- if (eq(Car(list2),obj))
- # Streiche (car list2):
- if (eq(list2,list))
- # noch am Listenanfang
- { list2 = list1 = list = Cdr(list2); }
- else
- # weiter hinten in der Liste
- { Cdr(list1) = list2 = Cdr(list2); }
- else
- # Nichts streichen, weiterrücken:
- { list1 = list2; list2 = Cdr(list2); }
- }
- return list;
- }
-
- # UP: Liefert (car obj), mit Typprüfung
- # > subr_self: Aufrufer (ein SUBR)
- local object car (object obj);
- local object car(obj)
- var reg1 object obj;
- { if (consp(obj)) return Car(obj);
- else if (nullp(obj)) return obj;
- else fehler_list(obj);
- }
-
- # UP: Liefert (cdr obj), mit Typprüfung
- # > subr_self: Aufrufer (ein SUBR)
- local object cdr (object obj);
- local object cdr(obj)
- var reg1 object obj;
- { if (consp(obj)) return Cdr(obj);
- else if (nullp(obj)) return obj;
- else fehler_list(obj);
- }
-
- LISPFUNN(car,1) # (CAR list), CLTL S. 262
- { value1 = car(popSTACK()); mv_count=1; }
-
- LISPFUNN(cdr,1) # (CDR list), CLTL S. 262
- { value1 = cdr(popSTACK()); mv_count=1; }
-
- LISPFUNN(caar,1) # (CAAR list), CLTL S. 263
- { value1 = car(car(popSTACK())); mv_count=1; }
-
- LISPFUNN(cadr,1) # (CADR list), CLTL S. 263
- { value1 = car(cdr(popSTACK())); mv_count=1; }
-
- LISPFUNN(cdar,1) # (CDAR list), CLTL S. 263
- { value1 = cdr(car(popSTACK())); mv_count=1; }
-
- LISPFUNN(cddr,1) # (CDDR list), CLTL S. 263
- { value1 = cdr(cdr(popSTACK())); mv_count=1; }
-
- LISPFUNN(caaar,1) # (CAAAR list), CLTL S. 263
- { value1 = car(car(car(popSTACK()))); mv_count=1; }
-
- LISPFUNN(caadr,1) # (CAADR list), CLTL S. 263
- { value1 = car(car(cdr(popSTACK()))); mv_count=1; }
-
- LISPFUNN(cadar,1) # (CADAR list), CLTL S. 263
- { value1 = car(cdr(car(popSTACK()))); mv_count=1; }
-
- LISPFUNN(caddr,1) # (CADDR list), CLTL S. 263
- { value1 = car(cdr(cdr(popSTACK()))); mv_count=1; }
-
- LISPFUNN(cdaar,1) # (CDAAR list), CLTL S. 263
- { value1 = cdr(car(car(popSTACK()))); mv_count=1; }
-
- LISPFUNN(cdadr,1) # (CDADR list), CLTL S. 263
- { value1 = cdr(car(cdr(popSTACK()))); mv_count=1; }
-
- LISPFUNN(cddar,1) # (CDDAR list), CLTL S. 263
- { value1 = cdr(cdr(car(popSTACK()))); mv_count=1; }
-
- LISPFUNN(cdddr,1) # (CDDDR list), CLTL S. 263
- { value1 = cdr(cdr(cdr(popSTACK()))); mv_count=1; }
-
- LISPFUNN(caaaar,1) # (CAAAAR list), CLTL S. 263
- { value1 = car(car(car(car(popSTACK())))); mv_count=1; }
-
- LISPFUNN(caaadr,1) # (CAAADR list), CLTL S. 263
- { value1 = car(car(car(cdr(popSTACK())))); mv_count=1; }
-
- LISPFUNN(caadar,1) # (CAADAR list), CLTL S. 263
- { value1 = car(car(cdr(car(popSTACK())))); mv_count=1; }
-
- LISPFUNN(caaddr,1) # (CAADDR list), CLTL S. 263
- { value1 = car(car(cdr(cdr(popSTACK())))); mv_count=1; }
-
- LISPFUNN(cadaar,1) # (CADAAR list), CLTL S. 263
- { value1 = car(cdr(car(car(popSTACK())))); mv_count=1; }
-
- LISPFUNN(cadadr,1) # (CADADR list), CLTL S. 263
- { value1 = car(cdr(car(cdr(popSTACK())))); mv_count=1; }
-
- LISPFUNN(caddar,1) # (CADDAR list), CLTL S. 263
- { value1 = car(cdr(cdr(car(popSTACK())))); mv_count=1; }
-
- LISPFUNN(cadddr,1) # (CADDDR list), CLTL S. 263
- { value1 = car(cdr(cdr(cdr(popSTACK())))); mv_count=1; }
-
- LISPFUNN(cdaaar,1) # (CDAAAR list), CLTL S. 263
- { value1 = cdr(car(car(car(popSTACK())))); mv_count=1; }
-
- LISPFUNN(cdaadr,1) # (CDAADR list), CLTL S. 263
- { value1 = cdr(car(car(cdr(popSTACK())))); mv_count=1; }
-
- LISPFUNN(cdadar,1) # (CDADAR list), CLTL S. 263
- { value1 = cdr(car(cdr(car(popSTACK())))); mv_count=1; }
-
- LISPFUNN(cdaddr,1) # (CDADDR list), CLTL S. 263
- { value1 = cdr(car(cdr(cdr(popSTACK())))); mv_count=1; }
-
- LISPFUNN(cddaar,1) # (CDDAAR list), CLTL S. 263
- { value1 = cdr(cdr(car(car(popSTACK())))); mv_count=1; }
-
- LISPFUNN(cddadr,1) # (CDDADR list), CLTL S. 263
- { value1 = cdr(cdr(car(cdr(popSTACK())))); mv_count=1; }
-
- LISPFUNN(cdddar,1) # (CDDDAR list), CLTL S. 263
- { value1 = cdr(cdr(cdr(car(popSTACK())))); mv_count=1; }
-
- LISPFUNN(cddddr,1) # (CDDDDR list), CLTL S. 263
- { value1 = cdr(cdr(cdr(cdr(popSTACK())))); mv_count=1; }
-
- LISPFUNN(cons,2) # (CONS obj1 obj2), CLTL S. 264
- { var reg1 object new_cons = allocate_cons();
- Cdr(new_cons) = popSTACK();
- Car(new_cons) = popSTACK();
- value1 = new_cons; mv_count=1;
- }
-
- # Unterprogramm zum Ausführen des Tests :TEST
- # up2_test(stackptr,arg1,arg2)
- # > *(stackptr+1): die Testfunktion
- # > arg1,arg2: Argumente
- # < ergebnis: TRUE falls der Test erfüllt ist, FALSE sonst
- # kann GC auslösen
- local boolean up2_test (object* stackptr, object arg1, object arg2);
- local boolean up2_test(stackptr,arg1,arg2)
- var object* stackptr;
- var object arg1;
- var object arg2;
- { pushSTACK(arg1); pushSTACK(arg2); funcall(*(stackptr STACKop 1),2);
- if (nullp(value1)) return FALSE; else return TRUE;
- }
-
- # Unterprogramm zum Ausführen des Tests :TEST-NOT
- # up2_test_not(stackptr,arg1,arg2)
- # > *(stackptr+0): die Testfunktion
- # > arg1,arg2: Argumente
- # < ergebnis: TRUE falls der Test erfüllt ist, FALSE sonst
- # kann GC auslösen
- local boolean up2_test_not (object* stackptr, object arg1, object arg2);
- local boolean up2_test_not(stackptr,arg1,arg2)
- var object* stackptr;
- var object arg1;
- var object arg2;
- { pushSTACK(arg1); pushSTACK(arg2); funcall(*(stackptr STACKop 0),2);
- if (nullp(value1)) return TRUE; else return FALSE;
- }
-
- # UP: Überprüft die :TEST, :TEST-NOT - Argumente
- # test_test2_args(stackptr)
- # > stackptr: Pointer in den STACK
- # > *(stackptr+1): :TEST-Argument
- # > *(stackptr+0): :TEST-NOT-Argument
- # > subr_self: Aufrufer (ein SUBR)
- # < *(stackptr+1): verarbeitetes :TEST-Argument
- # < *(stackptr+0): verarbeitetes :TEST-NOT-Argument
- # < up2_fun: Adresse einer Testfunktion, die wie folgt spezifiziert ist:
- # > stackptr: derselbe Pointer in den Stack, arg1, arg2: Argumente
- # < TRUE, falls der Test erfüllt ist, FALSE sonst.
- # up2_function sei der Typ der Adresse einer solchen Testfunktion:
- typedef boolean (*up2_function) (object* stackptr, object arg1, object arg2);
- local up2_function test_test2_args (object* stackptr);
- local up2_function test_test2_args(stackptr)
- var reg1 object* stackptr;
- { var reg1 object test_arg = *(stackptr STACKop 1);
- if (eq(test_arg,unbound)) { test_arg=NIL; }
- # test_arg ist das :TEST-Argument
- {var reg1 object test_not_arg = *(stackptr STACKop 0);
- if (eq(test_not_arg,unbound)) { test_not_arg=NIL; }
- # test_not_arg ist das :TEST-NOT-Argument
- if (nullp(test_not_arg))
- # :TEST-NOT wurde nicht angegeben
- { if (nullp(test_arg))
- *(stackptr STACKop 1) = L(eql); # #'EQL als Default für :TEST
- return(&up2_test);
- }
- # :TEST-NOT wurde angegeben
- { if (nullp(test_arg))
- return(&up2_test_not);
- else
- fehler_both_tests();
- }} }
-
- # UP: Testet, ob zwei Bäume gleich sind.
- # tree_equal(stackptr,up2_fun,arg1,arg2)
- # > arg1,arg2: Bäume
- # > stackptr: Pointer in den Stack
- # > A5: Adresse einer Testfunktion, die arg1 und arg2 vergleicht und dabei auf
- # die :TEST/:TEST-NOT-Argumente in *(stackptr+1).L bzw.
- # *(stackprt+0).L zugreifen kann.
- # < ergebnis: TRUE, falls gleich, FALSE sonst
- # kann GC auslösen
- local boolean tree_equal (object* stackptr, up2_function up2_fun, object arg1, object arg2);
- local boolean tree_equal(stackptr,up2_fun,arg1,arg2)
- var object* stackptr;
- var up2_function up2_fun;
- var reg1 object arg1;
- var reg1 object arg2;
- { start:
- if (atomp(arg1))
- if (atomp(arg2))
- # arg1 und arg2 sind beide Atome
- return(up2_fun(stackptr,arg1,arg2));
- else
- return FALSE;
- else
- if (atomp(arg2))
- return FALSE;
- else
- # arg1 und arg2 sind beides Conses
- { check_STACK(); check_SP();
- pushSTACK(Cdr(arg1)); pushSTACK(Cdr(arg2));
- if (tree_equal(stackptr,up2_fun,Car(arg1),Car(arg2))) # rekursiv die CARs vergleichen
- # falls gleich, tail-end-rekursiv die CDRs vergleichen
- { arg2=popSTACK(); arg1=popSTACK(); goto start; }
- else
- { skipSTACK(2); return FALSE; }
- } }
-
- LISPFUN(tree_equal,2,0,norest,key,2, (kw(test),kw(test_not)) )
- # (TREE-EQUAL x y :test :test-not), CLTL S. 264
- { var reg1 object* stackptr = &STACK_0;
- var reg2 up2_function up2_fun = test_test2_args(stackptr); # :TEST/:TEST-NOT-Argumente überprüfen
- value1 = tree_equal(stackptr,up2_fun,STACK_3,STACK_2) ? T : NIL;
- mv_count=1;
- skipSTACK(4);
- }
-
- # UP: Testet auf Listenende
- # endp(obj)
- # > obj: Objekt
- # > subr_self: Aufrufer (ein SUBR)
- # < ergebnis: TRUE falls obj ein Listenende NIL ist,
- # FALSE falls obj ein Cons ist.
- local boolean endp (object obj);
- local boolean endp(obj)
- var reg1 object obj;
- { if (consp(obj)) return FALSE;
- else if (nullp(obj)) return TRUE;
- else { pushSTACK(obj); pushSTACK(TheSubr(subr_self)->name);
- //: DEUTSCH "~: Eine echte Liste darf nicht mit ~ aufhören."
- //: ENGLISH "~: A true list must not end with ~"
- //: FRANCAIS "~ : Une vraie liste ne peut pas se terminer en ~."
- fehler(error, GETTEXT("~: A true list must not end with ~"));
- } }
-
- LISPFUNN(endp,1) # (ENDP object), CLTL S. 264
- { value1 = endp(popSTACK()) ? T : NIL;
- mv_count=1;
- }
-
- LISPFUNN(list_length,1) # (LIST-LENGTH list), CLTL S. 265
- # (defun list-length (list) ; vgl. CLTL, S. 265
- # (do ((n 0 (+ n 2))
- # (fast list (cddr fast))
- # (slow list (cdr slow))
- # )
- # (nil)
- # (when (endp fast) (return n))
- # (when (endp (cdr fast)) (return (1+ n)))
- # (when (eq (cdr fast) slow) (return nil))
- # ) )
- { var reg1 object fast = popSTACK();
- var reg2 object slow = fast;
- var reg3 uintL n = 0;
- loop
- { if (endp(fast)) break;
- fast = Cdr(fast); n++;
- if (endp(fast)) break;
- if (eq(fast,slow)) # (eq (cdr fast) slow)
- { value1=NIL; mv_count=1; return; }
- fast = Cdr(fast); n++;
- slow = Cdr(slow);
- }
- value1 = fixnum(n); # n als Fixnum
- mv_count=1;
- }
-
- # Fehlermeldung für NTH und NTHCDR
- # fehler_nth()
- # > STACK_0: fehlerhafter Index
- # > subr_self: Aufrufer (ein SUBR)
- nonreturning_function(local, fehler_nth, (void));
- local void fehler_nth()
- { pushSTACK(STACK_0); # Wert für Slot DATUM von TYPE-ERROR
- pushSTACK(O(type_posfixnum)); # Wert für Slot EXPECTED-TYPE von TYPE-ERROR
- pushSTACK(STACK_(0+2));
- pushSTACK(TheSubr(subr_self)->name);
- //: DEUTSCH "~: ~ ist kein erlaubter Index, da kein Fixnum>=0."
- //: ENGLISH "~: ~ is not a nonnegative fixnum and therefore not a valid index"
- //: FRANCAIS "~ : ~, n'étant pas de type FIXNUM positif ou zéro, n'est pas un index valide."
- fehler(type_error, GETTEXT("~: ~ is not a nonnegative fixnum and therefore not a valid index"));
- }
-
- LISPFUNN(nth,2) # (NTH integer list), CLTL S. 265
- { var reg1 object list = popSTACK();
- if (mposfixnump(STACK_0)) # integer muß ein Fixnum >=0 sein
- { var reg2 uintL count = posfixnum_to_L(popSTACK()); # Wert des Fixnum
- # count mal den CDR von list nehmen:
- dotimesL(count,count, { list = cdr(list); } );
- # 1 mal den CAR nehmen:
- value1 = car(list); mv_count=1;
- }
- else
- fehler_nth();
- }
-
- LISPFUNN(first,1) # (FIRST list), CLTL S. 266
- { value1 = car(popSTACK()); mv_count=1; }
-
- LISPFUNN(second,1) # (SECOND list), CLTL S. 266
- { value1 = car(cdr(popSTACK())); mv_count=1; }
-
- LISPFUNN(third,1) # (THIRD list), CLTL S. 266
- { value1 = car(cdr(cdr(popSTACK()))); mv_count=1; }
-
- LISPFUNN(fourth,1) # (FOURTH list), CLTL S. 266
- { value1 = car(cdr(cdr(cdr(popSTACK())))); mv_count=1; }
-
- LISPFUNN(fifth,1) # (FIFTH list), CLTL S. 266
- { value1 = car(cdr(cdr(cdr(cdr(popSTACK()))))); mv_count=1; }
-
- LISPFUNN(sixth,1) # (SIXTH list), CLTL S. 266
- { value1 = car(cdr(cdr(cdr(cdr(cdr(popSTACK())))))); mv_count=1; }
-
- LISPFUNN(seventh,1) # (SEVENTH list), CLTL S. 266
- { value1 = car(cdr(cdr(cdr(cdr(cdr(cdr(popSTACK()))))))); mv_count=1; }
-
- LISPFUNN(eighth,1) # (EIGHTH list), CLTL S. 266
- { value1 = car(cdr(cdr(cdr(cdr(cdr(cdr(cdr(popSTACK())))))))); mv_count=1; }
-
- LISPFUNN(ninth,1) # (NINTH list), CLTL S. 266
- { value1 = car(cdr(cdr(cdr(cdr(cdr(cdr(cdr(cdr(popSTACK()))))))))); mv_count=1; }
-
- LISPFUNN(tenth,1) # (TENTH list), CLTL S. 266
- { value1 = car(cdr(cdr(cdr(cdr(cdr(cdr(cdr(cdr(cdr(popSTACK())))))))))); mv_count=1; }
-
- LISPFUNN(rest,1) # (REST list), CLTL S. 266
- { value1 = cdr(popSTACK()); mv_count=1; }
-
- LISPFUNN(nthcdr,2) # (NTHCDR integer list), CLTL S. 267
- { var reg1 object list = popSTACK();
- if (mposfixnump(STACK_0)) # integer muß ein Fixnum >=0 sein
- { var reg2 uintL count = posfixnum_to_L(popSTACK()); # Wert des Fixnum
- # count mal den CDR von list nehmen:
- dotimesL(count,count, { list = cdr(list); } );
- value1 = list; mv_count=1;
- }
- else
- fehler_nth();
- }
-
- # Fehlermeldung für LAST, BUTLAST und NBUTLAST
- # fehler_butlast(badindex)
- # > badindex: fehlerhaftes 2. Argument
- # > subr_self: Aufrufer (ein SUBR)
- nonreturning_function(local, fehler_butlast, (object badindex));
- local void fehler_butlast(badindex)
- var object badindex;
- { pushSTACK(badindex); # Wert für Slot DATUM von TYPE-ERROR
- pushSTACK(O(type_posinteger)); # Wert für Slot EXPECTED-TYPE von TYPE-ERROR
- pushSTACK(badindex); pushSTACK(TheSubr(subr_self)->name);
- //: DEUTSCH "~: ~ ist keine erlaubte Abschnittlänge, da kein Integer >=0."
- //: ENGLISH "~: ~ is not a nonnegative integer and therefore not a valid argument"
- //: FRANCAIS "~ : ~, n'etant pas un nombre entier positif ou zéro, ne désigne pas une bonne longueur."
- fehler(type_error, GETTEXT("~: ~ is not a nonnegative integer and therefore not a valid argument"));
- }
-
- LISPFUN(last,1,1,norest,nokey,0,NIL) # (LAST list [n]), CLtL2 S. 416-417, dpANS p. 14-34
- # (defun last (list &optional (n 1))
- # (check-type n (integer 0 *))
- # (do ((l list (cdr l))
- # (r list)
- # (i 0 (+ i 1)))
- # ((atom l) r)
- # (when (>= i n) (pop r))
- # ) )
- { var reg3 object intarg = popSTACK();
- # optionales Integer-Argument überprüfen:
- var reg2 uintL count; # Anzahl der zu kopierenden Elemente
- if (eq(intarg,unbound))
- { count = 1; }
- else
- { if (!(integerp(intarg) && positivep(intarg))) fehler_butlast(intarg);
- count = (posfixnump(intarg) ? posfixnum_to_L(intarg) : ~(uintL)0);
- }
- {var reg2 object list = popSTACK();
- # Optimierung der beiden häufigsten Fälle count=1 und count=0:
- switch (count)
- { case 0:
- while (consp(list)) { list = Cdr(list); }
- break;
- case 1:
- { var reg1 object list2;
- if (consp(list))
- { loop
- { # Hier ist list ein Cons.
- list2 = Cdr(list);
- if (atomp(list2)) break;
- list = list2;
- } }
- }
- break;
- default:
- { var reg1 object list2 = list;
- dotimespL(count,count,
- { if (atomp(list2)) goto done;
- list2 = Cdr(list2);
- });
- while (consp(list2)) { list2 = Cdr(list2); list = Cdr(list); }
- done: ;
- }
- break;
- }
- value1 = list; mv_count=1;
- }}
-
- # UP: Bildet eine Liste mit gegebenen Elementen.
- # listof(len)
- # > uintC len: gewünschte Listenlänge
- # > auf STACK: len Objekte, erstes zuoberst
- # < ergebnis: Liste dieser Objekte
- # Erhöht STACK
- # verändert STACK, kann GC auslösen
- global object listof (uintC len);
- global object listof(len)
- var reg2 uintC len;
- { pushSTACK(NIL); # bisherige Gesamtliste
- # die len Argumente vor diese Liste consen:
- dotimesC(len,len,
- { var reg1 object new_cons = allocate_cons();
- Cdr(new_cons) = popSTACK();
- Car(new_cons) = STACK_0;
- STACK_0 = new_cons;
- });
- return popSTACK();
- }
-
- LISPFUN(list,0,0,rest,nokey,0,NIL)
- # (LIST {object}), CLTL S. 267
- { pushSTACK(NIL); # bisherige Gesamtliste
- # die argcount Argumente vor diese Liste consen:
- dotimesC(argcount,argcount,
- { var reg1 object new_cons = allocate_cons();
- Cdr(new_cons) = popSTACK(); # nächstes Argument davor
- Car(new_cons) = STACK_0;
- STACK_0 = new_cons;
- });
- value1 = popSTACK(); mv_count=1;
- }
-
- LISPFUN(liststern,1,0,rest,nokey,0,NIL)
- # (LIST* obj1 {object}), CLTL S. 267
- { # bisherige Gesamtliste bereits im Stack
- # die argcount restlichen Argumente vor diese Liste consen:
- dotimesC(argcount,argcount,
- { var reg1 object new_cons = allocate_cons();
- Cdr(new_cons) = popSTACK(); # nächstes Argument davor
- Car(new_cons) = STACK_0;
- STACK_0 = new_cons;
- });
- value1 = popSTACK(); mv_count=1;
- }
-
- LISPFUN(make_list,1,0,norest,key,1, (kw(initial_element)) )
- # (MAKE-LIST size :initial-element), CLTL S. 268
- { # :initial-element überprüfen:
- if (eq(STACK_0,unbound))
- STACK_0 = NIL; # Default-Initialisierung für initial-element
- # :size überprüfen:
- if (mposfixnump(STACK_1))
- { value1 = make_list(posfixnum_to_L(STACK_1)); mv_count=1;
- skipSTACK(2);
- }
- else
- { # size in STACK_1
- pushSTACK(STACK_1); # Wert für Slot DATUM von TYPE-ERROR
- pushSTACK(O(type_posfixnum)); # Wert für Slot EXPECTED-TYPE von TYPE-ERROR
- pushSTACK(STACK_(1+2)); # size
- pushSTACK(TheSubr(subr_self)->name);
- //: DEUTSCH "~: ~ ist als Listengröße nicht geeignet, da kein Fixnum >= 0"
- //: ENGLISH "~: ~ is not a nonnegative fixnum and therefore not a valid list length"
- //: FRANCAIS "~ : ~, n'étant pas de type FIXNUM positif ou zéro, n'est pas acceptable comme longueur de liste."
- fehler(type_error, GETTEXT("~: ~ is not a nonnegative fixnum and therefore not a valid list length"));
- } }
-
- LISPFUN(append,0,0,rest,nokey,0,NIL) # (APPEND {list}), CLTL S. 268
- { if (argcount==0)
- { value1=NIL; mv_count=1; } # keine Argumente -> NIL als Ergebnis
- else
- # Argumente aneinanderhängen. Dazu Schleife argcount-1 mal durchlaufen:
- { dotimesC(argcount,argcount-1,
- # STACK_0 = bisherige Gesamtliste von rechts.
- # STACK_1 := (append STACK_1 STACK_0), STACK um 1 erhöhen:
- { var reg3 object list1;
- {var reg1 object list2 = popSTACK(); # bisherige Gesamtliste (von rechts)
- list1 = STACK_0; # vorne anzuhängendes Argument
- STACK_0 = list2; # bisherige Gesamtliste wieder stacken
- }
- # list1 muß Liste sein:
- if (atomp(list1))
- if (nullp(list1))
- ; # falls list1=NIL: (append nil x) = x, nichts tun
- else
- fehler_list(list1);
- else
- # (append list1 STACK_0), wobei list1 ein Cons ist:
- # Kopiere list1 und halte das letzte Cons fest:
- { var reg1 object lauf;
- pushSTACK(list1);
- { var reg2 object new_list = allocate_cons();
- lauf = STACK_0; # lauf läuft durch die alte Liste list1 durch
- Car(new_list) = Car(lauf);
- STACK_0 = new_list;
- pushSTACK(new_list);
- }
- # Schleife: STACK_1 ist die Gesamtkopie, STACK_0 = LAST davon,
- # lauf = das entsprechende Cons der Original-Liste list1.
- while ( lauf=Cdr(lauf), consp(lauf) )
- { # es kommt noch ein Cons
- pushSTACK(lauf); # lauf retten
- {var reg1 object new_cons = allocate_cons(); # neues Cons allozieren
- lauf = popSTACK(); # lauf zurück
- Cdr(STACK_0) = new_cons; # und als CDR des LAST einhängen
- Car(new_cons) = Car(lauf); # CAR kopieren
- STACK_0 = new_cons; # das ist nun das neue LAST
- }}
- # Kopie fertig. STACK_2 = bisherige Gesamtliste,
- # STACK_1 = Kopie von list1, STACK_0 = LAST davon.
- lauf = popSTACK(); # Ende der Kopie
- list1 = popSTACK(); # ganze Kopie
- Cdr(lauf) = STACK_0; # bisherige Gesamtkopie einhängen
- STACK_0 = list1; # und die Kopie ist die neue Gesamtliste
- }
- });
- value1 = popSTACK(); mv_count=1; # Gesamtliste als Wert
- } }
-
- LISPFUNN(copy_list,1) # (COPY-LIST list), CLTL S. 268
- { var reg1 object list = popSTACK();
- if (listp(list))
- { value1 = copy_list(list); mv_count=1; }
- else
- { fehler_list(list); }
- }
-
- # UP: Kopiert eine Aliste
- # copy_alist(alist)
- # > alist: Aliste
- # < ergebnis: Kopie der Aliste
- # kann GC auslösen
- local object copy_alist (object alist);
- # Methode:
- # Statt
- # (mapcar #'(lambda (x) (if (consp x) (cons (car x) (cdr x)) x)) l)
- # wird die Liste erst kopiert mit copy-list, dann die Top-Level-Elemente
- # der Kopie, die Conses sind, durch neue Conses mit selbem CAR und CDR
- # ersetzt.
- local object copy_alist(alist)
- var reg3 object alist;
- { alist = copy_list(alist);
- pushSTACK(alist); # Gesamtliste retten
- # alist läuft durch die Gesamtliste
- until (atomp(alist))
- { if (mconsp(Car(alist)))
- { pushSTACK(alist); # alist retten
- {var reg1 object new_cons = allocate_cons(); # neues Cons
- alist = popSTACK(); # alist zurück
- {var reg2 object old_cons = Car(alist);
- Car(new_cons) = Car(old_cons); Cdr(new_cons) = Cdr(old_cons);
- }
- Car(alist) = new_cons;
- }}
- alist = Cdr(alist);
- }
- return popSTACK();
- }
-
- LISPFUNN(copy_alist,1) # (COPY-ALIST alist), CLTL S. 268
- { value1 = copy_alist(popSTACK()); mv_count=1; }
-
- # UP: Kopiert einen Baum.
- local object copy_tree (object tree);
- local object copy_tree(tree)
- var reg2 object tree;
- { if (atomp(tree))
- return tree; # Atome unverändert zurückgeben
- else
- { check_STACK(); check_SP();
- pushSTACK(Cdr(tree)); # CDR retten
- {var reg1 object temp = copy_tree(Car(tree)); # den CAR rekursiv kopieren
- tree = STACK_0;
- STACK_0 = temp; # CAR-Kopie retten
- temp = copy_tree(tree); # den CDR rekursiv kopieren
- pushSTACK(temp); # CDR-Kopie retten
- }
- {var reg1 object new_cons = allocate_cons(); # neues Cons
- Cdr(new_cons) = popSTACK(); Car(new_cons) = popSTACK(); # füllen
- return new_cons;
- } }}
-
- LISPFUNN(copy_tree,1) # (COPY-TREE tree), CLTL S. 269
- { value1 = copy_tree(popSTACK()); mv_count=1; }
-
- LISPFUNN(revappend,2) # (REVAPPEND list object), CLTL S. 269
- { until (matomp(STACK_1))
- { var reg1 object new_cons = allocate_cons(); # neues Cons
- Car(new_cons) = Car(STACK_1); Cdr(new_cons) = STACK_0; # (cons (car list) object)
- STACK_0 = new_cons; # das ist das neue, verlängerte object
- STACK_1 = Cdr(STACK_1); # list verkürzen
- }
- value1 = popSTACK(); mv_count=1;
- skipSTACK(1);
- }
-
- LISPFUN(nconc,0,0,rest,nokey,0,NIL) # (NCONC {list}), CLTL S. 269
- { if (argcount==0)
- { value1=NIL; mv_count=1; } # keine Argumente -> NIL als Ergebnis
- else
- # Argumente aneinanderhängen. Dazu Schleife argcount-1 mal durchlaufen:
- { dotimesC(argcount,argcount-1,
- # STACK_0 = bisherige Gesamtliste von rechts.
- # STACK_1 := (nconc STACK_1 STACK_0), STACK um 1 erhöhen:
- { if (matomp(STACK_1))
- if (nullp(STACK_1))
- { STACK_1 = STACK_0; skipSTACK(1); } # Gesamtliste bleibt, Argument vergessen
- else
- fehler_list(STACK_1);
- else
- { # Gesamtliste in (cdr (last STACK_1)) einhängen:
- var reg2 object list1 = STACK_1;
- var reg1 object list2;
- loop
- { # Hier ist list1 ein Cons.
- list2 = Cdr(list1);
- if (atomp(list2)) break;
- list1 = list2;
- }
- # list1 ist das letzte Cons des Arguments STACK_1
- Cdr(list1) = popSTACK(); # bisherige Gesamtliste einhängen
- # STACK_0 = neue Gesamtliste
- }
- });
- value1 = popSTACK(); mv_count=1;
- } }
-
- LISPFUNN(nreconc,2) # (NRECONC list1 list2), CLTL S. 269
- { var reg2 object list2 = popSTACK();
- var reg1 object list1 = popSTACK();
- if (listp(list1))
- { value1 = nreconc(list1,list2); mv_count=1; }
- else
- fehler_list(list1);
- }
-
- LISPFUNN(list_nreverse,1) # (SYS::LIST-NREVERSE list)
- # wie (NREVERSE list), wenn list eine Liste ist.
- { value1 = nreverse(popSTACK()); mv_count=1; }
-
- LISPFUN(butlast,1,1,norest,nokey,0,NIL)
- # (BUTLAST list [integer]), CLTL S. 271
- { var reg2 object intarg = popSTACK();
- # optionales Integer-Argument überprüfen:
- var reg2 uintL count; # Anzahl der zu entfernenden Elemente
- if (eq(intarg,unbound))
- { count = 1; }
- else
- { if (!(integerp(intarg) && positivep(intarg))) fehler_butlast(intarg);
- count = (posfixnump(intarg) ? posfixnum_to_L(intarg) : ~(uintL)0);
- }
- {var reg2 uintL len = llength(STACK_0); # Anzahl der Elemente der Liste
- if (len<=count)
- { value1=NIL; mv_count=1; skipSTACK(1); } # Länge(list)<=count -> NIL als Wert
- else
- { var reg4 uintL new_len = len - count; # >0
- # Liefere eine Kopie der ersten new_len Conses der Liste STACK_0:
- var reg3 object new_list = make_list(new_len); # neue Liste allozieren
- # Listenelemente einzeln kopieren, bis new_list voll ist:
- var reg1 object new_lauf = new_list; # läuft durch die neue Liste
- var reg2 object old_lauf = popSTACK(); # läuft durch die alte Liste
- do { Car(new_lauf) = Car(old_lauf);
- old_lauf = Cdr(old_lauf); new_lauf = Cdr(new_lauf);
- }
- until (atomp(new_lauf));
- value1 = new_list; mv_count=1;
- }} }
-
- LISPFUN(nbutlast,1,1,norest,nokey,0,NIL)
- # (NBUTLAST list [integer]), CLTL S. 271
- { var reg2 object intarg = popSTACK();
- # optionales Integer-Argument überprüfen:
- var reg2 uintL count; # Anzahl der zu entfernenden Elemente
- if (eq(intarg,unbound))
- { count = 1; }
- else
- { if (!(integerp(intarg) && positivep(intarg))) fehler_butlast(intarg);
- count = (posfixnump(intarg) ? posfixnum_to_L(intarg) : ~(uintL)0);
- }
- {var reg2 uintL len = llength(STACK_0); # Anzahl der Elemente der Liste
- if (len<=count)
- { value1=NIL; mv_count=1; skipSTACK(1); } # Länge(list)<=count -> NIL als Wert
- else
- { var reg2 uintL new_len = len - count; # >0
- var reg1 object lauf = STACK_0; # läuft durch die Liste
- # new_len-1 mal den CDR nehmen und dann den CDR auf NIL setzen:
- dotimesL(new_len,new_len-1, { lauf = Cdr(lauf); } );
- Cdr(lauf) = NIL;
- value1 = popSTACK(); mv_count=1; # Liste als Wert
- }} }
-
- LISPFUNN(ldiff,2) # (LDIFF list sublist), CLTL S. 272
- { var reg3 object sublist = popSTACK();
- # Suche, wo sublist in list beginnt:
- var reg2 uintL new_len = 0;
- {var reg1 object listr = STACK_0;
- until (endp(listr) || eq(listr,sublist)) { listr = Cdr(listr); new_len++; }
- }
- # Liefere eine Kopie der ersten new_len Conses der Liste STACK_0:
- {var reg3 object new_list = make_list(new_len); # neue Liste allozieren
- # Listenelemente einzeln kopieren, bis new_list voll ist:
- var reg1 object new_lauf = new_list; # läuft durch die neue Liste
- var reg2 object old_lauf = popSTACK(); # läuft durch die alte Liste
- until (atomp(new_lauf))
- { Car(new_lauf) = Car(old_lauf);
- old_lauf = Cdr(old_lauf); new_lauf = Cdr(new_lauf);
- }
- value1 = new_list; mv_count=1;
- }}
-
- # Fehlermeldung für RPLACA und RPLACD u.ä.
- # fehler_cons(badobject)
- # > badobject: Nicht-Cons
- # > subr_self: Aufrufer (ein SUBR)
- nonreturning_function(local, fehler_cons, (object badobject));
- local void fehler_cons(badobject)
- object badobject;
- { pushSTACK(badobject); # Wert für Slot DATUM von TYPE-ERROR
- pushSTACK(S(cons)); # Wert für Slot EXPECTED-TYPE von TYPE-ERROR
- pushSTACK(badobject); pushSTACK(TheSubr(subr_self)->name);
- //: DEUTSCH "~: ~ ist kein Paar."
- //: ENGLISH "~: ~ is not a pair"
- //: FRANCAIS "~ : ~ n'est pas une paire."
- fehler(type_error, GETTEXT("~: ~ is not a pair"));
- }
-
- LISPFUNN(rplaca,2) # (RPLACA cons object), CLTL S. 272
- { if (matomp(STACK_1))
- fehler_cons(STACK_1);
- else
- { var reg2 object arg2 = popSTACK();
- var reg1 object arg1 = popSTACK();
- Car(arg1) = arg2;
- value1 = arg1; mv_count=1;
- } }
-
- LISPFUNN(prplaca,2) # (SYS::%RPLACA cons object)
- # Wie (RPLACA cons object), hier jedoch object als Wert
- { if (matomp(STACK_1))
- fehler_cons(STACK_1);
- else
- { var reg2 object arg2 = popSTACK();
- var reg1 object arg1 = popSTACK();
- Car(arg1) = arg2;
- value1 = arg2; mv_count=1;
- } }
-
- LISPFUNN(rplacd,2) # (RPLACD cons object), CLTL S. 272
- { if (matomp(STACK_1))
- fehler_cons(STACK_1);
- else
- { var reg2 object arg2 = popSTACK();
- var reg1 object arg1 = popSTACK();
- Cdr(arg1) = arg2;
- value1 = arg1; mv_count=1;
- } }
-
- LISPFUNN(prplacd,2) # (SYS::%RPLACD cons object)
- # Wie (RPLACD cons object), hier jedoch object als Wert
- { if (matomp(STACK_1))
- fehler_cons(STACK_1);
- else
- { var reg2 object arg2 = popSTACK();
- var reg1 object arg1 = popSTACK();
- Cdr(arg1) = arg2;
- value1 = arg2; mv_count=1;
- } }
-
- # Unterprogramm zum Ausführen des Tests :TEST
- # up_test(stackptr,x)
- # > *(stackptr+1): die Testfunktion
- # > *(stackptr+3): das zu vergleichende Item
- # > x: Argument
- # < ergebnis: TRUE falls der Test erfüllt ist, FALSE sonst
- # kann GC auslösen
- local boolean up_test (object* stackptr, object x);
- local boolean up_test(stackptr,x)
- var object* stackptr;
- var object x;
- { # nach CLTL S. 247 ein (funcall testfun item x) ausführen:
- pushSTACK(*(stackptr STACKop 3)); # item
- pushSTACK(x); # x
- funcall(*(stackptr STACKop 1),2);
- if (nullp(value1)) return FALSE; else return TRUE;
- }
-
- # Unterprogramm zum Ausführen des Tests :TEST-NOT
- # up_test_not(stackptr,x)
- # > *(stackptr+0): die Testfunktion
- # > *(stackptr+3): das zu vergleichende Item
- # > x: Argument
- # < ergebnis: TRUE falls der Test erfüllt ist, FALSE sonst
- # kann GC auslösen
- local boolean up_test_not (object* stackptr, object x);
- local boolean up_test_not(stackptr,x)
- var object* stackptr;
- var object x;
- { # nach CLTL S. 247 ein (not (funcall testfun item x)) ausführen:
- pushSTACK(*(stackptr STACKop 3)); # item
- pushSTACK(x); # x
- funcall(*(stackptr STACKop 0),2);
- if (nullp(value1)) return TRUE; else return FALSE;
- }
-
- # Unterprogramm zum Ausführen des Tests -IF
- # up_if(stackptr,x)
- # > *(stackptr+1): das Testprädikat
- # > x: Argument
- # < ergebnis: TRUE falls der Test erfüllt ist, FALSE sonst
- # kann GC auslösen
- local boolean up_if (object* stackptr, object x);
- local boolean up_if(stackptr,x)
- var object* stackptr;
- var object x;
- { # nach CLTL S. 247 ein (funcall predicate x) ausführen:
- pushSTACK(x); funcall(*(stackptr STACKop 1),1);
- if (nullp(value1)) return FALSE; else return TRUE;
- }
-
- # Unterprogramm zum Ausführen des Tests -IF-NOT
- # up_if_not(stackptr,x)
- # > *(stackptr+1): das Testprädikat
- # > x: Argument
- # < ergebnis: TRUE falls der Test erfüllt ist, FALSE sonst
- # kann GC auslösen
- local boolean up_if_not (object* stackptr, object x);
- local boolean up_if_not(stackptr,x)
- var object* stackptr;
- var object x;
- { # nach CLTL S. 247 ein (not (funcall predicate x)) ausführen:
- pushSTACK(x); funcall(*(stackptr STACKop 1),1);
- if (nullp(value1)) return TRUE; else return FALSE;
- }
-
- # UP: Überprüft das :KEY-Argument
- # test_key_arg()
- # > STACK_0: optionales Argument
- # < STACK_0: korrekte KEY-Funktion
- local void test_key_arg (void);
- local void test_key_arg()
- { var reg1 object key_arg = STACK_0;
- if (eq(key_arg,unbound) || nullp(key_arg))
- STACK_0 = L(identity); # #'IDENTITY als Default für :KEY
- }
-
- # UP: Überprüft die :TEST, :TEST-NOT - Argumente
- # test_test_args()
- # > stackptr:=&STACK_1 : Pointer in den STACK
- # > STACK_2: :TEST-Argument
- # > STACK_1: :TEST-NOT-Argument
- # > subr_self: Aufrufer (ein SUBR)
- # < STACK_2: verarbeitetes :TEST-Argument
- # < STACK_1: verarbeitetes :TEST-NOT-Argument
- # < up_fun: Adresse einer Testfunktion, die wie folgt spezifiziert ist:
- # > stackptr: derselbe Pointer in den Stack, *(stackptr+3) = item,
- # *(stackptr+1) = :test-Argument, *(stackptr+0) = :test-not-Argument,
- # > x: Argument
- # < TRUE, falls der Test erfüllt ist, FALSE sonst.
- # up_function sei der Typ der Adresse einer solchen Testfunktion:
- typedef boolean (*up_function) (object* stackptr, object x);
- local up_function test_test_args (void);
- local up_function test_test_args()
- { var reg2 object test_arg = STACK_2;
- if (eq(test_arg,unbound)) { test_arg=NIL; }
- # test_arg ist das :TEST-Argument
- {var reg1 object test_not_arg = STACK_1;
- if (eq(test_not_arg,unbound)) { test_not_arg=NIL; }
- # test_not_arg ist das :TEST-NOT-Argument
- if (nullp(test_not_arg))
- # :TEST-NOT wurde nicht angegeben
- { if (nullp(test_arg))
- STACK_2 = L(eql); # #'EQL als Default für :TEST
- return(&up_test);
- }
- # :TEST-NOT wurde angegeben
- { if (nullp(test_arg))
- return(&up_test_not);
- else
- fehler_both_tests();
- }} }
-
- # UP: Ersetzt im Baum tree alle x, deren KEY der TESTFUNktion genügen,
- # durch NEW. Konstruktiv.
- # subst(tree,stackptr,up_fun)
- # > tree: Baum
- # > stackptr: *(stackptr-2) = NEW, *(stackptr-1) = KEY
- # > up_fun: TESTFUN = Adresse der Testfunktion,
- # wird selbem stackptr und mit (KEY x) als Argument angesprungen.
- # Sie liefert TRUE, falls der Test erfüllt ist, FALSE sonst.
- # < ergebnis: (evtl. neuer) Baum
- # kann GC auslösen
- local object subst (object tree, object* stackptr, up_function up_fun);
- local object subst(tree,stackptr,up_fun)
- var reg3 object tree;
- var reg2 object* stackptr;
- var up_function up_fun;
- { # erst (KEY tree) berechnen und TESTFUN aufrufen:
- pushSTACK(tree); # tree retten
- pushSTACK(tree); funcall(*(stackptr STACKop -1),1); # (KEY tree)
- if (up_fun(stackptr,value1)) # TESTFUN aufrufen
- # Test erfüllt
- { skipSTACK(1); return *(stackptr STACKop -2); } # NEW als Wert
- else
- # Test nicht erfüllt
- if (matomp(STACK_0))
- # Argument Atom -> unverändert lassen
- { return popSTACK(); }
- else
- # Argument ist ein Cons -> SUBST rekursiv aufrufen:
- { check_STACK(); check_SP();
- { # rekursiv für den CDR aufrufen:
- var reg4 object new_cdr = subst(Cdr(STACK_0),stackptr,up_fun);
- pushSTACK(new_cdr); # CDR-Ergebnis retten
- {# rekursiv für den CAR aufrufen:
- var reg3 object new_car = subst(Car(STACK_1),stackptr,up_fun);
- if (eq(new_car,Car(STACK_1)) && eq(STACK_0,Cdr(STACK_1)))
- # beides unverändert
- { skipSTACK(1); # CDR-Ergebnis vergessen
- return popSTACK();
- }
- else
- { STACK_1 = new_car; # CAR-Ergebnis retten
- {var reg1 object new_cons = allocate_cons(); # neue Cons-Zelle
- Cdr(new_cons) = popSTACK(); Car(new_cons) = popSTACK();
- return new_cons;
- } }}} }}
-
- LISPFUN(subst,3,0,norest,key,3, (kw(test),kw(test_not),kw(key)) )
- # (SUBST new old tree :test :test-not :key), CLTL S. 273
- { test_key_arg(); # :KEY-Argument in STACK_0
- {var reg2 up_function up_fun = test_test_args(); # :TEST/:TEST-NOT-Argumente in STACK_2,STACK_1
- {var reg1 object new = STACK_5; pushSTACK(new); }
- # Stackaufbau: new, old, tree, test, test_not, key, new.
- value1 = subst(STACK_4,&STACK_2,up_fun); # Ersetzung durchführen
- mv_count=1;
- skipSTACK(7);
- }}
-
- LISPFUN(subst_if,3,0,norest,key,1, (kw(key)) )
- # (SUBST-IF new pred tree :key), CLTL S. 273
- { test_key_arg(); # :KEY-Argument in STACK_0
- {var reg1 object new = STACK_3; pushSTACK(new); }
- # Stackaufbau: new, pred, tree, key, new.
- value1 = subst(STACK_2,&STACK_2,&up_if); # Ersetzung durchführen
- mv_count=1;
- skipSTACK(5);
- }
-
- LISPFUN(subst_if_not,3,0,norest,key,1, (kw(key)) )
- # (SUBST-IF-NOT new pred tree :key), CLTL S. 273
- { test_key_arg(); # :KEY-Argument in STACK_0
- {var reg1 object new = STACK_3; pushSTACK(new); }
- # Stackaufbau: new, pred, tree, key, new.
- value1 = subst(STACK_2,&STACK_2,&up_if_not); # Ersetzung durchführen
- mv_count=1;
- skipSTACK(5);
- }
-
- # UP: Ersetzt im Baum tree alle x, deren KEY der TESTFUNktion genügen,
- # durch NEW. Destruktiv.
- # nsubst(tree,stackptr,up_fun)
- # > tree: Baum
- # > stackptr: *(stackptr-2) = NEW, *(stackptr-1) = KEY
- # > up_fun: TESTFUN = Adresse der Testfunktion,
- # wird selbem stackptr und mit (KEY x) als Argument angesprungen.
- # Sie liefert TRUE, falls der Test erfüllt ist, FALSE sonst.
- # < ergebnis: Baum
- # kann GC auslösen
- local object nsubst (object tree, object* stackptr, up_function up_fun);
- local object nsubst(tree,stackptr,up_fun)
- var reg3 object tree;
- var reg1 object* stackptr;
- var up_function up_fun;
- { # erst (KEY tree) berechnen und TESTFUN aufrufen:
- pushSTACK(tree); # tree retten
- pushSTACK(tree); funcall(*(stackptr STACKop -1),1); # (KEY tree)
- if (up_fun(stackptr,value1)) # TESTFUN aufrufen
- # Test erfüllt
- { skipSTACK(1); return *(stackptr STACKop -2); } # NEW als Wert
- else
- # Test nicht erfüllt
- { if (mconsp(STACK_0))
- # Argument ist ein Cons -> NSUBST rekursiv aufrufen:
- { check_STACK(); check_SP();
- # rekursiv für den CDR aufrufen:
- {var reg2 object modified_cdr = nsubst(Cdr(STACK_0),stackptr,up_fun);
- #ifdef IMMUTABLE_CONS
- if (!eq(Cdr(STACK_0),modified_cdr))
- #endif
- Cdr(STACK_0) = modified_cdr;
- }
- # rekursiv für den CAR aufrufen:
- {var reg2 object modified_car = nsubst(Car(STACK_0),stackptr,up_fun);
- #ifdef IMMUTABLE_CONS
- if (!eq(Car(STACK_0),modified_car))
- #endif
- Car(STACK_0) = modified_car;
- } }
- return popSTACK(); # ursprünglicher Baum zurück
- } }
-
- LISPFUN(nsubst,3,0,norest,key,3, (kw(test),kw(test_not),kw(key)) )
- # (NSUBST new old tree :test :test-not :key), CLTL S. 274
- { test_key_arg(); # :KEY-Argument in STACK_0
- {var reg2 up_function up_fun = test_test_args(); # :TEST/:TEST-NOT-Argumente in STACK_2,STACK_1
- {var reg1 object new = STACK_5; pushSTACK(new); }
- # Stackaufbau: new, old, tree, test, test_not, key, new.
- value1 = nsubst(STACK_4,&STACK_2,up_fun); # Ersetzung durchführen
- mv_count=1;
- skipSTACK(7);
- }}
-
- LISPFUN(nsubst_if,3,0,norest,key,1, (kw(key)) )
- # (NSUBST-IF new pred tree :key), CLTL S. 274
- { test_key_arg(); # :KEY-Argument in STACK_0
- {var reg1 object new = STACK_3; pushSTACK(new); }
- # Stackaufbau: new, pred, tree, key, new.
- value1 = nsubst(STACK_2,&STACK_2,&up_if); # Ersetzung durchführen
- mv_count=1;
- skipSTACK(5);
- }
-
- LISPFUN(nsubst_if_not,3,0,norest,key,1, (kw(key)) )
- # (NSUBST-IF-NOT new pred tree :key), CLTL S. 274
- { test_key_arg(); # :KEY-Argument in STACK_0
- {var reg1 object new = STACK_3; pushSTACK(new); }
- # Stackaufbau: new, pred, tree, key, new.
- value1 = nsubst(STACK_2,&STACK_2,&up_if_not); # Ersetzung durchführen
- mv_count=1;
- skipSTACK(5);
- }
-
- # UP: Liefert das erste Listenelement, dessen CAR der TESTFUNktion genügt.
- # sublis_assoc(stackptr)
- # > *(stackptr+3) = alist: Aliste
- # > stackptr: *(stackptr-1) = KEY
- # > *(stackptr-3) = TESTFUN = Testfunktion, wird für alle Listenelemente
- # (u . v) mit selbem stackptr und mit (KEY x) und u als Argumenten angesprungen.
- # Sie liefert TRUE, falls der Test erfüllt ist, FALSE sonst.
- # < ergebnis: Listenelement (ein Cons) oder NIL
- # kann GC auslösen
- local object sublis_assoc (object* stackptr);
- local object sublis_assoc(stackptr)
- var reg3 object* stackptr;
- { var reg2 object alist = *(stackptr STACKop 3);
- while (consp(alist))
- { if (mconsp(Car(alist))) # atomare Listenelemente überspringen
- { pushSTACK(alist); # Listenrest ((u . v) ...) retten
- # Testen, ob die zweiargumentige Testfunktion
- # *(stackptr-3) (eine Adresse!), angewandt auf u und das
- # vorher in *(stackptr-2) abgelegte Argument, erfüllt ist:
- {var reg1 boolean erg =
- (*(up2_function)TheMachine(*(stackptr STACKop -3))) # zweiargumentige Testfunktion, wurde abgelegt
- ( stackptr, *(stackptr STACKop -2), Car(Car(alist)) ); # auf (KEY x) und u anwenden
- alist = popSTACK();
- if (erg)
- # Test erfüllt -> x = (u . v) = (CAR alist) als Ergebnis
- return Car(alist);
- # Test nicht erfüllt
- }}
- alist = Cdr(alist); # Tail-End-Rekursion
- }
- # Listenende erreicht -> ergibt Ergebnis NIL
- return NIL;
- }
-
- # UP: Ersetzt im Baum tree alle x durch ihr ALIST-Abbild (mittels ASSOC):
- # x wird durch das erste v ersetzt, so daß (u . v) in ALIST vorkommt und
- # (KEY x) und u der TESTFUNktion genügen. Konstruktiv.
- # sublis(tree,stackptr)
- # > tree: Baum
- # > stackptr: *(stackptr-1) = KEY, *(stackptr+3) = ALIST,
- # *(stackptr-2) ist frei für (KEY x)
- # < ergebnis: (evtl. neuer) Baum
- # kann GC auslösen
- local object sublis (object tree, object* stackptr);
- local object sublis(tree,stackptr)
- var reg3 object tree;
- var reg1 object* stackptr;
- { # erst (KEY tree) berechnen und ASSOC aufrufen:
- pushSTACK(tree); # tree retten
- pushSTACK(tree); funcall(*(stackptr STACKop -1),1); # (KEY tree)
- *(stackptr STACKop -2) = value1; # retten für sublis_assoc
- {var reg2 object assoc_erg = sublis_assoc(stackptr);
- if (consp(assoc_erg))
- # Test erfüllt
- { skipSTACK(1); return Cdr(assoc_erg); } # (CDR (ASSOC ...)) als Wert
- else
- # Test nicht erfüllt
- if (matomp(STACK_0))
- # Argument Atom -> unverändert lassen
- { return popSTACK(); }
- else
- # Argument ist ein Cons -> SUBLIS rekursiv aufrufen:
- { check_STACK(); check_SP();
- { # rekursiv für den CDR aufrufen:
- var reg4 object new_cdr = sublis(Cdr(STACK_0),stackptr);
- pushSTACK(new_cdr); # CDR-Ergebnis retten
- {# rekursiv für den CAR aufrufen:
- var reg3 object new_car = sublis(Car(STACK_1),stackptr);
- if (eq(new_car,Car(STACK_1)) && eq(STACK_0,Cdr(STACK_1)))
- # beides unverändert
- { skipSTACK(1); # CDR-Ergebnis vergessen
- return popSTACK();
- }
- else
- { STACK_1 = new_car; # CAR-Ergebnis retten
- {var reg1 object new_cons = allocate_cons(); # neue Cons-Zelle
- Cdr(new_cons) = popSTACK(); Car(new_cons) = popSTACK();
- return new_cons;
- }} }}} }}
-
- LISPFUN(sublis,2,0,norest,key,3, (kw(test),kw(test_not),kw(key)) )
- # (SUBLIS alist tree :test :test-not :key), CLTL S. 274
- { test_key_arg(); # :KEY-Argument in STACK_0
- {var reg1 object* stackptr = &STACK_1;
- var reg2 up2_function up2_fun = test_test2_args(stackptr); # :TEST/:TEST-NOT-Argumente in STACK_2,STACK_1
- # up2_fun = Testfunktion, wird mit stackptr und (KEY x) und u als
- # Argumenten angesprungen. Sie liefert TRUE, falls der Test erfüllt ist.
- if (nullp(STACK_4)) # shortcut: nothing to do if alist = ()
- { value1 = STACK_3; mv_count=1;
- skipSTACK(5);
- }
- else
- { pushSTACK(NIL); # Dummy
- pushSTACK(type_pointer_object(machine_type,up2_fun)); # Testfunktion, wegen Typinfo=machine_type GC-sicher!
- # Stackaufbau: alist, tree, test, test_not, key, dummy, up2_fun.
- value1 = sublis(STACK_5,stackptr); # Ersetzung durchführen
- mv_count=1;
- skipSTACK(7);
- }} }
-
- # UP: Ersetzt im Baum tree alle x durch ihr ALIST-Abbild (mittels ASSOC):
- # x wird durch das erste v ersetzt, so daß (u . v) in ALIST vorkommt und
- # (KEY x) und u der TESTFUNktion genügen. Destruktiv.
- # nsublis(tree,stackptr)
- # > tree: Baum
- # > stackptr: *(stackptr-1) = KEY, *(stackptr+3) = ALIST,
- # *(stackptr-2) ist frei für (KEY x)
- # < ergebnis: Baum
- # kann GC auslösen
- local object nsublis (object tree, object* stackptr);
- local object nsublis(tree,stackptr)
- var reg3 object tree;
- var reg1 object* stackptr;
- { # erst (KEY tree) berechnen und ASSOC aufrufen:
- pushSTACK(tree); # tree retten
- pushSTACK(tree); funcall(*(stackptr STACKop -1),1); # (KEY tree)
- *(stackptr STACKop -2) = value1; # retten für sublis_assoc
- {var reg2 object assoc_erg = sublis_assoc(stackptr);
- if (consp(assoc_erg))
- # Test erfüllt
- { skipSTACK(1); return Cdr(assoc_erg); } # (CDR (ASSOC ...)) als Wert
- else
- # Test nicht erfüllt
- { if (mconsp(STACK_0))
- # Argument ist ein Cons -> NSUBLIS rekursiv aufrufen:
- { check_STACK(); check_SP();
- # rekursiv für den CDR aufrufen:
- {var reg2 object modified_cdr = nsublis(Cdr(STACK_0),stackptr);
- #ifdef IMMUTABLE_CONS
- if (!eq(Cdr(STACK_0),modified_cdr))
- #endif
- Cdr(STACK_0) = modified_cdr;
- }
- # rekursiv für den CAR aufrufen:
- {var reg2 object modified_car = nsublis(Car(STACK_0),stackptr);
- #ifdef IMMUTABLE_CONS
- if (!eq(Car(STACK_0),modified_car))
- #endif
- Car(STACK_0) = modified_car;
- } }
- return popSTACK(); # ursprünglicher Baum zurück
- }} }
-
- LISPFUN(nsublis,2,0,norest,key,3, (kw(test),kw(test_not),kw(key)) )
- # (NSUBLIS alist tree :test :test-not :key), CLTL S. 275
- { test_key_arg(); # :KEY-Argument in STACK_0
- {var reg1 object* stackptr = &STACK_1;
- var reg2 up2_function up2_fun = test_test2_args(stackptr); # :TEST/:TEST-NOT-Argumente in STACK_2,STACK_1
- # up2_fun = Testfunktion, wird mit stackptr und (KEY x) und u als
- # Argumenten angesprungen. Sie liefert TRUE, falls der Test erfüllt ist.
- if (nullp(STACK_4)) # shortcut: nothing to do if alist = ()
- { value1 = STACK_3; mv_count=1;
- skipSTACK(5);
- }
- else
- { pushSTACK(NIL); # Dummy
- pushSTACK(type_pointer_object(machine_type,up2_fun)); # Testfunktion, wegen Typinfo=machine_type GC-sicher!
- # Stackaufbau: alist, tree, test, test_not, key, dummy, up2_fun.
- value1 = nsublis(STACK_5,stackptr); # Ersetzung durchführen
- mv_count=1;
- skipSTACK(7);
- }} }
-
- # UP: Liefert den Listenrest ab dem Listenelement, das der TESTFUNktion
- # genügt.
- # member(list,stackptr,up_fun)
- # > list: Liste
- # > STACK_0: Aufrufer (ein SUBR)
- # > stackptr: *(stackptr-1) = KEY
- # > up_fun: TESTFUN = Adresse der Testfunktion,
- # wird selbem stackptr und mit (KEY x) als Argument angesprungen.
- # Sie liefert TRUE, falls der Test erfüllt ist, FALSE sonst.
- # < ergebnis: Listenrest
- # kann GC auslösen
- local object member (object list, object* stackptr, up_function up_fun);
- local object member(list,stackptr,up_fun)
- var reg1 object list;
- var reg2 object* stackptr;
- var reg4 up_function up_fun;
- { until ((
- subr_self = STACK_0, # Aufrufer (für Fehlermeldung bei ENDP)
- endp(list) # Listenende erreicht?
- ))
- { pushSTACK(list); # Listenrest retten
- pushSTACK(Car(list)); funcall(*(stackptr STACKop -1),1); # (KEY x)
- {var reg3 boolean erg = up_fun(stackptr,value1); # TESTFUN aufrufen
- list = popSTACK();
- if (erg) { return list; } # Test erfüllt -> list als Ergebnis
- }
- # Test nicht erfüllt -> (member ... (cdr list)) aufrufen:
- list = Cdr(list); # tail-end-rekursiv
- }
- return list; # NIL als Ergebnis
- }
-
- LISPFUN(member,2,0,norest,key,3, (kw(test),kw(test_not),kw(key)) )
- # (MEMBER item list :test :test-not :key), CLTL S. 275
- { test_key_arg(); # :KEY-Argument in STACK_0
- {var reg2 up_function up_fun = test_test_args(); # :TEST/:TEST-NOT-Argumente in STACK_2,STACK_1
- pushSTACK(L(member)); # Aufrufer
- value1 = member(STACK_4,&STACK_2,up_fun); # Suche durchführen
- mv_count=1;
- skipSTACK(6);
- }}
-
- LISPFUN(member_if,2,0,norest,key,1, (kw(key)) )
- # (MEMBER-IF pred list :key), CLTL S. 275
- { test_key_arg(); # :KEY-Argument in STACK_0
- pushSTACK(L(member_if)); # Aufrufer
- value1 = member(STACK_2,&STACK_2,&up_if); # Suche durchführen
- mv_count=1;
- skipSTACK(4);
- }
-
- LISPFUN(member_if_not,2,0,norest,key,1, (kw(key)) )
- # (MEMBER-IF-NOT pred list :key), CLTL S. 275
- { test_key_arg(); # :KEY-Argument in STACK_0
- pushSTACK(L(member_if_not)); # Aufrufer
- value1 = member(STACK_2,&STACK_2,&up_if_not); # Suche durchführen
- mv_count=1;
- skipSTACK(4);
- }
-
- LISPFUNN(tailp,2) # (TAILP sublist list), CLTL S. 275
- #ifndef X3J13_175
- # (defun tailp (sublist list)
- # (do ((l list (rest l)))
- # ((endp l) (null sublist))
- # (when (eq l sublist) (return t))
- # ) )
- #else
- # (defun tailp (sublist list)
- # (loop
- # (when (eq sublist list) (return t))
- # (when (atom list) (return nil))
- # (setq list (cdr list))
- # ) )
- #endif
- { var reg1 object list = popSTACK();
- var reg2 object sublist = popSTACK();
- #ifndef X3J13_175
- loop
- { if (endp(list)) goto end;
- if (eq(list,sublist)) goto yes;
- list = Cdr(list);
- }
- end:
- if (nullp(sublist)) goto yes;
- #else
- loop
- { if (eq(list,sublist)) goto yes;
- if (atomp(list)) break;
- list = Cdr(list);
- }
- #endif
- value1 = NIL; mv_count=1; return; # NIL als Wert
- yes:
- value1 = T; mv_count=1; return; # T als Wert
- }
-
- LISPFUN(adjoin,2,0,norest,key,3, (kw(test),kw(test_not),kw(key)) )
- # (ADJOIN item list :test :test-not :key), CLTL S. 276
- { # erst Test auf (MEMBER (key item) list :test :test-not :key):
- test_key_arg(); # :KEY-Argument in STACK_0
- {var reg2 up_function up_fun = test_test_args(); # :TEST/:TEST-NOT-Argumente in STACK_2,STACK_1
- {var reg1 object item = STACK_4;
- pushSTACK(item); # item retten
- pushSTACK(item); funcall(STACK_2,1); STACK_5 = value1; # item := (funcall key item)
- }
- pushSTACK(L(adjoin)); # Aufrufer
- # Stackaufbau: (key item), list, test, test-not, key, item, #'adjoin.
- if (nullp(member(STACK_5,&STACK_3,up_fun))) # Suche durchführen
- # item noch nicht in list gefunden: muß consen
- { var reg1 object new_cons = allocate_cons();
- Cdr(new_cons) = STACK_5; # = list
- Car(new_cons) = STACK_1; # = item
- value1 = new_cons;
- }
- else
- { value1 = STACK_5; } # list als Wert
- mv_count=1; skipSTACK(7); return;
- }}
-
- LISPFUNN(acons,3)
- # (ACONS key val alist) = (CONS (CONS key val) alist), CLTL S. 279
- {{var reg1 object new_cons = allocate_cons();
- Car(new_cons) = STACK_2; # key
- Cdr(new_cons) = STACK_1; # value
- STACK_1 = new_cons;
- }
- {var reg1 object new_cons = allocate_cons();
- Cdr(new_cons) = popSTACK(); # alist
- Car(new_cons) = popSTACK(); # (key . val)
- value1 = new_cons; mv_count=1;
- skipSTACK(1);
- }}
-
- LISPFUN(pairlis,2,1,norest,nokey,0,NIL)
- # (PAIRLIS keys data [alist]), CLTL S. 280
- { if (eq(STACK_0,unbound)) { STACK_0=NIL; } # NIL als Default für alist
- {var reg1 object keys_list = STACK_2;
- var reg2 object data_list = STACK_1;
- pushSTACK(keys_list);
- pushSTACK(data_list);
- }
- loop # Stackaufbau: keys, data, alist, keysr, datar.
- { if (matomp(STACK_0)) # data-Liste zu Ende?
- # ja
- if (matomp(STACK_1)) # keys-Liste auch zu Ende?
- goto end;
- else
- goto fehler_lengths;
- # nein
- else
- if (matomp(STACK_1)) # aber keys-Liste zu Ende?
- goto fehler_lengths;
- else
- { var reg1 object new_cons = allocate_cons();
- Car(new_cons) = Car(STACK_1); # nächstes key als CAR
- Cdr(new_cons) = Car(STACK_0); # nächstes data als CDR
- STACK_1 = Cdr(STACK_1); # keys verkürzen
- STACK_0 = Cdr(STACK_0); # data verkürzen
- pushSTACK(new_cons);
- new_cons = allocate_cons(); # weiteres neues Cons
- Car(new_cons) = popSTACK(); # mit (key . data) als CAR
- Cdr(new_cons) = STACK_2; # und alist als CDR
- STACK_2 = new_cons; # ergibt neues alist
- } }
- fehler_lengths:
- skipSTACK(3);
- { var reg2 object data_list = popSTACK();
- var reg1 object keys_list = popSTACK();
- pushSTACK(data_list); pushSTACK(keys_list); pushSTACK(TheSubr(subr_self)->name);
- //: DEUTSCH "~: Listen ~ und ~ sind verschieden lang."
- //: ENGLISH "~: lists ~ and ~ are not of same length"
- //: FRANCAIS "~ : Les listes ~ et ~ sont de longueurs distinctes."
- fehler(error, GETTEXT("~: lists ~ and ~ are not of same length"));
- }
- end: value1 = STACK_2; mv_count=1; skipSTACK(5); # alist als Wert
- }
-
- # UP: Liefert das erste Listenelement, dessen CAR der TESTFUNktion genügt.
- # assoc(alist,stackptr)
- # > alist: Aliste
- # > stackptr: *(stackptr-1) = KEY
- # > up_fun: TESTFUN = Adresse der Testfunktion, wird für alle Listenelemente
- # (u . v) mit selbem stackptr und mit (KEY u) als Argument angesprungen.
- # Sie liefert TRUE, falls der Test erfüllt ist, FALSE sonst.
- # < ergebnis: Listenelement (ein Cons) oder NIL
- # kann GC auslösen
- local object assoc (object alist, object* stackptr, up_function up_fun);
- local object assoc(alist,stackptr,up_fun)
- var reg2 object alist;
- var reg3 object* stackptr;
- var reg4 up_function up_fun;
- { start:
- if (atomp(alist))
- # Listenende erreicht -> ergibt Ergebnis NIL
- return NIL;
- else
- { if (mconsp(Car(alist))) # atomare Listenelemente überspringen
- { pushSTACK(alist); # Listenrest ((u . v) ...) retten
- pushSTACK(Car(Car(alist))); funcall(*(stackptr STACKop -1),1); # (KEY u)
- {var reg1 boolean erg = up_fun(stackptr,value1); # TESTFUN aufrufen
- alist = popSTACK();
- if (erg)
- # Test erfüllt -> x = (u . v) = (CAR alist) als Ergebnis
- return Car(alist);
- # Test nicht erfüllt
- }}
- # tail-end-rekursiv (assoc ... (cdr alist)) aufrufen:
- alist = Cdr(alist); goto start;
- } }
-
- LISPFUN(assoc,2,0,norest,key,3, (kw(test),kw(test_not),kw(key)) )
- # (ASSOC item alist :test :test-not :key), CLTL S. 280
- { test_key_arg(); # :KEY-Argument in STACK_0
- {var reg2 up_function up_fun = test_test_args(); # :TEST/:TEST-NOT-Argumente in STACK_2,STACK_1
- value1 = assoc(STACK_3,&STACK_1,up_fun); # Suche durchführen
- mv_count=1;
- skipSTACK(5);
- }}
-
- LISPFUN(assoc_if,2,0,norest,key,1, (kw(key)) )
- # (ASSOC-IF pred alist :key), CLTL S. 280
- { test_key_arg(); # :KEY-Argument in STACK_0
- value1 = assoc(STACK_1,&STACK_1,&up_if); # Suche durchführen
- mv_count=1;
- skipSTACK(3);
- }
-
- LISPFUN(assoc_if_not,2,0,norest,key,1, (kw(key)) )
- # (ASSOC-IF-NOT pred alist :key), CLTL S. 280
- { test_key_arg(); # :KEY-Argument in STACK_0
- value1 = assoc(STACK_1,&STACK_1,&up_if_not); # Suche durchführen
- mv_count=1;
- skipSTACK(3);
- }
-
- # UP: Liefert das erste Listenelement, dessen CDR der TESTFUNktion genügt.
- # rassoc(alist,stackptr)
- # > alist: Aliste
- # > stackptr: *(stackptr-1) = KEY
- # > up_fun: TESTFUN = Adresse der Testfunktion, wird für alle Listenelemente
- # (u . v) mit selbem stackptr und mit (KEY v) als Argument angesprungen.
- # Sie liefert TRUE, falls der Test erfüllt ist, FALSE sonst.
- # < ergebnis: Listenelement (ein Cons) oder NIL
- # kann GC auslösen
- local object rassoc (object alist, object* stackptr, up_function up_fun);
- local object rassoc(alist,stackptr,up_fun)
- var reg2 object alist;
- var reg3 object* stackptr;
- var reg4 up_function up_fun;
- { start:
- if (atomp(alist))
- # Listenende erreicht -> ergibt Ergebnis NIL
- return NIL;
- else
- { if (mconsp(Car(alist))) # atomare Listenelemente überspringen
- { pushSTACK(alist); # Listenrest ((u . v) ...) retten
- pushSTACK(Cdr(Car(alist))); funcall(*(stackptr STACKop -1),1); # (KEY v)
- {var reg1 boolean erg = up_fun(stackptr,value1); # TESTFUN aufrufen
- alist = popSTACK();
- if (erg)
- # Test erfüllt -> x = (u . v) = (CAR alist) als Ergebnis
- return Car(alist);
- # Test nicht erfüllt
- }}
- # tail-end-rekursiv (rassoc ... (cdr alist)) aufrufen:
- alist = Cdr(alist); goto start;
- } }
-
- LISPFUN(rassoc,2,0,norest,key,3, (kw(test),kw(test_not),kw(key)) )
- # (RASSOC item alist :test :test-not :key), CLTL S. 281
- { test_key_arg(); # :KEY-Argument in STACK_0
- {var reg2 up_function up_fun = test_test_args(); # :TEST/:TEST-NOT-Argumente in STACK_2,STACK_1
- value1 = rassoc(STACK_3,&STACK_1,up_fun); # Suche durchführen
- mv_count=1;
- skipSTACK(5);
- }}
-
- LISPFUN(rassoc_if,2,0,norest,key,1, (kw(key)) )
- # (RASSOC-IF pred alist :key), CLTL S. 281
- { test_key_arg(); # :KEY-Argument in STACK_0
- value1 = rassoc(STACK_1,&STACK_1,&up_if); # Suche durchführen
- mv_count=1;
- skipSTACK(3);
- }
-
- LISPFUN(rassoc_if_not,2,0,norest,key,1, (kw(key)) )
- # (RASSOC-IF-NOT pred alist :key), CLTL S. 281
- { test_key_arg(); # :KEY-Argument in STACK_0
- value1 = rassoc(STACK_1,&STACK_1,&up_if_not); # Suche durchführen
- mv_count=1;
- skipSTACK(3);
- }
-
- # Funktionen, die Listen zu Sequences machen:
-
- LISPFUNN(list_upd,2)
- # #'(lambda (seq pointer) (cdr pointer))
- { value1 = cdr(popSTACK()); mv_count=1; skipSTACK(1); }
-
- LISPFUNN(list_endtest,2)
- # #'(lambda (seq pointer) (atom pointer))
- { value1 = (matomp(STACK_0) ? T : NIL); mv_count=1; skipSTACK(2); }
-
- LISPFUNN(list_fe_init,1)
- # #'(lambda (seq) (revappend seq nil))
- { pushSTACK(NIL); C_revappend(); }
-
- LISPFUNN(list_access,2)
- # #'(lambda (seq pointer) (car pointer))
- { var reg1 object pointer = popSTACK();
- if (atomp(pointer)) fehler_cons(pointer);
- value1 = Car(pointer); mv_count=1;
- skipSTACK(1);
- }
-
- LISPFUNN(list_access_set,3)
- # #'(lambda (seq pointer value) (rplaca pointer value))
- { if (matomp(STACK_1)) fehler_cons(STACK_1);
- {var reg2 object value = popSTACK();
- var reg1 object pointer = popSTACK();
- Car(pointer) = value;
- value1 = value; mv_count=1;
- skipSTACK(1);
- }}
-
- LISPFUNN(list_llength,1)
- # #'(lambda (seq) (do ((L seq (cdr L)) (N 0 (1+ N))) ((atom L) N)))
- { value1 = fixnum(llength(popSTACK())); mv_count=1; }
-
- # UP: Läuft bis zum Element index in einer Liste.
- # elt_up(seq,index)
- # > seq
- # > index
- # > subr_self: Aufrufer (ein SUBR)
- # < ergebnis: Listenendstück ab diesem Index
- local object elt_up (object seq, object index);
- local object elt_up(seq,index)
- var reg4 object seq;
- var reg3 object index;
- # (do ((L seq (cdr L)) (N 0 (1+ N)))
- # (nil)
- # (if (atom L) (error "Zu großer Index in ELT: ~S" index))
- # (if (= N index) (return L))
- # )
- { var reg1 object l = seq;
- var reg2 object n = Fixnum_0;
- loop
- { if (atomp(l)) goto index_too_large;
- if (eq(n,index)) break;
- l = Cdr(l);
- n = fixnum_inc(n,1);
- }
- return l;
- index_too_large:
- pushSTACK(seq); pushSTACK(index); pushSTACK(TheSubr(subr_self)->name);
- //: DEUTSCH "~: Index ~ zu groß für ~"
- //: ENGLISH "~: index ~ too large for ~"
- //: FRANCAIS "~ : L'index ~ est trop grand pour ~."
- fehler(error, GETTEXT("~: index ~ too large for ~"));
- }
-
- LISPFUNN(list_elt,2)
- # #'(lambda (seq index)
- # (do ((L seq (cdr L)) (N 0 (1+ N)))
- # (nil)
- # (if (atom L) (error "Zu großer Index in ELT: ~S" index))
- # (if (= N index) (return (car L)))
- # ) )
- { var reg2 object index = popSTACK();
- var reg1 object seq = popSTACK();
- value1 = Car(elt_up(seq,index)); mv_count=1;
- }
-
- LISPFUNN(list_set_elt,3)
- # #'(lambda (seq index value)
- # (do ((L seq (cdr L)) (N 0 (1+ N)))
- # (nil)
- # (if (atom L) (error "Zu großer Index in ELT: ~S" index))
- # (if (= N index) (return (rplaca L value)))
- # ) )
- { var reg1 object nthcdr = elt_up(STACK_2,STACK_1);
- value1 = Car(nthcdr) = popSTACK(); mv_count=1;
- skipSTACK(2);
- }
-
- LISPFUNN(list_init_start,2)
- # #'(lambda (seq index)
- # (do ((L seq (cdr L)) (N 0 (1+ N)))
- # ((= N index) (return L))
- # (if (atom L) (error "Unzulässiger :START - Index : ~S" index))
- # ) )
- { var reg3 object index = popSTACK();
- var reg4 object seq = popSTACK();
- {var reg1 object l = seq;
- var reg2 object n = Fixnum_0;
- loop
- { if (eq(n,index)) break;
- if (atomp(l)) goto index_too_large;
- l = Cdr(l);
- n = fixnum_inc(n,1);
- }
- value1 = l; mv_count=1; return;
- index_too_large:
- pushSTACK(seq); pushSTACK(index); pushSTACK(S(list_init_start));
- //: DEUTSCH "~: START-Index ~ zu groß für ~"
- //: ENGLISH "~: start index ~ too large for ~"
- //: FRANCAIS "~ : L'index :START ~ est trop grand pour ~"
- fehler(error, GETTEXT("~: start index ~ too large for ~"));
- }}
-
- LISPFUNN(list_fe_init_end,2)
- # #'(lambda (seq index)
- # (if (<= 0 index)
- # (do* ((L1 nil (cons (car L2) L1))
- # (L2 seq (cdr L2))
- # (i index (1- i)))
- # ((zerop i) L1)
- # (if (atom L2)
- # (error "Unzulässiger :END - Index : ~S" index)
- # ) )
- # (error "Unzulässiger :END - Index : ~S" index)
- # ) )
- { # index ist sowieso ein Integer >=0.
- pushSTACK(NIL); # L1 := nil
- {var reg1 object seq = STACK_2; pushSTACK(seq); } # L2 := seq
- pushSTACK(Fixnum_0); # i := 0
- loop
- { # Stackaufbau: seq, index, L1, L2, i
- if (eq(STACK_0,STACK_3)) # i=index ?
- goto end;
- if (matomp(STACK_1)) # (atom L2) ?
- goto index_too_large;
- {var reg1 object new_cons = allocate_cons(); # neues Cons
- var reg2 object L2 = STACK_1; STACK_1 = Cdr(L2); # (pop L2)
- Car(new_cons) = Car(L2); # als CAR
- Cdr(new_cons) = STACK_2; # L1 als CDR
- STACK_2 = new_cons; # L1 := neues Cons
- STACK_0 = fixnum_inc(STACK_0,1); # i := i+1
- }}
- index_too_large:
- skipSTACK(3); # Stackaufbau: seq, index
- pushSTACK(S(list_fe_init_end));
- //: DEUTSCH "~: END-Index ~ zu groß für ~"
- //: ENGLISH "~: end index ~ too large for ~"
- //: FRANCAIS "~ : L'index :END ~ est trop grand pour ~."
- fehler(error, GETTEXT("~: end index ~ too large for ~"));
- end:
- value1 = STACK_2; mv_count=1; # L1 als Wert
- skipSTACK(5);
- }
-
-