[english] : [zurueck] : [anfang] : [L4 archiv] :-: [mail] :   : DPANS94 : f.i.g. UK : FORTH e.V. :  





 
lib4th (L4)
Der Forth-Kern enthält einen ausführbaren Processor-Code compilierenden "subroutine threaded native code" Compiler und Interpreter, wobei der Interpreter sich vom Compiler (im wesentlichen) nur durch die sofortige Ausführung des gerade compilierten Codes unterscheidet. Alle 'syscalls' beliebiger Linux-Versionen sind mit Namen aufrufbar, sie werden beim Erzeugen der L4 aus den jeweils vorhandenen Kernel-Quellen des Linux übernommen. "lib4th"-Quellen und Hilfsprogramme sind ausführlich kommentiert, samt einer 'handgefertigten' (der "nasm"-Assembler leistet leider nichts dergleichen), Labels und deren Aufrufstellen verzeichnenden Querverweis-Liste ("cross reference").
 
Die Worte des Forth liegen als Subroutinen vor, sodaß sie auch unmittelbar zur vereinfachten Assemblerprogrammierung benutzt werden können. Man mag sowas "High Level Assembler" nennen - und hat damit dem Kind einen (m.E. ziemlich hohlen) Namen gegegben. Die Vielseitigkeit solchen Zugangs auf Assembler-Niveau ist damit nicht annähernd beschrieben, diese werden wohl nur eigene Versuche veranschaulichen.
 
Die "lib4th" besteht aus nur positionsunabhängigem und wiedereintrittstauglichem Code und enthält keinerlei Bezug auf fremde Datenstrukturen ("g.o.t", "p.l.t", o.dgl.), d.h. solche, die nicht dem Forth selber zueigen sind. Sie ist von allen Linux/ELF-Spezifika soweit unabhängig, daß sie sich nach Anpassung der 'syscalls' leicht auch innerhalb anderer Systeme verwenden lassen sollte.
Grund für die Einrichtung als eigenständiger, insbes. auch von einer libc unabhängiger "dll" ist zum einen der grandiose Mist, der in einigen der "glibc"-Versionen produziert wurde und wohl auch weiterhin zu erwarten ist (2.2.5!), sowie vor allem mein Wunsch, nicht mit jedem neuen Forth-Programm wieder und wieder immer auch den ganzen Kern und irgendwelche zweifelhaften Hilfsprogramme in den Speicher holen zu müssen. Was neben der Speicheranforderung auch die Startzeit der betr. Programme (mit K6-2/350mcs um eine sagenhafte Millisekunde) verringert. Zugriff aus andersartigen Programmen steht vorerst nicht im Vordergrund.
Der 'subroutine threaded native code' compilerende und interpretierende Aufbau ist vor allem wegen seiner gegenüber den traditionellen Ansätzen einfacheren und z.B. im Hinblick auf geeignete Register-Zuordnung weit besseren Darstellbarkeit entstanden, und wegen der im Gegensatz zu den Ergebnissen gemeiner Programmierhilfen wie "C" u.dgl. bis ins letzte Detail überschaubaren inneren Gestalt. Die im Forth relativ seltene Möglichkeit, auch Schleifen und bedingte Konstrukte 'interaktiv', ohne vorheriges Compilieren in ein "Wort" auszuführen, ergab sich auf diese Weise von selbst und hat den Compiler/Interpreter eher noch weiter vereinfacht. Die recht hohe Ausführungsgeschwindigkeit wurde als willkommenes Nebenprodukt zwar beachtet, aber doch nur zweitrangig mitgenommen; sie hat erst nach Vorliegen einiger Tests durch ihre (für mich) unvermutet guten Werte besonderen Stellenwert erlangt. Ganz drollig, am Rande, daß die L4 in den c.l.f.-news bei gutem Willen zwar bestenfalls als originelle private Einzellösung aufgenommen wurde, sich später aber Meldungen über ähnliche Ansätze in bemerkenswerter Weise zu häufen beginnen - natürlich (mit einer Ausnahme) ohne Bezug auf die "lib4th". Niedlich, das:)
 
