Forth (Programmiersprache)

Die grundlegende Datenstruktur von Forth ist das „Wörterbuch“, das „Wörter“ ausführbarem Code oder benannten Datenstrukturen zuordnet. Das Wörterbuch ist im Speicher als Baum verknüpfter Listen angelegt, wobei die Links vom neuesten (zuletzt) definierten Wort zum ältesten gehen, bis ein Sentinel-Wert, normalerweise ein Nullzeiger, gefunden wird. Ein Kontextwechsel bewirkt, dass eine Listensuche an einem anderen Blatt beginnt. Eine verknüpfte Listensuche wird fortgesetzt, wenn der Zweig in den Hauptstamm übergeht und schließlich zurück zum Sentinel, der Wurzel, führt.Es kann mehrere Wörterbücher geben. In seltenen Fällen wie der Meta-Kompilierung kann ein Wörterbuch isoliert und eigenständig sein.Der Effekt ähnelt dem Verschachteln von Namespaces und kann Schlüsselwörter je nach Kontext überladen.

Ein definiertes Wort besteht im Allgemeinen aus head und body, wobei der head aus dem Namensfeld (NF) und dem Linkfeld (LF) und der body aus dem Codefeld (CF) und dem Parameterfeld (PF) besteht.

Kopf und Körper eines Wörterbucheintrags werden getrennt behandelt, da sie möglicherweise nicht zusammenhängend sind. Wenn beispielsweise ein Forth-Programm für eine neue Plattform neu kompiliert wird, kann der Kopf auf dem kompilierenden Computer verbleiben, während der Körper zur neuen Plattform wechselt. In einigen Umgebungen (z. B. eingebetteten Systemen) belegen die Köpfe unnötig Speicher. Einige Cross-Compiler können jedoch Köpfe in das Ziel einfügen, wenn erwartet wird, dass das Ziel selbst eine interaktive Schnittstelle unterstützt.

Dictionary entryEdit

Das genaue Format eines Wörterbucheintrags ist nicht vorgeschrieben, und die Implementierungen variieren. Bestimmte Komponenten sind jedoch fast immer vorhanden, obwohl die genaue Größe und Reihenfolge variieren kann. Als Struktur beschrieben, könnte ein Wörterbucheintrag folgendermaßen aussehen:

 structure byte: flag \ 3bit flags + length of word's name char-array: name \ name's runtime length isn't known at compile time address: previous \ link field, backward ptr to previous word address: codeword \ ptr to the code to execute this word any-array: parameterfield \ unknown length of data, words, or opcodes end-structure forthword

Das Namensfeld beginnt mit einem Präfix, das die Länge des Wortnamens angibt (normalerweise bis zu 32 Byte), und mehreren Bits für Flags. Die Zeichendarstellung des Namens des Wortes folgt dann dem Präfix. Abhängig von der speziellen Implementierung von Forth kann es ein oder mehrere NUL (‚\0‘) Bytes für die Ausrichtung geben.

Das Linkfeld enthält einen Zeiger auf das zuvor definierte Wort. Der Zeiger kann eine relative Verschiebung oder eine absolute Adresse sein, die auf das nächstälteste Geschwister zeigt.

Der Codefeldzeiger ist entweder die Adresse des Wortes, das den Code oder die Daten im Parameterfeld ausführt, oder der Anfang des Maschinencodes, den der Prozessor direkt ausführt. Bei bereits definierten Wörtern zeigt der Codefeldzeiger auf das Wort, das den aktuellen vierten Befehlszeiger (IP) auf dem Rückgabestapel speichert, und lädt die IP mit der neuen Adresse, von der aus die Ausführung von Wörtern fortgesetzt werden soll. Dies ist dasselbe wie die Call / Return-Anweisungen eines Prozessors.

Struktur des compilerEdit

Der Compiler selbst ist kein monolithisches Programm. Es besteht aus vier Wörtern, die für das System sichtbar und von einem Programmierer verwendet werden können. Dies ermöglicht es einem Programmierer, die Wörter des Compilers für spezielle Zwecke zu ändern.

Das Flag „compile time“ im Feld name wird für Wörter mit dem Verhalten „compile time“ gesetzt. Die meisten einfachen Wörter führen denselben Code aus, unabhängig davon, ob sie in einer Befehlszeile eingegeben oder in Code eingebettet sind. Beim Kompilieren platziert der Compiler einfach Code oder einen Thread-Zeiger auf das Wort.

