Beschreibung wichtiger LISP-Systeme

 

LISP1.5 auf der IBM7090

Die zweite LISP-Implementation ist gut bekannt. Das Manual [MCC62c] stellteine Beschreibung der Nutzermöglichkeiten dar und gibt auch eine ganze Reihe von Hinweisen zur LISP-Implementation.

\subsection {Die Umgebung des LISP1.5-Systems: Anlage, Peripherie, Betriebssystem}

Die IBM7090 war ein 35-Bit, 32K-Worte-Rechner der zweiten Generation. Sie war als Nachfolgerin der Röhren-Maschine IBM709 vollständig kompatibel mit dieser und nahezu kompatibel mit der IBM704 (der Maschine des LISP1-Systems). Die Zykluszeit betrug 2.18 $\mu$s; 227 000 Instruktionen in der Sekunde wurden durchgeführt. Dies war gegenüber der IBM704 mit 40 000 Instruktionen pro Sekunde ein enormer Fortschritt. Für die LISP-Implementierung waren die drei Indexregister und die verfügbaren Transformationen zwischen Akkumulator (AC), Multiplikator-Quotient-Register (MQ) und den Indexregisternbedeutsam.

In den Worten befanden sich zwei 15-Bit-Anteile, die mit je einem Befehl geladen werden konnte: Dekrement und Adreßteil (PDX- und PAX-Befehl).Damit konnten Zeigerstrukturen verwirklicht werden.

Die IBM7090 verfügte über die Anfang 1960 übliche Peripherie, die schon Magnetplatten enthielt; daneben standen Kartenleser, Drucker, Konsole und Magnetbänder zur Verfügung.

Da damals umfassende ausgearbeitete Betriebssysteme noch nicht mitgeliefert wurden (statt dessen einer Programmiersprachen zugeordnete Verwalter, die die übliche Abfolge von Laden, Übersetzen und Ausführen steuerten, wie z.B. eines für das Assemblerprogramm SAP, eines für FORTRAN (das FORTRAN Monitor System) usw.), war für das LISP-System ein eigener Monitor aufgebaut worden. Dieses Programm, das OVERLORD hieß, erfüllte folgende Aufgaben [MCC62c][S. 31, 80ff]: Organisation der Arbeit mit den E/A-Geräten, Starten, Wiederherstellen und Retten der LISP-System-Varianten.

Am MIT standen 1962 sieben E/A-Geräte für die normale LISP-Arbeit zur Verfügung: Kartenleser, Drucker und fünf Magnetbandgeräte. Von den letzteren konnten drei wahlweise für normale E-/A-Aufgaben anstelle der sonst üblichen kartenorientierten Geräten eingesetzt werden: SYSPIT (Eingabe), SYSPOT(Ausgabe) und SYSPPT (Ausstanzen). Es war üblich, über eine IBM1401 dieKarten auf Magnetband zu übertragen bzw. die Magnetbänder auszudrucken. Die übrigen zwei Magnetbandgeräte dienten zur Verwaltung von Abzügen des Hauptspeichers. Eines nahm das Standardsystem auf, ein anderes das Nutzersystem. Das Standardsystem (auf SYSTAP) war der normale Ausgangpunkt für kleinereLISP-Programme. Es enthielt nur die Maschinenfunktionen und die im Manual beschriebenen symbolischen Ausdrücke für einige komplexe Funktionen (MAP-Familie). Hatte der Nutzer eine Reihe von LISP-Funktionen definiertund sich so eine spezielle Arbeitsumgebung geschaffen, so konnte er diese auf das zweite Band (SYSTMP) retten und im Fehlerfall immer wieder vondiesem festgehaltenen Zustand ausgehen. Auch auf diesem Band war dann ein Hauptspeicherabzug gespeichert, so da\ssdieses temporäre System bei späterenLäufen als Ausgangssystem dienen konnte. Mit speziellen Steuerkarten konnte der Anwender dafür sorgen, da\ssnach der Abarbeitung von bestimmtenEingabefolgen ein Basissystem wiederhergestellt wurde. Ebenso war es möglich, den neu erreichten Zustand auf SYSTMP festzuhalten. Zu diesemZweck kannte man folgende Arbeitsweisen (durch gleichlautende Steuerkarten eingeführt): TEST, SET und DEBUG.

Für den Benutzer charakteristisch war das Eingabeformat. Da die Funktion EVALQUOTE die eingelesenen LISP-Ausdrücke verarbeitete (toplevel), wurden immerzwei Informationen als zusammengehörig betrachtet: Funktionsname und Liste der (nicht auszuwertenden) Argumente. Diese Paare wurden als Doublettenbezeichnet. Im TEST-Betrieb wurde nun solange LISP-Eingabe von SYSPIT gelesen bis dieEndekarte STOP erreicht war. Dann wurde das gesamte System von SYSTMP herwieder auf den Anfangszustand gebracht. Im SET-Betrieb wurde nach derLISP-Verarbeitung durch die STOP-Karte ein Hauptspeicherabzug auf das BandSYSTMP geschrieben. Trat ein Fehler auf, so wurde wie im TEST-Betriebverfahren (der Hauptspeicherabzug konnte jedoch auch erzwungen werden). Der DEBUG-Betrieb unterschied sich vom TEST-Betrieb dadurch, da\ssnach demEinlesen der Doubletten die Objektliste abgehängt wurde, so da\ssalleInformationen (Symbole) nur geschützt waren, wenn sie wirklich benutzt wurden. Ein direktes Einlesen war dann allerdings nicht mehr möglich.

Das Einleseprogramm hatte die unangenehme Eigenschaft, bei Klammernfehlern aus dem Takt zu kommen. Waren insbesondere schließende Klammern vergessen worden, dann konnte es geschehen, da\ssbis zur STOP-Karte gelesen wurdeund diese sogar ignoriert wurde. Deshalb wurden dann und wann Karten mit vielen schließenden Klammern zwischen die Doubletten gelegt, um solch einen Proze\ssstoppen zu können. Vor bzw hinter STOP waren immer viele schließendeKlammern abgelocht (vgl. [SAU64c], S. 297, 305, 317).

Die Arbeit mit Hauptspeicherabzügen führte dazu, da\ssBasissysteme benutztwurden, die bestimmte nützliche LISP-Funktionen nicht als implementierte Unterprogramme enthielten, sondern als Adreßstrukturen in Listenspeicher, wie z.B. DEFINE.

 

Datentypen, Speicherplatzverwaltung, Garbage Collection

Der gesamte Speicher der IBM7090 war in acht Bereiche aufgeteilt. Der Lader, der zum Einlesen des gesamten Systems diente, nahm nur einen kleinen Teilbereich in Anspruch.

Dr LISP-Compiler und das Assemblerprogramm LAP belegten einen recht großenTeilbereich. Da diese Programme meist nur eine Zeitlang benötigt werden, wenn überhaupt, gab es eine Möglichkeit, um sie zu entfernen und so nützlichen Platz zu bekommen (EXCISE). Während der Compiler alsLISP-Programm vorlag [MCC62c][S. 76], ist dies von LAP nicht bekannt.

Das Programmiersystem selbst (OVERLORD, Interpreter und zugeordneteFunktionen) nahm etwa 7,5 K Worte (oktal 17 000) in Anspruch. Der Nutzer konnte über das Monitorprogramm OVERLORD die Aufteilung des Restes, der alsLISP-Speicher zur Verfügung stand, bestimmen. Die Standardauslegung des 7090-LISP ist nicht bekannt. Aus den Daten für das SHARE-LISP\footnote{Anhang I in der Ausgabe von [MCC62c} aus dem Jahre 1965.] kann man aber ableiten, da\ssdiese ca. 51 000(oktal) Worte, also etwas mehr als 20K Worte, in folgender Weise aufgeteilt waren: etwa die Hälfte für den Listenspeicher (free storage), ein Drittelfür compilierte Programme (binary program space (BPS)) und je ein Sechstel für Kellerspeicher und Zahlenbereich (push down list (PDL) bzw. full word storage (FWS)).

Der Listenspeicher diente zur Aufnahme der Listenstrukturen und der Atomstrukturen (P-Listen). Im BPS fanden nicht nur die compilierten Programme, sondern auch die Felder (arrays) Aufnahme. Der FWS war für Zahlenwerte, interne Namensdarstellungen (Printnamen) und die zu den Indikatoren SUBR bzw. FSUBR gehörigenBedeutungen (Sprünge zu den zugeordneten Routinen) gedacht.

Der Kellerspeicher war ein reiner Kontrollkellerspeicher (control stack), wenn nur interpretiert wurde. Bei der Verarbeitung compilierter Programme waren jedoch hier die lokalen Variablen abgespeichert. Diese standen dann neben den sonstigen hier geretteten Informationen (Rücksprungadressen, Zwischenresultaten und Teillisten bei der Steuerung rekursive Programme).

Die Zellen im Listenspeicher belegten je ein Wort der IBM7090. Damit verfügte das System im Normalfall über ca. 10000 Zellen (entspricht 80K Bytes auf IBM/360-kompatiblen Rechnern). Interessanterweise waren die Zeiger in den Worten, d.h. jeweils im Adreß- bzw. Dekrementteil, durch ihr Komplement dargestellt. Jedes Laden des Car bzw. Cdr benötigte daher mindestens drei Instruktionen: zwei für die Indexregistertransfers (der Akkumulator war nicht als Indexregister verwendbar) und eine AC-Ladeoperation. Um möglichst einfach arbeiten zu können, hatte man NIL die Adresse 0 (daher die sonst unverständliche Beziehung für die Funktion NULL!) und T die Adresse -1 gegeben\footnote{[MCC62c][S. 57]; vgl. dagegen die Darstellung des Komplements von T} als Oktal 1 000 000 im Widerspruch zu S. 36!

Die Zeiger belegten jeweils 15 Bit in den Worten, die übrigen drei Bits pro Zeiger dienten speziellen Zwecken (Verschlüsselung des Zahlentyps, Garbage-Collector-Marke usw.).

Da die Worte im FWS vollständig belegt waren und in ihnen kein Platz für Garbage-Collector-Marken frei war, mußten zwei getrennte Läufe des Garbage Collectors ausgeführt werden. Es ist nicht bekannt, ob diese immer nacheinander stattfanden oder getrennt, je nachdem, ob der jeweilige Bereich ausgeschöpft worden war.

Das Garbage Collection im FWS verwendete Bittafeln. Diese bestanden aus einer Folge von Worten, in denen jedem Wort des FWS ein Bit zugeordnet war. Für aktive Worte war das zugehörige Bit eingeschaltet, man konnte daher nach der Markierungsphase eine Liste freier Worte aufbauen und neuen Eintragungen zur Verfügung stellen.

Die dynamische Speicherverwaltung des Listenspeichers beruhte auf dem klassischen Garbage-Collection-Algorithmus. Die aktiven Zellen waren erreichbar, wenn man von der Objektliste (in der alle Atome stehen), dem zur Zeit benutzten Kellerspeicherteil und der Temlis, einer Liste von Zeigern, die von compilierten Programmen aus in den Listenspeicher führen, ausging.

Durch Verfolgung der Car-Ketten bis zu den Atomen wird jede aktive Zelle erreicht und falls noch nicht markiert, durch Setzen des Sign-Bits als zu rettende Information gekennzeichnet. Durch einen rekursiven Proze\sswird nach Verfolgung einer Car-Kette um einen Schritt in Cdr-Richtung weitergegangen und der gleiche Vorgang noch einmal ausgelöst. Die Markierung ist beendet, wenn das letzte Element des Cdr des S-Ausdrucks in der obersten Ebene erreicht ist. Wird ein Zweig angetroffen, der bereits markiert ist, so wird ebenfalls in der Cdr-Richtung weitergegangen.

Wenn die Markierungsphase beendet ist, mu\ssein linearer Lauf durch den gesamten Listenspeicher gemacht werden. Alle nicht markierten Worte werden zu einer Liste der verfügbaren Zellen (Freispeicherliste) zusammengehängt. In den markierten Zellen wird das Kennzeichenbit gelöscht.

Wie in [MCC62c][S. 90] angegeben, dauerte ein Garbage-Collection-Lauf etwa eine Sekunde.

 

Implementierte Funktionen

Die Menge die in LISP1.5 implementierten Funktionen galt lange als klassisches Vorbild. Während die I/O-Funktionen in den heutigen LISP-Systemen nicht mehr verwendet werden, sind die übrigen im allgemeinen doch anzutreffen.

Listenverarbeitung

