FORTH für den NASCOM
von Günter Kreidl
Es soll hier nicht wieder, wie es leider schon häufiger im
NASCOM-JOURNAL geschehen ist, auf mehreren Seiten ein Programm
ausführlich beschrieben werden, das dann anschließend zum Kauf
angeboten wird. Andererseits wird hier auch kein
"betriebsfertiges" FORTH-System vorgelegt, das man nur noch
einzutippen braucht. Vielmehr verstehe ich diesen und die folgenden
Beiträge als Einladung an die Leser, gemeinsam ein solches FORTH-System
zu entwickeln. Um eine Grundlage zu haben, wird in diesem Heft zunächst
der prinzipielle Aufbau von FORTH erläutert. Im nächsten Heft erscheint
dann das Assemblerlisting einer "Schmalspurversion" bzw.
eines TINY FORTH, das wir dann gemeinsam ausbauen und verbessern wollen.
"Fädelcode"
Wer öfters größere Programme in Assembler oder Maschinensprache
schreibt, hat sich vielleicht eine Bibliothek von Routinen
zusammengestellt, die dann universell einsetzbar sind. Große Teile
eines solchen Programms sehen dann oft so aus:
CALL Routine1
Registeranpassung
CALL Routine2
Registeranpassung usw.
Unter Registeranpassung wird hier alles verstanden, was mit dem Retten
von Registerinhalten über die PUSH-Befehle und der Übergabe von
Parametern zwischen den Unterprogrammen zusammenhängt. Wenn man nun
statt der individuellen Registeranpassungen ein Standardsystem der
Parameterübergabe einführt, vereinfacht sich das Programm erheblich.
Nehmen wir einmal an, alle Parameter werden über den Stack übergeben.
Da dann auch keine Registerinhalte mehr gerettet werden müssen, besteht
das Programm nur noch aus Unterprogrammaufrufen:
CALL Routine1
CALL Routine2 usw.
Jetzt kann man sich aber auch noch den CALL-Befehl selbst sparen, wenn
man stattdessen eine Routine einführt, die eine Reihe von aufeinander
folgenden Adressen eben als Adressen von Unterprogrammen
| |
interpretiert. Wir brauchen also einen kleinen INTERPRETER, der diesen
speziellen Code, der nur aus einer Aneinanderreihung von Adressen von
Unterprogrammen besteht, abarbeiten kann. Dieser kleine Interpreter,
der nicht mehr als ca. 50 Bytes Speicherplatz belegt, und dieser
spezielle Code, den man im Englischen THREADED CODE nennt, was ich hier
mit Fädelcode übersetzt habe, bilden das Kernstück von FORTH. Der
Interpreter ist wesentlich kleiner als bei anderen "höheren"
Programmiersprachen und wesentlich schneller (etwa 10 x so schnell wie
ein Basic-Interpreter).
Bestandteile von FORTH
Woraus besteht also die Programmiersprache FORTH? Zunächst einmal aus
einer Bibliothek von Routinen in Maschinensprache (sogenannten
"Primitives"). Aus diesen Routinen sind dann weitere Routinen
im Fädelcode zusammengesetzt. Beide Arten von Routinen können von dem
oben beschriebenen Interpreter aufgerufen werden. Diesen
THREADED-CODE-INTERPRETER wollen wir den internen Interpreter nennen,
denn das System verfügt noch über einen anderen, den äußeren oder
Benutzerinterpreter, der interaktiv die Eingaben des Anwenders (Text
oder Zahlen) in Startadressen für den internen Interpreter umwandelt.
Der dritte Bestandteil von FORTH ist ein Compiler, der es ermöglicht,
der Sprache weitere Befehle als Threaded-Code -Routinen hinzuzufügen.
Ein ausgebautes FORTH-System enthält darüber hinaus noch einen Editor
und einen Assembler - und das alles in 5 - 6 K Speicherplatz.
Der interne Interpreter
Der interne Interpreter imitiert gewisse Funktionen der CPU. Dazu
braucht er einen Programmzähler und einen eigenen Stack. Programmzähler
und Stackpointer befinden sich im Speicher, da die entsprechenden
CPU-Register natürlich anderweitig benutzt werden. Seine Funktion ist
einfach: er holt die nächste Adresse (aus dem Fädelcode!) aus dem
Speicher und führt einen Sprung dorthin aus. Diese Adresse ist entweder
die Adresse einer Routine in Maschinensprache - diese wird dann
ausgeführt und endet nicht mit einem Return-Befehl sondern mit einem:
JP NEXT (der Name des Interpreters)
- oder die Adresse einer Routine im Fädelcode. Eine solche muß
stets mit einer
|