previous next Title Contents Index

9. Leibniz - Ein hypertextbasiertes Softwaresystem



AG-Text-Code: LEIBHP.DOC

@:LPL_HYP

9.1. Abstract

Das Leibniz® System [5] entstand 1984 und mutierte 1985 zu einer der ersten hypertextbasierten Software-Entwicklungsumgebungen. Der TLSI, oder Token-Listen-Subroutinen-Interpreter, ist ein logisches Maschinenmodell, das aufgrund seiner Struktur prädestiniert ist für Hypertext. Zwischen 1984 und 1992 wuchs das Leibniz-System von einem Minimal-Kernel mit 32 Kilobyte und dem Komfort eines interaktiven Assembler-Debug-Monitors zu einer Software-Entwicklungsumgebung mit insgesamt ca. 10.000 Funktionen oder Methoden in 100.000 Zeilen Source Code und noch einmal soviel Kommentar und Dokumentation, insgesamt ca. 6 MByte. Die Hauptversion ist unter DOS auf einem PC-AT realisiert und umfaßt 550 KB compiliert. Das gesamte System ist in der rapid-prototyping Shell-Sprache LPL (Leibniz Programming Language) erstellt. Die Shell bedient sich einer Philosophie des Benutzer-Interfaces mit eigenem (PC-Character-) Windowing, frei benutzer-konfigurierbaren Menus, Hypertext-basiertem Editor, und kontextsensitiver Hilfs-Funktion. Die Leistungsfähigkeit des Leibniz-Konzepts läßt sich daran ermessen, daß es möglich war, das System in Teilzeitarbeit im wesentlichen mit einer einzigen Person zu erstellen, zu warten und zu pflegen.

9.2. Einführung, Geschichte

Das Leibniz® System entstand 1984 auf Basis des IBM PC aus einem Kooperationsprojekt unabhängiger Software-Entwickler zur Schaffung einer deutschen Programmiersprache. Die Namensgebung erfolgte in Anlehnung an Arbeiten von A. Goppold (AI-LRN77) zur Characteristica Universalis von Leibniz und Leibnizens Bedeutung als wesentlicher Vordenker der heutigen Entwicklungen in der Computerindustrie. Die frühen Ideen zum Leibniz-System wurden in TIME-FR.DOC, PARA-PRG84 und TRENDS84 beschrieben. Das Ursprungsprojekt erwies sich als kurzlebig, da der gleichzeitige Erfolg von Turbo-Pascal [6] und später C einer auf völlig anderen Prinzipien beruhenden Programmiersprache keine Entfaltungsmöglichkeiten mehr bot. Das Leibniz-System wurde daher von A. Goppold in den folgenden Jahren in Industrieprojekten (maschinennahe Steuerungen) weiterentwickelt. Im Jahre 1985 entstand auf der Basis von Leibniz eines der ersten Hypertextbasierten Software-Entwicklungssysteme, lange bevor die Standard-Entwicklungsumgebungen von Borland und Microsoft solche Möglichkeiten erlaubten.

9.3. Die Tokenlisten-Maschine TLSI: Basis des Leibniz Hypertext-Systems

Der Token-Listen-Subroutinen-Interpreter, kurz TLSI genannt, ist die softwaretechnische Basis des Leibniz Hypertext-Systems. Man kann in der Rückschau sagen, daß dieser Typ einer logischen Maschine notwendigerweise prädestiniert ist für ein Hypertext-System. Dies war natürlich im Jahre 1984 noch nicht absehbar, weil Hypertext damals außer durch ein paar Artikel von Ted Nelson noch nicht bekannt war, und seine Eignung für die Software-Entwicklung bei einer Programmiererschaft, für die der vi und vielleicht der EMACS das Nonplusultra aller Entwicklertools darstellte, kaum eine Resonanz fand.
Der TLSI gehört als Klasse von logischen Maschinen zu der größeren Gruppe der Metacode-Maschinen. Metacode-Maschinen sind Rechnermodelle, deren Programmcode von dem Compiler nicht in den Objekt-Code (Maschinencode oder Assemblercode) des verwendeten physikalischen Rechners übersetzt wird, sondern von einem residenten Kontrollprogramm interpretierend abgearbeitet wird. Beispiele dafür sind z.B. der Pascal P-Code (Pseudocode), APL, LISP und Postscript. Der TLSI von Leibniz ist ein sehr einfaches Rechnermodell, das sich auf jedem beliebigen Von-Neumann Rechner mit ca. 10 bis 30 KByte -Code installieren läßt. Für die damalige PC-Installation wurde erstmals ein 32-Bit Modell gewählt, das aus Geschwindigkeitsgründen in Assembler programmiert war [7].
Die wesentlichen, damals Eigenschaften des TLSI sind: Erweiterbarkeit, Portierbarkeit, und Interaktivität. Als wesentlich für spätere Entwicklungen erwies sich die Möglichkeit der Umwandlung in compilierbaren C-Code.
(Abb.: Schema der Tokenlisten-Maschine)