{\small

Name Argumentzahl Typ Aktion Bemerkungen

CAR 1 SUBR Car eine Zelle Keine Prüfung ob Wert gültiger
Zeiger

CDR 1 SUBR Cdr einer Zelle Keine Prüfung, ob Wert gültiger
Zeiger

CONS 2 SUBR Konstruktion einer Zelle Löst Garbage
Collection aus

LIST bel. FSUBR Liste aus Argumenten FSUBR wegen
variabler Argumentzahl

RPLACA 2 SUBR Änderung des Car Physische Änderung
``Pseudofunktionen''

RPLACD 2 SUBR Änderung des Cdr Physische Änderung
``Pseudofunktion''

 

Name Argumentzahl Typ Aktion Bemerkungen

APPEND 2 SUBR Zusammenhängen von Listen 1. Liste wird
kopiert

NCONC 2 SUBR Zusammenhängen von Listen 1. Liste wird
physisch geändert.

REVERSE 1 SUBR Umkehren einer Liste Es wird kopiert

PAIR 2 SUBR Liste von gepunkteten Paaren aus den Elementen
der Listen Obwohl das Beispiel ([MCC62c], S. 60) als Ergebnis (($
(a_{1}$\*$b_{1})(a_{2}$\*$b_{2})$...) zeigt, scheint die Reihenfolge verkehrt
worden zu sein. Fehler bei ungleicher Listenlänge!

LENGTH 1 SUBR Länge der Liste  

SUBST 3 SUBR Substitution des
1. Arguments für
2. Argument im
3. Argument

SUBLIST 2 SUBR 1. Argument = Liste von gepunkteten Paaren. Im
2. Argument wird für jedes Atom, das als Car in einem Paar des 1. Arguments
vorkommt, der zugehörige Cdr eingesetzt. Kopiert

SASSOC 3 SUBR 2. Argument = Liste von gepunkteten Paaren. 1.
Argument wird als Car eines Paares im 2. Argument gesucht. Im Erfolgsfall:
Ergebnis = Paar; im Mißerfolgsfall: 3. Argument, eine Funktion ohne Argument,
wird aufgerufen. Funktional

EFFACE 2 SUBR Beseitigt 1. Vorkommen des 1. Arguments im 2.
Argument (top level). Physische Änderung, ``Pseudofunktion''

COPY 1 SUBR Kopiert Argument.

\vspace{3mm}

Durchgehende Eigenschaft der Listenmanipulationsfunktionen in LISP1.5 ist die auf Listen eingeschränkte Anwendbarkeit. Bis auf die von der Funktion her gegebene Abweichung SUBST testen alle Funktionen ein NIL-Ende ab. Dadurchsind unangenehme Fehler bei der Anwendung auf allgemeine S-Ausdrücke möglich.

Prädikate für die Listenmanipulation

{\small

Name Argumentzahl Typ Aktion Bemerkungen

ATOM 1 SUBR Atomtest  

EQ 2 SUBR Atomgleichheit Test auf physikalische Identität
der Zeiger

NULL 1 SUBR NIL-Vergleich Test, ob Zeiger = 0

MEMBER 2 SUBR 1. Argument wird als Element vom 2. Argument
gesucht (top level der Liste)

 

Name Argumentzahl Typ Aktion Bemerkungen

EQUAL 2 SUBR Gleichheitstest Strukturgleichheit von
S-Ausdrücken, EQ-Gleichheit von Atomen, numerische Gleichheit von ganzen
Zahlen, für Gleitkommazahlen mit Toleranz $3*10^{-6}$

Funktionale (Funktionen mit Funktionen als Argumente)

Name Argumentzahl Typ Aktion Bemerkungen

MAP 2 SUBR Anwendung der Funktion auf Liste und ihre Enden
(Cdr) Ergebnis: NIL

MAPCON 2 SUBR wie MAP Ergebnis wird aus Teilergebnissen
zusammengeschoben (NCONC)

MAPLIST 2 SUBR Wie MAP Ergebnis wird aus Teilergebnissen
aufgebaut (CONS)

SEARCH 4 SUBR Im 1.Argument wird Element gesucht, das Bedingung
(2. Argument) erfüllt. Erfolgsfall: Auf Element wird Funktion des 3.
Arguments angewandt. Mißerfolgsfall: 4. Argument wird mit Argument NIL
aufgerufen 2., 3., und 4. Argument sind Funktionen

\end {tabular}}
 
\vspace{3mm}
 
Die MAP-Funktionale in LISP1.5 bekommen die Parameterfunktion als 2.
Argument übergeben.

Arithmetische Funktionen

 
{\small
\begin {tabular}{c|c|c|p{4cm}|p{3.5cm}}
Name Argumentzahl Typ Aktion Bemerkungen

ADD1 1 SUBR Addition von 1  

DIFFERENCE 2 SUBR Subtraktion
1. Argument --
2. Argument  

EXPT 2 SUBR Potenz
1.$ Argument^{2. Argument} $ 1. Argument darf
nicht negativ sein. Ist eines der Argumente Gleichkommazahl, wird mit
logarithmen gearbeitet.

DIVIDE 2 SUBR Liste aus Quotient und Rest  

LEFTSHIFT 2 SUBR Verschiebung der Bitfolge nach links oder
rechts  

LOGOR bel. FSUBR Verknüpfung der Bitfolgen durch bitweises
``ODER'' Disjunktion; FSUBR wegen variabler Argumentzahl

LOGAND bel. FSUBR Verknüpfung der Bitfolgen durch bitweises
``UND'' Konjuktion; FSUBR wegen variabler Argumentzahl

LOGXOR bel. FSUBR Verknüpfung der Bitfolgen durch bitweises
ausschließendes ``ODER'' FSUBR wegen variabler Argumentzahl

MAX bel. FSUBR Maximum von Zahlen FSUBR wegen variabler
Argumentzahl

MIN del. FSUBR Minimum von Zahlen FSUBR wegen variabler
Argumentzahl

 

Name Argumentzahl Typ Aktion Bemerkungen

MINUS 1 SUBR Multiplikation mit --1  

PLUS bel. FSUBR Addition von Zahlen FSUBR wegen variabler
Argumentzahl

\vspace{3mm}

Bekommt eine arithmetische Funktion nicht die erforderlichen Zahlen als Argumente übergeben, so resultiert ein Fehler. Weitere Fehler treten auf, wenn die logische Funktionen (LOG...) oder LEFTSHIFT Gleitkommazahlenverarbeitet sollen, bzw. wenn durch 0 dividiert werden soll oder Gleitkommaunterlauf vorkommt.

Die Oktalzahlen (logische Zahlen) wurden nicht von den ganzen Zahlen unterschieden. Der Typ des Ergebnisses einer Rechnung wurde in üblicher Weise aus den Argumenttypen abgeleitet: Sind alle Argumente ganze Zahlen, dann ist auch das Ergebnis eine ganze Zahl. Tritt auch nur eine einzige Gleitkommazahl unter den Argumenten auf, so ist das Ergebnis eine Gleitkommazahl.

Arithmetische Prädikate

 

Name Argumentzahl Typ Aktion Bemerkungen

FIXP 1 SUBR Test, ob ganze Zahl
FLOATP 1 SUBR Test, ob Gleitkommazahl
GREATERP 1 SUBR Ist 1.A $>$ 2.A?
LESSP 2 SUBR Ist 1.A $<$ 2.A?
MINUSP 1 SUBR Test, ob Zahl $<$ 0
NUMBERP 1 SUBR Ist Zahl = 1 ?
ONEP 1 SUBR Ist Zahl = 1 ? Genauigkeit: EQUAL
ZEROP 1 SUBR Ist Zahl = 0 ? Genauigkeit: EQUAL

\vspace{3mm}

Auch die arithmetischen Prädikate (Ausnahme: NUMBERP) verlangen Zahlen alsArgumente. Die Typen sind mischbar. Gleichheit von Zahlen kann mit EQUALabgefragt werden (EQ ist nicht verwendbar).

Funktionen, die zur Steuerung des Programmablaufs dienen

Name Argumentzahl Typ Aktion Bemerkungen

AND bel. FSUBR Wert ist NIL, wenn eines der Argumente NIL
ist, sonst T. Verarbeitung bricht beim 1. Argument, das NIL ist, ab

OR bel. FSUBR Wert ist T, wenn eines der Argumente nicht
NIL ist, sonst NIL. Verarbeitung bricht ab beim 1. Argument, das
nicht NIL ist.

NOT 1 SUBR Wert ist T, wenn Argument NIL ist.  
Entspricht NULL; Compiler optimiert.

COND bel. FSUBR Die Argumente sind Paare: Bedingung -- Folge.
Die Bedingungen werden sequentiell ausgewertet, bis eine nicht NIL liefert,
die zugehörige Folge gibt den Gesamtwert. Steht COND nicht im PROG,
so wird Fehler gemeldet, wenn alle Bedingungen NIL liefern.

 

Name Argumentzahl Typ Aktion Bemerkungen

PROG bel. FSUBR 1. Argument = Liste von Atomen ( = lokale
Variable); weitere Argumente, falls Atome, sind Marken, sonst ``Anweisungen'';
Sprünge mit GO; Wert $\neq$ NIL mit RETURN Marken dürfen
beliebige literale Atome sein, auch lokale Variable

GO 1 FSUBR Sprunge zur Marke Argument mu\ssMarke im
aktuellen PROG sein; GO darf nur in einem COND auf PROG-Niveau
stehen

RETURN 1 SUBR Aktuelles PROG wird verlassen mit Argument als
Wert. RETURN darf an ``jedem Punkt'' stehen.

Funktionen zur Beeinflussung des Interpreters

Name Argumentzahl Typ Aktion Bemerkungen

COUNT 1 SUBR Aufstellung eines CONS-Zählers mit Grenze ( =
Argument). Sind n ( = Argument) Aufrufe von CONS abgearbeitet
worden, erfolgt Fehlerabbruch.

ERROR 1 SUBR Fehlerfunktion: Drucken einer Nachricht ( =
Argument) und Rückkehr ins höchste Programmniveau  

ERRORSET 4 SUBR 1. Argument: Auszuwertender Ausdruck, 2.
Argument: erlaubte CONS-Zahl, 3. Argument: Nachrichtauswahl
(T oder
NIL), 4. Argument: Liste. Tritt Fehler bei Auswertung vom 1. Argument
auf, so ist Gesamtwert NIL, sonst (LIST (EVAL 1. Argument)). Im
Fehlerfall werden Variablenbindungen zurückgestellt. Einrichtung von
Fehlerbehandlungsniveaus

EXCISE -- SUBR Schafft Platz durch Entfernen des Compilers.  
Kann nur einmal aufgerufen werden.

PAUSE -- SUBR Programm wartet. Weiterverarbeitung nach
Druck auf Maschinenknopf.

RECLAIM -- SUBR Auslösung von Garbage Collection Wert ist
NIL  

SPEAK 1 SUBR Wert: Anzahl der CONS-Aufrufe. Argument ist
NIL.

TEMPUSFUGIT -- SUBR Wert: NIL, Ausdruck einer
Zeitinformation.  

UNCOUNT 1 SUBR Abstellen des CONS-Zählers. Argument ist
NIL

Basishandlungen des Interpreters

Name Argumentzahl Typ Aktion Bemerkungen

APPLY 3 SUBR Anwendung der Funktion (1. Argument) auf
Argumentliste (2. Argument) unter Beachtung der A-Liste (3. Argument) Nur
für SUBR und EXPR erlaubt, wenn 1. Argument ein Atom. Argumente werden nicht
noch einmal ausgewertet.

EVAL 2 SUBR Auswertung des Ausdrucks (1. Argument) unter
Beachtung der Argument der A-Liste (2. Argument)  

EVLIS 2 SUBR Auswertung von Argumentlisten (1. Argument) unter
Beachtung der A-Liste (2. Argument).  

FUNCTION 1 FSUBR Behandlung funktionaler Argumente; Wert:
(FUNARG Argument A-Liste) Wichtig für Compilierung und Funktionen als
LAMBDA-Ausdruck mit globalen Variablen.

PROG2 2 SUBR 2. Argument ist Wert.  

QUOTE 1 FSUBR keine Auswertung des Arguments.  

SET 2 SUBR Zuweisung von Wert (2. Argument) zu Variable (1.
Argument), die in A-Liste gebunden ist.  

SETQ 2 FSUBR Wie SET Wie SET, nur 2. Argument wird
ausgewertet.

Arbeit mit der P-Liste von Atomen

Name Argumentzahl Typ Aktion Bemerkungen

ATTRIB 2 SUBR 1. Argument = Liste oder Atom, 2. Argument =
Liste;
2 Argument wird am Emde der Liste bzw. der zum Atom gehörenden P-Liste
physisch angefügt. Arbeitet vermutlich wie NCONC ohne sofort auf das
Ende (Atom) zu testen.
GET 2 SUBR In Liste bzw. P-Liste des Atoms 1. Argument wird
(mit EQ) nach 2. Argument gesucht Erfolgsfall: Wert ist nächstes
Listenelement; sonst: NIL Wert: NIL ununterscheidbar vom
Mißerfolgsfall.
PROP 3 SUBR In Liste bzw. P-Liste des Atoms 1. Argument wird
(mit EQ) nach 2. Argument gesucht Erfolgsfall: Wert ist Restliste nach 2.
Argument. Mißerfolgsfall: Funktion ohne Argumente (3. Argument) wird
aufgerufen. Wert: NIL unterscheidbar vom Mißerfolgsfall.
REMPROP 2 SUBR In Liste bzw. P-Liste des Atoms 1. Argument
wird (Mit EQ) nach 2. Argument gesucht. Jedes vorkommen wird, mit
zugehörigem nächstem Element entfernt. Entfernen bedeutet beseitigen.
Nicht NIL setzen

\vspace{3mm}

Die Menge der Funktionen für die P-Listenarbeit ist überraschend gering. Die üblichen Funktionen wie CSET, CSETQ, DEFINE DEFLIST, FLAG und {\ttREMFLAG} waren nicht implementierte Funktionen, sondern vom Typ EXPRbzw. FEXPR.

Die Benutzung von GET hat den deutlichen Nachteil, da\ssder Wert NIL vomVersagen der Anwendung dieser Funktion (d.h. wenn überhaupt kein passender Indikator existiert) nicht zu unterscheiden ist. Die Folge dieser Tatsache ist, da\ssdie dem Indikator APVAL zugehörige Bedeutung, mit der derInterpreter arbeitet, sich ein Niveau tiefer befinden muß.

Im LISP1.5 waren Flags nicht einzelne Elemente in der P-Liste, sondern Paare von Indikator und Bedeutung, wobei die Bedeutung NIL war. Aus diesem Grundewar GET nicht anwendbar ([MCC62c], S. 60).

 

Compiler und zugeordnete Funktionen

Name Argumentzahl Typ Aktion Bemerkungen
COMMON 1 SUBR Deklarierung von globalen Variablen für die Kooperation
von Interpreter und compilierten Funktionen. Für Variable, die in EXPR
gebunden sind und in SUBR verwendet werden und umgekehrt

COMPILE 1 SUBR Compilierung einer Folge von Funktionen.  
``Pseudofunktion''

LAP 2 SUBR Assemblierung einer Folge von Funktionen  
Assemblernotation mittels Listen

SPECIAL 1 SUBR Deklarierung von globalen Variablen für die
Kooperation von compilierten Funktionen. Für Variable, die in SUBR
gebunden und in SUBR verwendet werden

UNCOMMON 1 SUBR Aufheben von COMMON-Deklarationen.  

UNSPECIAL 1 SUBR Aufheben von SPECIAL-Deklarationen.

Ein- und Ausgabefunktionen

Name Argumentzahl Typ Aktion Bemerkungen

READ -- SUBR Ein S-Ausdruck wird von Syspit bzw. von
Kartenleser gelesen.  

PRINT 1 SUBR Ein S-Ausdruck wird auf SYSPOT bzw. Drucker
ausgegeben. Wert ist das Argument.

PRIN1 1 SUBR Ein Atom wird in den Druckbereich gestellt. Wert ist
das Argument

PUNCH 1 SUBR Ein S-Ausdruck wird auf SYSPPT bzw. Drucker und
Stanzer ausgegeben. Wert ist das Argument

TERPRI -- SUBR Druckbereich wird als nächste Zeile
ausgegeben. ``Pseudofunktion''

\vspace{3mm}

Die Druck- und Einlesefunktionen werden durch Funktionen der Zeichenmanipulation (ADVANCE, ENDREAD, STARTREAD) ergänzt. Im Normalfallbenutzt der LISP-Programmierer jedoch diese Funktionen nicht und arbeitet mit der von System automatisch veranlaßten Ein- und Ausgabe im Auswertungszyklus.

Die im LISP1.5 vorgesehenen Funktionen haben einen Mangel, der nur mit Mühe und durch aufwendige Programme auszugleichen ist: Die ausgegebenen S-Ausdrücke müssen nicht einlesbar sein. Dieser schwerwiegende Defekt (erklärlich durch die damals übliche beschränkte Arbeit mit Ein- und Ausgabedateien)

Funktionen zur Zeichenbehandlung: Einlesen und Verarbeiten

Name Argumentzahl Typ Aktion Bemerkungen

ADVANCE -- SUBR Nächstes Zeichen wird gelesen. Das zugehörige
Zeichenobjekt ist der Wert. CURCHAR hat denselben Wert wie
(ADVANCE);CHARCOUNT enthält Spaltennummer
ENDREAD -- SUBR Rest des Satzes wird ignoriert; Wert ist
\$EORS\$. CURCHAR ist \$EOR\$, CHARCOUNT undefiniert.

ERROR1 -- SUBR Aktuelles Zeichen auf Satz wird markiert. Ist
Satz fertig vorarbeitet, so wird ein samt Markierungen gedruckt.

STARTREAD -- SUBR Erstes Zeichen auf der nächsten Satz wird
gelesen. Das zugehörige Zeichenobjekt ist der Wert. CURCHAR hat
denselben Wert wie (STARTREAD); CHARCOUNT enthält 1. Besondere Reaktion
auf EOF.

DASH 1 SUBR Wert: T, falls Argument Minuszeichen, sonst
NIL. Argument ist Zeichenobjekt

DIGIT 1 SUBR Wert: T, falls Argument Ziffer (0 bis 9), sonst
NIL Argument ist ein Zeichenobjekt

LITER 1 SUBR Wert: T, falls Argument Buchstabe, sonst
NIL Argument ist Zeichenobjekt

OPCHAR 1 SUBR Wert: T, falls Argument Zeichen: $+$, -, /
oder $\*$, sonst NIL. Argument ist Zeichenobjekt

CLEARBUFF -- SUBR leert Zeichen-Puffer  

MKNAM -- SUBR Formt aus Zeichen-Puffer einen P-Namen; leert den
Puffer.  

NUMOB -- SUBR Formt aus Zeichen-Puffer die entsprechende
Zahl.  

PACK -- SUBR Packt Zeichen in Zeichen-Puffer. Argument ist
Zeichenobjekt
INTERN -- SUBR Aus P-Namen wird Atom geformt und in Objektliste
gestellt. Keine Aktion, wenn Atom bereits existiert.

CP1 1 SUBR Kopiert P-Namen.  

GENSYM -- SUBR Generiert Atom der Form G00001; dies ist nicht
in Objektliste.  

REMOB 1 SUBR Beseitigt Atom aus Objektliste.  

UNPACK 1 SUBR Aus P-Namen wird Liste von Zeichenobjekten
erzeugt!

\vspace{3mm}

ergibt sich aus der Existenz spezieller Atome (durch \$-Klammerung können Sonderzeichen im Atomnamen stehen: \$\$!A+ (B)! wird als A+ (B)ausgedruckt, denn dies ist der P-Name des Atoms; siehe [MCC62c][S. 84] undder Zeichenobjekte (character objects, vgl [MCC62c][S. 83ff.])).

Die Arbeit mit P-Namen und Zeichen ist deshalb so verwickelt im 7090-LISP1.5, weil die P-Namen aus Worten im FWS bestehen, in denen die internen Zeichendarstellungen dicht gepackt sind, während den Zeichen der Zeichenobjekte entsprechen, die selbst Atome sind und das entsprechende Zeichen als P-Namen haben.

Damit die Zeichenmanipulationsfunktionen mit diesen Zeichenobjekten möglichst schnell arbeiten können, wurde ihnen ein Bereich am Anfang des Speichers zur Verfügung gestellt, so da\ssjedes Zeichenobjekt die interne Adresse hat, diedem (BCD-)Code des zugeordneten Zeichens entspricht. Da diese Codes numerisch fortlaufend sind, können an den entsprechenden Stellen nur die Atomköpfe stehen, d.h. Atomzeiger und Zeiger auf die Liste. Arbeitet man mit einem Atom, dessen P-Namen aus einem Buchstaben besteht, so verwendet man intern das entsprechende Zeichenobjekt (allerdings ist unklar, wie sich Tin dieses Schema einordnete). Interessant an dieser Arbeitsweise ist nun, da\ssdie Zeichenobjekte, die den Ziffern 0 bis 9 entsprechen, als Zahlendargestellt sind, denn sie dürfen arithmetisch verknüpft werden ([MCC62c], S.85). In diesem Fall befindet sich demnach in dem Wort, das dem Code einer Ziffer entspricht, der Kopf einer Zahl ([MCC62c], S. 41).

Einige Zeichenobjekte können nicht als Atomsymbole verwendet werden, nämlich die Syntaxzeichen. Sie können nur mittels der \$-Klammerung oder über Atome angesprochen werden, deren Wert sie sind. Zu diesem Zweck sind die Atome DOLLAR, SLASH, LPAR, RPAR, COMMA, PERIOD, DASH STAR, BLANK undEQSIGNvorhanden.

Auch für die Codes, denen kein Zeichen in externer Darstellung entspricht, gibt es zugehörige Zeichenobjekte. Sie haben einen P-Namen, der sich aus dem Code und einer Klammerung zusammensetzt (z.B. \$IL77\$ für die Codekombination 77 (oktal)).

 

Der Interpreter

Der LISP1.5-Interpreter liegt gut dokumentiert vor ([MCC62c][S. 70ff.],obwohl dieses Programm nicht bis ins letzte Komma erst genommen werden muß \footnote{``Diese M-Ausdrücke dürfen nicht zu ernst (literally) genommen werden. In vielen Fällen macht das wirkliche Programm eine Speicher- bzw. Sprungoperation, wenn hier Rekursion verwendet wird''[MCC62c}[S.70]]. Erstellt den Prototyp eines Auswertemechanismus dar, der mit Call-By-Value und A-Listen-Verarbeitung ausgerüstet ist. Die Grobstruktur zeigt drei Funktionen, eine Kombination von APPLY, EVAL und EVALQUOTE. Eine gewisse Zahlvon zugeordneten Funktionen ({\tt EVCON, ELVIS, SASSOC, ERROR,LIST, CONS, PAIR, NCONC, GET, MAPLIST} und CAR-CDR-Kombinationen) erledigt zweitrangigeAufgaben.

Dem Programmierer tritt die Funktion EVALQUOTE entgegen, die dieQuotierung der Argumente unnötig macht und mit den zwei Argumenten (Funktionen und Argumentenliste) entweder EVAL (wenn der Funktionstyp FEXPR oderFSUBR ist) oder APPLY (sonst) aufruft.

Die eigentlich zentrale Funktion ist EVAL, die zur Auswertung beliebigerTerme benutzt wird. Ihre Argumente sind die auszuwertende Form (der Ausdruck) und die aktuelle A-Liste.

Die Auswertung der Atome ist durch die Suche von Variablen in der A-Liste bzw, die Suche nach dem Indikator APVAL in der P-Liste des Atomsgekennzeichnet. Dabei wirkt sich die Anwendung der Funktion GET insofernungünstig aus, da\ssfür die APVAL-Bedeutung eine zusätzliche LISP-Zellebenötigt wird (sonst wäre der Wert NIL nicht zu unterscheiden von demNichtvorhandensein des Indikators). Durch Anwenden der Funktion CAR wirdder APVAL-Wert, der ein globaler Variablen Wert ist, aus dieser Zellegeholt. Die Suche in der A-Liste wird entweder direkt durch SASSOC oderdurch eine interne äquivalente Funktion bewirkt.

Zahlen werden nicht ausgewertet -- sie selbst gelten als Ergebnis der Auswertung.

Die Auswertung von Funktionsaufrufen folgt einem einheitlichen Schema: Mittels GET wird nach dem funktionalen Indikator gesucht und mit dergefundenen Bedeutung weitergearbeitet, entsprechend den Richtlinien, die von der Art des Indikators abgeleitet werden können.

Die Notierung dieses Programms ([MCC62c], S. 71) ist uneffizient undunelegant. Das liegt einerseits an der Absicht, EVAL ohne PROG zuformulieren, eine Absicht, die für die theoretische EVAL-Funktion([MCC62c], S. 13) durchführbar und sinnvoll erscheint, bei der Beschreibungdes realen Interpreters aber fehl am Platze ist. Anderseits rührt dies her von der Beschreibung von Aktionen, die mit LISP nicht beschreibbar sind.

Bezüglich der Effizienz haben die Verfasser selbst schon vermerkt, da\sseinzelne Operationen anders implementiert sind, als hier ([MCC62c], S.70--71) beschreiben. Man kann aber in einem so zentralen Programmteil nicht zulassen, da\ssein und dieselbe Liste (die P-Liste der Funktion) viermal mitGET durchsucht wird, um einen funktionalen Indikator zu finden.

Ob die aus der Notation folgende Bevorzugung des Indikators EXPRbeabsichtigt ist, darf bezweifelt werden.

Verbal kann die Vorgehenweise gut beschrieben werden: Bei Funktionen des Typs EXPR werden die Argumente auswertet, und der LAMBDA-Ausdruck, alsnormale Bedeutung zum Indikator EXPR, wird über die Funktion APPLY aufdie ausgewerteten Argumente angewendet.

Bei FEXPR-Funktionen werden aus der Liste der Argumente und aus derA-Liste zwei unausgewertete Argumente hergestellt. Anschließend wird wie bei EXPR-Funktionen APPLY mit dem LAMBDA-Ausdruck als Funktion aufgerufen.

Die Verarbeitung der SUBR-Funktionen ist notwendig LISP-fremd notiert. Nachder Auswertung der Argumente und ihrer Verteilung auf Übergaberegister oder -bereiche (es waren nur bis zu 20 zugelassen) wird die Funktion angesprungen. Um die A-Liste zu schützen, wird sie vor dem eigentlichen Aufruf des Maschinencodestücks festgehalten.

FSUBR-Funktionen werden nahezu gleich behandelt. Hier sind die Argumenteohne Auswertung bestimmt: Das erste Argument ist die eigentliche Argumentliste, das zweite Argument die A-Liste.

FSUBR-Funktionen werden nahezu gleich behandelt. Hier sind die Argumenteohne Auswertung bestimmt: Das erste Argument ist die eigentliche Argumentliste, das zweite Argument die A-Liste.

Unverständlich in dem angegebenen Programm ist die besondere Herausstellung von QUOTE, FUNCTION, COND und PROG\footnote{Die Fußnote bezieht sich nurirrtümlich nicht auf COND}., da\sswenn die Fußnote beachtet wird. Diese besagtnämlich, da\ssim praktisch realisierten Interpreter keine besondere Behandlungerfolgt. Man beachte dabei, da\ssdas abgetrennte Bearbeiten von Sonderfällenein einfaches Effizienzproblem ist, wenn man von dem Problem absieht, da\ssnach erfolgter Abtrennung der Benutzer die entsprechende Funktion nicht neu definieren kann. Zugegebenermaßen ist dies für die zur Diskussion stehenden Funktionen selten der Fall. Die Effizienzfrage wird beantwortet durch Berechnen des durchschnittlichen Auftretens eines entsprechenden Funktionsaufrufs und die Zahl der erforderlichen Befehle. Durch die mehrfachen GET-Operationen ist allerdings der Code bereits so schlechtgeworden, da\ssderart feine Überlegungen nicht sinnvoll sind und eine Änderungnur eine weitere Verschlechterungen mit sich bringt. (Auch die oft auftauchende Funktion QUOTE wird auf langsame Art bearbeitet, die zweiVergleichsbefehle beeinflussen die übrigen Fälle unwesentlich.)

Funktionen ohne Indikator werden als lokale gebundene Variable angesehen und in der A-Liste gesucht. Wird auch hier nichts gefunden, so resultiert ein Fehler.

Wird ein Ausdruck ausgewertet mit einem allgemeinen Ausdruck in funktionaler Stellung, so wird dieser auf die Liste der ausgewerteten Argumente mittels APPLY angewandt. Es scheint aber sehr problematisch, die Argumenteauszuwerten, bevor der Typ der berechneten Funktion bekannt ist -- zudem widerspricht dies dem Verhalten bei Funktionsvariablen.

APPLY arbeitet mit drei Argumenten: Funktion, Argumentliste und A-Liste.In APPLY wird die Argumentliste bzw. werden die Argumente nichtausgewertet. Die Funktion darf nicht von Typ FSUBR oder FEXPR sein.

Recht unverständlich\footnote{Auf gleicher Ebene liegen neuere Festlegungen, z.B. in MacLISP [WHI77][S. 8], wonach Car und Cdr von NIL wieder NIL} sind. ist die erste Programmzeile in der Funktion APPLY: steht NIL infunktionaler Stellung, ist der Gesamtwert NIL. Die Programmierpraxis zeigtaber, da\ssNIL als Funktion nur auftaucht, wenn ein semantischer Fehlervorliegt. Es wäre besser, an dieser Stelle den Fehler zu melden, als den Konfliktfall weiter zu verschleppen.

Liegt ein Atom als Funktion vor, so wird nach dem Indikator EXPR gesuchtund APPLY erneut auf die zugeordnete funktionale Bedeutung und die beidenübrigen Funktionen angewandt. Falls dieser Indikator nicht gefunden wird, schließt sich die Suche nach SUBR an. Die Behandlung dieses Falls ähneltsehr der Verfahrensweise in EVAL, mit der Ausnahme, da\ssdie Argumente nichtausgewertet werden.

In allen andren Fällen wird das als Funktionen auftretende Atom in der A-Liste gesucht und erneut APPLY aufgerufen. Ähnlich wie in EVAL wird einFehler angezeigt, wenn keine lokale Bindung für das Atom existiert.

APPLY erlaubte vier verschiedene Arten von nichtatomaren Ausdrücken alsFunktionen: LAMBDA-Ausdrücke, LABEL-Ausdrücke, FUNARG-Ausdrücke undallgemeine Formen, die durch Auswertung auf eine Funktion führen.

Die LAMBDA-Ausdrücke lösen die grundlegenden Handlungen derVariablenbindung aus: Bevor der Körper des LAMBDA-Ausdrucks alsauszuwertende Form der Funktion EVAL übergeben wird, werden dieLAMBDA-Variablen mit den Argumente je nach ihrer Stellung gepaart und indie A-Liste gestellt. Die Ablösung der Bindung erfolgt schnell und einfach beim Verlassen von APPLY: Der Anfang der A-Liste war aufgehoben (gemerkt)worden und wird wieder als solcher verwendet, d.h., der vorübergehend aktive Teil wird regelrecht abgehängt. Diese Vorgehenweise zeichnet sich also durch die unkomplizierte Art aus, mit der die Variablenbindung ausgelöst bzw. aufgehoben wird.

LABEL-Ausdrücke sollten verwendet werden, wenn man implizit Funktionen inder Form von LAMBDA-Ausdrücken verwendet, die rekursiv sind. Um denWiederaufruf zu ermöglichen, bekommt die Funktion einen lokalen Namen. Dieser wird, zusammen mit seinem Wert, dem LAMBDA-Ausdruck, in die A-Listegestellt. Die notierte Verarbeitung mutet etwas ungeschickt an: Mit LAMBDA-Ausdruck, der Argumentliste und der veränderten A-Liste wird erneutAPPLY angesprungen, statt sofort weiterzuarbeiten. Allerdings mu\ssdieBeschreibung gerade an dieser Stelle nicht das wirkliche Verhalten schildern, weil z.B. LABEL [MCC62c][S. 101] der Indikator FSUBR zugeschriebenwird.

Die FUNARG-Ausdrücke erlauben die korrekte Lösung desVariablen-Umgebungs-Problems im A-Listen-Interpreter. Mit ihrer Hilfe ist es möglich, Funktionen, die in einer bestimmten Umgebung von globalen Variablen definiert wurden (das Problem steht also nur für implizite Funktionen in der Form von LABEL- bzw. LAMBDA-Ausdrücken; ``definieren'' heißt in diesemZusammenhang: als funktionales Argument binden) sowohl in tieferen Verschachtelungen (innere LAMBDA-Bindungsbereiche oder PROG-Blöcke) alsauch in äußeren Bindungsumgebungen (innen definierte Funktion als Wert nach außen gegeben) so abzuarbeiten, da\ssdie Variablenumgebung zur Definitionszeitbenutzt werden kann.

Zu diesem Zweck enthält der FUNARG-Ausdruck neben der Funktion die A-Listeder Definitionsumgebung. Diese wird während der Anwendung der Funktion auf die Argumente als gültige A-Liste benutzt.

Der Verarbeitung allgemeiner Formen durch APPLY erfolgt unproblematischeinfach: Die Form wird ausgewertet, und mit dem Ergebnis wird APPLY erneutaufgerufen. Die Argumente werden nicht mehr geändert.

Es ist reizvoll, diesen unvollständigen LISP1.5-Interpreter aus dem LISP1.5 Manual mit diesem wirklich verwendeten Programm zu vergleichen: mit dem von R.A.Saunders vorgelegten Interpreter für das Q-32-LISP, das compiliertund in das Gesamtsystem eingefügt worden ist [BB64][S. 384].

Es ist erstaunlich, wie viele Ähnlichkeiten dieses korrekt ausformulierte Programm zu dem in M-Sprache geschriebenen LISP1.5-Interpreter aufweist. Leider ist allerdings kein APPLY dabei. Die Atomauswertung unterscheidetsich (an der Marke V) nur durch die Aufnahme weiter Soderfälle undallerdings durch die Bevorzugung der lokalen von der globalen Bindung.

Die Behandlung atomarer Funktionen konnte im Q-32-LISP ausformuliert werden (übrigens ebenso wie die Ermittlung der globalen Atombindung), weil die Funktion CAR, auf Atome angewandt, die Wertzelle bzw. dieFunktionsdefinitionen beschafft. Nur die in LISP nicht ausdrückbare Aktion des Funktionsaufrufs der implementierten SUBR-Funktionen wird mit einerhier undefinierten Basisfunktionen (*EVQ) erledigt.

Die Schwäche, eine Form in funktionaler Stellung mit den ausgewerteten Argumenten weiter zu begleiten, teilt der Q-32-Interpreter mit dem EVAL aus [MCC62c]. Dagegen scheint die Behandlung von LAMBDA-Ausdrücken, dieunausgewertete Argumente übergeben bekommen, allenfalls sinnvoll in FEXPR-Definitionen auftauchen. Steht jedoch im FUNARG-Ausdruck einLAMBDA-Ausdruck, so bekommt diese Funktion ihre Argumente in der Tatunausgewertet -- eine sicher unerwünschte Konsequenz.

 

Der Compiler

Der von T.P.Hart und M.I.Levin nach Auseindersetzung mit dem LISP1-Compiler von R.Brayton entwickelte Compiler ist in LISP geschriebenworden [MCC62c][S. 76]. Anschließend war er in einem Bootstrap-Verfahrendurch sich selbst compiliert worden. Dieser Vorgang dauerte auf der IBM7090 5 Minuten. Das Resultat, der Assemblercode, wurde, wenn ein Systemband erstellt wurde, eingelassen und in Maschinencode übersetzt. Diese Prozedur war zu jeder Zeit eine unerhörte und einmalige Sache. Auch heute ist sie nur mit wenigen Programmiersprachen durchführbar.

Dieser Compiler ist der Stammvater einer ganzen Familie von LISP-Compilern. Seine exakte Form ist nicht bekannt, jedoch läßt er sich aus den verfügbaren, Quellen dem von R.A.Saunders veröffentlichten Compiler-Listing für denQ-32 [SAU64c] und dem leicht zugänglichen Listing des STANFORD LISP/360,verläßlich rekonstruieren.

Seine äußere Form ist gegeben durch die Aufteilung des eigentlichen Compilers in Vorpaß, Code-Generator und Assemblerprogramm LAP.

Der Vorpa\ssübernimmt die Arbeit der Erkennung globaler Variablen und ihrerKennzeichnung, damit der Code-Generator hier keine Mühe mehr hat. Funktionen, die Variablen enthalten, die für andere Funktionen global sind, werden so umgeformt, da\ssdie Aufrufe der Funktionen für die Errichtung und Auflösungder Bindungen in den Quelltext (d.h. in die Listenstruktur des EXPR)aufgenommen werden. Im Vorpa\sswerden funktionale Argumente mit implizitenFunktionsdefinitionen (Ausdrücke der Form (FUNCTION (LAMBDA...)) oder(FUNCTION (LABEL...)) ) aus dem Zusammenhang herausgelöst, alsselbstständige Funktion übersetzt und wie eine unabhängige Funktion behandelt. Der generierte Name für diese Funktion wird dann an der Stelle verwendet, wo die implizite Definition stand. Da einerseits der Name nicht vorhergesagt werden kann und anderseits die Variablenumgebungen nun völlig getrennt sind (deshalb müssen alle Variablen in der impliziten Definition, die dort nicht unmittelbar gebunden sind, ebenfalls als globale deklariert werden), können Verwendungen von funktionalen Argumenten dieser Art nur unbequem verwaltet werden und werden deshalb tendenziell eher durch explizite Definitionen und Zitierung des Namens bereinigt.

Der Vorpa\sssorgt weiterhin für die korrekte Verbindung zu Funktionen desFSUBR-Typs (kuriose Besonderheit: für Funktionen des FEXPR-Typs gibt eskeine Vorkehrungen), behandelt die wichtigsten Funktionen dieser Art dabei direkt, überträgt einige Funktionen (etwa SELECTQ oder CONC) inäquivalente Formulierungen und nimmt durch Beseitigung einfacher Rekursionen eine gewisse Quelltextoptimierung vor.

Der Hauptpaß, der Code-Generator, ist in fünf wesentliche Teile gegliedert: Ein Teil, die Funktion COMVAL, steuert die Verarbeitung des gesamtenProgramms und wird auch sonst immer benutzt, wenn Argumentausdrücke allgemeiner Art (d.h. Formen) zu übersetzen sind. Die Funktion sorgt für die offene Compilierung von SETQ, stößt die offene Compilierung von AND-,OR-, COND- und PROG-Aufrufen an und teilt die gewöhnlichen Ausdrückein Funktion und Argumentteil. Durch ein Zusammenspiel zweier Unterfunktionen (die fallweise COMVAL wiederaufrufen), von COMLIS, das für dieÜbersetzung der Argumentfolgen verantwortlich ist, und CALL, das dieeigentliche Parameterübergabe und die Befehlsfolge zum Funktionsaufruf generiert, wird die Bearbeitung im allgemeinen Fall bewältigt. Als weitere Sonderfälle werden GO (wenn es in COMVAL auftaucht, gilt dies alsfehlerhafter Gebrauch), RETURN, LIST und die Funktionen für dieVariablenbindung angesehen.

CALL mu\ssals zweiter wichtiger Teil bezeichnet werden, da die Übersetzungvon Funktionsaufrufen offenbar das Herzstück des Ganzen darstellt. Hier wären auch Verbesserungen anzubringen, wollte man etwa CAR und CDR in offeneUnterprogramme Umsetzen.

Die weiteren Hauptteile des Code-Generators sind die Programmstücke für die offene Compilierung von PROG (COMPROG), COND (COMCOND) sowie von AND undOR (COMBOOL). Sie verwenden für ihre Arbeit die schon erwähnten zweiProgrammteile, haben daneben eine Reihe von Unterfunktionen für den Zweck, Bedingungen ökonomisch zu übersetzen (COMPACT, CEQ). Die FunktionCOMCOND (für COND-Verarbeitung) enthält besondere Vorkehrungen für dieBehandlung von ``auslaufenden Aktivierungen von COND'', d.h. Aufrufen vonCOND, die keine Sicherung dagegen enthielten, da\ssalle Bedingungen falschsind. Diese Operation konnte abgestellt werden, wenn CONCOND von COMPROGaus aufgerufen wurde,wenn sich also der COND-Aufruf im PROG befand. Durchpassende Parameterübergabe zwischen COMVAL und COMPROG hatte man damitkeine Schwirigkeiten.

In COMPROG selbst werden zu Anfang Befehle generiert für dieInitialisierung der PROG-Variablen mit NIL, danach die Marken in eine Markenliste gesammelt. Durch die Bindung dieser Markenliste als lokale Variable in COMPROG wurde auf einfache Art abgesichert, da\sskeine Sprünge aus einem PROG-Niveau heraus übersetzbar waren.Die Übersetzung der Ausdrücke im PROG-Körper wurde im Normalfall über COMVALabgewickelt, nur COND-Ausdrücke lösten den direkten Ruf von COMVAL aus.

Die Technik der Argumentbehandlung von Funktionsaufrufen scheint schon damals auf Kosten der richtigen Übersetzung von Argumenten mit Seiteneffekten vorgenommen worden zu sein: Dadurch, da\ssquotierte oder atomare Argumentenicht in temporären Speicherbereichen gerettet wurden, sondern bei der Argumentübergabe erst geladen wurden, war es möglich (im Unterschied zu der Verfahrensweise im Interpreter), vordere Argumente durch später auftauchende SETQ-Aufrufe zu ändern.

Eine wesentliche Idee in diesem Compiler war die, Begrenzungsmarken zu verwenden, die gleichzeitig für den Wert eines Teilausdrucks und für den Ort verwendet wurden, an dem dieser Wert vorliegt. Für einen normalen Argumentausdruck, der selbst wieder Argumentausdrücke enthielt, wurde die Begrenzungsmarke nur als Wertbezeichnung im Compiler verwendet. Unter ihrem Namen wurde in einer Liste, die die temporären Speicherplätze beschrieb, die Adresse festgehalten, wo der Wert abgelegt wurde.

Wenn der Ausdruck jedoch ein COND- oder PROG-Ausdruck war, so wurde dieBegrenzungsmarke direkt in den Objekttext (LAP) abgesetzt und hatte nebender Funktion, Bezeichnung für den Wert des Ausdrucks zu sein, noch die, als Endemarke für alle Sprünge aus dem Ausdruck heraus zu dienen.

War das Objektprogramm, ein assemblerähnlicher Code, fertigt generiert so übernahm LAP (LISP assembly programm) die Steuerung, erzeugte denMaschinencode, ordnete ihn in den BPS an und veränderte die P-Liste der nun übersetzten Funktion so, da\sskünftige Aufrufe sie als SUBR benutzen konnten.

Insgesamt stellte dieser Compiler eine beachtliche Leistung dar, deren Voraussetzung in der Arbeit R.Braytons allerdings noch nicht geklärt ist.Wie die Anmerkungen in einigen Veröffentlichungen zeigen, waren allerdings Fehler noch lange Zeit vorhanden (siehe z.B. [MOS66]).

MacLISP

``MacLISP'' ist eine Sammelbezeichnung für am MIT benutzte LISP-Systeme. Neben lokalen Weitergaben [WHI77] existiert nur ein System, das von einemMacLISP-Standard ausgeht und ihn erreichen will [LAU76]. Die ReferenceManuale [MOO74] und die Beschreibungen von G.L.Steele und J.L.White über innere Details stellen die Hauptinformationsquellen über dieses System dar. MacLISP wird heute wesentlich benutzt für die Aufgaben der Formelmanipulation [BOG75], der automatischen Programmierung[MART74] und für die Programmierung in Bereichen der Künstlichen Intelligenz(vgl. [HEW71c, SUS71, WINO71]).

 

 

Die Umgebung des MacLISP-Systems: Anlagen, Peripherie,Betriebssysteme

Die drei MacLISP-Implementationen laufen auf zwei verschiedenen Rechnern auf drei verschiedenen Betriebssystemen: Eine Variante, gewissermaßen das Stammsystem, arbeitet auf einer pdp-10 unter dem Time-Sharing-System ITS [EAS72], die zweite, ebenfalls auf der pdp-10, läuft in dem von derHerstellerfirma gelieferten Betriebssysteme TOPS-10 [DECU] und die dritteVariante arbeitet im System MULTICS, [MUL73, COR65], dessen Rechnerkerngegenwärtig eine Honeywell H6180 ist. Die Variante unterscheiden sich hauptsächlich durch die vom Betriebssystem bereitgestellten Möglichkeiten. Neben den für den Nutzer unwichtigen Differenzen in der Implementierungstechnik liegen daher die wichtigsten Unterschiede in der Ein- und Ausgabe.

Die pdp-10 ist ein Rechner der dritten Generation, der sich auszeichnet durch seine Eignung für Time-Sharing und Listenverarbeitung. Ein ungewöhnlich großes Befehlsangebot (310 Instruktionen) macht diesen Rechner für den Programmierer interessant [DECA].

Um 1980 gab es drei Typen von pdp-10-Prozessoren: KA10, KI10 und KL10. Die letzteren waren schneller und leistungsfähiger, außerdem boten sie ein etwas größeres Instruktionsrepertoire [BEL78]. Alle Prozessoren verarbeiteten Worte von 36 Bits, die in einem Speicher untergebracht sind, dessen maximale Kapazität vom Prozessor abhängt. Intern verwandten die Prozessoren 18-Bit-Adressen und konnten so 265 K Worte verwalten (Nutzerraum). Dies war für den KA10 der gesamte Adreßraum, im KI100 und KL10 war dies aber nur der virtuelle Adreßraum, der für ein einzelnes Programm verfügbar war. Der physische Speicher konnte bis zu 4M Worte umfassen ([DECA], S. 5).

Die Geschwindigkeit hängt von der konkreten Ausrüstung ab -- es gibt unterschiedliche Speichertypen. Für den KA10 darf eine Zykluszeit von 1 $\mu$s und eine mittlere Befehlsausführungszeit (für einen Ladebefehl) von 2,8 $\mu$s erwartet werden. Die entsprechenden Daten für den KI10 sind: 1 $\mu$s, 1,5 $\mu$s (KL10 ist fünfmal schneller). Über die auf der pdp-10 (heute meist DEC-10) arbeitenden Betriebssysteme ist bei weitem nicht soviel veröffentlicht worden wie über das System MULTICS:

ITS [EAS72] ist der von den Programmierern des Laboratoriums für KünstlicheIntelligenz erstellte (lokale) Nachfolger für das CTSS\footnote{CTSS: Compatible Time-Sharing-System, ITS: Incompatible Time-Sharing-System}. Es hat eine extrem kurze Antwortzeit, wie es die Verhältnisse beim Betrieb von Robotern und ähnlichen Geräten verlangen. Die verarbeitbaren Dateien können auf allen Geräten liegen, die sequentielle Dateien aufnehmen können. Nur ganz geringe Vorsorge ist getroffen worden, um Direktzugriffsdateien in das LISP-System einzuordnen. Demgegenüber ist der Arbeit mit Terminals (Displays) große Aufmerksamkeit gewidmet worden. Eine ganze Reihe von verschiedenen derartigen Geräten ins besondere in der ITS-Implementation verfügbar [MOO74][S. 152]. ITS ermöglicht darüber hinaus (Subsystem Moby IO) sogar dieBildausgabe. Es enthält Möglichkeiten zur Echtzeitkontrolle bestimmter Geräte (Roboter) und bietet Zugriff zu einer großen Palette gewöhnlicher und ungewöhnlicher externer Geräte (Fernsehekameras, mechanische Hände, Bildschirme usw.; [MOO74][S. 170]).

TOPS-10 ist ein Betriebssystem, das sowohl Time-Sharing als auch Batch-Multiprogramming-Subsysteme besitzt [DECU]. Es ermöglich den Nutzerndie interaktive Arbeit an Terminals und erlaubt die übliche freie Arbeit mit Dateien (Files). Es ist allerdings nicht seitenorientiert [WHI77][S. 6].

MULTICS [MUL73] ist, zum Unterschied von den erwähnten beidenBetriebssystemen, international berühmt, viel besprochen und über viele Veröffentlichungen weithin bekannt. Es wurde am MIT als Nachfolger des CTSS seit 1965 entworfen und läuft seit etwa 1967. Zunächst für die GE645 implementiert (allerdings wurde, um möglichst Rechnerunabhängigkeit zu erreichen, PL/I verwendet), ist es seit 1974 auch auf dem Honeywell H6180 verfügbar (aus dem GE645 war nach der Fusion von General Electric mit Honeywell die H645 geworden). Diese neue Anlage scheint wesentlich mit dem Blick auf MULTICS entworfen zu sein, und viele vorher programmtechnisch erledigte Dienste nun die Maschine selbst im Hardwareniveau aus [LAB12, 13].Damit ist das Betriebssystem von der Anlage nicht mehr zu trennen, und nur konsequent spricht T. Kurokawa in seinem Vergleich verschiedenerLISP-Systeme von der ``MULTICS-Maschine''. Nach seinen Angaben erreichte die MULTICS-Maschine eine Zykluszeit von 0.5 $\mu$s und eine durchschnittliche Abarbeitungsrate von 650 000 Operationen in der Sekunde [KUR76d][S. 1057]. Für LISP weiterhin wichtig sind dievielfältigen File-Mechanismen, die das Betriebssystem bereitstellt und der praktisch unbegrenzte Speicher. ``In der MULTICS-Implementation gibt es immer genug Platz, so da\ssder Fehler `Speicher erschöpft' nie vorkommt''[MOO74][S. 105].

Die File-Orientierung der Betriebssysteme macht sich auch im LISP bemerkbar. So geht beispielweise der Compiler davon aus, da\ssein File in das LISP-Systemeingelesen wird. Dieses File besteht aus Deklarationen, Funktionsdefinitionen oder anderen LISP-Ausdrücken. Bei der Übersetzung wird dann ein File von compilierten Funktionen aufgebaut und ausgegeben, das später insgesamt geladen wird.

Die Peripherie der Anlagen am MIT entspricht dem internationalen Standard und geht darüber hinaus, wenn die verschieden Geräte im Labor für Künstliche Intelligenz betrachtet wird. Dabei sind die Geräte für interaktive Arbeit für den Nutzer besonders wichtig. Es würde jedoch zu weit führen, sie alle hier zu erwähnen.

 

Datentypen, Speicherplatzverwaltung, Garbage Collection

Bei allen MacLISP-Implementationen sind die dem Programmierer verfügbaren Datentypen gleich. Allerdings kann die Verfügbarkeit durch unterschiedliche Basisfunktionen differieren (gute Zeichenketten-Manipulation z.B. nur in der MULTICS-Version).

In Erweiterung des Angebots von LISP1.5 bietet MacLISP neue Datentypen an. Um eine Systematik in diese zu bringen, hat man atomare, nicht atomare undzusammengesetzte Datentypen unterschieden.

Atomare Datentypen sind Zahlen, Atomsymbole (literale Atome), Zeichenketten und SUBR-Objekte.

Zahlen können durch drei Typen von atomaren Objekten dargestellt werden: Es gibt Fixnums, Flonums und Bignums. Während Fixnums ganzen Zahlenentsprechen, soweit diese intern in einem Maschienenwort Platz finden, sind Flonums Gleitkommazahlen. Genauigkeit und Wertebereich der Flonums hängen von der Maschine ab (z.B. 8 Bit für Exponent, 27 Bit für Mantisse). Bignums sind beliebig große ganze Zahlen. Es ist praktisch unmöglich, einen Überlauf in der Bignum-Arithmetik zu erzeugen, da die Bignums durch Listen von Teilwerten dargestellt werden. Geht man davon aus, da\ssdie größte Fixnum auf der pdp-10 bereits $2^{35}-1$ ist, so kann man ableiten, da\sseine Bignum aus zweiElementen bereits bis $2^{70}-1$ reicht. Da in den MacLISP-Systemen immer mindestens 256K Worte verfügbar sind, kann man leicht die in diesem Bereich darstellbare größte Bignum ausrechnen. Sie ist unvorstellbar gro\ssund wird praktisch nie auftreten. Die Syntax der drei numerischen Datentypen unterscheidet sich nicht von der in LISP1.5 angegebenen, Bignums sind einfach ganze Zahlen (Integers), die nicht als Fixnums darstellbar sind.

Zeichenketten haben 0 und mehr Zeichen. Sie werden benutzt, um Nachrichten intern festzuhalten, oder wenn ein Text mittels Listenverarbeitung nicht günstig verarbeitet werden kann. Dann lohnt es sich, zur Zeichenkettenverarbeitung zu greifen, die allerdings nur in MULTICS-Implementation verfügbar ist.

Die normalen Atome, auch Atomsymbole oder literale Atome genannt, sind in der üblichen Art verfügbar. Eine Längenbegrenzung der Atomnamen ist nicht bekannt. Atome mit sehr langen Namen sollte man aber besser als Zeichenketten einführen. Hat ein Atom einen Namen, der kürzer als zwei Zeichen ist, so wird es Zeichenobjekt genannt.

Die Atome sind intern nicht in einer Liste oder in einer Liste von Hash-Buketts verfügbar, sondern in einem speziellen, mit Hash-Funktionen zugreifbaren Feld (Obarray). Der Nutzer kann dieses Feld austauschen und eigene Verwaltung der Atome durchsetzen.

Der letzte der atomaren Datentypen, der SUBR-Objekt-Typ, wird für diefunktionale Eigenschaft der implementierten bzw. compilierten Funktionen benutzt. Ein SUBR-Objekt stellt den ausführbaren Maschinencode dar. Es läßt sich nicht manipulieren; nur der Zeiger auf den Code ist nützlich.

Einziger nichtatomarer Datentyp sind die Listenzellen oder gepunkteten Paare oder, wie in MacLISP formuliert wird, das Cons. Es ist, nicht anders als in LISP1.5, eine Struktur, die zwei Komponenten enthält, die von beliebigem Typ sein dürfen.

Die kompositiven Typen zerfallen in drei Arten. Wir unterscheiden Felder, (arrays) Dateien (files) und Listenvektoren (hunks).

Felder sind Gesamtheiten beliebigen LISP-Objekte. Sie werden als Folgen von Zeigern dargestellt. Es sind beliebig viele Dimensionen erlaubt. Der Zugriff zu einem Feld erfolgt über ein Atom, das in der P-Liste eine Eigenschaft beim Indikator ARRAY hat. Für den Nutzer ergeben sich kaumNotationsunterschiede etwa zu ALGOL60, wenn zugegriffen wird. Das Speichern erfolgt mit Hilfe der Funktion STORE. Felder können nicht eingelesenwerden, sondern nur gebildet, benutzt und vernichtet ([MOO74], S. 5ff).

Die File-Objekte beziehen sich auf sequentielle Dateien in der `` externen Welt''. Sie haben Attribute (wie z.B. den Namen, die EOF-Adresse, dieZeilenlänge usw.) und können eröffnet (d.h. das Objekt wird gebildet) und geschlossen (d.h. vernichtet) werden. Die Zeichenfolge in der externen Welt kann gelesen oder geschrieben werden.

Alle Datentypen werden auf die verschiedene Arten intern dargestellt. Auch die Speicherverwaltung läuft in drei Varianten ab. Während bis 1973 nur eine Variante existierte (MacLISP unter ITS mit einer zu LISP1.6 vergleichbaren Verfahrensweise), kam im Laufe jenes Jahres die MULTICS-Version hinzu und 1974 die seitenorientierte Version (BIBOP). Unter TOPS läuft nur die alte Version, während unter ITS damit zwei verschiedene Systeme verfügbar sind.

Wichtigster Unterschied zwischen MULTICS- und pdp-10-Version ist die Größe des Adreßraums: Während das Betriebssystem MULTICS einen nahezu unbegrenzten Adreßraum zur Verfügung stellt (Adresse 35 Bit), arbeiten die beiden pdp-10-Varianten mit einem 256-K-Speicher (Adresse 18 Bit). BIBOP-Version und MULTICS-Version ist aber die Tendenz gemeinsam, da\ssdas GarbageCollection eher ein Mittel ist, das Wachstum des gesamten Speichers zu Gunsten seiner ökonomischen Ausnutzung zu bremsen als an einer Grenze anzuhalten. Hat man nämlich auf allen Seiten ein paar Stücke aktiver Speicherstrukturen, so wächst der Organitationsaufwand zu sehr, die Verarbeitung verlangsamt sich.

Die Aufteilung des Speichers ist in der MULTICS-Version und in der früheren pdp-10-Version recht ähnlich. Sie lehnt sich an die Festlegungen in LISP1.5 an. Der Speicher ist in Bereiche unterteilt, die im Hinblick auf das Garbage Collection festgelegt wurden. So unterscheidet man in der MULTICS-Version den Sektor für Listen, in den alle gepunkteten Paare, Listen, Atome, P-Namen, Bignums und Zeichenketten angeordnet werden, den für permanente Informationsblöcke (static storage) für Felder, Files und Verbinder zu compilierten Funktionen und zwei Kellerspeicher (ein Keller, in dem LISP-Objekte während des Garbage Collection gerettet werden, ist markedpdl,und ein Keller für reine Steuerinformationen ist unmarkedpdl). Für Zahlengibt es keinen gesonderten Bereich, da diese über virtuelle Zeiger implementiert sind.

In der älteren pdp-10-Version gibt es, ähnlich wie in LISP1.5, den Listenspeicher (free-storage) für Listen und Atome, den Speicher für Informationen die das ganze Maschinenwort belegen (FWS), d.h. für Zahlen, P-Namen und Zeichenketten, dann den Bereich für compilierte Funktionen und Felder (BPS) und schließlich die zwei Kellerspeicher (normaler Steuerungskellerspeicher, der auch temporäre Listen enthält und Spezialkellerspeicher, in dem die Variablenbindungen -- die SPECIAL-Zellen -- gerettet werden).

Über die interne Darstellung der Datentypen ist bezüglich der MULTICS-Version recht wenig bekannt. Die ältere MacLISP-Version arbeitet mit ähnlichen Formaten wie STANFORD LISP1.6.

Aufteilung und Darstellung im Fall der BIBOP-Version sind durch Steelerecht gut beschrieben worden [STE77b].

Hier ist der Speicher in typenreine Seiten aufgeteilt. Aus der Adresse kann ein Zeiger in eine Seitentabelle abgeleitet werden, woher Information über Typen beschafft werden kann. Die Seiten unterschiedlicher Typen können bunt durcheinandergemischt sein. Folgende Seitensorten sind möglich: Für Listen und gepunktete Paare (list), für ganze (fixnum) und Gleitkommazahlen (flonum), für die Wurzelzellen von Bignums (bignum) -- die Zahl selbst wird von einer Liste aus Fixnums gebildet --, für Atome zwei verschiedene Teiltypen: einmal die Atomwurzel mit Zeigern auf P-Liste und Atomblock und zum zweiten dieser Block mit Zeigern auf Wertzelle (die in Seiten des abgetrennten VALUE-Typs liegen), auf P-Namen (wie Bignum eine Liste vonFlonums) und anderen Informationen.

Felder werden auch in zwei Teilen abgespeichert: Die Feldbeschreibung (special array cell, SAR) aus zwei Worten macht den einen Teil aus, der Block von Daten den anderen Teil; der letztere steht im Bereich der compilierten Funktionen. Auch die Hunks, die Zeigerfolgen, die zwischen gepunkteten Paaren und Felder stehen, werden auf eigenen Seiten abgespeichert.

Das Spektrum der Datentypen wird komplettiert durch die verschiedenen Kellerspeicher: Neben dem üblichen Keller für Kontrollinformationen und dem für die Variablenbindungen verfügt MacLISP noch über zwei Zahlenkeller (jeweils für ganze und Gleitkommazahlen) für die schnelle Arithmetik ([MOO74], S. 114).

Die eigentliche Verwaltung des Speicherplatzes, die zum Aufruf des Garbage Collectors führen kann, wird mit Hilfe von drei Parametern, die jedem Teilbereich zugeordnet sind, durchgeführt. Diese Parameter gcsize, gcmaxund gcmin, geben die Einheiten von Zellen Auskunft über den Zeitpunkt unddie Möglichkeiten eines Aufrufs des Garbage Collectors.

Der Parameter gcsize gibt Auskunft über die erwartete Größe desTeilbereichs; solange Objekte in dem Teilbereich angeordnet werden können, ohne da\ssder durch gcsize bestimmte Umfang erreicht ist, wird kein GarbageCollection ausgelöst. Dies geschieht erst, wenn diese Grenze überschreiten werden soll.

Beim Garbage Collection werden die beiden anderen Parameter berücksichtigt: gcmax bezeichnet den maximalen Umfang, bis zu dem der Teilbereich wachsensoll -- hat dieser die angegebene Größe erreicht, ist die Wahrscheinlichkeit sehr hoch, da\ssumfangreiche Läufe des Garbage Collectors häufig auftretenwerden. Durch gcmin wird der minimale freie Speicherplatz nach dem GarbageCollection bezeichnet. Dieser kann entweder als Zahl von Zellen oder als auf den ganzen Teilbereich bezogene Prozentzahl spezifiziert werden. Kann der Garbage Collector nicht so viel freien Platzbeschaffen, wie durch gcminangegeben, so wird neuer Platz zugeordnet.

Ist es nicht möglich, diesem Platz bereitzustellen, entweder weil das Betriebssystem nicht dazu bereit ist oder wenn gcmax erreicht wurde, werdenUnterbrechungen ausgelöst. Im letzteren Fall kann der Nutzer entscheiden, ob er mehr Speicherplatz anfordern will, um weiterrechnen zu können, oder ob eine fehlerhafte Situation vorliegt und er aufhören sollte.

Diese Analyse und eine intelligente Steuerung der Speicherplatzverteilung sind durch den GC-Dämon möglich, ein Programm, das vom Programmierergeliefert werden kann und nach jedem Garbage Collection mit vielfältigen Informationen versorgt wird. Wie damit problemangepaßtes optimales Speichermanagement verwirklicht werden kann, diskutiert H.G.Baker in[BAK77b].

Über das Garbage Collection der pdp-10-Varianten ist wenig bekannt. Anscheinend wird der klassische Algorithmus (Vorarbeiten in Car-Richtung, dabei Retten der Cdr-Zeiger und rekursives Abarbeiten der Listenstrukturen). Immerhin ist sicher, da\ssBittafeln für die Markierung benutzt werden([STE77b], S. 7ff.), da die Zeiger keinen Platz für Markierungsbits lassen.Die Bittafeln holt sich der Markierer über die GC-Segmenttafel, eine ... ähnliche Beschreibung der Seiten wie die normalen Seitentafel. Bei der Sammlung der nicht markierten Datenelemente bedient sich der Collector wiederum dieser Tafel, da alle Seiten gleichen Typs durch Zeiger verbunden sind. So können dann Freispeicherlisten gebildet werden.

Etwas ungünstig bei dieser Lösung ist, da\sskeine Seiten freigemacht werdenkönnen. Nur der Feldspeicher kann so verwaltet werden, da\ssunbenutzter Platzwieder an den Reservepool zurückgeht. Wegen der gegenüber der MULTICS-Version (16K Worte pro Seite) geringeren Größe der Seiten (512 Worte) wirkt sich diese Unumkehrbarkeit nicht so stark aus.

Im MULTICS-MacLISP wird im Unterschied zu dieser Lösung ein kompaktierendes Garbage Collection eingesetzt. Es stammt von dem von Yochelsonimplementierten LISP für MULTICS [YO67,FEN69].

 

Implementierte Funktionen

MacLISP bietet eine große Fülle (über 290) von implementierten. Außerdem stehen viele in LISP geschriebene, aber compilierte und über einen schnellen Ladealgorithmus effizient zugreifbare Funktionsgruppen zur Verfügung.

Neben der äußerst aufwendigen Arithmetik liegen die Hauptunterschiede zu LISP1.5 in der erweiterten bzw. veränderten Menge der Ein- und Ausgabefunktionen und dem neuen Funktionstyp LSUBR (nicht zu vergessen dievielen anderen Verbesserungen, wie Makrozeichen usw., siehe S. 208ff.).

 

Listenmanipulationsfunktionen

Wie in LISP1.5 (vgl. Abschnitt 5.1.3.1) sind definiert:

CAR, CDR, LIST (allerdings LSUBR), {\tt REVERSE, LENGTH, RPLACA, RPLACD,SUBST, SUBLIST, SASSOC} (allerdings mit EQUAL arbeitend). Neu hinzugekommensind:

 

\vspace{3mm}

 

Name Argumentzahl Typ Aktion Bemerkungen

ASSOC 2 SUBR wie SASSOC. Mißerfolgsfall: Wert ist NIL  
Suche mit EQUAL

ASSQ 2 SUBR wie ASSOC Suche mit EQ

DELETE 2/3 LSUBR Mit 2 Argumenten: In Liste (2. Argument) werden
alle Vorkommen vom 1. Argument beseitigt;
Mit 3 Argumenten: Nur n( = 3. Argument) Vorkommen werden beseitigt.  
Physische Änderung, arbeitet mit EQUAL

DELQ 2/3 LSUBR Wie DELETE Arbeitet mit EQ

LAST 1 SUBR Wert: letztes gepunktetes Paar des
S-Ausdrucks. `` Letztes'' heißt: am Ende der Cdr-Kette

MAKNUN 1 SUNR Wert: Zahl zur S-Ausdruck. pdp-10: Adresse
MULTICS: Hasch-Code. Zwei strukturgleiche Ausdrücke haben nicht unbedingt
dieselbe Zahl.

MAKNUN 1 SUBR Wert: Der S-Ausdruck zur Zahl (Argument).  
Nicht zu jeder Zahl existiert ein S-Ausdruck!

NCONS 1 SUBR (CONS Argument NIL)  

NRECONC 2 SUBR (NCONC (NREVERSE 1. Argument) 2. Argument)  

NREVERSE 1 SUBR Wie REVERSE physische Operation

SXHASH 2 SUBR Wert: Hash-Zahl zu S-Ausdruck Strukturgleiche
Ausdrücke haben gleiche Zahl.

XCONS 2 SUBR (CONS 2.Argument 1.Argument)

\vspace{3mm}

Alle Mitglieder der CAR-CDR-Familie bis zur vierfachen Verschachtelung sinddefiniert. Weitere auf Listen anwendbare Funktion sind SORT und SORTCAR,die jedoch, weil sie hauptsächlich für Felder gedacht sind, in 5.2.3.13 beschrieben werden.

 

Prädikate für die Listenverarbeitung

Wie in LISP1.5 sind definiert: ATOM, EQ, EQUAL, NULL, MEMBER (liefertstatt T den Listenrest, beginnend beim gesuchten Element). Zusätzlichbietet MacLISP:

\vspace{3mm}

 


Name Argumentzahl Typ Aktion Bemerkungen

MEMQ 2 SUBR wie MEMBER (s:o) sucht mit EQ

STRINGP 1 SUBR T, falls Argument eine Zeichenkette, sonst
NIL.  

SUBRP 1 SUBR T, falls Argument ein Sub-Objekt, NIL
sonst.  
TYPEP 1 SUBR Wert ist ein Atom, das den Typ beschreibt.

 

Funktionale (Funktionen mit Funktionen als Argument)

Die Definition der Funktionale ist gegenüber der von LISP1.5 leicht geändert: Die Argumentfunktion, die jetzt grundsätzlich als erstes Argument anzugeben ist, darf mehrere Parameter haben. Je nach dieser Zahl bestimmt sich auch die Zahl der weiteren Argumente des Funktionals. Bei Anwendung der Argumentes Funktion auf die übrigen Argumente wird dann aus dem zweiten Argument des Funktionals das erste der Argumentfunktion abgeleitet usw.

Die Funktionen MAP, MAPCON und MAPLIST sind, wenn diese Änderungberücksichtigt wird, ihren LISP1.5-Vorbildern gleichwertig. Alle Funktionale sind vom Typ LSUBR.

Hinzugekommen sind:

\vspace{3mm}

 

Name Argumentzahl Typ Aktion Bemerkung

MAPC 2/bel LSUBR Wie MAP, nur wird jeweils der Dar der
Argumentliste verwendet.  

MAPCAN 2/bel LSUBR Wie MAPCON, mit Cars. Steht zu
MAPCON wie MAPC zu MAP.

MAPCAR 2/bel LSUBR Wie MAPLIST, mit Cars. Steht zu
MAPLIST wie MAPC zu MAP.

MAPATOMS 1/2 LSUBR Wendet Funktion 1. Argument auf alle
Elemente des aktuellen oder angegebenen (2. Argument) Obarrays an.

 

Arithmetische Funktionen

Die normalen arithmetischen Funktionen sind in drei Klassen eingeteilt. In der allgemeinen Klasse ist, wie in LISP1.5, Typenmischung möglich: Ist eines der Argumente eine Gleitkommazahl (Flomun), so ist auch das Gesamtergebnis von diesen Typ; ansonsten entsteht eine ganze Zahl, falls die Funktion ganze Zahlen zu ganzen Zahlen verknüpft und der Wert als solche darstellbar ist. Ist das nicht der Fall, wird eine große Zahl (Bignum) geliefert.

Die vier Grundfunktionen PLUS, TIMES, DIFFERENCE und QUOTIENT sindin dieser Klasse; damit PLUS und TIMES, wie in LISP1.5, beliebigviele Argumente haben können, sind sie vom Typ LSUBR. Dies trifft imUnterschied zu LISP1.5 (dort hatten die Funktionen zwei Argumente) auch für DIFFERENCE und QUOTIENT zu. ADD1, SUB1, EXPT und {\ttREMAINDER} sowie MINUS, MIN und MAX entsprechen ihren Vorbildern inLISP1.5; die beiden letzten sind nun vom Typ LSUBR.

In der Klasse der Fixnum-Arithmetik sind die wichtigsten Funktionen noch einmal vertreten; jetzt allerdings nur noch für Argumente den einheitlichen Typ ganzer Zahlen verlangend. Ähnliches gilt für die Klasse der Flonum-Arithmetik.

Zusätzlich existiert eine Reihe von Funktionen, die für verschiedene Typen von Argumenten zugelassen sind, aber nur einen Typ, meist Gleitkommazahlen, zum Wert hat.

Die Typenreinheit der Funktionen erlaubt es dem Compiler, aus den Funktionsnamen auf den Ergebnistyp zu schließen und so optimalen numerischen Code herzustellen.

Die gegenüber LISP1.5 neuen Funktionen sind:

\vspace{3mm}

 

Name Argumentzahl Typ Aktion Bemerkungen

$+$ bel. LSUBR wie PLUS Fixnumklasse

$-$ bel LSUBR wie DIFFERENCE Fixnumklasse

$\ast$ bel LSUBR wie TIMES Fixnumklasse

$/$ LSUBR 4 wie QUOTIENT Fixnumklasse

1$+$ 1 SUBR wie ADD1 Fixnumklasse

1-- 1 SUBR wie SUB1 Fixnumklasse

$\backslash$ 2 SUBR wie REMAINDER Fixnumklasse

$\backslash \backslash$ 2 SUBR wie GCD Fixnumklasse

$\wedge$ 2 SUBR wie EXPT Fixnumklasse

$+$\$ bel LSUBR wie PLUS Flonumklasse

--\$ bel LSUBR wie DIFFERENCE Flonumklasse

$\ast$\$ bel LSUBR wie TIMES Flonumklasse

$/$\$ bel LSUBR wie QUOTIENT Flonumklasse; berechnet
1/Argument, wenn nur ein Argument

1$+$ \$ 1 SUBR wie ADD1 Flonumklasse

1-- \$ 1 SUBR wie SUB1 Flonumklasse

$\wedge$\$ 2 SUBR wie EXPT Flonumklasse, 2. Argument muß
Fixnum sein

ABS 1 SUBR Betrag allgemeine Klasse

ATAN 2 SUBR arctan (1. Argument 2.Argument) Argument:
Fixnum/Flonum
Ergebnis:
Flonum

BOOLE 3/bel. LSUBR Verknüpfung der internen Bitdarstellungen
der hinteren Argumente nach Vorschrift 1. Argument Verknüpft von links
nach rechts. 1.Argument = 1 dann AND, = 7 dann OR, = 6 dann XOR

COS 1 SUBR cosinus (Argument) Argument:
Fixnum/Flonum
Ergebnis:
Flonum

EXP 1 SUBR (EXPT e Argument) Ergebnis: Flonum

FIX 1 SUBR Konversion Ergebnis: Fixnum/Bignum

FLOAT 1 SUBR Konversion Ergebnis: Flonum

GCD 2 SUBR berechnet größten gemeinschaftlichen Teiler  
Argumente: Fixnums oder Bignums

HAIPART 2 SUBR liefert n (= 2. Argument) Bits der internen
Darstel-
 
lung vom 1. Argument $n>0$, dann von vorn $n<0$, dann von hinten
HAULONG 1 SUBR Anzahl der signifikanten Bits  

ISQRT 1 SUBR wie SQRT, rundet Ergebnis: Fixnum

 

Name Argumentzahl Typ Aktion Bemerkungen

LOG 1 SUBR ln (Argument) Ergebnis: Flonum

LSH 2 SUBR Wie LEFTSHIFT  

RANDOM 0/2 LSUBR Liefert Zufallszahl nach Vorschrift
ROT 2 SUBR Rotiert interne Bitdarstellung.  

SIN 1 SUBR sinus (Argument) Argument: Fixnum/Flonum
Ergebnis:
Flonum

SQRT 1 SUBR berechnet Wurzel Ergebnis: Fixnum

\vspace{3mm}

Die Gleitkommaarithmetik kann durch den Wert des Atoms ZUNDERFLOWbeeinflußt werden. Ist dieser nicht NIL, so wird ein unterlaufendesResultat zu 0.0 gesetzt, ist der Wert NIL, wird ein Fehler ausgelöst.Außerdem gibt es noch eine stark von der Maschinenarchitektur der pdp-10 abhängige Funktion FSC, die aus zwei Zahlen eine Gleitkommazahl aufbautund dabei von der internen Darstellung ausgeht. Diese Funktion existiert nicht in der MULTICS-Version.

 

Arithmetische Prädikate

Identisch mit der Beschreibung von LISP1.5 verhalten sich NUMBERP, MINUSPund ZEROP. Die Funktionen FIXP und FLOATP sind ein wenig verändert,weil sie nicht ein numerisches Argument erfordern. Der LISP1.5-Funktion GREATERP entspricht $>$, die Funktion GREATERP ist nun LSUER und liefertnur dann T, wenn die Argumente eine streng monoton absteigende Folgebilden; entsprechendes gilt bezüglich LESSP in LISP1.5 und den Vertreternund LESSP (letzteres ist demnach LSUBR).

Weitere Prädikate sind:

\vspace{3mm}

 

Name Argumentzahl Typ Aktion Bemerkungen

BIGP 1 SUBR T, falls Argument Bignum, sonst NIL.  
Argument mu\sskeine Zahl sein.

ODDP 1 SUBR T, falls Argument gerade, sonst NIL.  
Argument: Fixnum oder Bignum.

PLUSP 1 SUBR T, falls Argument $>0$, sonst NIL.
SIGNP 2 SUBR T, falls 2. Argument dem Test 1. Argument
genügt, sonst NIL. 1. Argument = L, LE, E, N, GE, G; z.B.: le
bedeutet: 2. Argument ist $<0$.

$=$ 2 SUBR T, wenn Zahlen gleich, sonst NIL. Nicht für
Bignums verwendbar.

 

Funktion für die Steuerung des Programmablaufs

COND, AND, OR und NOT entsprechend ihren Vorbildern in LISP1.5weitgehend; COND ist allerdings so verallgemeinert worden, da\ssnicht nurein Folgeausdruck zugelassen ist, sondern eine ganze Reihe, die nacheinander ausgewertet werden (der letzte liefert den Gesamtwert). Ist keine Bedingung von NIL verschieden, so ergibt sich als Wert nun NIL -- ein Fehler wirdnicht mehr angezeigt.

Auch PROG, GO und RETURN haben ihre alte Bedeutung behalten. Es gibtgewisse kleine Unterschiede bei der Abarbeitung eines GO zwischenInterpreter und compilierter Funktion: Der Compiler hält sich recht genau an die LISP1.5-Definition, während unter dem Interpreter beispielsweise die Marken durch einen Auswertungsproze\ssermittelt werden können.

GO und RETURN dürfen in der neuen Funktion DO verwendet werden.Insgesamt sind neu:

\vspace{3mm}

 

Name Argumentzahl Typ Aktion Bemerkungen

DO bel. FSUBR 1. Argument: Liste von
 
Steuerinformationen, 2.Argument: Endetest und Exitformen.
Danach DO-Körper (= PROG-Körper).
Steuerinformationen: Liste mit: Variable, Anfangswert, Änderungsausdruck für
Zyklus.
 
Anfangswerte und Änderungen werden den Variablen parallel zugewiesen.  
Ist 2. Argument NIL, so wird der DO-Körper nur einmal abgearbeitet.
CATCH 1/2 FSUBR 1. Argument wird ausgewertet und der Wert als
Ergebnis geliefert.
 
Wird innerhalb des 1. Arguments (THROW y) ausgewertet, so wird {\
tt CATCH}
unmittelbar mit dem Wert y verlassen. 2. Argument ist eine
Identifizierung der THROW und CATCH-Ausdrücke.
THROW 1/2 FSUBR 1. Argument wird ausgewertet und zu letztem
CATCH zurückgegangen. Ist 2. Argument angegeben, so wird zugehöriges
CATCH ausgewählt.

\vspace{3mm}

Da MacLISP keinerlei Primitiva für Backtracking Prozesse, Koroutinen und ähnliches liefert, sind die mit CATCH und THROW möglichen nichtlokalenAusgänge das wichtigste Arbeitsinstrument für den Programmierer bei der Verwirklichung neuer Steuerstrukturen.

 

Funktionen zur Beeinflussung des Interpreters

MacLISP bietet dem Nutzer so viele Klassen von Funktionen zur Beeinflussung der Systemarbeit an, da\sshier nur dann eine übersichtliche Beschreibungerfolgen kann, wenn entsprechend dieser Aufteilung vorgegangen wird. Meistenteils haben diese Funktionen keine Entsprechung in LISP1.5.

\vspace{2mm}

\noindent5.2.3.7.1 Funktionen zur Erzeugung und Kontrolle von Fehlern

\vspace{1mm}

 

Name Argumentzahl Typ Aktion

ERROR 0/3 LSUBR Fehlererzeugung: 0 Argumente: keine Nachricht;
1. Argument: Argument ist Nachricht; 2 Argument: Nachricht setzt sich aus
Argumenten zusammen; 3 Argumente: Ist 3. Argument eine arbeitende
Nutzerfehlerbehandlungsroutine, so wird diese angesprungen. Liefert sie eine
Liste, so ist der Car der Wert von ERROR (korrigierter Fehler). Ist Wert
ein Atom, so arbeitet ERROR wie mit 2 Argumenten.

ERR 0/2 FSUBR 0 Argumente: wie (ERROR); 1 Argument: wird zu
ERRSET zurückgegangen, so ist Argument Ergebnis, sonst wie (ERR);
 
2 Argumente: (ERR x NIL) = (ERRx), (ERR
x T) sorgt für Auswertung von x (1. Argument) erst nach
Rückstellung der Variablen (in ERRSET).

 

Name Argumentzahl Typ Aktion

ERRSET 1/2 FSUBR 1. Argument wird ausgewertet. Tritt kein Fehler
auf, so ist Endwert: (NCONS Wert). Tritt Fehler auf,ist Endwert {\tt
NIL}. Wurde ERR aufgerufen, so bestimmt es den Wert von ERRSET.
Hat ERRSET 2 Argumente und ist 2, Argument = NIL, werden keine
Fehlernachrichten gedruckt. Andernfalls werden sie ausgegeben.

\vspace{3mm}

Man kann in gewissen Grenzen ERROR mit seinem Namensvetter und {\tt ERRSET} mit ERRORSET in LISP1.5 vergleichen.

Kehrt das System durch einen normalen Fehler oder durch einen vom Programmierer erzeugten (mittels ERROR oder ERR) in das Hauptniveau zurück, so beginnt wieder der normale Verarbeitungszyklus. Dies kann jedoch beeinflußt werden, indem der Variablen ERRLIST eine Liste von auswertbaren Ausdrücken (Formen) zugewiesen wird. Diese Liste wird dann abgearbeitet, wenn die Verarbeitung ins Hauptniveau zurückkehrt.

\vspace{2mm}

\noindent5.2.3.7.2 Unterbrechungen

\vspace{1mm}

Mit Hilfe der Funktion BREAK (FSUBR) können bedingte Unterbrechungen ausgelöst werden. BREAK hat zwei oder drei Argumente: das erste dient als Nachricht, es wird nicht ausgewertet; das zweite dient als Wert -- ist sein Wert von NIL verschieden, wird eine Unterbrechung ausgelöst.

In der Unterbrechung kann der Nutzer wie im Hauptniveau Ausdrücke auswerten lassen; dabei führen Fehler nur ins Unterbrechungsniveau zurück. Soll die Unterbrechung beendet werden, kann \$P oder (RETURN x) eingegeben worden war, NIL als Wert zurückgegeben werden, sonst der Wert dieses dritten Arguments. Im zweiten Fall ist der Wert von x der durch BREAK zurückgegebene Wert.

\vspace{2mm}

\noindent5.2.3.7.3 Kontrollzeichen

\vspace{1mm}

Durch Eingabe von Kontrollzeichnung kann der Benutzer sofortige Veränderungen im Verarbeitungsablauf auslösen (Erzeugung von Fehlern, Anspringen von Unterbrechungspunkten, Auskunft über aktuelle Arbeit usw. usf.). Normalerweise werden diese auf dem Terminal eingegeben und wirken sofort [MOO74][S. 92ff]. Mit den Funktionen IOC und IOG kann man ähnlicheEffekte auslösen; beide sind FSUBR-Funktionen.

IOC löst Interrups aus, wenn das Argument eine Zahl ist; derentsprechende Interruptkanal wird angesteuert. Ist das Argument ein Atom, so wird der erste Buchstabe im P-Namen als Kontrollzeichen interpretiert.

IOG rettet zunächst gewisse Systemzustände und verfährt dann mit seinemerster Argument ähnlich wie IOC mit seinem. Anschließend werden die übrigenArgumente nacheinander ausgewertet; das letzte liefert den Gesamtwert. Nach der Abarbeitung werden die Systemzustände wiederhergestellt.

\vspace{2mm}

\noindent5.2.3.7.4 Funktionen zur Beeinflussung des Fehlerbehandlungssystems

\vspace{1mm}

In MacLISP werden zwei Fehlertypen unterschieden: unkorrigierbare und korrrigierbare ...Entwicklung. Man vergleiche die Lösung in InterLISP. Hier kann der Programmierer mit eigenen Maßnahmenprogrammen versuchen, den Fehler auszugleichen und die Verarbeitung fortzusetzen. Die erfolgreiche Behandlung wird durch nichtatomare Werte der Behandlungsprogramme angezeigt; diese werden über Verbindungsvariablen, die den einzelnen Interruptkanälen zugeordnet sind, erreicht.

So ist der Wert der Variablen UNDF-FNCTN die Behandlungsfunktionen für den Interruptkanal 5, der aktiviert wird, wenn eine nichtdefinierte Funktion benutzt werden soll.

Mit Hilfe der Funktion NOINTERRUPT (SUBR mit einem Argument) können Interrupts aufgehoben werden, wenn das Argument T ist. So werden kritische Programmabläufe geschützt. Durch den Aufruf (NOINTERRUPT NIL) werden die hängende Interrups aktiviert und nacheinander behandelt.

Der Interruptkanal 3 wird durch die Funktionen ALARMCLOCK verwaltet: Der Wert der Variablen ALARMCLOCK ist die Behandlungsfunktion für die Interrupts; die Funktion ALARMCLOCK startet eine Zeitbegrenzung.

Diese Funktion hat zwei Argumente: Mit dem ersten wird die Zeitschranke gestellt oder aufgehoben. Ist eine solche Schranke erreicht, wird der Interruptkanal 3 aktiviert.

\vspace{2mm}

\noindent5.2.3.7.5 Funktionen für die Fehlersuche

\vspace{1mm}

Die Hauptfunktionen zur Fehlersuche, TRACE und UNTRACE, sind FSUBRs und bieten gegenüber den entsprechenden Funktionen von LISP1.5 erweiterte Dienste. Sie werden geladen als Paket, wenn sie zum erstenmal aufgerufen werden [MOO74][S. 223], und können mittels REMTRACE beseitigt werden.

Daneben existieren weitere Funktionen, die zur Erkundung einer Fehlersituation genutzt werden können. Obwohl nicht erwähnt, scheinen sie vor allem in der Nutzer-Interrupt-Behandlung Anwendung zu finden.

Diese Funktionen sind:

\vspace{3mm}

 

Name Argumentzahl Typ Aktion Bemerkungen
BAKTRACE 0/2 LSUBR Druck den Kellerspeicher der wartenden
Funktionsaufrufe. Argumente steuern Umfang der Liste.
BAKTRACE1 0/2 LSUBR Wie BAKTRACE, liefert zusätzlich
A-Listenzeiger. (MULTICS)
BAKTRACE2 0/2 LSUBR Wie BAKTRACE1, liefert zusätzlich
Kellerspeicherzeiger. (MULTICS)
ERRFRAME 1 SUBR Liefert eine Fehlerbeschreibungsliste,
bestehend aus Kellerspeicherzeiger, Nachricht, A-Liste usw. Mit dem
Argument kann Fehlersuche beeinflußt werden.
ERRPRINT 1 SUBR Wie ERRFRAME, druckt die Nachricht.  
EVALFRAME 1 SUBR Sucht im Keller Speicher nach der Auswertung
eines Funktionsaufrufs, liefert ähnliche Beschreibungsliste wie
ERRFRAME.
FRETURN 2 SUBR Zwingt Auswertung, zu dem durch den
Kellerspeicherzeiger (1. Argument) angegebenen Punkt zurückzugehen;
übermittelt zu benutzenden Wert (2. Argument).
$\ast$RSET 1 SUBR Veranlaßt den Interpreter, Informationen für
die Fehlersuchfunktionen bereitzustellen.

\vspace{3mm}

Wie es scheint, sind diese Funktionen noch nicht ausgereift. Überhaupt ist es ja schwierig, automatische Rettung aus fehlerhaften Situationen zu implementieren oder auch automatisch ausreichende Information über alle wichtigen Umstände einer Fehlersituation zu liefern. ... Fehlerbehandlung erreicht.

\vspace{2mm}

\noindent5.2.3.7.6 Funktionen zur expliziten Speicherverwaltung

\vspace{1mm}

Ähnlich wie in LISP1.5 kann der Benutzer von MacLISP selber einen Lauf des Garbage Collectors auslösen. Die Funktionen zur Information über den Speicherverbrauch gibt es nicht mehr: Es gibt ausreichend Platz, also auch keine Notwendigkeit, scharfe Kontrollen vorzusehen.

Die neuen Funktionen sind:

\vspace{3mm}

 

Name Argumentzahl Typ Aktion

GC  
  FSUBR Löst Garbage Collection aus, Wert NIL.

GCT 0/1 FSUBR Ermöglicht Beseitigung von unwichtigen
Atomen

ALLOC 1 SUBR Dynamische Festlegung der Speicherbeschreibung
(-auslegung).

\vspace{3mm}

Die Variable GC-Daemon ist der Anschlußpunkt für eine mögliche Funktion desNutzers, um nach jedem Garbage Collection in den Gang der Speicherverwaltung einzugreifen. Einen möglichen eigenen Verwalter hat H.Baker vorgeschlagen[BAK77b].

\vspace{2mm}

\noindent5.2.3.7.7 Die universellen Steuerfunktionen STATUS und {\ttSSTATUS}

\vspace{1mm}

Um die Aktivitäten logisch zu ordnen und zusammenzufassen, mit denen innere Systemzustände abgefragt und geändert werden können, sind die Funktionen STATUS und SSTATUS (Set STATUS) eingeführt worden.

Die Funktionen STATUS wird benutzt, um den Wert der verschiedenenSystemvariablen zu ermitteln. Das erste Argument ist ein Atom, das anzeigt, welche Funktion von STATUS erwartet wird, die möglichen weiteren Argumentehängen von dieser Funktion ab.

Es gibt STATUS-Funktionen, die sich auf das Ein- und Ausgabesystem, aufden Leser und den Drucker speziell, auf die Speicherverwaltung, auf das Garbage Collection, auf die Zeit, das Datum und das Betriebssystem beziehen und weitere bezüglich vieler anderen Einzelheiten einer speziellen Implementation. {\tt SSTATUS}, wie STATUS ein FSUBR, dient zur Veränderung derSystemparameter. Seine Argumente sind ähnlich wie bei STATUS aufgebaut.Beinahe zu jeder Erkundigungsaktion mittels STATUS gehört eine möglicheVeränderungsfunktion mittels SSTATUS.

\vspace{3mm}

 

Name Argumentzahl Typ Aktion
RUNTIME 0 SUBR Liefert CPU-Zeit in Mikrosekunden, die der
LISP-Job bisher beanspruchte.
SLEEP 1 SUBR Erzeugt Pause von n (Argument) Sekunden.
TIME 0 SUBR Wie RUNTIME, allerdings Echtzeit in Sekunden

\vspace{3mm}

\noindent5.2.3.7.9 Funkionen zur Kooperation mit dem Betriebssystem

\vspace{1mm}

Diese Funktionen sind von Betriebssystem zu Betriebssystem verschieden. Man kann diese wesentlichen Aktionen auch über die Kontrollzeichen auslösen. In der MULTICS-Implementation sind darüber hinaus noch die Funktionen QUIT(Beendigung der LISP-Arbeit), SAVE (Rettung einer entstandenenLISP-Umgebung) und CLINE (Ausführung eines MULTICS-Kommandos) vorhanden,während in der ITS-Implementation die Funktionen MACDMP (log-out oder Dumpwichtiger Bereiche) und VALRET, womit im wesentlichen ebenfalls dieLISP-Aktivität beendet werden kann.

 

Basishandlungen des Interpreters

Die Basisaktionen, wie Variablenbindungen, Ausdrucksauswertung und Funktionsanwendung, werden in MacLISP mit nahezu denselben Funktionen wie in LISP1.5 durchgeführt. Die Definitionen von EVAL und APPLY\footnote{APPLY} ist auch auf FEXPR- und FSUBR-Funktionen anwendbar.sind nur insofern geändert, da\sssie die A-Listen freie Verarbeitungunterstützen: Beide sind vom Typ LSUBR, die normalerweise ohne das letzteArgument verwendet werden, das sie in LISP1.5 hatten. In besonderen Fällen kann allerginds eine Art A-Listen-Zeiger übermittelt werden, mit dem eine Bindungsumgebung verändert werden kann.

QUOTE hat sich nicht geändert, FUNCTION entspricht QUOTE, nur da\ssderCompiler es für funktionale Argumente benötigt. Um die Aktionen des LISP1.5 bezüglich FUNCTION zu erzeugen (FUNARG-Ausdruck), gibt es*FUNCTION. Dies ist ein Ausdruck für die Seltenheit der Verwendung vonDefinitionsumgebungen gegenüber Bindungsumgebungen.

PROG2 wurde etwas erweitert: Als LSUBR definiert, kann es beliebig vieleArgumente (allerdings mindestens zwei) akzeptieren; der Wert wird durch das 2. Argument erzeugt.

\vspace{3mm}

 

Name Argumentzahl Typ Aktion Bemerkungen

ARG 1 SUBR Argument = NIL, Wert: Argumentzahl; Argument =
Zahl: Wert des i.
 
Arguments des Aktuellen LEXPR. nur innerhalb eines LEXPR sinnvoll.

ARRAYCALL bel: FSUBR Direkter Feldzugriff über einen Feldzeiger.
 
1. Argumenttyp der Feldelemente, 2. Argument der Feldzeiger, danach die
Indizes. Wird äußerst effizient compiliert.

COMMENT bel. FSUBR Ignoriert Argumente, liefert Wert:
COMMENT:  

FUNCALL bel. LSUBR Ruft die Funktion 1. Argument mit den
Argumenten 2. Argument, 3. Argument usw. Funktion darf kein MACRO
sein.

LISTIFY 1 SUBR Bildet Liste von n (= abs(Argument)) Argumenten
des aktuellen LEXPR. Ist Argument $>0$, so werden die ersten n Argumente
benutzt, sonst die hinteren.

LSUBRCALL bel. FSUBR Direkter Funktionsaufruf über SUBR-Zeiger.
1. Argument: Typ des Funktionswertes, 2. Argument: SUBR-Zeiger; da nach die
Argumente für die LSUBR. Wird äußerst effizient compiliert.

PROGN bel. LSUBR Wert = letztes Argument.  

PROGV bel. FSUBR Wertet erst 1. Argument und 2. Argument aus.
Dann Bindung der Variablen aus 1. Argument mit Startwerten aus dem 2.
Argument oder mit NIL. Dann Auswertung der übrigen Argumente wie bei
PROGN. Rückstellung der Variablen und Exit.  

BOUNDP 1 SUBR NIL, falls Atom ( = Argument) keinen Wert hat,
sonst T. Änderung von 1974 zu 1975.

MAKUNBOUND 1 SUBR Wert des Atoms (Argument) wird
beseitigt.  

SETARG 2 SUBR i. Argument (i = 1. Argument) des aktuellen
LEXPR wird geändert zu 2. Argument. Möglich nur innerhalb eines LEXPR.

SUBRCALL bel. FSUBR Direkter Aufruf einer SUBR über
SUBR-Zeiger. 1. Argument: Typ des Wertes der SUBR, 2. Argument: SUBR Zeiger,
ab 3. Arguments: die Argumente. Wird sehr effizient compiliert.

SYMEVAL 1 SUBR Argument mu\ssAtom sein, Wert ist Wert des
Atoms Wird sehr effizient compiliert.

\vspace{3mm}

Auch die Funktionen SET und SETQ sind in MacLISP verfügbar. In derfrüheren Version waren sie praktisch mit (PUTPROP Atom 'VALUE) identisch; in der BIBOP-Version, wo sich die Wertzelle nicht mehr in der P-Liste befindet, sind die Funktionen wieder eigenständig.

MacLISP läßt bei Verwendung von SETQ gleich eine ganze Reihe vonZuweisungen zu. Man kann dies an folgendem Schema sehen (dabei wird $Val_{n}$ als Gesamtwert verwendet):

(SETQ $Sym_{l}$ $Val_{l}$ $Sym_{2}$ $Val_{2}$ ... $Sym_{n}$ $Val_{n}$). SET unterscheidet sich nicht von der gleichnamigen Funktion in LISP1.5.

 

Arbeit mit der P-Liste von Atomen

Die Funktionen GET und REMPROP haben nicht geändert. Neu sind:

\vspace{3mm}

 

Name Argumentzahl Typ Aktion Bemerkungen

DEFPROP 3 FSUBR Gibt Atom (1.Argument) Bedeutung (2. Argument)
zum Indikator (3. Argument). Wert ist 1. Argument.

DEFUN bel. FSUBR Definiert Funktionen. 1.Argument: Name, 2.
Argument: Typ, 3. Argument: Parameterliste, ab 4. Argument: Körper. Fehlt
Typangabe, so EXPR. 1. und 2. Argument vertauschbar.

GELT 2 SUBR 1. Argument: Atom, 2 Argument: Liste von
Indikatoren. Wert ist P-Liste, beginnend mit dem ersten gefundenen Indikator
aus den 2. Argument.  

PLIST 1 SUBR P-Liste des Atoms (Argument).  

PUTPROP 3 SUBR Wie DEFPROP Wert ist 2. Argument.

SETPLIST 2 SUBR Gibt dem Atom (1. Argument) die P-Liste (2.
Argument).  

SYSP 1 SUBR NIL, falls Atom (Argument) keine Funktion vom Typ
SUBR, FSUBR oder LSUBR. Sonst dieser Indikator.  

ARGS 1/2 LSUBR 1. Argument: Atom mit SUBR-Eigentschaft. Wert:
Argumentzahl. 2 Argumente: Änderungen der Argumentzahl im 2. Argument. Nur
für compilierte Funktionen möglich.

\vspace{3mm}

In MacLISP werden folgende funktionale Indikatoren benutzt: {\tt EXPR, FEXPR, LEXPR} \footnote {LEXPR sind EXPR mit einer unbestimmten Argumentanzahl.Sie haben ein Atom anstelle der LAMBDA-Variablenliste; dieses Atom bekommtdie Argumentzahl zugewiesen. Zu den Argumenten wird mit ARG bzw. SETARGzugegriffen (vgl. 5.2.3.8).},{\tt MACRO, SUBR, FSUBR, LSUBR, ARRAY, AUTOLOAD}\footnote{für das Nachladen früher compilierter Funktionen; zugehörige Eigentschaft ist eine File-Spezifikation.}.

 

Compiler und zugeordnete Funktionen

Der Compiler in MacLISP liegt nicht als Funktion des LISP-Systems vor. Vielmehr wird er über ein Kommando aktiviert. Anschließend können gewisse Möglichkeiten spezifiziert werden (Options). Um den Compiler zu starten,mu\ssdann ein Inputfile (die zu übersetzenden Funktionen und Deklarationen)und ein Outputfile (der LAP-Code) angegeben werden. Es ist aber auch möglich,den Compiler anzuweisen, er solle direkt Objekcode liefern, der geladen werden kann.

Ende der siebziger Jahre waren zwei Compiler aktiv: der die Arithmetik optimierende NCOMPLR und die normale Version COMPLR.

LAP, das Assemblerprogramm, ist wie in LISP1.5 ein FSUBR. Allerdingsarbeitet es auf wesentlich andere Art -- nicht der gesamte LAP-Code mu\sspräsent sein, sondern er wird nach und nach eingelesen (LAP arbeitet ineinem Paß) ([MOO74], S. 194ff). Die übrigen Compilerhilfsfunktionenbeeinflussen die Deklaration von Funktionen und Variablen, den Einlesevorgang des Compilers und die Auslegung der Objektprogramme.

\vspace{2mm}

 

Name Argumentzahl Typ Aktion Bemerkungen

DECLARE bel. FSUBR Deklarationen für Variable (global/lokal),
aufgerufene Funktionen (Funktionstypen, Wertarten). Steuerung des Compilers.  

$\%$INCLUDE

1 FSUBR Schiebt File in Eingabestrom.  

NOUUO

1 SUBR Beeinflußt Aufrufmechanismen in
compilierten Funktionen.  

PURCOPY 1 SUBR Ordnet Argument in mehrfach benutzbare Seiten
an. Nur in BIBOP.

 

Ein- und Ausgabefunktionen

Die Ein- und Ausgabefunktionen von LISP1.5 sind in MacLISP weiterentwickelt worden. Der hauptsächliche Unterschied besteht in der freien Arbeitsweise mit den verschiedensten Ein- und Ausgabegeräten, die über Files angesprochen werden können.

Jedem File ist eine Reihe von Attributen zugeordnet (Name, EOF-Funktion,ENDPAGE-Funktion, Linelength, Characterposition, Charactercount, Pagelength,usw. usf.).

Neben den Funktionen für die Lese- bzw. Schreibaktionen stehen eine Reihe von Funktionen zur File-Manipulation zur Verfügung.

\vspace{2mm}

\noindent5.2.3.11.1 Lesefunktionen

\vspace{2mm}

 

Name Argumentzahl Typ Aktion Bemerkungen

READ 0/2 LSURB - 0 Argumente: Einlesen von normalem Eingabestrom.
 
- 1 Argument: Ist dies eine Filename, so wird von dort gelesen, sonst
gilt das Argument als EOF--Wert.
 
- 2 Argumente: Ein Argument ist Filename, ein Argument EOF-Wert für
READ
  NIL ist Name des Nutzerterminals.

READCH 0/2 LSUBR Liest ein Zeichen und liefert
Zeichenobjekt. Argumente wie bei READ

READLINE 0/2 LSUBR Liest Zeile ein und liefert
Zeichenkette. Argumente wie bei READ.

TYI 0/1 LSUBR Liest ein Zeichen und liefert Zahl, die dem Code
entspricht. Argument wie bei READ.

TYIPEEK 0/1 LSUBR  
- 0 Argumente: wie TYI, nur ist Zeichen nicht richtig gelesen.
 
- 1 Argument: sucht nach Argument im Eingabefile.
  Es wird nur auf das Zeichen ``gepiekt'' ohne es zu
``essen''.

\vspace{3mm}

\noindent5.2.3.11.2 Ausgabefunktionen

\vspace{3mm}

 

Name Argumentzahl Typ Aktion Bemerkungen

PRINT 1/2 LSUBR Erst wird die letzte Zeile ausgegeben, dann
wird 1. Argument gedruckt, dann ein Leerzeichen. 2. Argument gibt File
an. Fehlt es, wird normaler Ausgabestrom benutzt.

PRIN1 1/2 LSUBR Druck 1. Argument in wieder einlesbare Form
aus. Wie PRINT

PRINC 1/2 LSUBR Wir PRIN1; nicht notwendig wieder einlesbar
(Sonderzeichen,Zeichenketten ohne entspr. Syntax). Wie PRINT

TYI 1/2 LSUBR 1.Argument ist Zahl. Zugehöriges Zeichen wird
ausgegeben. Wie PRINT

TERPRI 0/1 LSUBR Gibt letzte Zeile aus. Argument gibt File
an. Fehlt es, wird normaler Ausgabestrom benutzt.

\vspace{3mm}

\noindent5.2.3.11.3 Arbeit mit Files

\vspace{3mm}

 

Name Argumentzahl Typ Aktion

ALLFILES 1 SUBR Liefert zu einem File-Bezeichnungsmuster alle
ähnlichen existierenden files.

CLEAR-IMPUT 1 SUBR Löscht gerade (physisch) gelesene
Eingabe.

CLOSE 1 SUBR Schließt File ab.

CURSORPOS 0/2 LSUBR Manipulation des Cursors; Zugriff zu
einzelnen Zeichen auf dem Bildschirm.

DEFAULTF 1 SUBR In File-Bezeichnung werden ausgelassene Stellen
ausgefüllt.

DELETEF 1 SUBR File wird beseitigt.

FILEPOS 1/2 LSUBR Liefert aktuelle Zeichenposition (als Zahl),
oder setzt die Position auf bestimmten Punkt.

FORCE-OUTPUT 1 SUBR Sendet Ausgabe unmittelbar an E/A-Gerät
(wenn sinnvoll).

EOFFN 1/2 LSUBR Ermittelt EOF-Funktion eines Imputfiles (1.
Argument) oder verändert diese (2 Argumente).

LISTEN 0 SUBR Liefert Zahl, wenn Terminal eingabebereit, wartet
aus Ausgabe.

MERGEF 2 u. mehr SUBR Setzt File-Bezeichnungen zusammen.

NAMELIST 1 SUBR Konvertiert File-Bezeichnungen (extern in
intern).

NAMESTRING 1 SUBR Konvertiert File-Bezeichnung (intern in
extern).

OPENA 1 SUBR Bildet ein Fileobjekt für die Ausgabe durch
Anfügen ein vorhandenes File.

OPENI 1 SUBR Bildet ein Fileobjekt durch Eröffnen eines
Eingabefiles.

OPENO 1 SUBR Bildet ein Fileobjekt durch Eröffnen eines
Ausgabefiles.

RENAME 2 SUBR ändert File-Bezeichnung.

SHORTNAMESTRING 1 SUBR Konvertiert File-Bezeichnung, in der
Directory oder Gerät nicht angegeben ist (intern in extern).

\vspace{3mm}

\noindent5.2.3.11.4 Veränderung der Systemeingabe

\vspace{1mm}

Die Funktion READ arbeitet in MacLISP mit einer Syntaxtafel, die für jedesZeichen ein Wort enthält (26 Syntax-Bits und ein Übersetzungszeichen, mit dem die Zeichen veränderbar sind, wenn sie in die internen P-Namen übernommen werden). Diese sogenannte READTABLE, ein Feld im Sinne derLISP-Datenkonventionen, kann vom Benutzer geändert oder ausgetauscht werden.

Die Eintragung einzelner Zeichen kann durch die Funktion SETSYNTAXgeändert werden (SUBR mit drei Argumenten). Das betreffende Zeichen wird alsZahl (ASCII-Code) oder als Zeichenobjekt angegeben (erstes Argument), die Änderung durch eine zweite Zahl (der Benutzer mu\ssder Bedeutung derSyntaxbits kennen ([MOO74], S. 159ff)) (zweites Argument) und dasÜbersetzungszeichen (drittes Argument). Es ist auch möglich, ein Zeichen als Macro einzusetzen. In diesem Fall mu\ssdas zweite Argument MACRO heißenund das dritte Argument die Makrofunktion bedeuten.

Der Austausch der READTABLE ist möglich durch Erzeugung einer Kopie mittelsMAKREADTABLE (SUBR, ein Argument), die einem Symbol eine Kopie der aktuellenREADTABLE als ARRAY. Eigenschaft zugeordnet. Da das Einleseprogrammdiese Eigenschaft als Wert des Symbols voraussetzt, kann durch

(SETQ READTABLE (GET (MAKREADTABLE ATOMX) 'ARRAY))

zu der Tafel übergegangen werden, die über das Symbol ATOMX zugreifbar ist.

\vspace{2mm}

\noindent5.2.3.11.5 Veränderung der Systemausgabe

\vspace{1mm}

Um die Systemausgabe zu verändern, sind bestimmte Attribute des Ausgabefiles zu verändern (Zeilenlänge, Anzahl vom Zeilen pro Seite usw.).

\vspace{3mm}

 

Name Argumentzahl Typ Aktion

CHARPOS 1/2 LSUBR Liefert aktuelle Zeichenposition (1
Argument) oder verändert sie (2 Argumente).

ENDPAGEFN 1/2 LSUBR Liefert aktuelle Seitenendefunktion (1
Argument) oder setzt neue ein (2 Argumente).

LINEL 1/2 LSUBR Liefert aktuelle Zeilenlänge (1 Argument) oder
verändert sie (2 Argumente).

LINENUM 1/2 LSUBR Liefert aktuelle Zeilenzahl (1 Argument) oder
verändert sie (2 Argumente).

PAGEL 1/2 LSUBR Liefert Zeilenzahl pro Seite (1 Argument) oder
ändert sie (2 Argumente).

PAGENUM 1/2 LSUBR Liefert aktuelle Seitenzahl (1 Argument) oder
ändert sie (2 Argument).

\vspace{3mm}

Der Druckvorgang kann nicht nur mit den angegebenen Funktionen gesteuert werden, sondern einige Variablen beeinflussen bestimmte Teilaktionen. So kann der Nutzer die Basis der Zahlen ändern (üblich: dezimal, also Basis 10), Zahlen mit sehr vielen Nullen verkürzen, das Drucken von komplizierten Listen an einem bestimmten Niveau aufhalten und die Zeilenlänge bei einem Druckvorgang begrenzen, so da\sskeine unendlichen Drucklisten entstehen können.

 

Zeichenmanipulation, Arbeiten mit P-Namen, Zeichenkettenverarbeitung, Arbeit mit OBARRAY

 

Alle Funktionen dieser Abteilung stehen für die kleine Klasse der Funktionen zur Zeichenmanipulation in LISP1.5. Dabei sind die Funktionen, die ein einzelnes Zeichen ausgeben oder einlesen (READCH, TYI usw.), schon unterden Ein- und Ausgabefunktionen erwähnt werden.

Die Zeichenverarbeitung in MacLISP wird durch Funktionen ausgeführt, die entweder einzelne oder Listen von Zeichenobjekten (weniger als zwei Zeichen im P-Namen) als Argument haben oder als Ergebnis liefern. Eine Besonderheit der Zeichenmanipulation in MacLISP liegt in der Äquivalenz von echten Zeichenobjekten (d.h. Atomsymbolen) und Zahlen (Fixnums), deren Wert dem ASCII-Code des Zeichens entspricht. Beide Formen können stets füreinander und miteinander gemischt auftreten.

\vspace{2mm}

\noindent5.2.3.12.1 Zeichenmanipulation

\vspace{3mm}

 

Name Argumentzahl Typ Aktion

ASCII 1 SUBR Formt aus Zahl Zeichenobjekt.

EXPLODE 1 SUBR Formt aus S-Ausdruck Liste von Zeichenobjekten,
die der Ausgabe durch PRIN1 entspricht.

EXPLODEC 1 SUBR Wie EXPLODE; Bezugsfunktion: PRINC.

EXPLODEN 1 SUBR Wie EXPLODEC; allerdings enthält die Liste
statt Zeichenobjekten die entsprechenden Zahlen.

FLATC 1 SUBR (LENGTH(EXPLODEC 1. Argument)).

FLATSIZE 1 SUBR (LENGTH(EXPLODE 1. Argument)).

IMPLODE 1 SUBR Aus Liste von Zeichenobjekten (oder
entsprechenden Zahlen) wird Atom gebildet (Name = Zeichenfolge) und falls
dort nicht vorhanden, in aktuellen OBARRAY aufgenommen.

MAKNAM 1 SUBR Wie IMPLODE, jedoch ohne Aufnahme in
OBARRAY.

READLIST 1 SUBR Aus Listen von Zeichenobjekten wird
entsprechender S-Ausdruck gebildet (als ob durch READ eingelesen).

\vspace{3mm}

\noindent5.2.3.12.2 Zeichenkettenmanipulation

\vspace{3mm}

Die Funktionen zur Zeichenkettenmanipulation sind nur in der MULTICS-Implementation verfügbar. Sie können immer auch auf normale Atomnamen (P-Namen) angewendet werden. Wenn der Wert einer solchen Funktion eine Zeichenkette sein soll, wird allerdings in jedem Fall eine Zeichenkette gebildet.

\vspace{3mm}

 

Name Argumentzahl Typ Aktion

CATENATE bel. LSUBR Hängt zwei Zeichenketten zusammen.

CTOI 1 SUBR Liefert 1. Zeichen als Zahl.

GET-PNAME 1 SUBR Formt P-Namen in Zeichenkette um.

INDEX 2 SUBR Liefert Position des 1. Vorkommens vom 2. Argument
im 1. Argument als Zahl.

ITOC 1 SUBR Formt aus Zahl (Code) Zeichenkette der Länge 1.

MAKE-ATOM 1 SUBR Liefert Atom, dessen P-Namen der Zeichenkette
entspricht.

STRINGLENGTH 1 SUBR Länge der Zeichenkette.

SUBSTR 2/3 LSUBR Liefert Teilzeichenkette von Position 2.
Argument bis Position 3. Argument (oder Ende). Position: Zahl. 1. Argument:
Zeichenkette.

\newpage

\noindent5.2.3.12.3. Arbeit mit P-Namen und OBARRAY

\vspace{3mm}

 


Name Argumentzahl Typ Aktion

ALPHALESSP 2 SUBR Argument sind Atomsymbole oder Zeichenketten.
Wert: T, falls in lexikalischer Ordnung, NIL sonst.

GENSYM 0/1 LSUBR Generiert neue Atome. Argument ist Zahl, wird
diese für den Ziffernteil verwendet, ist es ein Atomsymbol, so beginnen die
generierten Atome mit dem ersten Buchstaben von Argument.

GETCHAR 2 SUBR Liefert n Zeichen (n = 2. Argument) aus
dem P-Namen vom 1. Argument.

INTERN 1 SUBR Argument: Atomsymbol. Ist ein Atom mit gleichen
Namen im OBARRAY vorhanden, so ist dieses der Wert. Sonst wird das Argument
neu in den OBARRAY gestellt und ist selbst der Wert.

REMOB 1 SUBR Argument: Atomsymbol. Dieses wird aus OBARRAY
entfernt. Wert: NIL.

SAMEPNAMEP 2 SUBR T, wenn beide Argumente den gleichen P-Namen
haben, sonst NIL.

COPYSYMBOL 2 SUBR Ist 2. Argument NIL: Wert ist Atomsymbol
mit gleichen Namen wie 1. Argument, aber nicht im OBARRAY. Ist 2. Argument
T,wird auch die gesamte P-Liste vom 1. Argument kopiert.
MAKOBLIST 1 SUBR Liefert eine Kopie des aktuellen OBARRAY.

\vspace{3mm}

Der OBARRAY ist als Array und als Variable zugreifbar. So kann der OBARRAY direkt verändert werden oder das Symbol mit neuen Wert, die allerdings selbst Kopien des OBARRAY sein müssen, belegt werden. Dadurch ist es möglich, mitverschiedenen ausgelegten ``Namenslisten'' (vgl. S. 335) zu arbeiten bzw. den Standard-OBARRAY freizuhalten von unerwünschten Symbolmassen.

Mit den Ausdrücken:

(SETQ PRIVATE-OBARRAY (GET (MAKOBLIST 'PRIVATE-OBARRAY) 'ARRAY))

und

((LAMBDA(OBARRAY) (READ)) PRIVATE-OBARRAY)

kann ein Leseproze\ssmit einem eigenen OBARRAY gestartet werden.

 

Feldverarbeitung

Felder sind implementiert durch einen Bereich, in dem die Elemente stehen und eine Funktion, die zu dem Feld zugreift. Der Name dieser Funktion gilt als Name des Feldes -- insofern ist die ARRAY-Eigenschaft eine funktionaleEigenschaft.

Die Argumente der Funktion sind die Indizierungen (die immer mit 0 beginnen). Die Zugriffsfunktion liefert den Inhalt der adressierten Zelle und rettet gleichzeitig den Zeiger für eine eventuelle Speicheroperation.

Normalerweise werden die Elemente der Felder vor dem Garbage Collection geschützt. Es gibt eine spezielle Sorte von Feldern, bei denen dieser Schutz nicht durchgeführt wird. Eine weitere Feldsorte führt statt der Zeiger auf Zahlen die Zahlen direkt als Elemente.

Die Verarbeitungsfunktionen sind recht vielfältig:

\vspace{3mm}

 


Name Argumentzahl Typ Aktion

ARRAY 3 und mehr FSUBR Definiert Feld mit Dimension 3.
Argument, 4. Argument, ...; 1. Argument: Feldname, 2. Argument: Feldtyp.

*ARRAY 3 und mehr LSUBR Wie ARRAY, nur werden die
Argumente (LSUBR) vorher ausgewertet.

ARRAYDIMS 1 SUBR Argument: ARRAY-Zeiger oder Feldname. Wert:
Liste aus Typ und Dimensionen des Feldes.

BLTARRAY 2 SUBR Kopiert ein Feld in ein anderes. Dimensionen
nicht notwendig gleich!

FILLARRAY 2 SUBR Füllt Feld mit Elementen aus der Liste (2.
Argument).

LISTARRAY 1/2 LSUBR - 1 Argument: Bildet Liste aus Feldelementen;
 
- 2 Argumente: 2. Argument ist Längegrenze der zu erzeugende Liste.

*REARRAY 1 und mehr LSUBR Definiert Dimensionen eines
Feldes neu.

STORE 2 SUBR 1. Argument: Bezugnahme auf Feldelemente, 2.
Argument: Ausdruck, dessen Wert in Feldelement gespeichert wird.

SORT 2 SUBR 1. Argument: Feld oder Liste, 2. Argument:
Sortiertprädikat von 2 Argumenten. Ergebnis: sortiertes Feld oder sortierte
Liste.
SORTCAR 2 SUBR Wie SORT, nur werden jeweils die Cars der
Elemente verglichen.

DUMPARRAYS 2 SUBR Gibt Felder (1. Argument) in File (2.
Argument) aus.

LOADARRAYS 2 SUBR Lädt Felder (1. Argument) von File (2.
Argument)in Speicher zurück.

 

Der Interpreter

Der MacLISP-Interpreter folgt dem Schema des LISP1.6-Interpreters, der mit Call-By-Value und Wertzellen-Verarbeitung (d.h. shallow access) ausgerüstetist.

Im Vergleich zu LISP1.5 ist das Funktionensystem um LSUBR, LEXPR, ARRAYund AUTOLOAD erweitert. Inwieweit APPLY auch tatsächlich in die Strukturdes Interpreters eingebunden ist, geht aus den Dokumentationen nicht hervor. Die wesentliche Funktion ist jedenfalls EVAL; sie tritt dem Programmiererauch im LISP-Hauptniveau entgegen.

Argument von EVAL ist der auszuwertende Ausdruck und, auf besondereAnforderung des Nutzers, ein Zeiger in einen Kellerspeicherbereich, mit dem ähnlich gearbeitet werden kann, wie mit der A-Liste. Die Auswertung der Atome ist durch den direkten Zugriff zur VALUE-Zelle über das Atomgekennzeichnet. Im BIBOP-System ist dieser über zwei Ladebefehle vom Atomkopf her erreichbar. In den sonstigen Implementationen mu\sseine Suche nach dem VALUE-Indikator in der P-Liste durchgeführt werden. Dabei ist nicht ganzklar, ob dieser Indikator immer am Anfang der P-Liste stehen muß. Wäre dies nicht der Fall, könnte das P-Listenschema im MacLISP (wie in STANFORD LISP1.6) für Variablen mit vielen Eigenschaften ungünstig werden. Wenn EVALzwei Argumente gehabt hat, wird eine Suche der Kellerspeicher durchgeführt.

Wie allgemein üblich , wird die Auswertung von Zahlen und Zeichenketten sofort mit dem Argument selbst als Ergebnis beendet.

Die Auswertung von Funktionsaufrufen ist gegenüber LISP1.5 vereinfach und vernünftiger gestaltet worden: Es wird grundsätzlich die erste funktionale Eigenschaft benutzt. Damit ist auch der merkwürdige Fall ausgeschaltet, daß NIL in funktionaler Position akzeptiert wird.

Wird keine funktionale Eigenschaft bei dem Atom gefunden, so wird der Wert des Atoms ( VALUE-Eigenschaft) als neue Funktion benutzt.

Tritt der Indikator ARRAY auf, so liegt eine Referenz auf ein Feld vor. DieArgumente werden von links nach rechts ausgewertet und als Indizes benutzt; sie müssen in gleicher Anzahl wie die Felddimensionen vorliegen und Fixnums innerhalb der Grenzen sein.

Bezüglich der Indikatoren SUBR und FSUBR verläuft die Auswertung wie inLISP1.5. Allerdings dürfen die Funktionen maximal nur fünf Argumente haben. Die Behandlung von LSUBR-Funktionen unterscheidet sich vor derjenigen bei SUBR-Funktionen nur dadurch, da\ssauch eine Angabe über die Zahl derArgumente mitgeliefert wird.

Die Bedeutung zum Indikator FEXPR mu\ssein LAMBDA-Ausdruck sein, d.h.eine Funktion; diese mu\ssentweder ein oder zwei Parameter haben. Die Bindungdieser zwei Variablen wird ohne Argumentauswertung vorgenommen: der ersten wird die gesamte Argumentliste, der zweiten, falls sie auftritt, ein sogenannter A-Listenzeiger zugeordnet, der den Bindungsstand vor Betreten der Funktion widerspiegelt. Anschließend wird der LAMBDA-Körper ausgewertet.

Auch die EXPR-Bedeutung darf nur eingeschränkter Art sein entweder einAtom oder ein LAMBDA-Ausdruck. Liegt ein Atom vor, so wird dies als neueFunktion benutzt, und die Auswertung beginnt von vorn. Dabei werden die Argumente nicht ausgewertet!

Wird dagegen ein LAMBDA-Ausdruck entdeckt, so werden die Argumente vonlinks nach rechts ausgewertet. Bei der Bindung der Variablen sind wieder zwei Fälle zu unterscheiden: Steht hinter LAMBDA eine Liste von Variablen, somüssen genausoviele Argumente wie Parameter vorhanden sein. Jeder Variablen wird, nach Rettung ihres alten Wertes, das entsprechende Argument zugewiesen, d.h. in die Wertzelle eingespeichert.

Hat die Position hinter LAMBDA aber ein einzelnes Atom ($\neq$ NIL) inne,so wird diesem, ebenfalls nach Rettung des alten Wertes, die Argumentzahl als Wert zugewiesen. Die wirklichen Argumente sind mittels der Funktionen ARG und SETARG zugreifbar.

Dieser Spezialfall der EXPR-Verarbeitung wird auch LEXPR-Behandlunggenannt, obwohl der Indikator LEXPR nicht existiert.

Wird der Indikator MACRO gefunden, dann wird, wie bei FEXPR-Funktionenvorausgesetzt, da\ssein LAMBDA-Ausdruck die zugeordnete Bedeutung ist.Ansonsten ist die Verarbeitung sehr ähnlich der bei FEXPR; Unterschiedebestehen darin, da\ssder ersten Variablen nicht nur die Argumentliste, sondernder gesamte Ausdruck zugewissen wird. Das Ergebnis der Auswertung wird natürlich anders behandelt: Durch en ersten Auswerteproze\ssist das Makro``expandiert'' worden, anschließend wird der hergestellte Ausdruck als eigentlich auszuwertender Ausdruck angesehen und EVAL erneut übergeben.

Der letzte funktionale Indikator, AUTOLOAD, wird benutzt, um Funktionen voneinem externen File zu laden.

Die Verarbeitung von Ausdrücke (forms), die nicht ein Atom in funktionaler Stellung haben, folgt der Vorgehensweise von LISP1.5 in groben Zügen: Funktionen in Form von LAMBDA-Ausdrücken werden völlig gleichartig mit EXPR-Eigenschaften behandelt. LABEL-Ausdrücke werden durch Binden derVariablen mit dem funktionalen Ausdruck verarbeitet. Anschließend wird dieser, der als LAMBDA-Ausdruck vorzuliegen hat, gemeinsam mit dem Argumentals neuer auszuwertender Ausdruck angesehen: die Auswertung folgt dem FEXPR-Vorbild.

FUNARG-Ausdrücke unterscheiden sich nur insoweit von ihren äquivalenten inLISP1.5, als die dortige A-Liste in MacLISP durch einen A-Listenzeiger, d.h. einen Zeiger in der Variablen-Kellerspeicher, vertreten ist. Mit diesem wird der gleiche Effekt erzielt.

Man geht davon aus, da\ss LABEL- und FUNARG-Ausdrücke selten auftreten.

Fällt der funktionale Ausdruck nicht in einer dieser Klassen, dann wird er zunächst ausgewertet und der Wert an seiner Stelle als Funktion benutzt. Die Auswertung wird dann erneut gestartet.

Interessant für die Struktur des Interpreters ist die Art, wie die Hauptfunktionen EVAL und APPLY verknüpft sind: Während inLISP1.5-Interpreter beide Funktionen gleichwichtig waren und sich die auswertarbeit teilter, scheint in MacLISP die Funktion EVAL alle Arbeit zuerledigen. APPLY ist nur eine der vielen, im LISP-System ebenfallsauftretenden Funktionen.

Übrigens akzeptiert APPLY Funktionen und Argumente getrennt, weshalb MACRO-Funktionen als Argument nicht zugelassen sind. Die Argumente aus derListe, die als zweites Argument APPLY übergeben werden, werden grundsätzlichnicht noch ein mal ausgewertet.

 

Der Compiler

Die groben Strukturen des MacLISP-Compilers unterscheiden sich nicht von denen des LISP1.5-Compilers: Er arbeitet in zwei Pässen, zu denen in gewissem Sinne noch das Assemblerprogramm LAP als dritter Pa\sshinzukommt.

Im ersten Pa\sswerden die S-Ausdrücke der zu übersetzenden Funktion studiertund in gewissem Sinne verändert. Diese änderungen betreffen sicher die Arbeit mit globalen Variablen [GOL70] und sehr wahrscheinlich die arithmetischenVariablen im Fall das die numerischen Berechnungen optimierenden Compilers. Den Variablen werden verschiedene Tabelle zugeordnet ([GOL70], S.1). danebenwerden die Makros expandiert, Quelltransformationen für einige Funktionen durchgeführt usw. In Welchem Grade auch eine Rekursionsbeseitigung stattfindet, ist unbekannt.

Der zweite Pa\ssgeneriert den Assemblercode. Dieser wird im allgemeinen aufein externes File ausgegeben und erst von dort aus weiter verarbeitet. Dieser zweite Pa\sssoll verschiedenartigste Codeoptimierungen durchführen, eineAufgabe, die am pdp-10 nicht einfach ist.

Es ist nicht bekannt, welche Funktionen von dem Compiler offen übersetzt werden. Sicher gilt dies für alle FSUBR-Funktionen ([MOO74], S.179),wahrscheinlich ist es auch für einige SUBR-Funktionen der Fall.

Die Besonderheit des MacLISP-Compilers ist, da\sses eine Version gibt, dieauch die arithmetischen Funktionen offen übersetzt. Die Ursache für die oft beklagte ungünstige Abarbeitung numerischer Algorithmen besteht einerseits in den unnötigen Funktionsaufrufen für die arithmetischen Grundoperationen und adererseits im Zwang, LISP-Zahlen aus den Ergebnissen zu formen. Eine weitere wesentliche Ursache für die Ineffizienz landläufiger LISP-Systeme bei der Abarbeitung numerischer Rechnungen ist die ständige Typabfrage zur Laufzeit.

Wird nicht offen übersetzt, so enthält der compilierte Code weiterhin Aufrufe in die Standardfunktionen, wo der Typ geprüft und das Ergebnis zur regelrechten Zahl umgeformt wird. Die Zeitdauer insbesondere für die letztere Operation schwankt; sie hängt einerseits von der Arbeit ab, die zu tun ist, um die Maschinenzahl in eine LISP-Zahl umzuformen und adererseits, da oft ein Wort für die Zahl bereitzustellen ist, kann es passieren, da\ssauch nochein Garbage Collection ausgelöst wird.

Im MacLISP-Compiler wird zugleich der offenen übersetzung der arithmetischen Funktionen auch dafür gesorgt, da\ssnur an Ende einer Kette von Operationeneine LISP-Zahl hergestellt wird; dazwischen wird mit Maschinenzahlen (in Registern) gearbeitet.

Dieser übersetzung basiert auf der Typ-Deklaration der Variablen und Funktionen durch den Nutzer. Wo dies nicht geschehen ist, kann der Compiler keinen Typ voraussetzen und mu\ssAufrufe zu den Funktionen der ``allgemeinenArithmetik'' generieren, so da\ssTypprüfung und Zahlenaufbau resultieren.

Für alle Variablen, die als Fixnum oder Flonum dekadiert sind, fällt die Typprüfung zur Laufzeit jedoch weg. Um besseren Code zu ermöglichen, wurde für eine gleichartige interne Repräsentation beider Zahlentypen gesorgt. Dies führte insbesondere zur Unterdrückung des Typs der kleinen ganzen Zahlendurch White [WHI77].

Viele Zahlen tauchen nur als Zwischenergebnisse auf. Nicht in jedem Fall können sie in einem Register aufgewahrt werden. Um einen temporären Speicherplatz für diese Zahlen zu schaffen, wurden nach Ideen von BinfordZahlenkeller eingeführt, je einer für Gleitkomma- und ganze Zahlen. Da der Compiler nicht in jedem Fall entscheiden kann, ob eine Zahl wirklich nur Zwischenergebnis, mu\sszur Laufzeit darüber gewacht werden, da\ssZahlen die imKellerspeicher aufbewahrt sind, nicht als Funktionswert verwendbar sind. Beim Austritt aus einer Funktion wird dieser nämlich zurückgestellt, und die Zahl kann vernichtet werden.

Für die Lösung dieses Problem wurden der Begriff sicheren Zeigers([STE77c], S.4) eingeführt und explizite Umformungen von Zahlen imKellerspeicher zu Zahlen im Zahlenspeicher vorgesehen, wenn eine Zahl auf unsichere Art gezeigt wird.

Die compilierten Funktionen untereinander übergeben sich die numerischen Ergebnisse als Maschinenzahlen. Wird eine solche Funktion vom Interpreter aufgerufen, so liefert sie eine LISP-Zahl. Diese verschiedenartige Resultatübergabe wird ermöglicht durch zwei Eintrittspunkte, in denen entsprechende Schalter gestellt werden.

Neben dem verbesserten Umgang mit Zahlen und ihren Typen sind auch Zugriffe zu Feldern so gestaltet, da\ssder Compiler optimalen Code generieren kann.Zwischen Feld und Feldzeiger wurde eine Datenstruktur von zwei Worten geschoben, um eine unveränderliche Quantität adressieren zu können (Felder können beim Garbage Collection ihren Platz wechseln). So kann über einen indirekten Zugriff mit einem Befehl das Dimensionsfeld erreicht werden, und die Berechnung des Elements aus den Indizes verläuft äußerst schnell. Dies kann durch den Programmierer weiter beschleunigt werden, indem er dem Compiler die Dimensionsgrenzen mitteilt.

Das Ergebnis, das durch diese Festlegungen und Entscheidungen über den Compiler und die numerischen Datenstrukturen erreicht wurde, ist äußerst respektabel: Der Compiler produziert Code, der mit dem eines guten FORTRAN-Compilers vergleichbar ist [FAT71, STE77c]!

Für den Programmierer wesentlich ist die Arbeit des Compilers mit Files.

Durch die Voraussetzung, da\ssder Compiler ein File von Funktionen undDeklarationen verarbeitet, ist die Rettung der ursprünglichen Funktionsdefinition unnötig. Durch die Festlegung, da\ssein File vonAssemblerbefehlen spart. So erweist sich die File-Orientierung als vorteilhafte Vorgehensweise. Daneben ermöglicht die Existenz des LAP-File,da\sseine compilierte Funktion nicht noch einmal übersetztwerden muß; sie kannjederzeit assembliert und so mit wenig Zeitaufwand geladen werden.

Darüber hinaus liefert der Compiler im Normalfall ein File, das bereits assemblierten Objektcode darstellt. Ein solches File, wegen der Schnelligkeit des Ladevorgangs Fastload-file ( FASL-File) genannt, kann geschlossengeladen werden. Es ist aber auch möglich, aus diesem File eine bestimmte Funktion erst dann direkt zu laden, wenn sie benötigt wird. Dies ist die Autoload-Möglichkeit ([MOO74], S.107, 192).

 

BESM-6-LISP

BESM-6-LISP ist die in der UdSSR hauptsächlich verwendete LISP-Implementation. Wegen der Unverträglichkeit der diversen Betriebssysteme bestanden bisher Schwierigkeiten für einen Export dieses Systems.

Das Buch von Lawrow und Silagadse [LAW69] stellt immer noch dieHauptquelle über BESM-6-LISP dar, obwohl in der Zwischenzeit bemerkenswerte änderungen und Erweiterungen vorgenommen wurden [JU73]. Das angegebene Buchist selbst in den UdSSR schwer beschaffbar; die Auslegung des jeweils benutzten Systems ist nur den Nutzer selbst bekannt.

 

Die Umgebung des LISP-Systems: die BESM-6, ihre Peripherie undBetriebssystem

Die BESM-6 [BRA72] ist eine Anlage der zweite Rechnergeneration, die sichdennoch durch eine moderne Architektur und enorme Geschwindigkeit (ca. 1 MIPS) auszeichnet. So verfügt sie über eine hardwareunterstütztes virtuelles Speicherkonzept, Befehle zur Arbeit mit Kellerspeichern und andere Eigenschaften moderner Rechner. Lediglich die Verbindung zu den externen Geräten ist ein wenig ungünstig gelöst: Die Ein- und Ausgabe-Geräte sind nicht nach einem Kanalprinzip angeschlossen, sondern werden noch durch die Zentraleinheit gesteuert. Dadurch geht Zeit des Prozessors verloren. Bei der Ausgabe z.B. werden die einzelnen Zeichen gezählt und nicht die Zeilen. Diese Nachteile können aber durch Kopplung der zentralen Anlage mit einem geeigneten Satelliten ausgegliechen werden.

Mit ihrer Operationsgeschwindigkeit von 1 Million Befehlen pro Sekunde, gewisse parallelen Strategien bei der Befehlsabarbeitung kann sich die BESM-6 trotz ihres beachtlichen Alters (seit 1964 in Betrieb) immer noch mit vielen zeitgenössischen Datenverarbeitungsanlagen vergleichen.

Der Speicher, der in Segmente zu je 1024 48-Bit-Worten aufgeteilt ist, erreicht mit 64K Worten allerdings meist keine wesentlichen Größenordnungen. Daran ändert auch die mancherorts anzutreffende Erweiterung auf 128K nicht viel. Durch die Verfügbarkeit schneller Trommeln und viel Ein- und Auslagerungsarbeit läßt sich jedoch virtuelles Speicherkonzept gut verwirklichen.

Neben den Trommeln verfügt jede BESM-6 über ein umfangreiches Magnetbandsystem und die übliche Menge langsamer Ein- und Ausgabegeräte. Mit der Verfügbarkeit von Magnetplattenspeichern und Displays sind auch diese erfolgreich an die BESM-6 angeschlossen worden.

Ihre Zugehörigkeit zur weiten Rechnergeneration kann zuerst hauptsächlich in der schwachen Ausrüstung mit Betriebssystemen zum Ausdruck. Dann jedoch war die Frage des Multiprogramming von Anfang an recht ausgeprägt in den ersten Betriebssystemen. Als das BESM-6-LISP 1969 implementiert wurde, dürfte im wesentlichen nur ein bescheidenes Monitorsystem die Aufgabenverteilung bewältigt haben. Seit 1970--71 aber arbeitet das Stapelverarbeitungssystem DISPAK, in dessen Rahmen ein begrenzter Dialogbetrieb mit dem LISP-System möglich wurde.

In neuester Zeit verfügt man z.B. am Rechenzemtrum der Akademie der Wissenschaften in Moskau über ein Teilnehmersystem [BRI72], das imSystem DISPAK läuft und über ca. 16 Displays einen Direktzugriff zur Anlage gestattet.

 

 

Datentypen, Speicherplatzverwaltung, Garbage Collection

BESM-6-LISP arbeitet in einem 15-Bit Adressraum (in der BESM-6 steht jedem Programm ein virtueller Adressraum von 32K zur Verfügung). Die um vieles die Erfordernisse von zwei Zeigern (statt 30 Bit: 48 Bit) übersteigende Wortstruktur hat zu einigen sehr machinenabhängigen Entscheidungen geführt (ähnlich wie an den Kleinrechnern pdp-8 usw.). Dadurch ist BESM-6-LISP nicht kompatibel mit anderen Systemen. Die vielen freien Bits wurden für die Darstellung von Informationen benutzt, die sonst frei in den P-Listen mittels Indikatoren angeordnet sind. Dennoch sind immer noch neun Bits völlig unbenutzt.

 

 

 

 

 

 

 

 

 

 

 

 

Es werden drei verschiedene Arten von Grunddatenstrukturen angeboten: Listen, Zahlen und sonstige Atome.

Atome und Zahlen sind in den Bereich für Objekte, der als Hasch-Liste organisiert ist, in einer nahezu identischen Weise dargestellt: Die Eigenschaft, ein Atom zu sein, wird im Bit 43 angezeigt.

Der Wert für EVAL befindet sich im Car der Zelle, in dem Bitbereich25 -- 39. Bei Zahlen ist hier ein Zeiger auf das LISP-Objekt selbst enthalten, so da\ssbei der Auswertung kein besondere Test auf dieZahleigenschaft erfolgen muß. Der Cdr (Bits 1 -- 15) zeigt entweder auf den P-Namen oder auf die Maschinenzahl. Beide Elemente sind im FWS untergebracht. Es gibt keine P-Listen.

Da die BESM-6 nur Gleitkommazahlen kennt, sind auch die ganzen Zahlen als Gleitkommazahlen dargestellt. Der Unterschied zwischen beiden Zahltypen ist nur beim Einlesen und Ausgeben wichtig. Die logischen Zahlen liegen alsMaschinenworte mit Oktalzahlen vor. Sie sind beispielweise für die Arbeit mit externen Speichern von Bedeutung.

Bei den Atomsymbolen sind maximal 29 Zeichen zugelassen. Intern ist der P-Name dargestellt als Aufeinanderfolge von bis zu fünf Maschinenworten. In den Bits 18 bis 25 des Atomkopfes ist die Länge des Namens verschlüsselt.

Die fehlende P-Liste wird durch die Möglichkeit ersetzt, jedem Atom eine Eigenschaft zuweisen zu können. Die Indikatoren für die funktionalen Eigenschaften und für die globale Werte sind als Bits im Atomkopf verschlüsselt (Bits 44 -- 47). Die Funktion GET ist für die Arbeit mitden so dargestellten Indikatoren eingerichtet, diese dürften sein: {\tt EXPR, FEXPR, SUBR, FSUBR, APVAL} ([LAW69]). Durch eine Serie weitererFunktionen kann der Typ der Zahlen z.B. noch genauer untersucht werden.

Die normalen LISP-Zellen, mit denen die Listenelemente dargestellt werden, sind aufgeteilt in der Cdr (Bits 1--15) und den Car (Bits 25 -- 39). Die Wortstruktur der BESM-6 würde bequem die Darstellung eines dritten Zeigers ermöglichen \footnote{Vergleiche dazu die Lösung in UT-LISP (S. 323) mit 60 Bits!} so sind trotz extensiver Ausnutzung in der Atomdarstellung immer noch neuen Bits unbelegt (19--24, 40--42).

Der Speicherplatz ist in sieben Bereiche aufgeteilt: In den Bereich für den Interpreter (1969:3100$_{s}$ Worte), den Bereich für die Objektliste und Zahlen -- kurz: die Objektliste (1969: standardmäßig 2000$_{s}$ Worte), den Listenspeicher (1969: standardmäßig 10400$_{s}$ Worte, den Voll-Wort-Speicher (FWS) (1969: standardmäßig 1400$_{s}$ Worte), einen Bereich für E/A-Puffer und zwei Kellerspeicher (BESM-6-Terminologie: Magazin), davon einer für die A-Liste (1969: standardmäßig 3000$_{s}$) Der Benutzer kann beim Aufruf von LISP vier Parameter angeben, mit denen diese Größen verändert werden können.

Das Garbage Collection folgt dem klassischen Algorithmus. Zur Anzeige aktiver Elemente wird das Bits 48 verwendet.

 

Implementierte Funktionen

An arithmetischen und Listenverarbeitungsfunktionen ist das BESM-6-LISP nicht schlecht ausgestattet. Allerdings fällt die übliche Namesgebung auf. Es gibt keine Funktionale und keine Funktionen zur Zeichenverarbeitung.

 

Funktionen zur Listenmanipulation

Ihren Vorbildern in LISP1.5 entsprechen völlig: {\tt CAR, CDR, CONS, LIST, RPLACA, RPLACD, APPEND} (auch APP genannt), LENGTH (auch LEL genannt)und COPY. Die Funktionen REVERSE heißt hier REV, NCONC dagegenDAPPEND bzw. DAPP. Aus der CAR-CDR-Familie sind alle Mitglieder bis zurvierfachen Verschachtelung vorhanden. Neu sind:

\vspace{3mm}

 

Name Argumentzahl Typ Aktion Bemerkungen

ASS 2 SUBR Wie ASSQ in MacLISP  

LASS 2 SUBR Wie ASSOC in MacLISP  

MCAR 2 SUBR Liefert Liste der ersten n Elemente (n = 1.
Argument) von Liste (2. Argument). Kopiert!

DMCAR 2 SUBR Wie MCAR Destruktiv

MCDR 2 SUBR Liefert Liste der letzten n Elemente (n = 1.
Argument) von Liste (2. Argument) Kopiert!

LCONS 2 SUBR (APPEND 1. Argument (LIST 2.
Argument)) Kopiert 1. Argument

DCONS 2 SUBR (NCONC 1. Argument (LIST 2.
Argument)) Zerstört 1. Argument

INS 3 SUBR Fügt Element (3. Argument) hinter i.Element (i =
2. Argument) in Liste (1. Argument) ein. Kopiert Anfang

DINS 3 SUBR Wie INS Fügt physisch ein

DREV 1 SUBR Wie NREVERSE in MacLISP. Zerstört Argument

ELEM 2 SUBR Liefert i. Element (i = 2. Argument)  

LAST 1 SUBR Wie LAST in MacLISP  

TAIL 1 SUBR Liefert Listenstück mit letztem Element. Last
Element of LIST

SSTORE 3 SUBR ändert i. Element (i. = 2. Argument) zu 3.
Argument in Liste (1. Argument) Kopiert Anfang

STORE 3 SUBR Wie SSTORE Physische änderung

 

Prädikate zur Listenverarbeitung

Auf bekannte Funktionen in LISP1.5 gehen ohne Änderung zurück: {\tt ATOM; NULL; EQUAL} und MEMBER. Die Funktion EQ arbeitet für alle Zahlen.

Neu ist LISTP, eine Funktion, die prüft, ob der vorgelegte S-Ausdruck miteinem korrekten Listenende (NIL) endet.

 

Arithmetische Funktionen

Ein wesentlicher Unterschied der Arithmetik im BESM-6-LISP zu der in LISP1.5 besteht in der Dreiteilung der Typen. Die logischen Zahlenverknüpfungen sind nur für Oktalzahlen zugelassen.

Wie in LISP1.5, auch hinsichtlich der Mischung von ganzen und Gleitkommazahlen, arbeiten {\tt ADD1, DIFFERENCE, DIVIDE, EXPT, MINUS, MIN, MAX, PLUS, QUOTIENT, REMAINDER, SUB1} und TIMES. RECIP liefert, im Gegensatz zuLISP1.5, in jedem Fall eine Gleitkommazahl, die die reziproke Zahl repräsentiert.

Beachte man, da\sssie nur für Oktalzahlen (Bits) zugelassen sind, sounterscheiden sich auch die Funktionen LEFTSHIFT, LOGOR, LOGAND undLOGXOR nicht von den entsprechenden Funktionen in LISP1.5.

Neue arithmetische Funktionen sind eine Serie aus dem Repertoire der FORTRAN-Standardfunktionen: {\tt ABS, SIGN, EMTIER, ROUND, SQRT. EXP. LN, SIN, COS, TG} (bzw COTAN), ARCSIN, ARCTG (bzw. ARCTAN).

Bei den Oktalzahlen ist außer den angegebenen Funktionen noch CLADDverfügbar, womit zwei Oktalzahlen logisch werden können. Bei dieser Operation wird der übertrag zyklisch wieder in der untersten Stelle hinzugefügt.

 

Arithmetische Prädikate

Wie in LISP1.5 sind verfühbar: COND, NOT, AND und OR, PROG, GO undRETURN. Dabei beobachtet COND die erweiterten Konventionen wie in MacLISP.

Außerdem sind implementiert:

\vspace{3mm}

 

Name Argumentzahl TYP Aktion Bemerkungen

EXIT 0 SUBR Unterbrechung der Verarbeitung, Rücksprung ins
LISP-Hauptniveau.  

STOP 1 SUBR Ende des LISP-Jobs. Argument wird als letzte
Zeile gedruckt.

TERPRI 1 SUBR Sprung zu unterner Adresse Ungewöhnliche
Namensgebung!

 

Behandlungen des Interpreters

Mußte schon das Fehlen von Funktionalen störend auffallen, so ist die Armut in dieser Funktionsgruppe sehr Hemmend. Neben QUOTE ist nur EVALvorhanden. LAMBDA ist der Name der FSUBR, die LAMBDA-Ausdrücke aufArgumente anwendet.

Die Funktionen SET und SETQ sind vorhanden; sie sind in die fürBESM-6-LISP eigentümliche Gruppe der Funktionen zur Arbeit mit PROG-Variablen gestellt worden.

 

Funktionen zur Beeinflussung des Interpreters

 

Die Protokollfunktion TRACE und ihr Gegenstück UNTRACE sind festimplementiert FSUBR. TRACE löst den Druck des Namens der zuprotokollierenden Funktion aus, zeigt die Argumentwerte und beim Verlassen der Funktion wieder den Namen und den Funktionswert.

 

Arbeit mit der P-Liste

Wie schon erwähnt, gibt es im BESM-6-LISP eine eigentliche P-Liste nicht. Jedes Atom kann höchstens eine Eigentschaft besitzen; der Indikator ist in Bits verschlüsselt.

Die Funktion GET,die sich an ihr Vorbild in LISP1.5 anschliebt, kann dahernur mit dieser einen Eigenschaft arbeiten.

Normalerweise kann der Programmierer über folgende Indikatoren verfügen: EXPR, FEXPR, SUBR, FSUBR, APVAL, NONE. Man hat versucht, das Spektrum durchBelegung der freien Bits im Atomkopf zu vergrößern; allerdings bleibt die Tatsache, da\ssauf einfache Art nicht mit P-listenähnlichen Objektengearbeitet werden kann.

ähnlich wie für GET mu\ssauch die Verfügbarkeit von CSET und CSETQverstanden werden; hier sind die Unterschiede zu LISP1.5 allerdings verschwindend gering.

Weitere Funktionen sind:

\vspace{3mm}

 

Name Argumentzahl Typ Aktion Bemerkungen

DEFINE bel. FSUBR wie DEFINE in LISP1.5  

GEFTPR 1 SUBR Wert: aktueller Indikator vom Argument  

SEXPR 2 FSUBR definiert EXPR. 1. Argument Funktionsnamen 2.
Argument: LAMBDA-Ausdr.  

SFEXPR 2 FSUBR Wie SEXPR, definiert FEXPR.  

TCSET 3 FSUBR dem Atom (1. Argument) wird Bedeutung (2.
Argument) zu Indikator (3. Argument) zugeordnet Indikator als Oktalzahl
zwischen 0 und 63.

TRGET 1 SIBR Wert ist Indikator (Bitzahl) des Arguments.  

TRPUT 2 FSUBR Indikator (Bitzahl) vom 1. Argument wird
geändert.

 

Compiler und zugeordnete Funktionen

Im BESM-6-LISP ist kein LAP verfügbar. Der Compiler wird, wie auch inLISP1.5, mit COMPILE aufrufen, wobei die Argumente die Namen der zucompilierenden Funktionen sind. Mit Hilfe von EXCISE kann der Compilerbeseitigt und der Platz für den Listenspeicher freigemacht werden.

 

Ein- und Ausgabefunktionen.

Die Ein- und Ausgabefunktionen im BESM-6-LISP beschränken sich auf die zwei Funktionen READ und PRINT. Mit Hilfe der Funktion EDIT kann dafürgesorgt werden, da\ssdie Druckliste mit Zeilenabstand und nur im halbenFormaterstellt wird. Mit der Funktion DIGIT kann man die Zahl der zudruckende Stellen in Gleichkommazahlen bestimmen.

Ansonsten ist die Funktion READ auch für die Arbeit mit externen Speicherngedacht. Es wird davon ausgegangen, da\ssLISP-Ausdrücke in externer Form aufMagnetband ausgegeben worden sind. Hat der Benutzer sich Kataloge der externen Adressen angefertigt, so kann er jederzeit diese Ausdrücke einlesen und verarbeiten. Mit READ können Zeichenketten eingelesen werden: Ergebnisist eine Liste der Zeichenatome.

Das Funktionsspektrum dafür ist allerdings schmal; dabei fällt die Betonung der Arbeit mit numerischen iInformationen auf. Dies erklärt sich aus der Tatsache, da\ssmit denselben Mechanismus der Anschlu\ssvon ALGOL-60-Programmenan das LISP-System erfolgt. Dann werden vor allen numerischen Informationen ausgetauscht.

Bei der Arbeit mit einem externen Gerät ist dieses direk zu adressieren. Dazu wird eine Oktazahl angegeben, die aus folgenden Teile besteht: Kanaladresse, Bandnummer, Zone und Wort. Folgende Funktionen arbeiten mit den externen Geräten über diese Adressen:

\vspace{3mm}

 

Name Argumentzahl Typ Aktion

RNUMB 1 FSUBR Liest eine Zelle vom externen Speicher.

RLNUMB 1 SUBR Liest eine Liste von Zahlen vom externen
Speicher.

WLNUMB 2 SUBR Schreibt eine Liste von Zahlen auf den externen
Speicher.

WNUMB 2 FSUBR Schreib eine Zelle auf de3n externen Speicher.

WRITE 2 FSUBR 1. Argument: Adresse, 2. Argument: Name des
Atoms, dessen Wert geschrieben werden soll.

 

Sonstige Funktionen

\noindent5.3.3.11.1. Funktionen zur Arbeit mit PROG-Variablen

\vspace{3mm}

 

Name Argumentzahl Typ Aktion

POP 1 FSUBR (SETQ x (CDR x))

POPUP 2 FSUBR (SETQ x (CAR y)) {\tt
(SETQ} y (CDR y))

PUSH 2 FSUBR (SETQ y (CONS x y))

SADD1 1 FSUBR (SETQ x (ADD1 x))

SSUB1 1 FSUBR (SETQ x (SUB1 x))

\vspace{3mm}

Daneben gibt es GET und SETQ wie in LISP1.5.

\vspace{2mm}

\noindent5.3.3.11.2. Funktionen zur Typumwandlung

\vspace{3mm}

Mit Hilfe dieser Funktionen läßt sich in beschränktem Maße eine Zeichenverarbeitung durchführen. Die Funktion ALT etwa entspricht EXPLODEin MacLISP, und LTA korrespodiert mit IMPLODE.\footnote{Dasentstehende Atom wird immer in die Objektliste aufgenommen, falls es nicht schon dort ist.}

\vspace{3mm}

 

Name Argumentzahl Typ Aktion Bemerkungen

ALT 1 SUBR EXPLODE in MacLISP Sonderzeichen gibt es
nicht

ATN 1 SUBR Aus Atomnamen wird Zahl aufgebaut.  

BTF 1 SUBR Aus Oktalzahl wird ganze Zahl gebildet.  

FTB 1 SUBR Aus ganzer Zahl wird Oktalzahl geformt  

LTA 1 SUBR IMPLODE in MacLISP Immer intern\footnote{Das
entstehende Atom wird immer in die Objektliste aufgenommen, falls es nicht
schon dort ist.}

NTA 1 SUBR Aus Zahl wird Atom gebildet, dessen Namen den zu
druckenden Ziffern entspricht.

\vspace{3mm}

\noindent5.3.3.11.3. Restliche Funktionen

\vspace{3mm}

 

Name Argumentzahl Typ Aktion Bemerkungen

GENSYM 0 SUBR Wie in LISP1.5  

OBLIST 0 SUBR Druckt Objektliste.  

RANDOM 0 SUBR Wie RANDOM in MacLISP. Zufallszahl

TIME 0 SUBR Zeit seit Jobstart In Sekunden

REMPROP 0 SUBR Wie REMOB in LISP1.5

 

Der Interpreter

BESM-6-LISP benutzt kein EVALQUOTE. Die dem Programmierer entgegentretendeHauptfunktion ist EVAL. Charakteristisch für die Verarbeitung ist dieVerwendung eines Variablenkellerspeichers anstelle der A-Liste -- ähnlich wie in InterLISP (allerdings gibt es generell kein FUNARG).

Bekommt EVAL ein Atom gegeben, so wird zunächst nach dem globalen Wert, deretwa dem APVAL-Wert von LISP1.5 entspricht, gesehen. Da die Atome keineP-Listen haben, kann dies durch einfache Bit-Testung im Atomkopf absolviert werden. Die Zahlen sind so repräsentiert, da\ssfür siew die selbe Aktionmöglich ist: So sind keine Typprüfungen erforderlich. Für Zahlen wie für Atome mit globalem Wert ist demnach die Auswertung schnell beendet.

Wird im Atomkopf kein Bit gefunden, das einen Wert anzeigt, so beginnt die sequentielle Suche im Wertkeller, wo die temporären Werte abgelagert werden. Die lineare Organisation ermöglicht eine schnelle Abwicklung dieses Verarbeitungsschritts. Geht die Suche negativ aus, so wird entweder der fahlende Variablenwert bemängelt oder, falls das betreffende Atom funktionale Eigentschaften hat, wird ein Strukturfehler angezeigt.

Bekommt EVAL eine Liste als Argument, so wird, wie üblich, das ersteElement dieser Liste analysiert. Es darf ein Atom mit fukntionaler Bedeutung (EXPR, FEXPR, SUBR, FSUBR) sein, eine Variable mit funktionalerBedeutung in der A-Liste oder ein LAMBDA-Ausdruck. In jedem anderen Fallwird ein Fehler gemeldet. Auch die zu den Indikatoren EXPR bzw. FEXPRgehörende Eigenschaft mu\ssein LAMBDA-Ausdruck sein [SIL75].

Ein wesentliches Problem im BESM-6-LISP ist die überaus langsame Arithmetik. Ursache dafür ist, da\ssdie Zahlen (wie die Atome) in einer Hash-Listeverwaltet werden. Jede erzeugte Zahl wird erst aufgesucht, um doppelte Speicherung zu vermeiden.

 

Der Compiler

über den BESM-6-Compiler für LISP ist nicht allzuviel bekannt. Verbürgt ist, da\sser hauptsächlich mit einem Variablentyp arbeitet, der denCOMMON-Variablen in LISP1.5 ähnlich ist. Alle Variablen compilierterFunktionen werden, wie im Interpreterregime, mitsamt ihrem Wert in die A-Liste gestellt. Damit gibt es kein Problem der Koordinierung von Interpreter und compilierten Funktionen, aber eine wesentliche Quelle für die Effizienz der Maschinenprogramme ist vergeben.

Der haupteffekt der Compilierung liegt somit in der offenen überstzung der Funktionen (CAR, CDR, COND, CSETQ, GO, PROG, SETQ), denn beim Zugriff zufreien Variablen mu\ssin der A-Liste gesucht werden. Für den Zugriff zulokalen Variablen wird das Anfangsstück des Variablenkellers mit einem Register adressiert. Es wird berichtet, da\ssder Compiler die Programme starkanalysiert und dadurch wesentlich optimiert [JU76].

Der Compiler arbeitet ohne ein LAP. Er setzt den Code direkt in den Bereichfür die Maschinenprogramme ab. Dies ist ersichtlich aus der Technik ([SIL71b], S. 4), die für die Behandlung von Sprüngen und Marken verwendetwird.

Die Übersetzung rekursiver Funktionen ist in [SIL71.b] recht unklarbeschrieben. Folgt man den Angaben, so werden ` ` innere Rekursivitäten' ' DE F (X) (...(G(F(HX))) ... )) aufgelöst mittels Zählmeschanismen undoptimiert, während ` ` äußere Rekursivitäten' ' {\tt (DE F(X) ( ... (COND)((HX) (F X)) (...))} aufrechterhalten bleiben müssen.

Einige Vergleichzahlen über den Effekt des BESM-6-Compilers sind bekannt:

 

Funktion Interpreterzeit ($\mu$s) Compiliert ($\mu$s)
(CAR C) 232 12
(CDR C) 236 13
(CONS T NIL) 404 115
(EQ T T) 396 82
(EQUAL T T) 404 91
(COND (T T)) 816 5
(SETQ N 1) 160 12
(PLUS5 9) 632 622
(ATL (QUOTE ABC)) 892 621

 

InterLISP

InterLISP war Ende der siebziger Jahre ein für Zwecke der Künstlichen Intelligenz sehr wichtiges und umfassendes System. Seine gewaltige Basis standardmäßig verfügberer Funktionen (über 500), seine die Programmierarbeit bequem und einfach manchenden Subsysteme mache es zum Vorbild einer Arbeitsumgebung für die Programmierung.

Viele bekannte LISP-Systeme sind unter Verwendung von Teilen von InterLISP erweitert worden. Zugleich ist dieses System auf einer ganze Reihe von anderen Maschinen implementiert worden. InterLISP läuft in den USA auf der pdp-10 (DEC-10), auf der DEc-20, in England auf der ICL-4, in Schweden und Japan auf der IBM/360 und in Westeuropa auf der Simmens 4004.

Das Interesse an weiteren Implementationen wurde verstärkt durch die Veröffenlichungen des InterLISP-Basissystems: Die InterLISP-Virtual-Maschine-Specification von J.S. Moore [MOO76]. DieHauptquelle bezüglich InterLISP ist das vorzügliche Manual von {\sc W. Teitelman} [TE74], Beschreibungen der Implementationen an den von der pdp-10verschiedenen Maschinen sind ebenfalls vorhanden [U75, GU78a]. Vergessenwerden sollte auch nicht das kleinere Werk von A. Haraldson [HAR75], daseine durchsichtige Einführung bietet.

Es ist möglich, im Rahmen dieses Buches das ganze System einigermaße zu beschreiben. Allein das Manual für die pdp-10 [TE74] hat über 550 Seiten!

So können wir auf keinen Fall auf die verschiedenen Implamentationen eingeben. Basis des vorliegenden überblicks ist Moores Veröffentlichung.Die Subsysteme, die die interaktive Arbeit des Programmierers mit dem System so entscheidend prägen, können ebenfalls nur ganz grob dargestellt werden. Dies scheint zu einem gewissen Grade gerecht gegenüber den anderen LISP-Systemen, die unter Zuhilfenahme von Hilfssystemen, die im LISP geschrieben, zur Test- und Programmierarbeit verwendet werden, ebensolche Dimensionen erreichen könnten.

Andererseits werden wir mit diesem Vorgehen InterLISP nicht gerecht. Die verwendete Implementationstechnologie, nur einen Kern von ca. 200 Funktionen in Assemblarsprache zu kodieren und darauf den entscheidenden Körpers des Systems aufzubauen, indem LISP als Systemprogrammiersprache verwendet wird, hat sich als beste Lösung bei der Verbreitung des InterLISP-Systems erwiesen. Der Nutzer des Systems kann keinen Unterschied zwischen handcodierten und zur Zeit der Systemgenerierung compilierten LISP-Funktionen feststellen.

 

Die Umgebung des InterLISP-Systems: Anlage, Betriebssysteme

InterLISP läuft heute auf verschiedenen Anlagen: pdp-10 (DEC-10), DEC-20, IBM/370, IBM/360, CDC3300, Burroghs 6700 ([TE74], S. iii) sowie Siemens 4004,ICL-4 und Fujitso M160. Alle diese Maschinen gehören zu den derzeit modernsten, ihre Daten sind mehr oder weniger zugänglich.

Die Peripherie umfaßt ebenfalls alle modernen Geräte: Neben den üblichen langsamen Einheiten wie Karteleser, Lochstreifengeräten und ähnlichem sind Direktzugriffsgeräte wie Plattenspeicher, Großraumspeicher, Trommel usw. uns selbstverständlich Magnetbandspeicher zu finden und, dem Namen des Systems entsprechend (InterLISP kommt von ``interaktives LISP''), Terminalgeräte aööer Art (Fernschreiber, Displays usw.).

Die Betriebssysteme können entweder auf einem hardwarenmäßig realisierten virtuellen Speicher operieren (IBM/370, pdp-10, DEC-20 usw.), oder sie sind software-Paging-Systeme (IBM/360). Einen besonderen Platz nimmt gewi\ssdasStamm-Betriebssystem von InterLISP, das Time-Sharing-System TENEX ein [BO72]. Die für LISP so interessante Seite der Speicherverwaltung durch dasBetriebssystem ist durch einen der Entwickler, D. Murphy, beschriebenworden [MUR72]

 

Datentypen, Speicherplatzverwaltung, Garbage Collection

InterLISP hat zu den üblichen LISP-Datentypen neue eingeführt. Es enthält kleine und große ganze Zahlen, Gleitkommazahlen, Atomsymbole (literale Atome), Zeichenketten und P-Namen, Feder (Arrays) und Hashlisten (hash arrays), Kellerspeicherzeiger (stack pointer) und Tafeln für die Ein-Ausgabe (read-tables und Terminal-tables). Hinzu Kommen einige der Benutzer eingeschränkten Zugriff hat (Zeichenkettenzeiger, Bittafeln).

Compilierten Funktionen, d.h. Stücke von Maschinencode, werden in der Form von Feldern dargestellt.

Zahlen sind also in drei Arten Vertreten. Den in MacLISP benutzten Typ der Bignums gibt es nicht. Für den Nutzer interessant ist das Syntaxformat, das dem in ALGOL 60 üblichen entspricht. Auf der pdp-10 dürfen die ganzen Zahlen eine Größe von $2^{35}$ nicht erreichen. Während kleinere ganze Zahlen (im Bereich von -- 1536 bis +1535) durch den Zeiger selbst dargestellt sind, gilt dies für die größeren ganzen Zahlen nicht. Die Zeigen beziehen sich auf Worte im Zahlenspeicher (boxes), wo diese Zahlen abgelagert sind.

Wie die größeren Zahlen werden auch die Gleitkommazahlen behandelt. Ihr Wertebereich liegt zwischen $2,94^{-39}$ und $1,69^{38}$ auf der pdp-10.

Da der Nutzer direkten Zugriff zu den Zahlenworten (boxes) hat und dort auch physich ändern kann, gibt es in InterLISP den Begriff des sichern Zeigers [STE77c] nicht.

Die Atomsymbole, in InterLISP literale Atome genannt, sind in der pdp-10-Implementation auf 99 Zeichen begrenzt. Jede Zeichenkette von nichtzutrennenden Zeichen, die nicht als Zahl interpretierbar ist, wird als solches Atom angesehen: z.B. also 2E+A. Die Trennzeichen sind: Leerzeichen, End-of-File, Line-Feed, (, ), ", [ und ]. Mittels \% dem InterLISP-Escape-Zeichen (slashifier), können diese Zeichen in den Atomnamen eingebaut werden.

Die Atome werden intern durch drei aufeinanderfolgende Worte dargestellt; der Nutzer kann direkt nur mit der P-Liste, dem Top-Level-Wert (in der pdp-10 Implementation Cdr bzw. Car des Atoms, in der Beschreibung der virtuellen Maschine mit spezifischen Zugriffsfunktionen) und der im zweiten Wort untergebrachten Funktionsdefinitionen arbeiten. Diese Funktionsdefinition ist in der pdp-10 als Funktionsaufrufinstruktion dargestellt, die für SUBR anders ist als für EXPR. Auf Grund der Maschinenarchitektur steht aber in der rechten Hälfte des Befehls praktisch die Adresse der Funktion selbst. Im dritten Wort ist noch der Ziger auf den Namen enthalten.

Print-Namen gelten als getrennter Datentyp; sie können als Teil von Atomen oder als Repräsentationen von Zeichenketten vorkommen. Ihre maximale Länge entspricht in der pdp-10 126 Zeichen.

Das Problem von ``intern'' und ``nicht interen'' Atomen scheint in InterLISP nicht vorhanden zu sein; die Art, wie die Atome verknüpft sind (als Liste, Feld oder Hash-Liste), ist nicht beschrieben und so dem Implementator überlassen. Grundsätzlich ist jedes Atom nur einmal da, auch Gensyms werden sofort in die Atomsammlung aufgenommen, so da\sses vorkommen kann, da\ssein schon vorhandenes Atom ``neu'' gebildet wird ([TE74], S.10.5). Wie das Problem der unnötigen Atome und überquellenden Atomabsammlung beherrscht wird,kann hier deshalb nicht beschrieben werden. \footnote{Eiziger Hinweis: der Fehler ``12-ATOM HASH TABLE FULL''}.

Zeichenketten werden extern durch '' umgeschlossen; inter sind sie dargestellt in zwei Teilen: als Zeichenkettenzeiger (in dem die Länge der Zeichenkette und ihr Beginn -- entweder als Adresse oder als Adresse und ein Index ([MOO76], S. 76) -- enthalten ist) und als P-namenähnliche Zeichenfolge, die jedoch in einem Zeichenkettenbereich enthalten ist. In der pdp-10 darf die längste Zeichenkette 12768 Zeichen lang sein ([TE74], S. 3.11).

Die Listenelemente (nodes) sind intern in Zellen untergebracht, die in Car- und Cdr-Teil zerfallen. In der pdp-10 kann ein Wort eine Zelle aufnehmen: Der Adressraum enthält 256K Worte. Felder sind nur mit einer Dimension möglich. Sie können, wie in MacLISP, weder eingelesen noch ausgedruckt werden; versucht man das letztere dennoch , erscheint ein \#, gefolgt von der Oktaladresse des Zeigers.

Intern werden die Felder vierteilig dargestellt: Es gibt einen Kopf, einen Bereich von Maschienenzahlen, die nicht als Zeiger implementiert sind (unboxed numbers, z.B. Maschinenbefehle), einen Bereich von Zeigern und

 

 

 

 

 

 

 

 

 

 

 

eine Folge von Verschiebungsinformationen. Im Kopf wird die Länge des Feldes und die relative Anfangsadresse der Teilbereiche beschrieben.

Hash-Listen sind praktisch Felder, nur bestehen ihre Elemente aus zwei Teilen: Aus Hash-Item dessen Hash-Code gebildet wird und mit diesem ein bestimmtes Feld im Hash-Array adressiert wird. Ist zu dem Item schon eine Eintragung vorhanden, so gibt es einen zugeordneten Wert. Ist an der adressierten Stelle nichts enthalten, so kann das neue Item samt Wert eingetragen werden. Es wird angestrebt, da\ssdie Hash-Liste nahezu voll ist, hervor sich Ergebnisse häufen, da\ssein Teilfeld besetzt ist mit einem Item das von einem neueeinzufügenden Item verschieden ist ([MOO76], S. 23).

Read-Tables sind Objekte, die die syntaktischen Eigenschaften von Zeichen für Ein- und Ausgaberoutinen beschreiben. Jedes Zeichen mu\ssdabei zu genau einer Syntaxklasse gehören, von denen es neuen Basistypen gibt und eine beliebige Menge von nutzerdefinierten Klassen (Makro-Zeichen). Due Read-Table garentiert die Beziehung zwischen einem Zeichen und ihrer Syntaxklasse.

Terminal-Tables sind Objekte, die die Ein- Ausgaberoutinen mit Information versorgen, die sich auf das Terminal beziehen.

Kellerspeicherzeiger werden zur Arbeit mit Umbegungs- und Kontrollinformationen benötigen, die üblicherweise im Kellerspeicher abgelagert sind. Das im InterLISP verwirklichte komplizierte Modell baumartiger Kellerspeicherstrukturen (der Spaghetti-Stack) macht einen direkten Zugriff zu beliebigen Variablenumgebungen und die mehrfache Verwendung solcher Strukturen möglich.

Die vom Nutzer eingeführten Datentypen dürfen aus Zeigern, Zahlen und Bitfolgen bestehen. Mit einer Spezifikation hat der Programmierer seine Datentypen anzugeben. Er wird mit Zugriffsfunktionen versorgt; die Zeiger werden bei der Bewertung von Teilstrukturen als erreichbar beachtet.

Bei der Spezifikation der virtuellen InterLISP Maschine [MOO76] sind keine Aussagen über die Organisation des Speichers und des Garbage Collectors aufgestellt worden. Die pdp-10-Implementation arbeitet in einem 18-Bit Adressenraum. Dieser ist aufgeteilt in Seiten zu 512 Worten mit einer oberen Grenze von 512 Seiten, so da\ssjeder Benutzer des Systems eienen Speicherplatz vom 256K Worten 36 Bit zur Verfügung hat. Das Betriebssystem TENEX leistet die Verwaltungsarbeit dieses Speichers; nur die zu einer gewissen Zeit wirklich erforderlichen Seiten befinden sich in der Maschine.

Jedem Datentyp ist ein gewisser Speicherplatz zugeordnet. Zu Anfang ist dies ein relativ kleiner Raum (minimal eine Seite); wenn im Laufe der Arbeit mehr benötigt wird, so wird mehr zugeordnet.

Der Speicher ist in typenreine Seiten aufgeteilt. Der Typ des Datums, auf das ein bestimmter Zeiger zeigt, ist nicht aus diesem selbst oder aus der Form des gezeigten Objekts abzuleiten, sondern ergibt sich aus der Beschreibung der Seite, ohne da\ssdas Objekt sich wirklich im Hauptspeicher befindet.

Die Zuordnung von Platz bzw. die Belegung des Seitenraums, der einem bestimmten Datentyp zur Verfügung steht, folgt gewissen Regeln, die hauptsächlich darauf abzielen, den Seitenaustausch (Hauptspeicher mit Schwappbereich auf externen Speicher) gering zu halten. So wird z.B. ein Unterschied zwischen Daten fester Länge (z.B. Listenelemente) und Daten variabler Länge (z.B. Zeichenketten) gemacht. Während die Daten fester Länge so in eine Seite eingepaßt werden, da\ssdie Seitengrenze nicht überschritten werden -- die Folge ist, da\ssfür Daten eines solchen Typs die Seiten nicht aufeinanderfolgen zu brauchen -- so kann das für Daten variabler Länge nicht erreicht werden. In diesen Fällen mu\sszur Erweiterung eine direkt folgende Seite zur Verfügung stehen.

Die Verwaltung für Daten fester Länge erfolgt mittels Frei-Speicher-Listen, während die Daten variabler Länge hintereinander abgespeichert werden.

Bei normaler LISP-Arbeit wird der Listenspeicher am stärksten belastet. Deshalb arbeitet die Funktion CONS, die allein neue Listenelemente erzeugt, nach bestimmten Regeln: Ein neues Listenelement wird auf die Seite plaziert, auf der sich der Listenrest schon befindet (also das 2. Argument von CONS). Ist dort kein Platz oder ist der Listenrest ein Atom, dann wird die Seite benutzt, auf der sich das 1. CONS-Argument befindet. Kann auch dort kein Platz gefunden werden, dann wird die Seite verwendet, auf die beim vorigen CONS-Aufruf zugegriffen wurde.

Sollte selbst nach einem Garbage Collection nicht genügend Platz für einen Datentyp zur Verfügung stehen, dann wird soviel neu bereitgestellt, da\ssdas Minimum, das der betreffende Typ verlangt, erreicht wird. Dabei kann bei Daten fester Länge mit beliebigen Seiten gearbeitet werden, während bei Daten variabler Länge oft Daten verschoben werden müssen, um die erforderlichen aufsteigenden Seitenfolgen zu erreichen.

Das Garbage Collection beginnt zu arbeiten, wenn entweder für einen gewissen Datentyp kein Platz mehr verfügbar ist oder wenn der Benutzer es in Gang setzt. Die Bestimmung des aktiven Speicherplatzes geschieht im wesetlichen nach dem klassischen Algorithmus, allerdings werden für die Markierung Bittafeln verwendet\footnote{Bittafeln sind nötig, weil in den Zeigern kein Platz mehr ist. Sie sind günstig, weil während des Garbage Collection die Bittafel praktisch nicht ausgeschwappt wird und so weniger Seitenaustauschoperationen erforderlich sind.}. Jedemfalls gibt es keine Kompaktierung.

Es gibt hier einen interessanten Kontrast, wenn die Meinung von Fenichel und Yochelson zitiert wird [FEN69], die die InterLISP\footnote{damals noch BBN-SDS-940-LISP}-Methode als geeignet für einen kleinen Rechner bezeichnen und bei einem großen System ein kompaktierendes Garbage Collection für die einzige Lösung halten. Leider gibt es keine Erfahrungsberichte und Vergleiche der verschiedenen Strategien. Eine Untersuchung [CON74] kommt zum Resultat, da\ssmöglichst gar kein Garbage Collection gemacht werden sollte, und wenn, dann kompaktierend. Die Ausgangsbasis dieser Untersuchung ist aber nicht bekannt.

Es scheint aber der Raum von 256K Worten nicht gerade klein zu sein, und die Tatsache, da\ssder Mechanismus seit über acht Jahren benutzt wird ohne da\ss die Motivation für eine Veränderung gesehen wurde, spricht für sich.\footnote{Auch die Wahl in MacLISP trotz der Erfahrungen mit der MULTICS-Implementation zeigt in die Richtung.}

Für die Datentypen fester Länge wird also in InterLISP keine Kompaktierung durchgeführt. Dies geschieht aber bei den Daten variabler Länge. Anschließend müssen allerdings alle Zeiger auf den kompaktierten Bereich erneuert werden.

Wird ein Garbage Collection initiiert, dann löst es nicht nur das Speicherproblem, um dessentwillen es arbeitet, sondern weitere schnell zu lösende Probleme. So wird bei jeder Reorganisation des Speichers eines beliebigen Datentyps auch jeder Datentyp fester Länge erfaßt. Außerdem wird diesen Datentypen vorausschauend neuer Speicherplatz zugeordnet, wenn der Verbrauch stark angestiegen war.

Mit Hilfe eines Überlagerungs-Schwapp-Bereiches kann der InterLISP-Nutzer seinen aktiven Speicher um weitere 256K Worte vergrößern (64 Seiten 512 Worte werden als Schwapp-Puffer eingesetzt); diese Möglichkeit wird vor allem für compilierte Funktionen genutzt.

 

Implementierte Funktionen

InterLISP enthält so viele Funktionen, da\sssie hier nicht alle beschrieben werden können. Ursache dafür ist die Tatsache, da\sszwar nur 180\footnote{im Manual [TE74}, 1. Revision, Oktober 1974.] Funktionen als handcodierte SUBR-Funktion vorliegen, die übrigen aber, zunächst in LISP geschrieben, zur Systemgenerierungszeit compiliert werden und so in derselben Form verfügbar sind wie jene.

Für eine gewisse Klasse arithmetischer Funktionen ist überdies bekannt, da\ss sie handcodiert sind und mittels ASSEMBLE (d.h. LAP) zu dem System hinzugefügt wurden. Sie sind nicht als SUBR beschrieben ([TE74], S. 13.8, Fußnote 6).

Im Manual sind die Funktionsarten in dieser Hinsicht wenig unterschieden, was auf eine gleichartige Effizienz der Funktionen hindeutet.

Die in LISP1.5 gemachte Unterscheidung zwischen SUBR, FSUBR, EXPR und FEXPR ist in InterLISP weitergeführt worden. Neben der Unterteilung in handcodierte (SUBR), zu interpretierende (EXPR) und compilierte (CEXPR) Funktionen dient die Auswertung der Argumente als weiteres Unterscheidungsmerkmal (LAMBDA-Funktionen, die nicht mit ausgewerteten Argumente ... bekommen) und auch die Verteilung der Argumente auf die Variablen. Hier sind die von InterLISP eingeführten Begriffe für die Funktionen, die in üblicher Weise die Argumente aufgeteilt bekommen, die ``Spread''-Funktionen, und diejenigen, die beliebig viele Argumente haben können und sie nicht aufteilen -- die ``Nospread''-Funktionen. Für die Bezeichnung wurde für die Nichtauswertung der Argumente der Präfix F wie in LISP1.5 gewählt und für die Nichtunterteilung der Postfix $\*$ (statt des L von MacLISP).

Es gibt also 12 Funktionstypen.

Der Sprachgebrauch verzichtet auf die Postfixe. So ist bekannte Funktion AND ein LAMBDA-Nospread-SUBR (FSUBR*).

 

Funktionen zur Listenmanipulation

Wie in LISP1.5 sind verfügbar: CAR, CDR, RPLACA, RPLACD undLIST\footnoteSUBR*), laut Manual [TE74] ebenfalls NCONC. DieFunktionen APPEND, COPY, LENGTH, REVERSE, SUBLIST und SUBST sind in LISPgeschrieben. Weitere Funktionen, deren Typ ebenfalls als CEXPR angegebenist, sind: ASSOC (= ASSQ in MacLISP), SASSOC (= ASSOC in MacLISP),REMOVE (= DELETE in MacLISP,kopiert, DREMOVE (= DELQ in MacLISP),DREVERSE (= NREVERSE in MacLISP), LAST (= LAST in MacLISP), SORT (=SORT in MacLISP). Zu einigen Funktionen existieren zwei Versionen: dieallgemein bekannte Version und eine, mit dem Präfix F, die offen compiliertwird: FASSOC, FRPLACA, FRPLACD, FLENGTH, FNTH, FLAST. Außerdem sind einigeinteressante Funktionen definiert worden; und zwar Varianten der Substitution: DSUBST (physisch arbeitend), ESUBST (kontrollierend, ob zusubstituierendes Element vorkommt), LSUBST (Listensegmente einbettend);Varianten der Zusammenfügung: NCONC1 (ein Element hinten anfügend), TCONCund LCONC (mit speziellen Zeigern arbeitend).

Hinzu kommen bekannte Funktionen wie NTH (n-tes Element einer Liste),INTERSECTION (Liste der Elemente, die in beiden Argumentliste vorkommen)und UNION (Liste der Elemente, die in mindestens einer Argumentlistevorkommt).

Alle Mitglieder der CAR-CDR-Familie bis zu vierfacher Verschachtelung sindim System verfügbar.

 

 

Prädikate für die Listenmanipulation (und Typprädikate)

Wie in LISP1.5 sind definiert: ATOM (für literale Atome und Zahlen), EQ(auch für kleine ganze Zahlen), EQUAL\footnote{CEXPR} und NULL.Zusätzlich gibt es:

\vspace{3mm}

 

Name Argumentzahl Typ Aktion

ALPHORDER 2 CEXPR T, wenn 1. Argument vor 2. Argument in der
inneren Ordnung steht.

ARRAYP 1 SUBR T, wenn Argument Feld, sonst NIL.

LISTP 1 SUBR T, wenn Argument Listenzelle, sonst NIL.

LITATOM 1 SUBR T, wenn Argument literales Atom, sonst
NIL.

NTYP 1 SUBR Liefert Typbeschreibungszahl.

STRINGP 1 SUBR T, wenn Argument Zeichenkette, sonst NIL.

\vspace{3mm}

Zu LISTP und EQ gibt es negative Funktionen: NEQ und NLIST. DieFunktion MEMB (=MEMQ in MacLISP), ihre offen compilierte Variante FMEMBsowie die Funktion TAILP (testet, ob ein Argument echtes Endstück desanderen ist sind ebenso CEXPR.

 

Funktionale (Funktionen mit Funktionen als Argument)

Die Funktionale werden wir ausführlicher besprechen, obwohl nur MAPATOMSin [MOO76] aufgeführt ist. Die Definition der Funktionale ist gegenüber dervon LISP1.5 leicht geändert, allerdings in einer anderen Richtung, als dies in MacLISP geschehen ist: Die MAP-Funktionale besitzen durchweg dreiArgumente \footnote{beachte dabei, da\ssin InterLISP jedes fehlende Argumentautomatisch durch NIL} ergänzt wird!. Die ersten zwei entsprechen denbei LISP1.5 üblichen (1. Argument = Liste, 2. Argument = Funktion); hinzu kommt ein drittes Argument zum Weiterstellen in der Liste ({\em Generierung des nächsten Element}). Ist dies Argument NIL, dann wird wie in LISP 1.5 dernormale Listenrest, d.h. die Funktion CDR, benutzt. Aus derMAP-Familie (alle CEXPR) sind von LISP1.5 übernommen worden: {\tt MAP,MAPCON} und MAPLIST. Wie in MacLISP sind MAPC, MAPCAR und MAPCONC (dortMAPCAN).

Weitere Funktionale sind:

\vspace{3mm}

 

Name Argumentzahl Typ Aktion Bemerkungen

EVERY 3 CEXPR Wert ist T, wenn Prädikat (2. Argument) für
alle (bezüglich der Generatorfunktion 3. Argument) 1. Argument den Wert T
hat, sonst NIL. Auswertung stoppt beim ersten Element, für das NIL
ermittelt wird.

MAPATOMS 1 SUBR Funktion wird auf jedes Atom
angewendet.  

MAP2C 4 CEXPR Wie MAPC, allerdings sind zwei Listen
vorhanden (1. Argument uns 2. Argument). Die Applikatorfunktion mu\sszwei
Argumente haben. Ende ist erreicht, wenn eine der Listen fertig
bearbeitet.  

MAP2CAR 4 CEXPR Wie MAPCAR; mit den gleichen Änderungen wie
bei MAP2C.  

NOTANY 3 CEXPR (NULL(SOME \em1.Argument 2.Argument 3.Argument\tt)). Auswertung stoppt beim ersten Element, für das T ermittelt
wird.

NOTEVERY 3 CEXPR (NULL(EVERY \em1.Argument 2.Argument 3.Argument\tt)).  

SOME 3 CEXPR Wert ist die Restliste vom 1. Argument, deren
erstes Element das erste in der Reihenfolge war, für das das Prädikat nicht
NIL liefert. Siehe NOTANY

SUBSET 3 CEXPR Wert ist die Teilliste vom 1. Argument mit den
Elementen, für die das Prädikat erfüllt war.

\vspace{3mm}

Viele der aufgeführten Funktionale werden offen übersetzt, d.h. mit einem Zyklus.

In anderen Funktionsklassen tauchen weitere Spezialfunktionale auf.

 

Arithmethische Funktionen

ähnlich wie in MacLISP gibt es drei Klassen arithmetischer Funktionen: die Klasse der Interarithmetik, die Klasse der Gleitkommaarithmetik und die Klasse der allgemeinen arithmetischen Funktionen, deren Elemente auch für Typmischungen geeignet sind. Die Funktionen der Intergerarithmetik sind durch den Präfix I und die der Gleitkommaarithmetik durch den Präfix F zuerkennen.

Diese Bezeichnung mit dem Präfix gilt für die aus LISP1.5 übernommenen Grundfunktionen DIFFERENCE\footnote{CEXPR},MINUS, PLUS\footnoteSUBR*, QUOTIENT, REMAINDER und \newlineTIMES. Inder Integerarithmetik werden die entsprechende Funktionen\footnote{d.h. IDIFFERENCE, IMINUS, IPLUS, IQUOTIENT, IREMAINDER} und ITIMES. ergänztdurch ADD und SUB, die Funktion für den größten gemeinschaftlichenTeiler GCD sowie einige Funktionen, die die Zahlen als Bitfolgeninterpretetieren: wie in LISP1.5 sind LOGAND, LOGOR und LOGXOR verfügbar;die Verschiebungsoperationen heißen: LLSH und RSH für arithmetischeVerschiebungsoperationnen und LLSH sowie LRSH für logische.

Ähnlich wie in MacLISP sind die Konvertiertungsfunktionen FIX und FLOATvorhanden.

Mit einer Serie von Funktionen (der allgemeinen Arithmetik) für Potenzierung, Logarithmierung und solchen aus der Menge der trigonometrischen Grundfunktionen wird das InterLISP-Spektrum abgerundet. Alle diese Funktionen sind aus der FORTRAN-Bibliothek übernommen worden und in LISP-Assembler codiert dem System hinzugefügt: EXPR (für $x^{y}$), SQRT (für $\sqrt{x}$), LOG (für $ln x$), ANTILOG (für $e^{x}$), dazu {\tt SIN, COS, TAN, ARCSIN,ARCOS, ARCTAN.}

Komplettiert wird dises Sortiment durch zwei Funktionen für die Bildung von Zufallzahlen (RAND und RANDSET) und die Funktion für den AbsolutbetragABS.

 

Prädikate für die Arithmetik

Neben den in drei Varianten vorliegenden Vergleichsprädikaten GREATERP undLESSP (Integerversion mit Präfix I, Gleitkommaversion mit PräfixF\footnote{In [MOO76] ist diese Parallelität konsequent; in [TE74]steht FGTP} für FGREATERP.) sind wie in LISP1.5 vorhanden: FIXP\footnote{CEXPR},FLOATP\footnote{CEXPR} und MINUSP. Nur für die Integerarithmetikverwendbar ist ZEROP\footnote{CEXPR}. Neu ist das Typprädikat für kleineIntegers SMALLP\footnote{CEXPR} und die Vergleichsfunktion EQP, die füralle Zahlen und literale Atome verwendbar ist.

 

Funktionen zur Steuerung des Programmablaufs

InterLISP enthält\footnote{Wir verzichten hier auf die Berücksichtigung der Spaghetti-Stack-Implementation in den Funktionsbeschreibung.} die Möglichkeit, LAMBDA-Körper als Folgen von Formenaufzubauen: das implizite PROGN. Es ist z.B. erlaubt, {\tt (LAMBDA(X) (PRINTX) (TERPRI 1)X)} zu schreiben. Die Funktionen COND, AND, OR und NOTentsprechen die gleichnamigen Funktionen in MacLISP.

Innerhalb von PROG können die Anfangszuweisungen zu den PROG-Variableninnerhalb der Variablenliste notiert werden: Diese darf aus literalen Atomen oder aus zweielementigen Listen bestehen, deren erstes Element die Variable bezeichnet und das zweite den für den Startwert auszuwertenden Ausdruck. Auswertung und Anfangswertzuweisung geschehen praktisch ``parallel''.

GO und RETURN entsprechend weitgehend ihren Vorbildern in LISP1.5. IhrAnwendungsbereich ist insofern erweitert, als alle diesbezüglichen Aufrufe sich grundsätzlich auf das letzte PROG beziehen, das aktiviert wurde. Sokönnen GO- oder RETURN-Aufrufe innerhalb beliebiger Funktionen gegebenwerden -- allerdings ist nicht klar, was der Compiler dann unternimmt.

Die Funktion PROGN ist identisch mit der in MacLISP vorhandenen Funktiongleichen Namens; PROG1 ist ein FSUBR$\*$, das nach linearer Auswertungder Argumente den Wert des ersten annimmt.

Oberhalb des Niveaus der virtuellen InterLISP-Maschine liegen die Funktionen SELECTQ und die Familie der RESET-Funktionen. SELECTQ ist eineErweiterung der FEXPR-Funktion SELECT aus LISP1.5 und stellt eine ArtCASE-Konstruktion dar, die mit einem sonst -- Ausgang versehen ist. DieRESET-Funktionen werten eine oder mehrere Ausdrücke in gegen Fehlergeschützten (ERRORSET!) Umgebungen aus und etablieren in diese Umgebungengewisse Zustände (z.B. globale Variablenbindungen), die beim Verlassen wieder aufgehoben werden.

Da Funktionen für die Steuerung des Programmablaufs mehr organisatorische als produzierende Aufgaben haben, wird durch ihre offene Compilierung ein erheblicher Geschwindigkeitsgewinn erreicht.

 

Funktionen zur Beeinflussung des Interpreters

Die Beeinflussung der Arbeit des Interpreters (in InterLISP bedeutet dies die Beeinflussung der Arbeit der virtuellen Maschine) verläuft weitgehend anders als etwa in MacLISP. Ursache für diese Unterschiedlichkeit ist die völlig andere Entwurfsphilosophie: InterLISP bietet praktisch alles, was MacLISP auf diesem Gebiet möglich machte, aber die Funktionen, die die gewünschten Aktionen ausführen, gehören nicht selbst zur Basis, d.h. sind keine Elemente der virtuellen Maschine, sondern können in LISP geschrieben werden.

So sind nahezu alle Funktionen der Fehlerbehandlung, alle Funktionen zur Unterstützung der Testarbeit durch programmierte Unterbrechungen usw. in LISP programmiert worden. Grundlage für diese den Benutzer unterstützenden Teilsysteme sind die Funktionen zur Manipulation des Kellerspeichers.

Diese Funktionen arbeiten über Stackzeiger mit dem Kellerspeicher (der in der Spaghetti-Stack-Implementation in verkettete Blöcke, Frames genannt,aufgegliedert ist). Sie können einen solchen Block analysieren (bezüglich der Binweise die Struktur eine Kette von Blöcken).

Durch die Manipulation von Frames, das Löschen bzw. Ändern von Stack-Strukturen, können schließlich alle Effekte der Fehlerbehandlung, einschließlich Auslösung und Wiedereintritt, hervorgerufen werden.

Die Funktion zur Analyse und Manipulation des Kellerspeichers sind:

\vspace{3mm}

 

Name Argumenzahl Typ Aktion

STACKP 1 SUBR T, wenn Argument ein Stackzeiger, sonst NIL

CLEARSTK 1 SUBR Falls Argument == NIL: Löscht alle existierenden
Stackzeiger. sonst: Liefert alle Stackzeiger, die nicht gelöscht sind (als
Liste).

COPYSTK 2 SUBR Kopiert eine Kette von Frames zwischen 1. und 2.
Argument (A-Links).

FRAMESCAN 2 SUBR T, wenn in Frame (2. Argument) eine Bindung
der Variablen (1. Argument) enthalten ist; sonst NIL.

 

Name Argumenzahl Typ Aktion

MKFRAME 5 SUBR Kopie eines Frames (1. Argument) mit A-Link (2.
Argument), C-Link vom 4. Argument wird entweder ganzes Frame kopiert oder nur
die sogenannte Frame Extension. 5. Argument, ein Stackzeiger, kann zur
Wertdarstellung benutzt werden.

RELSTK 1 SUBR Löscht Stackzeiger (Argument).

RELSTKP 1 SUBR T, falls Argument ein Stackzeiger und dieser
gelöscht ist, sonst NIL.

SETSTKARG 3 SUBR n. Bindung (n = 1. Argument) Im Frame (2.
Argument) wird geändert, so da\ssVariable zum Wert (3. Argument) gebunden
ist.

SETSTKARGNAME 3 SUBR n. Bindung (n = 1. Argument) im
Frame (2. Argument) wird geändert, so da\ssVariable (3. Argument) statt der
bisherigen Variablen zum bisherigen Wert gebunden ist.

STKARG 2 CEXPR Liefert aus n. Bindung (n = 1. Argument) im
Frame (2. Argument) den Wert (entspricht etwa dem aktuellen Parameter).

STKARGNAME 2 CEXPR Liefert aus n. Bindung (n = 1. Argument)
im Frame (2. Argument) den Namen der betreffenden Variablen. Ist 1. Argument
ein literales Atom, wird die Zahl n geliefert, in der das Atom zum
erstenmal als Variable auftaucht.

STKNAME 1 SUBR Liefert Bezeichnung des Frame.

STKNARGS 1 SUBR Liefert Größe des Frame, d.h. Anzahl der
lokalen Variablen.

STKNTH 3 SUBR Liefert n. (n = 1. Argument) von Frame (2.
Argument) erreichbares Frame. Ist 1. Argument KO, so bezieht sich die Zahl
auf die Folge der C-Links, sonst wird die Folge der A-Links verwendet.
Ergebnis kann im 3. Argument untergebracht werden.

STKNTHNAME 2 CEXPR STKNAME(STKNTH 1. Argument 2. Argument
PTR)), wo PTR ein bestimmter Stackzeiger ist.

STKPOS 4 CEXPR Sucht das n. Vorkommen (n = 2. Argument).
des Frame (1. Argument) Ausgehend vom Frame (3. Argument). Ergebnis kann im
4. Argument untergebracht werden. Vorzeichen vom 2. Argument dient zur
Auswahl der Framefolgen wie in STKNTH.

STKSCAN 3 SUBR Sucht erstes Frame ausgehend vom Frame (2.
Argument), in dem die Variable (1. Argument) gebunden wird. Ergebnis kann im
3. Argument untergebracht werden.

\vspace{3mm}

\noindent5.4.3.7.1. Funktionen zur Erzeugung und Kontrolle von Fehlern

\vspace{2mm}

Die entscheidenden Fehlerbehandlungsroutinen, ERRORX und FAULTEVAL,analysieren die Fehler und entscheidung über eine interaktive Fehlerbereinigung oder den Abbruch der Verarbeitung.

Basis des automatischen Anfangens von Fehlern ist die Funktion ERRORSET,die weitgehend ERRSET in MacLISP entspricht; sie ist allerdings vom TypSUBR. Handcodiert sind nur die Funktionen, die ohne Fehleranalyse zumletzten ERRORSET zurückspringen (ERROR!) bzw. direkt insHauptverarbeitungsniveau (RESET).

Der Programmierer kann sowohl eigene Fehler auslösen, indem er ERRORXaufruft, als auch für die Behandlung bestimmter Fehler-Typen sorgen, indem er das betreffende Element der ERRORTYPELST ändert.

Sind die typischen Interpreterfehler undefinierte Funktion undnichtgebundene Variable aufgetreten, dann versucht im Normalfall dasProgrammpaket DWIM, den Fehler durch sorfältige Untersuchung desLISP-Programms als Schreib- oder Klammerfehler zu erkennen und zu beheben. DWIM arbeitet in zwei ermägtigungsstufen: In der unteren verlang der Nutzerextreme Sorgfalt, und so informiert das Programm ihn über jede beabsichtigte Korrektur (Cautous Mode). In der obere vertraut der Nutzer DWIM völlig,und das Programm informiert nur über durchgeführte änderungen ({\em Trusting Mode}). Kann DWIM den Fehler beseitigen, dann wird die Verarbeitung unterBenutzung der Funktion RETEVAL mit dem korrekten Ausdruck erneut betretenund schließlich verlassen, als ob kein Fehler aufgetreten wäre.

Kann DWIM nicht helfen oder lag einer der anderen Fehlerarten vor, wirdgeprüft, ob eine Unterbrechung sinnvoll oder erwünscht ist. Entscheiden sich die Fehlerbehandlungsfunktionen dafür, so tritt das System in den Unterbrechungszustand ein. Dies geschiedt durch Aufruf der (ebenfalls in LISP geschriebenen) Funktion BREAK1.

Wenn InterLISP in den Unterbrechungszustand eintritt, wird zunächst eine Nachricht gedruckt. Anschließend wird durch Ausgabe eines antwortverlangenden Zeichens (prompt character), des:, dem Nutzer angezeigt, da\ssnun ein besonderer Dialogzustand etabliert ist. Der Nutzer befindet sichin einer Unterbrechung (he is the break).

In der Unterbrechung kann der Programmierer den Systemzustand erforschern, den Zustand und damit den zukünftigen Abarbeitungsverlauf beeinflussen, belibige LISP-Ausdrücke auswerten lassen und spezielle Kommandos eingeben.Macht der Nutzer Fehler oder bricht er einen Auswertungsablauf ab, so bleibt er dennoch im Unterbrechungszustand. Schließlich kann über die Kommandos GO, OK oder RETURN, in diesem Fall durch Angabe einesexpliziten Ersatzwertes für den Ausdruck, der zum Fehler geführt hatte, der Unterbrechungszustand aufgehoben werden.

Das Programmpaket für Unterbrechungen BREAK besteht sowohl aus derHauptfunktion BREAK1, die die Unterbrechung auslöst und betreut, als auchaus einer Reihe von Funktionen, die Unterbrechungsanforderungen in Nutzer-LISP-Programme einbauen, wie z.B. BREAK, BREAKO, BREAKIN undTRACE und ausbauen, wie z.B. UNBREAK, UNBREAKO usw.

Wenn der Programmierer etwa die Vorgeschichte eines Fehlers wissen will, kann er mittels BAKTRACE eine übersicht über den Zustand des Kellerspeichersanfordern, in der wartenden Funktionsaufrufe ablesbar sind.

Ein weiteres Subsystem von InterLISP, das über dem Interpreterkern, der virtuellen InterLISP-Maschine, gelagert ist und dem Anwender vielfältigeEinflußmöglichkeiten auf den Abarbeitungsverlauf bietet, ist der Assistent des Programmierers (programmer' s assistant).

Dieses System wurde mit der Absicht geschaffen, da\ssder Programmierer nichteinem passiven Auswertesystem gegenüberstehe, sondern einem hilfreichen, geduldigen Medium. Wichtigster Dient dieses Helfers ist sein Erinnerrungsvermögen: Er merkt sich die Wünsche des Nutzers, führt sie aus, kann frühere Wünsche erneut befriedigen unter eventuellen änderungen und ist schließlich auch noch in der Lage, frühere Aktionen rückgängigzumachen. Der Assistent des Programmieres ist in InterLISP regelrecht an der Stelle tätig, wo in LISP1.5 EVALQUOTE arbeitete und in MacLISP EVAL.

Seine Absicht verwirklicht dieses Programmsystem durch die Erstellung und Verwaltung sogennanter History-Listen, d.h. Verzeichnisse von Aktionen desNutzers Indem man sich auf frühere LISP-Eingaben oder Kommandos bezieht, kann man erneut ausführen lassen, ungeschehen machen oder in geänderter Weise wiederholen. Dies wird über History-Kommandos erreicht.

Der Assistent des Programmieres erstellt auch Listen der Funktionen und Variablen des jeweiligen Programmierers, so da\ssdie Schreibkorrekturinnerhalb DWIM auf mögliche Kandidaten korrekt geschriebener Funktionenzurückgreifen kann.

Eine Hauptfunktion des Assistenten besteht im Rückgängigmachen aller vom Nutzer als falsch bezeichneten Aktionen. Dies ist für Zuweisungen und Bindungen relativ einfach, jedoch schwierig, wenn destruktive Aktionen durchgeführt wurden. Um auch in diesen Fällen die erforderlichen Informationen für das Rückgängigmachen aufzuheben, gibt es zu allen primitiven destruktiven Funktionen eine zweite Variante, die leicht rückgängig gemacht werden kann. Alle Aufrufe der destruktiven vom Hauptverarbeitungsniveau aus werden zu Aufrufen der reversiblen Funktionen geändert. Will man jede destruktive Aktion, auch die in beliebiger Programmtiefe, rückgängig machen können, so mu\ssman sich in den Testmodusbegeben. Natürlich wird die Verarbeitung dann einigermaßen gebremst.

Der Assistent kann auch Unterscheiden, ob eine Eingabe EVALQUOTE oder fürEVAL gedacht war, er filtert die Kommandos aus und ermöglicht sogar, da\ssder Nutzer vor die Verarbeitung eine private Sprachverarbeitungsphase einschiebt, mit der Eingaben analysiert und so umgeformt werden können, daßsie LISP-Ausdrücke sind.

Schließlich kann der Benutzer des InterLISP alle die Aktionen, mit denen er das normale Grundsystem für seine Bedürfnisse zurechtstutzt, in einem File aufbewahren. Der Assistent sorgt dann beim Beginn jeder Sitzung für die Einrichtung dieses Verwendungsprofils von InterLISP.

Hauptfunktionen des Subsystems Programmer' s Assistant ist die Funktion LISPX, die, wie die übrigen aus diesem System, in LISP notiert wurde.

\vspace{1mm}

\noindent5.4.3.7.2. Kontrollzeichen und zugeordnete Funktionen

\vspace{2mm}

Während die üblichen Unterbrechungen innerhalb InterLISP programmiert auftreten, kann es nützlich sein, auf unvorhergesehene Situationen sofort zu reagieren: wenn z.B. eine Rechnung zu lange dauert oder ein Druckvorgang unnötig ist und etwa klar ist, da\ssdie Verarbeitung in eine gänzlichunerwünschte Richtung abgleitet.

Die virtuelle InterLISP-Maschine geht davon aus, da\ssüber die TerminaleUnterbrechungen ausgelöst werden können durch Eingabe spezieller Zeichen (der Kontrollzeichen). Unterbrechungen können verarbeitet und unterdrückt werden. Nach einer Periode der Unterdrückung mu\sswenigstens der letzte Versuch einerUnterbrechung erinnert werden. Die Unterdrückung wird durch ein NIL imUnterbrechungsfeld (interrrupts armed field) angezeigt.

Wird ein Kontrollzeichen eingegeben, dann wird, falls die Verarbeitung nicht unterdrückt wird, das Zeichen in das Rettungsfeld für das Unterbrechungszeichen (saved interrupt character) eingspeichert und in der Unterbrechungstabelle (interrupt table) kontrolliert, ob diesem Zeichen eine Unterbrechungsart zugeordnet ist. Handelt es sich dabei um eine der sieben Basis-Unterbrechungsklassen, dann wird in der LISP-Verarbeitung ein sichererPunkt abgewartet und die Unterbrechung wird behandelt.

Als sicher gilt der Punkt, wenn ein Funktionsaufruf EVAL übergeben wird.Dieser Ausdruck kann in seiner Abarbeitung ohne schwerwiegende Systemänderung verzögert werden.

Den Basis-Unterbrechungsklassen darf jeweils höchstens ein Kontrollzeichen zugeordnet sein. Diese Klassen und die ihnen gegenwärtig in der pdpd-10 Implementation zugeordneten Zeichen sind:

\vspace{3mm}

 

Name der Klasse Zeichen Funktion/Erklärung
HALP H Am nächsten sicheren Punkt wird die Funktion INTERRUPT
gerufen. Diese löst einen BREAK1-Aufruf aus.

PRINTLEVEL P Nutzer kann Zahlen eingeben, um PRINTLEVEL-Felder zu
ändern und damit die Tiefe und Länge der ausgedruckten Information ändern.

RUBOUT delete/rubout Aktuelle Eingabezeile wird gelöscht.

ERROR E Löscht Ausgabe-Puffer, erzeugt Fehler (ohne BREAK1) durch
Aufruf von ERROR!

RESET D Löscht Ausgabepuffer, geht mittels Funktion RESET direkt
ins Hauptverarbeitungsniveau.

OUTPUTBUFFER O Löscht Ausgabe-Puffer.

BREAK B Löscht Ausgabe-Puffer; löst BREAK1-Aufruf sofort aus (d.
h. möglicherweise an einem unsicheren Punkt aus durch Erzeugung eines
Fehlers.

ERRORX U (` ` USER' ' ). Löscht Ausgabe-Puffer, löst
BREAK1-Aufruf an sicherem Punkt aus durch Erzeugung eines Fehlers.

INTERRUPT (definierbar) Löscht Ausgabe-Puffer. Am nächsten sicheren
Punkt wird die Funktion INTERRUPT gerufen (mit anderen Argumenten als
durch HELP.

NONE   Es wird keine Unterbrechung erzeugt.

\vspace{3mm}

Die pdp-10-Implementation bietet noch:

\vspace{3mm}

 

Name der Klasse Zeichen Funktion/Erklärung
TIME T Löscht Informationsnachricht über den Programmlauf
einschlie\sslich Gesamtausführungszeit aus.

STORAGE C Änderung der minimalen Auslegung Speicherbereiche
möglich.

\vspace{3mm}

Zu allen übrigen Zeichen, denen Unterbrechungen gehören, stehen in der Unterbrechungstabelle Variablen. Wird nun das entsprechende Kontrollzeichen auf dem Terminal gedrückt, dann bekommt die zugeordnete Variable einen Wert T zugewissen, und die unterbrochene Verarbeitung läuft weiter.

Die erwähnte Funktion INTERRUPT hat drei Argumente. Das erste ist dieanschließend aufzurufende Funktion, das zweite deren Argumentliste und das dritte eine Steuerinformation. In Abhängigkeit von dieser löst INTERRUPT BREAK1-Unterbrechungen aus oder führt andere Aktionen durch.

In der virtuellen Maschine sind folgende Funktionen für die Manipulation der erwähnten Tafeln vorhanden:

\vspace{3mm}

 

Name Argumentzahl Typ Aktion

INTERRUPTABLE bel. SUBR? Argumentzahl$ \neq 0$: Ist 1. Argument
nicht NIL, so wird das Interrups Armed Field tu T gesetzt. Ist im Saved
Interrupt Character Field einn Zeichen eingespeichert, so wird dieses Feld
wieder auf NIL geöoscht und die zu dem Zeichen gehörende
Unterbrechungsaktion durchgeführt. Ist die Argumentzahl = 0, so wird das
Interrupts Armed Field auf NIL gelöscht. Wert ist der frühere Wert des
Interrupts Armed Field.

GETINTERRUPT 1 SUBR? Ist das Argument ein Zeichen, so wird die
zugehörige Unterbrechungsklasse geliefert. Ist das Argument eine
Unterbrechungsklasse, so wird das zugehörige Zeichen geliefert.

SETINTERRUPT 2 SUBR? Weist dem Zeichen (1. Argument) in der
Unterbrechungstabelle 2. Argument als Unterbrechungsklasse zu. Dabei werden
eventuelle andere Zeichen, die dieselbe Klasse haben, verändert.

\vspace{3mm}

\noindent5.4.3.7.3 Funktionen zur Speicherverwaltung

\vspace{2mm}

Wie in LISP1.5 oder MacLISP kann der Programmierer selbst ein Garbage Collection auslösen. Es gibt Funktionen, die ihn bei der Steuerung des Speichergebrauchs durch Lieferung von Statistiken unterstützen. In diesen Daten sind Zeitinformationen, Anzahlen verwendeter Listenzellen oder Zahlezellenb (Boxen) sowie Häufigkeitsangaben über Seitennachladeoperationen enthalten.

\vspace{3mm}

 

Name Argumentzahl Typ Aktion

BOXCOUNT 2 SUBR Zählt die Zahlenzellen (boxen), die für den
Typ (1. Argument) seit Systemstart nötig waren. Ist 2. Argument nicht NIL,
so wird der Zähler auf diese Zahl gesetzt.

BREAKDOWN bel. FEXPR$\*$ Ermöglicht Analyse des
Auswertungsvorgangs aufgeschlüsselt auf einzelne Funktionen (Argumente): mißt
Zeit, zählt Aufrufe, Cons, Boxen, Pagefaults usw.

CLOCK 1 SUBR Liefert in Abhängigkeit von Argument verschiedene
Zeitinformationen.

CONSCOUNT 1 SUBR Liefert Anzahl der Cons-Aufrufe seit
Systemstart. Ist Argument nicht NIL, so wird Zähler auf diese Zahl
gesetzt.

GCGAG 1 SUBR Argument wird die bei Garbage Collection gedruckte
Nachricht.

GCTRP 1 SUBR Erzeugt eine Unterbrechung, wenn im Listenspeicher
noch n (0 Argument) freie Zellen vorhanden sind.

MINFNS 2 SUBR Setzt für Datentyp (2. Argument) minimalen
Betrag (1. Argument) fest,den der Garbage Collector als Grenze betrachtet,
von wo ab neuer Speicherplatz hinzufügen ist.

 

Name Argumentzahl Typ Aktion

PAGEFAULTS -- EXPR Liefert Anzahl der Fälle, wo eine Seite
nachgeladen werden mußte.

RECLAIM 1 SUBR Startet für Datentyp (argument) ein Garbage
Collection.

RESULTS -- EXPR Wertet die durch BREAKDOWN erstellten
Statistiken aus.

STORAGE 1 EXPR Druck die Datentypzahlen und den zugeordneten
Speicherplatz des Nutzers bzw. (Argument = T) auch den des Systems.

TIME 3 FSUBR Wertet 1. Argument aus und mißt dabei die Zeit und
Anzahl der Cons-Aufrufe.

 

Basishandlungen des Interpreters

Die grundlegenden Funktionen zur Variablenbindung, Ausdrucksauswertung und Funktionsanwendungen entsprechend weitgehend den Funktion für diesen Zwecke in LISP1.5. Allerdings wird weder in EVAL noch in APPLY eine A-Listeangegeben.

Eine Einschränkung von InterLISP ist die Tatsache, da\ssder Ausdruck infunktionaler Stellung ein direkt als Funktion interpretierbares Element (Atom mit funktionaler Bedeutung, LAMBDA-, NLAMBDA- oder FUNARG-Ausdruck) habenmuß.

Die interne Verarbeitung ist allerdings wesentlich durch die reiche Kellerspeicherstruktur geprägt. Dadurch sind völlig neue Operationen möglich. Die prinzipiell nichts Neues bietenden Funktionen APPLY, EVAL, SET undSETQ werden nicht beschrieben.

\vspace{3mm}

 

Name Argumentzahl Typ Aktion

APPLY* bel SUBR* Wie FUNCALL in MacLISP.

ARG 2 FSUBR Zunächst Auswertung des 2. Arguments, dann Suche
eines Frame, in dem das 1. Argument gebunden ist. Ein Fehler wird erzeugt ,
wenn entweder der Wert vom 1. Argument in diesem Frame nicht die Größe des
Frames bedeutet oder wenn der Wert vom 2. Argument $<1$ oder größer als der
gefundene Wert vom 1. Argument ist. Wert ist der zur n. Variable (n = 2
Argument) gehörende Wert in dem Frame.

ENVAPPLY 6 ? Ausführung eines APPLY in einer neu zu
konstruierenden Frame-Umgebung. Zunächst Konstruktion eines Frame ohne
Bindungen mit Namen NIL, das das 3. Argument als A-Link und 4. Argument als
C-Link enthält. Die Stackpointer 3. Argument bzw. 4. Argument werden wieder
freigeben, wenn 5. Argument bzw. 6. Argument $\neq$NIL sind. Das aktuelle
Frame wird so geändert, da\ssder zugeordnete Prozeß, wenn er mit einem Wert
x wieder aktiviert wird, mit ebendiesem Wert unmittelbar darauf wieder
abschließt. Dann wird das konstruierte Frame als
aktuelles Frame verwendet und (APPLY 1. Argument 2. Argument) ausgewertet.
Mit dem Wert dieses Ausdrucks wird in den Proze\sszurückgekehrt, der durch den
C-Link bezeichnet wurde (4. Argument).

 

Name Argumentzahl Typ Aktion

ENVEVAL 5 ? Ausführung eines EVAL in einer
neuzukonstruierenden Frame-Umgebung. Die Operation verläuft wie bei
ENVAPPLY, nur das die Argumente jeweils eine Nummer kleiner zu nehmen sind
und (EVAL 1. Argument) ausgewertet wird.

EVALA 2 SUBR 2. Argument ist eine A-Liste im Sinne von LISP1.5.
Ein Frame wird konstruiert, das die in der A-Liste dargestellten Bindungen
verwirklicht. A-Link und C-Link zeigen auf das aktuelle Frame. Bezüglich des
konstruierten Frame wird (EVAL 1. Argument) ausgewertet. Dann wird wieder
das alte aktuelle Frame aktualisiert und der ermittelte Wert übergeben.

EVALV 2 ? Suche des Wertes der Variablen (1. Argument) in den
vom 2. Argument aus erreichbaren Frames. Falls die Variable nicht gefunden
wird, ist das Ergebnis der globale (top-level) Wert.

DEFEVAL 2 ? Legt Auswertung eines Datentyps fest (nicht erlaubt
für Atome, d.h. literale Atome und Zahlen sowie für Listen). Ist 2.
Argument = NIL, so ist Ergebnis die zum Typ (1. Argument) gehörende
Auswertprozedur; sonst wird die Prozedur zum 2. Argument verändert und die
alte Prozedur als Wert geliefrt. (T bede3utet, da\sseine Größe des Typs bei
Auswertung selbst das Ergebnis ist.

RETFROM 3 ? Rückkehr aus spezifiziertem Frame. Ist 3. Argument
$\neg$NIL, so wird der Stackpointer (1. Argument) gelöscht. Reaktivierung
des mit dem Frame verknüpften Prozesses, der als C-Link von Frame (1.
Argument) erreichbar ist. Als Rückkehrwert wird 2. Argument benutzt.

RETTO 3 SUBR Rückkehr in spezifiziertes Frame. Ist 3.
Argument $\neq$NIL, wird der Stackpointer (1. Argument) gelöscht.
Reaktivierung des mit Frame (1. Argument) verknüpften Prozesses mit
Rückkehrwert (2. Argument).

SETARG 3 FSUBR Siehe ARG. Ist richtige Bindung der Variablen
(1. Argument) gefunden, so wird n. Variable (n = 2. Argument) mit neuen
Wert (3. Argument) mit neuem Wert (3. Argument) versorgt.

\vspace{3mm}

Zu den auf dieser Basis implementierten CEXPR-Funktionen gehört E, eineFSUBR-Variante von EVAL, RPT und RPTQ, zwei Funktionen, die wiederholteAuswertungen durchführen, SETQQ. eine Variante von SETQ, die dieQuotierung des 2. Arguments unnötig macht sowie die Zuweisungsfunktionen für globale (top-level) Werte RPAQ und RPAQQ.

 

Arbeit mit der P-Liste und den funktionalen Bedeutung von Atomen

In InterLISP sind die funktionalen Indikatoren nicht, wie in LISP1.5 und MacLISP, in der P-Liste als Eigentschaften üblicher Art aufbewahrt, sondern in der Funktionsdefinitionszelle. Es gibt eine ganze Serie von Funktionen,die bezüglich diese Unterstruktur literaler Atome agieren.

\vspace{3mm}

 

Name Argumentzahl Typ Aktion

ARGLIST 1 SUBR Liefert Argumentliste der Funktion; für SUBR oder
CEXPR gibt es Standardform: ``das Parameter n-Tupel''.

ARGTYPE 1 SUBR Liefert Zahl, mit der die Argumentübergabe
beschrieben wird (z.B. eval/spread: 0, noeval/nospread: 3).

 

Name Argumentzahl Typ Aktion

CCODEP 1 SUBR T für CEXPR, sonst NIL (alle Arten!)

EXPRP 1 SUBR T für EXPR, sonst NIL (alle Argument!)

FNTYP 1 SUBR Liefert Typbeschreibung (z.B. SUBR).

GETD 1 SUBR Liefert Funktionsdefinition des Arguments.

NARGS 1 ? Liefert Anzahl der Argumente (für nospread-Funktionen: 1).

PUTD 2 SUBR Belegt Definitionszelle des Atoms 1. Arguments neu
mit Funktionsdefinition (2. Argument). Keine Prüfung, ob wirklich gültige
Definition vorliegt!

SUBRP 1 SUBR T für SUBR, sonst NIL (alle Arten!)

\vspace{3mm}

Auf der Grundlage dieser Funktion aus der virtuellen InterLISP-Maschine sind noch folgende Funktionen definiert: DEFINE (verhält sich wie DEFINE inLISP1.5; verlang also eine Liste von Paaren Atom -- Funktionsdefinition. Es ist erlaubt, sttat des LAMBDA-Ausdrucks zwei Elemente zu notieren:Argumentliste und Funktionskörper), DEFINEQ (wieDEFINE, Listenklammer umdas Argument kann weggelassen werden), MOVD (transportiertFunktionsdefinition vom 1., zum 2. Argument), PUTDQ (FSUBR-Variante vonPUTD) sowie SAVEDEF und UNSAVEDEF, mit denen die Funktionsdefinitionbei einem Indikator in der P-Liste gerettet werden kann.

Die Funktionen für die Arbeit mit der P-Liste gehören ausnahmslos dem höheren InterLISP-Niveau an, d.h. sie sind in LISP geschrieben und benötigen nur zwei Basisfunktionen, GETPROPLIST bzw. SETPROLIST, um zur P-Listezuzugreifen. GET und PUTL, das dem PROP in LISP1.5 entspricht,verlangen, wie ihre Vorbilder in LISP1.5, nicht unbedingt ein Atom als 1. Argument, sondern können auch mit beliebigen Listen arbeiten.

P-Listenfunktionen im engeren Sinne sind daher ADDPROP (stellt 3. Argumentin die Liste, die als Bedeutung zum Indikator (2. Argument) auftritt), CHANGEPROP (verändert den Indikator (2. Argument) zu dem Indikator (3.Argument)), DEFLIST (wie in LISP1.5), GETLIS (wie GETL in MacLISP),GETP (wie GET; nur für P-Listen benutzbar),PUT (wie PUTPROP inMacLISP) und REMPROP (wie in LISP1.5).

Das InterLISP-System benutzt für seine Arbeit eine ganze Menge von Indikatoren. Der Verwendungszweck ist allerdings von dem in anderen Systemen, wie z.B. LISP1.5 oder MacLISP, völlig verschieden. Sie dienen hauptsächlich der Fehlerkorrektur, den Unterbrechungsfunktionen, dem Assistent des Programmierers und dem Compiler. Der Interpreter arbeitet nicht mit ihnen.

 

Compiler und zugeordnete Funktionen

Die Stellung des Compilers in InterLISP stellt einen Kompromi\ssder zwischender völligen Einbettung in LISP1.5 und der völligen Selbstständigkeit in MacLISP. Es ist hier sowohl möglich, ganze Files von Funktionen nacheinander zu übersetzen als auch einzelne Funktionen. Der Compiler wird als Funktion aufgerufen.

Die Funktion COMPILE arbeitet, ähnlich wie in LISP1.5, mit einer Folge vonFunktionsnamen von intern verfügbaren Funktionen. Daneben gibt es noch etwa sechs weitere Hauptfunktionen, die eine Compilierung auslösen:

COMPILE1 übersetzt immer eine Funktion (2. Argument) und ordnet den Codedem Atom (1. Argument) als neue Funktionsdefinition zu;

TCOMPL übersetzt alle Funktionen einer Liste von Files;

RECOMPILE übersetzt aus einem File nur bestimmte Funktionen. Für dieübrigen werden aus einem 2. File die übersetzungsresultaten genommen;

BLOCKCOMPILE übersetzt eine Gruppe von Funktionen in einen Block, so da\ssQuerverbindungen zwischen den Funktionen extrem schnell verwirklicht werden;

BCOMPL übersetzt die Funktionen aus einer Liste von Files mit demBlockcompiler;

BRECOMPILE erlaubt Neucompilierung von Funktionen innerhalb eines Blocks.

LAP, das Assemblerprogramm, ist nicht, wie in anderen LISP-Systemen, direktaufrufbar. Es dient zur Assemblierung der Ausgabe des erste3n Compilerpasses. Will der Nutzer dennoch direkt Assemblerprogramme schreiben, so mu\sser denCompiler benutzen und die Folge von Assemblerbefehlen mit dem Atom ASSEMBLEankündigen.

Wie in MacLISP wied die Funktion DECLARE benutzt, um die Compilierung zubeeinflussen. In InterLISP geschieht das entweder durch Spezifizierung von Ausdrücken, die während der Compilierung auszuwerten sind (z.B. um Makros auszuführen oder durch Angabe von Ausdrücken, die nicht in das Ausgabefile übernommen werden sollen.).

Die für die Blockcompilierung nötigen Informationen werden über die Funktion PRETTYDEF als globaler Wert einem dem File zugeordneten Atom zugewiesen.

 

Ein- und Ausgabefunktionen

ähnlich wie im MacLISP, führte die Einbettung von InterLISP in ein Betriebssystem, das die Arbeit mit Datenfiles organosiert, zu eineer erheblichen Ausweitung der Ein- und Ausgabefunktionen gegenüber LISP1.5.

Neben den Funktionen für die eigentlichen Lese- und Schreiboperationen (in deren Argument jetzt Filebezeichnungen auftreten) gibt es ein großes Spektrum von Funktionen für die Organisation der Files. Viele der Argumente der hauptsächlichlichen Funktionen sind optional. Das resultiert aus der Tatsache, da\ssnicht angegebene Argumente als NIL übergeben werden.

\vspace{1mm}

\noindent5.4.3.11.1. Lesefunktionen

\vspace{2mm}

In den wesentlichen Lesefunktionen kann neben dem File auch noch die Syntaxtabelle angegeben werden, nach der die Syntaxklasse der Zeichen bestimmt wird. Wird hier NIL als Argument gefunden, so benutzt dasLeseprogramm die Standardsyntaxtabelle.

InterLISP erlaubt auch MACRO-Zeichen (vgl. 5.4.3.11.4.).

\vspace{3mm}

 

Name Argumentzahl Typ Aktion

BKLINBUF 1 SUBR Leert Zeilen-Puffer und stellt Argument
(Zeichenkette) hinein.

BKSYSBUF 1 SUBR Leert Systemeingaben-Puffer und stellt
Argument (Zeichenkette) hinein.

BUFP --   Zahl der zeichen im Zeilen-Puffer oder NIL, wenn
dieser leer ist.

CLEARBUF 1 SUBR Argument = NIL: löscht Systemeingabe-Puffer
und Zeilen-Puffer, sonst: wenn Puffer nicht leer ist, kopiert Systemeingabe-Puffer
in SYSBUF und Zeilen-Puffer in LINBUF

COPYBYTES 4   Kopiert nacheinander Zeichen vom File (1.
Argument) auf File (2. Argument) von i.Zeichen (i = 3. Argument) ab bis
zum k. Zeichen (k = 4. Argument).

FILEPOS 6   Liefert Zahl, die die Zeichenposition einer
Zeichenkette (P-Name vom 1. Argument) auf einem File (2. Argument) zwischen
den Positionen vom 3. und 4. Argument bezeichnet. Dabei kann Deckzeichen (5.
Argument) verwendet werden. Ist 6. Argument = T, so Endeposition, sonst
Startposition.

LASTC 1 SUBR Wurde vom File (Argument) noch kein Zeichen
gelesen, ist das Ergebnis undefiniert; sonst: letztes gelesenes Zeichen.

LINBUF 1 SUBR Argument = NIL: Lösche LINBUF; sonst: Wert
ist Zeichenkette aus LINBUF-Inhalt.

PEEKC 2 SUBR Liefert nächstes lesbares Zeichen vom File, ohne
es zu entfernen. 2. Argument beeinflußt Pufferbenutzung.

RATEST 1 SUBR Liefert T, wenn vor letzten Atom ein Separator,
Unterbrecher oder Escape-Zeichen gefunden wurde (in Abhängigkeit vom
Argument).

RATOM 2 SUBR Liest Atom vom File (1. Argument). Besondere
Behandlung eines führenden Separators. 2. Argument: Readtafel -- für
Syntax.

READ 3 SUBR Liest S-Ausdruck von File (1. Argument) unter
Benutzung der Readtafel (2. Argument): Readtafel -- für Syntax.

READC 1 SUBR Liest S-Ausdruck von File (1. Argument) unter
Benutzung der Readtafel (2. Argument). 3. Argument beeinflußt Pufferung.

READP 2 SUBR T, wenn lesbare Eingabe im Puffer oder File
vorhanden.

RSTRING 2 SUBR Liest bis zum nächsten Terminator ein und bildet
eine Zeichenkette.

SKREAD 2   Spring hinter S-Ausdruck in File (1. Argument), als
ob er gelesen wurde. Startposition ist dabei der aktuelle Filezeiger,
beeinflußt durch 2. Argument, einer Folge von zusätzlichen Zeichen. Liefert
letzte Klammer dieses hypothetischen Lesens (), , , ] oder NIL.

SYSBUF 1 SUBR Argument 0 NIL: Löscht den
Systemeingabe-Puffer. Sonst: Wert ist Zeichenkette aus Inhalt des
Systemeingabe-Puffers.

\vspace{3mm}

Nicht in der Virtuellen Maschine enthalten sind die Funktionen READLINE(liest eine Zeile vom Terminal und liefert Liste von Zeichen) und RATOMS8liest Atome, bis ein spezifiziertes gefunden wurde).

\vspace{1mm}

\noindent5.4.3.11.2. Ausgabefunktionen

\vspace{2mm}

In einigen Ausgabefunktionen taucht als Argument wiederum eine Syntaxtabelle auf, die erforderlich ist für die Hervorhebung von Sonderzeichen in Atomen für ein späteres Wiedereinlesen.

\vspace{3mm}

 

Name Argumentzahl Typ Aktion

LINELENGTH 1 SUBR Ist Argument Zahl: setze Zeilenlänge neu mit
dieser Zahl fest. Sonst: Wert ist Zeilenlänge.

PRIN1 2 SUBR druck S-Ausdruck (1. Argument) in File (2.
Argument). Sonderzeichen in Atomen werden nicht angekündigt -- File nicht
wiedereinlesbar. Atome werden nicht über Zeilenende gedruckt.

PRIN2 3 SUBR Wie PRIN1. Allerdings mit
Sonderzeichenankündigung (Escape.Zeichen) bezüglich Readtafel (3.
Argument).

PRIN3 2 SUBR Wie PRIN1. Allerdings ohne Beachtung des
Zeilendes beim Atomnamen.

PRIN4 3   Wie PRIN2. Allerdings ohne Beachtung des
Zeilenendes bei Atomnamen.

PRINT 3 SUBR (PRIN2 1. Argument 2. Argument 3. Argument)
(TERPRI 2. Argument).

PRINTLEVEL 1 SUBR Ausgabe zum Terminal wird aud i (Argument)
Listenniveau beschränkt.

RADIX 1 SUBR Setzt Zahlenbasis fest (Standard: 10, d.h.
Dezimalzahlen werden gedruckt).

SPACES 2 SUBR Gibt in File (2. Argument) n (n = 1.
Argument) Leerzeichen aus.

TERPRI 1 SUBR Beendet Druckzeile, gibt sie physisch aus.

\vspace{3mm}

\noindent5.4.3.11.3. Arbeit mit Files

\vspace{2mm}

Files sind externe Folgen von Zeichen. Der Name eines File wird mittels eines literalen Atoms dargestellt. Mit der Eröffnung eines Files wird sein Verarbeitungsmodus festgelegt. Dieser kann einer der folgenden Möglichkeiten sein: INPUT (File nur zum Einlesen), OUTPUT (File nur zum Ausgeben).BOTH (File für Ein- und Ausgabe) sowie APPEND (File nur zur Ausgabe; wirdam Ende fortgeschrieben). Jedem File sind drei Zähler zugeordnet: die Position, der Filezeiger und der EOF-Zeiger.

Die Position stellt einen Zähler für Zeichen dar, die in eine Zeile des File geschrieben wurden bzw. von dort gelesen wurden. Der Filezeiger stellt einen Zeiger auf das jeweilige Zeichen dar. Er kann eine direkte Adresse sein oder ein Zeichenzähler relativ zum Anfang. Der EOF-Zeiger enthält dieGesamtzeichenzahl.

Die Filename werden vom Betriebssystem bestimmt. T wird in InterLISP alsName für das Terminal benutzt. Neben der Terminal spiellen drei standardmäßige Files eine wesentliche Rolle: die Haupteingabe, die Hauptausgabe und das Dribble File (für die Aufzeichnung des Dialogs am Terminal). Es gibt kurze Versionen der Filenamen, die das InterLISP-System kennt und mit den im Betriebssystem zu verwenden exakten vollständigen Namen in Verbindung bringen kann.

Zusätzlich ist jedem File Verfügbarkeitszustand zugeordnet, je nachdem ob es sich um ein altes, neues oder eine alte Version File handelt.

\vspace{3mm}

 

Name Argumentzahl Typ Aktion

CLOSEALL

-- SUBR Schließt alle Files außer Terminal ab.

CLOSEF 1 SUBR Schließt File (Argument) ab.

DELFILE 1 ? Beseitigt vorher abgeschlossenes File.

DRIBBLE 1 ? Eröffnet und benutzt Argument als Dribble-File.

DRIBBLEFILE -- ? Liefert vollständigen Namen des Dribble-File.

FULLNAME 2 ? Falls 1. Argument eine Abkürzende Bezeichnung für
ein eröffnetes File im Zustand (2. Argument) ist, wird vollständiger Filename
geliefert.

GETEOFPTR 1 ? Liefrert für eröffnetes File (Argument) den Inhalt
des EOF-Zeiger-Feldes.

GETFILEPTR 1 ? Liefert für ein eröffnetes File (Argument) den
Inhalt des Filezeiger-Feldes.

INFILE 1 SUBR (INPUT(OPENFILE Argument ' INPUT ' OLD))

INFILEP 1 SUBR (FULLNAME Argument ' OLD)

INPUT 1 SUBR Argument = NIL: Name des Haupteingabefiles.
Sonst: File (Argument) ist nun Haupteingabefile. Wert: Name des alten
Haupteingabefiles.

IOFILE 1 SUBR (OPENFILE Argument ' BOTH ' OLD)

OPENFILE 4 SUBR Eröffnetfile (1. Argument) im Zustand (3.
Argument) im Verarbeitungsmodus (2. Argument) und Bytegröße (4. Argument).

OPENP 3   Auskunft über ein File (1. Argument) oder, falls 1.
Argument = NIL, über alle Files mit Zustand (3. Argument) und
Verarbeitungsmodus (2. Argument). Wert ist entweder vollständiger Name von 1.
Argument oder Liste von vollständigen Filenamen oder NIL.

OUTFILEP 1 SUBR 8FULLNAME Argument ' NEW)

OUTFILE 1 SUBR (OUTPUT(OPENFILE Argument ' OUTPUT ' NEW))

OUTPUT 1 SUBR Argument = NIL: Name des Hauptausgabefiles.
Sonst: File (Argument) ist nun Hauptausgabefile. Wert: Name des alten
Hauptausgabefiles.

POSITION 2   2. Argument = NIL: gegenwärtiger Wert des
Positionsfeldes vom File (1. Argument). Sonst wird das Feld mit dem 2.
Argument neu belegt mit dem 2. Argument neu belegt und der alte Wert
übergeben.

RANDACCESSP 1   Argument, wenn File (Argument) Direkzugriff
erlaubt. Sonst NIL.

RENAMEFILE 2   Eingabefile (1. Argument) bekommt, wenn nicht
eröffnet, Filenamen (2. Argument), wenn dieser zu keinem existierenden File
gehört. Das umbenannte File hat Zustand NEW.

SETFILEPTR 2   Nur möglich bei Direkzugriffsdateien: Ist 2.
Argument = -1, so setze Filezeiger auf EOF. Sonst (2. Argument) $\geq0$)
setze Filezeiger auf das 2. Argument.

\vspace{3mm}

In der pdp-10-Implementation von InterLISP dürfen nur zehn Files gleichzeitig eröffent sein. Außerdem gibt es eine Reihe von Funktionen, die bestimmte Eigenschaften des TENEX-Filessystems ausnutzen ({\tt OPENF, OPNJFN, GTJFN, RLJFN, JFGNS)}.

Die Funktionen ECHOCONTROL, ECHIMODE, DELETECONTROL und RAISE erlaubenspezielle Arbeitsweise am Terminal.

Drei Gruppen von Funktionen erlauben das Umgehen mit Files in bequemerer Weise, als es mit nur den Ein- und Ausgabefunktionen möglich wäre: Mit den Funktionen READFILE bzw. LOAD kann ein ganzes File auf einmal (durch dasAtom STOP oder das Ende des Files begrenzt) bzw. mittels LOADFNS aus demFile ausgewählte Teile (Funktionsdefinitionen) eingelesen werden. Diese Files werden durch die Funktionen WRITEFILE, PP, PRETTYPRINT, PRETTYDEF und derenUnterfunktion PRINTFNS, PRINTDATE, TAB, ENDFILE und PRINTDEF erstellt.

Das File-Programmpaket mit der Hauptfunktion MAKEFILE stellt ein ganzesSystem zum Aktualisieren von Files dar ([TE74], S. 14, 63).

\vspace{1mm}

\noindent5.4.3.11.4. Veränderung der Systemeingabe

\vspace{2mm}

Die Einlesfunktionen in InterLISP arbeiten mit einer Syntaxtafel, und, falls das Terminal Eingabequelle ist, mit einer zweiten geräteabhängigen Zeichentafel.

In der READ-Tafel sind die Informationen über die Syntaxbedeutungen der Zeichen enthalten: die Syntaxklassen {\tt LEFTPAREN, RIGTHPAREN, LEFTBRACKET, RIGTHBRACKET, STRINGDELIM, ESCAPE, BREAKCHAR, SEPCHAR} und OTHER. Normalerweise wird das Zeichen ` ` als STRINGDELIM' ' benutzt, das Leerzeichen und die vier technischen Zeichen Wagenrücklauf, Zeilenvorschub, Seitenvorschub und End-of-Line als Separatoren. (SEPCHAR), $\%$ als Escape-Zeichen. Außerdem enthält die Read-Tafel die Eintragung T bei einem Zeichen, das als MACRO-Zeichen verarbeitet werden soll.

In der Terminal-Tafel sind den Zeichen technische Bedeutung zugeordnet. Dies können sein: WAKEUPCHAR, CHARDELETE, LINEDELETE, RETYPE, CTRLV und NOTE. Für die ersten fünf Klassen müssen jeweils fünf verschiedene Zeichen zur Verfügung stehen (die speziellen Terminalzeichen). Diese Zeichen dienen einer einfachen Editierung der Eingabezeilen.

Diese Tafeln können manipuliert werden: Außer der änderung der System-Read-Tafel (Funktionen SETSYNTAX, SETSEPR, SETBRK) können neue Tafeln durch COPYREADTABLE (COPYTERMTABLE) hergestellt werden, sie sind untereinander kopierbar (RESETREADTABLE, RESETTERMTABLE), und eine bestimmte Tafel kann an die Stelle Systemtafel treten ({\tt SETREADTABLE, SETTERMTABLE}).

Eine besondere Möglichkeit bei der Eingabe ist die Einführung von MACRO-Zeichen. Durch die Funktion READ-MACROS kann die Berücksichtigung dieser Zeichen eingeschaltet werden; Wird danach ein solches Zeichen gefunden, dann wird aus der Read-Tafel ein Ausdruck entnommen (das Body-Attribut), der ausgewertet die Makroaktion hervorruft. Mit weiteren Attributen (Type-Kontext-, Wake-Up-Mode-, Escape-Flag- und Body-Attribut) kann ein kontext angegeben werden, es kann spezifiziert werden, was mit dem Wert der MACRO-Auswertung gemacht wird und wie das Zeichen auszudrucken ist.

Mit diesem Hilfsmittel lassen sich Infixoperatoren an die funktionale Stellung versetzen, Literale durch Expandierung auflösen und Zeichen in Teilausdrücke umsetzen (etwa ' in (QUOTE ...) ).

 

Zeichenmanipulation, Arbeit mit P-Namen, Zeichenkettenverarbeitung

In InterLISP werden die Zeichen, die durch die Funktion PRIN1 ausgegeben werden, als P-Namen bezeichnet. Damit hat jedes Datenelement seinen P-Namen; nur Atome und Zeichenketten, besitzen einen intern explizit dargestellten P-Namen.

Alle Funktionen, die P-Namen manipulieren, können daher nicht nur auf Atome angewendet werden, sondern auf beliebige Datenstrukturen (vgl. EXPLODE und READLIST in MacLISP!).

\vspace{3mm}

 

 

Name Argumentzahl Typ Aktion

CHARACTER 1 SUBR Formt aus Codezahl (Argument) Atom mit
entsprechendem Zeichen als P-Namen.

CHCON 3 SUBR Wie UNPACK; Ergebnisliste enthält Codezahlen für
die einzelnen Zeichen (EXPLODEN in MacLISP).

CHCON1 1 SUBR Liefert Codezahl des 1. Zeichens im P-Namen von
Argument.

DCHCON 4   Steht zu CHCON wie DUNPACK zu UNPACK.

DUNPACK 4   Destruktive Version von UNPACK. 1. Argument wird
in Liste (2. Argument) zerlegt, d.h 2. Argument nimmt die Zeiger zu den
einzelnen Atomen auf.

NCHARS 3 SUBR Zahl der Zeichen im P-Namen vom 1. Argument. Ist
2. Argument $\neq$NIL, so PRIN2 Name (d.h. mit Readtafel.

NTHCHAR 4 SUBR Liefert Atom, das dem i. Zeichen (i =2.
Argument) des P-Namens vom 1. Argument entspricht. Ist 3. Argument $\neq$
NIL, so PRIN2 Name (d.h. mit Escape-Zeichen). 4. Argument: Readtafel.

PACK 1 SUBR (MKATOM(CONCAT) a1 a2 a3 ... an)) wenn
Argument 0 (a1 a2 a3 ... an).

PACKC 1 SUBR wie PACK; Liste enthält aber Codezahlen.

UNPACK 3 SUBR P-Name vom 1. Argument wird in Liste von Atomen
zerlegt, deren P-Namen je ein Zeichen enthält (EXPLODEC in MacLISP). Ist
2. Argument $\neq$NIL, so PRIN2 Name (d.h. Escape-Zeichen EXPLODE in
MacLISP). 3. Argument: Readtafel.

\vspace{3mm}

Die Funktion GENSYM ist auf der Grundlage dieser Funktionen in LISP geschrieben.

Die Funktionen für die Zeichenkettenmanipulation sind eng verwand mit denen zur Verarbeitung von P-Namen: P-Namen werden als eine Art von Zeichenketten angesehen. Eine ganze Reihe der Funktionen erzeugt sich zunächst aus dem Argument eine Zeichenkette, die dem P-Namen entspricht, um mit ihm zu arbeiten. Hinzu kommt die nahezu vollkommene Identität der internen Realisierung von Zeichenketten und P-Namen von Atomen (in der pdp-10-Implementation).

\vspace{3mm}

 

Namen Argument Typ Aktion

CONCAT bel. SUBR* Bildet neue Zeichenkette aus
aneindergehängten Argumenten (dabei werden Argumente, die keine Zeichenkette
sind, vorher konvertiert).

GLC 1 SUBR Liefert letztes Zeichen einer Zeichenkette (falls
keine vorliegt, wird konvertiert). Das Zeichen wird durch Erniedrigen des
Längenfeldes aus der Zeichenkette entfernt.

 

Namen Argument Typ Aktion

GNC 1 SUBR Liefert erstes Zeichen einer Zeichenkette (falls
keine vorliegt, wird konvertiert). Das Zeichen wird durch Erhöhen des
Startzeigers aus der Zeichenkette entfernt.

MAKEBITTABLE 3   Baut Bit-Tafel für STRPOSL auf (für jedes
Zeichen einer Zeichenmenge ein Bit an).

MKATOM 1 SUBR Bildet aus Zeichenkette Zahl, falls
Syntaxregeln erfüllt sind, sonst literales Atom

MKSTRING 1 SUBR Bildet aus beliebigem Argument eine
Zeichenkette die dem P-Namen entspricht.

RPLSTRING 3 SUBR Ersetzt in Zeichenkette (1. Argument) ab i.
Zeichen (i = 2. Argument) alle Zeichen durch die der Zeichenkette (3.
Argument) (falls keine Zeichenkette vorliegen, wird konvertiert).

STREQUAL 2   Vergleich zwei Zeichenketten. T, wenn sie
gleich sind, NIL sonst.

STRPOS 6   Zeichenkettevergleich (match) 1. Argument wird im
2. Argument gesucht, ab Position 3. Argument. Mit weiteren Argumenten (4.
Argument: Deckzeichen, 5. Argument: Wiederholungsschalter, 6. Argument:
Schalter für Anfangs- oder Endposition) kann Suche beeinflußt bzw Ergebnis
bestimmt werden.

STRPOSL 4   1. Argument: Liste von Zeichen oder Bittafel
(siehe MAKEBITTABLE), 4. Argument: Komplementschalter (d.h. angegebenen
Buchstaben sollen nicht gesucht werden). In Zeichenkette (2. Argument)
wird ab Position 3. Argument nach dem ersten Zeichen aus dem 1. Argument
gesucht. Dessen Position ist der Wert (als Zahl).

SUBSTRING 3 SUBR Liefert Teilzeichenkette des 1. Arguments vom
i. Zeichen (i = 2. Argument) bis zum k. Zeichen (k = 3. Argument)-
Liegt keine Zeichenkette vor, so wird Ergebniszeichenkette neu gebildet.

\vspace{3mm}

Aktionen, die MAKOBLIST in MacLISP vergleichbar wären, sind in InterLISP nicht durchführbar.

 

Funktionen zur Verarbeitung von Feldern und neuer Datentypen

Die Felder dürfen in InterLISP nur eine Dimension haben. Es gibt zwei verschiedene Typen: normale Felder, wo die Elemente beliebige Datentypen von LISP sein können und Zahlenfelder, wo die Elemente gante Zahlen sind, die die Elemente direkt darstellen (sogenannte unboxed numbers).

\vspace{3mm}

 

Name Argument Typ Aktion

ARRAY 3 SUBR Erstellt Feld mit Größe (1. Argument), vom Typ
(2. Argument) und Anfangswerten (3. Argument).

ARRAYP 1 SUBR T, wenn Argument ein Feld, sonst NIL.

ARRAYSIZE 1   Größe des Feldes Argument.

ARRAYTYP 1   Typ des Feldes Argument.

ELT 2 SUBR Liefert i. Element (i = 2. Argument) des Feldes
1. Argument.

SETA 3 SUBR Setzt i. Element (i = 2. Argument) des Feldes
1. Argument auf Wert des 3. Arguments.

\vspace{3mm}

Hash-Felder (Hash-Array, Hash-Listen) sind sequentielle Datenstrukturen aus zweiteiligen Elemente. Die zwei Teile heißen Hash-Item bzw. Hash-Wert. Ein Element wird als Hash-Link bezeichnet. Es ist möglich, über ein bestimmtes Hash-Item zu dem zugeordneten Hash-Wert zuzugreifen, ihn zu verändern und ein ganzes Hash-Link hinzufügen bzw. zu beseitigen. Der Zugriff erfolgt mittels eines Hash-Algorithmus, der zu einem gegebenen Hash-Item einen Hash-Code bestimmt, der dann als Index in dem Hash-Feld verwendet wird. Es wird vorausgesetzt, da\ssder Algorithmus so gut arbeitet, da\sser erst, wenn das Hash-Feld fast voll ist, für verschiedene Items denselben Hash-Code liefert.

\vspace{3mm}

 

Name Argumentzahl Typ Aktion

CLRHASH 1 SUBR Beseitigt alle Hash-Links aus Hash-Feld
(Argument).

GETHASH 2 SUBR Liefert den zum Hash-Item (1. Argument)
gehörenden Hash-Wert im Hash-Feld (2. Argument).

HARRAY 1   Erstellt Hash-Feld der Größe des 1. Arguments.

HARRAYSIZE 1   T, falls Argument Hash-Feld; sonst NIL.

PUTHASH 3 SUBR Ist Item (1. Argument) im Hash-Feld (3.
Argument) vorhanden und 2. Argument $\neq$NIL, setze neuen Hash-Wert
fest (2. Argument). Ist 2. Argument = NIL, beseitigte das Hash-Link. Ist
Item nicht vorhanden, so füge neues Link mit Item (1. Argument) und Wert (2.
Argument) ein.

REHASH 2 SUBR 1. CLRHASH bezüglich 2. Argument.
2.(APPLY $\*$ ' PUTHASH item val 2. Argument) für alle Items aus dem 1.
Argument.

\vspace{3mm}

Die virtuelle InterLISP-Maschine gestattet die Einführung neuer Datentypen. Diese Datentypen müssen so strukturiert sein, da\ssman sie als Zusammensetzung von Feldern bestimmter Art beschreiben kann. Als Teilfelder eines neuen Datentyps sind zugelassen: Zeiger zu LISP-Objekten, ganze und Gleitkommazahlen sowie kurze Zahlen, die aus Bits verschiedener Anzahl bestehen. Beim Zugriff zu den BIT-Teilelementen werden LISP-Zahlen abgeschnitten bzw. durch Einlagerung der Bits in die normale Zahlendarstellung erzeugt.

Bei der Einführung des Datentyps mu\ssder Nutzer die Teilfelder mittels der Spezifikationen POINTER, FLOATP, FIXP, (BIT i) bzw. (SIGNEBIT i) beschreiben. In BIT-Teilfelder dürfen nur positive ganze Zahlen gespeichert werden.

Aus der Spezifikation eines Teilfeldes sind Deskriptoren anleitbar, die für die Verarbeitung wesentlich sind.

\vspace{3mm}

 

Name Argumentzahl Typ Aktion

DECLAREDATATYPE 2 ? 1. Argument ist der Name des Datentyps
(ein literales Atom), 2. Argument ist eine Liste von Teilfeldbeschreibungen.
Es wird eine neue Objekklasse mit dem angegebenen Typ vorgesehen. Wert ist
eine Liste von Teilfelddeskriptoren.

FETCHFIELD 2 SUBR Zugriff zu einem bestimmten Teilfeld, dessen
Deskriptor (1. Argument) vorliegt, im Objekt (2. Argument).

GETDESCRIPTORS 1 ? Liefert für Datentyp (Argument) die Liste
der Teilfelddeskriptoren.

GETFIELDSPECS 2 ? Liefert Teilfeldbeschreibung aus
Teilfelddeskriptor.

 

Namen Argument Typ Aktion

NCREATE 2 ? Bildet neues Objekt vom Daten-typ des 1. Arguments
Initialisierung erfolgt mit Inhalt vom 2. Argument, wenn $\neq$NIL und
Objekt desselben Typs.

REPLACEFIELD 3 ? Veränderung eines bestimmten Teilfeldes,
dessen Deskriptor (1. Argument) vorliegt im Objekt (2. Argument) zu Wert (3.
Argument).

 

Der Interpreter

Das Variablenbindungsschema in InterLISP hatte zunächst große ähnlichkeit mit dem in BESM-6.LISP verwendeten\footnote{Lineare A-Liste im Kellerspeicher, siehe S. 381} und folgte damit mehr dem LISP1.5-Verfahren als LISP1.6.

Die Grundlage für die Entscheidung die Variablenbindungen im Kellerspeicher abzulagern, lag zunächst in den überlegungen über einen effizienten Einsatz des Systems innerhalb eines virtuellen Speichers begründet. Man geht dabei davon aus, da\ssdie spitze des Wertkellerspeichers ständig physich im (realen) Hauptspeicher verfügbar ist, während sowohl die Seiten mit den AStomen als auch die Seite mit den Teilelemente einer A-Liste häufiger ausgelagert sein dürften. So stellt ein kurzer sequentieller Suchlauf durch den realen Wertspeicher im Mittel eine bessere Lösung dar als das Nachladen der Seite, auf der sich das atom befindet beim direkten Wertzugriff.

Die Implementation des Spaghetti-Stack hat im Grunde genommen die ähnlichkeit zu LISP1.5 weiter verstärkt: Der Keller ist nun noch listenähnlicher; allerdings sind die lokalen Bindungen einer Funktion (eines PROG) nicht über eine Reihe von Listenelementen vertreut, sondern in Blöcken, den Frames. Durch die Aufnahme der Kontrollbeziehungen zu den Bindungen und Gültigkeitsbeziehungen und durch die Manipulierbarkeit dieser Struktur hebt sich der Spaghetti-Stack wesentlich von dem A-Listenmodell ab, das auch schon vernetzte Bindungsbereiche darstellen konnte (über FUNARG-Ausdrücke und explizite A-Listen-Manipulation).

Abgelesen von den mit dem Spaghetti-Stack erreichten Möglichkeiten (vgl. [MOO76], S. 43ff) stellt sich die Auswertung in InterLISP etwa wie folgt dar:

Wird der Interpreter mit einem literalen Atom betreten, so wird zunächst im Gültigkeitsbereich nach der Variablen gesucht, Das bedeutet, da\ssvom aktuellen Frame ausdgehend, die Kette der A-Links durchgegangen wird und in jedem Frame nach einer eventuellen Bindung gefragt wird. Ist eine solche vorhanden, wird der zugeordnete Wert genommen und die Auswertung ist beendet. Ist auch er nicht vorhanden, resultiert der Fehler ` ` u.b.a.' ' (vgl. 5.4.3.7.2.). Für alle Zahlen und die Datentypen, die in der EVAL-Tafel ein T eingetragen haben, wird die Auswertung mit dem Objekt selbst beendet.

Solleine Liste verarbeitet werden, dann mu\sseine Funktion in funktionaler Stellung stehen. Es ist nicht gestattet, dort beliebige Ausdrücke zu verwenden, die erst nach Auswertung aud die Funktion führen.

Als Funktionen sind möglich: Atome mit Funktionsdefinition, LAMBDA- oder NLAMBDA-Ausdrücke (darunter LAMBDA-Ausdrücke mit Variableniste oder mit einzelnem Atom) oder FUNARG-Ausdrücke.

Die Art der Funktion (LAMBDA- oder NLAMBDA-Typ) entscheidet über die Auswertung der Argumente und (spread bzw. nospread) über die Aufteilung der Argumente auf die Variablen, d.h. die Durchführung der eigentlichen Bindung.

 

Der Compiler

Der Compiler ist im Standardsystem von InterLISP enthalten. Er wurde in LISP geschrieben und liegt als compilierte Funktion vor. Man unterscheidet zwei Compilervarianten, die durch eine Menge von umfassenden Funktionen -- mit denen die Compilierung von Funktionsfolgen oder -files ausgeführt werden kann -- aufgerufen werden (vgl. 5.4.3.10). Diese Varianten unterscheiden sich in der Art, wie die einzelnen compilierten Funktionen zusammengefügt bzw. abgelagert werden: einzeln oder im Block.

Der Compiler, der die Funktionen einzeln übersetzt und sie isoliert aufbaut, läßt sich gut mit dem LISP1.5-Compiler vergleichen. Seine Besonderheit ist die offene Compilierung vieler Funktionen und die prizipielle Verträglichkeit des Compilers mit den Interpreter-Spezifikationen: Für die Compilierung sind in InterLISP keine Deklarationen globaler Variabler erforderlich. Das Variablenbindungsschema ermöglicht die Kooperation compilierter Programme mit dem Interpreter -- der Compiler ist kompatibel. Erreicht wird diese Effekt dadurch, da\sslokale Variable innerhalb einer Funktion zwar direkt adressiert werden, aber im Kellerspeicher Variablenwert und Variablenname abgelagert wird. Während die compilierte Funktion die Namen ignoriert, werden sie vom Interpreter benötigt; auch beim Zugriff zu nichtlokalen Variablen während der Abarbeitung einer compilierten Funktion sind sie erforderlich.

Aus der Literatur ist bekannt, da\ssder Compiler aus zwei wesentlichen Teilen besteht, dem Teil, der den Assemblercode generiert, und dem Assembler selbst.

Der erste Teilbesteht vermutlich aus zwei Pässen. Im ersten Pa\sswerden, wie im LISP1.5-Compiler, die globalen Variablen ausgezeichnet, aufgerufene FSUBR-Funktionen speziell behandelt und gewisse Rekursivitäten aufgelöst. Mit den impliziten Funktionen (funktionale Argumente in der Form von LAMBDA-Ausdrücken) wird anders verfahren als in anderen Copilern: Diese bleiben im Programmtext enthalten und werden nicht herausgelöst, wenn sie als Argumente eines offen übersetzten Funktionals auftreten.

Bei der übersetzung eines Funktionsaufrufs hat der Compiler darauf zu achten, da\sser nicht Argumentauswertung plant, wenn die Funktion vom Typ LAMBDA ist. Deshalb versucht sich der Compiler bei jedem Aufruf zu informieren: Ist die Funktion noch nicht definiert und hat der Nutzer dem Compiler keine Information geliefert, indem er den Funktionsnamen in eine der Listen LAMS (normale LAMBDA-Spread-Funktionen), NLAMA (NLAMBDA-Nospread) bzw. NLAML (NLAMBDA-Spread) stellt. Sonst sucht der Compiler das ganze zu übersetzende File nach Information ab.

Hat der Compiler keine Information, so nimmt er an, es handelt sich um eine LAMBDA-Spread-Funktion: der Code kann also fehlerhaft sein.

Variable, die in der Liste GLOBALVARS vorkommen, werden so behandelt, da\ss ein Zugriff zur Wertzelle erfolgen kann. Gleiches gilt für alle Atome, die eine Eigenschaft beim Indikator GLOBALVAR haben.

Der Compiler übersetzt eine große Menge von Funktionen offen. Ende 1974 enthielt die Liste der Funktionen, die so behandelt wurden, 101 Elemente.Unter diesen sind keine , oft benutzte Funktionen, wie die Funktionen der CAR-CDR-Familie, EQ, CONS usw., dann eine Serie von Funktionen, die mit F beginnen und eine Version einer anderen Funktion sind (z.B. FMEMB offene Version von MEMB, FASSOC offene Version von ASSOC, usw.). Schließlich gibt es kompliziertere Funktionen, mit denen der Kontrollflu\ssbeeinflußt wird, und Funktionale, die offen übersetzt werden (PROG, COND,SELECTOQ, MAP, MAPCX', ..).

Der Programmierer kann die Compilierung durch Bereitstellung eines eigenen Generatorsn für die übersetzung von Funktionsaufrufen (COMPILEUSERFN) oderdurch Angabe von MACRO-Definitionen beeinflussen.

Bei der übersetzung von PROG, Funktionalen u. ä. bildet der Compiler imStrom der Assemblerbefehle Unterliste, die der Assembler dann in die normale Codefolge aufnimmt.

Die Compiler-Makros zerfallen in drei Klassen: Es gibt die einfachen offenen Makros, bei denen der Compiler über eine Art Funktionsdefinition verfügt. Die zweite Art sind die errechnete Makros, bei denen das MACRO während derübersetzung expandiert wird. Die Dritte Art von Makros werden mittels Substitution verwendet. Beispiele für die Klassen sind: {\tt (LAMBDA(X) (COND((GREATERP X O)X) (T(MINUS X))))} für {\tt ABS, (X(LIST' CONS(CAR X) (AND(CDR X) (CONS ' LIST(CDR X))))} für LIST und ((X) (IPLUS X 1)) . DerAnfang des Makros legt der jeweilige Art fest. Die Makros befindet sich beim Indikator MACRO in der P-Liste der jeweiligen Funktion.

Der Code-Generator liefert nicht direkt Assemblerbefehle, sondern Assembler-Makros. Damit kann er leicht an verschiedene Maschine angepaßt werden. Die Assembler-Makros stehen für Basisaktionen auf dem Maschinenniveau, die aber LISP-orientiert sind. Es gibt z.B. ([TE74], S.18.46): LDV bzw. STV (lade bzw. speichere Variable), LDT bzw. STT(lade bzw. speichere Temporäre), CLL (rufe Funktion mit n Argumenten),JN (springe, wenn AC = NIL) usw. usf.

In InterLISP ist zwischen Variablen zu unterscheiden, deren Wertzelle verarbeitet werden soll (global) und solche, die in einer Funktion lokalsind und global für eine Unterfunktion (frei). Im letzten Fall liegt derWert im Kellerspeicher, wie bei normalen lokalen Variablen. Da auch die compilierte Funktion die Namen der Varablem im Kellerspeicher vermerkt, unterscheidet sich der Kellerspeicherzustand bei Eintritt in eine compilierte Funktion nicht von dem, der einträte, wenn dieselbe Funktion interpretiert würde.

Damit ist zunächst die Kommunikation zwische Interpreter und compilierten Funktionen gesichert. Die Verarbeitung der freien Variablen wird dadurch erledigt, da\sseine compilierte Funktion sich, bevor ihre Arbeit beginnt, ihrefreien Variablen zusammensucht und im Kellerspeicher hinter der lokalen Variablen speichert. So mu\sssie Suche nur einmal durchgeführt werden, unddier Funktion kann auch die freien Variablen direkt adressieren. Um ein Durcheinander im Kellerspeicher zu verhindern, werdem die so umgespeicherten Variablenbindungen besonders gekennzeichnet.

In einer normelen Umgebung wäre dies sicher ein schlechtes Schema; die Notwendigkeit, Zugriffe auf ausgelagerte Seiten mit freien Variablen zu vermeiden, ändert aber diese Beurteilung.

Dennoch bleibt diese Variablenbehandlung in vielen Fällen ungünstig, genauso wie die oft langsame Verbindung zu anderen compilierten Funktionen. Oft hat man eine Gruppe von kooperierenden Funktionen: Die Verbindungslinie zwischen den Funktionen werden oft durchlaufen und die Variablen gemeinsam benutzt. Auch in einer bestimmten Stelle ab oft verarbeitet wird und daher mit der betreffenden Seite eingelagert sein muß. Würde man hier das allgemeinen Schema verwenden, so käme man zu sehr langsamen Verarbeitungsprozessen.

In diese Lücke spring der Blockcompiler. Er ermöglicht die übersetzung eine Menge von zusammengehörigen Funktionen und ihre Zusammenführung in einen Block. Die Verbindungen zwischen den Funktionen sind dann optimiert, d.h. direkt. Die freien Variablen werden nur beim Eintritt in den Block lokalisiert und bleiben immer an dieser Stelle. Jede Funktion beschäftigt sich nur noch mit ihren lokalen Variablen. Man erkennt leicht, da\sseinerheblicher Geschwidigkeitsgewinn resultieren muß.

Die offene Compilierung der arithmetischen Funktionen scheint nicht so gelungen zu sein wie in MacLISP. Das liegt aber nach Steele [STE77c]nicht so sehr am Compiler, als an der vorgenommenen Tayprüfung zur Laufzeit und an der Möglickeit, Zahlen in ihren Boxen zu ändern. Wie J. Urmiberichtet, beseitigt der Compiler in seltenen Fällen (vermutlich ähnlichen dem Q-32-Compiler [SAU64c] Rekursivitäten. Eine eigentliche Code- Optimierungfindet im nachhinein ncit statt. Inwieweit der Compiler mit den Marken umgeht und ob er die globalen Sprünge so ermöglicht, wie dies in [MOO76] gefordertwird, ist nicht bekannt.