Dokumentation zur Implementierung von CLISP =========================================== Die vorliegende LISP-Implementierung h„lt sich weitgehend an den Standard Guy L. Steele Jr.: Common Lisp - The Language (1st ed.). Digital Press 1984. (kurz CLTL genannt) Nachfolgend die Unterschiede von CLISP zu CLTL und Implementierungsdetails: KAPITEL 1 (Introduction) ------------------------ KAPITEL 2 (Data Types) ---------------------- (2.1.3.) Floating-Points gibt es in vier Auspr„gungen: Short-Float, Single-Float, Double-Float, Long-Float. Tabelle: Vorzeichen Mantisse Exponent Short-Float 1 Bit 16+1 Bits 8 Bits Single-Float 1 Bit 23+1 Bits 8 Bits IEEE-Format Double-Float 1 Bit 52+1 Bits 11 Bits IEEE-Format Long-Float 1 Bit 16*n Bits 32 Bits mit n>=4 Single und Double Float entsprechen dem IEEE-Standard (1981), allerdings ohne solche Features wie +0,-0, +inf,-inf, gradual underflow, NAN, ..., da COMMON LISP fr sie sowieso keine Verwendung hat. Long-Floats haben variable L„nge, die Default-L„nge beim Einlesen von Long-Floats kann mit der Place LONG-FLOAT-DIGITS eingestellt werden, d.h. mittels (SETF (LONG-FLOAT-DIGITS) nnn), nnn positive ganze Zahl. (2.1.4.) Komplexe Zahlen k”nnen Real- und Imagin„rteil verschiedenen Typs haben. Z.B. liefert (sqrt -9.0) die Zahl #C(0 3.0), bei der der Realteil exakt = 0 und nicht nur 0.0 (ungef„hr = 0) ist. Der Type-Specifier hierfr ist (COMPLEX INTEGER SHORT-FLOAT), allgemein (COMPLEX Realteil-Typ Imagin„rteil-Typ). Ein Type-Specifier (COMPLEX type) ist somit zu (COMPLEX type type) „quivalent. (2.2.1.) Die Anordnung der String-Chars entspricht der ASCII-Codierung, genauer dem Atari-Zeichensatz: $0 $1 $2 $3 $4 $5 $6 $7 $8 $9 $A $B $C $D $E $F $00 **     ** ** ** ** ** ** ** ** **   $10           ** **     $20 ! " # $ % & ' ( ) * + , - . / $30 0 1 2 3 4 5 6 7 8 9 : ; < = > ? $40 @ A B C D E F G H I J K L M N O $50 P Q R S T U V W X Y Z [ \ ] ^ _ $60 ` a b c d e f g h i j k l m n o $70 p q r s t u v w x y z { | } ~  $80 € ‚ ƒ „ … † ‡ ˆ ‰ Š ‹ Œ Ž $90 ‘ ’ “ ” • – — ˜ ™ š › œ ž Ÿ $A0   ¡ ¢ £ ¤ ¥ ¦ § ¨ © ª « ¬ ­ ® ¯ $B0 ° ± ² ³ ´ µ ¶ · ¸ ¹ º » ¼ ½ ¾ ¿ $C0 À Á Â Ã Ä Å Æ Ç È É Ê Ë Ì Í Î Ï $D0 Ð Ñ Ò Ó Ô Õ Ö × Ø Ù Ú Û Ü Ý Þ ß $E0 à á â ã ä å æ ç è é ê ë ì í î ï $F0 ð ñ ò ó ô õ ö ÷ ø ù ú û ü ý þ ÿ Dabei sind ** Steuerzeichen, also keine Graphic-Characters. Standard-Characters: #\Space $20 #\Newline $0A Semi-Standard-Characters: #\Backspace $08 #\Tab $09 #\Linefeed $0A #\Page $0C #\Return $0D #\Rubout $08 (2.2.2.) #\Newline ist das Trennzeichen zwischen zwei Zeilen. Beim Schreiben auf eine Datei wird #\Newline in CR/LF umgewandelt, was dem Atari-Standard entspricht. (Somit wird z.B. #\Return #\Newline als CR/CR/LF auf die Datei geschrieben.) Rckumwandlung: CR/LF -> #\Newline, CR ohne nachfolgendes LF -> #\Return. (2.2.3.) Zus„tzliche Characters: #\Null $00 #\Bell $07 #\Escape $1B (2.2.4.) Code eines Character ist >=0, <256. CHAR-CODE-LIMIT = 256. Fonts 0 bis 15 sind implementiert. CHAR-FONT-LIMIT = 16. Vom System wird nur Font 0 benutzt. Bits sind implementiert: :CONTROL, :META, :SUPER, :HYPER. Daher CHAR-BITS-LIMIT = 16. Vom System werden diese Bits nur benutzt, um bei (READ-CHAR *KEYBOARD-INPUT*) Sondertasten und den Status der Control/Alt/Shift-Tasten anzugeben. (2.5.) Maximaler Rang (Dimensionszahl) eines Arrays ist 65535. (2.13.) Alle Funktionen, die von FUNCTION oder COMPILE o.„. gebildet werden, sind Atome. Es gibt assemblierte und compilierte Funktionen (vom Typ COMPILED-FUNCTION) und interpretierte Funktionen ("Closures", vom Typ FUNCTION). Als Funktionsnamen (CLTL S. 59) k”nnen Symbole und Lambda-Ausdrcke auftreten. (2.14.) Nicht wiedereinlesbare Objekte sind: Alle Structures, bei denen kein Keyword-Constructor vorhanden ist. Alle Arrays aužer Strings, wenn *PRINT-ARRAY* = NIL. # Assemblierte Funktion # Special-Form # Compilierte Funktion bei *PRINT-CLOSURE* = NIL # Interpretierte Funktion # Pointer auf einen Stack-Frame # Frame-Pointer, der nach Verlassen eines Blocks oder eines Tagbody nicht mehr gltig ist #<...-STREAM ...> Stream # Package # Hash-Table bei *PRINT-ARRAY* = NIL # Readtable # Pathname # Byte-Specifier (CLTL S. 225) # "Wert" eines Symbols, das keinen Wert hat; "Wert" eines nicht angegebenen Keyword-Arguments # Environment-Markierung fr SPECIAL-deklarierte Variable # Internes Read-Ergebnis fr "." # Internes Read-Ergebnis, wenn Datei-Ende erreicht # Vorl„ufiges internes Read-Ergebnis fr #n# #
Maschinen-Adresse. Sollte nicht auftreten # Sollte nicht auftreten (2.15.) Der Typ NUMBER setzt sich disjunkt zusammen aus den Typen RATIONAL, FLOAT, COMPLEX. (CLTL-Sprechweise: "exhaustive partition") Der Typ RATIONAL setzt sich disjunkt zusammen aus den Typen INTEGER, RATIO. Der Typ INTEGER setzt sich disjunkt zusammen aus den Typen FIXNUM, BIGNUM. Der Typ FLOAT setzt sich disjunkt zusammen aus den Typen SHORT-FLOAT, SINGLE-FLOAT, DOUBLE-FLOAT, LONG-FLOAT. KAPITEL 3 (Scope and Extent) ---------------------------- KAPITEL 4 (Type Specifiers) --------------------------- (4.5.) Die allgemeine Form des COMPLEX-Typs lautet (COMPLEX Realteil-Typ Imagin„rteil-Typ). Ein Type-Specifier (COMPLEX type) ist zu (COMPLEX type type) „quivalent. (4.7.) DEFTYPE erlaubt in der Lambdaliste auch destructuring (verschachtelte Lambdalisten wie bei DEFMACRO) und &WHOLE-Marker, aber kein &ENVIRONMENT. (4.9.) Die m”glichen Ergebnisse von TYPE-OF: CONS SYMBOL FIXNUM BIGNUM RATIO SHORT-FLOAT SINGLE-FLOAT DOUBLE-FLOAT LONG-FLOAT COMPLEX (ARRAY element-type dimensions), (SIMPLE-ARRAY element-type dimensions) (VECTOR T size), (SIMPLE-VECTOR size) (STRING size), (SIMPLE-STRING size) (BIT-VECTOR size), (SIMPLE-BIT-VECTOR size) FUNCTION COMPILED-FUNCTION STREAM PACKAGE HASH-TABLE READTABLE PATHNAME RANDOM-STATE BYTE LOAD-TIME-EVAL READ-LABEL FRAME-POINTER SYSTEM-INTERNAL ADDRESS (sollte nicht auftreten) sonstiges Symbol (Structure-Typ) KAPITEL 5 (Program Structure) ----------------------------- (5.1.3.) Aužer den auf S. 57 angegebenen 24 Special Forms sind auch PSETQ, PROG1, PROG2, WHEN, UNLESS, COND, MULTIPLE-VALUE-LIST, MULTIPLE-VALUE-BIND, MULTIPLE-VALUE-SETQ, AND, OR als Special-Forms implementiert. Konstanten k”nnen weder dynamisch noch lexikalisch gebunden werden. (5.2.2.) LAMBDA-LIST-KEYWORDS = (&OPTIONAL &REST &KEY &ALLOW-OTHER-KEYS &AUX &BODY &WHOLE &ENVIRONMENT) LAMBDA-PARAMETERS-LIMIT = 65536 (5.3.) DEFUN und DEFMACRO sind auch in Formen verschachtelt zul„ssig. Beispiel: Definition von GENSYM: (let ((gensym-prefix "G") (gensym-count 1)) (defun gensym (&optional (x nil s)) (when s (cond ((stringp x) (setq gensym-prefix x)) ((integerp x) (if (minusp x) (error "~S: Index ~S ist negativ" 'gensym x) (setq gensym-count x) )) (t (error "~S: Argument ~S hat falschen Typ" 'gensym x)) ) ) (prog1 (make-symbol (concatenate 'string gensym-prefix (write-to-string gensym-count :base 10 :radix nil) ) ) (incf gensym-count) ) ) ) (5.3.2.) Es ist nicht m”glich, (PROCLAIM '(SPECIAL var)) - Deklarationen und damit auch DEFVAR - und DEFPARAMETER - Deklarationen rckg„ngig zu machen. Auch DEFCONSTANT - Deklarationen sind nicht rckg„ngig zu machen. Bei DEFCONSTANT wird nicht berprft, ob die Variable nicht bereits momentan gebunden ist. Konstanten k”nnen weder dynamisch noch lexikalisch gebunden werden. KAPITEL 6 (Predicates) ---------------------- (6.2.1.) Die Funktion SUBTYPEP ist nicht implementiert. (6.2.2.) COMPILED-FUNCTION-P ergibt T bei allen assemblierten oder compilierten Funktionen und bei allen Special-Form-Objekten. COMPILED-FUNCTION ist also kein Untertyp von FUNCTION. (6.3.) EQ wirkt auf Characters und Fixnums wie EQL. Denn von Zahlen und Characters werden keine unn”tigen Kopien gemacht. Dennoch sollte man EQL verwenden. (let ((x y)) (eq x x)) ergibt stets T, unabh„ngig von y. (6.4.) AND, OR sind als Special-Forms implementiert und dadurch recht effizient. KAPITEL 7 (Control Structure) ----------------------------- (7.1.1.) (FUNCTION symbol) liefert die lokale (mit FLET oder LABELS errichtete) Funktionsdefinition von name, falls eine solche existiert. Sonst natrlich die globale Funktionsdefinition. (SPECIAL-FORM-P symbol) liefert NIL oder T. Falls T, kann man sich mit (SYMBOL-FUNCTION symbol) das Special-Form-Objekt holen, das aber wertlos ist. (7.1.2.) PSETQ ist als Special-Form implementiert und dadurch recht effizient. (7.2.) Bei (SETF (SYMBOL-FUNCTION symbol) object) muž object entweder eine Funktion oder ein SYMBOL-FUNCTION - Wert oder ein Lambda-Ausdruck sein. Ein Lambda- Ausdruck wird dabei sofort in eine Funktion umgewandelt. SETF akzeptiert auch Places, die mehrere Werte liefern. Zus„tzliche Places: FUNCALL : (SETF (FUNCALL #'symbol ...) object) und (SETF (FUNCALL 'symbol ...) object) wirken wie (SETF (symbol ...) object). GET-DISPATCH-MACRO-CHARACTER : (SETF (GET-DISPATCH-MACRO-CHARACTER ...) ...) fhrt ein SET-DISPATCH-MACRO-CHARACTER aus. LONG-FLOAT-DIGITS : (SETF (LONG-FLOAT-DIGITS) digits) setzt die Default-Mantissenl„nge von Long-Floats, gemessen in Bits, auf digits. VALUES : (SETF (VALUES place1 ... placek) form) wirkt etwa wie (MULTIPLE-VALUE-BIND (dummy1 ... dummyk) form (SETF place1 dummy1 ... placek dummyk) (VALUES dummy1 ... dummyk) ) VALUES-LIST : (SETF (VALUES-LIST list) form) wirkt wie (VALUES-LIST (SETF list (MULTIPLE-VALUE-LIST form))) Beispiel: (SETF (VALUES A B) (VALUES B A)) vertauscht A und B. (GET-SETF-METHOD form &optional env) und (GET-SETF-METHOD-MULTIPLE-VALUE form &optional env) bekommen das fr Macro-Expansionen n”tige Environment als optionales Argument. Bei DEFINE-SETF-METHOD kann man nach &environment eine Variable angeben, an die das Environment gebunden wird; es sollte in allen GET-SETF-METHOD - und GET-SETF-METHOD-MULTIPLE-VALUE - Aufrufe weitergereicht werden. Wird das getan, so werden auch lokale Macros korrekt als Places interpretiert. (7.3.) CALL-ARGUMENTS-LIMIT = 65536 (7.4.) PROG1, PROG2 sind als Special-Forms implementiert und dadurch recht effizient. (7.5.) Die Macros LETF und LETF* wirken wie LET bzw. LET*, nur daž Places, auch mit mehreren Werten gebunden werden k”nnen. Beispiel: (LETF (((VALUES A B) form)) ...) wirkt wie (MULTIPLE-VALUE-BIND (A B) form ...) (LETF (((FIRST L) 7)) ...) wirkt etwa wie (LET* ((#:G1 L) (#:G2 (FIRST #:G1))) (UNWIND-PROTECT (PROGN (SETF (FIRST #:G1) 7) ...) (SETF (FIRST #:G1) #:G2) ) ) (7.6.) WHEN, UNLESS, COND sind als Special-Forms implementiert und dadurch recht effizient. (7.8.4.) Die Funktion MAPCAP wirkt wie MAPCAN, nur h„ngt sie die Ergebnislisten mit APPEND statt mit NCONC zusammen: (MAPCAP fun x1 ... xn) = (apply #'append (mapcar fun x1 ... xn)), ist jedoch etwas effizienter. Die Funktion MAPLAP wirkt wie MAPCON, nur h„ngt sie die Ergebnislisten mit APPEND statt mit NCONC zusammen: (MAPLAP fun x1 ... xn) = (apply #'append (maplist fun x1 ... xn)), ist jedoch etwas effizienter. (7.9.1.) MULTIPLE-VALUES-LIMIT = 128 MULTIPLE-VALUE-LIST, MULTIPLE-VALUE-BIND, MULTIPLE-VALUE-SETQ sind als Special-Forms implementiert und dadurch recht effizient. Der Macro NTH-VALUE: (NTH-VALUE n form) liefert den (n+1)-ten Wert (n>=0) von form. KAPITEL 8 (Macros) ------------------ KAPITEL 9 (Declarations) ------------------------ (9.2.) Die Deklarationen (TYPE type var ...), (FTYPE type fun ...), (FUNCTION name arglist result-type), (OPTIMIZE (quality value) ...) werden sowohl vom Interpreter als auch vom Compiler ignoriert. Zus„tzliche Deklaration: Die Deklaration (COMPILE) bewirkt, daž die momentane Form vor der Ausfhrung compiliert wird. Diese Deklaration ist pervasiv. Beispiel: (LOCALLY (DECLARE (COMPILE)) form) Beispiel: (let ((x 0)) (flet ((inc () (declare (compile)) (incf x)) (dec () (decf x))) (values #'inc #'dec) ) ) liefert zwei Funktionen. Die erste ist compiliert und incrementiert x, die zweite ist interpretiert (langsamer) und decrementiert dasselbe x. (9.3.) Bei THE wird der Typtest nur in interpretiertem Code durchgefhrt, nicht in compiliertem Code. Bei (ETHE value-type form) wird der Typtest auch in compiliertem Code durchgefhrt. KAPITEL 10 (Symbols) -------------------- KAPITEL 11 (Packages) --------------------- (11.6.) Package SYSTEM hat aužer dem Nickname "SYS" auch den Nickname "COMPILER". (11.8.) Die Funktion REQUIRE bekommt als optionales Argument entweder einen Pathname oder eine Liste von Pathnames, die zu laden sind, falls das angeforderte Modul noch nicht im Speicher ist. KAPITEL 12 (Numbers) -------------------- - Single- und Double-Floats entsprechen dem IEEE-Standard (1981), allerdings ohne solche Features wie +0,-0, +inf,-inf, gradual underflow, NAN, ..., da COMMON LISP fr sie sowieso keine Verwendung hat. - Die Genauigkeit der Long-Floats (in Bits gemessen) wird durch die Place (LONG-FLOAT-DIGITS) gegeben. Z.B. kann die Long-Float-Genauigkeit mit (SETF (LONG-FLOAT-DIGITS) 3322) auf 1000 Dezimalstellen eingestellt werden. (12.1.) - Complex drfen aus zwei Real-Komponenten bestehen, die von verschiedenem Typ sind. Falls der Imagin„rteil EQL zu 0 ist, wird ein Real draus gemacht. (Vgl. CLTL S. 195) Vorteil: Dann liefert (let ((x (sqrt -9.0))) (* x x)) (statt x = #C(0.0 3.0) -> Wert #C(-9.0 0.0) ) x = #C(0 3.0) -> Wert #C(-9.0 0) = -9.0 - Coercionen bei Operationen, wo verschiedene Typen auftreten: Das Ergebnis einer arithmetischen Operation wird auf das Float-Format des krzeren (ungenaueren) gerundet. Rational -> Long-float -> Double-float -> Single-float -> Short-float (abweichend von CLTL S. 195) Grund: mathematisch gesehen, ist (1.0 +- 1e-8) + (1.0 +- 1e-16) = (2.0 +- 1e-8), also ist (+ 1.0s0 1.0d0) ==> 2.0s0 gerechtfertigt. Kurz: Nicht vorhandene Genauigkeit (accuracy) soll nicht (durch precision) vorget„uscht werden. Beispiel: (- (+ 1.7 pi) pi) sollte nicht 1.700000726342836417234L0, sondern eher 1.7f0 oder h”chstens 1.700001f0 liefern. - Mssen rationale Zahlen in Floats umgewandelt werden (ber FLOAT, COERCE, SQRT oder die transzendenten Funktionen), so richtet sich der Ergebnistyp nach der Variablen *DEFAULT-FLOAT-FORMAT*. (12.4.) (LCM), ohne Argumente aufgerufen, liefert 1, was das neutrale Element der LCM-Verknpfung ist. (! n) liefert die Fakult„t einer ganzen Zahl n>=0. (EXQUO x y) liefert den Quotient x/y zweier Integers x,y, wenn dieser wieder ein Integer ist. (12.5.1.) (EXPT base exponent) ist bei betragsm„žig grožem exponent recht ungenau. (LOG number base) liefert bei base=1 einen Error. (12.5.2.) Der Wert von PI ist ein Long-Float von der mit (LONG-FLOAT-DIGITS) einge- stellten Genauigkeit. Wird diese Genauigkeit ge„ndert, so wird der Wert von PI automatisch nachberechnet. Daher ist PI keine Konstante, sondern eine Variable. (12.6.) FLOAT-RADIX liefert immer den Wert 2. (FLOAT-DIGITS number digits) wandelt number (eine reelle Zahl) in ein Floating-Point mit mindestens digits Mantissenstellen um, so daž also (>= (FLOAT-DIGITS (FLOAT-DIGITS number digits)) digits) gilt. (12.7.) BOOLE-CLR = 0 BOOLE-SET = 15 BOOLE-1 = 10 BOOLE-2 = 12 BOOLE-C1 = 5 BOOLE-C2 = 3 BOOLE-AND = 8 BOOLE-IOR = 14 BOOLE-XOR = 6 BOOLE-EQV = 9 BOOLE-NAND = 7 BOOLE-NOR = 1 BOOLE-ANDC1 = 4 BOOLE-ANDC2 = 2 BOOLE-ORC1 = 13 BOOLE-ORC2 = 11 (12.10.) MOST-POSITIVE-FIXNUM = 2^24-1 = 16777215 MOST-NEGATIVE-FIXNUm = -2^24 = -16777216 Das fr PI Gesagte gilt auch fr die anderen Long-Float-Konstanten MOST-POSITIVE-LONG-FLOAT, LEAST-POSITIVE-LONG-FLOAT, LEAST-NEGATIVE-LONG-FLOAT, MOST-NEGATIVE-LONG-FLOAT, LONG-FLOAT-EPSILON, LONG-FLOAT-NEGATIVE-EPSILON: Sie sind Variablen und werden bei Žnderung von (LONG-FLOAT-DIGITS) ge„ndert. KAPITEL 13 (Characters) ----------------------- Siehe erst oben (2.2.). (13.1.) CHAR-CODE-LIMIT = 256 CHAR-FONT-LIMIT = 16 CHAR-BITS-LIMIT = 16 (13.2.) String-Chars sind die Characters mit font=0 und bits=0. Graphic Characters sind diejenigen String-Chars, die in obiger Tabelle nicht mit ** gekennzeichnet sind. Standard-Chars sind #\Newline und diejenigen Graphic Characters mit einem Code c mit $20 <= c <= $7E. Alphabetische Characters sind diejenigen String-Chars mit einem Code c, mit $41 <= c <= $5A oder $61 <= c <= $7A oder $80 <= c <= $9A oder $9E <= c <= $A7 oder $B0 <= c <= $B8 oder $C0 <= c <= $C1. Dies sind: ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™šžŸ ¡¢£¤¥¦§°±²³´µ¶·¸ÀÁ Die Funktionen CHAR-EQUAL, CHAR-NOT-EQUAL, CHAR-LESSP, CHAR-GREATERP, CHAR-NOT-GREATERP, CHAR-NOT-LESSP ignorieren Bits- und Font-Attribute ihrer Argumente. (13.4.) Die String-Chars, die keine Graphic Characters sind, und das Space haben Namen: $00 #\Null $05 #\Code5 $06 #\Code6 $07 #\Bell $08 #\Backspace = #\Rubout $09 #\Tab $0A #\Newline = #\Linefeed $0B #\Code11 $0C #\Page $0D #\Return $1A #\Code26 $1B #\Escape $20 #\Space (13.5.) CHAR-CONTROL-BIT = 1 CHAR-META-BIT = 2 CHAR-SUPER-BIT = 4 CHAR-HYPER-BIT = 8 KAPITEL 14 (Sequences) ---------------------- (14.1.) Das Ergebnis von NREVERSE ist immer EQ zum Argument: Bei Vektoren werden die Elemente paarweise vertauscht, bei Listen werden das erste und das letzte Element vertauscht und die Listenverkettung zwischendrin umgedreht. (14.2.) Zum Durchlaufen einer Sequence kann man statt MAP den zu DOLIST analogen Macro DOSEQ benutzen: (doseq (var seqform [resultform]) {declaration}* {tag|statement}* ) (14.3.) REMOVE, REMOVE-IF, REMOVE-IF-NOT, REMOVE-DUPLICATES liefern ihr Argument unver„ndert zurck, falls kein Element zu entfernen ist. DELETE, DELETE-IF, DELETE-IF-NOT, DELETE-DUPLICATES zerst”ren ihr Argument in folgendem Sinne: Ist das Argument eine Liste, so werden die CDR-Teile modifiziert. Ist das Argument ein Vektor mit Fill-Pointer, so wird der Fill-Pointer verkleinert und die zu behaltenden Elemente im Bereich unterhalb des neuen Fill-Pointer konzentriert. (14.5.) SORT und STABLE-SORT haben zwei zus„tzliche Keywords :START und :END: (SORT sequence predicate &key :key :start :end) (STABLE-SORT sequence predicate &key :key :start :end) SORT und STABLE-SORT sind identisch, weil mit Mergesort programmiert. KAPITEL 15 (Lists) ------------------ KAPITEL 16 (Hash Tables) ------------------------ (16.1.) MAKE-HASH-TABLE hat ein zus„tzliches Keyword :INITIAL-CONTENTS : (MAKE-HASH-TABLE &key :test :initial-contents :size :rehash-size :rehash-threshold) Das :INITIAL-CONTENTS-Argument ist eine Aliste, die zur Initialisierung der neu erzeugten Hashtabelle dient. Das :REHASH-THRESHOLD-Argument wird ignoriert. Zum Durchlaufen einer Hash-Tabelle kann man statt MAP den zu DOLIST analogen Macro DOHASH benutzen: (dohash (key-var value-var hash-table-form [resultform]) {declaration}* {tag|statement}* ) KAPITEL 17 (Arrays) ------------------- (17.1.) ARRAY-RANK-LIMIT = 2^16 = 65536 ARRAY-DIMENSION-LIMIT = 2^24 = 16777216 ARRAY-TOTAL-SIZE-LIMIT = 2^24 = 16777216 (17.6.) Ein Array, auf den ein anderer Array displaced ist, sollte nicht mit ADJUST-ARRAY so weit verkleinert werden, daž der andere Array ins Leere zeigt. Dies wird nicht berprft! KAPITEL 18 (Strings) -------------------- KAPITEL 19 (Structures) ----------------------- (19.5.) Zur :PRINT-FUNCTION - Option: Das Argument sollte eine Funktion der Gestalt (lambda (structure stream depth) (declare (ignore depth)) ... ) sein, die die externe Repr„sentation von structure auf den Stream ausgibt. Sie sollte dies tun, indem sie mit WRITE-CHAR, WRITE-STRING, WRITE, PRIN1, PRINC, PRINT, PPRINT, FORMAT o.„. Text auf den Stream ausgibt. Dabei gelten folgende Regeln: - Der Wert von *PRINT-ESCAPE* muž beachtet werden. - Der Wert von *PRINT-PRETTY* soll und kann nicht beachtet werden, da der Pretty-Print-Mechanismus von aužen nicht zug„nglich ist. - Der Wert von *PRINT-CIRCLE* braucht nicht beachtet zu werden; er wird vom System verwaltet. (Allerdings k”nnen nur solche Objekte in den Print-Circle-Mechanismus einbezogen werden, die auch (direkt oder indirekt) Komponenten von structure sind.) - Der Wert von *PRINT-LEVEL* wird von WRITE, PRIN1, PRINC, PRINT, PPRINT, FORMAT ~A, FORMAT ~S, FORMAT ~W und von FORMAT ~D,~B,~O,~X,~R,~F,~E,~G,~$ mit nichtnumerischem Argument beachtet. Der Print-Level-Mechanismus funktioniert daher automatisch, sofern nur diese Funktionen fr Objekt- Ausgaben benutzt werden und mit ihnen nicht tiefere Verschachtelungen ausgeben werden. (Der Print-Level-Mechanismus erkennt nicht, wieviele offene Klammern Sie ausgegeben haben, sondern nur, wie oft er rekursiv aufgerufen wurde.) - Der Wert von *PRINT-LENGTH* muž beachtet werden, insbesondere wenn Sie beliebig viele Komponenten ausgeben wollen. - Um die Werte von *PRINT-BASE*, *PRINT-RADIX*, *PRINT-CASE*, *PRINT-GENSYM*, *PRINT-ARRAY*, *PRINT-CLOSURE* brauchen Sie sich nicht zu kmmern. KAPITEL 20 (The Evaluator) -------------------------- Wie in SCHEME: Der Macro (THE-ENVIRONMENT) liefert in interpretiertem Code das aktuelle lexikalische Environment. Nicht compilierbar! (EVAL-ENV form [env]) evaluiert eine Form in einem gegebenen lexikalischen Environment (also so, wie wenn die Form im Programmtext dort gestanden w„re, wo das Environment herkommt). KAPITEL 21 (Streams) -------------------- (21.1.) Neben *TERMINAL-IO* gibt es einen weiteren Stream, der direkt mit dem Benutzer kommuniziert: *KEYBOARD-INPUT* ist der Stream, der die Tastendrcke von Tastatur liest. Er liefert jeden Tastendruck detailliert als Character mit folgenden Bits zurck: HYPER falls Sondertaste. Zu den Sondertasten z„hlen die Non-Standard-Tasten des Atari: Funktionstasten, Cursorblock, Ziffernblock, Delete-Taste. CHAR-CODE Bei normalen Tasten der Ascii-Code, bei Sondertasten: F1 -> #\F1, ..., F9 -> #\F9, F10 -> #\F10, Help -> #\Help, Undo -> #\Undo, Insert -> #\Insert, Delete -> #\Delete, ClrHome -> #\Home,  -> #\Up,  -> #\Down,  -> #\Left,  -> #\Right. SUPER falls mit Shift-Taste(n) gedrckt und sich ohne Shift ein anderer Code ergeben h„tte, CONTROL falls mit Control-Taste gedrckt, META falls mit Alternate-Taste gedrckt. Dabei wird nichts auf den Bildschirm ausgegeben. Er wird von *TERMINAL-IO* benutzt. Der Stream *PRINTER-OUTPUT* gibt Characters auf den Drucker aus. Sollte der Drucker nicht bereit sein, wird eine Warteschleife von bis zu *PRINTER-TIMEOUT* /200 sec. (Default: 5 sec.) eingelegt. (21.3.) Bei CLOSE wird das :ABORT-Argument ignoriert. KAPITEL 22 (Input/Output) ------------------------- (22.1.2.) Ein "Reserved Token", d.i. ein Token, das Potential-Number-Syntax besitzt und dennoch nicht als Zahl interpretiert werden kann, wird beim Einlesen als Symbol interpretiert. (CLTL S. 341 oben) Wird ein Token eingelesen, bei dem Package-Marker vorkommen, so wird nicht (CLTL S. 343 unten / S. 344 oben) berprft, ob der Package-Teil und der Symbolname-Teil nicht Zahlsyntax haben. (Wozu auch?) Wir behandeln also Tokens wie USER:: oder :1 oder LISP::4711 oder 21:3 als Symbole. (22.1.3.) Der Backquote-Readmacro funktioniert auch verschachtelt. Beispiel: (eval ``(,#'(lambda () ',a) ,#'(lambda () ',b))) = (eval `(list #'(lambda () ',a) #'(lambda () ',b))) = (eval (list 'list (list 'function (list 'lambda nil (list 'quote a))) (list 'function (list 'lambda nil (list 'quote b))) ) ) (22.1.4.) #\ erlaubt die Eingabe von Characters mit beliebigem Code: #\Code231 liefert das Character (code-char 231.). Zus„tzliche Read-Dispatch-Macros: #Y dient zum Einlesen von compilierten Funktionen. #" dient zum Einlesen von Pathnames: #"test.lsp" ist das Objekt (pathname "test.lsp") Wie in allen Strings, so mssen auch hier Backslashes doppelt geschrieben werden: #"A:\\programs\\test.lsp" (22.1.5.) Es ist nicht m”glich, mit GET-MACRO-CHARACTER die Read-Macro-Funktion eines Dispatch-Macro-Characters wie #\# zu holen. (22.1.6.) Die Ausgabe von Floating-Point-Zahlen erfolgt in Abwesenheit von SYS::WRITE-FLOAT bin„r. Pathnames werden bei *PRINT-ESCAPE* /= NIL in der Syntax #"namestring" ausgegeben, bei *PRINT-ESCAPE* = NIL wird nur der Namestring ausgegeben. *PRINT-CASE* kontrolliert nicht nur die Ausgabe von Symbolen, sondern auch von Characters und einigen #<...>-Objekten. *PRINT-PRETTY* ist ursprnglich = NIL. *PRINT-ARRAY* ist ursprnglich = T. Eine zus„tzliche Variable *PRINT-CLOSURE* kontrolliert, ob compilierte und interpretierte Funktionen (Closures) detailliert ausgegeben werden oder nicht. Compilierte Closures werden bei *PRINT-CLOSURE* /= NIL in wieder- einlesbarer #Y - Syntax ausgegeben. Zu Beginn ist *PRINT-CLOSURE* = NIL. (22.3.1.) Die Funktionen WRITE und WRITE-TO-STRING haben ein zus„tzliches Keyword :CLOSURE, mit dem *PRINT-CLOSURE* gebunden werden kann. (22.3.3.) Die FORMAT-Option ~W ist analog zu ~A und ~S, vermeidet jedoch das Binden von *PRINT-ESCAPE*. (FORMAT stream "~W" object) ist zu (WRITE object :stream stream) „quivalent. Mit FORMAT ~R und FORMAT ~:R k”nnen nur Integers n im Bereich |n| < 10^66 ausgegeben werden, die Ausgabe erfolgt auf Englisch mit amerikanischer Z„hlweise, und nur im Bereich |n| < 10^9 ist diese mit der britischen Z„hlweise identisch. FORMAT ~T ist in der Lage, von jedem Stream die aktuelle Spalte zu bestimmen. KAPITEL 23 (File System Interface) ---------------------------------- (23.1.1.) Pathname-Komponenten: HOST stets NIL DEVICE NIL oder :WILD oder "A"|...|"Z" DIRECTORY (Disknummer . Subdirs) wobei Disknummer = NIL oder die Seriennummer der Diskette ist, Subdirs = () | (subdir . Subdirs) subdir = :DEFAULT (Default-Directory des Device, nur als erstes subdir geeignet) oder subdir = :CURRENT (bedeutet ".") oder subdir = :PARENT (bedeutet "..") oder subdir = :WILD (bedeutet "...", alle Subdirectories) oder subdir = (name . type) name = :WILD oder Simple-String mit max. 8 Zeichen type = :WILD oder Simple-String mit max. 3 Zeichen NAME NIL oder :WILD oder Simple-String mit max. 8 Zeichen TYPE NIL oder :WILD oder Simple-String mit max. 3 Zeichen VERSION stets NIL (auch :WILD oder :NEWEST bei Eingabe) Wenn ein Pathname vollst„ndig spezifiziert sein muž (keine Wildcards), ist :WILD nicht erlaubt, bei NAME evtl. auch nicht NIL. Externe Notation: A123456:\sub1.typ\sub2.typ\name.typ mit Defaults: \sub1.typ\sub2.typ\name.typ oder name.typ oder *:\sub1.typ\*.*\name.* oder Žhnliches. (23.1.2.) Externe Notation von Pathnames (vgl. PARSE-NAMESTRING bzw. NAMESTRING), natrlich ohne Spaces, [,],{,}: [ [drivespec] ein Buchstabe '*'|'A'|...|'Z'|'a'|...|'z' [Seriennummer] ein Integer >=0, <2^24 in Dezimalschreibweise : ] { name [. type] \ } jeweils ein Unterdirectory [name [. type] ] Filename mit Typ (Extension) Als name und type sind dabei beliebig lange Zeichenfolgen (bestehend aus alphabetischen Characters und Underscores '_'), die dann auf 8 bzw. 3 Zeichen verkrzt und in Grožbuchstaben umgewandelt werden, oder ein einzelner '*' als Krzel fr :WILD zugelassen. NAMESTRING hat ein optionales Flag-Argument: (NAMESTRING pathname T) liefert eine frs Betriebssystem GEMDOS geeignete externe Notation eines Pathname. Die Funktion USER-HOMEDIR-PATHNAME ist nicht implementiert. (23.3.) FILE-AUTHOR liefert immer NIL. FILE-POSITION funktioniert fr jeden File-Stream. Wird ein NL auf einen File-Stream ausgegeben bzw. von einem File-Stream gelesen, so erh”ht sich dessen Position um 2, weil NL auf dem File als CR/LF abgelegt wird. (23.4.) LOAD hat zwei zus„tzliche Keywords :ECHO und :COMPILING. (LOAD filename &key :verbose :print :echo :if-does-not-exist :compiling) :VERBOSE T veranlažt eine kurze Meldung, daž eine Datei geladen wird. (Default: *LOAD-VERBOSE*, ursprnglich = T.) :PRINT T veranlažt, daž der Wert jeder Form ausgegeben wird. (Default: *LOAD-PRINT*, ursprnglich = NIL.) :ECHO T veranlažt, daž der Input von Datei ber *STANDARD-OUTPUT* auf dem Bildschirm mitprotokolliert wird, so daž man eine eventuelle Fehlerstelle im geladenen Programm sofort sieht. (Default: *LOAD-ECHO*, ursprnglich = NIL.) :COMPILING T veranlažt, daž jede der geladenen Formen sofort compiliert wird. Das Compilat wird sofort ausgefhrt und im Gegensatz zu COMPILE-FILE nicht in einem File abgelegt. Die Variable *LOAD-PATHS* enth„lt eine Liste von Directories, in denen - zus„tzlich zum angegebenen oder aktuellen Directory - Programmfiles bei LOAD, REQUIRE, COMPILE-FILE gesucht werden. (23.5.) (DIRECTORY [pathname [:full]]) kann in zwei Modi laufen: enth„lt pathname keine Name- oder Typ-Komponente, so wird eine Liste aller matchenden Directories geliefert. Ansonsten eine Liste aller matchenden Files bzw. (bei :FULL /= NIL) mit zus„tzlicher Information: eine Liste von Dreierlisten (file-pathname file-write-date-as-decoded-time file-length). (DIR [pathname]) ist wie DIRECTORY, liefert jedoch keine Werte, sondern zeigt die gefundenen Pathnames sofort an. (DIR) zeigt den Inhalt des aktuellen Directorys an. (CD [pathname]) verwaltet das aktuelle Device und das aktuelle Directory: (CD pathname) setzt es, (CD) liefert es. (MAKE-DIR directory-pathname) erzeugt ein neues Unterdirectory. (DELETE-DIR directory-pathname) l”scht ein (leeres) Unterdirectory. (EXECUTE programfile [args [space]]) ruft ein externes Programm programfile auf. args ist der Argumentestring (auch "Command Tail" genannt, Default ""). Dem Programm werden space Bytes zur Verfgung gestellt (Default: soviel das Programm braucht). KAPITEL 24 (Errors) ------------------- (24.1.) Nach Errors befindet man sich in einer Break-Schleife, in der man wie blich Formen auswerten kann und aužerdem ber die Help-Taste oder die ?-Taste eine Liste aller Kommandos bekommt. KAPITEL 25 (Miscellaneous Features) ----------------------------------- (25.1.) Der Compiler kann aužer mit den Funktionen COMPILE, COMPILE-FILE und DISASSEMBLE mit der Deklaration (COMPILE) aufgerufen werden. COMPILE-FILE hat folgende Form: (COMPILE-FILE input-file [:output-file] [:listing] [:verbose] [:warnings]). input-file sollte ein Pathname/String/Symbol sein. :output-file sollte nil oder t oder ein Pathname/String/Symbol oder ein Output-Stream sein. Default: t. :listing sollte nil oder t oder ein Pathname/String/Symbol oder ein Output-Stream sein. Default: nil. :warnings gibt an, ob die Warnings auch auf dem Bildschirm erscheinen sollen. :verbose gibt an, ob die Errors auch auf dem Bildschirm erscheinen sollen. Der normale Aufruf lautet (COMPILE-FILE input-file). (25.2.) Zu den Systemfunktionen ist keine Online-Dokumentation vorhanden. (25.3.) (TRACE fun ...) tracet die Funktionen fun, ... zus„tzlich. Format fr fun: Entweder ein Symbol symbol oder eine Liste aus einem Symbol und einigen Keyword-Argumenten (paarig!) (symbol [:suppress-if form] ; kein Trace-Output, solange form erfllt ist [:step-if form] ; Trace geht in den Stepper, falls form erfllt [:pre form] ; fhrt vor Funktionsaufruf form aus [:post form] ; fhrt nach Funktionsaufruf form aus [:pre-break-if form] ; Trace geht vor Funktionsaufruf in die Break-Loop, ; falls form erfllt [:post-break-if form] ; Trace geht nach Funktionsaufruf in die Break-Loop, ; falls form erfllt [:pre-print form] ; gibt die Werte von form vor Funktionsaufruf aus [:post-print form] ; gibt die Werte von form nach Funktionsaufruf aus [:print form] ; gibt die Werte von form vor und nach Funktionsaufruf aus ) In all diesen Formen kann auf *TRACE-FUNCTION* (die Funktion selbst) und *TRACE-ARGS* (die Argumente an die Funktion) und *TRACE-FORM* (der Funktions-/Macro-Aufruf als Form) und nach Funktionsaufruf auch auf *TRACE-VALUES* (die Liste der Werte des Funktionsaufrufs) zugegriffen werden, und mit RETURN kann der Aufruf mit gegebenen Werten verlassen werden. TRACE und UNTRACE sind auch auf Macros anwendbar, nicht jedoch auf lokal definierte Funktionen und Macros. Die Funktionen DESCRIBE, INSPECT sind nicht implementiert. (25.4.1.) Bei Decoded-Time muž Time-Zone nicht notwendigerweise ein Integer sein, sollte aber (als Float oder als Rational) Vielfaches von 1/4 sein. INTERNAL-TIME-UNITS-PER-SECOND = 200. (25.4.2.) Die Funktionen MACHINE-TYPE, MACHINE-VERSION, MACHINE-INSTANCE sowie SHORT-SITE-NAME, LONG-SITE-NAME sollte jeder Benutzer in seiner CONFIG.LSP- Datei definieren. Die Variable *FEATURES* hat ursprnglich den Wert (COMPILER INTERPRETER CLISP ATARI). Symbole, die mit ADJOIN zu *FEATURES* hinzugefgt werden, sollten im LISP- Package sitzen und exportiert werden, damit es bei Lesen von #+ und #- keine Probleme mit Packages gibt. Autoren: -------- Bruno Haible Michael Stoll Ritterstraže 42 Riesenfeldstraže 96 7500 Karlsruhe 1 8000 Mnchen 40 Druckfehler in CLTL =================== S. 10, Z. 1 v.o. Komma in der 1. Spalte fehlt S. 10, Z. 2 v.o. Doppelpunkt in der 1. Spalte fehlt S. 94, Z. 11 v.u. Streiche ")" S. 145, Z. 3 v.u. Links fehlt das Wort &environment S. 204, Z. 10 v.u. Ersetze "0.5" durch "1.0" S. 209, Z. 5 v.u. Ersetze "1-1/xý" durch "1/(1-xý)" S. 213, Z. 11 v.u. Ersetze "1-1/zý" durch "1/(1-zý)" S. 231, Z. 4 v.o. Ersetze "DATA" durch ":DATA" S. 242, Z. 4 v.u. Ersetze "false" durch "nil" S. 274, Z. 10 v.u. Ersetze "satisfy the test" durch "match" S. 280, Z. 20,19 v.u. Erg„nze "&key :key" bei assoc-if, assoc-if-not S. 281, Z. 12,11 v.u. Erg„nze "&key :key" bei rassoc-if, rassoc-if-not S. 322, Z. 13-12 v.u. Ersetze "evaluating the form" durch "applying the function to the arguments" S. 323, Z. 14 v.u. Ersetze "'eval-hook-function" durch "#'eval-hook-function" S. 323, Z. 15-13 v.u. hook muž compiliert sein, damit das funktioniert S. 324, Z. 2,3 v.o. Ersetze "2" durch "3" S. 394, Z. 16 v.u. Ersetze "~Scale factor ~2D: |~13,6,2,VE|" durch "~%Scale factor ~2D~:*: |~13,6,2,VE|" S. 396, Z. 4 v.o. Ersetze "x x x))" durch "x x x x))" S. 396, Z. 12 v.o. Ersetze "(foo 3.14E12)" durch "(foo 3.142E12)" S. 396, Z. 12 v.o. Ersetze "3.14L+12" durch "3.14E+12" S. 412, Z. 20 v.o. Ersetze "sion." durch "sion)." S. 417, Z. 15 v.u. Ersetze "directory-name" durch "directory and device" S. 417, Z. 14 v.u. Ersetze "host-name" durch "host" S. 452, Z. 23-24 v.o. Es fehlt der Eintrag: BOA 316 S. 453, Z. 1 v.o. Ersetze "common date type predicate 76" durch "common data type 35; 76" S. 454, Z. 28 v.o. erste Seitenzahl muž 67 lauten: defun macro 67; 54, ... S. 456, Z. 5 v.o. Das Wort "format" muž in Verbatim-Schrift erscheinen S. 458, Z. 20 v.u. erste Seitenangabe muž 113-114 lauten: macrolet special form 113-114; 57, ... S. 459, Z. 9 v.u. Seitenangabe muž 135 lauten: multiple-value-limit constant 135 S. 460, Z. 15 v.u. Seitenangabe muž 370 statt 370-373 lauten: pathname 13, 31, 370 S. 461, Z. 17 v.u. Ersetze "replacd" durch "rplacd": rplacd function 272-273; 263 S. 462, Z. 18 v.o. Ersetze 387 durch 386: *standard-output* variable 327-328; 329, 382, 386, 426, 441, 442, 443 S. 463, Z. 27 v.u. Ersetze 382 durch 332: stream-element-type function 332; 420 S. 463, Z. 26 v.u. streamp S. 463, Z. 7 v.u. tailp function 275 S. 465, Z. 13-12 v.u. Es fehlt der Eintrag: zerop function 195