9.4. Die Eigenschaften des TLSI

Erweiterbarkeit: Der wichtigste Aspekt des TLSI ist seine Erweiterbarkeit. Der TLSI ist eine dynamisch erweiterbare Programmiersprache. Dadurch ist es möglich, mit einem primitiven Kernel-System in einer Minimalkonfiguration (10 bis 30 KBytes) wie mit einem interaktiven Debugging-Monitor zu arbeiten, als auch auf einer Workstation-Umgebung mit Megabyte-Größen sehr reichhaltige Entwicklungssysteme zu realisieren. Die vorhandene PC-Demoversion nutzt den verfügbaren Addressraum des PC mit ca. 550 KB bis zum letzten aus und stellt dort die Grenze des technisch machbaren dar. Die Erweiterbarkeit erlaubt Anpassung an jede denkbare (und nicht denkbare) Konfiguration. Der TLSI ist eines der flexibelsten Software-Systeme überhaupt.
Portierbarkeit: Dieses genormte Rechnermodell läßt sich auf einer Vielzahl von Ziel-Prozessoren mit relativ geringem Anpassungs-Aufwand installieren. Es ist dadurch möglich, Standalone-Installationen auf jedem Zielrechner zu machen, und auch auf Industrie-Rechner ohne Betriebssystem zu portieren [8]. Der Arbeitsaufwand liegt bei Assembler um 3 Mann-Monate. Verwendet man die C-Installation, dann ist der Portierungsaufwand nahe Null. Die C-Installation erfordert dringend ein 32-Bit Modell, und war deshalb auf PC-basiserten Compilern bisher kaum machbar. Diese wurden erst mit dem 32-Bit DOS-Extender möglich. Unter Windows sind sie auch heute noch nicht möglich.
Interaktivität: Auch in der Minimalversion ist eine User-Shell (UINT) integriert, daher ist immer interaktives Arbeiten möglich. Das System verhält sich in seiner Minimal-Konfiguration wie ein sehr leistungsfähiger Debugging-Monitor.
Abstrakter Rechner: Für theoretische Betrachtungen interessant ist der Faktor, daß der TLSI wahrscheinlich das einfachste praktisch nutzbare Rechnermodell ist. Es ist vergleichbar mit einer LISP-Maschine, wird aber wesentlich effektiver implementiert, so daß kein aufwendiger Rechner zur schnellen Abarbeitung erforderlich ist. Wie eingangs schon festgestellt, ist das System auf Minimalanforderungen ausgelegt. Kernelversionen des Systems laufen auch auf Single-Chip Prozessoren mit 16-bit Installationen.
Umwandlungsmöglichkeit in compilierbaren Code: Weil hier ein Zwischencode interpretiert wird, ist die Ausführungsgeschwindigkeit nicht so hoch wie compilierter Assembler-Code. Es ist aber in dem C-implementierten System möglich, mit einem einfachen Filter eine Konversion von Tokencode zu compilierbarem C-Source Code zu machen, indem man jeden Token-Call durch einen C-Function Call ersetzt. Dies ist ein wesentlicher Vorteil gegenüber einer konventionellen Shell, wie sie in Unix verwendet wird (C-Shell, Bourne Shell). Die Entwicklungsgeschwindigkeit ist durch die interaktive Arbeitsweise wesentlich höher als mit einem konventionellen Compiler-System.
Ideal für Source-Code-Debugger: Ein ganz entscheidender Vorteil ergibt sich durch die extrem einfache Verbindung des Run-Time Token Codes mit der Source-Information, das die Erstellung eines Source Code Debuggers zu einem vergleichsweise einfachen Projekt macht. Statt der Größenordnung von 1 bis 5 Mannjahren, läßt sich ein ausgefeilter Source-Code Debugger in ca. 3-6 Mannmonaten erstellen.

