Die erste Idee for(;;) (*ip++)()
eignet sich bei näherer
Betrachtung nur zur Ausführung von Worten, die ausschlieálich aus
Primitives zusammencompiliert sind. Denn es wird angenommen, daá
compilierter Forth-Code aus Listen von Zeigern auf ausführbare
Funktionen besteht. Ein High-Level-Wort ist aber keine ausführbare
C-Funktion.
Die L÷sung besteht natürlich in der Einführung einer weiteren Indirektion: Ein compiliertes Forth-Wort ist ein Zeiger auf einen Platz, in dem ein Zeiger steht, der über die Bedeutung des Wortes entscheidet. Der innere Interpreter wird zu:
for (;;) (**ip++) ();Daraus und aus der angestrebten Traditionalität ergibt sich eine vorläufige Struktur für den Kopf einer Funktion im Dictionary:
Countbyte |
Name |
Link |
CFA |
Body |
... |
Wie kommt die Runtime-Funktion nest zu dem Body der Funktion,
von der aus sie aufgerufen wurde? Sie kann ihn etwas trickreich aus
IP schlieáen: ip = &ip [-1][1]
(mit einigen Type-Casts).
Besser man erleichtert ihr diese Aufgabe indem man im inneren
Interpreter die Variable W der virtuellen Maschine einführt:
for (;;) { w = *ip++; (*w) (); }Mit dieser endgültigen Form des inneren Interpreters lauten nest und unnest:
nest () { *--rp = ip; ip = ++w; } unnest () { ip = *rp++; }
Ein weiteres Problem ergibt sich mit Definitionsworten. Wie gesagt ist für alle Definitionsworte der Code in der CFA eines von ihnen definierten Wortes derselbe. Das Datenfeld beginnt zwingend unmittelbar hinter der CFA. Wo also kann vermerkt werden, von welchem Definitionswort ein Wort definiert wurde?11 Die wenig befriedigende L÷sung besteht in der Einführung eines weiteren Zeigers aux in den Kopf jeder Definition, der im Fall einer von einem Definitionswort definierten Definition diese Information enthalten kann:
Countbyte |
Name |
Link |
Aux |
CFA |
Body |
... |