Die klassischen Beispiele für Kompilierzeitwörter sind die Kontrollstrukturen wie IF und WHILE. Fast alle Steuerstrukturen von Forth und fast alle Compiler sind als Kompilierungswörter implementiert. Abgesehen von einigen selten verwendeten Kontrollflusswörtern, die nur in wenigen Implementierungen vorkommen, wie z. B. einer bedingten Rückgabe, werden alle Kontrollflusswörter von Forth während der Kompilierung ausgeführt, um verschiedene Kombinationen von primitiven Wörtern zusammen mit ihren Verzweigungsadressen zu kompilieren. Zum Beispiel IF und WHILE und die Wörter, die mit diesen übereinstimmen, richten BRANCH (bedingungsloser Zweig) und ?BRANCH (Pop einen Wert vom Stapel und verzweigen, wenn er falsch ist). Gezählte Schleifensteuerungsflusswörter funktionieren ähnlich, richten jedoch Kombinationen von primitiven Wörtern ein, die mit einem Zähler arbeiten, und so weiter. Während der Kompilierung wird der Datenstapel verwendet, um den Steuerstrukturausgleich, die Verschachtelung und das Back-Patching von Zweigadressen zu unterstützen. Das Snippet:

 ... DUP 6 < IF DROP 5 ELSE 1 - THEN ...

würde innerhalb einer Definition in die folgende Sequenz kompiliert:

 ... DUP LIT 6 < ?BRANCH 5 DROP LIT 5 BRANCH 3 LIT 1 - ...

Die Zahlen nach BRANCH repräsentieren relative Sprungadressen. LIT ist das primitive Wort, um eine „literale“ Zahl auf den Datenstapel zu schieben.

Kompilierungszustand und Interpretation stateEdit

Das Wort : (Doppelpunkt) analysiert einen Namen als Parameter, erstellt einen Wörterbucheintrag (eine Doppelpunktdefinition) und tritt in den Kompilierungszustand ein. Der Interpreter liest weiterhin durch Leerzeichen getrennte Wörter vom Benutzereingabegerät. Wenn ein Wort gefunden wird, führt der Interpreter die dem Wort zugeordnete Kompilierungssemantik anstelle der Interpretationssemantik aus. Die standardmäßige Kompilierungssemantik eines Wortes besteht darin, seine Interpretationssemantik an die aktuelle Definition anzuhängen.

Das Wort ; (Semikolon) beendet die aktuelle Definition und kehrt in den Interpretationszustand zurück. Es ist ein Beispiel für ein Wort, dessen Kompilierungssemantik von der Standardeinstellung abweicht. Die Interpretationssemantik von ; (Semikolon), den meisten Kontrollflusswörtern und einigen anderen Wörtern ist in ANS undefiniert, was bedeutet, dass sie nur innerhalb von Definitionen und nicht in der interaktiven Befehlszeile verwendet werden dürfen.

Der Interpreterstatus kann manuell mit den Wörtern (rechte Klammer) geändert werden, die den Interpretationsstatus bzw. den Kompilierungsstatus eingeben. Diese Wörter können mit dem Wort LITERAL verwendet werden, um einen Wert während einer Kompilierung zu berechnen und den berechneten Wert in die aktuelle Doppelpunktdefinition einzufügen. LITERAL hat die Kompilierungssemantik, um ein Objekt aus dem Datenstapel zu nehmen und Semantik an die aktuelle Doppelpunktdefinition anzuhängen, um dieses Objekt auf dem Datenstapel zu platzieren.

In ANS Forth kann der aktuelle Zustand des Interpreters aus dem Flag STATE gelesen werden, das im Kompilierungszustand den Wert true und ansonsten false enthält. Dies ermöglicht die Implementierung sogenannter State-Smart-Wörter mit einem Verhalten, das sich entsprechend dem aktuellen Status des Interpreters ändert.

Immediate wordsEdit

Das Wort IMMEDIATE markiert die neueste Doppelpunktdefinition als immediate word und ersetzt effektiv seine Kompilierungssemantik durch seine Interpretationssemantik. Unmittelbare Wörter werden normalerweise während der Kompilierung ausgeführt, nicht kompiliert, aber dies kann vom Programmierer in beiden Zuständen überschrieben werden. ; ist ein Beispiel für ein unmittelbares Wort. In ANS Forth nimmt das Wort POSTPONE einen Namen als Parameter und hängt die Kompilierungssemantik des benannten Wortes an die aktuelle Definition an, auch wenn das Wort als unmittelbar markiert wurde. Forth-83 definierte separate Wörter COMPILE und , um die Zusammenstellung von nicht unmittelbaren bzw. unmittelbaren Wörtern zu erzwingen.

Unbenannte Wörter und Ausführungstokenedit