9.5. Aufbau und Abarbeitung einer Tokenliste

Die Tokenliste (TL) besteht aus einer Folge von Toke ns, die in einer geeigneten Datenstruktur abgelegt sind. Diese Datenstruktur besteht aus einer Folge von CELLs (Zellen). Jede CELL kann ein Token oder ein Datenelement enthalten, bei der vorliegenden Implementation werden CELL-Größen von 4 Byte verwendet. Die konzeptuelle Einfachheit dieses Schemas gegenüber den Assembler-Instruktionsformaten normaler (CISC-) Prozessoren besteht darin, daß die Befehlsbreite immer gleich ist.
Ein Token ist ein Stellvertreter für eine Routine. Eine Routin e wird ausgeführt, indem die zugeordnete Tokenliste von der STEP-Maschine abgearbeitet wird. Dies bedeutet, daß die einzelnen Tokens der Liste (oder vielmehr die damit repräsentierten Routinen) ausgeführt werden. Der jeweils aktuelle Stand der Abarbeitung innerhalb der Tokenliste wird im Befehlszeiger (Instruction-Pointer: IP) gehalten.
(Abb.: Schema der STEP-Maschine)

9.6. Subroutinen-Abarbeitung

Die STEP-Maschine arbeitet somit eine Tokenliste vom Start bis zum Ende ab. Da in der meisten Fällen die Tokens in den CELLs auf weitere Tokenlisten verweisen, wird in der bekannten Art des Subroutine-Nest die augenblickliche Position des IP in der augenblicklichen TL auf dem Control- oder Return-Stack gerettet, und die entsprechende neue Tokenliste abgearbeitet. Trifft die STEP-Maschine auf eine Routine, die Assemblercode des Host-Prozessors enthält, wird der Instruktions-Satz des Host-Prozessors ausgeführt.

9.7. TLSI und Hypertext: Eine produktive Verbindung

Der Grund für die äußerst glückliche Verbindung von TLSI und Hypertext beruht auf zwei Faktoren:
Der TLSI ist ein komplett hierarchisch aufgebautes System von einander aufrufenden Subroutinen, von denen jede einen eigenen (unambiguous) Namen hat. Alle Operatoren, angefangen von ADD, SUBtract, MULtiply, DIVide sind Subroutinen, die über einen eigenen Namen aufgerufen werden. Jede Composite-Subroutine, die aus schon bestehenden zusammengesetzt ist, wird wiederum mit einem eigenen Namen in der Datenbank abgelegt. Somit stellt das ganze System sich als ein System von Hypertextknoten dar.
Der andere Faktor liegt in der Datenstruktur der Tokenliste. Wie in der Abbildung "Das Schema der Tokenlisten-Maschine" ersichtlich ist, ist im Benutzerteil UINT eine Name-Key Datenbank angelegt, die mit einem sehr einfachen Kunstgriff in die Basis für ein Hypertext-System umgewandelt werden kann: Man muß nur zu jedem Namensfeld einen Pointer auf die Datei und Position einfügen, wo der Name-Key vom Compile-Scan gefunden wurde, und man erhält eine Hypertext-Datenbank-Struktur. Da der Compile-Scan schneller als bei Turbo-Pascal funktionierte (ca. 1 MB pro Minute), war eine Hypertext-Indizierung eines großen Projekts mit mehreren MB fast in real-time machbar. Der nächste Schritt schließt sich folgerichtig an: Da das Leibniz-System von Anfang an seinen eigenen, systemintegrierten Editor hatte, war es nur ein kleiner Schritt, im Editor eine Direktabfrage nach dem Namen der Routine unter dem Cursor einzubauen, der mit den Daten der UINT Datenbank Dateinamen und Position augenblicklich zur Verfügung hatte. So war es 1985 gelungen, einen Hypertext-integrierten Editor zu erstellen, der jede beliebige Routine eines großen Projekts von 10.000 Routinen in mehreren hundert Dateien mit einer maximalen Zugriffszeit von 100 MSec zugänglich machte. Diese schnelle Zugriffszeit ist im 32-Bit Modell nur mit einem Assemblerkern möglich, weshalb es bisher auch Probleme bereitete, dasselbe Modell auf Windows (mit 16-Bit Modell des C-Compilers) zu portieren.
Eine derartig schnelle Zugriffszeit von max. 1/10 Sec. erlaubt eine Arbeitsweise des interaktiven Programmierens, die von keinem anderen Software-Entwicklungssystem (nach augenblicklichen Kenntnisstand) erreicht werden kann. Die Vielzahl von Tastendrücken, und Mausklicks, die in einem System wie dem Turbo-Editor nötig ist, um eine Subfunktion einer C-Routine zuzugreifen, erlaubt in keinem Fall eine derartig kohärente und flüssige Arbeitsweise wie im Leibniz-System. Die in Leibniz möglichen Arbeitsgänge sind allerdings in den bekannten Kategorien der Programmierung, die sich eher an dem Prinzip "Langsam aber Sicher" orientiert, und deren Hauptarbeitswerkzeug heute wie vor 20 Jahren immer noch der vi ist, kaum darstellen. Dazu müssen andere Ergebnisse aus der menschlichen Kognitionsforschung, vor allem des Kurzzeitgedächtnisses, und den Verschmelzungseffekten, die bei schnell abfolgenden Bewegungsabläufen, die innerhalb der 1/10 Sekundenschwelle liegen (Tadhani-Effekt) hinzugezogen werden. Diese Effekte sind der Gegenstand eines anderen Papers.

