% Content-encoding: UTF-8
\documentclass[ngerman]{article}
\usepackage[utf8]{inputenc}
\usepackage{multicol,babel}
\setcounter{secnumdepth}{0}
\setcounter{tocdepth}{0}

\renewcommand{\reftextbefore}{auf der vorherigen Seite}
\renewcommand{\reftextfacebefore}{auf der gegenüberliegenden Seite}
\renewcommand{\reftextafter}{auf der nächsten Seite}
\renewcommand{\reftextfaceafter}{auf der gegenüberliegenden Seite}

\renewenvironment{lyxcode}
{\par\begin{list}{}{
\setlength{\leftmargin}{0pt}
\setlength{\rightmargin}{\leftmargin}
\setlength{\listparindent}{0pt}% needed for AMS classes
\raggedright
\setlength{\itemsep}{0pt}
\setlength{\parsep}{0pt}
\normalfont\ttfamily}%
 \item[]}
{\end{list}}

\begin{document}

\title{\emph{F}orth \emph{I}nspired \emph{C}ommand \emph{L}anguage (\emph{FICL}%
\thanks{\protect\url{http://ficl.sourceforge.net}})}
\author{Gerd Franzkowiak}
\ifx\shorttitle\undefined\else
\shorttitle{FICL}
\fi
\maketitle

\begin{abstract}
\noindent Auf der Suche nach einem kleinen FORTH--System für meine
Embedded--Linux--Entwicklung stieß ich vor einiger Zeit auf FICL. Erfreulicherweise 
konnte ich auf einem ARM9--System mit \texttt{Clibc--Linux}%
\footnote{Linux wurde compiliert mit der für eingebettete Systeme optimierten
C library \texttt{Clibc}} ein ca. 100~KB großes statisches \emph{ficl} erzeugen. Dies schien
mir ansprechend genug, um das System mal etwas näher zu beleuchten.\\
\\
\emph{Zitat:}\\
\textsl{\scriptsize Wenn die meisten sich schon armseliger Kleider
und Möbel schämen, wie viel mehr sollten wir uns da erst armseliger
Ideen und Weltanschauungen schämen.}{\scriptsize{} }\textit{\scriptsize }\\
\textit{\scriptsize (Albert Einstein)}{\scriptsize{} }{\scriptsize \par}
\end{abstract}

\begin{multicols}{2}

\section{Einführung}

Eigentlich ist \emph{FICL} nicht als 100\%--iges FORTH entstanden.
Es lehnt sich aber stark an den ANS von 1994 und vermittelt mit der
ersten Anwendung sofort FORTH--feeling.

Entwickelt wurde \emph{FICL} von \emph{John~Sadler} und auf der $20^{th}$
FORML Conference 1989 vorgestellt. John~Sadler wollte ein Tool, welches
für schnelle und effektive Entwicklungen in andere Anwendungen, vorrangig
C/C++, einzubetten ist und auf verschiedenster Firmware nutzbar sein
kann. Aufgrund dessen hat John den Kern komplett in ANSI--C geschrieben. 

Die Lizenz von \emph{FICL} ist im Stil der BSD--Lizenz und stellt somit
kaum ein Hindernis für eine große Zahl von Projekten dar.

Dementsprechend kann man \emph{FICL} auch als Bootloader für den
Kernel von FreeBSD finden.


\section{Erste Schritte}

Mir ging es bei meinem ersten Versuch darum, einfach mal meinen Treiber,
den ich für ein FPGA auf einer ARM9--Anwendung geschrieben hatte, anzusprechen. 

Gesagt, getan, nahm ich mir als Toolchain die ScratchBox von Nokia
(GPL) zur Hand, schob die Quellen von ficl4.0.31 hinein, compilierte
erfolgreich und kopierte es auf das genannte Board.

Ich startete <./ficl> und --- siehe da; \textit{loading, Date, version}
--- es lief. 

Mit der Eingabe von \emph{WORDS} fühlte ich mich auch gleich in der
richtigen Umgebung. Es ist fast alles vorhanden, was man in FORTH
so benötigt.

Um nun meine Treiber mal anzusprechen, versuchte ich,
\begin{lyxcode}
s\textquotedbl{}~/dev/myfpga\textquotedbl{}~r/w~open-file~throw~Value~fd
\end{lyxcode}
einzugeben, und konnte mit 
\begin{lyxcode}
s''~xxx''~fd~write-file~fd~close-file
\end{lyxcode}
erste Reaktionen erleben. 
\begin{quote}
Das nahezu ideale Tool !
\end{quote}
Welche Reaktionen das auf dem Board waren, ist hier nicht so wichtig,
es wurden jedenfalls Tabellen--Werte im FPGA eingetragen.


\section{Der Aufbau}

\begin{center}
\includegraphics[scale=0.5]{2009-02/ficl-system}
\end{center}

In FICL wird mit dem Start ein System angelegt, welches aus mindestens
einer virtuellen Maschine, mit zugehörigen Dictionarys, besteht, aber
auch aus mehreren VMs bestehen kann.

Mit dem Anlegen eines FICL--Systems existiert automatisch ein ANS~Forth~CORE~word~set,
welches dann, nach der entsprechenden Intitialisierung, die Dictionarys
der virtuellen Maschine(n) anlegt. Das Schöne an den virtuellen Maschinen
ist, dass jede einen eigenen Status hält und eigene I/O--Kanäle möglich
sind. 

Darüber hinaus ist, zu des Programmierers Glück, FICL--Code auch noch
\emph{thread~safe} und \emph{re--entrant}.

Für denjenigen, welcher sich in FICL einarbeiten möchte, liegt eine
umfangreiche Dokumentation vor und die Sourcen bieten natürlich beste
Informationen.


\subsection{Das Prinzip}

FICL ist, entsprechend Anton Ertls Beschreibung%
\footnote{\url{http://www.complang.tuwien.ac.at/forth/threaded-code.html}%
} über Threaded Code als Switch Threading Forth entwickelt worden.

Das Application Interface gestaltet sich recht einfach, gut und überschaubar.
Ein Beispiel für den Aufruf aus anderen C--Applikationen kann so aussehen,
wie es in \textit{main.c} vorliegt:
\begin{lyxcode}
{\scriptsize \#include~<stdio.h>}{\scriptsize \par}

{\scriptsize \#include~<stdlib.h>}{\scriptsize \par}

{\scriptsize \#include~\textquotedbl{}ficl.h\textquotedbl{}}{\scriptsize \par}



{\scriptsize int~main(int~argc,~char~{*}{*}argv)~\{}{\scriptsize \par}

{\scriptsize{}~~~~int~returnValue~=~0;}{\scriptsize \par}

{\scriptsize{}~~~~char~buffer{[}256{]};}{\scriptsize \par}

{\scriptsize{}~~~~ficlVm~{*}vm;}{\scriptsize \par}

{\scriptsize{}~~~~ficlSystem~{*}system;}{\scriptsize \par}



{\scriptsize{}~~~~system~=~ficlSystemCreate(NULL);~/{*}~System~anlegen~{*}/}{\scriptsize \par}

{\scriptsize{}~~~~ficlSystemCompileExtras(system);}{\scriptsize \par}

{\scriptsize{}~~~~vm~=~ficlSystemCreateVm(system);~/{*}~Virtual~Machine~erzeugen~{*}/}{\scriptsize \par}



{\scriptsize{}~~~~returnValue~=~ficlVmEvaluate(vm,}

{\scriptsize{}~~~~~~~~~~~~~~~~~~~~~~~~~\textquotedbl{}.ver~.(~\textquotedbl{}~\_\_DATE\_\_~\textquotedbl{}~)~cr~quit\textquotedbl{});}{\scriptsize \par}



{\scriptsize{}~~~~while~(returnValue~!=~FICL\_VM\_STATUS\_USER\_EXIT)~\{}{\scriptsize \par}

{\scriptsize{}~~~~~~~~fputs(FICL\_PROMPT,~stdout);}{\scriptsize \par}

{\scriptsize{}~~~~~~~~fgets(buffer,~sizeof(buffer),~stdin);}{\scriptsize \par}

{\scriptsize{}~~~~~~~~returnValue~=~ficlVmEvaluate(vm,~buffer);}{\scriptsize \par}

{\scriptsize{}~~~~\}}{\scriptsize \par}

{\scriptsize{}~~~~ficlSystemDestroy(system);}{\scriptsize \par}

{\scriptsize{}~~~~return~0;}{\scriptsize \par}

{\scriptsize \}~}{\scriptsize \par}
\end{lyxcode}
Genau auf diese Art und Weise ist man in einem C--Projekt auch in der
Lage, mal einen kleinen interaktiven Part einzubinden und sich ein
wenig im System umzusehen.

Mit der Funktion \textsc{ficlSystemCreate} und einer angepassten Struktur,
statt dem NULL--Pointer in der Parameterübergabe, bieten sich dann
weitere Möglichkeiten eines eigenen Systems an.
\begin{lyxcode}
{\scriptsize struct~ficlSystemInformation~\{}{\scriptsize \par}

{\scriptsize{}~int~size;~~~~~~~~~~~/{*}~structure~size~tag~for~versioning~{*}/}{\scriptsize \par}

{\scriptsize{}~void~{*}context;~~~~~~/{*}~Initializes~VM's~context~pointer~-}

{\scriptsize{}~~~~~~~~~~~~~~~~~~~~~~~~~~for~application~use~{*}/}{\scriptsize \par}

{\scriptsize{}~int~dictionarySize;~/{*}~Size~of~system's~Dictionary,~in~cells~{*}/}{\scriptsize \par}

{\scriptsize{}~int~stackSize;~~~~~~/{*}~Size~of~all~stacks~created,~in~cells~~{*}/}{\scriptsize \par}

{\scriptsize{}~ficlOutputFunction~textOut;~~/{*}~default~textOut~function~{*}/}{\scriptsize \par}

{\scriptsize{}~ficlOutputFunction~errorOut;~/{*}~textOut~function~used~for~errors~{*}/}{\scriptsize \par}

{\scriptsize{}~int~environmentSize;~/{*}~Size~of~Environment~dictionary,~in~cells~{*}/}{\scriptsize \par}

{\scriptsize \};~}{\scriptsize \par}
\end{lyxcode}
Zu erkennen ist, dass mit dieser Struktur schon eigene Ausgabe--Funktionen
festgelegt werden können. Soll dies für jede VM erfolgen, so wird
es über Callback--Funktionen der VMs realisiert.


\subsection{Netzwerk--Anbindung}

Schaut man sich z.B. FORTH--83--Systeme an, so war es schon eine Kleinigkeit,
wenn man den Ein--/Ausgabestrom auf andere Hardware umlenken wollte.
Es genügte schon, die Worte KEY?, KEY und EMIT anzupassen, und ein FORTH--System
funktionierte beispielsweise über eine serielle Schnittstelle.\\
Bedenkt man, welche Klimmzüge C--Programme da vollziehen mussten
und welche Software--Monster (PC--Irgendwas) da notwendig wurden, war
FORTH immer schon entwicklerfreundlich.\\
Mit Netzwerkanbindungen, z.B. über einen TCP/IP--Stack, ist es natürlich
nicht so einfach. Nicht einfach ASCII--Zeichen werden übertragen, sondern
ein kompletter Protokollstapel muss durchlaufen werden.\\
FICL bietet mit seiner Methode jedoch ein recht elegantes Verfahren,
was ein FORTH, sofern in dessen Umgebung ein TCP/IP--Stack vorhanden
ist, schnell über ein Netzwerk bedienbar macht.\\
Meine Versuche waren das Anbinden des TCP/IP--Stacks an das FICL--System
auf folgende Art:

\begin{quote}
\begin{lyxcode}


{\scriptsize /{*}}{\scriptsize \par}

{\scriptsize{}~{*}~my.c}{\scriptsize \par}

{\scriptsize{}~{*}/}{\scriptsize \par}

{\scriptsize \#include~<stdio.h>}{\scriptsize \par}

{\scriptsize \#include~<string.h>}{\scriptsize \par}

{\scriptsize \#include~<stdlib.h>}{\scriptsize \par}

{\scriptsize \#include~<signal.h>}{\scriptsize \par}

{\scriptsize \#include~\textquotedbl{}ficl.h\textquotedbl{}}{\scriptsize \par}



{\scriptsize /{*}}{\scriptsize \par}

{\scriptsize{}~{*}~Example~of~server~using~TCP~protocol.}{\scriptsize \par}

{\scriptsize{}~{*}/}{\scriptsize \par}

{\scriptsize \#include~<sys/types.h>}{\scriptsize \par}

{\scriptsize \#include~<sys/socket.h>}{\scriptsize \par}

{\scriptsize \#include~<sys/wait.h>}{\scriptsize \par}

{\scriptsize \#include~<netinet/in.h>}{\scriptsize \par}



{\scriptsize \#define~SERV\_TCP\_PORT~65535}{\scriptsize \par}

{\scriptsize \#define~SERV\_HOST\_ADDR~\textquotedbl{}\textquotedbl{}}{\scriptsize \par}



{\scriptsize void~catcher();}{\scriptsize \par}



{\scriptsize typedef~struct~\{}{\scriptsize \par}

{\scriptsize{}~~FILE~~~{*}fptr;}{\scriptsize \par}

{\scriptsize{}~~int~~~~newsockfd;}{\scriptsize \par}

{\scriptsize \}~myVmSockPar;}{\scriptsize \par}



{\scriptsize myVmSockPar~vmSockPar;}{\scriptsize \par}

{\scriptsize int~~~~~~~~~sockfd;}{\scriptsize \par}



{\scriptsize /{*}}{\scriptsize \par}

{\scriptsize{}~{*}~Callback~function}{\scriptsize \par}

{\scriptsize{}~{*}/}{\scriptsize \par}

{\scriptsize void~myCbTextOut(ficlCallback~{*}pCB,~char~{*}text)~\{}{\scriptsize \par}

{\scriptsize{}~~char~buffer{[}256{]};}{\scriptsize \par}

{\scriptsize{}~~FICL\_IGNORE(pCB);}{\scriptsize \par}

{\scriptsize{}~~if~(text~!=~NULL)~\{}{\scriptsize \par}

{\scriptsize{}~~~~fputs(text,~stdout);}{\scriptsize \par}

{\scriptsize{}~~\}}{\scriptsize \par}

{\scriptsize{}~~else~\{}{\scriptsize \par}

{\scriptsize{}~~~~fflush(stdout);}{\scriptsize \par}

{\scriptsize{}~~\}}{\scriptsize \par}

{\scriptsize{}~~return;}{\scriptsize \par}

{\scriptsize \}}{\scriptsize \par}



{\scriptsize /{*}}{\scriptsize \par}

{\scriptsize{}~{*}Callback~function~for~TCP~connection}{\scriptsize \par}

{\scriptsize{}~{*}/}{\scriptsize \par}

{\scriptsize void~mySocketTextOut(ficlCallback~{*}pCB,~char~{*}text)~\{}{\scriptsize \par}

{\scriptsize{}~~FICL\_IGNORE(pCB);}{\scriptsize \par}

{\scriptsize{}~~if~(text~!=~NULL)~\{}{\scriptsize \par}

{\scriptsize{}~~~~fputs(text,~vmSockPar.fptr);}{\scriptsize \par}

{\scriptsize{}~~\}}{\scriptsize \par}

{\scriptsize{}~~return;}{\scriptsize \par}

{\scriptsize \}}{\scriptsize \par}



{\scriptsize int~myVmSocketConnection(ficlVm~{*}vm,~int~vmsockfd)~\{}{\scriptsize \par}

{\scriptsize{}~~char~~~buffer{[}256{]};}{\scriptsize \par}

{\scriptsize{}~~int~~~~returnValue~=~0;}{\scriptsize \par}

{\scriptsize{}~~vmSockPar.fptr~=~fdopen(vmsockfd,~\textquotedbl{}r+\textquotedbl{});}{\scriptsize \par}

{\scriptsize{}~~/{*}~The~old~one~was~vmSetTextOut~{*}/}{\scriptsize \par}

{\scriptsize{}~~ficlVmSetTextOut(vm,~\&mySocketTextOut);}{\scriptsize \par}

{\scriptsize{}~~ficlVmSetErrorOut(vm,~\&mySocketTextOut);}{\scriptsize \par}



{\scriptsize{}~~while(returnValue~!=~FICL\_VM\_STATUS\_USER\_EXIT)~\{}{\scriptsize \par}

{\scriptsize{}~~~~fputs(FICL\_PROMPT,~vmSockPar.fptr);}{\scriptsize \par}

{\scriptsize{}~~~~fgets(buffer,~sizeof(buffer),~vmSockPar.fptr);}{\scriptsize \par}

{\scriptsize{}~~~~returnValue~=~ficlVmEvaluate(vm,~buffer);}{\scriptsize \par}

{\scriptsize{}~~\}}{\scriptsize \par}

{\scriptsize{}~~fclose(vmSockPar.fptr);}{\scriptsize \par}

{\scriptsize{}~~close(vmsockfd);}{\scriptsize \par}

{\scriptsize{}~~return~FICL\_VM\_STATUS\_USER\_EXIT;}{\scriptsize \par}

{\scriptsize \}}{\scriptsize \par}



{\scriptsize void~catcher()~\{}{\scriptsize \par}

{\scriptsize{}~~close(vmSockPar.newsockfd);}{\scriptsize \par}

{\scriptsize{}~~close(sockfd);}{\scriptsize \par}

{\scriptsize{}~~exit(1);}{\scriptsize \par}

{\scriptsize \}}{\scriptsize \par}



{\scriptsize \#define~NUMBEROFSYSTEMS~2}{\scriptsize \par}

{\scriptsize \#define~NUMBEROFVMS~2}{\scriptsize \par}

{\scriptsize \#define~STARTUP~0}{\scriptsize \par}



{\scriptsize int~main(int~argc,~char~{*}{*}argv)~\{}{\scriptsize \par}

{\scriptsize{}~int~~~~~~~~netuse;}{\scriptsize \par}

{\scriptsize{}~int~~~~~~~~returnValue~=~0;}{\scriptsize \par}

{\scriptsize{}~int~~~~~~~~pid;}{\scriptsize \par}

{\scriptsize{}~int~~~~~~~~state;}{\scriptsize \par}

{\scriptsize{}~char~~~~~~~buffer{[}256{]};}{\scriptsize \par}

{\scriptsize{}~char~~~~~~~{*}selstr~=~buffer;}{\scriptsize \par}

{\scriptsize{}~int~~~~~~~~clilen;}{\scriptsize \par}

{\scriptsize{}~ficlVm~~~~~{*}vm{[}NUMBEROFVMS{]};}{\scriptsize \par}

{\scriptsize{}~ficlSystem~{*}system{[}NUMBEROFSYSTEMS{]};}{\scriptsize \par}

{\scriptsize{}~ficlSystem~{*}showtest;}{\scriptsize \par}



{\scriptsize{}~struct~sockaddr\_in~server\_addr;}{\scriptsize \par}

{\scriptsize{}~struct~sockaddr\_in~client\_addr;}{\scriptsize \par}

{\scriptsize{}~ficlSystemInformation~myFiclInfo;}{\scriptsize \par}



{\scriptsize{}~system{[}STARTUP{]}~=~ficlSystemCreate(NULL);}{\scriptsize \par}

{\scriptsize{}~ficlSystemCompileExtras(system{[}STARTUP{]});}{\scriptsize \par}



{\scriptsize{}~buildMyInterface(system{[}STARTUP{]});}{\scriptsize \par}



{\scriptsize{}~vm{[}STARTUP{]}~=~ficlSystemCreateVm(system{[}STARTUP{]});}{\scriptsize \par}



{\scriptsize{}~signal(SIGINT,catcher);}{\scriptsize \par}



{\scriptsize{}~returnValue~=~ficlVmEvaluate(vm{[}STARTUP{]},}{\scriptsize \par}
{\scriptsize{}~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\textquotedbl{}.ver~.(~\textquotedbl{}~\_\_DATE\_\_~\textquotedbl{}~)~cr~quit\textquotedbl{});}{\scriptsize \par}



{\scriptsize{}~/{*}~cmd~line~argument~for~socket~connection~?~{*}/}{\scriptsize \par}

{\scriptsize{}~if~(argc~>~1)~\{}{\scriptsize \par}

{\scriptsize{}~~selstr~=~argv{[}1{]};}{\scriptsize \par}

{\scriptsize{}~~netuse~=~strcmp(selstr,~\textquotedbl{}tcp\textquotedbl{});}{\scriptsize \par}

{\scriptsize{}~\}}{\scriptsize \par}

{\scriptsize{}~else~\{}{\scriptsize \par}

{\scriptsize{}~~netuse~=~-1;}{\scriptsize \par}

{\scriptsize{}~\}}{\scriptsize \par}



{\scriptsize{}~/{*}~Without~TCP/IP~?~{*}/}{\scriptsize \par}

{\scriptsize{}~if(netuse~!=~0)~\{}{\scriptsize \par}

{\scriptsize{}~~~/{*}~stdin/stout~loop~{*}/}{\scriptsize \par}

{\scriptsize{}~~~while~(returnValue~!=~FICL\_VM\_STATUS\_USER\_EXIT)~\{}{\scriptsize \par}

{\scriptsize{}~~~~~fputs(FICL\_PROMPT,~stdout);}{\scriptsize \par}

{\scriptsize{}~~~~~fgets(buffer,~sizeof(buffer),~stdin);}{\scriptsize \par}

{\scriptsize{}~~~~~returnValue~=~ficlVmEvaluate(vm{[}STARTUP{]},~buffer);}{\scriptsize \par}

{\scriptsize{}~~~\}}{\scriptsize \par}

{\scriptsize{}~\}}{\scriptsize \par}

{\scriptsize{}~/{*}~Remote~via~TCP/IP~{*}/}{\scriptsize \par}

{\scriptsize{}~else~\{}{\scriptsize \par}

{\scriptsize{}~~~/{*}}{\scriptsize \par}

{\scriptsize{}~~~~{*}~Open~a~TCP~socket~(an~Internet~stream~socket~).}{\scriptsize \par}

{\scriptsize{}~~~~{*}/}{\scriptsize \par}

{\scriptsize{}~~~if~((sockfd~=~socket(AF\_INET,~SOCK\_STREAM,~0))~<~0)}{\scriptsize \par}

{\scriptsize{}~~~~~fprintf(~stderr,~\textquotedbl{}server:~can't~open~stream~socket~!\textquotedbl{});}{\scriptsize \par}



{\scriptsize{}~~~/{*}}{\scriptsize \par}

{\scriptsize{}~~~~{*}~Bind~our~local~address~so~that~the~client~can~send~to~us.}{\scriptsize \par}

{\scriptsize{}~~~~{*}/}{\scriptsize \par}

{\scriptsize{}~~~bzero(~(char~{*})~\&server\_addr,~sizeof(server\_addr));}{\scriptsize \par}

{\scriptsize{}~~~server\_addr.sin\_family~~~~~~=~AF\_INET;}{\scriptsize \par}
{\scriptsize{}~~~server\_addr.sin\_addr.s\_addr~=~htonl(INADDR\_ANY);}{\scriptsize \par}

{\scriptsize{}~~~server\_addr.sin\_port~~~~~~~~=~htons(SERV\_TCP\_PORT);}{\scriptsize \par}



{\scriptsize{}~~~if(bind(sockfd,~(struct~sockaddr~{*})~\&server\_addr,}{\scriptsize \par}
{\scriptsize{}~~~~~~~~~~~sizeof(server\_addr))~<~0)}{\scriptsize \par}

{\scriptsize{}~~~~~fprintf(~stderr,~\textquotedbl{}SERVER:~can't~bind~local~address~!\textquotedbl{});}{\scriptsize \par}



{\scriptsize{}~~~listen(sockfd,~5);}{\scriptsize \par}



{\scriptsize{}~~~while~(returnValue~!=~FICL\_VM\_STATUS\_USER\_EXIT)~\{}{\scriptsize \par}

{\scriptsize{}~~~~~/{*}}{\scriptsize \par}

{\scriptsize{}~~~~~~{*}~Wait~for~a~connection~from~client~process.}{\scriptsize \par}

{\scriptsize{}~~~~~~{*}~This~is~an~example~of~a~concurrent~server.}{\scriptsize \par}

{\scriptsize{}~~~~~~{*}/}{\scriptsize \par}

{\scriptsize{}~~~~~clilen~=~sizeof(client\_addr);}{\scriptsize \par}

{\scriptsize{}~~~~~vmSockPar.newsockfd~=~accept(sockfd,~\textbackslash{}}{\scriptsize \par}

{\scriptsize{}~~~~~~~~~~~~~~~~~~~(struct~sockaddr~{*})\&client\_addr,~\textbackslash{}}{\scriptsize \par}

{\scriptsize{}~~~~~~~~~~~~~~~~~~~\&clilen);}{\scriptsize \par}



{\scriptsize{}~~~~~if~(vmSockPar.newsockfd~<~0)}{\scriptsize \par}

{\scriptsize{}~~~~~~~fprintf(~stderr,~\textquotedbl{}SERVER:~accept~error~!\textquotedbl{});}{\scriptsize \par}



{\scriptsize{}~~~~~/{*}~Child~process~successfully~created~?~{*}/}{\scriptsize \par}

{\scriptsize{}~~~~~if(~(pid~=~fork())~<~0)}{\scriptsize \par}

{\scriptsize{}~~~~~~~fprintf(~stderr,~\textquotedbl{}server:~fork~error~!\textquotedbl{});}{\scriptsize \par}

{\scriptsize{}~~~~~/{*}~child~process~?~{*}/}{\scriptsize \par}

{\scriptsize{}~~~~~else~if~(pid~==~0)~\{}{\scriptsize \par}

{\scriptsize{}~~~~~~~/{*}~close~listening~socket~{*}/}{\scriptsize \par}

{\scriptsize{}~~~~~~~close(sockfd);}{\scriptsize \par}

{\scriptsize{}~~~~~~~/{*}~process~the~requests~{*}/}{\scriptsize \par}

{\scriptsize{}~~~~~~~returnValue~=~myVmSocketConnection(vm{[}STARTUP{]},}{\scriptsize \par}
{\scriptsize{}~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~vmSockPar.newsockfd);}{\scriptsize \par}

{\scriptsize{}~~~~~~~exit(returnValue);}{\scriptsize \par}

{\scriptsize{}~~~~~\}}{\scriptsize \par}

{\scriptsize{}~~~~~else~\{}{\scriptsize \par}

{\scriptsize{}~~~~~~~pid~=~wait(\&state);}{\scriptsize \par}

{\scriptsize{}~~~~~~~/{*}~child~process~terminated~with~error~?~{*}/}{\scriptsize \par}

{\scriptsize{}~~~~~~~if(WIFEXITED(state)~==~0)~\{}{\scriptsize \par}

{\scriptsize{}~~~~~~~~~close(vmSockPar.newsockfd);}{\scriptsize \par}

{\scriptsize{}~~~~~~~\}}{\scriptsize \par}

{\scriptsize{}~~~~~~~else~\{}{\scriptsize \par}

{\scriptsize{}~~~~~~~~~/{*}~8-bit~equality~?~{*}/}{\scriptsize \par}

{\scriptsize{}~~~~~~~~~if(WEXITSTATUS(state)==(FICL\_VM\_STATUS\_USER\_EXIT\&0xFF))}{\scriptsize \par}

{\scriptsize{}~~~~~~~~~~~returnValue~=~FICL\_VM\_STATUS\_USER\_EXIT;}{\scriptsize \par}

{\scriptsize{}~~~~~~~\}}{\scriptsize \par}

{\scriptsize{}~~~~~\}}{\scriptsize \par}

{\scriptsize{}~~~\}}{\scriptsize \par}

{\scriptsize{}~\}}{\scriptsize \par}

{\scriptsize{}~ficlSystemDestroy(system{[}STARTUP{]});}{\scriptsize \par}

{\scriptsize{}~return~0;}{\scriptsize \par}

{\scriptsize \}}{\scriptsize \par}
\end{lyxcode}
\end{quote}
Sicherlich kann man das eleganter ausführen, aber prinzpiell ist zu
erkennen, dass nur die Parameter der der C--Funktionen \textsc{fgets}
und \textsc{fputs} unterschiedlich sind.\\
Ausgewählt wird mit dem Kommandozeilenparameter {}``\emph{tcp}'',
welcher Ein--/Ausgabepfad genutzt wird. Existiert {}``\emph{tcp}'',
dann wird die Socket--Verbindung aufgebaut und eine entsprechende Ein--/Ausgabe--Schleife
über die C--Funktion {}``\textsc{myVmSocketConnection}{}`` aufgerufen.
In dieser Funktion ist auch ein Beispiel, wie die Ausgabe einer virtuellen
Maschine zugeordnet wird.\\
Fehlerbetrachtungen und weitere Dinge sind hier nicht einbezogen.


\subsection{Der Bootloader und FICL}

FreeBSD hat als Bestandteil seines Boot--Loaders FICL integriert. Nicht
anders als bei anderen Betriebssystemen in der x86--Welt besteht das
Problem, dass im Master--Boot--Record nur 446 Bytes zur Verfügung stehen,
und so wurde in BSD folgender Ablauf während des \textquotedblleft{}Bootstrap--Vorgangs\textquotedblright{}
festgelegte:
\begin{enumerate}
\item %
\begin{minipage}[t]{1\columnwidth}%
\begin{description}
\item [{boot0}] 446 Byte Boot--Manager im MBR
\end{description}
%
\end{minipage}
\item %
\begin{minipage}[t]{1\columnwidth}%
\begin{description}
\item [{boot1}] 512 Byte Programm im Boot--Record eines Slices, einer Partition,
welches Informationen enthält und boot2 sucht 
\item [{boot2}] Schnittstelle, welche den Loader oder einen Kernel laden
kann.
\end{description}
%
\end{minipage}
\item %
\begin{minipage}[t]{1\columnwidth}%
\begin{description}
\item [{Loader}] wie es das BSD--Handbuch beschreibt --- \emph{eine schöne
und einfach zu bedienende Boot--Konfigurations--Schnittstelle} --- oder
man kann auch FICL sagen.
\end{description}
%
\end{minipage}
\end{enumerate}

\subsubsection{Loader--Ablauf}

%\footnote{12.3.3.1.~Loader~Ablauf\protect \\
%\url{http://www.freebsd.org/doc/de\_DE.ISO8859-1/books/handbook/book.html%\#BOOT-INTRODUCTION}}}

\noindent \textit{\footnotesize Der Loader sucht während seiner Initialisierung
nach Konsolen und Laufwerken, findet heraus, von welchem Laufwerk
er gerade bootet und setzt dementsprechend bestimmte Variablen. Dann
wird ein Interpreter gestartet, der Befehle interaktiv oder von einem
Skript empfangen kann.}{\footnotesize \par}

\noindent \textit{\footnotesize Danach liest der Loader die Datei
/boot/loader.rc aus, welche ihn standardmäßig anweist, /boot/defaults/loader.conf
zu lesen, wo sinnvolle Standardeinstellungen für diverse Variablen
festgelegt werden und wiederum /boot/loader.conf für lokale Änderungen
an diesen Variablen ausgelesen wird. Anschließend arbeitet dann loader.rc
entsprechend dieser Variablen und lädt die ausgewählten Module und
den gewünschten Kernel.}{\footnotesize \par}

\noindent \textit{\footnotesize In der Voreinstellung wartet der Loader
10 Sekunden lang auf eine Tastatureingabe und bootet den Kernel, falls
keine Taste betätigt wurde. Falls doch eine Taste betätigt wurde, wird
dem Benutzer eine Eingabeaufforderung angezeigt. Sie nimmt einen einfach
zu bedienenden Befehlssatz entgegen, der es dem Benutzer erlaubt,
Änderungen an Variablen vorzunehmen, Module zu laden, alle Module
zu entladen oder schließlich zu booten bzw. neu zu booten.}{\footnotesize \par}

Ich habe hier mal den Auszug aus dem BSD--Handbuch übernommen, da dieser
eigentlich schon alles erklärt.

Wissenswert in diesem Zusammenhang ist noch, dass der Loader in einem
\textbf{\emph{B}}\emph{oo}\textbf{\emph{T}}\emph{ e}\textbf{\emph{X}}\emph{tender
(BTX) ausgeführt wird. BTX ist ein Code--Teil, der den Prozessor in
den Protected~Mode umschaltet, Descriptor--Tabellen anlegt und eine
SysCall--Möglichkeit schafft. BTX ist somit eine Schutzumgebung für
das Programm.~}%
\footnote{Sollte sich jemand an meinen Leserbrief aus der VD 4/2006 {}``\textsl{Die
Anwendung~--~Automatisierung}'' erinnern, so war dort der Gedanke
aufgekommen, ein FORTH für Roboter zu verwenden. Ich denke, mit diesem
Ansatz des BSD--Loaders sind schon ein paar kleine Voraussetzungen
gegeben, welche aufgegriffen werden können.%
}


\section{Was geht und was geht nicht}

Wie in meinen ersten Ausführungen schon dargelegt, ist fast alles,
was ANS--FORTH so bietet, auch in FICL vorhanden. Ein paar kleine Einschränkungen
gibt es jedoch.

Die Worte KEY? und KEY existieren normal nicht, sind aber z.B. im
BSD--Loader durch den Loader, der dann FICL einbindet, realisiert.


\subsection{Ein FORTH--Wort in C}

Auf meinem System habe ich z.B. KEY? mal eingebunden und wer die unterschiedlichen
Möglichkeiten in .nixen und Linux kennt, der weiß, welche Herausforderung
das werden kann. Ich habe es mal --- nicht portabel --- realisiert und
möchte damit auch ein Beipiel aufzeigen, wie z.B. eine C--Funktion
in FICL als FORTH--Wort eingebunden werden kann.
\begin{enumerate}
\item Code des Wortes/Primitives\\
%
\begin{minipage}[t]{1\columnwidth}%
\begin{lyxcode}
{\scriptsize /{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}}{\scriptsize \par}

{\scriptsize {*}{*}~functions~used~by~primitives~}{\scriptsize \par}

{\scriptsize {*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}/}{\scriptsize \par}

{\scriptsize static~int~arrived\_char~=~-1;}{\scriptsize \par}

{\scriptsize int~availchar(void)~\{}{\scriptsize \par}

{\scriptsize{}~~~char~buffer{[}1{]}~=~\textquotedbl{}\textquotedbl{};~~~/{*}~Buffer~bereitstellen~~~~~~{*}/}{\scriptsize \par}

{\scriptsize{}~~~struct~termio~old,new;~/{*}~struct~termio~in~termio.h~{*}/}{\scriptsize \par}

{\scriptsize{}~~~int~flags,~counted,~rval;~/{*}~deklariert~{*}/}{\scriptsize \par}

{\scriptsize{}~~~if~(arrived\_char~!=~-1)}{\scriptsize \par}

{\scriptsize{}~~~~~~return~FICL\_TRUE;~/{*}~char~from~previos~keypressed()~{*}/}{\scriptsize \par}



{\scriptsize{}~~~/{*}~waitchar~OFF~{*}/}{\scriptsize \par}

{\scriptsize{}~~~ioctl(0,TCGETA,\&old);~/{*}~Alte~Parameter~holen~{*}/}{\scriptsize \par}

{\scriptsize{}~~~new~=~old;~/{*}~und~merken~{*}/}{\scriptsize \par}

{\scriptsize{}~~~new.c\_lflag~=~\textasciitilde{}(ECHO|ICANON);~/{*}~Echo~ausschalten~{*}/}{\scriptsize \par}

{\scriptsize{}~~~new.c\_cc{[}VMIN{]}~=~0;~/{*}~Pufferung~aus~{*}/}{\scriptsize \par}

{\scriptsize{}~~~new.c\_cc{[}VTIME{]}~=~0;~/{*}~Warte~0/10~s~auf~Zeichen~{*}/}{\scriptsize \par}

{\scriptsize{}~~~ioctl(0,TCSETA,\&new);~/{*}~Neue~Werte~setzen~{*}/}{\scriptsize \par}



{\scriptsize{}~~~counted~=~read(0,~buffer,~1);}{\scriptsize \par}

{\scriptsize{}~~~if~(counted==1)~\{}{\scriptsize \par}

{\scriptsize{}~~~~~~arrived\_char~=~buffer{[}0{]};}{\scriptsize \par}

{\scriptsize{}~~~~~~rval~=~FICL\_TRUE;}{\scriptsize \par}

{\scriptsize{}~~~\}}{\scriptsize \par}

{\scriptsize{}~~~else}{\scriptsize \par}

{\scriptsize{}~~~~~~rval~=~FICL\_FALSE;}{\scriptsize \par}



{\scriptsize{}~~~/{*}~waitchar~ON~{*}/}{\scriptsize \par}

{\scriptsize{}~~~ioctl(0,TCSETA,\&old);~/{*}~Alte~Werte~setzen,~haengt~bash~{*}/}{\scriptsize \par}

{\scriptsize{}~~~return~rval;}{\scriptsize \par}

{\scriptsize \}~}
\end{lyxcode}
%
\end{minipage}
\item FORTH~primitive\\
%
\begin{minipage}[t]{1\columnwidth}%
\begin{lyxcode}
\textrm{\scriptsize /{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}}{\scriptsize \par}

\textrm{\scriptsize{}~{*}{*}~~~~~~~~~~~key?~-~check~for~a~character~from~stdin~(FACILITY)}{\scriptsize \par}

\textrm{\scriptsize{}~{*}{*}}{\scriptsize \par}

\textrm{\scriptsize{}~{*}{*}~key?~(~--~flag~)}{\scriptsize \par}

\textrm{\scriptsize{}~{*}{*}}{\scriptsize \par}

\textrm{\scriptsize{}~{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}/}{\scriptsize \par}

\textrm{\scriptsize static~void~ficlPrimitiveKeyQuestion(ficlVm~{*}vm)~\{}{\scriptsize \par}

\textrm{\scriptsize \#if~FICL\_ROBUST~>~1}{\scriptsize \par}

\textrm{\scriptsize{}~~~~FICL\_STACK\_CHECK(vm->dataStack,~0,~1);}{\scriptsize \par}

\textrm{\scriptsize \#endif}{\scriptsize \par}

\textrm{\scriptsize{}~~~~/{*}~But~here~do~the~right~thing.~{*}/}{\scriptsize \par}

\textrm{\scriptsize{}~~~~ficlStackPushInteger(~vm->dataStack,~availchar()~);}{\scriptsize \par}

\textrm{\scriptsize{}~~~~return;}{\scriptsize \par}

\textrm{\scriptsize \}}
\end{lyxcode}
%
\end{minipage}
\item FORTH--Wort erstellen\\
%
\begin{minipage}[t]{1\columnwidth}%
\begin{lyxcode}
{\scriptsize /{*}}{\scriptsize \par}

{\scriptsize{}~{*}~Corresponding~ficlBuild~~calls...~}{\scriptsize \par}

{\scriptsize{}~{*}/}{\scriptsize \par}

{\scriptsize ficlBuild(pSys,~\textquotedbl{}KEY?\textquotedbl{},~ficlPrimitiveKeyQuestion,~FICL\_WORD\_DEFAULT);}
\end{lyxcode}
%
\end{minipage}
\end{enumerate}

\subsection{Nicht ganz ausgereift}

Nach einigen Experimenten bin ich auf ein Problem mit doppeltgenauen
Stackwerten gestoßen. Meines Wissens erzeugt die Eingabe einer
Zahl mit einem Punkt eine doppeltgenaue Zahl auf dem Stack, welche
ihren high--Anteil auf dem TOS liegen hat und den low--Anteil auf dem
NOS.

Leider war die Reihenfolge vertauscht und ich habe mich bemüht, eine
Lösung über ?NUMBER zu realisieren. Die Lösung funktioniert erst einmal,
aber auch die Tatsache, dass der Punkt an beliebiger Stelle in der
Zahl stehen kann, ist nicht realisiert und bedarf noch mehr Aufwand.\\
Darüber hinaus überschaue ich noch nicht alle Varianten, welche
durch solch eine Änderung eintreten können.\\
Ich nahm daraufhin Kontakt mit John~Sadler auf, bekam aber 
bedauerlicherweise die Antwort, dass er gegenwärtig nicht mehr aktiv entwickelt
--- okay --- kommt Zeit, kommt Lösung. Es ist ja \emph{open source}.


\section{Fazit}

FICL ist, auch wenn noch nicht alles ausgereift ist und angewendet
wurde, ein sehr elegantes gut beschriebenes Software--Tool, welches
gerade im Embedded--Bereich mit vorhandenen 32-Bit--Betriebssystemen
sehr nützlich ist. Es überzeugt besonders durch seine Kompaktheit
und die vorhandene Geschwindigkeit.

\end{multicols}

\end{document}