In ANS Forth können unbenannte Wörter mit dem Wort :NONAME definiert werden, das die folgenden Wörter bis zum nächsten ; (Semikolon) kompiliert und ein Ausführungstoken auf dem Datenstapel hinterlässt. Das Ausführungstoken stellt ein undurchsichtiges Handle für die kompilierte Semantik bereit, ähnlich den Funktionszeigern der Programmiersprache C.

Ausführungstoken können in Variablen gespeichert werden. Das Wort EXECUTE nimmt ein Ausführungstoken aus dem Datenstapel und führt die zugehörige Semantik aus. Das Wort COMPILE, (compile-comma) nimmt ein Ausführungstoken aus dem Datenstapel und hängt die zugehörige Semantik an die aktuelle Definition an.

Das Wort ' (tick) nimmt den Namen eines Wortes als Parameter und gibt das Ausführungstoken zurück, das diesem Wort auf dem Datenstapel zugeordnet ist. In diesem Zustand entspricht ' RANDOM-WORD EXECUTERANDOM-WORD .

Edit

Die Wörter : (Doppelpunkt), POSTPONE' (Häkchen) sind Beispiele für das Parsen von Wörtern, die ihre Argumente vom Benutzereingabegerät anstelle des Datenstapels beziehen. Ein weiteres Beispiel ist das Wort ( (paren), das die folgenden Wörter bis einschließlich der nächsten rechten Klammer liest und ignoriert und zum Platzieren von Kommentaren in einer Doppelpunktdefinition verwendet wird. In ähnlicher Weise wird das Wort \ (Backslash) für Kommentare verwendet, die bis zum Ende der aktuellen Zeile fortgesetzt werden. Um korrekt analysiert zu werden, müssen ( (paren) und \ (Backslash) durch Leerzeichen vom folgenden Kommentartext getrennt werden.

Struktur von codeEdit

In den meisten Forth-Systemen besteht der Hauptteil einer Codedefinition entweder aus Maschinensprache oder einer Form von Thread-Code. Das ursprüngliche Forth, das dem informellen FIG-Standard (Forth Interest Group) folgt, ist eine TIL (Threaded Interpretive Language). Dies wird auch als Indirect-Threaded-Code bezeichnet, aber auch Direct-Threaded- und Subroutinen-Threaded-Forths sind in der Neuzeit populär geworden. Die schnellsten modernen Forths wie SwiftForth, VFX Forth und iForth kompilieren Forth in nativen Maschinencode.

Data objectsEdit

Wenn ein Wort eine Variable oder ein anderes Datenobjekt ist, zeigt der CF auf den Laufzeitcode, der dem definierenden Wort zugeordnet ist, das es erstellt hat. Ein definierendes Wort hat ein charakteristisches „definierendes Verhalten“ (Erstellen eines Wörterbucheintrags plus möglicherweise Zuweisen und Initialisieren von Datenraum) und spezifiziert auch das Verhalten einer Instanz der Klasse von Wörtern, die durch dieses definierende Wort konstruiert werden. Beispiele hierfür sind:

VARIABLEBenennt einen nicht initialisierten Speicherort mit einer Zelle. Instanzverhalten einesVARIABLEgibt seine Adresse auf dem Stapel zurück.CONSTANTBenennt einen Wert (angegeben als Argument fürCONSTANT). Instanzverhalten gibt den Wert zurück.CREATEBenennt einen Speicherort; An diesem Speicherort kann Speicherplatz zugewiesen oder ein String oder ein anderer initialisierter Wert enthalten sein. Instanzverhalten gibt die Adresse des Beginns dieses Bereichs zurück.

Forth bietet auch eine Möglichkeit, mit der ein Programmierer neue anwendungsspezifische definierende Wörter definieren kann, die sowohl ein benutzerdefiniertes definierendes Verhalten als auch ein Instanzverhalten angeben. Einige Beispiele umfassen kreisförmige Puffer, benannte Bits an einem E / A-Port und automatisch indizierte Arrays.

Datenobjekte, die durch diese und ähnliche Wörter definiert werden, haben einen globalen Gültigkeitsbereich. Die Funktion, die von lokalen Variablen in anderen Sprachen bereitgestellt wird, wird vom Datenstapel in Forth bereitgestellt (obwohl Forth auch echte lokale Variablen hat). Der Forth-Programmierstil verwendet im Vergleich zu anderen Sprachen nur sehr wenige benannte Datenobjekte; typischerweise werden solche Datenobjekte verwendet, um Daten zu enthalten, die von einer Anzahl von Wörtern oder Aufgaben verwendet werden (in einer Multitasking-Implementierung).Es liegt in der Verantwortung des Programmierers, geeignete Operatoren zu verwenden, um Werte abzurufen und zu speichern oder andere Operationen an Daten durchzuführen.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.