Nascom Journal |
August 1981 · Ausgabe 8 |
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.
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).
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 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
Seite 3 von 24 |
---|