Anwendungen
liegen neben dem - inzwischen hinreichend erprobten und bewährten - Blockfile-Editor noch kaum vor. Das Startprogramm "f8ed" zum L4 Blockfile-Editor gibt u.a. ein Beispiel für automatisches Compilieren eines Programmtextes und Starten der betr. Erweiterung durch ein ausführbares Basis-Programm. Auch der Umgang mit CREATE .. DOES>, den besonderen Kontrollworten für FORGET, der periodisch durch SIGALARM ausgelösten (Teil-)Programm-Ausführung, Formatierung der Bildschirm-Ausgabe u.v.m. ist dort am konkreten Beispiel nachvollziehbar.
Die bekannten ANS-4th Testprogramme wie (der nicht wirklich standardkonforme!) "coretest", "bench", das obligatorische "tetris", auch ein Assembler und Disassembler (Quellen im Archiv), u.dgl. werden immerhin erfolgreich verarbeitet. Da sämtliche "syscalls" des jeweiligen Linux-Kerns leicht handhabbar zur Verfügung stehen, eignen sich die L4-Programme besonders auch zu recht sicheren Experimenten mit diesen Systemaufrufen.
Im Übrigen sei auf die einfachen Programme im Quellenpaket verwiesen, "f8" mit etwas über 1K Bytes Programm-Größe zum Einsprung in das Forth-System, und "calc4th" als absolutes Minimalprogram zum Einsprung in den lib4th-Kern mit gerade mal 628 Bytes, für die Nutzung des Forth-Systems z.B. als einem interaktiven rsp. als Script ausführbaren Kommandozeilen-Rechner für Ganze oder Reelle Zahlen zu beliebiger (sinnvoller) Basis 2..256 bei unbegrenztem(!) Wertebereich - aus welchen Vorhaben nebenbei die gesamte "lib4th" sintemalen überhaupt erst entstanden ist...
"quotaq" entstand aus der Notwendigkeit, meinen (nicht zuletzt deshalb aufgegebenen) Inet-Bunker bei "snafu" (r.i.p.) zu kontrollieren, seit man dort besonders clever die Preise 'korrigiert' hat und stillschweigend die zugesagten 10MB in 'Cluster'-Einheiten nichtgenanter Größe vergibt, und die Grenze pedantisch rsp. eher 'vorausschauend' überwacht - aufgrund welcher seltsamen Interpretation mein "quota" überschritten war. Das Script ermittelt den Platzbedarf einer Anzahl Dateien aus einer nach Muster der Linux-Ausgabe von <ls -l ...> übergebenen Liste und erzeugt abhängig von der Art des Aufrufs ggf. auch eine HTML-Datei mit einem entsprechenden, 'gelinkten' Verzeichnis. Neben dem Nutzeffekt zeigt es insbes. den Umgang mit den verschiedenen Typen der Ein-/Ausgabe-Umleitung in einem L4-Script.
"p3f" als Secundär-Filter zum Perl-Programm "POP3Filter" veranschaulicht einige besondere Funktionen der Textbearbeitung und gibt Hinweise zur Anwendung als Forth-Script mit Ein-/Ausgabe auch über 'pipes'. Er ist sehr simpel aufgebaut, sein praktischer Nutzen hält sich (noch) in recht engen Grenzen.
"htmlxref.f8" dient der Erzeugung der Querverweis-Referenzen zu den L4-Quellen. Das per {INCLUDE} o.ä. zu compilierende Programm liefert sein Ergebnis bereits nach ca. 5m ("call-by-disp"-Modus), mit dem vorher verwandten "bash"-Script wurden für dieselbe Aufgabe ca. 60m benötigt. Es arbeitet dazu für jedes der gut 2400 Forth-Worte 1MB Quelltexte durch und liefert den Ort der Definition mit Filenamen und Zeilennummer, entsprechend alle Stellen, an denen das betr. Wort aufgerufen wird, und es legt einen Verweis auf den zugehörigen Glossar-Eintrag an. Insbes. für den Zugriff auf mit {MMAP} in den Speicher eingeordnete Dateien und für die Vielseitgkeit von {EVALUATE} bieten sich darin einige Anwendungsbeispiele. Besonders hilfreich ist die Möglichkeit, mit EVALUATE aus den von der Kommandozeile hineigereichten Filenamen die jeweils zugeordneten Datenposten in Form von daraus benannten {CONSTANT}- und {VALUE}-Definitionen einzurichten und abzufragen, etwa Bereichsgröße und Basisadresse des betr. Dateien-Bereichs. Die mmap-Variante hat gegenüber dem unmittelbaren File-Zugriff die Ausführungszeit des Forth-Programms insgesamt auf ca. 1/3 reduziert - beide im L4-Archiv.
 


DPANS94:

