<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">\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 &gt; 1) {
        int zahl;
        int i;
        for (i = 1; i &lt; objc; i++) {
            resultat = Tcl_GetIntFromObj(interp, objv[i], &amp;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 &gt;in benutzt wird: */
        int len; systemvariable[1] = (int)Tcl_GetStringFromObj(eingabe,&amp;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),&amp;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(&amp;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, &amp;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}</pre></body></html>