\documentclass[a4paper]{article} \usepackage[utf-8]{inputenc} \usepackage[german]{babel} \usepackage{url} \usepackage{alltt} \usepackage{multicol} \renewcommand{\reftextbefore}{auf der vorherigen Seite} \renewcommand{\reftextfacebefore}{auf der vorherigen Seite} \renewcommand{\reftextafter}{auf der nächsten Seite} \renewcommand{\reftextfaceafter}{auf der nächsten Seite} \renewcommand{\reftextfaraway}[1]{auf Seite~\pageref{#1}} \renewcommand{\figurename}{Listing} \title{Forth und Skriptsprachen} \author{Reinhold Straub} \begin{document} \maketitle \emph{Wo} läuft Forth? Traditionell gibt es zwei Antworten auf diese Frage: entweder läuft es \glqq nativ auf der Hardware\grqq\ oder es läuft unter einem Betriebssystem. Hier soll eine dritte Antwort gegeben werden: Forth könnte auch auf eine Skriptsprache wie Python, Ruby oder Scheme portiert werden. \begin{figure*}[b] \begin{center} \begin{verbatim} int *dataspace, *systemvariable; int *SP; int *RP; int TOS; static int Forth_Cmd(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj * CONST objv[]) { int resultat; Tcl_Obj *eingabe = NULL; if (objc > 1) { int zahl; int i; for (i = 1; i < objc; i++) { resultat = Tcl_GetIntFromObj(interp, objv[i], &zahl); /* (1) */ if (resultat == TCL_OK) {push(zahl);} else { /* (2) */ eingabe = Tcl_ConcatObj(objc-i, objv+i); break;} } /* Falls nur eine Folge von Zahlen eingegeben wurde, sind wir schon fertig: */ if (eingabe == NULL) {return TCL_OK;} /* Nun die Eingabe an eine Stelle im Wörterbuch schreiben, die von >in benutzt wird: */ int len; systemvariable[1] = (int)Tcl_GetStringFromObj(eingabe,&len); systemvariable[2] = len; } /* ... */ } \end{verbatim} \end{center} \caption{\label{Skriptforth:listing1}C--Implementierung des Befehls \texttt{Forth\_Cmd}} \end{figure*} \begin{multicols}{2} Theoretisch wäre ein Forth, das unter einer Skriptsprache statt unter einem Betriebssystem läuft, nichts Neues. So wie ein Forth sich z.~B.\ auf die Ressourcen von Linux stützen kann, ebenso könnte es sich auf die Ressourcen von, sagen wir, Ruby stützen. Nur praktisch wurde es anscheinend noch nicht versucht. Das ist erstaunlich, denn die Kombination von Forth mit einer Skriptsprache hat eine ganze Reihe von Vorteilen im Vergleich zur Kombination mit einem Betriebssystem. Erstens sind Skriptsprachen nicht nur Funktionsbibliotheken, die den Zugang zu einem Dateisystem oder einem Grafiksystem verwalten, sondern komplette Programmiersprachen, die sich als solche von Forth aus nutzen ließen. Nun ist Forth bekanntlich selbst bereits ein Alleskönner. Dennoch enthalten Skriptsprachen regelmäßig hochabstrakte, leicht benutzbare Konstrukte, die schon vorhanden sind und nicht erst irgendwie gefunden, eingerichtet, geladen oder gar geschrieben werden müssen. Ferner ist Skriptsprachen--Code, jedenfalls in den genannten Sprachen, plattformübergreifend. Die Mühsal, eine API für mehrere Betriebssysteme zu schreiben, und darunter insbesondere eine für das schwierige Windows, haben die tapferen Skriptsprachen--Entwickler auf sich genommen. Davon können auch die Forth--Leute profitieren. \begin{figure*}[t] \begin{quote} \begin{verbatim} int ende = 0; while(1) { resultat = forthevaluate(TOS,(int)rSP,(int)rRP,(int)systemvariable, (int)dataspace,systemvariable[3]); switch(resultat) { case 0: /* Eingabequelle erschöpft */ /* Der Speicher für eingabe kann freigegeben werden: */ Tcl_DecrRefCount(eingabe); ende = 1; break; case 1: /* Coroutine */ ende = 1; break; case 2: /* ... */ /* ... */ } if (ende == 1) break; } \end{verbatim} \caption{\label{Skriptforth:listing2}Die Endlosschleife von \texttt{Forth\_Cmd}} \end{quote} \end{figure*} Schließlich haben die Skriptsprachen große Programmbibliotheken, im Unterschied zu Forth --- was in Forth--Kreisen häufig beklagt wird. Dieser Mangel wäre behoben. Außerdem würdem die Skriptsprachen eine GUI in die Beziehung einbringen; auch das fehlt den meisten Forths. Die Stärken und Schwächen von Forth und die Skriptsprachen scheinen komplementär zu sein: in Forth lässt sich effizienter \emph{Low--Level}--Code schreiben, man kommt an die Bits und Bytes direkt heran. Außerdem ist Forth flexibel; benötigt man eine neuartige Datenstruktur, dann ist man mit dem feinmechanischen Forth besser dran als mit den groben Bausteinen der Skriptsprachen. Die Forth--Kultur ist auch mehr daran orientiert, je eine einzelne Lösung für ein gegebenes Problem zu finden anstelle einer allgemeinen Lösung für viele ähnliche Probleme. Somit würden sich die Abstraktionen der Skriptsprachen und die Konkretion von Forth sehr gut ergänzen. Die API--Funktionen eines Betriebssystems sind allerdings sehr viel differenzierter als die Möglichkeiten der Skriptsprachen, so dass Forths wie Win32Forth für Windows oder Powermops für die Carbon--API des Mac OS durch ein Skriptsprachen--Forth nicht ganz ersetzbar sind. Forths hingegen, die nur in einer Konsole isoliert vom Rest des Betriebssystems laufen wie etwa gforth oder kforth würden auf jeden Fall sehr von der Einbindung in eine Skriptsprache profitieren, glaube ich. Aber auch Powermops ist ein instruktives Beispiel: Es ist ein Forth mit einem optimierenden Compiler für PowerPC--Prozessoren, das die Carbon--API des Mac OS (Classic und X) unterstützt. Nun verkauft Apple keine PowerPC--Prozessoren mehr, und somit tun sich zwei Richtungen auf, in die Powermops weiterentwickelt werden könnte: man kann weiterhin auf Mac OS X setzen und müsste dann mittelfristig den Compiler auf Intel--Assembly umstellen. Oder man bleibt dem PowerPC treu, würde dann allerdings eine neue Betriebssystem--API benötigen. In dieser Situation ergibt es Sinn, Powermops für PPC auf eine Skriptsprache zu portieren und könnte damit \emph{cross platform} auf dem PPC sowohl unter Mac OS X als auch unter Linux arbeiten. Forth und Skriptsprachen haben zudem Gemeinsamkeiten, durch die es leicht fällt, sie ineinander zu integrieren und mit gemischtem Quellcode zu arbeiten. Vor allem sind beide interaktiv und eignen sich für \emph{rapid prototyping}. Forth ist eine imperative Sprache und passt als solche zu Sprachen, die ebenfalls solche Konstrukte aufweisen. \begin{figure*}[t] \begin{quote} \begin{verbatim} int forthevaluate(int lTOS, int lSP, int lRP, int systemvariable, int dataspace, int addressofentry) { int linkvar, countvar, resultat; asm{ mr r3,lTOS /* "move register", nämlich lTOS nach Register r3 */ mr r4,lSP /* man kann hier keine globalen Variablen benutzen */ mr r5,lRP mr r6,systemvariable mr r7,dataspace mfctr countvar /* "move from count register", nämlich "to countvar" */ mflr linkvar /* "move from link register" - "to linkvar" */ mtctr addressofentry /* "move to count register" */ bctrl /* "branch to count register and link": die Codeadresse der nächsten*/ /* Zeile ist jetzt auf dem link register. */ /* Forth sichert sie dann als erstes für den Rücksprung. */ mtlr linkvar /* alten Inhalt des link register wiederherstellen */ mtctr countvar /* alten Inhalt des count register wiederherstellen */ mr dataspace,r7 mr systemvariable,r6 mr lRP,r5 mr lSP,r4 mr lTOS,r3 mr resultat,r8 /* Forth setzt die Flagge für Tcl auf Register r8 */ } TOS = lTOS; SP = (int *)lSP; RP = (int *)lRP; return resultat; } \end{verbatim} \end{quote} \caption{\label{Skriptforth:listing3}Der Übergang von C nach Assembly} \end{figure*} Nun gibt es verschiedene Möglichkeiten, zwei Sprachen zu kombinieren. Die einfachste besteht wohl darin, beide in ihrer jeweiligen Umgebung laufen zu lassen und die Möglichkeit der Kommunikation zwischen Prozessen zu benutzen, wie etwa Applescript oder Unixröhren (\emph{pipes}\/). Das geht, ist jedoch etwas teuer, so dass man sparsam damit umgehen würde und die Arbeit nur grobkörnig auf die beteiligten Sprachen aufteilen würde. Um die jeweiligen Vorteile optimal zu nutzen, wäre eine wesentlich engere und vielseitigere Verzahnung vermutlich sinnvoller. Zweitens könnte man Skriptsprachen--Code von Forth aus aufrufen; das wäre so ähnlich wie die Benutzung einer Betriebssystem--API von Forth aus. Drittens könnte man die Skriptsprache um einen Forth--Evaluate--Befehl erweitern, so dass es möglich wird, Forth--Code von der Skriptsprache her auszuführen. Viertens könnte man das Forth und die Skriptsprache in Form von Coroutinen zusammenschalten. Diese letztgenannten drei Möglichkeiten sollen im Folgenden genauer betrachtet werden. Ich arbeite an einem Projekt, das ein neues kleines spezielles Forth für PowerPC--Prozessoren auf Tcl/Tk zum Laufen bringen soll. Hier wird es jedoch nicht um das Forth gehen, sondern um die Methode, wie es in Tcl eingefügt wird. Die Wahl von Tcl/Tk als Skriptsprache ist einigermaßen willkürlich, da ich der Meinung bin, dass jedes Desktop--Forth es verdienen würde, auf \emph{jede} Skriptsprache portiert zu werden; also insbesondere auch auf Tcl/Tk. Allerdings kann es scheinen, dass Tcl eine besonders Forth--kompatible Sprache ist. Aus Forth--Sicht besteht ein Tcl--Skript aus einer Serie von Befehlswörtern; und zwar handelt es sich dabei jeweils um ein \emph{parsing word}, das die folgenden Wörter bis zum Zeilenende liest, dann bestimmte Substitutionen vornimmt, wodurch die Argumente für das Befehlswort gebildet werden, die kommen dann --- sozusagen --- auf den Stapel und schließlich wird der Befehl ausgeführt. Dieses kleine Beispiel zeigt etwa den Umgang von Tcl mit Variablen: \begin{verbatim} % set x 17 17 % puts $x 17 \end{verbatim} Das Kommando \texttt{set} parst die folgende Zeile, die Zeichenkette \texttt{x} wird der Name der Variablen, die Zeichenkette \texttt{17} ihr Wert. Das Kommando puts parst den Rest der Zeile, da steht nur \texttt{\$x}, \texttt{x} wird als Variablenname erkannt, das \texttt{\$}--Zeichen holt den Wert aus der Variablen (substituiert die Zeichenkette \texttt{\$x} durch die Zeichenkette \texttt{17}), damit ist der Parameter für \texttt{puts} gebildet, und \texttt{puts} schreibt ihn auf die Konsole. Nun besteht bekanntlich auch Forthcode aus einer Folge von Befehlswörtern, wobei manche den Quellcode parsen, so dass sich Forth im Kontext von Tcl und Tcl im Kontext von Forth ganz gut sehen lassen könnten. (Aus Tcl--Sicht erscheint ein Forth--Wort wie ein parameterloser Befehl mit gewissen Seiteneffekten bzgl. Stapel, Wörterbuch, Datenraum.) Man kann Tcl durch neue Befehlswörter erweitern. Zum Beispiel ließe sich ein Tcl--Befehl \texttt{forth} definieren, der die folgende Zeile liest und sie per \texttt{EVALUATE} bearbeitet. Umgekehrt kann Forth ein Wort \texttt{tcl-eval} enthalten, das Tcl--Code ausführen lässt, z.~B.: \begin{verbatim} S" set x 17" tcl-eval \end{verbatim} Neue Befehlswörter für Tcl lassen sich in C schreiben. Man erzeugt hierfür eine Datei mit Binärcode, die zur Laufzeit in Tcl geladen wird. Eine Möglichkeit hierfür liefert der Tcl--Befehl \texttt{package}. \begin{verbatim} % package require forth \end{verbatim} Der Package--Befehl ruft nun eine Funktion namens \verb|Forth_Init| auf. Die ist dafür zuständig, aus einer Datei die Konfigurationsdaten des Forth zu lesen, Speicher für Wörterbuch, Coderaum und Stapel zu besorgen, die Adressen an Orten zu notieren, wo Forth sie lesen kann --- also alles, um Forth so weit zu starten, dass es Zeichenketten als Forth--Code evaluieren kann. Außerdem erzeugt \texttt{Forth\_Init} einen Tcl--Befehl namens \texttt{forth}. \begin{figure*}[t] \begin{quote} \begin{verbatim} :ppc_code EVALUATE r9 mflr, \ Rücksprungadresse nach forthevaluate(C) r9 16 r6 stw, \ an systemvariable[4] speichern \ Schleife: parsen, finden, usw. r9 16 r6 lwz, \ toplevel Rücksprungadresse nach r9 geholt r9 mtlr, \ toplevel Rücksprungadresse nun auf dem link register blr, ;ppc_code \end{verbatim} \end{quote} \caption{\label{Skriptforth:listing4}\texttt{EVALUATE} in PowerPC--Assembly} \end{figure*} \begin{figure*}[b] \begin{quote} \begin{verbatim} :ppc_code tcl-eval r8 3 li, \ "load immediate", nämlich die Zahl 3 auf Register r8. \ Dies ist der Rückgabewert für switch case Tcl_EvalObjEx r10 mflr, \ Adresse der nächsten Instruktion \ des tcl-eval aufrufenden Wortes nach r10 holen und r10 12 r6 stw, \ an systemvariable[3] speichern (NB 3 4 * 12 =). (stw: "store word") r9 16 r6 lwz, \ toplevel Rücksprungadresse aus systemvariable[4] \ nach r9 holen ("load word") r9 mtlr, \ und auf das link register schieben blr, \ "branch to link register": \ zurück geht's nach forthevaluate! ;ppc_code \end{verbatim} \end{quote} \caption{\label{Skriptforth:listing5}\texttt{tcl--eval} in PowerPC--Assembly} \end{figure*} So ein Tcl--Befehl besteht wie gesagt aus einem Befehlswort am Zeilenanfang, gefolgt von einer Serie von Parametern, die am Zeilenumbruch (oder auch an einem Semikolon) enden. Theoretisch bräuchte man für \texttt{forth} nur einen Parameter, nämlich die Zeichenkette, die an \texttt{EVALUATE} übergeben wird. Dennoch kann man sich die Tatsache, dass mehrere Parameter möglich sind, zunutze machen: in Tcl gilt nämlich der Grundsatz, dass \glqq Alles eine Zeichenkette ist\grqq, aber Tcl--Variablen enthalten intern oft eine effizientere Darstellung, z.~B. würde die Variable \texttt{x} nach \begin{verbatim} % set x 17 \end{verbatim} die Zahl \texttt{17} unter Umständen nicht nur als Zeichenkette \verb|"17"|, sondern auch als Binärzahl enthalten. Die Umwandlung der Zeichenkettendarstellung in die Binärdarstellung erfolgt z.~B., wenn eine mathematische Operation ausgeführt wird wie \texttt{incr \$x}. \texttt{x} enthält jetzt die Binärzahl \texttt{18}, während die Zeichenkettendarstellung als ungültig gesetzt wird. Ein weiteres \texttt{incr \$x} würde dann unmittelbar die Binärzahl verwenden und müsste nicht erst die Zeichenkette in eine solche umwandeln. Der Befehl \texttt{puts \$x} würde dann aus der Binärzahl \texttt{18} wieder die Zeichenkette \verb|"18"| machen --- die Zeichenkettenversion wurde ja ungültig gesetzt --- um sie auszugeben. Dieser Mechanismus hat Tcl schnell gemacht. Wir können ihn auch für den \texttt{forth}--Befehl nutzbar machen, zum Beispiel so: Wir gehen die Parameter der Reihe nach durch und prüfen, ob es sich um Zahlen handelt. Falls ja, wird die Zahl sofort auf den Stapel gelegt. Treffen wir auf einen Parameter, der keine Zahl ist, dann verbinden wir diesen und alle weiteren Parameter zu einer einzigen Zeichenkette und evaluieren sie. Auf die Weise ist es möglich, Folgendes zu schreiben (in Tcl): \begin{verbatim} % set x 17; set y 4 4 % forth $x $y + . 21 \end{verbatim} Das ist unter Umständen sehr viel schneller als: \begin{verbatim} % forth "$x $y + ." 21 \end{verbatim} Sofern \texttt{x} und \texttt{y} intern ihren Wert als Binärzahl halten, ist nämlich im ersten Fall keine Umwandlung Zahl $\rightarrow$ Zeichenkette $\rightarrow$ Wörterbuchsuche $\rightarrow$ Zahl nötig, wie sie im zweiten Fall geschieht, da die Zahlen \texttt{17} und \texttt{4} sofort auf den Stapel kommen und dann nur noch \texttt{+ .} in Forth evaluiert wird. Der C--Code hierfür sieht etwa so aus, wie in \figurename\ \vref{Skriptforth:listing1} zu sehen ist. Der Parameter \verb|Tcl_Obj * CONST objv[]| enthält die Serie der Tcl--Parameter mit denen der Befehl forth aufgerufen wurde: \begin{verbatim} % forth par1 par2 par3 \end{verbatim} ergibt \texttt{objc = 4}, \texttt{objv[0] =} \verb|"forth"|, \texttt{objc[1] =} \verb|"par1"|, etc. (1) Die C--Funktion \texttt{push(}zahl\texttt{)} legt \texttt{zahl} auf den Stapel. Sie kann z.~B.\ so implementiert werden: \begin{verbatim} push(int zahl) { SP = SP-stackcellsdistance; *SP = zahl; } \end{verbatim} (2) \verb|Tcl_ConcatObj| kopiert die Argumente in einen neuen Speicherbereich. Das ist etwas ineffizient; man könnte auch den Parameter \verb|objv[objc]| direkt verwenden, falls es der erste Parameter ist, der keine Zahl enthält. Jetzt kann das Forth aufgerufen werden. Da Forth selbst zwischendurch immer wieder Tcl--Funktionen benötigt (wie z.~B. für \verb|ALLOCATE|) --- und ohnehin ein enges Zusammenspiel mit Tcl angestrebt wird --- folgt nun eine Art von Coroutinen--Konstruktion: die Funktion \verb|Forth_Cmd| ruft in einer Endlosschleife immer wieder Forth auf; braucht Forth eine Tcl--Funktion, unterbricht es sich, speichert die Adresse der nächsten Instruktion und gibt eine Flagge an \verb|Forth_Cmd| zurück. Mit Hilfe der Flagge wird eine Tcl--Funktion aufgerufen und dann geht es entweder nach Forth zurück oder nach Tcl. Das sieht dann etwa so aus wie in \figurename\ \vref{Skriptforth:listing2}. Hierbei enthält \verb|systemvariable[3]| das Forth--xt, welches ausgeführt werden soll, also in der Regel \verb|['] EVALUATE|. Es wird bereits in \verb|Forth_Init| bestimmt und dort hineingeschrieben. Da das Befehlswort \texttt{forth} in C geschrieben wird, liegt es sicherlich nahe, auch das Forth selbst, d.~h.\ die Funktion \texttt{forthevaluate} in C zu schreiben; bzw.\ dürfte es für C--Programmierer nicht schwer sein, C--basierte Forths so nach Tcl zu portieren. Mein eigenes Forth ist allerdings in PowerPC--Assembly geschrieben, so dass also noch der Übergang von C nach Assembly gemacht werden muss, wie in \figurename\ \vref{Skriptforth:listing3} zu sehen ist. (So elegant geht das nur mit gcc leider nur unter Mac OS X. Bei anderen Systemen muss man gcc inline assembly verwenden.) \texttt{addressofentry} ist hier wie gesagt in der Regel das xt von \texttt{EVALUATE}. Um Subroutinen aufzurufen hat der PowerPC zwei spezielle Register: das \texttt{count}--Register und das \texttt{link}--Register. Hier wird das \texttt{count}--Register verwendet. (Ich hoffe die Kommentare im Code machen einigermaßen klar, was hier passiert, auch wenn man PPC--Assembly vielleicht nicht versteht.) Forth ist nun dran und tut seine Arbeit: Eingabe parsen, xt finden usw.\ (siehe \figurename\ \vref{Skriptforth:listing4}). An \texttt{systemvariable[4]} steht jetzt die Adresse des Befehls \texttt{mtlr linkvar} aus \texttt{forthevaluate}. Damit kann sich Forth selbst jederzeit unterbrechen, um Tcl zu bemühen (\figurename\ \vref{Skriptforth:listing5}). \texttt{Forthevaluate} gibt nun die Flagge \texttt{3} an \verb|Forth_Cmd| zurück, also landet man in \texttt{case 3} des \texttt{switch}--Blocks: \begin{small} \begin{verbatim} case 3: /* addr-len-String als Tcl-Code evaluieren */ resultat = Tcl_EvalObjEx( interp, Tcl_NewStringObj((char *)*NOS,TOS),0); *NOS = Tcl_GetStringFromObj( Tcl_GetObjResult(interp),&TOS); break; \end{verbatim} \end{small} \texttt{NOS} ist hierbei \texttt{SP+stackcellsdistance}. Das Kommando \verb|Tcl_EvalObjEx| wertet die Zeichenkette, die auf dem Stapel liegt (welcher ja von \verb|Forth_Cmd| aus zugänglich ist, da \texttt{forthevaluate} \texttt{TOS} und \texttt{SP} in C--Variablen sichert), als Tcl--Code aus und schreibt das Ergebnis in die Result--Variable des Tcl--Interpreters, der den \texttt{forth}--Befehl auswertet. Dort holen wir es --- als Zeichenkette --- heraus, wobei der zweite Parameter von \verb|Tcl_GetStringFromObj| die Länge der Zeichenkette enthält: so liegt das Ergebnis als (c-addr len)--Zeichenkette auf dem Stapel. Das \texttt{break} verlässt den \texttt{switch} und die \texttt{while}--Schleife ruft wieder \texttt{forthevaluate}. Diesmal wird jedoch nicht das xt von \texttt{EVALUATE} übergeben, sondern die Adresse der nächsten Instruktion des \texttt{tcl-eval} aufrufenden Wortes, d.~h. Forth setzt sein Werk an der Stelle fort, wo \texttt{tcl-eval} es unterbrochen hatte. Angenommen, in Tcl--Hochsprache sei Folgendes kodiert gewesen: \begin{verbatim} % forth { S" puts $x" tcl-eval TYPE} 17 \end{verbatim} (In Tcl schließen geschweifte Klammern Zeichenketten ein.) \texttt{tcl-eval} unterbrach den Textinterpreter, der nun weitermacht, das Wort \texttt{TYPE} liest und es ausführt. \texttt{TYPE} unterbricht Forth wieder und ruft eine Tcl--Funktion, die NOS und TOS als Zeichenkette erkennt und in einer \emph{dynamischen Zeichenkettenvariablen} (DString) speichert: \begin{verbatim} case 6: /* unterstützt TYPE */ Tcl_DStringAppend(&dsPtr,(char *)*NOS,TOS); twodrop(); break; \end{verbatim} (\texttt{dsPtr} sammelt zwischenzeitlich alle Ausgaben per TYPE oder . (dot).) Jetzt ist erstmal der Forthinterpreter wieder dran, aber da die Eingabe erschöpft ist, geht es mit der Flagge \texttt{0} nach Tcl zurück, infolgedessen wird die Variable \texttt{ende} auf \texttt{1} gesetzt, und die Endlosschleife \texttt{while(1)} verlassen. Es folgt nur noch: \begin{verbatim} Tcl_DStringResult(interp, &dsPtr); return TCL_OK; \end{verbatim} Damit endet \verb|Forth_Cmd|, die Result--Variable des Tcl--Interpreters enthält nun den DString \texttt{dsptr} mit allen Textausgaben, die der Forth--Aufruf erzeugt hat. Sowohl das Forth als auch die Verbindung Forth--Tcl sind bislang erst rudimentär implementiert, eine ganze Reihe von Fragen ist noch offen; um nur eines zu nennen, man muss zum Beispiel damit rechnen, dass Tcl--Code, der von Forth aus evaluiert wird, seinerseits den \texttt{forth}--Befehl enthält und also Forthcode evaluiert werden soll, und dann stauen sich zwei unvollendete Forth--Evaluierungen an, es entsteht ein Stapel von Eingabe--Zeichenketten, der irgendwie verwaltet werden muss. Dennoch glaube ich, dass man es ungefähr so machen kann, wie es hier skizziert wurde, und dass Forth von der Einbettung in eine Skriptsprache unmittelbar profitieren würde, indem die vielfältigen Möglichkeiten dieser Sprachen sofort zugänglich werden, während umgekehrt Forth bei den Skriptsprachen vielleicht eine neue Nische finden könnte, in der es von Nutzen wäre. \end{multicols} \end{document}