Compilieren von ANS-Forth-Programmen erfordert selten besondere Änderungen. Aufrufe über { ' execute } sollten nur bei genauer Kenntnis der Worteigenschaften (z.B. mit "help") benutzt werden, da aufgrund der Besonderheiten des Compilers viele zustandsabhängige "immediate" Worte existieren, die dann u.U. fehlerhaft ausgeführt werden.
 
Verknüpfung zwischen Zahlen- oder reinen Binärwerten und der inneren Zahlendarstellung ist zu vermeiden (s.u.).
 
Im gesamten lib4th-System werden Datengruppen "little endian" (höherwertige Teile zu höhergelegenen Adressen hin) abgelegt. Dadurch kann es zu Konflikten kommen, da das ANS-Forth die für x86-Rechner absurde "big-endian" Anordnung doppelt-genauer Gruppen von "CELLS" vorschreibt. Entsprechende Worte finden sich im {ans}-Vocabular, das ggf. vorrangig in die Such-Ordnung aufzunehmen ist.
 
Der Forth-Standard nach "ANS" ist mir nicht ultimativer Maßstab, wohl aber hervorragende Grundlage für austauschbare Programme und Ausgangspunkt zur Verständigung über das, was - ohne seine Eigenschaft als Betriebssystem - ein "Forth" ausmacht. In diesem Sinne mag man meine Bemühungen sehen, besagtem Standard Genüge zu tun.


 

Da die L4-Dokumentation in englischer Sprache abgefaßt ist, in loser Folge ein paar ergänzende Angaben:


 

Dokumentation
liegt als "Glossary" in Klartext vor, außerdem in einer Gruppe html-Texte, in der die ca. 2400 Worte des Kerns nach verschiedenen Gesichtspunkten geordnet sind, "l4gls.html, "l4toc.html", etc. "l4xrf.html" ist eine Querverweis-Liste der Aufrufe und Einsprungstellen in den Assembler-Quellen. Wurde die Vorgabe nicht geändert, finden sich die Texte nach Installation im Verzeichnis "/usr/share/doc/lib4th" und einige Beispiele in "/usr/local/lib/f8".
Zu allen Worten des Kerns kann jederzeit, auch während einer Wortdefinition, der zugehörige Glossar-Text in's Bild geholt werden, { help forthwort } gibt den Text zum ersten in der gesamten Vocabularliste gefundenen "forthwort" aus. Soll nur in der Reihenfolge des Vocabularstacks gesucht werden, schreibt man { hv help forthwort }.
Ob ein Wort überhaupt vorhanden ist, zeigt { v forthwort } an, indem es entweder die "lfa" als Referenz in den Wortheader und das Vocabular, in dem es definiert ist, ausgibt, oder ein Fragezeichen, wenn es unbekannt ist.
Den Zustand des Vocabularstacks zeigt {order}, und {vocs} gibt aus, welche Vocabulare vorhanden sind.

Localer Speicher, "Value"s
"Locals" werden in einem zum Zeitpunkt der Ausführung betr. Worte angelegten geschlossenen Speicherbereich durchgehend adressierbar und ohne Einfluß auf irgendwelche Zugriffsformen auf andere Daten (Stacks, Speicher) angeordnet. Sie sind durch nichts eingeschränkt, als ihre auf das Wort bezogene Gültigkeit, ihre Namen sind gewöhnliche Forth-Namen aus bis zu 255 Schriftzeichen, ihre Anzahl ist einzig durch den gerade verfügbaren Speicher begrenzt. Es können jederzeit auch in der Größe frei wählbare Bereiche eingerichtet werden. Stets ist der geordnete Zugriff auf die jeweils übergeordneten "Locals" in der Kette aufrufender Worte möglich.
Andererseits werden viele LOCALs dadurch entbehrlich, daß alle Varianten {PICK} und {ROLL} mit negativem Argument die jeweilige Umkehr-Operation ausführen. Negatives {PICK} erlaubt damit auch Rückspeichern an ausgewählte Stackpositionen ohne zeitraubende und u.U. auch verwirrende Datenschaufelei. Sofern nicht größere geschlossene Speicherbereiche benötigt werden (die "der Standard" ebensowenig vorsieht), zeigte sich diese Vorgehensweise der Verwendung von "LOCALs" weit überlegen.
 

Byte Order
ist die Reihenfolge von Daten im Speicher, die, wenn nicht strikt auf Konsistenz geachtet wird, oft (und leicht) zu Konflikten und Mißverständnissen führt.

Vieles, insbes. einfache Arithmetik an größeren Posten, läßt sich in der little-endian-Manier leichter ausführen, als in 'big-endian'-Anordung. - In über zehnjähriger Mühsal z.B. mit den MC680xx-Processoren ist mir kein Fall begegnet, wo letztere irgendeinen nennenswerten Vorteil erwiesen hätte. Beschränkte Erfahrung, sicherlich, und vielleicht rein persönlicher Eindruck, sei's drum, die L4 "wohnt" im 386er Linux. Und dort liegen Bytes (nahezu) unvermeidlich nur 'little endian', wirre Spezifikationen "des" Standards implizieren aber die 'big-endian'-Ablage von Zellen-Paaren, jedoch, man muß wohl nicht jeden Unsinn mitmachen.
L4 ist ganz stur 'little endian' organisiert, selbst, wenn irgendwer das aus welch krausen Gründen auch immer anders vorgesehen haben sollte. Nach ANS geforderte Mischformen wurden in das gleichnamige Vocabular ausgelagert, stehen damit zwar zur Verfügung, belästigen aber auch nicht weiter.
In Konsequenz sind einige Spielereien aus dem ANS-Forth mit L4 nur im {ans}-Vocabular möglich:
Abschließend und nur für besonders Hartnäckige: Die Inkonsistenz liegt darin, daß in der Speicheradressierung fortschreitende Adressen vorzeichenlos zu höheren Zahlenwerten hin gezählt werden und nicht, wie in grauer Frühzeit gelegentlich gängige Praxis, zu niedrigeren Werten hin. In letzterem Falle wäre die 'big-endian' Anordnung durchaus vernünftig; wo's sowas aber noch geben mag, entzieht sich meiner Kenntnis, und so ist mir das Raisonieren über eine 'bessere' Datenanordnung nur noch nostalgisch nutzlose Zeitvergeudung.

Zahlen
Bei Ein- und Ausgabe aller Zahlenarten einschl. "Fließkomma" wird die in der User-Variablen {BASE} gerade eingestellte Umrechnungsbasis zugrundegelegt, lediglich innerhalb von Texten zur Ausgabe mit {TYPE} &c nach dem Muster "\nnn" gilt stets die oktale Basis als Vorgabe.
Zusätzlich läßt sich die Basis einer einzelnen Zahl mit einem Praefix festlegen:

Zweiercomplement
In L4 gilt strikt die Anwendbarkeit der Negation auf jede beliebig Zahl. Die (einer nicht ganz unbekannten Quelle entnommene) Sequenz zur Ermittlung der kleinsten darstellbaren, negativen Zahl
    { 0 INVERT 1 RSHIFT INVERT CONSTANT MIN-INT }
sieht zwar ungemein "Standard"-mäßig aus, ist aber doch nur Unsinn (s. u.a. DPPANS94 3.1.3.2), oder bestenfalls als 'Überlauf in das Vorzeichen-Bit' interpretierbar. Etwa die Charakterisierung der Null nach dem Axiom der Addition durch { 0+x =/= 0-x } für alle x=/=0 führt mit nach obigem Modell besetztem x zum Widerspruch, (in 'c.l.f.' gehabte) Streitereien um deren Gültigkeit sind müßig. Des einfachen Begriffes halber und wegen { 0-x = 0+x } sowie {x < 0 } heißt solch ein Bitmuster im Zusammenhang mit L4 auch 'negative Null'.
Im übrigen belegt auch die Charakterisierung gültiger Zahlen im DPANS94-Dokument, derzufolge etwa die Sequenz { DUP NEGATE OVER OVER < ROT ROT > = } für keinen von Null verschiedenen Wert das Ergebnis "{true}" haben darf, die Wertlosigkeit der o.g. Herleitung.

BIGNUM
steht kurz für eine Art Ganzzahlen, deren Repräsentation aus einem Zähler als erster "Zelle" und der entsprechenden Anzahl 32bit-Posten der Zahl besteht. Notation negativer Werte im Zweiercomplement. Deren Größe ist nur durch den gerade verfügbaren Speicherplatz begrenzt. Es sind sämtliche arithmetischen Operationen einschließlich Quadratwurzel und Stackmanipulationen vorhanden, die erforderlich sind, um diese Zahlenart leicht und vollwertig einsetzbar zu machen. Alle betr. Operationen finden im Datenstack ohne zusätzlichen Speicherplatz statt, sie sind uneingeschränkt Recursions-tauglich.

Rationale Zahlen
genauer, die "Reellen Zahlen", bestehen aus Paaren von Ganzzahlen für Zähler und Nenner eines (ggf. unechten) Bruches. D.h. Operationen für "Fließkommazahlen" sind auch in der lib4th enthalten, allerdings nicht in der vergleichsweise schlecht zu verarbeitenden Form nach IEEE-Norm. Die Darstellung als Bruch zweier Zahlen erlaubt sehr einfache und schnelle arithmetische Operationen sowie die völlig problemfreie Verknüpfung mit den "normalen" im Forth gewöhnlich bevorzugten Ganzzahlen beliebiger Postengröße. Insbes. die Scalierungsoperatoren wie { */ } sind dazu praedestiniert. Weiterrechnen nach Aufteilung in Ganzzahl und reinen Bruch ermöglicht unbegrenzte Genauigkeit und eindeutige Rundungsergebnisse - wo die Zahlenrepräsentation nach IEEE-Norm völlig versagt. Nebenbei kann damit wie bei Ganzzahlen mit gleichermaßen geringem Aufwand in jeder auch auf jene anwendbaren Zahlenbasis gerechnet werden.
Ein- oder Ausgabe in Form einer "Fließkomma"-Zahl oder einzeln als Zähler und Nenner, Ausgabe zusätzlich auch als gemischt gebrochene Zahl, beides zu der in {BASE} gegebenen Zahlenbasis, Eingabe auch mit Praefix (s.o.).
Die RATIONAL rsp. FLOATING/-EXT Wortsätze sind vollständig nach ANS und bezüglich aller Erfordernisse, d.h. sie enthalten bei einstellbarer Genauigkeit die Grundrechenarten samt Quadratwurzel und transzendenten Funktionen (e- und Winkel-Funktionen) sowie viele unterstützende Worte, so z.B. eine FOR/STEP/NEXT-Variante mit variierbarem Laufindex rsp Increment. Ausführungszeit der leeren Schleife mit gebrochenem Increment ca 30-fach gegenüber DO/LOOP mit einfachen Ganzzahlen, andere Worte ab etwa dem Vierfachen doppeltgenauer (64-Bit) Ganzzahl-Operationen, einige brauchen weit weniger, etwa das Reziproke oder die Negation.
Das {FLOAT}-Vocabular enthält die Worte des ANS-Forth nebst Umformung zwischen der vom Standard geforderten Datenrepräsentation nach IEEE-Norm und dem eigenen RATIONAL-Format.

Ein/Ausgabe-Umleitung
und die recht effiziente Zwischenspeicherung bewerkstelligt der Linux-Kern bereits, die L4 fügt lediglich eine Indirektion hinzu, um zum einen der Vorgabe des ANS-Forth Genüge zu tun, die eine einzelne Zelle als eindeutige Kennung einer offenen Datei vorschreibt, welche aber für den geordneten Zugriff nicht immer ausreicht, und zum andern die Vereinheitlichung des Zugriffs sowie Bereitstellung besonders häufig benötigter Parameter (File-Pointer, -Größe, Zustandsflags) zu ermöglichen. Dies sind die als Indices in eine Tabelle von entspr. Datenblöcken dargestellten "Kanäle", die den File-Operationen anstelle der wirklichen "File descriptoren" des Linux übergeben werden.
Besondere Kanäle sind "stdin", "stdout", "stderr" entsprechend den Linux-Konventionen, sowie "work", der einheitlich bestimmten Operationen dient und u.a. durch {open-file} besetzt wird; "kbd" weist stets auf die Tastatur, "dr0" und "dr1" sind vorrangig den "Blockfiles" zugeordnet. {new-chan} gibt den ersten freien Platz der Kanaltabelle zurück, und {is-chan} besetzt jenen Kanal mit den betr. Daten aus "work", die damit zugleich auch vor dem Überschreiben geschützt werden. Um auch das Vertauschen solcher Knäle zu ermöglichen, wird dabei ein unter einem solchen Index bereits offener Kanal nicht automatisch geschlossen. Das ggf. zuvor aufzurufende {close-file} macht zunächst die betr. Kanaltabelle ungütig und schließt den wirklichen Systemkanal nur, wenn derselbe 'file descriptor' nicht auch noch unter anderen Kanalnummern (außer "work") eingetragen ist.
{in-chan}, {out-chan}, {err-chan} sind Kernel-VALUEs, die beim Systemstart automatisch mit den Standardkanälen des Linux besetzt werden und diese z.B. zur Verwendung in Scripts vor dem Überschreiben durch die Initialisierung des ausführenden Forth-Jobs schützen. Beim (interaktiven) Aufruf ohne Ein- oder Ausgabe-Umleitung sind sie mit {stdin}, {stdout}, {stderr} identisch.
Die Anforderungen sind nicht ganz leicht zu bewätigen:

	Ein- und Ausgabe existieren in den Konstellationen
			pipe:	eingabe | f8 | ausgabe
			file:	f8 <eingabe ausgabe>
			cmd:	f8 forthworte -- inaktive-daten
			script:	-in allen Varianten-
Die Arbeit mit beliebigem Kombinationen davon ist nicht immer ohne weiteres möglich, da eine ggf. benutzte Script-Datei, "stdin" und die Kommandozeile um den Interpreter konkurrieren, der den "Eingabestrom" stets aus "stdin" empfängt. Auf relativ einfache Weise unterstützt das Wort {x-i/o} den jeweils benötigten Zugriff, das im {root}-Vocabular definiert und damit stets verfügbar ist. Es vertauscht die Standardkanäle mit den beim Start übergebenen:
Ein Script liegt dem ausführenden Forth zunächst selbst als Text in "stdin" vor, sodaß, weil der Interpreter stets aus diesem Kanal liest, er erst nach dessen Abarbeitung rsp. an sonstwie geeigneter Stelle durch den ggf. umgeleiteten Text ersetzt werden kann. Da die Kanäle nur vertauscht werden und offen bleiben, kann von der jeweils freigegebenen Seite aus beliebig zwischen ihnen umgeschaltet werden. Werden nur Daten in ein Script gereicht, ist diese Umschaltung unnötig, sie erlaubt aber die Abarbeitung von Programmteilen sowohl z.B. über Pipe-Eingabe als aus der Kommandozeile desselben Aufrufs, auch nach dort eingetragenem "include" anderer Programmquellen.

BLOCK
Forth-"screenfiles" oder "blockfiles" bestehen aus Klartext ohne irgendwelche Steuerzeichen, der üblicherweise so angeordnet wird, daß er in Zeilen zu 64 Zeichen lesbar ist. 16 solcher Zeilen heißen eine "screen", gedacht als Mindestmaß selbst auf bescheidenen Sichtgeräten (z.B. von Meßgeräten, Maschinen) zumeist noch darstellbaren Bildschirminhalts, mit 1K Bytes zugleich vereinbarte Blockgröße und ganzzahliges Maß für die Länge der betr. Dateien.
Vorteil dieser Ablageform ist ihre größtmögliche Einfachheit und damit weitgehende Unabhängigkeit von der jeweiligen System-Umgebung, die leichte Wiedergabe auf Druckern oder Sichtgeräten, auch effiziente Comprimierbarkeit, oder z.B. der sehr kompakte Aufbau zugehöriger Editoren - der Zeileneditor im L4-Kern belegt gerade mal 2K Speicher. Verlust von Texten etwa durch Speicherüberlauf während des Editierens ist unmöglich, da stets nur in bereits zugewiesene Bereiche geschrieben wird. Selbstätige Pufferung und Übergabe des Pufferinhalts an die betr. Datei machen die "Block-Puffer" ebensogut ganz allgemein zur Datengewinnung und -Verarbeitung tauglich.
L4 richtet Pufferspeicher für "blockfiles" bedarfsweise automatisch durch die betr. Worte ein, mit {FORGET} eines älteren Wortes (sie selbst haben keinen Header) kann ihr Speicher freigegeben werden. Auch dies geschieht automatisch und bedarf außer evtl. vorherigen Sicherns veränderter Daten keiner besonderen Vorkehrungen, Einrichtung eines "Forget-Handlers" kann ggf. auch diese Aufgabe noch automatisieren. Zusätzliche Puffer können durch Aufruf in nur durch den verfügbaren Speicher begrenzter Zahl zugewiesen werden - was im allgemeinen nicht erforderlich sein wird.
Die Blockpuffer haben "PAGE_SIZE"-Größe (vier unmittelbar einander folgende "screens" zu je 1K) und liegen an entsprechend justierter Adresse, wodurch sie sich auch zur Einordnung beliebiger Files in den Speicher etwa mittels Syscall "mmap" eignen.
Verschiedenen Files werden jeweils unabhängige Pufferblöcke zugeordnet. Alle Blockfile-Operationen finden nur an den Puffern statt, die zu dem gerade bearbeiteten Kanal gehören.

FORGET
geht völlig problemlos durch alle Vocabulare der aktuellen Such-Ordnung und erfaßt auch Vocabulare rsp. "wordlist"s selbst. "current" und "context" werden ggf. möglichst auf den vorherigen Zustand gesetzt, notfalls geht "forth" nach "current", im Vocabularstack wird anstelle gelöschter Vocabulare "local" eingetragen, das dort von neutraler Wirkung ist, da es ohnehin stets zuerst durchsucht wird.
DEFERed Worte stellen sich beim Aufruf automatisch auf die z.B. mit {default-is} festgelegte Vorgabe zurück, wenn das eigentliche Ziel nicht im benutzten Codebereich liegt, oder werden inaktiv, falls auch jene entfernt wurde. Sie sollten darum nach FORGET vor der Definition anderer Worte etwa mit { 0 is name } deaktiviert werden, da sie andernfalls das nächste mit dem "uot-Index" der ersten Festlegung (s. Glossar, "execution token") bezeichnete Wort ausführen würden. Diese Deaktivierung kann auch ein zusätzlicher "forget-handler" erledigen:
Durch { FORGET: forthwort ..auszuführende Wortfolge.. ; } lassen sich ohne Ausnahme allen Worten beliebig viele, ggf. der Reihe nach auszuführende "forget-handler" in Form gewöhnlicher Wortdefinitionen zuordnen, die unmittelbar vor Entfernen des betr. Wortes automatisch aufgerufen werden.
Aus CREATE und DOES> gebildete Definitionsworte können in der Form {.. CREATE .. FORGET> handlerwort DOES> ..} erweitert werden, sie weisen dann den daraus entstehenden Worten ohne weitere Vorkehrungen einheitlich diesen Handler zu.

Textverarbeitung
wird insbes. unterstützt durch:

Sicher nicht sonderlich sinnvoll, aber immerhin, wegen der besonderen Textbehandlung können auch Forth-Namen mit Zeichen, die nicht durch die Tastatur erreichbar sind, problemlos hingeschrieben werden, etwa
    : DIESER\#160COMPUTER [ latest ] literal id. ."  ist meiner.\n" ;
    DIESER\#160COMPUTER
(s. "bench.f8").
 
Als Zeichensatz gilt, was für die Linux-Konsole (oder ein X-Terminal) gerade eingestellt ist. Alle Schriftzeichen (derzeit code 0...256, Unicode -vorsichtig- in Vorbereitung) sind erreichbar, Einschränkung auf die im ANSI-Standard beschriebenen, aber - auch wenn Gegenteiliges gerne zitiert wird - keineswegs darauf begrenzten us-ascii-Zeichen ist nicht vorgesehen. Wäre m.E. gar zu absurd, ausgerechnet durch solcherlei unnötige Beschränktheit den Nutzen eines Forth-Systems auf einen minderen Interessentenkreis zu begrenzen. Auch Zusammensetzen von Schriftzeichen durch Betätigung mehrerer Tasten ist möglich, sofern die zugrundeliegende Linux-Konsole(n-Emulation) dies vorsieht rsp. einzustellen erlaubt.
Umschalten zwischen den Zeichensätzen sehr einfach z.B. mittels VT-Steuersequenzen, Änderungen auch des Schriftbildes sind mit dem 'ioctl'-Systemaufruf bei Angabe neuer Zeichensätze möglich.
{EMIT} sendet alle Bytes einer 32-Bit-"Zelle", beginnend mit der niederwertigeren Position und solange, bis nur noch Nullen übrigbleiben. Dies ist recht bequem bei der Ausgabe kleiner, bekannter Zeichenfolgen, ist aber in erster Linie als Voraussetzung für die - noch fehlende - Ausgabe von Unicode-Zeichen vorgesehen.

Terminal/Console
sind mit den Definitionen ihrer Steueraktionen in eingermaßen verrottetem Zustand. Linux-Distributionen und selbst einzelne Programme kommen zudem noch oft mit eigenen Definitionen, die aus welch rätselhaftem Grunde auch immer deren Autoren der Vorgabe für überlegen zu halten scheinen, die aber kaum mehr bewirken, als die Verwirrung zu steigern. Seitens der "lib4th" werden darum weder 'termcap'- noch 'terminfo'-Daten in irgendeiner Weise interpretiert oder überhaupt wahrgenommen, die betr. Worte senden lediglich ihre Steuercodes an das jeweilige Terminal und es bleibt dem Anwender überlassen, die in den betr. VT-Beschreibungen dargestellten Aktionen ggf. entsprechend zu konfigurieren. Solche Konfiguration ist im allgemeinen nicht schwer, nur es ist aufgrund des herrschenden Durcheinanders (mir) gar zu umständlich, ein von 'außen' hinzukommendes Programm zuverlässig darauf einzustellen. Auch soll die "lib4th" diesem Wirrwarr nicht noch eine weitere Konfigurationsvariante hinzufügen.
Für die - eher ferne - Zukunft ist auch Auswertung der 'terminfo' vorgesehen. Bis dahin müssen die fest codierten Aktionen genügen, sofern sich nicht jemand anderes aufrafft...
Die betr. L4-Worte sind soweit irgend möglich so gestaltet, daß die bereits zwischen der Linux Console und einem der ihr am nächsten stehenden Terminal-Emulatoren für X-Windows, "rxvt", bestehenden Unterschiede in den VT-Steuersequenzen nicht in Erscheinung treten. D.h, "Linux Console" und "rxvt" sind mit den Worten der L4 annähernd gleichartig kontrollierbar. Ein Beispiel hierzu gibt der Screenfile-Editor, "f8ed". Andere Terminal-Emulationen sind z.T. derart eingenwillig definiert, weisen selbst versionsbedingt noch erhebliche, schlecht bis garnicht dokumentierte Unterschiede auf (z.B. "xterm"), daß sie einfach nur unberücksichtigt bleiben konnten.

>BODY
ergibt unterschiedliche, vom jeweils gerade gegebenen Wort abhängige Adressen, erzeugt konstante Referenz einzig in Bezug auf den gerade compilierten Code, steht auch bei gleicher Grunddefinition nicht immer im selben Abstand zu irgendeinem anderen Speicherort! Dasselbe trifft auf {>DATA} zu, mit dem man die {>body} entsprechende Referenz auf bereits im Kern definierte umd beim Systemstart in den schreibbaren Speicher übertragene Datenposten erhält.
Hier offenbart sich ein (früher) Entwurfsfehler; generelle Referenz über den Abstand zur Basisadresse des Datenbereichs wäre zwar ein wenig langsamer, in vielerlei Hinsicht aber weitaus günstiger, entspr. Änderung ist - vorerst mal in eher ferner Zukunft - vorgesehen.

save-system kommt nicht vor,
denn das Compilieren von Forth-Textquellen geht außerordentlich schnell, braucht kaum mehr Zeit, als etwa `Linken' einer zusätzlichen Library, und ist, da der Inhalt damit völlig offengelegt ist, die einzige für jeden Anwender sicher durchschaubare Form eines Programms. Fest daran binden lassen sich solche Quellen durch entsprechende Eintragung in den Programm-Rumpf, der Screenfile-Editor "f8ed" gibt ein Beispiel dafür. Nebenbei macht dieses Verfahren den Copright-Kram einfacher und erspart mir den zickigen Aufbau (a la GNU &c) zur Lizensierung von Folgeprogrammen, da jene und die lib4th so stets klar unterscheidbar bleiben. Auch wird Schwachsinn der Art 'behead' oder sonstwie mutwilliges Unleserlichmachen von Forth-Namen durch das Compilieren von Klartextquellen sicher unterbunden, ein weiterer Grund, weshalb auch für spätere L4-Versionen vorcompilierbare Programme oder Module definitiv nicht vorgesehen sind.

Code-Optimierung
Abgesehen davon, daß es nicht #die# Optimierung gibt und ich mich auch nicht mit hohlem Gequake über Super-optimierende Super-Compiler - die "man" hat, aber über die offenbar niemand verfügt - abgebe, die folgende Notiz; mehr dazu im Text "a-forth-design" des Quellenarchivs:

Auch ohne die hier beschriebenen Mätzchen sind L4-Programme recht schnell, im allgemeinen schneller als gleichartige "C"-Proggramme (s. Beispiel am Ende der Seite). Weiteres zur "Optimierung" dürfte sich damit vorerst erübrigen...


 
Was neben allen anderen Details (hoffentlich...) hinreichend in der beigefügten Dokumentation beschrieben ist.
Kommentare & Anregungen, egal welcher Art, interessieren mich sehr; ggf. bitte e-mail.


 

 

 



 

 



 
H.-Peter Recktenwald, Berlin, 12.Juni 2000 = .hpr.l0 = : 44-452

 

"Systems Software Research is Irrelevant", Rob Pike, Bell Labs Lucent Technologies, rob@plan9.bell-labs.com, Feb 21, 2000: "Linux may fall into the Macintosh trap: smug isolation leading to (near) obsolescence...