9.8. Frei konfigurierbare, hypertextorientierte Benutzerschnittstellen


Ein Mensch-Maschine-System sollte die folgenden Eigenschaften bieten:
- Die maximale und optimale, individuelle Benutzerkonfigurierung auf der Basis von ASCII-lesbaren Dateien. Jeder Benutzer sollte sich die Makro-Sequenzen so einstellen können, wie es seinen Präferenzen entspricht.
- Kontextsensitive Hilfefunktion. Die Funktion sollte auch den Systemzustand berücksichtigen.
Einige heute erhältliche Softwaresysteme, wie etwa MS-Word bieten zwar die Möglichkeit der individuellen Konfigurierung über eine interne interpretierte Kommandosprache (Word-Basic), aber die aktuelle Konfiguration und die Belegung der Funktionstasten ist nur über komplizierte, und nicht sehr benutzerfreundliche Menus zugänglich. Einfacher wäre eine Konfiguration, die in einer ASCII-lesbaren Datei dokumentiert ist, und mit einem normalen Editor bearbeitet werden kann, wie sie z.B. von EMACS und Abkömmlingen mit der LISP-Programmierung geboten wird.
Das folgende Beispiel zeigt die Konfigurationsdatei aus dem String Interaktor des Leibniz-Systems. Diese Konfiguration ist jederzeit, auch während des Programmlaufs, interaktiv zu ändern.
Die Abbildung "String-Aktor Menus" zeigt die Ansicht des daraus entstehenden Menus.
Hier der Eintrag in der Menu-Konfigurations-Datei:
:GRP VX-IO/MOVE \ i/o and move
LD-VX[ VD-A1
$.user_input 0 I 0 "user input string "
$.get 5 G 0 "get string with len from adr "
$.get_cnt 12 A 0 "get counted string from adr"
$.put 6 P 0 "put string to adr"
$.put_cnt 6 U 0 "put counted string to adr"
$.dup_top 0 D 0 "duplicate top string"
$.mov_2nd 0 M 0 "xchg top 2 strings"
$.copy_2nd 0 C 0 "copy 2nd string to top"
$.copy_# O 0 "copy nth string to top (0cnt) "
$.mov_# 4 T 0 "move nth string to top (0cnt) "
$.mov_bot 0 B 0 "move bottom string to top"
$.push_#x 16 R 0 "move/del to nth_pos top string (0cnt) "
$.del_top 0 X 0 "drop top string"
$.del_#strn 9 N 0 "drop off n strings"
$.len 0 L 0 "length of top string "
END;
(| AG 19:29 08/11/92 )
Eine Zeile der Menu-Datei erklärt die Zuordnungen:
$.user_input 0 I 0 "user input string "
^ ^ ^Menu-Eintrag
^ ^ ^
^ ^ Input-Character (ALT-)
^ ^ optionaler String bei Ausführung des Menus
^
aufgerufende Methode
Durch Integration in das Leibniz-Hypertext-System ist zu jedem Eintrag zudem noch ein kontextsensitiver Help-Text verfügbar, der ebenfalls in einer ASCII-lesbaren Textdatei liegt, die jederzeit editiert werden kann. Unten der Ausschnitt aus der Help-Textdatei zu dem obigen Menu. Für Texte in verschiedenen Landessprachen genügen die Präfixe !ENG !GER !FRA !ITA etc. Die Umschaltung in die verschiedenen Landessprachen kann ebenfalls zur run-time durch das Konfigurationsmenu gemacht werden.
!" XXX
!" $.user_input
!ENG user input string
\LThe user enters a string at the keyboard. The key <ENTER> finishes
the string. With ESC it is possible to leave the input, and a
zero-string is produced. The string input system has an
editing capability which allows to edit the present line with
the cursor control keys and the Wordstar (R) or Turbo (R)
diamond pattern. It also allows to retrieve old inputs and gives a
full-screen editor for them.
!GER Benutzer String eingabe.
!" $.get
!ENG get string with len from adr
\LA string that is at a buffer address is collected into
the String Actor buffer. The length of the string is needed
as second parameter ( adr len -P- )
!GER String Text
!" $.get_cnt
!ENG get counted string from adr
\LA counted string in Pascal format
that is at a buffer address is collected into
the String Actor buffer. The length of the string is
in the count byte at the address.
!GER String Text
!" $.put
!ENG put string to adr
\LThe Top string in the Actor Buffer is deposited
into a buffer address.
!GER String Text
!" $.put_cnt
!ENG put counted string to adr
\LThe Top string in the Actor Buffer is deposited
into a buffer address. The count of the string is in
the first byte of the address (Pascal format).
!GER String Text
!" $.dup_top
!ENG duplicate top string
\LThe Top string in the Actor Buffer is duplicated.
!" $.mov_2nd
!ENG xchg top 2 strings
\LThe Top two strings in the Actor Buffer are exchanged.
!GER String Text
!" $.copy_2nd
!ENG copy 2nd string to top
\LThe Top second string in the Actor Buffer is copied to the
Top, pushing the former Top down to the second position.
The original of the copied second string is then in third
position.
!" $.copy_#
!ENG copy nth string to top (0cnt)
\LThe nth string in the Actor Buffer is copied to Top.
The parameter is interpreted as zero count, ie the
Top string is element # 0, the second is element #1.
!" $.mov_#
!ENG move nth string to top (0cnt)
\LThe nth string in the Actor Buffer is moved to Top.
It is deleted at the former position.
The parameter is interpreted as zero count, i.e. the
Top string is element # 0, the second is element #1.
!" $.mov_bot
!ENG move bottom string to top
\LThe bottom string in the Actor Buffer is moved to Top.
This way, one can completely traverse the whole string
buffer in steps.
!" $.push_#x
!ENG move/del to nth_pos top string (0cnt)
\LThe Top string in the Actor Buffer is moved to nth
position. It is deleted at the Top.
!" $.del_top
!ENG drop top string
\LThe Top string in the Actor Buffer is deleted.
!" $.del_#strn
!ENG drop off n strings
\LThe Top n strings in the String Actor Buffer are deleted.
!" $.len
!ENG length of top string
\LThe number of bytes of the
Top string in the Actor Buffer is left as parameter.
!" XXX
Kontextsensitive Hilfefunktion und Selbst-Auskunftssystem
Die Problematik bekannter Hilfe-Systeme, wie etwa in Windows ist, daß keine exakte Koppelung zwischen dem augenblicklichen Systemzustand und den Hilfstexten besteht. Dies ist nur möglich, wenn der Funktionen-Stack ausgewertet werden kann. Dies ist bei der herkömmlichen (C-Compiler-) Technololgie schwierig. Verwendet man aber ein Interpretersystem wie den in "Leibniz - Ein hypertextbasiertes Softwaresystem" genannten TLSI-Prozessor, so ist die Selbst-Analyse des Systems möglich.


[5]Leibniz® ist ein angemeldetes Warenzeichen von A. Goppold.
[6]Pascal war ebenso wie Leibniz einer der sehr frühen Pioniere der Rechenmaschinen.
[7]Das war 1984! Heute, zehn Jahre später haben wir mit OS/2 und dem noch erwarteten Windows 4 endlich 32-Bit Modelle. Ein 16-Bit TLSI ist aus diversen Gründen kontraproduktiv.
[8] Diese Anwendung war in den folgenden Jahren dann auch der hauptsächliche Einsatzort des Leibniz-Systems.


previous next Title Contents Index