Einen Assembler bietet pfe nicht. Man kann es aber leicht durch
C-Funktionen erweitern, was allerdings eine neue Übersetzung des
Systems mit dem C-Compiler erfordert und insofern in der täglichen
Arbeit ein schwacher Trost ist.
Dem C-Programmierer bietet der Rest des Systems folgendes
Programmiermodell:
- Datentypen:
- Mit den Objekten aus Sicht von Forth kompatible
Objekte in C sind als die folgenden typedefs bekannt:
- Cell
- eine Einheit auf dem Stack, Integer-Typ mit
Vorzeichen, zuweisungskompatibel mit Zeigertypen.
- uCell
- eine Einheit auf dem Stack, Integer-Typ ohne
Vorzeichen.
- dCell
- eine doppelt genaue Zahl mit Vorzeichen, struct
bestehend aus Cell hi und uCell lo.
- udCell
- wie dCell, vorzeichenlos.
- void (*pcode) (void)
- ist ein Zeiger auf eine ein Primitive
realisierende C-Funktion, die also der Gestalt void primitive
(void) ist. Zur Vermeidung von Namenskollisionen enden die Namen
all dieser C-Funktionen in einem Tiefstrich. Zur Erleichterung der
Definition gibt es das Makro code(NAME), das den Funktionskopf
void NAME_(void)
erzeugt. Im Kopf jedes Wortes steht ein
solcher Zeiger auf die auszuführende Funktion.
- pcode *CFA
- ist der Typ des Execution Tokens, ein Zeiger auf
die Position im Kopf eines Wortes, wo der Zeiger auf dieas Wort
realisierende C-Funktion steht.
- Register der virtuellen Maschine
- sind global deklarierte
C-Variablen:
- Cell *sp
- Daten-Stackpointer
- CFA *ip
- Instruktionszeiger. Zeigt in die Liste compilierter
Worte, deren jedes jeweils genau das Execution Token, also ein
Zeiger des Typs CFA ist.
- CFA **rp
- Der Return-Stack dient zur Sicherung des ip,
der Stapelzeiger ist also ein Zeiger auf den Typ des ip.
- CFA w
- Das W-Register der virtuellen Maschine, hier kann ein
Primitive seine eigene CFA ablesen. Zugriff auf den Body des Wortes
über (typ *)&w[1].
- Systemvariablen
- Weil die Art der Speicherung der
Systemvariablen sich ändern k÷nnte, gibt es zum Zugriff auf die in
Forth definierten Systemvariablen Makros mit nahenliegenden Namen.
So kann in C-Funktionen z.B. auf den DP unter dem Namen
DP
zugegriffen werden usw.
- Funktionen
- Das System enthält hunderte von C-Funktionen, wovon
natürlich nicht jede in ihrer jetzigen Form garantiert – oder gar
dokumentiert – werden kann. Beispiele:
- void abortq (char *fmt, ...);
- gibt – mit den Fähigkeiten
von printf() ausgestattet – eine Fehlermeldung aus und führt
-2 THROW
aus.
- void type (char *s, Cell n)
- gibt eine Zeichenkette wie
TYPE
aus.
- char *word (char del)
- wie das Forth-Wort
WORD
, liest
ein Wort aus dem Eingabestrom in den Speicher ab HERE und
übergibt diese Stelle als Funktionsergebnis.
- void run_forth (CFA xt);
- führt ein beliebiges (auch
High-level) Forth Wort aus. Enthält den inneren Interpreter.
- Makros
- erleichtern die Anpassung von C an Forth sehr, weil sich
darin viele der notwendigen Type-Casts verbergen lassen. Einige
Beispiele:
- POP(T,P,X)
- liest ein Objekt des Typs T über den
Zeiger P in die Variable X, unabhängig von den
tatsächlichen Typen der Operanden. Erh÷ht P entsprechend.
- PUSH(T,X,P)
- Umkehrung zu POP, schreibt ein Objekt
X des Typs T in einen zu kleineren Adressen hin
wachsenden Stapel mit Stapelzeiger P.
- RPUSH(X)
- legt ein Objekt der Grևe einer Cell auf den
Return-Stack.
- RPOP(X)
- holt eine Cell vom Return-Stack.
- FLAG(X)
- macht aus X ein Forth-Flag, also 0 bzw. -1.
- COMMA(X)
- schreibt das Objekt X der Grևe 1 Cell ins
Dictionary.
Will man das System zum Beispiel um einen für ein bestimmtes
Betriebssystem wichtigen Satz von Worten erweitern, bietet sich die
Anlage einer entsprechenden Quelltextdatei an. Sie enthält alle
system- oder aufgabenspezifischen C-Funktionen, die in eine Reihe von
C-Funktionen münden, die die Gestalt von Forth-Primitives haben, also
mit dem Makro Code (name) deklariert sind. Diese
Primitives werden in eine Wortliste zusammengefaát, die beim System
registriert wird14 und so beim Start von pfe mit ins Dictionary geladen
wird.
Vollständiges Beispiel:
#include "forth.h"
#include "support.h"
Code (user_added_primitive)
{
outs ("\nThis is a sample primitive."
" See src/yours.c "
"for it's definition.\n");
}
LISTWORDS (your) =
{
CO ("USER-ADDED-PRIMITIVE",
user_added_primitive),
};
COUNTWORDS (your, "Your kernel extensions");
Das Makro LISTWORDS deklariert eine Wortlisten-Struktur,
die zu Initialisieren ist mithilfe der Makros:
CO(NM,PCODE) |
gew÷hnliches Wort |
CI(NM,PCODE) |
immediate Wort |
CS(NM,SEM) |
Compiler Erweiterung |
SV(NM,VAR) |
Systemvariable |
SC(NM,VAR) |
Forth-Konstante, deren Wert aus
einer Variablen stammt |
OC(NM,VAL) |
normale Konstante |
VO(NM,RUNTM) |
WORDLIST |
Das Makro COUNTWORDS zählt schlicht die Anzahl Worte in der
Liste und stellt sie zur Einbindung bereit.