VolksForth/doc/atari-st/vf-atari-st-380-manual-de.sidecar.txt
Philip Zembrod 6c20832e1e Replace vf-atari-st-380-manual-de.pdf with text-annotated version made by OCRmyPDF,
alongside with sidecar.txt file containing the text annotation.
2024-08-01 22:27:39 +02:00

15905 lines
330 KiB
Plaintext
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

jvalksf| cc» 1256 wescn/resr
| FORTHE:
H
ı
D
-
a
w
m
u
in
®
x
@
a
%
-
N
Fr
w
Handbuch zum volksFORTH83 rev 3.8
2. Auflage 18.12.1986
Die Autoren haben sich in diesem Handbuch um eine vollständige
und akkurate Darstellung bemüht. Die in diesem Handbuch enthal-
tenen Informationen dienen jedoch allein der Produktbeschrei-
bung und sind nicht als zugesicherte Eigenschaften im Rechts-
sinne aufzufassen. Ewaige Schadensersatzansprüche gegen die
Autoren - gleich aus welchem Rechtsgrund - sind ausgeschlossen,
soweit die Autoren nicht Vorsatz oder grobe Fahrlässigkeit
trifft. Es wird keine Gewähr übernommen, daß die angegebenen
Verfahren frei von Schutzrechten Dritter sind.
Alle Rechte vorbehalten. Ein Nachdruck, auch auszugsweise, ist
nur zulässig mit Einwilligung der Autoren und genauer Quellen-
angabe sowie Einsendung eines Belegexemplars an die Autoren.
(ce) 1985,1986
Bernd Pennemann, Klaus Schleisiek, Georg Rehfeld, Dietrich
Weineck - Mitglieder der Forth Gesellschaft e.V.
Unser Dank gilt der gesamten FORTH-Gemeinschaft, insbesondere
Mike Perry, Charles Moore und Henry Laxen.
(<) 1328 werbe/reirs I=3
m
7 s
| Einleitung E I-4 (ec) 1288
(2) 1228 werbe/re/ks 2-5 Einleitung N
INHALTSVERZEICHNIS
Prolog
ı1 Über das volksFORTH83
14 Über dieses Handbuch
Teil 1 - Getting started
17 Umgang mit den Disketten
19 Erster Einstieg
20 Erstellen einer Applikation
21 Für Fortgeschrittene
22 Erstellen eines eigenen Systens
Teil 2 - Erläuterungen
1 1) Dictionarystruktur des volksFORTH83
1 1) Struktur der Worte
6 2) Vokabular-Struktur
9 2) Die Ausführung von Forth-Worten
9 1) Aufbau des Adressinterpreters
10 2) Die Funktion des Adressinterpreters
12 3) Verschiedene Immediate Worte
13 3) Die Does> - Struktur
15 4) Vektoren und Deferred Worte
15 1) deferred Worte
16 2) >interpret
16 3) Variablen
16 4) Vektoren
18 Die Druckeranpassung
31 5) Der Heap
33 6) Der Multitasker
33 1) Anwendungsbeispiel : Ein Kochrezept
35 2) Implementation
39 3) Semaphore und "Lock"
40 4) Eine Bemerkung bzgl. BLOCK
41 7) Debugging - Techniken
41 1) Voraussetzungen für die Fehlersuche
42 2) Der Tracer
47 3) Stacksicherheit
49 4) Aufrufgeschichte
50 5) Speicherdump
51 6) Der Dekcmpiler
m
Rn
J Einleitung | I-6 (2) HB2E werbp/re/iks
Teil 3 - Glossare
1 Notation
3 Arithmetik
* »/ */mod + - -1 / /md 0 1 1+ 1- 2
2+ 2- 2/ 3 3+ 4 abs even max min mod negate
u/mod umax umin
6 Logik und Vergleiche
0< 0<> O0= 03 < = >) and case? false not
true ut u> uwithin xor
8 Speicheroperationen
1 +! 2! 2@ @ ei c@ cmove cmove>
ctoggle erase fill move off on pad place
10 32-Bit-Worte
d* d+ d- dO= d< d= dabs dnegate extend
m/mod ud/mod um* um/mod
12 Stack
-Fol1l -Eöt .S 2dup 2drop 2over 2swap
clearstack depth drop dup nip over pick
rot s0O swap sp! sp@ under
14 Returnstack
»r push r> rp! rO r@ rdepth rdrop rp@
15 Strings
® # #> #s /string <# accumulate capital
capitalize convert digit? hold nullstring? number
number? scan sign skip
18 Datentypen
5 : 2Variable 2Constant Alias Constant Create
Defer Input: Is Output: User Variable Vocabulary
22 Dictionary - Worte
! (forget „ .name align allot c, clear custom-
remove dp empty forget here hide last
origin remove reveal save wuallot udp >body
25 Vokabular - Worte
also Assembler context current definitions
£forth-83 Only Onlyforth seal toss words voc-link
vp
21 Heap - Worte
?head halign hallot heap heap? ı
28 Kontrollstrukturen
+LOOP ?DO ?exit BEGIN bounds DO ELSE execute
IE J LEAVE LOOP perform REPEAT THEN
WHILE
31 Compiler - Worte
recursive restrict [ ['] [compile]
Ascii compile Does> immediate Literal
FORTE
33
36
38
40
44
48
51
56
59
>
“=
BEE
werbe/re/hs Einleitung
Interpreter - Worte
{ +load +thru --) >»in »>interpret blk find
interpret load loadfile name notfound parse quit
source state thru word ] \ \\ \needs
Fehlerbehandlung
(error ?pairs ?stack abort abort" error"
errorhandler warning
Sonstiges
"abort "cold 'quit 'restart (quit status bye
cold end-trace makeview next-link noop r# restart
ser
Massenspeicher
»drive all-buffers allotbuffer b/blk b/buf
blk/drv block buffer convey copy core? drive
drv? empty-buffers first flush freebuffer fromfile
isfile limit offset prev r/w save-buffers update
ST-Spezifische Worte
#col Hesc #1£ #row bconin bceonout bceonstat
bcostat con! curleft curoff curon currite
display drvO drvi drvinit getkey keyboard rwabs
Stat STat? STer STdecode STdel STemit STexpect
STkey STkey? STpage STr/w STtype
Multitasking
's activate lock multitask pass pause rendezvous
singletask sleep stop Task tasks unlock up® up!
wake
1/0
#bs #cr #tib -trailing . ."” .( .r >tib ?cr at
at? base bl c/l col cr d. d.r decimal decode
del emit expect hex input key key? l/s list
output page query row space spaces span
standardi/o stop? tib type u. u.r
erweiterte Adressierung
forthstart 1! 12! 12@ 1@ 1c! 1c@ Icmove Int!
Index
en |
| Preis I I-8 (23 1828 we/bp/rterks
17
31
33
41
43
45
47
49
59
61
67
Teil 4 - Definition der verwendeten Begriffe
Entscheidungskriterien
Definition der Begriffe
Anhang
Atari ST Fullscreen Editor
Die GEM-Bibliothek des volksFORTH83
Der Assembler
Der Disassembler
Fileinterface für das volksFORTH83
Diverses
Allocate
Relocate
Strings
Abweichungen von Programmieren in Forth
Abweichungen von "Forth Tools"
Fehlermeldungen des volksFORTH83
Targetcompiler-Worte
2) 19328 werbp/refkhs =) Einleitung
I-10 ke) BEE werbp/rerhs
(23 A828 we/ibpe/re/iks I-11 Einleitung h
Prolog : über das volksFORTH83
volksFORTH83 ist eine Sprache, die in verschiedener Hinsicht
ungewöhnlich ist. Einen ersten Eindruck vom volksFORTH83 und
von unserem Stolz darüber soll dieser Prolog vermitteln.
volksFORTH83 braucht nicht geknackt oder geklaut zu werden. Im
Gegenteil, wir hoffen, daß viele Leute das volksFORTH83
möglichst schnell bekommen und ihrerseits weitergeben.
Warum stellen wir dieses System als "public domain” zur
Verfügung ?
Die Verbreitung, die die Sprache FORTH gefunden hat, war
wesentlich an die Existenz von figFORTH geknüpft. Auch figFORTH
ist ein public domain Programm, d.h. es darf weitergegeben und
kopiert werden. Trotzdem haben sich bedauerlicherweise ver-
schiedene Anbieter die einfache Adaption des figFORTH an
verschiedene Rechner sehr teuer bezahlen lassen. Das im Jahr
1979 erschienene figFORTH ist heute nicht mehr so aktuell, weil
mit der weiteren Verbreitung von Forth eine Fülle von eleganten
Konzepten entstanden sind, die z.T. im Forth-Standard von 1983
Eingang gefunden haben. Daraufhin wurde von Laxen und Perry das
F83 geschrieben und als Public Domain verbreitet.
Dieses freie 83-Standard-Forth mit zahlreichen Utilities ist
recht komplex, es wird auch nicht mit Handbuch geliefert.
Insbesondere gibt es keine Version für C64- und Apple-Computer.
Der C64 spielt jedoch in Deutschland eine große Rolle.
wir haben ein neues Forth für verschiedene Rechner entwickelt.
Das Ergebnis ist das volksFORTH83, eines der besten Forth-
Systeme, die es gibt. Es wurde zunächst für den C64 geschrie-
ben. Nach Erscheinen der Rechner der Atari ST-Serie entschlos-
sen wir uns, auch für sie ein volksFORTH83 zu entwickeln. Die
erste ausgelieferte Version 3.7 war, was Editor und Massen-
speicher betraf, noch stark an den C64 angelehnt. Sie enthielt
jedoch schon einen verbesserten Tracer, die GEM-Bibliothek und
die anderen Tools für den ST. Der nächste Schritt bestand in
der Einbindung der Betriebssystem-Files. Nun konnten Quelltexte
auch vom Desktop und mit anderen Utilities verarbeitet werden.
Mit der jetzt verteilten Version 3.8 ist das volksFORTH
vollständig: Der GEM-unterstützte Editor erleichert auch
Anfängern das Programmieren, und der Code ist relokatibel
geworden, sodaß Applikationen sehr einfach zu realisieren sind.
Die Probleme der früheren Versionen mit Accessories etc.
entfallen ebenfalls. Schließlich wurde die Dokumentation erheb-
lich erweitert, und für die wichtigsten Files liegen Shadow-
screens vor. Der Editor dürfte mit seinen fast 50 kByte
Kommentar das am besten dokumentierte umfangreiche GEM-Programm
sein, das frei erhältlich ist. Gleichzeitig führt er
exemplarisch vor, wie man GEM in Forth programmiert.
Warum soll man in volksFORTH83 programmieren ?
Das volksFORTH83 ist ein ausgesprochen leistungsfähiges und
kompaktes Werkzeug. Durch residente Runtime-library, Compiler,
Editor und Debugger sind die ermüdenden ECLG-Zyklen ("Edit,
Compile, Link and Go") überflüssig; der Code wird Modul für
(2) I52E we/cp/rerhs
Modul entwickelt, kompiliert und getestet. Der integrierte
Debugger ist die perfekte Testumgebung für Worte; es gibt keine
riesigen Hexdumps oder Assemblerlistings, die kaum Ähnlichkeit
mit dem Quelltext haben.
Ein anderer wichtiger Aspekt ist das Multitasking. So wie man
ein Programm in einzelne, unabhängige Module oder Worte auf-
teilt, so sollte man es auch in einzelne, unabhängige Prozesse
aufteilen können. Das ist in den meisten Sprachen nicht
möglich, auch mit den sog. Desk-Accessories nicht. Das volks-
FORTH83 besitzt einen einfachen, aber leistungsfähigen Multi-
tasker, der auch für Aufgaben eingesetzt werden kann, die über
einen Druckerspooler hinausgehen.
Schließlich besitzt das volksFORTH83 noch eine Fülle von
Details, die andere Forthsysteme nicht haben. Es benutzt an
vielen Stellen Vektoren und sog. deferred Worte, die eine
einfache Umgestaltung des Systems für verschiedene Gerätekon-
figurationen ermöglichen. Es besitzt einen Heap (für
"namenlose” Worte oder für Code, der nur zeitweilig benötigt
wird). Der Blockmechanismus ist so schnell, daß er auch
sinnvoll für die Bearbeitung großer Datenmengen, die in Files
vorliegen, eingesetzt werden kann.
Die mit dem System gelieferten Disketten umfassen Tracer,
Decompiler, Multitasker, Assembler, Editor, Disassembler, GEM-
Bibliothek, Graphikdemos, Printerinterface ...
Das volksFORTH83 erzeugt, verglichen mit anderen Forthsystemen,
relativ schnellen Code, der aber langsamer als der anderer
Compilersprachen ist. Alle anderen Interpreter hängt es aber
mühelos ab, auch sogenannte "schnelle" BASICs.
Kurz: Das System stellt in einer Vielzahl von Details einen
Fortschritt dar!
Noch einmal : Ihr dürft und sollt diese Disks an eure Freunde
weitergeben.
Aber wenn sich jemand erdreistet, damit einen Riesenreibach zu
machen, dann werden wir ihn bis an das Ende der Welt und seiner
Tage verfolgen !
s 02) 1822 weibpire/ks Te13 Einleitung
Wir behalten uns die kommerzielle Verwertung des volksFORTH83
vor!
Mit diesem Handbuch soll die Unterstützung des volksFORTH83
noch nicht zuende sein. Die Forth Gesellschaft e.v., ein
gemeinütziger Verein, bietet dafür die Plattform. Sie gibt die
"VIERTE DIMENSION - Forth Magazin" heraus und betreibt den
FORTH-Tree, einen ungewöhnlichen, aber sehr leistungsfähigen
"Mailbox"-ähnlichen Rechner.
Forth Gesellschaft e.V.
Friedensalle 92
2000 HAMBURG 50
040 - 390 42 04 (Dienstags 18-20 Uhr mündlich, sonst
Tree !)
Schickt uns bitte auch eure Meinung zum volksFORTH, Progranne,
die fertig oder halbfertig sind, Ideen zum volksFORTH, Artikel,
die in der Presse erschienen sind (schreibt selbst welche !) „
kurz: Schickt uns alles, was entfernt mit dem volksFORTH zu tun
hat. Und natürlich : Anregungen, Ergänzungen und Hinweise
auf evtl. Fehler im Handbuch und volksFORTH83.
Wir sind nämlich, trotz der vielen verteilten Systeme, des
Lobes und der Kritik, die uns erreichte, etwas enttäuscht über
die geringe "forthige" Resonanz !
Wenn euch das volksFORTH gefällt, so erwarten wir eine Spende
von ca DM 20,-, denn die Entwicklung des volksFORTH sowie des
Handbuchs war teuer und der Preis, den wir verlangen, deckt nur
die Unkosten.
Für die Autoren des volksFORTH :
Bernd Pennemann
Steilshooper Str. 46
2000 Hamburg 60
Über dieses Handbuch
Dieses Handbuch ist kein Lehrbuch. Für Anfänger sei auf das
immer noch beste Lehrbuch "Starting Forth" von Leo Brodie
verwiesen. Das Buch ist auf Deutsch unter dem Titel
"Programmieren in Forth" im Hanser Verlag erschienen. Dieses
Handbuch enthält auch eine Liste der Abweichungen des volks-
FORTH83 von dem im Brodie besprochenen Forth. Diese Liste ist
erforderlich, weil Brodie sein Buch vor 1983 geschrieben hat,
als es den 83-Standard noch nicht gab.
Es wird vorausgesetzt, daß der Leser dieses Handbuchs "Starting
Forth" oder ein ähnliches Lehrbuch kennt. Darüber hinausgehende
Kenntnisse sind jedoch nicht unbedingt erforderlich.
Dieses Handbuch dokumentiert die benutzten Konzepte und Worte.
Der erste Teil führt den Leser in die Benutzung des volks-
FORTH83 auf dem Atari ST ein.
Der zweite Teil erklärt wie dieses Forth-System aufgebaut ist
und wie es funktioniert. Dieser Teil soll dem Anfänger die
Möglichkeit geben, sich in diese umfangreiche Sprache voll-
ständig einzuarbeiten, also auch zu wissen, wie sie funktio-
niert. Dem Fortgeschrittenen soll er die Übertragung auf andere
Rechner oder Prozessoren erleichtern.
Der dritte Teil enthält, nach Sachgruppen geordnet, die Worte
des volksFORTH83. Soweit sie durch den 83er-Standard festgelegt
sind, wurden die Definitionen aus dem Standard übersetzt.
Der vierte Teil enthält Definitionen der benutzten Begriffe.
Sie entstammen direkt dem Standard und wurden angepaßt.
Schließlich befinden sich im Anhang Erläuterungen zu Editor,
Assembler, GEM, Tools, Fehlermeldungen und Abweichungen von
anderen Forth-Systemen.
Namen von Forthworten werden im Text groß geschrieben.
m
(c) IBZE we/ibpo/re/ks I-15 Einleitung
f ie
L Einleitung \ I-16 (23 1828 werbp/reirs
(2% 1S2E weibp/re/iks I-17
Einleitung 1
Teil 1 Getting started ...
Um volksFORTH83 vollständig nutzen zu können, sollten Sie
dieses Handbuch sorgfältig studieren. Damit Sie möglichst
schnell einsteigen können, werden wir in diesem Kapitel
beschreiben,
- wie man mit den Disketten umgeht
- wie man das System startet
- wie man eine fertige Applikation erstellt.
- wie man ein eigenes Arbeitssystem zusammenstellt
Ungang mit den Disketten
Zu Ihrem Handbuch haben Sie drei Disketten erhalten. Fertigen
Sie auf jeden Fall Sicherheitskopien von diesen Disketten an.
Die Gefahr eines Datenverlustes ist groß, da FORTH Ihnen in
jeder Hinsicht freie Hand läßt - auch beim versehentlichen
Löschen Ihrer Systemdisketten !! Auf der einen Diskette befin-
den sich die Programme ATH.PRG, und FORTHRER.PRG sowie ein
Ordner mit Textdokumenten und das Demoprogramm "Super copy'.
Diese Diskette wird im Folgenden Systemdiskette genannt.
4TH.PRG ist das normale Arbeitssystem, FORTHKER.PRG eine Mini-
malversion, die nur den Sprachkern enthält. Damit können Sie
eigene FORTH-Versionen z.B. mit einem veränderten Editor oder
anderer Graphic zusammenstellen und mit SAVESYSTEM als
fertiges System abspeichern. In der gleichen Art können Sie
auch fertige Applikationen herstellen, denen man ihre "FORTH-
Abstammung nicht mehr ansieht (ein Beispiel dazu ist SUPER
COPY auf Ihrer Systemdiskette.) 4TH.PRG ist ein komplettes
Arbeitsssystem mit residentem Fileinterface, Editor, Assembler,
Tools, usw.
Die beiden anderen Disketten enthalten alle weiteren Quelltexte
des Systems. Ein Verzeichnis erhalten Sie mit FILES (analog
zu WORDS ). Bei dem File FORTH_83.SCR handelt es sich um den
Quelltext des Sprachkerns. Eben dieser Quelltext ist mit einem
Target-Compiler kompiliert worden und entspricht exakt dem
FORTHRER.PRG . Sie können sich also den Compiler ansehen, wenn
Sie wissen wollen, wie das volksFORTH83 funktioniert. Im File
STARTUP.SCR gibt es einen Loadscreen, der alle Teile kompi-
liert, die zu 4TH.PRG gehören. Mit diesem Loadscreen ist aus
FORTHKER.PRG das File A4TH.PRG zusammengestellt worden.
I-18 (23 BEE werbp/re/ks
FORTH J
Erster Einstieg
Legen Sie die Systemdiskette in Laufwerk B, die Quelltext-
diskette Files 2 in Laufwerk A. (Beim Arbeiten mit einem
Laufwerk werden Sie an den entsprechenden Stellen zum Wechseln
der Diskette aufgefordert.) Laden Sie 4TH.PRG wie üblich durch
Anklicken mit der Maus. volksFORTH83 meldet sich nun mit einer
Einschaltmeldung, die die Versionsnummer enthält.
Geben Sie jetzt ein:
use tutorial.scr <Return>
ı1 <Return>
Auf die Aufforderung 'Enter your ID :' antworten Sie zunächst
mit <Return>. Sie befinden sich jetzt im Editor und können sich
diesen und die folgenden Screens ansehen und dabei den ersten
Umgang mit dem Editor erlernen. Der Editor läuft komplett unter
einer GEM-Umgebung, sodaß sich Anleitungen erübrigen. Trotzdem
finden Sie einige Erklärungen im Anhang. Probieren Sie ein
wenig herum und verlassen Sie dann den Editor, z.B. durch
Drücken von <Esc>.
Sie können sich jetzt z.B. die Graphik-Demos ansehen. Sie
befinden sich auf derselben Diskette. Zusätzlich wird aller-
dings noch der Assembler von Diskette Files 1 gebraucht. Legen
Sie also diese anstelle der Systemdiskette in Laufwerk B.
Geben Sie ein
include demo.scr <Return>
Das Laufwerk läuft an, Sie sehen zuerst, welche Screens gerade
kompiliert werden und dann einige Graphic-Beispiele. Nach jedem
Bild können Sie mit einer beliebigen Taste weitermachen oder
mit <ESC> abbrechen.
Jetzt gehts aber richtig los ....
wir wollen jetzt einige eigene Worte kompilieren und dazu ein
neues Quelltextfile anlegen. Legen Sie dazu eine neue Diskette
in Laufwerk A ein. Geben Sie dann ein:
makefile first.scr 2 more <Return>
Sie erzeugen damit ein File namens FIRST.SCR mit einer Länge
von 2 Blöcken (2048 Byte), bestehend aus Screen O0 und 1. Un
einige Definitionen auf Screen 1 zu schreiben, rufen Sie den
Editor auf mit
ı 1 <Return>
In der obersten Zeile eines Screens sollte eine Kurzbeschrei-
bung dessen, was der Screen enthält, stehen. (Mit dem Wort
INDEX erhält man so ein Inhaltsverzeichnis des Files.) Schrei-
ben Sie also, beginnend in der linken oberen Ecke
\ Mein erstes FORTH-Programm
(23 1926 we/bp/rerke 1-19
Di
Der \ (Backslash) sorgt dafür, daß diese Zeile nicht konmpi-
liert wird, sondern als Kommentar aufgefaßt wird. Vielleicht
ist Ihnen auch bereits aufgefallen, daß bei unseren Quelltexten
in der oberen rechten Ecke Datum und Autor der letzten Änderung
vermerkt sind. Diese Kennung erzeugt der Editor automatisch,
wenn beim ersten Aufruf eine ID angegeben wurde. Sie können
Ihre ID jedoch auch nachträglich setzen, wenn Sie die Tasten-
kombination CTRL-G drücken oder den entsprechenden Menüpunkt
"GET-ID" anwählen.
Die zweite Zeile des Screens bleibt frei, in der dritten
definieren wir:
: test .”" Das ist mein erstes 'Programm'." ;
Verlassen Sie nun den Editor mit CTRL-S. Dabei wird der -
inzwischen ja veränderte - Screen auf Diskette zurückgeschrie-
ben. Nun rufen wir den Compiler auf mit
1 load <Return>
Mit für 'Cc'- oder Pascal-Programmierer unvorstellbarer
Geschwindigkeit wird unser Mini-Programm kompiliert und steht
jetzt zur Ausführung bereit. Geben Sie einmal WORDS ein, dann
werden Sie feststellen, daß Ihr neues Wort TEST ganz oben im
Dietionary steht (drücken Sie die <ESC>-Taste, um die Ausgabe
von WORDS abzubrechen oder irgendeine andere Taste, um sie
anzuhalten ). Um das Ergebnis unseres ersten Programmierver-
suchs zu überprüfen, geben wir nun ein:
test <Return>
und siehe da, es tut sich etwas. Schöner wäre es allerdings,
wenn der Satz auf einer neuen Zeile beginnen würde. Um dies zu
ändern, werfen wir erst einmal das alte Wort TEST weg.
forget test
Nun rufen wir erneut den Editor auf mit V. Vor dem String
fügen wir ein CR ein. Das Wort sieht dann so aus
: test er ." Das ist mein erstes "Programm." ;
Dann kompilieren wir wie gehabt. Unsere Änderung erweist sich
als erfolgreich, und Sie haben gelernt, wie einfach in FORTH
das Schreiben, Austesten und Ändern von Programnmteilen ist.
Einleitung I-20 (2) 1azE
Herstellung einer Applikation
Wir wollen unser 'Programm' nun als eigenständige Applikation
abspeichern. Dazu erweitern wir es zunächst ein klein wenig
(Editor mit V aufrufen.) FÜgen Sie nun noch folgende Defini-
tion in einer neuen Zeile hinzu:
: runalone test key drop bye ;
RUNALONE führt zuerst TEST aus, wartet dann auf eine Taste
und kehrt zum Desktop zurück. Kompilieren Sie nun erneut,
führen Sie RUNALONE aber nicht aus, sonst würden wir ja FORTH
verlassen. Das Problem besteht vielmehr darin, das System so
abzuspeichern, daß es gleich nach dem Laden RUNALONE ausführt
und sonst gar nichts.
volksFORTH83 ist an zwei Stellen für solche Zwecke vorbereitet.
In den Worten COLD und RESTART befinden sich zwei 'deferred
words' namens "COLD bzw. 'RESTART „ die im Normalfall nichts
tun, vom Anwender aber nachträglich verändert werden können.
Wir benutzen hier 'COLD, um auch schon die Startmeldung zu
unterbinden. i
Geben Sie also ein
° runalone Is 'cold <Return>
und speichern Sie das Ganze mit
savesystem myprog.prg
auf Diskette zurück. Laden Sie dann MYPROG.PRG durch das
übliche anklicken. Sie haben Ihre erste Applikation erstellt !
Etwas enttäuschend ist es aber schon. Das angeblich so kompakte
FORTH benötigt über 40 kByte, um einen lächerlichen String
auszugeben ?? Da stimmt doch etwas nicht. Natürlich, wir haben
ja eine Reihe Systemteile mit abgespeichert, vom Fileinterface
über den Assembler, die halbe GEM-Bibliothek, den Editor usw.,
die für unser Programm überhaupt nicht benötigt werden.
Um dieses und ähnliche Probleme zu lösen, gibt es das File
FORTHKER.PRG. Dieses Programm enthält nur den Systemkern und
das Fileinterface. Laden Sie also FORTHKER.PRG und kompilie-
ren Sie Ihre Applikation mit
include first.scr
Dann wie gehabt, RUNALONE in "COLD patchen und das System
auf Diskette zurückspeichern. Sie haben jetzt eine verhältnis-
mäßig kompakte Version vorliegen. Natürlich ließe sich auch
diese noch erheblich kürzen, aber dafür bräuchten Sie einen
Target-Compiler, mit dem Sie nur noch die wirklich benötigten
Systenteile selektiv aus dem Quelltext zusammenstellen könnten.
Mit der beschriebenen Methode lassen sich aber auch größere
Programme kompilieren und als Stand-alone-Applikationen
abspeichern.
(23 15EE Werbe/re/kz r-21
Einleitung ;
Für Fortgeschrittene
Man kann allerdings im obigen Beispiel ohne Target-Compiler
auskommen, wenn man auf das File-Interface, das ca. 4 KByte
belegt, verzichten kann. Dazu muß man zunächst eine FORTH-
Version ohne Fileinterface herstellen. Laden Sie dazu
FORTHKER.PRG und geben Sie ein:
' blke Is makeview <Return>
noop Is custom-remove <Return>
STr/w Is r/w <Return>
direct <Return>
Damit werden die 'deferred words', die das Fileinterface
umgestellt hat, wieder auf Direktmodus umgeschaltet und das
Fileinterface selbst abgeschaltet.
Das erste Wort im Fileinterface oberhalb von SAVESYSTEM ist
DOS. Dieses Wort kann man aber nicht mit FORGET vergessen, da
es sich im 'geschützten Bereich' befindet. Probieren Sie es
ruhig aus; Sie erhalten die Meldung: 'DOS is protected. Für
solche Fälle gibt es das Wort (FORGET .
' Dos >name 4- (forget save <Return>
Damit haben Sie ein System 'ohne alles'. Speichern Sie es mit
savesystem minimal.prg <Return>
auf Diskette zurück.
Natürlich können wir unser Testfile nicht mehr mit INCLUDE
laden, denn es gibt ja kein Fileinterface mehr. Stattdessen
suchen wir uns die entsprechenden Blocks im Direktzugriff.
Laden Sie also wieder 4TH.PRG, schalten Sie das Fileinterface
mit
direct
ab, und geben Sie ein:
1 500 index
(500 ist zwar sicher mehr als reichlich, aber INDEX stoppt
sowieso automatisch beim letzten Disketten- oder Fileblock.)
Unser Testscreen dürfte ziemlich weit hinten stehen, aber wir
bekommen so auch gleich einen Überblick über den Disketten-
inhalt. Merken Sie sich die Nummer n des Testscreens, und
verlassen Sie FORTH. Laden Sie dann MINIMAL.PRG und kompilie-
ren Sie Ihren Screen ohne Angabe eines Filenamens mit <n>
LOAD.
Ganz trickreiche Programmierer sind sicherlich auch in der
Lage, mit diesem System das Fileinterface auf den Heap zu
laden, ähnlich wie das beim Assembler vorgeführt wird. Dann
kann man es zum Zusammensteilen der Applikation benutzen,
SAVESYSTEM speichert es aber nicht mit ab.
Einleitung E 1-22 (2) 1326 we/ibg/rerks
Rerstellen eines eigenen Systems
Das File ATN.PRG ist als Arbeitsversion gedacht. Es enthält
alle wichtigen Systemteile wie Editor, Printer-Interface,
Tools, GEM-Graphic, Decompiler, Tracer usw. Sollte Ihnen die
Zusammenstellung nicht gefallen, können Sie sich jederzeit ein
Ihren speziellen Wünschen angepaßtes System zusammenstellen.
Schlüssel dazu ist der Loadscreen im File STARTUP.SCR der
Diskette Files 1. Sie können dort Systemteile, die Sie nicht
benötigen, mit dem Backslash '\' wegkommentieren oder die
entsprechenden Zeilen ganz löschen. Ebenso können Sie natürlich
dem Loadscreen eigene Files hinzufügen.
Entspricht der Loadscreen Ihren Wünschen, speichern Sie ihn mit
CTRL-S zurück, und verlassen Sie das System mit BYE. Laden Sie
nun File FORTHKER.PRG. Geben Sie dann ein:
include startup.scr <Return>
Ist das System fertig kompiliert, legen Sie die Systemdiskette
ein und schreiben:
savesystem 4dth.prg <Return>
Damit wird Ihr altes File überschrieben (Sicherheitskopie !!!),
sodaß Sie beim nächsten Laden von 4TH.PRG Ihr eigenes System
erhalten. Natürlich können Sie 'Ihr' System auch unter einem
anderen Namen mit SAVESYSTEM abspeichern.
Ebenso können Sie Systemvoreinstellungen ändern. Unsere
Arbeitsversion arbeitet - voreingestellt - neuerdings im dezi-
malen Zahlensystem. Natürlich können Sie mit
hex <Return>
auf Hexadezimalsystem umstellen; wir halten das für sehr viel
sinnvoller, weil vor allem Speicheradressen im Dezimalsystem
kaum etwas aussagen (oder wissen Sie, ob Speicherstelle 978584
im Bildschirmspeicher liegt oder nicht ?) . Wollen Sie bereits
unmittelbar nach dem Laden im Hexadezimalsystem arbeiten,
können Sie sich dies mit SAVESYSTEM, wie oben beschrieben,
abspeichern.
Im Übrigen empfehlen wir bei allen Zahlen über 9 dringend die
Benutzung der sogenannten Präfixe $ für Hexadezimal-, & für
Dezimal- und % für Binärzahlen. Man vermeidet so, daß irgend-
welche Files nicht - oder noch schlimmer, falsch - kompiliert
werden, weil man gerade im anderen Zahlensystem ist. Außerdem
ist es möglich, hexadezimale und dezimale Zahlen beliebig zu
kombinieren, je nachdem, was gerade sinnvoller ist. In unseren
Quelltexten finden Sie genug entsprechende Beispiele.
(23 BEE wesbp/re/ks 1223 Einleitung
Wenn Sie nur ein Laufwerk zur Verfügung haben, sollten Sie den
voreingestellten Suchpfad - es wird erst Laufwerk A, dann
Laufwerk B durchsucht - ändern. Wenn nur auf Laufwerk A gesucht
werden soll, geben Sie folgende Sequenz ein
path ; a:
und speichern das System mit SAVESYSTEM auf Diskette zurück.
Umkopieren des Systems auf doppelseitige Disketten
Wenn Sie über doppelseitige Laufwerke verfügen, können Sie das
System auf doppelseitige Disketten umkopieren. Der Vorteil
liegt darin, daß die VIEW-Funktion natürlich nur dann funktio-
niert, wenn die entsprechenden Quelltextfiles verfügbar sind.
Und auf ein oder zwei doppelseitigen Disketten läßt sich schon
eine Reihe Files zur Verfügung halten.
Ebenso ist es natürlich möglich, alle Teile des Systens auf
einer Festplatte abzulegen. Sie sollten dafür einen eigenen
Ordner einrichten und PATH und DIR entsprechend einstellen.
Auch die Arbeit mit einer RAM-Disk ist prinzipiell möglich,
allerdings nicht sehr zu empfehlen. FORTH ist sehr maschinennah
und Systemabstürze daher vor allem zu Anfang nicht so ganz
auszuschließen. Wir empfehlen stattdessen die Verwendung des
Files RAMDISK.SCR . Damit werden sehr viele Blockbuffer im RAM
- außerhalb des FORTH-Systems - eingerichtet, was die Kompila-
tionszeiten erheblich beschleunigt. Trotzdem ist große Daten-
sicherheit vorhanden, weil alle geänderten Blocks immer auf
Diskette zurückgeschrieben werden, wenn man den Editor mit
CTRL-S verläßt. Die Gefahr eines Datenverlustes bei System-
absturz ist so nahezu ausgeschlossen.
Ausdrucken der Quelltexte
Sicher ist es sinnvoll, die Quelltexte des Systems auszu-
drucken, um Beispiele für den Umgang mit volksFORTH83 zu sehen.
Inzwischen ist ein großer Teil der Quelltexte mit Kommentar-
screens versehen, was - wie wir hoffen - gerade für den
Einsteiger eine große Hilfe darstellt. Welche Files sich im
Einzelnen auf Ihren Disketten befinden und ob sie Kommentar-
screens enthalten, steht im File README.DOC.
Zunächst müssen Sie das Printerinterface hinzuladen, falls es
nicht schon vorhanden ist. Reagiert Ihr volksFORTH83 auf die
Eingabe von PRINTER mit einem kräftigen Haeh? ,„, so ist das
Printerinterface nicht vorhanden. Legen Sie die entsprechende
Diskette ein und laden Sie es mit :
include printer.scr
nö} =
| Einleitung E I-24 2) BEE weibp/re/hs
Zum Ausdrucken von Files mit Shadowscreens gibt man ein :
USE <filename> LISTING
Für Files ohne Shadowscreens benutzt man :
USE <£filename> PRINTALL
Näheres zum Drucker-Interface finden Sie im Kapitel 4 des
zweiten Teils.
“iD
u Erläuterungen
(23 HSFEE weibp/re/ks IT=1
Erläuterungen ]
Teil 2
1) Dictionarystruktur des volksFORTH83
Das Forthsystem besteht aus einem Dictionary von Worten.
Struktur der Worte und des Dictionaries soll
erläutert werden.
Die
im folgenden
1.1) Struktur der Worte
Die Forthworte sind in Listen angeordnet (s.a. Struktur der
Vokabulare). Die vom Benutzer definierten Worte werden eben-
falls in diese Listen eingetragen . Jedes Wort besteht aus
sechs Teilen.
Es sind dies:
a) "block"
Der Nummer des Blocks, in dem das Wort definiert wurde
(siehe auch VIEW im Glossar).
b) "link"
Einer Adresse (Zeiger)
, die auf das "Linkfeld" des
nächsten Wortes zeigt.
ce) "count"
Die Länge des Namens dieses Wortes und drei
Markierungs-
bits.
ad) "name"
Der Name selbst.
e) "code"
Einer Adresse (Zeiger) ,„ die auf den Maschinencode zeigt,
der bei Aufruf dieses Wortes ausgeführt wird. Die Adresse
dieses Feldes heißt Kompilationsadresse.
£) "parameter"
Das Parameterfeld.
Ein Wort sieht dann so aus :
Kort
[ block ] link ] count | nane ] code ] parameter _.,, |
[ Erläuterungen | IIl=2 (23 1988
1.1.1) Countfeld
Das count-Feld enthält die Länge des Namens ( 1..31 Zeichen )
und drei Markierungsbits :
[restrict | imnediate | indirect | Länge |
Bit: 7 6 5 rl
Ist das immediate-Bit gesetzt, so wird das entsprechende
Wort im kompilierenden Zustand unmittelbar ausgeführt,
und nicht ins Dictionary kompiliert (siehe auch IMMEDIATE
im Glossar).
Ist das restrict-Bit gesetzt, so kann das Wort nicht
durch Eingabe von der Tastatur ausgeführt, sondern nur in
anderen Worten kompiliert werden. Gibt man es dennoch im
interpretierenden Zustand ein, so erscheint die Fehler-
meldung "compile only" (siehe auch RESTRICT im Glossar).
Ist das indirect-Bit gesetzt, so folgt auf den Namen kein
Codefeld, sondern ein Zeiger darauf. Damit kann der Name
vom Rumpf ( Code- und Parameterfeld )J getrennt werden.
Die Trennung geschieht z.B. bei Verwendung der Worte |
oder ALIAS.
Beispiel:
° 1+ Alias addl
ergibt folgende Struktur im Speicher (Dictionary) :
[ block | link | $24 ] ADDi | pointer |
v
ı v
C andere Korte ) &
ı &
%
[| block | 1ink' ] 582 ] i* | code | parameter |
( Bei allen folgenden Bildern werden die Felder block
link count nicht mehr extra dargestellt. )
"_
ic} 4822 we/bp/re/ks II-3 Erläuterungen N
1.1.2) Name
Der Name besteht normalerweise aus ASCII-Zeichen, Bei der
Eingabe werden Klein- in Großbuchstaben umgewandelt. Daher
druckt WORDS auch nur groß geschriebene Namen. Da Namen
sowohl groß als auch klein geschrieben eingegeben werden
können, haben wir eine Konvention erarbeitet, die die Schreib-
weise von Namen festlegt:
Bei Kontrollstrukturen wie DO LOOP etc. werden alle Buch-
staben groß geschrieben.
Bei Namen von Vokabularen, immediate Worten und definierenden
Worten, die CREATE ausführen, wird nur der erste Buchstabe
groß geschrieben. Beispiele sind: Is Forth Constant
Alle anderen Worte werden klein geschrieben. Beispiele sind:
dup cold base
Bestimmte Worte, die von immediate Worten kompiliert werden,
beginnen mit der öffnenden Klammer "(" „ gefolgt vom Namen des
immediate Wortes. Ein Beispiel: DO kompiliert (do x
Diese Schreibweise ist nicht zwingend; Sie sollten sich aber
daran halten, um die Lesbarkeit Ihrer Quelltexte zu erhöhen.
Das volksFORTH unterscheidet nicht zwischen Groß- und Klein-
schreibung, sodaß Sie die Worte beliebig eingeben können.
1.1.3) Link
Über das link-Feld sind die Worte eines Vokabulars zu einer
Liste verkettet. Jedes link-Feld enthält die Adresse des
vorherigen link-Feldes. Jedes Wort zeigt also auf seinen
Vorgänger. Das unterste Wort der Liste enthält im link-Feld
eine Null. Die Null zeigt das Ende der Liste an.
°%6 88666 8066
8 o 8
[_ Mort_] Wort | Wort | Wort
8 a &
296666 28066
1.1.4) Block
Das block-Feld enthält in codierter Form die Nummer des Blocks
und den Namen des Files, in dem das Wort definiert wurde. Wurde
es von der Tastatur aus eingegeben, so enthält das Feld Null.
| Erläuterungen | II-4 123
1.1.5) Code
Jedes Wort weist auf ein Stück Maschinencode. Die Adresse
dieses Code-Stücks ist im Code-Feld enthalten. Gleiche Wort-
typen weisen auf den gleichen Code. Es gibt verschiedene
Worttypen, z.B. :-Definitionen , Variablen ,„ Konstanten „,
Vokabulare usw. Sie haben jeweils ihren eigenen charakte-
ristischen Code gemeinsan.
Die Adresse des Code-Feldes heißt Kompilationsadresse.
1.1.6) Parameter
Das Parameterfeld enthält Daten, die vom Typ des Wortes
abhängen.
Beispiele :
a) Typ "Constant"
Hier enthält das Parameterfeld des Wortes den Wert der
Konstanten. Der dem Wort zugeordnete Code liest den
Inhalt des Parameterfeldes aus und legt ihn auf den
Stack.
b) Typ "Variable"
Das Parameterfeld enthält den Wert der Variablen, der
zugeordnete Code liest jedoch nicht das Parameterfeld
aus, sondern legt dessen Adresse auf den Stack. Der
Benutzer kann dann mit dem Wort @ den Wert holen und
mit dem Wort ! überschreiben.
ce) Typ ":-definition"
Das ist ein mit : und ; gebildetes Wort. In diesem
Fall enthält das Parameterfeld hintereinander die Kompi-
lationsadressen der Worte, die diese Definition bilden.
Der zugeordnete Code sorgt dann dafür, daß diese Worte
der Reihe nach ausgeführt werden.
Beispiel : : test dup ;
ergibt:
[ TEST ] code | pointer | pointer |
. 8
8006
8
| code ] paraneter | ©
DEE GGS
oo
©
v
o
EXIT | code | parameter |
(2) 1928 we/kp/re/kz Pr5
Erläuterungen 3
Das Wort : hat den Namen TEST erzeugt.
EXIT wurde durch das Wort ; erzeugt
ad) Typ "Code"
Worte vom Typ "Code" werden mit dem Assembler erzeugt.
Hier zeigt das Codefeld in der Regel auf das Parameter-
feld. Dorthin wurde der Maschinencode assembliert. Code-
worte im volksFORTH können leicht "umgepatcht"” werden, da
lediglich die Adresse im Codefeld auf eine neue (andere)
Maschinencodesequenz gesetzt werden muß.
PR: ; 4
ni =
.l Erläuterungen E II-6 (23 1828 werbpitefhs
1.2) Vokabular-Struktur
Eine Liste von Worten ist ein Vokabular. Ein Forth-System
besteht im allgemeinen aus mehreren Vokabularen, die nebenei-
nander existieren. Neue Vokabulare werden durch das definie-
rende Wort VOCABULARY erzeugt und haben ihrerseits einen
Namen, der in einer Liste enthalten ist.
Gewöhnlich kann von mehreren Worten mit gleichem Namen nur das
zuletzt definierte erreicht werden. Befinden sich jedoch die
einzelnen Worte in verschiedenen Vokabularen, so bleiben sie
einzeln erreichbar.
1.2.1) Die Suchreihenfolge
Die Suchreihenfolge gibt an, in welcher Reihenfolge die
verschiedenen Vokabulare nach einem Wort durchsucht werden.
Sie besteht aus zwei Teilen, dem auswechselbaren und dem festen
Teil. Der auswechselbare Teil enthält genau ein Vokabular. Dies
wird zuerst durchsucht. Wird ein Vokabular durch Eingeben
seines Namens ausgeführt, so trägt es sich in den auswechsel-
baren Teil ein. Dabei wird der alte Inhalt überschrieben.
Einige andere Worte ändern ebenfalls den auswechselbaren Teil.
Soll ein Vokabular immer durchsucht werden, so muß es in den
festen Teil befördert werden. Dieser enthält null bis sechs
Vokabulare und wird nur vom Benutzer bzw. seinen Worten
verändert. Zur Manipulation stehen u.a. die Worte ONLY ALSO
TOSS zur Verfügung. Das Vokabular, in das neue Worte
einzutragen sind, wird durch das Wort DEFINITIONS angegeben.
Die Suchreihenfolge kann man sich mit ORDER ansehen.
Beispiele :
Eingabe : ORDER ergibt dann :
Onlyforth FORTH FORTH ONLY FORTH
Editor also EDITOR EDITOR FORTH ONLY FORTH
Assembler ASSEMBLER EDITOR FORTH ONLY FORTH
definitions Forth FORTH EDITOR FORTH ONLY ASSEMBLER
: test ; ASSEMBLER EDITOR FORTH ONLY ASSEMBLER
o 23 4328 wesbp/rerks 11-7
FÜRTH
Erläuterungen
1.2.2)
Struktur des Dictionaries
Der Inhalt eines Vokabulars besteht aus einer Liste von Worten,
die durch ihre link-Felder miteinander verbunden sind. Es gibt
also genauso viele Listen wie Vokabulare. Alle Vokabulare sind
selbst noch einmal über eine Liste verbunden, deren Anfang in
VOC-LINK steht. Diese Verkettung ist nötig, um ein komfor-
tables FORGET zu ermöglichen.
Man bekommt beispielsweise folgendes Bild:
Voc-link 9 ® (iezener) »» [Only | »» LForth | » 9» Hull
Mr Me rl
Ö & &
Kull Kull Kull
II-8
weibp/irerts
we/bp/reihz T I-9
-
r
-
y
Kr
in
Erläuterungen
2) Die Ausführung von Forth-Worten
Der geringe Platzbedarf übersetzter Forth-Worte rührt
wesentlich von der Existenz des Adressinterpreters her.
Wie aus dem Kapitel 1.1.6 Absatz c) ersichtlich, besteht eine
:-Definition aus dem Codefeld und dem Parameterfeld. Im Para-
meterfeld steht eine Folge von Adressen. Ein Wort wird kompi-
liert, indem seine Kompilationsadresse dem Parameterfeld der :-
Definition angefügt wird. Eine Ausnahme bilden die Immediate
Worte. Da sie während der Kompilation ausgeführt werden, können
sie dem Parameterfeld der :-Definition alles mögliche hinzu-
fügen.
Daraus wird klar, daß die meisten Worte innerhalb der :-
Definition nur eine Adresse, also in einem 16-Bit-System genau
2 Bytes an Platz verbrauchen.
Wird die :-Definition nun aufgerufen, so sollen alle Worte,
deren Kompilationsadresse im Parameterfeld stehen, ausgeführt
werden. Das besorgt der Adressinterpreter.
2.1) Aufbau des Adressinterpreters beim volksFORTH83
Der Adressinterpreter benutzt einige Register der CPU, die im
Kapitel über den Assembler aufgeführt werden. Es gibt aber
mindestens die folgenden Register :
IP W sp RP
a) IP ist der Instruktionszeiger (englisch : Instruction
Pointer). Er zeigt auf die nächste auszuführende
Instruktion. Das ist beim volksFORTH83 die Speicher-
zelle, die die Kompilationsadresse des nächsten auszu-
führenden Wortes enthält.
b) W ist das Wortregister. Es zeigt auf die Kompilations-
adresse des Wortes, das gerade ausgeführt wird.
c) SP ist der (Daten-) Stackpointer. Er zeigt auf das
oberste Element des Stacks.
a) RP ist der Returnstackpointer. Er zeigt auf das
oberste Element des Returnstacks.
Erläuterungen i 11-10 (23 1828
2.2) Die Funktion des Adressinterpreters
NEXT ist die Anfangsadresse der Routine, die die Instruktion
ausführt, auf die IP gerade zeigt.
Die Routine NEXT ist ein Teil des Adressinterpreters. Zur
Verdeutlichung der Arbeitsweise schreiben wir hier diesen Teil
in High Level:
Variable IP
Variable W
: Next IP@e ®@ WW!
2 IP +!
W perform ;
Tatsächlich ist NEXT jedoch eine Maschinencoderoutine, weil
dadurch die Ausführungszeit von Forth-Worten erheblich kürzer
wird. NEXT ist somit die Einsprungadresse einer Routine, die
diejenige Instruktion ausführt, auf die das Register IP zeigt.
Ein Wort wird ausgeführt, indem der Code, auf den die Kompila-
tionsadresse zeigt, als Maschinencode angesprungen wird.
Der Code kann z.B. den alten Inhalt des IP auf den Returnstack
bringen, die Adresse des Parameterfeldes im IP speichern und
dann NEXT anspringen.
Diese Routine gibt es wirklich, sie heißt "docol" und ihre
Adresse steht im Codefeld jeder :-Definition. Das Gegenstück zu
dieser Routine ist ein Forth-Wort mit dem Namen EXIT . Dabei
handelt es sich um ein Wort, das das oberste Element des
Returnstacks in den IP bringt und anschließend NEXT
anspringt. Damit ist dann die Ausführung der Colon-definition
beendet.
Beipiel :
: 2% dup + ;
Ssods 28
Ein Aufruf von
5.2.
von der Tastatur aus führt zu folgenden Situationen :
a) [| 2. | docol ] 2% | EXIT ]
o I 5 | [ susten |
IP Stack Rstack
Nach der ersten Ausführung von NEXT bekommt man :
2} jiS2E be/icp/refhs II-11
Erläuterungen |
DE TEE ET ESOr EZ
b) [ 2. | docol | 2%] , | EXIT
%
c) | 2% | docol | DUP | + | EXIT] 5 system
© 5 addri
IP Stack Rstack
0)
e)
addri
[2% | docol | DUP | + ] EXIT | system
a 5 addri
IP Stack Rstack
Nochmalige Ausführung von NEXT ergibt :
{ DUP ist ein Wort vom Typ "Code" )
Nach der nächsten Ausführung von NEXT zeigt der IP auf
EXIT und nach dem darauf folgenden NEXT wird addäri
wieder in den IP geladen :
2. | docol | 2% | . | EXIT
© [18 | [ system |]
IP Stack Rstack
Die Ausführung von . erfolgt analog zu den Schritten
b,ce und d. Anschließend zeigt IP auf EXIT in 2. *
Nach Ausführung von NEXT kehrt das System wieder in
den Textinterpreter zurück. Dessen Rückkehradresse wird
durch system angedeutet. Damit ist die Ausführung von
2. beendet.
II-12 Ä
3
v
W
a
ın
we/bp/re/hz
2.3) Verschiedene Immediate Worte
In diesem Abschnitt werden Beispiele für immediate Worte
angegeben, die mehr als nur eine Adresse kompilieren.
a) Zeichenketten, die durch " abgeschlossen werden,
liegen als counted Strings im Dictionary vor.
Beispiel: abort” Test” liefert :
I (ABORT" 1 04 | Tileis|tı!
b) Einige Kontrollstrukturen kompilieren ?BRANCH oder
BRANCH ,„, denen ein Offset mit 16 Bit Länge folgt.
Beispiel: 0< IF swap THEN - liefert :
1 0< | ?BRANCH | A | SWAP | - |
Beispiel: BEGIN ?dup WHILE @ REPEAT
liefert : I ?DUP ! ?BRANCH | 8 | @ | BRANCH I -10 |
c) Ebenso fügen DO und ?DO einen Offset hinter das
von ihnen kompilierte Wort (DO bzw. (?DoO . Mit dem
Dekompiler können Sie sich eigene Beispiele anschauen.
d) Zahlen werden in das Wort LIT ,„ gefolgt von einem
16-Bit-Wert, kompiliert.
Beispiel: [ hex ] 8 1000
liefert : | LIT I $0008 } LIT | $1000 | .
ic) 1328 weibp/reiks TI=13 Erläuterungen
3) Die Does>-Struktur
Die Struktur von Worten, die mit CREATE .. DOES> erzeugt
wurden, soll anhand eines Beispiels erläutert werden.
Das Beispielprogramm lautet :
: Constant Create „ Does> @ ;
3 Constant drei
Der erzeugte Code sieht folgendermaßen aus:
Der jump-Befehl ist symbolisch
gemeint. In Wirklichkeit wird eine
andere Adressierungsart benutzt |!
DREI | code | 8883
v
BIIIIIDIPIIPPPIPIGU
&
[ CONSTANT | docol | Create | , ] (;code |] jmp dodoes> | @ | EXIT |
Das Wort (;CODE wurde durch DOES> erzeugt. Es setzt das
Codefeld des durch CREATE erzeugten Wortes DREI und beendet
dann die Ausführung von CONSTANT . Das Codefeld von DREI
zeigt anschließend au£ jmp dodoes>). Wird DREI später aufge-
xrufen , so wird der zugeordnete Code ausgeführt. Das ist in
diesem Fall jmp dodoes>. dodoes> legt nun die Adresse des
Parameterfeldes von DREI auf den Stack und führt die auf
jmp dodoes> folgende Sequenz von Worten aus. ( Man beachte
die Ähnlichkeit zu :-Definitionen).
Diese Sequenz besteht aus @ und EXIT . Der Inhalt des
Parameterfeldes von DREI wird damit auf den Stack gebracht.
Der Aufruf von DREI liefert also tatsächlich 0003. Statt des
jmp dodoes> und der Sequenz von Forthworten kann sich hinter
(;CoDE auch ausschließlich Maschinencode befinden. Das ist
der Fall, wenn wir das Wort ;CODE statt DOES> benutzt
hätten. Wird diese Maschinencodesequenz später ausgeführt, so
zeigt das W-Register des Adressinterpreters auf das Codefeld
des Wortes, dem dieser Code zugeordnet ist. Erhöht man also das
W-Register um 2 „ so zeigt es auf das Parameterfeld des gerade
auszuführenden Wortes.
II-14 2) SEE weibp/re/ks
(23 HERE weibe/re/ks II-15 Erläuterungen
4) Vektoren und Deferred Worte
Das volksFORTH833 besitzt eine Reihe von Strukturen, die dazu
dienen, das Verhalten des Systems zu ändern.
4.1) deferred Worte
Sie werden durch das Wort DEFER erzeugt. Im System sind
bereits folgende deferred Worte vorhanden:
R/W 'cOLD 'RESTART "ABORT 'QuUIT NOTFOUND .STATUS
DISKERR MAKEVIEW und CUSTOM-REMOVE.
Um sie zu ändern, benutzt man die Phrase:
<name> Is <namex>
Hierbei ist <namex> ein durch DEFER erzeugtes Wort und
<name> der Name des Wortes, das in Zukunft bei Aufruf von
<namex> ausgeführt wird.
Wird <namex> ausgeführt bevor es mit IS wiünitialisiert wurde,
so erscheint die Meldung "Crash" auf dem Bildschirm.
Anwendungsmöglichkeiten von deferred Worten :
Durch Ändern von R/W kann man andere Floppies oder eine RAM-
Disk betreiben. Es ist auch leicht möglich, Teile einer Disk
gegen überschreiben zu schützen.
Durch Ändern von NOTFOUND kann man z.B. Worte, die nicht im
Dictionary gefunden wurden, anschließend in einer Disk-Direc-
tory suchen lassen oder automatisch als Vorwärtsreferenz ver-
merken.
Ändert man 'COLD , so kann man die Einschaltmeldung des
volksFORTH83 unterdrücken. und stattdessen ein Anwenderprogramm
starten, ohne daß Eingaben von der Tastatur aus erforderlich
sind (siehe z.B. Teil 1, "Erstellen einer Applikation").
Ähnliches gilt für 'RESTART.
"ABORT ist z.B. dafür gedacht, eigene Stacks, z.B. für
Fließkommazahlen, im Fehlerfall zu löschen. Die Verwendung
dieses Wortes erfordert aber schon eine gewisse Systemkenntnis.
Das gilt auch für das Wort 'QUIT.
'QUIT wird dazu benutzt, eigene Quitloops in den Compiler
einzubetten. Wer sich für diese Materie interessiert, sollte
sich den Quelltext des Tracer anschauen. Dort wird vorgeführt,
wie man das macht.
.STATUS schließlich wird vor Laden eines Blocks ausgeführt.
Man kann sich damit anzeigen lassen, welchen Block einer
längeren Sequenz das System gerade lädt und z.B. wieviel freier
Speicher noch zur Verfügung steht.
CUSTOM-REMOVE kann vom fortgeschrittenen Programmierer dazu
benutzt werden, eigene Datenstrukturen, die miteinander durch
Zeiger verkettet sind, zu vergessen. Ein Beispiel dafür sind
die File Control Blöcke des Fileinterfaces.
II-16 (23 1S2E we/bp/re/hs
4.2) >interpret
Dieses Wort ist ein spezielles deferred Wort, das für die
Umschaltung des Textinterpreters in den Kompilationszustand und
zurück benutzt wird.
4.3) Variablen
Es gibt im System die Uservariable ERRORHANDLER . Dabei
handelt es sich um eine normale Variable, die als Inhalt die
Kompilationsadresse eines Wortes hat. Der Inhalt der Variablen
wird auf folgende Weise ausgeführt:
ERRORHANDLER PERFORM
Zuweisen und Auslesen dieser Variablen geschieht mit @ und !
. Der Inhalt von ERRORHANDLER wird ausgeführt, wenn das System
ABORT" oder ERROR" ausführt und das von diesen Worten
verbrauchte Flag wahr ist. Die Adresse des Textes mit der
Fehlermeldung befindet sich auf dem Stack. Siehe z.B. (ERROR .
4.4) Vektoren
Das volksFORTH83 benutzt die indirekten Vektoren INPUT und
OUTPUT. Die Funktionsweise der sich daraus ergebenden Struktu-
ren soll am Beispiel von INPUT verdeutlicht werden.
INPUT ist eine Uservariable, die auf einen Vektor zeigt, in dem
wiederum vier Kompilationsadressen abgelegt sind. Jedes der
vier Inputworte KEY KEY? DECODE und EXPECT führt eine der
Kompilationsadressen aus. Kompiliert wird solch ein Vektor in
der folgenden Form:
Input: vector
<namel> <name2> <name3> <name4> ;
wird VECTOR ausgeführt, so schreibt er seine Parameterfeld-
adresse in die Uservariable INPUT . Von nun an führen die
Inputworte die ihnen so zugewiesenen Worte aus. KEY führt also
<NAMEl> aus usw...
Das Beispiel KEY? soll dieses Prinzip verdeutlichen:
: key? (—-cec)
input @ 2+ perform ;
(Tatsächlich wurde KEY? im System ebenso wie die anderen
Inputworte durch das nicht mehr sichtbare definierende Wort
IN: erzeugt.)
(2) 126 weibp/reiks IT Erläuterungen N
Ein Beispiel für einen Inputvektor, der die Eingabe von der
Tastatur holt :
Input: keyboard
STkey STkey? STdecode STexpect ;
keyboard
ergibt :
input | pointer |
v
BP
v
[ KEYBOARD | code |_STkey_| STkey? | Sldecode | STexpeet |
2 °
ausgeführt von: key key? decode expect
Analog verhält es sich mit OUTPUT und den Outputworten EMIT
CR TYPE DEL PAGE AT und AT? . Outputvektoren werden mit
OUTPUT: genauso wie die Inputvektoren erzeugt.
Mit der Input/Output-Vektorisierung kann man z.B. mit einem
Schlag die Eingabe von der Tastatur auf ein Modem umschalten.
Bitte beachten Sie, daß immer alle Worte in der richtigen
Reihenfolge aufgeführt werden müssen ! Soll nur ein Wort
geändert werden, so müssen sie trotzdem die anderen mit
hinschreiben.
MER >
|| Erläuterungen II-18 (23 1828
Die Druckeranpassung
Alle Ausgabeworte (EMIT, TYPE, SPACE etc.) sind im volksFORTH-
83 vektorisiert, d.h. bei ihrem Aufruf wird die Codefeldadresse
des zugehörigen Befehls aus einer Tabelle entnommen und ausge-
führt. Im System enthalten ist eine Tabelle mit Namen DISPLAY,
die für die Ausgabe auf das Bildschirmterminal sorgt. Dieses
Verfahren bietet entscheidende Vorteile:
= Mit einer neuen Tabelle können alle Ausgaben auf ein
anderes Gerät (z.B. einen Drucker) geleitet werden,
ohne die Ausgabebefehle selbst ändern zu müssen.
= Mit einem Wort (DISPLAY, PRINT) kann das gesamte
Ausgabeverhalten geändert werden. Gibt man z.B. ein:
print 1 list display
wird Screen 1 auf einen Drucker ausgegeben,
anschließend wieder auf den Bildschirm zurückge-
schaltet. Man braucht also kein neues Wort, etwa
PRINTERLIST, zu definieren.
Eine neue Tabelle wird mit dem Wort OUTPUT: erzeugt. (Die
Definition können Sie mit VIEW OUTPUT: nachsehen.) OUTPUT:
erwartet eine Liste von Ausgabeworten, die mit ; abge-
schlossen werden muß. Beispiel:
Output: >printer
pemit pcr ptype pdel ppage pat pat? ;
Damit wird eine neue Tabelle mit dem Namen >PRINTER angelegt.
Beim späteren Aufruf von >PRINTER wird die Adresse dieser
Tabelle in die Uservariable OUTPUT geschrieben. Ab sofort
führt EMIT ein PEMIT aus, TYPE ein PTYPE usw. Die
Reihenfolge der Worte nach OUTPUT: userEMIT userCR userTYPE
userDEL userPAGE UuserAT userAT? muß unbedingt eingehalten
werden.
Der folgende Quelltext enthält die Anpassung für einen Epson-
Drucker RX8O/FX80 oder kompatible am Atari ST. Zusätzlich zu
den reinen Ausgaberoutinen (Screen 7) sind eine Reihe nützli-
cher Worte enthalten, mit denen die Druckersteuerung sehr
komfortabel vorgenommen werden kann.
Arbeiten Sie mit einem Drucker, der andere Steuercodes als
Epson verwendet, müssen Sie die Screens 2 und 4 bis 6 anpassen.
Bei IBM-kompatiblen Druckern ist es meist damit getan, daß die
Umlautwandliung (Screen 6) weggelassen wird. Dies erreicht man,
indem man in Zeile 1 einen doppelten Backslash (\\) setzt.
Im Arbeitssystem ist das Printerinterface bereits enthalten.
Müssen Sie Änderungen vornehmen, können Sie entweder jedesmal
Ihr geändertes Printerinterface mit
include printer.scr
(2) 322 weibp/re/ks ITI-19
Erläuterungen 1
dazuladen oder sich ein neues Arbeitssystem zusammenstellen wie
im Kapitel "Getting started ...' beschrieben. Sie können
natürlich auch den Loadscreen in seiner jetzigen Fassung
benutzen und das Printer-Interface 'von Hand nachladen.
Im zweiten Teil des Printer-Interface (Screen 9 ff.) sind
einige Worte zur Ausgabe eines formatierten Listings enthalten.
PTHRU druckt einen Bereich von Screens, PRINTALL ein ganzes
File, jeweils 6 Screens auf einer DIN A4 Seite in komprimierter
Schrift. Ganz ähnlich arbeiten die Worte DOCUMENT und
LISTINGS ,„ jedoch wird bei diesen Worten neben einen Quell-
textscreen der zugehörige Shadowscreen gedruckt. (Mehr über das
Shadowscreen-Konzept erfahren Sie im Kapitel über den Editor.)
Man erhält so ein übersichtliches Listing eines Files mit
ausführlichen Kommentaren. Es empfiehlt sich daher, alle Files,
die Shadowscreens enthalten, einmal mit LISTING auszudrucken.
An dieser Stelle folgt das Listing des Files PRINTER.SCR.
voNauBummHro
PRrPrPrrHr
UBRWDHO
VvoQıauın Bumd Ho
VOQInUBWNDHMHO
PRINTER.SCR Scr O0 Dr O0
\\ **%* Printer-Interface *** 10oct86we
Dieses File enthält das Printer-Interface. Die Definitionen für
die Druckersteuerung müssen ggf. an Ihren Drucker angepaßt wer-
den.
PRINT lenkt alle Ausgabeworte auf den Drucker um, mit DISPLAY
wird wieder auf dem Bildschirm ausgegeben.
Zum Ausdrucken der Quelltexte gibt es die Worte
pthru ( £rom to -- ) druckt Screen from bis to
document ( £rom to -- ) wie pthru, aber mit Shadow-Screens
printall (=) wie pthru, aber druckt das ganze File
listing (--) wie document, aber für das ganze File
PRINTER.SCR Scr 1 Dr O
\ Printer Interface Epson RX80\FX80 2loct36we
Onlyforth
\needs file? ' noop ı Alias file?
\needs capacity ' plk/drv Alias capacity
Vocabulary Printer Printer definitions also
ji &13 +thru
Onlyforth \ clear
PRINTER.SCR Scr 2 Dr O0
\ Printer p! and controls 18nov&6we
' bceostat ! Alias ready? ' 0 } Alias printer
p! (n=)
BEGIN pause printer ready? UNTIL printer bconout ;
I x etrl: (8b -- ) Create c, does» (--) ce@p!;
07 ctrl: BEL $7F | ctrl: DEL $S0D | ctrl: RET
$1B | ctrls EScC SO0A etrl: LF SE ctri: FF
VoIP WMDHO
PRARFrRHR
VUBWNDHrO
VvVoynummwmro
PRrRAPrPRHr
UBLDLHRO
VvOoSIAUTBRWNDHO
(©) SEE werbp/re/kz 21-21 Erläuterungen
PRINTER.SCR Scr 15 Dr 0
NN *%% Printer-Interface *** 130oct36we
Eingestellt ist das Druckerinterface auf Epson und kompatible
Drucker. Die Steuersequenzen auf den Screens 2, 4 und 5 müssen
gegebenenfalls auf Ihren Drucker angepaßt werden. Bei uns gab
es mit verschiedenen Druckern allerdings keine Probleme, da
sich inzwischen die meisten Druckerhersteller an die Epson-
Steuercodes halten.
Arbeiten Sie mit einem IBM-kompatiblen Drucker, muß die Umlaut-
wandlung auf Screen 6 wegkommentiert werden.
Zusätzliche 'exotische' Steuersequenzen können nach dem Muster
auf den Screens 4 und 5 jederzeit eingebaut werden.
PRINTER.SCR Scr 16 Dr 0
\ Printer Interface Epson RX80 130oct86we
setzt order auf FORTH FORTH ONLY FORTH
falls das Fileinterface nicht im System ist, werden die ent-
sprechenden Worte ersetzt.
Printer-Worte erhalten ein eigenes Vocabulary.
PRINTER.SCR Scr 17 Dr O0
\ Printer p! and controls 100oct86we
nur aus stilistischen Gründen. Das Folgende liest sich besser.
Hauptausgabewort; gibt ein Zeichen auf den Drucker aus. Es wird
gewartet, bis der Drucker bereit ist. (PAUSE für Multitasking)
gibt Steuerzeichen an Drucker
Steuerzeichen für Drucker, Gegebenenfalls anpassen!
Donau $BPUWDHO
voJaubwmH Oo
2) IpzE ve/ibp/reihz
PRINTER.SCR Scr 3 Dr O
\ Printer controls 09sep386re
In esc: (8b -- ) Create c, does» (--) ESC c@p!;
ı 2 esc2 ( 8b0 8bl -- ) ESCE p! pl ;
I 2 on: (8b -- ) Create c, does> (--) ESCc@ep! 1ip!;
I 2 off: ( 8b -- ) Create c, does> (--) ESCcep! Op!;
PRINTER.SCR Scr 4 Dr O0
\ Printer Escapes Epson RX-80/FX-80 12sepö6re
SOF ! ctrl: (+17cpi °$12 } etri: (-17cpi
Ascii P ! esc: (+10cpi Ascii M | esc: (+12cpi
Ascii 9 esc: 1/8" Ascii 1 esc: 1/10”
Ascii 2 esc: 1/6" Ascii T esc: suoff
Ascii N esc: +jump Ascii O esc: -jump
Ascii G esc: +dark Ascii H esc: -dark
\ Ascii 4 esc: +tcursive Ascii 5 esc: -cursive
Ascii W on: +twide Ascii W off: -wide
Ascii - on: +under Ascii - off: -under
Ascii S on: sub Ascii S off: super
PRINTER.SCR Scr 5 Dr 0
\ Printer Escapes Epson RX-80/FX-80 12sep36re
10cpi (-17cpi (+10cpi ; ' 10cpi Alias pica
: 12cpi (-17cpi (+12cpi ; ' 12epi Alias elite
: 17epi (+10cpi (+17cpi ; ' 17cpi Alias small
: lines ( #.of.lines -- ) Ascii C esc2 ;
"long ( inches -- ) oO lines p! ;
american 0 Ascii R esc2 ;
german 2 Ascii R esc2 ;
normal 10cpi american suoff 1/6" &12 "long RET;
von wm Ho
vo=-aurwmHOo
PRrrrr
DWUHO
1:5
(23 SEE weibp/teihs 11-23 Erläuterungen
PRINTER.SCR Scr 18 Dr O0
\ Printer controls 100oct86we
gibt Escape-Sequenzen an den Drucker aus.
gibt Escape und zwei Zeichen aus.
gibt Escape, ein Zeichen und eine 1 an den Drucker aus.
gibt Escape, ein Zeichen und eine O0 an den Drucker aus.
PRINTER.SCR Scr 19 Dr 0
\ Printer Escapes Epson RX-80/FX-80 10loct36we
setzt bzw. löscht Ausgabe komprimierter Schrift.
setzt Zeichenbreite auf 10 bzw. 12 cpi.
Zeilenabstand in Zoll.
schaltet Super- und Subscript ab
Perforation überspringen ein- und ausschalten.
Es folgen die Steuercodes für Fettdruck, Kursivschrift, Breit-
schrift, Unterstreichen, Subscript und Superscript.
Diese müssen ggf. an Ihren Drucker angepaßt werden.
Selbstverständlich können auch weitere Fähigkeiten Ihres Druk-
kers genutzt werden wie Proportionalschrift, NLQ etc.
PRINTER.SCR Scr 20 Dr O0
\ Printer Escapes Epson RX-80/FX-80 130oct86we
Hier wird die Zeichenbreite eingestellt. Dazu kann man sowohl
Worte mit der Anzahl der characters per inch (cpi) als auch
pica, elite und small benutzen.
setzt Anzahl der Zeilen pro Seite; Einstellung:
&66 lines oder &12 "long
schaltet auf amerikanischen Zeichensatz.
schaltet auf deutschen Zeichensatz.
Voreinstellung des Druckers auf 'normale' Werte; wird beim
Einschalten mit PRINT ausgeführt. 5
vosyauıPummr Oo
Von URPWDHO
Perkehe
VBWDErO
vonauPbuwuvHo
Erläuterungen 1I-24 (23 18EE we/bp/rerns
nn EN ERS SF rer un
PRINTER.SCR Scr 6 Dr O
\ Umlaute
I Create DIN
Asciiäc, Ascil 8'c, Ascii Cr Ascii ß c,
Ascii A c, Ascii Ö cc, Ascii Ey Ascii S c,
I Create AMI
Ascii [ c, Ascii | c, Ascii e, Asch "ec;
Ascii [ c, Ascii \c, Ascii €r Ascii @ cc,
here AMI - | Constant tablen
ı ı pl ( char -- ) dup $80 < IF p! exit THEN
tablen 0 DO dup IDIN+c@e =
IF drop I AMI + c@ LEAVE THEN LOOP
german p! american ;
PRINTER.SCR Scr 7 Dr 0
\ Printer Output
| Variable pcol pcol off | Variable prow prow off
I 2 pemit ( 8b -- ) p! 1 pcol +!
I ı per (--) RET LF 1 prow +! pcol off ;
| ı: Bdel_t*=-) DEL pcol @ 1- O0 max pcol ! ;
ı 2 ppage ( -- FF prow off pcol off ;
ı =: Bät { Fow col —= ) over prow @ < IF ppage THEN
0 ?DO pcr LOOP
IF RET pcol off
swap prow @ -
dup pcol ® <
LOOP
| x: pat? ( -- row col ) prow@ pcol @ ;
I: ptype ( adr len -- )
aup pcol +! bounds ?DO TI ce®p!
PRINTER.SCR Scr 8 Dr 0
\ Printer cutput
Output: >printer
Forth definitions
normal ;
: print »printer
pemit pcr ptype pdel ppage pat pat?
l4oct86we
12sep386re
THEN pcol @ - spaces
18nov&ßwe
voUauıBPwmumH Oo
PHRPePrer
UBLWDHO
voSaupbtwmnmHOo
PRerkre
UBWNDHO
von BRWNmDHMO
(23 IREE weibp/re/hs II-25 Erläuterungen
PRINTER.SCR Scr 21 Dr 0
\ Umlaute bp 120ct86
Auf diesem Screen werden die Umlaute aus dem IBM- (ATARI)-Zeichen
satz in DIN-Umlaute aus dem deutschen Zeichensatz gewandelt.
Wenn Sie einen IBM-kompatiblen Drucker benutzen, kann dieser
Screen mit \\ in der ersten Zeile wegkommentiert werden.
p! wird neu definiert. Daher brauchen die folgenden Worte p!
nicht zu ändern, egal, ob mit oder ohne Umlautwandlung gearbei-
tet wird.
PRINTER.SCR Scr 22 Dr O0
\ Printer Output 10oct86we
aktuelle Druckerzeile und -spalte.
Routinen zur Druckerausgabe entspricht Befehl
ein Zeichen auf Drucker emit
CR und LF auf Drucker er
ein Zeichen löschen (?!) del
neue Seite page
Drucker auf Zeile und Spalte at
positionieren; wenn nötig,
neue Seite.
Position feststellen at?
Zeichenkette ausgeben type
Damit sind die Worte für eine eigene Output-Struktur vorhanden.
PRINTER.SCR Scr 23 Dr O
\ Printer output 1l0oct86we
erzeugt die Output-Tabelle >printer.
Die folgenden Worte sind von FORTH aus zugänglich.
schaltet Ausgabe auf Printer um. (Zurückschalten mit DISPLAY)
N
voQIaUuUrumNmHo
VvVOoAUANIABAWDMO
Re.
Erläuterungen 5 II-26 23 1838 werbefrerks
PRINTER.SCR Scr 9 Dr O0
\ Variables and Setup bp 120ct86
Printer definitions
' 0 ı Alias logo
I: header ( pageno -- )
i2cpi “dark - „" volksFORTH-83 FORTH-Gesellschaft eV "
-dark 17cpi ." (c) 1985/86 we/bp/re/ks " 12cpi +tdark
file? -dark 17cpi ." Seite" .;
PRINTER.SCR Scr 10 Dr 0
\ Print 2 screens across on a page 260ct386we
iı : 2lines ( scr#1 scr#2 line# -- )
er dup 2 .r space c/l * >r
pad c/1l 2* 1+ bl fill swap
block r@ + pad c/1l cmove
block r> + pad ce/l + 1+ c/1l cmove
pad c/1l 2* 1+ -trailing type ;
I: 2screens ( scr#1 scr#2 -- )
er cr &30 spaces
+wide +dark over 4 .r &28 spaces dup 4 .r -wide -dark
er 1/s 0 DO 2dup I 2lines LOOP 2drop ;
PRINTER.,SCR Scr 11 Dr 0 m
\ print 6 screens on a page 18sep36we
I x pageprint ( last+1 first pageno -- )
header 2dup - 1+ 2/ dup 0
?DO >r 2dup under r@ + >
IF dup r@ + ELSE logo THEN 2screens 1+ r> LOOP
drop 2drop page ;
Ir >shadow (nf = n2)
capacity 2/ 2dup < IF + ELSE - THEN ;
I: shadowprint ( last+1 first pagsno -- )
header 2dup - 0
?DO dup dup >shadow 2screens 1+ LOOP
2drop page ;
VvoıauumHm Oo
PrRrerre
VBLWLHO
vosauwwmHOo
VvVOoSINUPBPUWDHO
23 1828 we/bp/re/hs II-27 Erläuterungen
PRINTER.SCR Scr 24 Dr 0
\ Variables and Setup 10oct86we
Diese Worte sind nur im Printer-Vokabular enthalten.
Dieser Screen wird gedruckt, wenn es nichts besseres gibt.
Druckt die Überschrift der Seite pageno.
PRINTER.SCR Scr 25 Dr 0
\ Print 2 screens across on a page 10oct36we
druckt nebeneinander die Zeilen line# der beiden Screens.
Die komplette Druck-Zeile wird erst in PAD aufbereitet.
formatierte Ausgabe der beiden Screens nebeneinander
mit fettgedruckten Screennummern. Druck erfolgt mit 17cpi, also
in komprimierter Schrift.
PRINTER.SCR Scr 26 Dr 0
\ print 6 screens on a page l0oct36we
gibt eine Seite aus. Anordnung der Screens auf der Seite: 14
Wenn weniger als 6 Screens vorhanden sind, werden 25
Lücken auf der rechten Seite mit dem Logo-Screen (0) 3%
aufgefüllt.
berechnet zu Screen nl den Shadowscreen n2 (Kommentarscreen wie
dieser hier).
wie pageprint, aber anstelle der Screens 4, 5 und 6 werden die
Shadowscreens zu 1, 2 und 3 gedruckt.
ON ANBRWUDHMO
Hr
Prere
uUBwWvHr
voJanaurwnmH Oo
VvoNSVaUuU wm HO
10
II-28 ic) AFFE weiop/terns
en Scr 12 Dr O0
v
P
\
inting without Shadows bi1nov86we
Forth definitions also
ı Variable printersem 0 printersenm |! \ for multitasking
pthru ( first last -- ) 2 arguments
printersem lock output push print
l1+ capacity umin swap 2dup - 6 /mod swap 0<> - O0
?DO 2dup 6 + min over I 1+ pageprint 6 + LOOP
2drop printersem unlock ;
printall (en) O capacity 1- pthru ;
PRINTER.SCR Scr 13 Dr 0
\ Printing with Shadows bp 120ct86
: document ( first last -- )
printersem lock output push print
1+ capacity 2/ umin swap 2dup - 3 /mod swap 0<> -
?DO 2dup 3+ min over I 1+ shadowprint 3+ LOOP
2drop printersem unlock ;
: listing ( --) 0 capacity 2/ 1- document ;
PRINTER.SCR Scr 14 Dr 0
\ Printerspool
\needs Task NN
$100 $200 Task spooler
spool' (24) \ reads word
isfile@ offset @ base @ spooler depth 1-
base ! offset ! isfile ! execute
true abort" SPOOL' ready for next job!" stop ;
14oct386we
6 min
pass
vVOoSINURLWMHO
voSauibwmH Oo
voaunbwuwhmo
(2) 1222 weibe/re/ks II-29 Erläuterungen
PRINTER.SCR Scr 27 Dr 0
\ Printing without Shadows b220ct86we
Die folgenden Definitionen stellen das Benutzer-Interface dar.
Daher sollen sie in FORTH gefunden werden.
PRINTERSEM ist ein Semaphor für das Multitasking, der den Zugang
auf den Drucker für die einzelnen Tasks regelt.
PTHRU gibt die Screens von from bis to aus.
Ausgabegerät merken und Drucker einschalten. Multitasking wird,
sofern es den Drucker betrifft, gesperrt.
Die Screens werden mit pageprint ausgegeben.
wie oben, jedoch wird das komplette File gedruckt.
PRINTER.SCR Scr 28 Dr O0
\ Printing with Shadows 1l0oct86we
wie pthru, aber mit Shadowscreens.
wie printall, aber mit Shadowscreens.
PRINTER.SCR Scr 29 Dr 0
\ Printerspool 10oct386we
Falls der Multitasker nicht vorhanden ist, wird abgebrochen.
Der Arbeitsbereich der Task wird erzeugt.
Mit diesem Wort wird das Drucken im Hintergrund gestartet.
Aufruf mit :
spool' listing
spool' printail
from to spool' pthru
from to spool' document
Vor (oder auch nach) dem Aufruf von spool' muß der Multitasker
mit multitask eingeschaltet werden.
A ” =
| Erläuterungen E II-30 k2) A8EE weibp/rerks
(23 1326 werbp/re/ks 77-31 Erläuterungen
5) Der Heap
Eine der ungewöhnlichen und fortschrittlichen Konzepte des
volksFORTH83 besteht in der Möglichkeit, Namen von Worten zu
entfernen, ohne den Rumpf zu vernichten.
Das ist insbesondere während der Kompilation nützlich, denn
Namen von Worten, deren Benutzung von der Tastatur aus nicht
sinnvoll wäre, tauchen am Ende der Kompilation auch nicht mehr
im Dictionary auf. Man kann dem Quelltext sofort ansehen, ob
ein Wort für den Gebrauch außerhalb des Programmes bestimmt ist
oder nicht.
Die Namen, die entfernt wurden, verbrauchen natürlich keinen
Speicherplatz mehr. Damit wird die Verwendung von mehr und
längeren Namen und dadurch die Lesbarkeit gefördert.
Namen, die später eliminiert werden sollen, werden durch das
Wort |} gekennzeichnet. Das Wort } muß unmittelbar vor dem
Wort stehen, das den zu eliminierenden Namen erzeugt. Der so
erzeugte Name wird in einem Speicherbereich abgelegt, der Heap
heißt. Der Heap kann später mit dem Wort CLEAR gelöscht
werden. Dann sind natürlich auch alle Namen, die sich im Heap
befanden, verschwunden.
Beispiel: }ı Variable sum
1 sum !
ergibt :
im heap! im Dictionary:
[SuM ] pointer ] code | 8881
v 2
PIPPI
Es werden weitere Worte definiert und dann CLEAR ausgeführt:
: clearsum (--) 0Osum ! ;
: add (n--) sımat+t!;
: show -=) sun@.;
clear
liefert die Worte CLEARSUM ADD SHOW ,„ während der Name SUM
aurch CLEAR entfernt wurde; das Codefeld und der Wert 0001
existieren jedoch noch. (Das Beispiel soll eine Art Taschen-
rechner darstellen.)
Man kann den Heap auch dazu "mißbrauchen”, Code, der nur
zeitweilig benötigt wird, nachher wieder zu entfernen. Der
Assembler wird auf diese Art geladen, so daß er nach Fertig-
stellen der Applikation mit CLEAR wieder entfernt werden kann
und keinen Platz im Speicher mehr benötigt. Schauen Sie bitte
in den Quelltext des Assemblers, um zu sehen, wie man das
macht.
II-32 (23
ag
3
ın
we/bpo/re/ihs
(2? 1925 werbp/terks II=33 Erläuterungen ]
6) Der Multitasker
Das volksFORTH besitzt einen recht einfachen, aber leistungs-
fähigen Multitasker. Er ermöglicht die Konstruktion von
Druckerspoolern, Uhren, Zählern und anderen einfachen Tasks.
Als Beispiel soll gezeigt werden, wie man einen einfachen
Druckerspooler konstruiert. Dieser Spooler ist in verbesserter
Form auch im Quelltext des Multitaskers enthalten, hier wird er
aus didaktischen Gründen möglichst simpel gehalten.
6.1) Anwendungsbeispiel: Ein Kochrezept
Das Programm für einen Druckerspooler lautet:
SFO $100 Task background
: spool background activate 1 100 pthru stop ;
multitask spool
Normalerweise würde PTHRU den Rechner "lahmlegen", bis die
Screens von 1 bis 100 ausgedruckt worden sind. Bei Aufruf von
SPOOL ist das nicht so; der Rechner kann sofort weitere
Eingaben verarbeiten. Damit alles richtig funktioniert, muß
PTHRU allerdings einige Voraussetzungen erfüllen, die dieses
Kapitel erklären will.
Das Wort TASK ist ein definierendes Wort, das eine Task
erzeugt. Die Task besitzt übrigens Userarea, Stack, Returnstack
und Dictionary unabhängig von der sog. Konsolen- oder Main-
Task. Im Beispiel ist $FO die Länge des reservierten Speicher-
bereichs für Returnstack und Userarea, $100 die Länge für Stack
und Dictionary, jeweils in Bytes. Der Name der Task ist in
diesem Fall BACKGROUND. Die neue Task tut nichts, bis sie
aufgeweckt wird. Das geschieht durch das Wort SPOOL .
MULTITASK sagt dem Rechner, daß in Zukunft womöglich noch
andere Tasks außer der Konsolentask auszuführen sind. Es
schaltet also den Taskwechsler ein.
Bei Ausführen von SINGLETASK wird der Taskwechsler abgeschal-
tet. Dann wird nur noch die gerade aktive Task ausgeführt.
Bei Ausführung von SPOOL geschieht nun folgendes:
Die Task BACKGROUND wird aufgeweckt und ihr wird der Code
hinter ACTIVATE (nämlich 1 100 PTHRU STOP ) zur Ausführung
übergeben. Damit ist die Ausführung von SPOOL beendet, es
können jetzt andere Worte eingetippt werden. Die Task jedoch
führt unverdrossen 1 100 PTHRU aus, bis sie damit fertig ist.
Dann stößt sie auf STOP und hält an. Man sagt, die Task
schläft.
Will man die Task während des Druckvorganges anhalten, z.B. um
Papier nachzufüllen, so tippt man BACKGROUND SLEEP ein. Dann
wird BACKGROUND vom Taskwechsler übergangen. Soll es weiter-
gehen, so tippt man BACKGROUND WAKE ein.
| Erläuterungen BE II-34 12) BEE we/bpire/ks
Häufig möchte man erst bei Aufruf von SPOOL den Bereich als
Argument angeben, der ausgedruckt werden soll. Das geht wie
folgt:
: newspool ( from to -- )
2 background pass pthru stop ;
Die Phrase 2 BACKGROUND PASS funktioniert ähnlich wie
BACKGROUND ACTIVATE ,„ jedoch werden der Task auf dem Stack
zusätzlich die beiden obersten Werte ( hier from und to )
übergeben. Um die Screens 1 bis 100 auszudrucken, tippt man
jetzt ein:
1 100 newspool
Es äist klar, daß BACKGROUND ACTIVATE gerade der Phrase 0
BACKGROUND PASS entspricht.
(2) 1828 wesbp/reiks TI-35
6.2) Implementation
Der Unterschied dieses Multitaskers zu herkömmlichen liegt in
seiner kooperativen Struktur begründet. Damit ist gemeint, daß
jede Task explizit die Kontrolle über den Rechner und die
Ein/Ausgabegeräte aufgeben und damit für andere Tasks verfügbar
machen muß. Jede Task kann aber selbst "wählen", wann das
geschieht. Es ist klar, daß das oft genug geschehen muß, damit
alle Tasks ihre Aufgaben wahrnehmen können.
Die Kontrolle über den Rechner wird durch das Wort PAUSE
aufgegeben. PAUSE führt den Code aus, der den gegenwärtigen
Zustand der gerade aktiven Task rettet und die Kontrolle des
Rechners an den Taskwechsler übergibt. Der Zustand einer Task
besteht aus den Werten von Interpreterpointer (IP) ,„ Return-
stackpointer (RP) und des Stackpointers (SP).
Der Taskwechsler besteht aus einer geschlossenen Schleife. Jede
Task enthält einen Maschinencodesprung auf die nächste Task,
gefolgt von der Aufweckprozedur. Beim volksFORTH83 für .den
Atari besteht dieser Sprung aus zwei Befehlen, nämlich "move.w
#next task,d6" und "jmp O(FP,d6)". Zunächst wird also die
Adresse (vom Anfang des Forthsystems aus gerechnet) geladen,
durch den Sprungbefehl wird diese Adresse auf den Anfang des
Speichers umgerechnet und dann auf diese Adresse gesprungen
(mehr zu dieser Umrechnung finden Sie im Kapitel über den
Assembler). Dort befindet sich die entsprechende Instruktion
der nächsten Task. Ist die Task gestoppt, so wird dort
ebenfalls ein Maschinencodesprung zur nächsten Task ausgeführt.
Ist die Task dagegen aktiv, so ist der Sprung durch den Trap #3
ersetzt worden, der die Aufweckprozedur auslöst. Diese Prozedur
lädt den Zustand der Task (bestehend aus SP „a RP und IP) und
setzt den Userpointer (UP), so daß er auf diese Task zeigt
(siehe Bild). 1
Userareas
ne von Task3 +8 I
jinp_(d6) Tasks Task3 + 4
ı.„next task | »% Task3 + 2
»»9»» | move #,,,,d6 % schlafend Task3 + 8
° &
2 DEE GGG GG
29% Per Task2 +8
2% imp_(d6) Task2 + 4
29 1 next task | & Task2 + 2
2 9» trap 3 © aktiv Task2 + 8
o ®
2 BEE EGGGSO
ne inp (6) I
® next task ; >
2,9 ine zZ >08 aktiv Taski + 2
© P Ö Taskl + 0
PETE GEORG
Erläuterungen
cc} jis2E we/ibp/rtrerhz
SINGLETASK ändert nun PAUSE so, daß überhaupt kein Taskwech-
sel stattfindet, wenn PAUSE aufgerufen wird. Das ist in dem
Fall sinnvoll, wenn nur eine Task existiert, nämlich die
Konsolentask, die beim Kaltstart des Systems "erzeugt" wurde.
Dann würde PAUSE unnötig Zeit damit verbrauchen, einen
Taskwechsel auszuführen, der sowieso wieder auf dieselbe Task
führt. STOP entspricht PAUSE ,„ jedoch mit dem Unterschied,
daß die leere Anweisung durch einen Sprungbefehl ersetzt wird.
Das System unterstützt den Multitasker, indem es während vieler
Ein/Ausgabeoperationen wie KEY „a TYPE und BLOCK usw. PAUSE
ausführt. Häufig reicht das schon aus, damit eine Task (z.B.
der Druckerspooler) gleichmäßig arbeitet.
Tasks werden im Dictionary der Konsolentask erzeugt. Jede
besitzt ihre eigene Userarea mit einer Kopie der Uservariablen.
Die Implementation des Systens wird aber durch die Einchränkung
vereinfacht, daß nur die Konsolentask Eingabetext interpretie-
ren bzw. kompilieren kann. Es gibt z.B. nur eine Suchreihen-
folge, die im Prinzip für alle Tasks gilt. Da aber nur die
Konsolentask von ihr Gebrauch macht, ist das nicht weiter
störend.
Es ist übrigens möglich, aktive Tasks mit FORGET usw. zu
vergessen. Das ist eine Eigenschaft, die nicht viele Systeme
aufweisen! Allerdings geht das manchmal auch schief... Nämlich
dann, wenn die vergessene Task einen "Semaphor" (s.u.) besaß.
Der wird beim Vergessen nämlich nicht freigegeben und damit ist
das zugehörige Gerät blockiert.
Schließlich sollte man noch erwähnen, daß beim Ausführen eines
Tasknamens der Beginn der Userarea dieser Task auf dem Stack
hinterlassen wird.
FORTE
Kz
>
IS2E we/bp/re/ts
| Speicherbelegung einer Task _]
r8 8
rp@
upe
heap
sd 8
spe
here
Returnstack | ©
&
frei
Q rien
Userarea &
Heap o
unbenutzt
Stack
5 slen
tra}
Q
Dictionary G
Erläuterungen
Erläuterungen
linit ® Buffer
Buffer
Buffer
first ßB unbenutzt
r8 ®
Returnstack ?
rp® Ö
{rei
rlen
Userarea 8
up® o
Heap
heap Stack-Underflow
8 8
Stack
spe 8
Frei
Q slen
here
Dictionary
Boot-Area 8
erigin
11-38
Ko
> IREE
Memory Map des volksFORTH83
Code for GEMDIS
we/bp/rte/hs
(2) 1328 werbp/teihs 17-39 Erläuterungen
6.3) Semaphore und "Lock"
Ein Problem, daß bisher noch nicht erwähnt wurde, ist: Was
passiert, wenn zwei Tasks gleichzeitig drucken (oder Daten von
der Diskette lesen) wollen?
Es ist klar: Um ein Durcheinander oder Fehler zu vermeiden,
darf das immer nur eine Task zur Zeit.
Programmtechnisch wird das Problem durch "Semaphore" gelöst:
Create disp 0 „,
: newtype disp lock type disp unlock;
Der Effekt ist der folgende:
Wenn zwei Tasks gleichzeitig NEWTYPE ausführen, so kann doch
nur eine zur Zeit TYPE ausführen, unabhängig davon, wie viele
PAUSE in TYPE enthalten sind. Die Phrase DISP LOCK schal-
tet nämlich hinter der ersten Task, die sie ausführt, die
"Ampel auf rot" und läßt keine andere Task durch. Die anderen
machen solange PAUSE ,„ bis die erste Task die Ampel mit DISP
UNLOCK wieder auf grün umschaltet. Dann kann eine (!) andere
Task die Ampel hinter sich umschalten usw. .
Übrigens wird die Task, die die Ampel auf rot schaltete, bei
DISP LOCK nicht aufgehalten, sondern durchgelassen. Das ist
notwendig, da ja TYPE ebenfalls DISP LOCK enthalten könnte
(Im obigen Beispiel natürlich nicht, aber es ist denkbar) .
Die Implementation sieht nun folgendermaßen aus:
( Man muß sich noch vor Augen halten, daß jede Task
eindeutig durch den Anfang ihrer Userarea identifi-
zierbar ist. )
DISP ist ein sog. Semaphor; er muß den Anfangswert 0
haben!
LOCK schaut sich nun den Semaphor an:
Ist er Null, so wird die gerade aktive Task (bzw. der
Anfang ihrer Userarea) in den Semaphor eingetragen und
die Task darf weitermarschieren.
Ist der Wert des Semaphors gerade die aktive Task, so
darf sie natürlich auch weiter.
Wenn aber der Wert des Semaphors von dem Anfang der
Userarea der aktiven Task abweicht, dann ist gerade
eine andere Task hinter der Ampel aktiv und die Task
muß solange PAUSE machen, bis die Ampel wieder grün,
d.h. der Semaphor null ist.
UNLOCK muß nun nichts anderes mehr tun, als den Wert des
Semaphors wieder auf Null setzen.
BLOCK und BUFFER sind übrigens auf diese Weise für die
Benutzung durch mehrere Tasks gesichert: Es kann immer nur eine
Task das Laden von Blöcken von der Diskette veranlassen.
Ob TYPE ,Ä EMIT usw. ebenfalls gesichert sind, hängt von der
Implementation ab. i
II-40 c:
>
r0
N
ın
we/bp/re/ihs
n
6.4) Eine Bemerkung bzgl. BLOCK und anderer Dinge
Wie man dem Glossar entnehmen kann, ist immer nur die Adresse
des zuletzt mit BLOCK oder BUFFER angeforderten Blockpuf-
fers gültig, d.h. ältere Blöcke sind, je nach der Zahl der
Blockpuffer, womöglich schon wieder auf die Diskette ausgela-
gert worden. Auf der sicheren Seite liegt man, wenn man sich
vorstellt, daß nur ein Blockpuffer im gesamten System
existiert.
Nun kann jede Task BLOCK ausführen und damit anderen Tasks
die Blöcke "unter den Füßen" wegnehmen. Daher sollte man nicht
die Adresse eines Blocks nach einem Wort, das PAUSE ausführt,
weiter benutzen, sondern lieber neu mit BLOCK anfordern. Ein
Beispiel:
: .line ( block -- )
block c/l bounds DO I c@ emit LOOP ;
ist FALSCH, denn nach EMIT stimmt der Adressbereich, den der
Schleifenindex überstreicht, womöglich gar nicht mehr.
= „iinen: ( block=--i))
c/1 0 DO dup block I + c@ emit LOOP drop :
ist RICHTIG, denn es wird nur die Nummer des Blocks, nicht die
Adresse seines Puffers aufbewahrt.
: .line ( block -- ) block c/1l type ;
ist FALSCH, da TYPE ja EMIT wiederholt ausführen kann und
somit die von BLOCK gelieferte Adresse in TYPE ungültig
wird.
: >type ( adr len -- ) >r pad r@ cmove pad r> type ;
: .line ( block -- ) block c/i >type ;
ist RICHTIG, denn PAD ist für jeden Task verschieden.
(2) iBEE weibp/re/ks II-41 Erläuterungen
7) Debugging - Techniken
Fehlersuche ist in allen Programmiersprachen die aufwendigste
Aufgabe des Programmierers.
Für verschiedene Programme sind in der Regel auch verschiedene
Hilfsmittel erforderlich. Daher kann dieses Kapitel die Fehler-
suche nicht erschöpfend behandeln. Da aber Anfänger häufig
typische Fehler machen, kann man gerade für diese Gruppe
brauchbare Hilfsmittel angeben.
7.1) Voraussetzungen für die Fehlersuche
Voraussetzung für die Fehlersuche ist immer ein übersichtliches
und verständliches Programm. In Forth bedeutet das :
-) suggestive und prägnante Namen für Worte
-) starke Faktorisierung, d.h. sinnvoll zusammengehörende
Teile eines Wortes sind zu einem eigenen Wort zusam-
mengefaßt. Worte sollten durchschnittlich nicht länger
als 2 - 3 Zeilen lang sein !
-) Übergabe von Parametern auf dem Stack statt in Variab-
len, überall wo das möglich ist.
Guter Stil in Forth ist nicht schwer, erleichtert aber sehr die
Fehlersuche. Ein Buch, das auch diesen Aspekt behandelt, sei
unbedingt empfohlen :
"Thinking Forth" von Leo Brodie, Prentice Hall 1984,
Sind diese Bedingungen erfüllt, ist es meist möglich, die Worte
interaktiv zu testen. Damit ist gemeint, daß man bestimmte
Parameter auf dem Stack versammelt und anschließend das zu
testende Wort aufruft. Anhand der abgelieferten Werte auf dem
Stack kann man dann beurteilen, ob das Wort korrekt arbeitet.
Sinnvollerweise testet man natürlich die zuerst definierten
Worte auch zuerst, denn ein Wort, das fehlerhafte Worte
aufruft, funktioniert natürlich nicht korrekt.
Wenn nun ein Wort auf diese Weise als fehlerhaft identifiziert
wurde, muß man das Geschehen innerhalb des Wortes verfolgen.
Das geschieht meist durch "tracen".
II-42 (23 ==
W
ın
weibe/rerhz
7.2) Der Tracer
Angenommen, Sie wollen folgendes Wort auf Fehler untersuchen:
(bitte tippen Sie ein, alle nötigen Eingaben sind fett und alle
Ausgaben des volksFORTH83 sind unterstrichen dargestellt.)
: -trailing ( addri nl -- addri n2 ) __compiling
2dup bounds ?DO 2dup + 1- c@ bl = _compiling
IF LEAVE THEN 1- LOOP ; ok
Die Funktion dieses Wortes können Sie, wenn sie Ihnen unklar
ist, dem Glossar entnehmen. Zum Testen des Wortes wird ein
String benötigt. Sie definieren:
Create teststring ‚„"” Dies ist ein Test "ok
wobei Sie bitte absichtlich einige zusätzliche Leerzeichen
eingefügt haben. Sie geben nun ein :
teststring count .s_16 7E39 ok
-trailing .s_16 7E39 _ok
und stellen zu Ihrem Erstaunen fest, daß -TRAILING kein
einziges Leerzeichen abgeschnitten hat. (Spätestens jetzt soll-
ten Sie am Rechner sitzen und den Tracer laden, wenn er noch
nicht im System vorhanden ist. Prüfen Sie, ob es das Wort DEBUG
im FORTH Vokabular gibt, dann ist der Tracer vorhanden. Der
Tracer gehört zu den sogenannten Tools. Die Quelltexte finden
Sie auf Ihrer Diskette ).
Mit dem Tracer können Sie Worte, die mit dem : definiert
wurden, schrittweise testen. Um den Tracer zu benutzen, geben
Sie folgendes ein:
debug <namel> __ok
Hierbei ist <nameil> das zu tracende Wort. Zunächst geschieht
noch gar nichts. DEBUG hat nur den Tracer "scharf gemacht".
Geben Sie nun eine Sequenz ein, die <namel> enthält, unter-
bricht der Tracer die Ausführung, wenn er auf <namel> stößt. Es
erscheint folgendes Bild.
addri addr2 <name2> (Werte)
Hierbei ist addrl eine Adresse im Parameterfeld von <namel>,
nämlich die, in der addr2 steht. addr2 ist die Kompilations-
Adresse von <name2>. <name2> ist das Wort, das als nächstes
ausgeführt werden soll. (Werte) sind die Werte, die gerade auf
dem Stack liegen.
ic} 1328 wei/icp/refrz 1IT-43
Erläuterungen )
Bleiben wir bei unserem Beispiel, Sie geben ein:
debug -trailing _ok
Es geschieht zunächst nichts.
Nun versuchen Sie es wieder mit der Sequenz
teststring count .s_16 7E39 ok
-trailing
und erhalten folgendes Bild:
7E04 536 __2DUP 16_7E39
16 7E39 ist der Stackinhalt, wie er von TESTSTRING COUNT
geliefert wurde, nämlich Adresse und Länge des Strings
TESTSTRING .
Natürlich können die Zahlen bei Ihnen anders aussehen, je
nachdem, wohin TESTSTRING und -TRAILING kompiliert wurde.
536 ist die Kompilationsadresse von 2DUP ,„ T7EO4 die Position
von 2DUP in -TRAILING . (Auch diese Adressen können sich
geändert haben!) Diese Zahlen werden mit ausgegeben, so daß
auch im Falle mehrerer Worte mit gleichem Namen eine Identifi-
zierung möglich ist.
Drücken Sie jetzt so lange <Return>, bis OK erscheint.
Insgesamt wird dabei folgendes ausgegeben :
debug -trailing teststring count .s_16 7E39 ok
-trailing
7E0O4 536 _2DUP 16_7E39
7EO6 954 BOUNDS 16 7E39 16 7E39
7E08 _92C__(?DO 7E39 TE4F 16 7E39
7EOC 536 _2DUP 16 7E39
7EOE 546 _ + 16 7E39 16 7E39
7E1O__64C 1- TEA4F 16 7E39
TEl2 _34E _C@ TE4E 16 7E39
7E14 215C__BL 20 16 7E39
7El6 _816 = 20 20 16 7E39
7E18 _AOC _?BRANCH FFFF_16 7E39
7EIC _BE2 LEAVE 16_7E39
7E24 2F4A UNNEST 16 _7E39 ok
Sehen wir uns die Ausgabe nun etwas genauer an. Bei den ersten
beiden Zeilen wächst der Wert ganz links immer um 2. Es ist der
Inhalt des Instructionpointers (IP), der immer auf die nächste
auszuführende Adresse zeigt. Der Inhalt dieser Adresse ist
jeweils eine Kompilationsadresse ( 536 bei 2DUP usw.). Jede
Kompilationsadresse benötigt zwei Bytes, daher muß der IP immer
um 2 erhöht werden.
II-44 c
> 1m:
n
ın
weribp/re/ihz
Immer? Nein, denn schon die nächste Zeile zeigt eine Ausnahme.
Das Wort (?DO erhöht den IP um 4 ! Woher kommt eigentlich
(?DoO ,„ in der Definition von -TRAILING stand doch nur ?DO .
(?DO ist ein von ?DO kompiliertes Wort, das zusätzlich zur
Kompilationsadresse noch einen 16-Bit-Wert benötigt, nämlich
für den Sprungoffset hinter LOOP, wenn die Schleife beendet
ist. Zwei ähnliche Fälle treten noch auf. Das IF aus dem
Quelltext hat ein ?BRANCH kompiliert. Es wird gesprungen,
wenn der oberste Stackwert FALSE ( = 0) ist. Auch ?BRANCH
benötigt einen zusätzlichen 16-Bit-Wert für den Sprungoffset.
Nach LEAVE geht es hinter LOOP weiter, es wird UNNEST
ausgeführt, das vom ; win -TRAILING kompiliert wurde und das
gleiche wie EXIT bewirkt, und damit ist das Wort -TRAILING auch
beendet. Das hier gelistete Wort UNNEST ist nicht zu verwech-
seln mit dem UNNEST des Tracers (siehe unten).
Wo liegt nun der Fehler in unserer Definition von -TRAILING ?
Bevor Sie weiterlesen, sollten Sie die Fehlerbeschreibung, den
Tracelauf und Ihre Vorstellung von der korrekten Arbeitsweise
des Wortes noch einmal unter die Lupe nehmen.
Der Stack ist vor und nach -TRAILING gleich geblieben, die
Länge des Strings also nicht verändert worden. Offensichtlich
wird die Schleife gleich beim ersten Mal verlassen, obwohl das
letzte Zeichen des Textes ein Leerzeichen war. Die Schleife
hätte also eigentlich mit dem vorletzten Zeichen weiter machen
müssen. Mit anderen Worten:
Die Abbruchbedingung in der Schleife ist falsch. Sie ist genau
verkehrt herum gewählt. Ersetzt man = durch = NOT oder -,
so funktioniert das Wort korrekt. Überlegen Sie bitte, warum -
statt = NOT eingesetzt werden kann. (Tip: der IF -Zweig wird
nicht ausgeführt, wenn der oberste Stackwert FALSE (also = 0)
ist.)
Der volksFORTH83-Tracer gestattet es, jederzeit Befehle einzu-
geben, die vor dem Abarbeiten des nächsten Trace-Kommandos
ausgeführt werden. Damit kann man zZ. B. Stack-Werte verändern
oder das Tracen abbrechen. Ändern Sie probehalber beim nächsten
Trace-Lauf von -TRAILING das TRUE-Flag (SFFFF) auf dem Stack
vor der Ausführung von ?BRANCH durch Eingabe von NOT auf 0
und verfolgen Sie den weiteren Trace-Lauf. Sie werden bemerken,
daß die LOOP ein zweites Mal durchlaufen wird.
wollen Sie das Tracen und die weitere Ausführung des getraceten
Wortes abbrechen, so geben Sie RESTART ein. RESTART führt
einen Warm-Start des FORTH-Systems aus und schaltet den Tracer
ab. RESTART ist auch die Katastrophen-Notbremse, die man
einsetzt, wenn man sieht, daß das System mit dem nächsten
Befehl zwangsläufig im Computer-Nirwana entschwinden wird.
Nützlich ist auch die Möglichkeit, das Wort, das als nächstes
-
nn
w
SEE weibe/re/hs II-45 Erläuterungen
zur Ausführung ansteht, solange zu tracen, bis es ins
aufrufende Wort zurückkehrt. Dafür ist das Wort NEST
vorgesehen. Wollen Sie also wissen, was BOUNDS macht, so geben
Sie bitte, wenn BOUNDS als nächstes auszuführendes Wort
angezeigt wird, NEST ein und Sie erhalten dann:
1E04 536 _2DUP 16 7E39
7EO6 _954__BOUNDS 16 7E39 16 7E39 nest
956 44C OVER 16 7E39 16 7E39
958 546 + 7E39 16 7E39 16 7E39
95A__40A__SWAP 7E4F 7E39 16 7539
95C _2F4 _UNNEST 71639 TE4F 16 7E39
7EO8 _92C _(?DO 7E39 T7EAF 16 7E39
Beachten Sie bitte, daß die Zeilen jetzt eingerückt dargestellt
werden, bis der Tracer automatisch in das aufrufende Wort
zurückkehrt. Der Gebrauch von NEST ist nur dadurch einge-
schränkt, daß sich einige Worte, die den Return-Stack manipu-
lieren, mit NEST nicht tracen lassen, da der Tracer selbst
Gebrauch vom Return-Stack macht. Auf solche Worte muß man den
Tracer mit DEBUG ansetzen.
Wollen Sie das Tracen eines Wortes beenden, ohne die Ausführung
des Wortes abzubrechen, so benutzen Sie UNNEST . (Ist der
Tracer geladen, so kommen Sie an das tief im System steckende
UNNEST, einem Synonym für EXIT, das ausschließlich vom “
kompiliert wird, nicht mehr heran und benutzen statt dessen das
Tracer-UNNEST, das Sie eine Ebene im Trace-Lauf zurückbringt.)
Manchmal hat man in einem Wort vorkommende Schleifen beim
ersten Durchlauf als korrekt erkannt und möchte diese nicht
weiter tracen. Das kann sowohl bei DO...LOOPs der Fall sein als
auch bei Konstruktionen mit BEGIN...WHILE...REPEAT oder
BEGIN...UNTIL. In diesen Fällen gibt man am Ende der Schleife
das Wort ENDLOOP ein. Die Schleife wird dann in Echtzeit
abgearbeitet und der Tracer meldet sich erst wieder, wenn er
nach dem Wort angekommen ist, bei dem ENDLOOP eingegeben
wurde.
Haben Sie den Fehler gefunden und wollen deshalb nicht mehr
tracen, so müssen Sie nach dem Ende des Tracens END-TRACE oder
jederzeit RESTART eingeben, ansonsten bleibt der Tracer
"scharf", was zu merkwürdigen Erscheinungen führen kann; außer-
dem verringert sich bei eingeschaltetem Tracer die Laufzeit des
Systens.
Der Tracer läßt sich auch mit dem Wort TRACE' starten, das
seinerseits ein zu tracendes Forth-Wort erwartet. Sie könnten
also auch im obigen Beispiel eingeben:
teststring count trace' -trailing
und hätten damit dieselbe Wirkung erzielt. TRACE' schaltet aber
im Gegensatz zu DEBUG nach Durchlauf des Wortes den Tracer
automatisch mit END-TRACE wieder ab.
II-46 (23 1R2E We/ibp/re/ks
if H
Beachten Sie bitte auch, daß die Worte DEBUG und TRACE' das
Vokabular TOOLS mit in die Suchreihenfolge aufnehmen. Sie
sollten also nach - hoffentlich erfolgreichem - Tracelauf die
Suchordnung wieder umschalten,
Wenn man sich eingearbeitet hat, ist der Tracer ein wirklich
verblüffendes Werkzeug, mit dem man sehr viele Fehler schnell
finden kann. Er ist gleichsam ein Mikroskop, mit dem man sehr
tief ins Innere von Forth schauen kann.
(23 1228 we/ibp/re/ks II-47
Erläuterungen E|
7.3) Stacksicherheit
Anfänger neigen häufig dazu, Fehler bei der Stackmanipulation
zu machen. Erschwerend kommt häufig hinzu, daß sie viel zu
lange Worte schreiben, in denen es dann von unübersichtlichen
Stackmanipulationen nur so wimmelt. Es gibt einige Worte, die
sehr einfach sind und Fehler bei der Stackmanipulation früh
erkennen helfen. Denn leider führen schwerwiegende Stackfehler
zu "mysteriösen" Systemcrashs.
In Schleifen führt ein nicht ausgeglichener Stack oft zu
solchen Fehlern. Während der Testphase eines Programms oder
Wortes sollte man daher bei jedem Schleifendurchlauf prüfen, ob
der Stack evtl. über- oder leerläuft.
Das geschieht durch Eintippen von :
LOOP compile ?stack [compile] LOOP ; immediate restrict
+LOOP compile ?stack [compile] +LOOP ; immediate restrict
UNTIL compile ?stack [compile] UNTIL ; immediate restrict
REPEAT compile ?stack [compile] REPEAT ; immediate restrict
a : compile ?stack ;
Versuchen Sie ruhig, herauszufinden wie die letzte Definition
£unktioniert. Es ist nicht kompliziert.
Durch diese Worte bekommt man sehr schnell mitgeteilt, wann ein
Fehler auftrat. Es erscheint dann die Fehlermeldung :
<name> stack full
wobei <name> der zuletzt vom Terminal eingegebene Nane ist.
Wenn man nun überhaupt keine Ahnung hat, wo der Fehler auftrat,
so gebe man ein :
: unravel rdrop rdrop rdrop \ delete errorhandler-nest
er ."” trace dump on abort is :" cr
BEGIN rp@e r0e@e- \ until stack empty
WHILE r> dup 8 u.r space
2- @ >name .name cr REPEAT
(error ;
unravel errorhandler !
Sie bekommen dann bei Eingabe von
120 %*/
ungefähr folgenden Ausdruck :
Erläuterungen i II-48 ic) IBEE weibp/te/ks
trace dump on abort is:
4678 M/MOD
4692 */MOD
9248 EXECUTE
10060 INTERPRET
10104 'QUIT/ division overflow
'QUIT INTERPRET und EXECUTE rühren vom Textinterpreter her.
Interessant wird es bei */MOD . Wir wissen nämlich, daß */MOD
von */ aufgerufen wird. */MOD ruft nun wieder M/MOD auf,
in M/MOD gehts weiter nach UM/MOD . Dieses Wort ist in Code
geschrieben und "verursachte" den Fehler, indem es eine Divi-
sion durch Null ausführte.
Nicht immer treten Fehler in Schleifen auf. Es kann auch der
Fall sein, daß ein Wort zu wenig Argumente auf dem Stack
vorfindet, weniger nämlich, als Sie für dieses Wort vorgesehen
haben. Diesen Fall sichert ARGUMENTS .
Die Definition dieses Wortes ist:
: ARGUMENTS [nn Sys
depth 1- < abort"” not enough arguments"” ;
Es wird folgendermaßen benutzt:
: -trailing ( adr len -- ) 2 arguments ...:;
wobei die drei Punkte den Rest des Quelltextes andeuten sollen.
Findet -TRAILING nun weniger als zwei Werte auf dem Stack
vor, so wird eine Fehlermeldung ausgegeben. Natürlich kann man
damit nicht prüfen, ob die Werte auf dem Stack wirklich für
-TRAILING bestimmt waren.
Sind Sie als Programmierer sicher, daß an einer bestimmten
Stelle im Programm eine bestimmte Anzahl von Werten auf dem
Stack liegt, so können Sie das ebenfalls sicherstellen:
: is-depth ( n -- ) depth 1- - abort” wrong depth” ;
IS-DEPTH bricht das Programm ab, wenn die Zahl der Werte auf
dem Stack nicht n ist, wobei n natürlich nicht mitgezählt
wird. Es wird analog zu ARGUMENTS benutzt.
Mit diesen Worten lassen sich Stackfehler oft feststellen und
lokalisieren.
{2} 1528 weibp/refhs II-49
Erläuterungen |
7.4) Aufrufgeschichte
Möchte man wissen, was geschah, bevor ein Fehler auftrat und
nicht nur, wo er auftrat (denn nur diese Information liefert
UNRAVEL), so kann man einen modifizierten Tracer verwenden, bei
dem man nicht nach jeder Zeile <RETURN> drücken muß:
Does> cr rdepth 2* spaces
dup 2- >name .name >r;
Hierbei wird ein neues Wort mit dem Namen & definiert,
das
zunächst das alte Wort s aufruft und so ein Wort im
Dictionary erzeugt. Das Laufzeitverhalten dieses Wortes wird
aber so geändert, daß es sich jedesmal wieder ausdruckt, wenn
es aufgerufen wird. Alle Worte, die nach der Redefinition (so
nennt man das erneute Definieren eines schon bekannten Wortes)
des : definiert wurden, weisen dieses Verhalten auf.
Beispiel :
a
: rechne ( --n) 123//;
r
RECHNE
Mi
/ RECHNE division overflow
wir sehen also, daß erst bei der zweiten Division der Fehler
auftrat. Das ist auch logisch, denn 2 3 / ergibt 0
Sie sind sicher in der Lage, die Grundidee dieses zweiten
Tracers zu verfeinern. Ideen wären z.B. :
°
Ausgabe der Werte auf dem Stack bei Aufruf eines Wortes
Die Möglichkeit, Teile eines Tracelaufs komfortabel zu
unterdrücken.
| Erläuterungen ; II-50 (23 1826 werbpfterhs
7.5) Speicherdump
Ein Dump des Speichers benötigt man beim Programmieren sehr
oft, mindestens dann, wenn man eigene Datenstrukturen anschauen
will. Oft ist es dann hinderlich, eigene Worte zur (womöglich
gar formatierten) Ausgabe der Datenstrukturen schreiben zu
müssen. In diesen Fällen benötigt man ein Wort, das einen
Speicherdump ausgibt. Das volksFORTH besitzt zwei Worte zum
Dumpen von Speicherblöcken sowie einen Dekompiler, der auch für
Datenstrukturen verwendet werden kann.
DUMP (addrn -- )
Ab addr werden n Bytes formatiert ausgegeben. Dabei steht am
Anfang einer Zeile die Adresse (abgerundet auf das nächste
Vielfache von $10) ,„ dann folgen 16 Byte, in der Mitte zur
besseren Übersicht getrennt und dann die Ascii-Darstellung.
Dabei werden nur Zeichen im Bereich zwischen $20 und S$T7F
ausgegeben, alle anderen Werte werden als Punkt angezeigt. Die
Ausgabe läßt sich jederzeit mit einer beliebigen Taste unter-
brechen oder mit <Esc> abbrechen. Mit PRINT 1äßt sich die
Ausgabe auf einen Drucker umleiten. Beispiel:
print pad 40 dump display
Das abschließende DISPLAY sorgt dafür, daß wieder der Bild-
schirm als Ausgabegerät gesetzt wird.
Möchte man Speicherbereich außerhalb des FORTH-Systems dumpen,
gibt es dafür das Wort
LDUMP ( laddär n -- )
laddr muß eine - doppelt lange - absolute Speicheradresse sein,
n gibt wie oben die Anzahl der Bytes an. Da das FORTH-Systen
immer im sogenannten Supervisormodus arbeitet, können alle
Speicherbereiche einschließlich der Trap-Vektoren usw. ange-
zeigt werden. Die Ausgabe auf einen Drucker geschieht genau so
wie oben beschrieben.
{23 1322 werbp/re/ks II-51 Erläuterungen
7.6) Der Dekompiler
Ein Dekompiler gehört so zu sagen zum guten Ton eines FORTH-
Systens, war er bisher doch die einzige Möglichkeit, wenigstens
ungefähr den Aufbau eines Systems zu durchschauen. Bei volks-
FORTH-83 ist das anders, und zwar aus zwei Gründen:
-) Sie haben sämtliche Quelltexte vorliegen, und es gibt
die VIEW-Funktion. Letztere ist normalerweise sinn-
voller als der beste Dekompiler, da kein Dekompiler in
der Lage ist, z.B. Stackkommentare zu rekonstruieren.
-) Der Tracer ist beim Debugging sehr viel hilfreicher
als ein Dekompiler, da er auch die Verarbeitung von
Stackwerten erkennen läßt. Damit sind Fehler leicht
aufzufinden.
Dennoch gibt es natürlich auch im volksFORTH einen Dekompiler,
allerdings in einfacher, von Hand zu bedienender, Form. Er
befindet sich, wie der Tracer, im Vokabular TOOLS. Folgende
Worte stehen zur Verfügung.
N (name) ( addr -- addr' )
druckt den Namen des bei addr kompilierten Wortes aus und
setzt addr auf das nächste Wort.
K (konstante) ( addr -- addr' )
wird nach LIT benutzt und druckt den Inhalt von addr als
Zahl aus. Es wird also nicht versucht, den Inhalt, wie bei
N, als Forthwort zu interpretieren.
Ss (string) ( addär -- addr' )
wird nach (ABORT" (" (." und allen anderen Worten
benutzt, auf die ein String folgt. Der String wird
ausgedruckt und addr entsprechend erhöht, sodaß sie hinter
den String zeigt.
€ (character) ( addr -- addr' )
druckt den Inhalt von addr als Ascii-Zeichen aus und geht
ein Byte weiter. Damit kann man eigene Datenstrukturen
ansehen.
B (branch) ( addr -- addr' )
wird nach BRANCH oder ?BRANCH benutzt und druckt den
Inhalt einer Adresse als Sprungoffset und Sprungziel aus.
D (dump) ( addr n -- addr' )
Dumped n Bytes. Wird benutzt, um selbstdefinierte Daten-
strukturen anzusehen. (s.a. DUMP und LDUMP)
Sehen wir uns nun ein Beispiel zur Benutzung des Dekompilers
an. Geben Sie bitte folgende Definition ein:
: test (nn)
12 = IF cr ." Die Zahl ist zwölf !" THEN ;
r
11-52 (23 SEE weibp/te/ks
Erläuterungen
FÜRTH
Rufen Sie das Vokabular TOOLS - durch Nennen seines Namens auf
und ermitteln Sie die Adresse des ersten in TEST kompilierten
Wortes:
' test >body
Jetzt können Sie TEST nach folgendem Muster dekompilieren
n A988: B54 LIT ok
k AY8A: 12 _ok
n A98C: c52 = _ ok
n A98E: E74 _?TBRANCH ok
b A990: 1A AYAA ok
n A992: 32BC_CR ok
n A994; 1776 („". oX
s A996: 12 Die Zahl ist zwölf _ok
n AY9A: 416 UNNEST
drop
Die erste Adresse ist die, an der im Wort TEST die anderen
Worte kompiliert sind. Die zweite ist jeweils die Kompilations-
adresse der Worte, danach folgen die sonstigen Ausgaben des
Dekompilers.
Probieren Sie dieses Beispiel auch mit dem Tracer aus:
20 trace! test
und achten Sie auf die Unterschiede. Sie werden sehen, daß der
Tracer aussagefähiger und dazu noch einfacher zu bedienen ist.
Wenn Sie sich die Ratschläge und Tips zu Herzen genommen haben
und noch etwas den Umgang mit den Hilfsmitteln üben, werden Sie
sich sicher nicht mehr vorstellen können, wie Sie jemals in
anderen Sprachen ohne diese Hilfsmittel ausgekommen sind.
Bedenken Sie bitte auch : Diese Mittel sind kein Heiligtum ;
oft wird Sie eine Modifikation schneller zum Ziel führen.
Scheuen Sie sich nicht, sich vor dem Bearbeiten einer umfang-
reichen Aufgabe erst die geeigneten Hilfsmittel zu verschaffen.
er
wolhzEl co» 1828 we
/bp/rer/ks E |
input!
blossar
forth-53
debug Treate
Use
list
Code
and
Variable
or exit
IF sp0
THEN
-trailing
drop , Does}
dig
Mmultitask
D
> “needs
core?
we/bp/re/ns
ke
(2) BEE weibp/re/ks IEL-1 Glossar El
Notation
Die Worte des volksFORTH83 sind in Wortgruppen zusammengefasst.
Die Worte jeder Wortgruppe sind alphabetisch sortiert. Die
Wortgruppen sind nicht geordnet.
Worte werden in der in Kapitel 1 angegeben Schreibweise
aufgeführt. Wortnamen im Text werden gross geschrieben.
Die Wirkung des Wortes auf den Stack wird in Klammern angegeben
und zwar in folgender Form:
( vorher -- nachher )
vorher : Werte auf dem Stack vor Ausführung des Wortes
nachher : Werte auf dem Stack nach Ausführung des Wortes
In dieser Notation wird das oberste Element des Stacks immer
ganz rechts geschrieben. Sofern nicht anders angegeben, bezie-
hen sich alle Stacknotationen auf die spätere Ausführung des
Wortes. Bei immediate Worten wird auch die Auswirkung des
Wortes auf den Stack während der Kompilierung angegeben.
Worte werden ferner durch folgende Symbole gekennzeichnet:
E
Dieses Wort kann nur während der Kompilation einer :-
Definition benutzt werden.
I
Dieses Wort ist ein immediate Wort, das auch im kompi-
lierenden Zustand ausgeführt wird.
83
Dieses Wort wird im 83-Standard definiert und muß auf
allen Standardsystemen äquivalent funktionieren.
U
Kennzeichnet eine Uservariable.
Weicht die Aussprache eines Wortes von der natürlichen engli-
schen Aussprache ab, so wird sie in Anführungszeichen angege-
ben. Gelegentlich folgt auch eine deutsche Übersetzung.
Die Namen der Stackparameter folgen, sofern nicht suggestive
Bezeichnungen gewählt wurden, dem nachstehendem Schema. Die
Bezeichnungen können mit einer nachfolgenden Ziffer versehen
sein.
III-2 er 1228
w
vs
n
we/bp/irerhz
Stack- Zahlentyp Wertebereich minimale
not. in Dezimal Feldbreite
£lag logischer Wert O=falsch, sonst=true 16 Bit
true logischer Wert -1 (als Ergebnis) 16
false logischer Wert 0 16
b Bit 0.1 %
char Zeichen 0..127 (0..256) 7
8b 8 beliebige Bits nicht anwendbar 8
16b 16 beliebige Bits nicht anwendbar 16
n' Zahl, bewertete Bits -32768..32767 16
+n positive Zahl 0..32767 16
u vorzeichenlose Zahl 0..65535 16
W Zahl, n oder u -32768..65535 16
addr Adresse, wie u 0..65535 16
32b 32 beliebige Bits nicht anwendbar 32
d doppelt genaue Zahl -2,147,483,648... 323
2,147,483,647
+d pos. doppelte Zahl 0..2,147,483,647 32
ud vorzeichenlose 0..4,294,967,295 32
doppelt genaue Zahl "
sys 0, 1 oder mehr na nicht
System-abhängige anwendbar
Werte
(2) 328 weibp/re/ks III-3 Glossar
*/mod
/mod
Arithmetik
{wi w2 -- w2 ) 83 " times"
Der Wert wi wird mit w2 multipliziert. w2 sind die
niederwertigen 16 Bits des Produktes. Ein Überlauf wird
nicht angezeigt.
(nin2 n3 -- nd ) 83 " times-divide"”
Zuerst wird nl mit n2 multipliziert und ein 32-bit
Zwischenergebnis erzeugt. n4 ist der Quotient aus dem
32-bit Zwischenergebnis und dem Divisior n3. Das Produkt
von ni mal n2 wird als 32-bit Zwischenergebnis darge-
stellt, um eine größere Genauigkeit gegenüber dem sonst
gleichwertigen Ausdruck ni n2 * n3 / zu erhalten. Eine
Fehlerbedingung besteht, wenn der Divisor Null ist, oder
der Quotient außerhalb des Intervalls (-32768.. 32767)
liegt.
(ni n2 n3 -- n4 n5 ) 83 " times-divide-mod "
Zuerst wird nl mit n2 multipliziert und ein 32-bit
Zwischenergebnis erzeugt. n4 ist der Rest und n5 der
Quotient aus dem 32-bit-Zwischenergebnis und dem Divisor
n3. n4 hat das gleiche Vorzeichen wie n3 oder ist Null.
Das Produkt von ni mal n2 wird als 32-bit Zwischenergeb-
nis dargestellt, um eine größere Genauigkeit gegenüber
dem sonst gleichwertigen Ausdruck ni n2 * n3 /mod zu
erhalten. Eine Fehlerbedingung besteht, falls der Divi-
sior Null ist oder der Quotient außerhalb des Intervalls
(-32768...32767) liegt.
(w1 w2 -- w3 ) 83 "»aolus-"
wl1 und w2 addiert ergibt w3.
(wi w2 -- w3 ) 83 " minus "
w2 von wl subtrahiert ergibt w3.
( =)
Oft benutzte Zahlenwerte wurden zu Konstanten gemacht.
Definiert in der Form :
n Constant n
Dadurch wird Speicherplatz eingespart und die Ausführ-
ungszeit verkürzt. Siehe auch CONSTANT.
(nin2 -- n3 ) 83 " divide "
n3 ist der Quotient aus der Division von nl durch den
Divisor n2. Eine Fehlerbedingung besteht, wenn der
Divisor Null ist oder der Quotient außerhalb des Inter-
valls (-32768...32767) liegt.
(nin2 --n3n4) 83 " divide-mod "
n3 ist der Rest und n4 der Quotient aus der Division von
n1l durch den Divisor n2. n3 hat dasselbe Vorzeichen wie
n2 oder ist Null. Eine Fehlerbedingung besteht, wenn der
Divisor Null ist oder der Quotient außerhalb des Inter-
valls (-32768..32767) liegt.
(>==209)
Siehe -1.
1+
2+
2/
3+
abs
even
max
(--1)
Siehe -1.
(w1 --w2)
w2 ist das Ergebnis von
wirkt genauso.
- (w1 --w2)
w2 ist das Ergebnis von
wirkt genauso.
(„== 2,)
Siehe -1.
(w1 --w2)
w
w2.
wird um ein Bit nach links geschoben und das
In das niederwertigste Bit wird eine Null geschrie-
83 " one-plus "
Eins plus wl1. Die Operation 1 +
83 " one-minus "
w1l minus Eins. Die Operation 1 -
two-times "
ergibt
ben. Die Operation 2 * wirkt genauso.
(w1 --w2)
w2 ist das Ergebnis von
wirkt genauso.
(w1 --w2)
w2 ist das Ergebnis von
wirkt genauso,
(nl --n2)
nl wird um ein Bit nach
n2. Das Vorzeichen wird
ändert. Die Operation 2
(--3)
Siehe -1.
(w1 --w2)
w2 ist das Ergebnis von
wirkt genauso.
(--4)
Siehe -1.
(n-- u)
u ist der Betrag von n.
den selben Wert wien.
Zweierkomplement".
{ul --u2)
83 " two-plus "
wi plus Zwei. Die Operation 2 +
83 " two-minus "
wl minus Zwei. Die Operation 2 -
83 " two-divide "
rechts verschoben und das ergibt
berücksichtigt und bleibt unver-
/ wirkt genauso.
" three-plus "
wi plus Drei. Die Operation 3 +
83 " absolute "
Wenn n gleich -32768 ist, hat u
Vergleiche auch "Arithmetik,
u2 ist die nächstgrößere gerade Zahl zu ul.
(nl na, --.n3)
n3 ist die Größere der beiden Werte nl und
die >
32767.
Operation. Die
83 " maximum
n2.
größte Zahl für nl oder
Benutzt
n2 ist
(23 1858 we/bp/re/ks III-5
mod
negate
u/mod
umax
umin
(nin2 -- n3 ) 83 " minimum "
n3 ist die Kleinere der beiden Werte nl und n2. Benutzt
die < Operation. Die kleinste Zahl für nl oder n2 ist
- 32768.
(ni n2 --n3 ) 83 "mod "
n3 ist der Rest der Division von nl durch den Divisor
n2. n3 hat daßelbe Vorzeichen wie n2 oder ist Null. Eine
Fehlerbedingung besteht, wenn der Divisor Null ist oder
der Quotient außerhalb des Intervalls (-32768..32767)
liegt.
(ni1--n2) 83
n2 hat den gleichen Betrag, aber das umgekehrte Vorzei-
chen von n. n2 ist gleich der Differenz von Null minus
ni.
(ul u2 -- u3 u4) " u-divide-mod "
u3 ist der Rest und u4 der Quotient aus der Division von
ul durch den Divisor u2. Die Zahlen u sind vorzeichen-
lose 16-Bit Werte (unsigned integer). Eine Fehler-
bedingung besteht, wenn der Divisor Null ist.
(ulu2 -- u3) " u-maximum "
u3 ist der Größere der beiden Werte ul und u2. Benutzt
die U> Operation. Die größte Zahl für ul oder u2 ist
65535,
(ul u2 -- u3 ) " u-minimum "
u3 ist der Kleinere der beiden Werte ul und u2. Benutzt
die U< Operation. Die kleinste Zahl für ul oder u2 ist
Null.
0<>
and
case?
false
not
cr
+
H
4
!
a
-
-
ii
in
we/cp/reithz
Logik und Vergleiche
(n-- flag ) 83 " zero-less "
Wenn n kleiner als Null (negativ) ist, ist flag wahr.
Dies ist immer dann der Fall, wenn das höchstwertige Bit
von n gesetzt ist. Deswegen kann dieser Operator zum
Testen dieses Bits benutzt werden.
(n-- £lag ) .
Wenn n verschieden von Null ist, ist flag wahr.
(wr-- flag ) 83 " zero-equals "
Wenn w gleich Null ist, ist flag wahr.
(n-- flag ) 83 " zero-greater "
Wenn n größer als Null ist, ist flag wahr.
(ni n2 -- flag ) 83 " less-than "
Wenn ni kleiner als n2 ist, ist flag wahr.
z.B. -32768 32767 < ist wahr.
-32768 0 < " ist wahr.
(w1 w2 -- flag ) 83 " equals "
Wenn wi gleich w2 ist, ist flag wahr.
(ni n2 -- flag ) 83 " greater-than "
Wenn nl größer als n2 ist, ist flag wahr.
z.B. -32768 32767 > ist falsch.
-32768 0 > ist falsch.
(wl w2 -- w3 ) 83
wi wird mit w2 bitweise logisch UND verknüpft und das
ergibt w3.
( 16b1 16b2 -- 16b1 false )
oder ( 16b1 16b2 -- true ) " case-question "
Vergleicht die beiden Werte 16bl und 16b2 miteinander.
Sind sie gleich, verbleibt TRUE auf dem Stack. Sind sie
verschieden, verbleibt FALSE und der darunterliegende
Wert 16b1l auf dem Stack. Wird z.B. in der folgenden Form
benutzt :
key Ascii a case? IF ... exit THEN
Ascii b case? IF ... exit THEN
drop
Entspricht dem Ausdruck OVER = DUP IF NIP THEN
(--0)
Hinterläßt Null als Zeichen für logisch-falsch auf dem
Stack.
(w1 -- w2) 83
Jedes Bit von wl wird einzeln invertiert und das ergibt
w2.
{w1 w2 -- w3 ) 83
wl wird mit w2 logisch ODER verknüpft und das ergibt w3.
3 4528 wesbp/re/ks ITr-7 Glossar H
true == -19
Hinterläßt -1 als Zeichen für logisch wahr auf dem
Stack.
ut ( ul u2 -- flag ) 83 " u-less-than "
Wenn ul kleiner als u2 ist, ist flag wahr. Die Zahlen u
sind vorzeichenlose 16-Bit Werte. Wenn Adressen ver-
glichen werden sollen, muß U< benutzt werden, sonst
passieren oberhalb von 32K seltsame Dinge !
Ur ( ul u2 -- flag ) 83 " u-greater-than "
Wenn ul größer als u2 ist, ist flag wahr. Ansonsten gilt
das gleiche wie für U.
uwithin (uul u2 -- flag )
Wenn ul kleiner oder gleich u und u kleiner u2 ist
(ul<=u<u2), ist flag wahr. Benutzt die U< Operation.
xor (wi w2 -- w3 ) 83 NegzonDN
wi wird mit w2 bitweise logisch EXKLUSIV ODER verknüpft
und das ergibt w3.
j:
ü Glossar I ZII-8 ic) SEE weibp/re/hs
Speicheroperationen
! ( 16b adr -- ) 83 "store "
16b werden in den Speicher auf die Adresse adr geschrie-
ben. In 8-Bitweise adressierten Speichern werden die
zwei Bytes adr und adr+1 überschrieben.
+! (wl adr -- ) 83 " plus-store "
w1 wird zu dem Wert w in der Adresse adr addiert.
Benutzt die + Operation. Die Summe wird in den Speicher
in die Adresse adr geschrieben. Der alte Speicherinhalt
wird überschrieben.
2! { 32b adr -- ) 83 " two-fetch "
32b werden in den Speicher ab Adresse adr geschrieben.
2@ ( adr -- 32b ) 83 " two-fetch "
Von der Adresse adr wird der Wert 32b aus dem Speicher
geholt,
@ ( adr.-- 16b ) 83 " fetch "
Von der Adresse adr wird der Wert 16b aus dem Speicher
geholt. Siehe auch ! .
@! ( 16b adr -- ) 83 " c-store "
Von 16b werden die niederwertigsten 8 Bit in den
Speicher in die Adresse adr geschrieben.
c®@ ( adr -- 8b ) 83 " c-fetch "
Von der Adresse adr wird der Wert 8b aus dem Speicher
geholt.
cmove { adrl adr2 u -- ) 83 " c-move "”
Beginnend bei adrl werden u Bytes zur Adresse adr2
kopiert. Zuerst wird das Byte von adri nach adr2 bewegt
und dann aufsteigend fortgefahren. Wenn u Null ist, wird
nichts kopiert.
cmove> ( adrli adr2 u -- ) 83 " c-move-up "
Beginnend bei adrl werden u Bytes zur Adresse adr2
kopiert. Zuerst wird das Byte von adri-plus-u-minus-i
nach adr2-plus-u-minus-1 kopiert und dann absteigend
fortgefahren. Wenn u Null ist, wird nichts kopiert. Das
Wort wird benutzt, um Speicherinhalte auf höhere Adres-
sen zu verschieben, wenn die Speicherbereiche sich
überlappen.
count ( adri -- adr2 +n ) 83
adr2 ist adri-plus-1 und +n der Inhalt von adri. Das
Byte mit der Adresse adärl enthält die Länge des Strings
angegeben in Bytes. Die Zeichen des Strings beginnen bei
adri+1. Die Länge +n eines Strings darf im Bereich
(0..255) liegen. Vergleiche auch "String, counted"
ctoggle ” ( 8b adr -- ) 83 " c-toggle "
Für jedes gesetzte Bit in 8b wird im Byte mit der
Adresse adr das entsprechende Bit invertiert (d.h. ein
zuvor gesetztes Bit ist danach gelöscht und ein gelösch-
erase
fill
move
off
on
pad
place
(2) 4828 weibp/re/ks IITI-9
Glossar
BEREITETE
tes Bit ist danach gesetzt). Für alle gelöschten Bits in
8b bleiben die entsprechenden Bits im Byte mit der
Adresse adr unverändert. Der Ausdruck DUP C@ ROT XOR
SWAP C! wirkt genauso.
( adr u--)
Von der Adresse adr an werden u Bytes im Speicher mit
$00 überschrieben. Hat u den Wert Null, passiert nichts.
( adr u 8b -- )
Von der Adresse adr an werden u Bytes des Speichers mit
8b überschrieben. Hat u den Wert Null, passiert nichts.
( adri1 adr2 u -- )
Beginnend bei adrl werden u Bytes nach adr2 kopiert.
Dabei ist es ohne Bedeutung, ob überlappende Speicher-
bereiche aufwärts oder abwärts kopiert werden, weil MOVE
die passende Routine datzu auswählt. Hat u den Wert
Null, passiert nichts. Siehe auch CMOVE und CMOVE>.
( adr -- )
Schreibt den Wert FALSE in den Speicher mit der Adresse
adr.
(adr --)
Schreibt den Wert TRUE in den Speicher mit der Adresse
adr.
( -- adr ) 83
adr ist die Startadresse einer "scratch area". In diesem
Speicherbereich können Daten für Zwischenrechnungen
abgelegt werden. Wenn die nächste verfügbare Stelle für
das Dictionary verändert wird, ändert sich auch die
Startadresse von PAD. Die vorherige Startadresse von PAD
geht ebenso wie die Daten dort verloren.
( adri +n adr2 -- )
Bewegt +n Bytes von der Adresse adril zur Adresse adr2+1
und schreibt +n in die Speicherstelle mit der Adresse
adr2. Wird in der Regel benutzt, um Text einer bestimm-
ten Länge als "counted string" abzuspeichern. adr2 darf
gleich, größer und auch kleiner als adri sein.
Glossar ä (23 1222 we/ibp/rerks
32-Bit-Worte
d* (a1 d2 -- d3) " d-times "
ai multipliziert mit d2 ergibt d3.
d+ (dı d2 -- d3 ) 83 " d-plus "
di und d2 addiert ergibt d3.
d- (d1d2 --d3) " d-minus"
d2 minus di ergibt d3.
d0= (d -- £lag ) 83 " d-zero-equals "
Wenn d gleich Null ist, ist flag wahr.
dc (di d2 -- flag ) 83 " d-less-than "
Wenn di kleiner als d2 ist, ist flag wahr.
d= ( dı d2 -- flag ) " d-equal"
Wenn di gleich d2 ist, ist flag wahr.
dabs (4 -- ud) 83 " d-absolut "
ud ist der Betrag von d. Wenn d gleich -2.147.483.648
ist, hat ud den selben Wert wie d.
dnegate (1 -- 2) 83 " d-negate "
d2 hat den gleichen Betrag aber ein anderes Vorzeichen
als dl.
extend ("nn ==)
Der Wert n wird auf den doppelt genauen Wert d vorzei-
chenrichtig erweitert.
m* (al n2 ==74) " m-times "
Der Wert von nl wird mit n2 multiplizert und d ist das
doppelt genaue Produkt.
m/mod (dnl--n2n3) " m-divide-mod "
n2 ist der Rest und n3 der Quotient aus der Division der
doppelt genauen Zahl d durch den Divisor ni. Der Rest n2
hat dasselbe Vorzeichen wie nl oder ist Null. Eine
Fehlerbedingung besteht, wenn der Divisor Null ist oder
der Quotient außerhalb des Intervalls (-32763..32767)
liegt.
ud/mod { udi ul -- u2 ud2 ) " u-d-divide-mod "
u2 ist der Rest und ud2 der doppelt genaue Quotient aus
der Divison der doppelt genauen Zahl udl durch den
Divisor ul. Die Zahlen u sind vorzeichenlose 16-Bit
Werte (unsigned integer). Eine Fehlerbedingung besteht,
wenn der Divisor Null ist.
um* ( ul u2 -- ud ) 83 " u-m-times "
Die Werte ul und u2 werden mulitpliziert und das ergibt
das doppelt genaue Produkt vwd. UM* ist die anderen
multiplizierenden Worten zugrundeliegende Routine.
ic) BEE we/bp/rerks a
um/mod
(ud ul -- u2 u3 ) 83 " u-m-divide-mod "
u2 ist der Rest und u3 der Quotient aus der Division von
ud durch den Divisor ul. Die Zahlen u sind vorzeichen-
lose Zahlen. Eine Fehlerbedingung besteht, wenn der
Divisor Null ist oder der Quotient außerhalb des Inter-
valls (0..65535) liegt.
Glossar & III-12 (2)
y
m
ın
wercp/re/ts
Stack
-2z011 ( 16bn .. 16b1 16b0 +n -- 16b0 16bn .. 16b1 )
" minus-roll "
Das oberste Glied eier Kette von +n Werten wird an die
n-te Position gerollt. Dabei wird +n selbst nicht
mitgezählt. 2 -ROLL wirkt wie -ROT. 0 -ROLL verändert
nichts.
-rot ( 16b1 16b2 16b3 -- 16b3 16b1 16b2 )
" minus-rot "
Die drei obersten 16b Werte werden rotiert, sodaß der
oberste Wert zum Untersten wird. Hebt ROT auf.
.S (--) " dot-s "
Gibt alle Werte, die auf dem Stack liegen aus, ohne den
Stack zu verändern. Oft benutzt, um neue Worte auszu-
testen. Die Ausgabe der Werte erfolgt von links nach
rechts, der oberste Stackwert zuerst |!
2dup ( 32b -- 32b' 32b ) 83 " two-dup "
Der Wert 32b wird dupliziert.
2drop ( 32b -- ) 83 " two-drop "
Der Wert 32b wird vom Stack entfernt.
2over ( 32b1 32b2 -- 32b1 32b2 31b1l ) "” two-over "
Der Wert 32bl wird über den Wert 32b2 herüber kopiert.
2swap { 32b1 32b2 -- 32b2 32b1 ) 83 " two-swap "
Die beiden obersten 32-Bit Werte 32bl und 32b2 werden
vertauscht.
?dup ( 16b -- 16b 16b ) 83 " question-dup "
oder ( 0 -- 0)
Nur wenn der Wert 16b von Null verschieden ist, wird er
verdoppelt.
clearstack ( -- empty )
Löscht den Datenstack. Alle Werte, die sich vorher auf
dem Stack befanden, sind verloren.
depth (--n)
n ist die Anzahl der Werte, die auf dem Stack lagen,
bevor DEPTH ausgeführt wurde.
drop ( 16b -- ) 83
Der Wert 16b wird vom Stack entfernt.
dup ( 16b -- 16b 16b ) 83
Der Wert 16b wird dupliziert.
nip ( i6b1 16b2 -- 16b2 )
Der Wert 16bl, der unter 16b2 auf dem Stack liegt, wird
vom Stack entfernt.
over ( 16b1 16b2 -- 16b1 16b2 16b1 ) 83
Der Wert 16bl wird über 16b2 herüberkopiert.
1S2E8 weibp/rerts 211-133
Glossar 1
roll
rot
s0O
swap
sp!
sp@
under
( 16bn..16b0 +n -- 16bn..16b0 16bn ) 83
Der +tn-te Wert auf dem Stack wird nach oben auf den
Stack kopiert. Dabei wird +n selbst nicht mitgezählt. 0
PICK wirkt wie DUP, 1 PICK wie OVER.
{ 16bn 16bm..16b0 +n -- 16bm..16b0 16bn ) 83
Das +n-te Glied einer Kette von n Werten wird nach oben
auf den Stack gerollt. Dabei wird +n selbst nicht
mitgezählt.
( 16b1 16b2 16b3 -- 16b2 16b3 16b1 ) 83
Die drei obersten Werte auf dem Stack werden rotiert,
sodaß der unterste zum obersten wird.
( -- adr ) " s-zero "
adr ist die Adresse einer Uservariablen, in der die
Startadresse des Stacks steht. Der Ausdruck SO @ sp!
wirkt wie CLEARSTACK und leert den Stack.
( 16b1 16b2 -- 16b2 16b1 )83
Die beiden obersten 16-Bit Werte werden vertauscht.
( adr --) " s-p-store "
Setzt den Stackzeiger (stack pointer) auf die Adresse
adr. Der oberste Wert auf dem Stack ist dann der,
welcher in der Adresse adr steht.
( -- adr ) " s-p-fetch "
Holt die Adresse adr aus dem Stackzeiger. Der oberste
Wert im Stack stand in der Speicherstelle bei adr, bevor
SP@ ausgeführt wurde.
( 16b1 16b2 -- 16b2 16b1 16b2 )
Eine Kopie des obersten Wertes auf dem Stack wird unter
dem zweiten Wert eingefügt.
m
J Glossar E I1I-14 2) 1528 wesibp/rerhz
>»r
push
er
rp!
ro
r@
rdepth
rdrop
rp@
Returnstack
( 16b -- ) C,83 ı tosr"
Der Wert 16b wird auf den Returnstack gelegt. Siehe auch
R> :
(adr -)
Der Inhalt aus der Adresse adr wird auf den Returnstack
bis zum nächsten EXIT oder ; verwahrt und sodann nach
adr zurück geschrieben. Dies ermöglicht die lokale
Verwendung von Variablen innerhalb einer :-Definition.
Wird z.B. benutzt in der Form :
: hex. (n-- )) base push hex. ;
Hier wird innerhalb von HEX. in der Zahlenbasis HEX
gearbeitet, um eine Zahl auszugeben. Nachdem HEX. ausge-
führt worden ist, besteht die gleiche Zahlenbasis wie
vorher, durch HEX wird sie also nur innerhalb von HEX.
verändert.
( -- 16b ) c,83 " r-£rom "
Der Wert 16b wird vom Returnstack geholt. Vergleiche R>.
( adr -- ) " r-p-store "
Setzt den Returnstackzeiger (return stack pointer) auf
die Adresse adr. Der oberste Wert im Returnstack ist nun
der, welcher in der Speicherstelle bei adr steht.
( -- adr ) U "r-zero "
adr ist die Adresse einer Uservariablen, in der die
Startadresse des Returnstacks steht.
( -- 16b ) C,83 " r-fetch "
Der Wert 16b ist eine Kopie des obersten Wertes auf dem
Returnstack.
ten) " r-depth "
n ist die Anzahl der Werte, die auf dem Returnstack
liegen.
(--) € " r-drop "
Der oberste Wert wird vom Returnstack entfernt. Der
Datenstack wird nicht verändert. Entspricht der Opera-
tion R> DROP .
(-- adr ) " r-p-fetch "
Holt die Adresse adr aus dem Returnstackzeiger. Der
oberste Wert im Returnstack steht in der Speicherstelle
bei adr.
1528 we/bp/re/ks 1111-15 Glossar
Strings
Siehe auch im Anhang : "Strings"
" ( -- adr ) c,ıI " string "
(-) ( compiling )
Liest den Text bis zum nächsten " und legt ihn als
counted string im Dictionary ab. Kann nur während der
Kompilation verwendet werden. Zur Laufzeit wird die
Startadresse des counted string auf den Stack gelegt.
wird in der folgenden Form benutzt
! <name> 2 MAEERt>" |
Das Leerzeichen, das auf das erste Anführungszeichen
folgt, ist nicht Bestandteil des Strings.
#- ( +#d1 -- +d2 ) 83 " sharp "
Der Rest von +d1 geteilt durch den Wert in BASE wird in
ein Ascii-Zeichen umgewandelt und dem Ausgabestring in
Richtung absteigender Adressen hinzugefügt. +d2 ist der
Quotient und verbleibt auf dem Stack zur weiteren
Bearbeitung. Üblicherweise zwischen <# und #> benutzt.
#> ( 32b -- adr +n ) 83 " sharp-greater "
Am Ende der strukturierten Zahlenausgabe wird der 32b
Wert vom Stack entfernt. Hinterlegt werden die Adresse
des erzeugten Ausgabestrings und +n als die Anzahl der
Zeichen im Ausgabstring, passend für TYPE .
#s (+d4-- 00) 83 " sharp-s "
+d wird mit # umgewandelt, bis der Quotient zu Null
geworden ist. Dabei wird jedes Zwischenergebnis in ein
Ascii-Zeichen umgewandelt und dem String für die struk-
turierte Zahlenausgabe angefügt. Wenn +d von vornherein
den Wert Null hatte, wird eine einzelne Null in den
String gegeben. Wird üblichwerweise zwischen <# und #>
benutzt.
/string ( adri ni n2 -- adr2 n3 ) " cut-string "
n2 ist ein Index, welcher in den String weist, der im
Speicher bei der Adresse adri beginnt. Der String hat
die Länge nl. adr2 ist die Adresse und n3 die Länge des
rechten Teilstrings, der bei Teilung des ursprünglichen
Strings vor dessen n2-ten Element entsteht.
<# (==) 83 " less-sharp "
Leitet die strukturierte Zahlenausgabe ein. Um eine
doppelt genaue Zahl in einen Ascii-String umzuwandeln,
benutze man die Worte : <# # #S HOLD SIGN #>
accumulate ( +dl adr char -- +d2 adr )
Dient der Umwandlung von Ziffern in Zahlen. Multipli-
ziert die Zahl +di mit BASE, um sie eine Stelle in der
aktuellen Zahlenbasis nach links zu rücken, und addiert
den Zahlenwert von char. char stellt eine Ziffer dar.
adr wird nicht verändert. wird z.B. in CONVERT benutzt.
char muß eine in der Zahlenbasis gültige Ziffer darstel-
len.
- B-
ıj Glossar III-16 (23 1328 weibp/rerhs
capital ( chal -- char2 )
Die Zeichen im Berich a bis z werden in die Groß-
buchstaben A bis Z umgewandelt. Andere Zeichen werden
nicht verändert.
capitalize ( adr -- adr )
Wandelt alle Kleinbuchstaben im counted string bei der
Adresse adr in GrOßbuchstaben um. adr wird nicht verän-
dert. Siehe auch CAPITAL .
convert ( +dl adri -- +42 adr2 ) 83
Wandelt den Ascii-Text ab adri+l in eine Zahl entspre-
chend der Zahlenbasis BASE um. Der enstehende Wert wird
in di akkumuliert und als d2 hinterlassen. adr2 ist die
Adresse des ersten nicht umwandelbaren Zeichens im Text.
digit? ( char -- digit true )
oder ( char -- false )
Prüft, ob das Zeichen char eine gültige Ziffer entspre-
chend der aktuellen Zahlenbasis in BASE ist. Ist das der
Fall, so wird der Zahlenwert der Ziffer und TRUE auf
den Stack gelegt. Ist char keine gültige Ziffer, wird
FALSE hinterlegt.
hold ( char -- ) 83
Das Zeichen char wird in den Ausgabestring für die
Zahlenausgabe eingefügt. Üblicherweise zwischen <# und
#> benutzt.
nullstring? ( adr -- adr false )
oder ( adr -- true )
Prüft, ob der counted string bei der Adresse adr ein
String der Länge Null ist. Wenn dies der Fall ist, wird
TRUE hinterlegt. Sonst bleibt adr erhalten und FALSE
wird obenauf gelegt.
number (adr --Ad)
Wandelt den counted string bei der Adresse adr in eine
Zahl d um. Die Umwandlung erfolgt entsprechend der
Zahlenbasis in BASE. Eine Fehlerbedingung besteht, wenn
die Ziffern des Strings nicht in eine Zahl verwandelt
werden können. Durch Angabe eines Präfix (siehe NUMBER?)
kann die Basis für diese Zahl modifiziert werden.
2) 1358 weibe/teiks III-17
number? ( adr --A0>)
oder ( adr - n0<)
oder ( adr -- adr false )
Wandelt den counted string bei der Adresse adr in eine
Zahl n um. Die Umwandlung erfolgt entsprechend der
Zahlenbasis in BASE oder wird vom ersten Zeichen im
String bestimmt. Enthält der String zwischen den Ziffer
auch die Asciizeichen für Punkt oder Komma, so wird er
als doppelt genaue Zahl interpretiert und 0> gibt die
Zahl der Ziffern hinter dem Punkt einschließlich an.
Sonst wird der String in eine einfach genaue Zahl n
umgewandelt und eine Zahl kleiner als Null hinterlassen.
Wenn die Ziffern des Strings nicht in eine Zahl umgewan-
delt werden können, bleibt die Adresse des String
erhalten und FALSE wird auf den Stack gelegt. Die
Zeichen, die zur Bestimmung der Zahlenbasis dem
Ziffernstring vorangestellt werden können, sind :
% ( Basis 2 "binär")
& ( Basis 10 "dezimal")
$ ( Basis 16 "hexadezimal")
h ( Basis 16 "hexadezimal")
Der Wert in BASE wird dadurch nicht verändert.
scan ( adri nl char -- adr2 n2 )
Der String mit der Länge nl, der im Speicher ab Adresse
adri steht, wird nach dem zeichen char durchsucht. adr2
ist die Adresse, bei der das Zeichen char gefunden
wurde. n2 ist die Länge des verbleibenden Strings. Wird
char nicht gefunden, so ist adr2 die Adrese des ersten
Bytes hinter dem String und n2 ist Null.
sign (»au-— ) 83
Wenn n negativ ist, wird ein Minuszeichen in den
Ausgabestring für die Zahlenausgabe eingefügt. Wird
üblicherweise zwischen <# und #> benutzt.
skip ( adri nl car -- adr2 n2 )
Der String mit der Länge nl, der im Speicher ab Adresse
adrl steht, wird nach dem ersten Zeichen, das verschie-
den von char ist, durchsucht. adr2 ist die Adresse
dieses Zeichens und n2 die Länge des verbleibenden
Strings. Besteht der gesamte String aus dem Zeichen char
so ist adr2 die Adresse des Bytes hinter dem String und
n2 ist Null.
Pa
Glossar E III-18 (ce) 1228 we/kp/rerts
Datentypen
( -- sys ) 83 "colon"
ein definierendes Wort, das in der Form:
: <name> an
benutzt wird. Es erzeugt die Wortdefinition für <name>
im Kompilations-Vokabular und schaltet den Kompiler an.
Das erste Vokabular der Suchreihenfolge (das
"transient" Vokabular) wird durch das Kompilations-
Vokabular ersetzt (ACHTUNG!). Das Kompilations-Vokabu-
lar wird nicht geändert. Der Quelltext wird anschlie-
ßBend kompiliert. <name> wird als "colon-definition"
oder ":-Definition" bezeichnet. Die neue Wortdefinition
für <name> kann nicht im Dictionary gefunden werden,
bis das zugehörige ; oder ;CODE erfolgreich ausge-
führt wurde. RECURSIVE macht <name> jedoch sofort
auffindbar. Vergleiche HIDE und REVEAL .
Eine Fehlerbehandlung wird eingeleitet, wenn ein Wort
während der Kompilation nicht gefunden bzw. nicht in
eine Zahl (siehe auch BASE ) gewandelt werden kann.
Der auf dem Stack hinterlassene Wert sys dient der
Kompiler-Sicherheit "und wird durch 5 bzw. :CODE
abgebaut.
Gr.) 83 I C "semi-colon"
(sys --) compiling
beendet die Kompilation einer :-Definition; macht den
Namen dieser :-Definition im Dictionary auffindbar,
schaltet den Kompiler aus, den Interpreter ein und
kompiliert ein UNNEST (Siehe auch EXIT ). Der Stack-
parameter sys, der in der Regel von : hinterlassen
wurde, wird geprüft und abgebaut. Eine Fehlerbehandlung
wird eingeleitet, wenn sys nicht dem erwarteten Wert
entspricht.
2Constant ( 32b -- ) 83
ein definierendes Wort, das in der Form:
32b 2Constant <name>
benutzt wird. Erzeugt einen Kopf für <name> und legt
32b in dessen Parameterfeld so ab, daß bei Ausführung
von <name> 32b wieder auf den Stack gelegt wird.
2Variable ==) 83
Alias
ein definierendes Wort, das in der Form:
2Variable <name>
benutzt wird. Erzeugt einen Kopf für <name> und hält 4
Byte in seinem Parameterfeld frei, die den Inhalt der
2VARIABLEN aufnehmen. Die 2VARIABLE wird nicht
initialisiert. Wenn <name> ausgeführt wird, wird die
Adresse des Parameterfelds auf den Stack gelegt. Siehe
VARIABLE
(cfa -- )
ein definierendes Wort, das typisch in der Form:
' <oldname> Alias <newname>
benutzt wird. ALIAS erzeugt einen Kopf für <newname>
im Dictionary. Wird <newname> aufgerufen, so verhält es
sich wie <oldname). Insbesondere wird beim Kompilieren
nicht <newname>, sondern <oldname> im Dictionary ein-
(2> 1828 we/bp/re/ks Irr-19
getragen. Im Unterschied zu
! <newname> <oldname> ;
ist es mit ALIAS möglich, Worte, die den Returnstack
beeinflussen (z.B. »R oder R> ), mit anderem Namen
zu definieren. Außer dem neuen Kopf für <newname> wird
kein zusaetzlicher Speicherplatz verbraucht.
Gegenwärtig wird bei Ausführung von >NAME aus einer
CFA in der Regel der letzte mit ALIAS erzeugte Name
gefunden.
Constant F 6b ==) 83
Create
Defer
Input:
ein definierendes Wort, das in der Form:
16b Constant <name>
benutzt wird. Wird <name)> später ausgeführt, so wird
i6b auf den Stack gelegt.
(ea) 83
ein definierendes Wort, das in der Form:
Create <name>
benutzt wird. Erzeugt einen Kopf für <name>. Die
nächste freie Stelle im Dictionary (vergleiche HERE
und DP ) ist nach einem CREATE <name> das erste Byte
des Parameterfelds von <name>. Wenn <name> ausgeführt
wird, legt es die Adresse seines Parameterfelds auf den
Stack. CREATE reserviert keinen Speicherplatz im
Parameterfeld von <name>.
(==)
ein definierendes Wort, das in der Form:
Defer <name>
benutzt wird. Erzeugt den Kopf für ein neues Wort
<name> im Dictionary, hält 2 Byte in dessen Parameter-
feld frei und speichert dort zunächst die Kompila-
tionsadresse einer Fehlerroutine. Wird <name> nun aus-
geführt, so wird eine Fehlerbehandlung eingeleitet. Man
kann dem Wort <name> jedoch zu jeder Zeit eine andere
Funktion zuweisen mit der Sequenz:
' <action> Is <name>
Nach dieser Zuweisung verhält sich <name> wie <action>.
Mit diesem Mechanismus kann man zwei Probleme elegant
lösen: Einerseits läßt sich <name> bereits kompilieren,
bevor ihm eine sinnvolle Aktion zugewiesen wurde. Damit
ist die Kompilation erst später definierter Worte
(Vorwärts-Referenzen) indirekt möglich. Andererseits
ist die Veränderung des Verhaltens von <name> für
spezielle Zwecke auch nachträglich möglich, ohne neu
kompilieren zu müssen.
Deferred Worte im System sind:
R/W , COLD, 'RESTART , "ABORT
NOTFOUND „, STATUS und DISKERR . .
Diese Worte sind DEFERred, damit ihr Verhalten für die
Anwendung geändert werden kann. Ein spezielles DEFERred
Wort ist >INTERERET .
r 'QuUIT ,
(--) "input-colon"
ein definierendes Wort, benutzt in der Form:
Input: <name>
newKEY newKEY? newDECODE newEXPECT ;
r
Output:
User
2) IREE we/bp/re/hs
INPUT: erzeugt einen Kopf für <name> im Dictionary und
kompiliert einen Satz von Zeigern auf Worte, die für
die Eingabe von Zeichen zuständig sind. Wird <name>
ausgeführt, so wird ein Zeiger auf das Parameterfeld
von <name> in die Uservariable INPUT geschrieben.
Alle Eingaben werden jetzt über die neuen Eingabewörte
abgewickelt. Die Reihenfolge der Worte nach
INPUT: <name> bis zum semi-colon muß eingehalten
werden: (..key ..key? ..decode ..expect).
Im System ist das mit INPUT: definierte Wort
KEYBOARD enthalten, nach dessen Ausführung alle Ein-
gaben von der Tastatur geholt werden und ein einfacher
Zeilen-Editor wirksam ist. Siehe DECODE und EXPECT
(cfa--)
ein Wort, mit dem das Verhalten eines deferred Wortes
verändert werden kann. IS wird in der Form:
' «<action> Is <name>
benutzt. Wenn <name> kein deferred Wort ist, wird eine
Fehlerbehandlung eingeleitet, sonst verhält sich <name>
anschließend wie (action). Siehe DEFER .
(ir) "output-colon"
ein definierendes Wort, benutzt in der Form:
Output: <name>
newEMIT newCR newTYPE newDEL newPAGE newAT
newAT? ;
OUTPUT: erzeugt einen Kopf für <name> im Dictionary
und kompiliert einen Satz von Zeigern auf Worte, die
für die Ausgabe von Zeichen zuständig sind. Wird <name>
ausgeführt, so wird ein Zeiger auf das Parameterfeld
von <name> in die Uservariable OUTPUT geschrieben.
Alle Ausgaben werden jetzt über die neuen Ausgabeworte
abgewickelt. Die Reihenfolge der Worte nach
OUTPUT: <«name> bis zum semi-colon muß eingehalten
werden: (..emit ..cr ..type ..del ..page ..at ..at?).
Im System ist das mit OUTPUT: definierte Wort
DISPLAY enthalten, nach dessen Ausführung alle Aus-
gaben auf den Bildschirm geleitet werden. Vergleiche
auch das Wort PRINT aus dem Printer-Interface.
a) 83
ein definierendes Wort, benutzt in der Form:
User <name>
USER erzeugt einen Kopf für <name> im Dictionary und
hält 2 Byte in der Userarea frei. Siehe UALLOT . Diese
2 Byte werden für den Inhalt der Uservariablen benutzt
und werden nicht initialisiert. Im Parameterfeld der
Uservariablen im Dictionary wird nur ein Offset zum
Beginn der Userarea abgelegt. Wird <name> ausgeführt,
so wird die Adresse des Wertes der Uservariablen in der
Userarea auf den Stack gegeben.
2) 1328 werbp/re/ks IIT-21
Uservariablen werden statt normaler Variablen z.B. dann
benutzt, wenn der Einsatz des Multitaskers geplant ist
und mindestens eine Task die Variable unbeeinflußt von
anderen Tasks benötigt. (Jede Task hat ihre eigene
Userarea).
Variable ) 83
ein definierendes Wort, benutzt in der Form:
Variable <name>
VARIABLE erzeugt einen Kopf für <name>) im Dictionary
und hält 2 Byte in seinem Parameterfeld frei. Siehe
ALLOT . Dies Parameterfeld wird für den Inhalt der
Variablen benutzt, wird jedoch nicht initialisiert.
Wird <name> ausgeführt, so wird die Adresse des Parame-
terfeldes von <name> auf den Stack gelegt. Mit ® und
! kann der Wert von <name> gelesen und geschrieben
werden. Siehe auch +! .
Vocabulary (e==%) 83
ein definierendes Wort, das in der Form:
Vocabulary <name>
benutzt wird. VOCABULARY erzeugt einen Kopf für
<name>, das den Anfang einer neuen Liste von Worten
bildet. Wird <name> ausgeführt, so werden bei der Suche
im Dictionary zuerst die Worte in der Liste von <nanme>
berücksichtigt.
wird das VOCABULARY <name> durch die Sequenz:
<name> DEFINITIONS
zum Kompilations-Vokabular, so werden neue Wort-Defi-
nitionen in die Liste von <name> gehängt. Vergleiche
auch CONTEXT „ CURRENT „ ALSO , TOSS „ ONLY .
FORTH ,„ ONLYFORTH .
(forget
IIT>22 (2) 1328 we/bp/refhs
Dictionary - Worte
(:--- adär: ) 83 "tick"
Wird in der Form ' <name> benutzt.
adär ist die Kompilationsadresse von name). Wird
<name> nicht in der Suchreihenfolge gefunden, so wird
eine Fehlerbehandlung eingeleitet.
( addr -- ) "paren-forget"
Entfernt alle Worte, deren Kompilationsadresse oberhalb
von addr liegt, aus dem Dictionary und setzt HERE
auf addr. Ein Fehler liegt vor, falls addr im Heap
liegt.
. { 16b: >=) 83 "comma'"
2 ALLOT für 16b und speichere 16b ab HERE 2- .
.name ( addr -- ) "dot-name"
addr ist die Adresse des Countfeldes eines Namens.
Dieser Name wird ausgedruckt. Befindet er sich im Heap,
so wird das Zeichen } vorangestellt. Ist addr null, so
wird "???" ausgegeben.
align (=)
rundet HERE auf den nächsten geraden Wert auf. Ist HERE
gerade, so geschieht nichts.
allot (w--) 83
Allokiere w Bytes im Dictionary. Die Adresse des
nächsten freien Dictionaryplatzes wird entsprechend
verstellt.
e, { 16b-- ) "c-comma"
ALLOT ein Byte und speichere die unteren 8 Bit von 16b
in HERE 1-.
clear (-- )
Löscht alle Namen und Worte im Heap.
custom-remove ( dic symb -- dic symb )
Ein deferred Wort, daß von FORGET , CLEAR usw. aufgeru-
fen wird. dic ist die untere Grenze des Dictonaryteils,
der vergessen wird und symb die obere. Gewöhnlich zeigt
symb in den Heap. Dieses Wort kann dazu benutzt werden,
eigene Datenstrukturen, die Zeiger enthalten, bei
FORGET korrekt abzuabrbeiten. Es wird vom Fileinterface
verwendet, daher darf es nicht einfach überschrieben
werden. Man kann es z.B. in folgender Form benutzen :
: <name> [ ' custom-remove >body @ , ]
<liststart> @ remove ;
' <name> Is custom-remove
Auf diese Weise stellt man sicher, daß das Wort, das
vorher in CUSTOM-REMOVE eingetragen war, weiterhin
ausgeführt wird. Siehe auch REMOVE
dp ( -- addr ) "a-pB"
Eine Uservariable, die die Adresse des nächsten freien
Dictionaryplatzes enthält.
23 EEE weibprrerks III-23 Glossar
empty
forget
here
hide
last
name>
origin
remove
reveal
u-=#)
Löscht alle Worte, die nach der letzten Ausführung von
SAVE oder dem letzten Kaltstart definiert wurden. DP
wird auf seinen Kaltstartwert gesetzt und der Heap
gelöscht.
(=) 83
Wird in der Form FORGET <name> benutzt.
Falls <name> in der Suchreihenfolge gefunden wird, so
werden <name> und alle danach definierten Worte aus dem
Dictionary entfernt. Wird <name> nicht gefunden, so
wird eine Fehlerbehandlung eingeleitet. Liegt <name> in
dem durch SAVE geschützten Bereich, so wird ebenfalls
eine Fehlerbehandlung eingeleitet. Es wurden Vorkehrun-
gen getroffen, die es ermöglichen, aktive Tasks und
Vokabulare, die in der Suchreihenfolge auftreten, zu
vergessen.
( -- addr ) 83
addr ist die Adresse des nächsten freien Dictionary-
platzes.
(&==2)
Entfernt das zuletzt definierte Wort aus der Liste des
Vokabulars, in das es eingetragen wurde. Dadurch kann
es nicht gefunden werden. Es ist aber noch im Speicher
vorhanden. ( s.a. REVEAL LAST )
( -- addr )
Variable, die auf das Countfeld des zuletzt definierten
Wortes zeigt.
( addri -- addr2 ) "name-£rom"
addr2 ist die Kompilationsadresse die mit dem Countfeld
in addri korrespondiert.
( -- addr )
addr ist die Adresse, ab der die Kaltstartwerte der
Uservariablen abgespeichert sind.
{ die sym thread -- dic syn )
Dies ist ein Wort, das zusammen mit CUSTOM-REMOVE
verwendet wird. dic ist die untere Grenze des Dictio-
narybereiches, der vergessen werden soll und sym die
obere. Typisch zeigt sym in den Heap. thread ist der
Anfang einer Kette von Zeigern, die durch einen Zeiger
mit dem Wert Null abgeschlossen wird. Wird REMOVE dann
ausgeführt, so werden alle Zeiger (durch Umhängen der
übrigen Zeiger) aus der Liste entfernt, die in dem zu
vergessenden Dictionarybereich liegen. Dadurch ist es
möglich, FORGET und ähnliche Worte auf Datenstrukturen
anzuwenden.
{ —
Trägt das zuletzt definierte Wort in die Liste des
Vokabulars ein, in dem es definiert wurde,
uallot
udp
»body
>name
0-3 iSZE weibo/rer/hs
Kopiert den Wert aller Uservariablen in den Speicher-
bereich ab ORIGIN und sichert alle Vokabularlisten.
Wird später COLD ausgeführt, so befindet sich das
System im gleichen Speicherzustand wie bei Ausführung
von SAVE.
(nl --n2)
Allokiere bzw. deallokiere nl Bytes in der Userarea. n2
gibt den Anfang des allokierten Bereiches relativ zum
Beginn der Userarea an. Eine Fehlerbehandlung wird
eingeleitet, wenn die Userarea voll ist.
( -- addr ) "u=äd-p"
Eine Uservariable, in dem das Ende der bisher allokier-
ten Userarea vermerkt ist.
( addri -- addr2 ) "to-body"
addr2 ist die Parameterfeldadresse, die mit der Kompi-
lationsadresse addri korrespondiert.
( addri -- addr2 ) "to-name"
addr2 ist die Adresse eines Countfeldes, das mit der
Kompilationsadresse addri korrespondiert. Es ist
möglich, daß es mehrere addr2 für ein addrli gibt. In
diesem Fall ist nicht definiert, welche ausgewählt
wird.
c$ iaz5E we/ibp/re/ks IMI-25
Glossar E|
Vokabular - Worte
also (--)
Ein Wort, um die Suchreihenfolge zu spezifizieren. Das
Vokabular im auswechselbarem Teil der Suchreihenfolge
wird zum ersten Vokabular im festen Teil gemacht, wobei
die anderen Vokabulare des festen Teils nach hinten
rücken. Ein Fehler liegt vor, falls der feste Teil
sechs Vokabulare enthält.
Assembler ==)
Ein Vokabular, das Prozessor-spezifische Worte enthält,
die für Code-Definitionen benötigt werden.
context ( -- addr )
addr ist die Adresse des auswechselbaren Teils der
Suchreihenfolge. Sie enthält einen Zeiger auf das erste
zu durchsuchende Vokabular.
current ( -- addr )
addr ist die Adresse eines Zeigers, der auf das
Kompilationsvokabular zeigt, win das neue Worte einge-
fügt werden.
definitions ( —) 83
Ersetzt das gegenwärtige Kompilationsvokabular durch
das Vokabular im auswechselbaren Teil der Suchreihen-
folge, d.h. neue Worte werden in dieses Vokabular
eingefügt.
Forth u) 83
Das ursprüngliche Vokabular.
forth-83 (=) 83
Lt. Forth83-Standard soll dieses Wort sicherstellen,
daß ein Standardsystem benutzt wird. Im volksFORTH
£funktionslos.
Only ME),
Löscht die Suchreihenfolge vollständig und ersetzt sie
durch das Vokabular ONLY im festen und auswechselbaren
Teil der Suchreihenfolge. ONLY enthält nur wenige
Worte, die für die Erzeugung einer Suchreihenfolge
benötigt werden.
Onlyforth (==)
entspricht der häufig benötigten Sequenz
ONLY FORTH ALSO DEFINITIONS,.
seal (==)
Löscht das Vokabular ONLY „ so daß es nicht mehr
durchsucht wird. Dadurch ist es möglich, nur die
Vokabulare des Anwenderproaramms durchsuchen zu lassen.
we/bp/re/hzs
toss =)
Entfernt das erste Vokabular des festen Teils der
Suchreihenfolge. Insofern ist es das Gegenstück zu
ALSO .
words sh)
Gibt die Namen der Worte des Vokabulars, das im
auswechselbaren Teil der Suchreihenfolge steht, aus,
beginnend mit dem zuletzt erzeugtem Namen.
voc-link ( -- addr )
Eine Uservariable. Sie enthält den Anfang einer Liste
mit allen Vokabularen. Diese Liste wird u.a. für FORGET
benötigt.
vp { -- addr ) "y-p"
Eine Variable, die das Ende der Suchreihenfolge mar-
kiert. Sie enthält ausserdem Informationen über die
Länge der Suchreihenfolge.
=
(23 IBZE weibp/re/rs III-27 Glossar
?head
halign
hallot
heap
heap?
Heap - Worte
( -- addr ) "question-head"
Eine Variable, die angibt, ob und wieviele der nächsten
zu erzeugenden Namen im Heap angelegt werden sollen
(Sea.scıh 6
(„=3=) "h-align"
HEAP wird auf den nächsten geradzahligen Wert abgerun-
det. Ist HEAP gerade, geschieht nichts.
(n)
Allokiere bzw. deallokiere n Bytes auf dem Heap. Dabei
wird der Stack verschoben, ebenso wie der Beginn des
Heap.
( -- addr )
addr ist der Anfang des Heap. Er wird u.A. durch HALLOT
geändert.
{( addr -- flag ) "heap-question"
Das Flag ist wahr, wenn addr ein Byte im Heap adres-
siert, ansonsten falsch.
(--) "headerless"
Setzt bei Ausführung ?HEAD so, daß der nächste erzeugte
Name nicht im normalen Dictionaryspeicher angelegt
wird, sondern auf dem Heap.
+LOOP
?DO
?exit
BEGIN
bounds
DO
ELSE
III-28 23 SEEE werbp/reiks
Kontrollstrukturen
(n--) 83,I,C "plus-loop"
(sys -- ) compiling
n wird zum Loopindex addiert. Falls durch die Addition
die Grenze zwischen limit-1 und limit überschritten
wurde, so wird die Schleife beendet und die Loop-
Parameter werden entfernt. Wurde die Schleife nicht
beendet, so wird sie hinter dem korrespondierenden DO
bzw. ?DO fortgesetzt.
(w1w2 --) 83,1,C "question-do"
( -- sys ) compiling
Wird in der folgenden Art benutzt:
rDo “m. LOOP bzw. ?DO ... +LOOP
Beginnt eine Schleife. Der Schleifenindex beginnt mit
w2, limit ist wi. Details über die Beendigung von
Schleifen: s. +LOOP. Ist w2=wl , so wird der Schleifen-
rumpf überhaupt nicht durchlaufen.
( £lag -- ) "question-exit"
Führt EXIT aus, falls das flag wahr ist. Ist das flag
falsch, so geschieht nichts.
(==) 83,I,c
(sys ---) compiling
wird in der folgenden Art benutzt:
BEGIN ( ...£lag WHILE ) ... flag UNTIL
oder: BEGIN ( ...£flag WHILE ) ... REPEAT
BEGIN markiert den Anfang einer Schleife. Der ()-
Ausdruck ist optional und kann beliebig oft auftreten.
Die Schleife wird wiederholt, bis das flag bei UNTIL
wahr oder oder das flag bei WHILE falsch ist. REPEAT
setzt die Schleife immer fort.
({ start count -- limit start )
Dient dazu, ein Intervall, das durch Anfangswert start
und Länge count gegeben ist, in ein Intervall umzu-
rechnen, das durch Anfangswert start und Endwert+1
limit beschrieben wird.
Beispiel : 10 3 bounds DO ... LOOP führt dazu, das I
die Werte 10 11 12 annimmt.
(w1w2 --) 83,I,C
(sys --) compiling
Entspricht ?DO „ jedoch wird der Schleifenrumpf mindes-
tens einmal durchlaufen. Ist wiI=sw2 , so wird der
Schleiferumpf 65536-mal durchlaufen.
(==) 83; 1sE
( sysli -- sys2 )compiling
Wird in der folgenden Art benutzt:
flag IF ... ELSE ... THEN
ELSE wird unmittelbar nach dem Wahr-Teil ,Ä der auf IF
folgt, ausgeführt. ELSE setzt die Ausführung unmittel-
bar hinter THEN fort.
ic} SEE we/bp/ire/ks 11-29 Glossar
execute
IF
LEAVE
LOOP
perform
REPEAT
THEN
( adär -- ) 83
Das Wort, dessen Kompilationsadresse addr ist, wird
ausgeführt.
(-) SIE
Wird zwischen DO und LOOP benutzt, um eine Kopie des
Schleifenindex auf den Stack zu holen.
( £lag -- ) 83,T.,C
(-- sys ) compiling
Wird in der folgenden Art benutzt:
flag IF ... ELSE ... TEEN
oder: flag IF ... THEN
Ist das flag wahr, so werden die Worte zwischen IF und
ELSE ausgeführt und die Worte zwischen ELSE und THEN
ignoriert. Der ELSE-Teil ist optional.
Ist das flag falsch, so werden die Worte zwischen IF
und ELSE ( bzw. zwischen IF und THEN ,„ falls ELSE nicht
vorhanden ist }) ignoriert.
(--w) 83,,c
Wird zwischen DO .. DO und LOOP .. LOOP benutzt, um
eine Kopie des Schleifenindex der äusseren Schleife auf
den Stack zu holen.
(1) 83,C
Setzt die Ausführung des Programmes hinter dem nächsten
LOOP oder +LOOP fort, wobei die zugehöhrige Schleife
beendet wird. Mehr als ein LEAVE pro Schleife ist
möglich, ferner kann LEAVE zwischen anderen Kontroll-
strukturen auftreten. Der Forth83-Standard schreibt
abweichend vom volksFORTH vor, daß LEAVE ein immediate
Wort ist.
ve) 83,1,C
(-- sys ) compiling
Entspricht +LOOP, jedoch mit n=1 fest gewählt.
( addr -- )
addr ist eine Adresse, unter der sich ein Zeiger auf
die Kompilationsadresse eines Wortes befindet. Dieses
Wort wird ausgeführt. Entspricht der Sequenz @
EXECUTE .
(=) 83,1,€
( -- sys ) compiling
Wird in der folgenden Form benutzt:
BEGIN (.. WHILE) .. REPEAT
REPEAT setzt die Ausführung der Schleife unmittelbar
hinter BEGIN fort. Der ()-Ausdruck ist optional und
kann beliebig oft auftreten.
(--) 83,1,C
(sys --) compiling
Wird in der folgenden Art benutzt:
IF (...ELSE) ... TBHEN
Hinter THEN ist die Programmverzweigung zuende.
WHILE
Glossar E III-30 (2) 4828 we/ibo/terhs
( £lag -- ) 83, 1uC
(sys --) compiling
Wird in der folgenden Art benutzt:
BEGIN (... flag WHILE) ... flag UNTIL
Markiert das Ende einer Schleife, deren Abbruch durch
flag herbeigeführt wird. Ist das flag vor UNTIL wahr,
so wird die Schleife beendet, ist es falsch, so wird
die Schleife unmittelbar hinter BEGIN fortgesetzt.
( £lag -- ) 83,I,c
( sysl -- sys2 )Jcompiling
Wird in der folgenden Art benutzt:
BEGIN .. flag WHILE .. REPEAT
oder: BEGIN .. flag WHILE .. flag UNTIL
Ist das flag vor WHILE wahr, so wird die Ausführung der
Schleife bis UNTIL oder REPEAT fortgesetzt, ist es
falsch, so wird die Schleife beendet und das Programm
hinter UNTIL bzw. REPEAT fortgesetzt. Es können mehre
WHILE in einer Schleife verwendet werden.
(2) 1982 werbp/re/hs z17r231
Ascii
compile
Does>
immedia
Literal
Glossar )
rem Er
Compiler - Worte
HE=%) "comma-quote"
Speichert einen counted String im Dictionary ab HERE.
Dabei wird die Länge des Strings in dessen erstem Byte,
das nicht zur Länge hinzugezählt wird, vermerkt.
( -- char ) I
=) compiling
Wird in der folgenden Art benutzt:
Ascii ccc
wobei ccc durch ein Leerzeichen beendet wird. char ist
der Wert des ersten Zeichens von ccc im benutzten
Zeichensatz (gewöhnlich ASCII). Falls sich das System
im kompilierenden Zustand befindet, so wird char als
Konstante compiliert. Wird die :-definition später
ausgeführt, so liegt char auf dem Stack.
(==) 83,C
Typischerweise in der folgenden Art benutzt:
: <name> ... compile <namex> ...;
Wird <name> ausgeführt, so wird die Kompilationsadresse
von <namex> zum Dictionary hinzugefügt und nicht ausge-
führt. Typisch ist <name> immediate und <namex> nicht
immediate.
( -- addr ) 83,I,C "does"
ve=) compiling
Definiert das Verhalten des Wortes, das durch ein
definierendes Wort erzeugt wurde. Wird in der folgenden
Art benutzt:
Hammer?" „.% <cheate> u... Doesy u... }
und später:
<namex> <name>
wobei <create> CREATE oder ein anderes Wort ist, das
CREATE ausführt.
Zeigt das Ende des Wort-erzeugenden Teils des definie-
renden Wortes an. Beginnt die Kompilation des Codes,
der ausgeführt wird, wenn <name> aufgerufen wird. In
diesem Fall ist addr die Parameterfeldadresse von
<name). addr wird auf den Stack gebracht und die
Sequenz zwischen DOES> und ; wird ausgeführt.
te (=) 83
Markiert das zuletzt definierte Wort als "immediate",
d.h. dieses Wort wird auch im kompilierenden Zustand
ausgeführt.
{ —- 16b ) 33,8,C
( 16b -- ) compiling
Typisch in der folgenden Art benutzt:
[ 16b ] Literal
Kompiliert ein systemabhängiges Wort, so daß bei Aus-
führung 16b auf den Stack gebracht wird.
111232 (23 48
[0
E o we/bp/re/rz
recursive (—) Ne
(==) compiling
Erlaubt die rekursive Kompilation des gerade definier-
ten Wortes in diesem Wort selbst. Ferner kann Code für
Fehlerkontrolle erzeugt werden.
restrict (--)
Markiert das zuletzt definierte Wort als "restrict”,
d.h. dieses Wort kann nicht vom Textinterpreter inter-
pretiert sondern ausschliesslich in anderen Worten
kompiliert werden.
[ GE) 83,I "left-bracket”
(--) compiling
Schaltet den interpretierenden Zustand ein. Der Quell-
text wird sukzessive ausgeführt. Typische Benutzung :
s. LITERAL
['] ( -- addr ) 83,1,C "bracket-tick"
(=) compiling
Wird in der folgenden Art benutzt:
['] <name>
Kompiliert die Kompilationsadresse von <name> als eine
Konstante. Wenn die :-definition später ausgeführt
wird, so wird addr auf den Stack gebracht. Ein Fehler
tritt auf, wenn <name> in der Suchreihenfolge nicht
gefunden wird.
[compile] ( == ) 83,1,C "bracket-compile"
=) compiling
wird in der folgenden Art benutzt:
[compile] <name>
Erzwingt die Kompilation des folgenden Wortes <name>.
Damit ist die Kompilation von immediate-Worten möglich.
ic) BEE werbpire/hs III-33 Glossar
Interpreter - Worte
(--) 83,1 "paren"
(Nz= 2) compiling
Wird in der folgenden Art benutzt:
( ccc)
Die Zeichen ccc, abgeschlossen durch ) ,„ werden als
Kommentar betrachtet. Kommentare werden ignoriert. Das
Leerzeichen zwischen ( und ccc ist nicht Teil des
Kommentars. ( kann im interpretierenden oder kompilie-
renden Zustand benutzt werden. Fehlt ) ,„ so werden alle
Zeichen im Quelltext als Kommentar betrachtet.
+load ({n==7 "plus-load"
LOAD den Block, dessen Nummer um n höher ist, als die
Nummer des gegenwärtig interpretierten Blockes,
+thru (nin2 --) "plus-thru"
LOAD die Blöcke hintereinander, die nl..n2 vom gegen-
wärtigen Block entfernt sind.
Beispiel : 1 2 +thru lädt die nächsten beiden
Blöcke.
--) (--) I "next-block"
e ==") compiling
Setze die Interpretation auf dem nächsten Block fort.
>»in ( -- addr ) 83 "to-in"
Eine Variable, die den Offset auf das gegenwärtige
Zeichen im Quelltext enthält. s. WORD
>»interpret Win) "to-interpret" j
Ein deferred Wort, das die gegenwärtige Interpreta-
tionsroutine aufruft, ohne eine Rückkehradresse auf dem
Returnstack zu hinterlassen (was INTERPRET tut). Es
kann als spezielles GOTO angesehen werden.
blk ( -- addr ) 83 "b=1-k"
Eine Variable, die die Nummer des gerade als Quelltext
interpretierten Blockes enthält. Ist der Wert von BULK
Null, so wird der Quelltext vom Texteingabepuffer
genommen.
find ( addri -- addr2 n )83
addri ist die Adresse eines counted string. Der String
enthält einen Namen, der in der aktuellen Suchreihen-
folge gesucht wird. Wird das Wort nicht gefunden, so
ist addr2 = addri und n = Null. Wird das Wort gefunden,
so ist addr2 dessen Kompilationsadresse und n erfüllt
folgende Bedingungen:
n ist vom Betrag 2 ,„ falls das Wort restrict ist, sonst
vom Betrag 1
n ist positiv, wenn das Wort immediate ist, sonst
negativ.
Glossar
III-34 (23 1228 weibprrefks vn
FRRTH
interpret (--)
load
loadfile
name
Beginnt die Interpretation des Quelltextes bei dem
Zeichen, das durch den Inhalt von >IN indiziert wird.
>IN indiziert relativ zum Anfang des Blockes, dessen
Nummer in BLK steht. Ist BLK Null, so werden Zeichen
aus dem Texteingabepuffer interpretiert.
(RA) 83
Die Inhalte von >IN und BLK, die den gegenwärtigen
Quelltext angeben, werden gespeichert. Der Block mit
der Nummer n wird dann zum Quelltext gemacht. Der Block
wird interpretiert. Die Interpretation wird bei Ende
des Blocks abgebrochen, sofern das nicht explizit
geschieht. Dann wird der alte Inhalt nach BLK und >IN
zurückgebracht. s.a. BLK >IN BLOCK
( -- addr)
Addr ist die Adresse einer Variablen, die auf das
Forth-File zeigt, das gerade geladen wird. Diese Var-
iable wird bei Aufruf von LOAD ,„, THRU usw. auf das
aktuelle File gesetzt.
( -- addr )
Holt den nächsten String, der durch Leerzeichen
eingeschlossen wird, aus dem Quelltext, wandelt ihn in
Grossbuchstaben um und hinterlässt die Adresse addr, ab
der der String im Speicher steht. s. WORD
notfound ( addr -- )
parse
quit
source
Ein deferred Wort, das aufgerufen wird, wenn der Text
aus dem Quelltext weder als Name in der Suchreihenfolge
gefunden wurde, noch als Zahl interpretiert werden
kann. Kann benutzt werden, um eigene Zahl- oder String-
eingabeformate zu erkennen. Ist mit NO.EXTENSIONS
vorbesetzt. Dieses Wort bricht die Interpretation des
Quelltextes ab und druckt die Fehlermeldung "haeh?"
aus.
( char -- addr +n )
Liefert die Adresse addr und Länge +n des nächsten
Strings im Quelltext, der durch den Delimiter char
abgeschlossen wird. +n ist Null, falls der Quelltext
erschöpft oder das erste Zeichen char ist. >IN wird
verändert.
(--) 83
Entleert den Returnstack, schaltet den interpretie-
renden Zustand ein, akzeptiert Eingaben von der aktuel-
len Eingabeeinheit und beginnt die Interpretation des
eingegebenen Textes.
( -- addr tn )
liefert Anfang addr und maximale Länge +n des Quelltex-
tes. Ist BLK Null, beziehen sich Anfang und Länge auf
den Texteingabepuffer, sonst auf den Block, dessen
Nummer in BLK steht und der in den Rechnerspeicher
kopiert wurde. s. BLOCK >IN
m
23 1822 weibp/re/ks IIlI-35 Glossar
thru
word
\\
\needs
( -- addr ) 83
Eine Variable, die den gegenwärtigen Zustand enthält.
Der Wert Null zeigt den interpretierenden Zustand an,
ein von Null verschiedener Wert den kompilierenden
Zustand.
(nın --)
LOAD die Blöcke von ni bis inklusive n2.
( char -- addr )83
erzeugt einen counted String durch Lesen von Zeichen
vom Quelltext, bis dieser erschöpft ist oder der
Delimiter char auftritt. Der Quelltext wird nicht
zerstört. Führende Delimiter werden ignoriert. Der
gesamte String wird im Speicher beginnend ab Adresse
addr als eine Sequenz von Bytes abgelegt. Das erste
Byte enthält die Länge des Strings (0..255). Der String
wird durch ein Leerzeichen beendet, das nicht in der
Längenangabe enthalten ist. Ist der String länger als
255 Zeichen, so ist die Länge undefiniert. War der
Quelltext schon erschöpft, als WORD aufgerufen wurde,
so wird ein String der Länge Null erzeugt.
Wird der Delimiter nicht im Quelltext gefunden, so ist
der Wert von >IN die Länge des Quelltextes. Wird der
Delimiter gefunden, so wird >IN so verändert, dass >IN
das Zeichen hinter dem Delimiter indiziert. #TIB wird
nicht verändert.
Der String kann sich oberhalb von HERE befinden.
(--) 83,I "right-bracket"
(=) compiling
Schaltet den kompilierenden Zustand ein. Der Text vom
Quelltext wird sukzessive kompiliert. Typische Benut-
zung s. LITERAL
{. ==.) I "skip-line”
( ==) compiling
Ignoriere den auf dieses Wort folgenden Text bis zum
Ende der Zeile. s. C/L
(= 7) I "skip-screen"
(==) compiling
Ignoriere den auf dieses Wort folgenden Text bis zum
Ende des Blockes. s. B/BLK
(--) "skip-needs"
Wird in der folgenden Art benutzt:
\needs <name>
Wird <name> in der Suchreihenfolge gefunden, so wird
der auf <name> folgende Text bis zum Ende der Zeile
ignoriert. Wird <name> nicht gefunden, so wird die
Interpretation hinter <name> fortgesetzt.
Beispiel: \needs Editor 1i+ load
Lädt den folgenden Block, falls EDITOR im Dictionary
nicht vorhanden ist.
(error
?pairs
?stack
abort
abort"
error"
III-36 12} 1S2E we/ibh/re/hs
Fehlerbehandlung
( string -- ) "paren-error"
Dieses Wort steht normalerweise in der Variablen
ERRORHANDLER und wird daher bei ABORT" und ERROR"
ausgeführt. string ist dann die Adresse des auf ABORT"
bzw. ERROR" folgenden Strings. (ERROR gibt das
letzte Wort des Quelltextes gefolgt von dem String auf
dem Bildschirm aus. Die Position des letzten Wortes im
Quelltext, bei dem der Fehler auftrat, wird in SCR und
R# abgelegt.
(nin2 --) "question-pairs"
Ist nl > n2 ,, so wird die Fehlermeldung
"unstructured" ausgegeben. Dieses Wort wird benutzt, um
die korrekte . Schachtelung der Kontrollstrukturen zu
überprüfen.
t =.) "question-stack"
Prüft, ob der Stack über- oder leerläuft. Der Stack
läuft leer, falls der Stackpointer auf eine Adresse
oberhalb von so zeigt. In diesem Fall wird die
Fehlermeldung "stack empty" ausgegeben. Der Stack
läuft über, falls der Stackpointer zwischen HERE und
HERE + $100 liegt. In diesem Fall wird die: Fehler-
meldung "tight stack" ausgegeben, falls mehr als 31
Werte auf dem Stack liegen. Ist das nicht der Fall, so
versucht das System, das zuletzt definierte Wort zu
vergessen und es wird die Fehlermeldung "dictionary
full" ausgegeben.
„==, 83,1
Leert den Stack, führt END-TRACE STANDARDI/O und
QUIT aus.
( £lag ) 83,1I,C "abort-quote"
(--) compiling
Wird in der folgenden Form benutzt:
flag Abort" ccc"
Wird ABORT" später ausgeführt, so geschieht nichts,
wenn flag falsch ist. Ist flag wahr, so wird der Stack
geleert und der Inhalt von ERRORHANDLER ausgeführt.
Beachten Sie bitte, daß im Gegensatz zu ABORT kein
END-TRACE ausgeführt wird.
( £lag ) L.c "error-quote"
(--) compiling
Dieses Wort entspricht ABORT" ı jedoch mit dem
Unterschied, daß der Stack nicht geleert wird.
errorhandler { -- adr )
adr ist die Adresse einer Uservariablen, deren Inhalt
die Kompilationsadresse eines Wortes ist. Dieses Wort
wird ausgeführt, wenn das flag, das ABORT" bzw.
ERROR" verbrauchen, wahr ist. Der Inhalt von
ERRORHANDLER ist normalerweise (ERROR.
23 1328 weite/re/ks III-37 Glossar
warning
( -= ade )
adr ist die Adresse einer Variablen. Ist der Inhalt der
Variablen null, so wird die Warnung "exists" ausgege-
ben, wenn ein Wort redefiniert wird. Ist der Wert nicht
null, so wird die Warnung unterdrückt. Kurioserweise
ist werden die Warnungen also durch WARNING ON
abgeschaltet.
ÄJ
"abort
"cold
'quit
'restart
(quit
status
bye
cold
Glossar III-38 ic) 188
Dr
ın
x
7
a
N
S
»
x
>
&
Sonstiges
(au) "tick-abort"
Dies ist ein deferred Wort, das mit NOOP vorbesetzt
ist. Es wird in ABORT ausgeführt, bevor QUIT aufge-
rufen wird. Es kann benutzt werden, um "automatisch"
selbst definierte Stacks zu löschen.
(--) "tick-cold"
Dies ist ein deferred Wort, das mit NOOP vorbesetzt
ist. Es wird in COLD aufgerufen, bevor die Einschalt-
meldung ausgegeben wird. Es wird benutzt, um Geräte zu
initialisieren oder Anwenderprogramme automatisch zu
starten.
(==) "tick-quit"
Dies ist ein deferred Wort, das normalerweise mit
(QUIT besetzt ist. Es wird in QUIT aufgerufen,
nachdem der Returnstack enleert und der interpretie-
rende Zustand eingeschaltet wurde. Es wird benutzt, um
spezielle Kommandointerpreter (wie z.B. im Tracer)
aufzubauen.
(e—) "tick-restart"
Dies ist ein deferred Wort, das mit NOOP vorbesetzt
ist. Es wird in RESTART aufgerufen, nachdem 'QUIT
mit (QUIT besetzt wurde. Es wird benutzt, um Geräte
nach einem Warmstart zu reinitialisieren.
(--) "paren-quit"
Dieses Wort ist normalerweise der Inhalt von '"QUIT. Es
wird von QUIT benutzt. Es akzeptiert eine Zeile von
der aktuellen Eingabeeinheit, führt sie aus und druckt
"ok" bzw. "compiling".
(--) "dot-status"
Dieses Wort ist ein deferred Wort, das vor dem Einlesen
einer Zeile bzw. dem Laden eines Blocks ausgeführt
wird. Es ist mit NOOP vorbesetzt und kann dazu
benutzt werden, Informationen über den Systemzustand
oder den Quelltext auszugeben.
(==)
Dieses Wort führt FLUSH und EMPTY aus. Anschlies-
send wird der Monitor des Rechners angesprungen oder
eine andere implementationsabhängige Funktion ausge-
führt.
(--)
Bewirkt den Kaltstart des Systems. Dabei werden alle
nach der letzten Ausführung von SAVE definierten
Worte entfernt, die Uservariablen auf den Wert gesetzt,
den sie bei SAVE hatten, die Blockpuffer neu initia-
lisiert, der Bildschirm gelöscht und die Einschaltmel-
dung "volksFORTH-83 rev..." ausgegeben. Anschliessend
wird RESTART ausgeführt.
2) 1322 weibp/re/ks ITI-39 Glossar
end-trace ==)
Schaltet den Tracer ab, der durch "patchen"” der Next-
Routine arbeitet. Die Ausführung des aufrufenden Wortes
wird fortgesetzt.
makeview ( -=.16b) -
Ein deferred Wort, dem mit IS ein Wort zugewiesen
wurde. Dieses Wort erzeugt aus dem gerade kompilierten
Block eine 16b Zahl, die von Create in das vViewfeld
eingetragen wird. Das deferred Wort wird benötigt, um
das Fileinterface rausschmeißen zu können.
next-link ( -- addr )
addr ist die Adresse einer Uservariablen, die auf die
Liste aller Nextroutinen zeigt. Der Assembler erzeugt
bei Verwendung des Wortes NEXT Code, für den ein Zeiger
in diese Liste eingetragen wird. Die so entstandene
Liste wird vom Tracer benutzt, um alle im System
vorhandenen Kopien des Codes für NEXT zu modifizieren.
noop ( u
Tut gar nichts.
xr# ( -- adr ) "r-sharp"
adr ist die Adresse einer Variablen, die den Abstand
des gerade editierten Zeichens vom Anfang des gerade
editierten Screens enthält. Vergleiche (ERROR und
SCR.
restart (=)
Bewirkt den Warmstart des Systems. Es setzt 'QUIT „,
ERRORHANDLER und "ABORT auf ihre normalen Werte und
führt ABORT aus.
scr ( -- adr ) 83 "s-c-r"
adr ist die Adresse einer Variablen, die die Nummer des
gerade editierten Screens enthält. Vergleiche R#
(ERROR und LIST.
»drive
iREE we/ibpfre/hs
0
-
a.
Massenspeicher
( block #drv -- block' )"to-drive"
block' ist die Nummer des Blocks block auf dem Laufwerk
#drv, bezogen auf das aktuelle Laufwerk ( Vergleiche
OFFSET und DRIVE ) . block' kann positiv oder negativ
sein. Beispiel:
23 1 >drive block
holt den Block mit der Nummer 21 vom Laufwerk 1, egal
welches Laufwerk gerade das aktuelle ist.
all-buffers { ==)
Belegt den gesamten Speicherbereich von LIMIT abwärts
bis zum oberen Ende des Returnstacks mit Blockpuffern.
Siehe ALLOTBUFFER .
allotbuffer { ==)
b/blk
b/buf
bik/drv
block
buffer
Fügt der Liste der Blockpuffer noch einen weiteren
hinzu, falls oberhalb vom Ende des Retunstacks dafür
noch Platz ist. FIRST wird entsprechend geändert.
Vergleiche FREEBUFFER und ALL-BUFFERS .
( -- &1024 ) . "bytes pro block"
Die Länge eines Blocks (bzw. Screens, immer 1 KByte)
wird auf den Stack gelegt. Siehe B/BUF .
(--n) "bytes pro buffer"
n ist die Länge eines Blockpuffers incl. der Verwalt-
ungsinformationen des Systens.
(-n) ? "blocks pro drive"
n ist die Anzahl der auf dem aktuellen Laufwerk
verfügbaren Blöcke.
(u-- addr ) 83
addr ist die Adresse des ersten Bytes des Blocks u in
dessen Blockpuffer. Der Block u stammt aus dem File in
ISFILE . BLOCK prüft den Pufferbereich auf die Existenz
des Blocks Nummer u. Befindet sich der Block u in
keinem der Blockpuffer, so wird er vom Massenspeicher
in einen an ihn vergebenen Blockpuffer geladen. Falls
der Block in diesem Puffer UPDATEd ,„ wird er auf den
Massenspeicher gesichert, bevor der Blockpuffer an den
Block u vergeben wird. Nur die Daten im letzten Puffer,
der über BLOCK oder BUFFER angesprochen wurde, sind
sicher zugreifbar. Alle anderen Blockpuffer dürfen
nicht mehr als gültig angenommen werden
{ möglicherweise existiert nur 1 Blockpuffer ). Vor-
sicht ist bei Benutzung des Multitaskers geboten, da
eine andere Task BLOCK oder BUFFER ausführen kann.
Der Inhalt eines Blockpuffers wird nur auf den Massen-
speicher gesichert, wenn der Block mit UPDATE als
verändert gekennzeichnet wurde.
(u--adr ) 83
Vergibt einen Blockpuffer an den Block u. addr ist die
Adresse des ersten Bytes des Blocks in seinem Puffer.
ic) IS2E weibp/re/ks III-41 Glossar
convey
copy
core?
drive
drv?
Dieses Wort entspricht BLOCK ,„ jedoch mit der Aus-
nahme, das, wenn der Block noch nicht im Speicher ist,
er nicht vom Massenspeicher geholt wird. Daher ist der
Inhalt dieses Blockpuffers undefiniert.
( 1st.block last.block to.blk -- )
Verschiebt die Blöcke von 1st.blk bis last.blk ein-
schließlich nach to.blk folgende. Die Bereiche dürfen
sich überlappen. Eine Fehlerbehandlung wird eingelei-
tet, wenn last.blk kleiner als i1st.blk ist.
Die Blöcke werden aus dem File in FROMFILE ausgelesen
und in das File in ISFILE geschrieben. FROMFILE und
ISFILE dürfen gleich sein.
Beispiel :
46 5 convey
kopiert die Blöcke 4,5,6 nach 5,6,7. Der alte Inhalt
des Blockes 7 ist verloren, der Inhalt der Blöcke 4 und
5 ist gleich.
(wuuwn2--)
Der Block ul wird in den Block u2 kopiert. Der alte
Inhalt des Blocks u2 ist verloren. Vergleiche auch
CONVEY
( bIk file -- addr/false )"core-question"
Prüft, ob sich der Block blk des Files file in einem
der Blockpuffer befindet und liefert dann die Adresse
addr des ersten Datenbytes. Befindet sich der Block
nicht im Speicher, so wird false als Ergebnis gelie-
£fert. Vergleiche BLOCK ,„ BUFFER und ISFILE
(#drv -- )
Selektiert das Laufwerk mit der Nummer #drv als
aktuelles Laufwerk. 0 BLOCK liefert die Adresse des
ersten Blocks auf dem aktuellen Laufwerk. Vergleiche
>DRIVE und OFFSET.
( block -- #drv ) "drive-question"
#drv ist die Nummer des Laufwerks auf dem sich der
Block block befindet. Vergleiche OFFSET >DRIVE und
DRIVE.
empty-buffers ( Sa)
first
£flush
Löscht den Inhalt aller Blockpuffer. UPDATEd Block-
puffer werden nicht auf den Massenspeicher zurückge-
schrieben.
( -- addr )
addr ist die Adresse einer Variablen, in der sich ein
Zeiger auf den Blockpuffer mit der niedrigsten Adresse
befindet. Vergleiche ALLOTBUFFER
(„= )) 83
Sichert alle UPDATEd Blocks auf den Massenspeicher
und löscht dann alle Blockpuffer. Vergleiche SAVE-
BUFFERS und EMPTY-BUFFERS .
(2) iS2E we/be/re/ks
freebuffer (--
Entfernt den Blockpuffer mit der niedrigsten Adresse
aus der Liste der Blockpuffer und gibt den dadurch
belegten Speicherbereich frei. FIRST wird entspre-
chend verändert (um B/BUF erhöht). Ist der Inhalt des
Puffers UPDATEd ,„ so wird er zuvor auf den Massen-
speicher gesichert. Gibt es im System nur noch einen
Blockpuffer, so geschieht nichts. Vergleiche
ALLOTBUFFER .
£fromfile ( -- adr )
isfile
limit
offset
prev
r/w
adr ist die Adresse einer Variablen, deren Wert die
Nummer eines Files ist, aus dem CONVEY und COPY die
Blöcke auslesen, um sie in das File, das in ISFILE
steht, zu kopieren. Siehe das Kapitel zum Fileinterface
( -- addr )
adär ist die Adresse einer Uservariablen, deren Wert
die Nummer des aktuellen Files, auf das sich alle
Massenspeicheroperationen beziehen, ist. Typisch ent-
spricht die Nummer eines Files der Adresse seines File
Control Blocks. Ist der Wert von FILE Null, so wird
direkt, ohne ein File, auf den Massenspeicher (z.B. die
Sektoren einer Diskette) zugegriffen. Siehe das Kapitel
zum Fileinterface.
( -- addr )
Unterhalb von addr befinden sich die Blockpuffer. Das
letzte Byte des obersten Blockpuffers befindet sich in
adär-1. Vergleiche ALL-BUFFERS ALLOTBUFFER
( -- addr )
addr ist die Adresse einer Uservariablen, deren Inhalt
zu der Blocknummer addiert wird, die sich bei Aufruf
von BLOCK BUFFER usw. auf dem Stack befindet. OFFSET
wird durch DRIVE verändert.
( -- addr )
addr ist die Adresse einer Variablen, deren Wert der
Anfang der Liste aller Blockpuffer ist. Der erste
Blockpuffer in der Liste ist der zuletzt durch BLOCK
oder BUFFER vergebene.
( addr block file n -- flag )"r-w"
Ein deferred Wort, bei dessen Aufruf das system-
abhängige Wort ausgeführt wird, das einen Block vom
Massenspeicher holt. Dabei ist addr die Anfangsadresse
des Speicherbereichs für den Block block, file die
Filenummer des Files, in dem sich der Block befindet
und n=0, falls der Block vom Speicherbereich auf den
Massenspeicher geschrieben werden soll. Ist n=1, so
soll der Block vom Massenspeicher in den Speicherber-
eich gelesen werden. Das flag ist Falsch, falls kein
Fehler auftrat, sonst Wahr.
(2) S2E we/ibp/re/iks III-43 Glossar I
save-buffers (--) 83
update
Sichert alle als UPDATEd gekennzeichneten Blöcke aus
den Blockpuffern auf den Massenspeicher. Das UPDATE -
Kennzeichen wird für alle Blöcke zurückgesetzt, die
Blöcke werden jedoch nicht verändert und bleiben für
weitere Zugriffe im Speicher erhalten.
(==) 83
Der zuletzt mit BLOCK BUFFER usw. zugegriffene Block
wird als verändert gekennzeichnet. Blöcke mit solcher
Kennzeichnung werden auf den Massenspeicher zurückge-
schrieben, wenn ihr Blockpuffer für einen anderen Block
benötigt oder wenn SAVE-BUFFERS ausgeführt wird. Ver-
gleiche PREV.
Be: bee
I Glossar E III-44 (23 1536 werbp/rerts
3
Atari ST - spezifische Worte
#col ( -- addr ) "number-col"
addr ist die Adresse einer Variablen, die die Nummer
der aktuellen Cursorzeile enthält.
#esc (NM) "number-escape"
n ist der Ascii-Wert für Escape.
#1£ (= An.) "number-linefeed"
n ist der Ascii-Wert für Linefeed.
#row ( -- addr ) "number-row"
addr ist die Adresse einer Variablen, die die Nummer
der aktuellen Cursorspalte enthält.
bconin ( dev# -- char ) "b-con-in"
char ist ein Zeichen, das vom Gerät mit der Nummer dev#
eingelesen wird. BCONIN wartet (und hängt dadurch),
bis ein Zeichen bereitsteht. Typische Gerätenummern
sind: &
0O PRT; Centronics-Schnittstelle (Druckerport)
1 AUX; RS232-Schnittstelle
2 CON; Tastatur und Bildschirm
3 MIDI; Midi-Schnittstelle
4 IKBD; Tastatur-Port
Gerätenummer 4 ist bei dieser Funktion nicht erlaubt.
bconout ( char dev# -- ) "b-con-out"”
char ist ein Zeichen, das an das Gerät mit der Nummer
dev# ausgegeben wird. BCONIN wartet (hängt), bis das
Zeichen ausgegeben wurde. Die Gerätenummern sind die
gleichen wie bei BCONIN . Alle Gerätenumnern sind
erlaubt.
bceonstat ( dev# -- flag ) "b-con-stat"
flag ist TRUE, wenn ein Zeichen auf dem Gerät mit der
Nummer dev# bereitsteht. Sonst ist flag = FALSE. Die
Gerätenummern sind die gleichen wie bei BCONIN . Die
Gerätenummern 0 und 4 sind bei dieser Funktion nicht
erlaubt.
bceostat ( dev# -- flag ) "b-co-stat”
flag ist TRUE, wenn das Gerät mit der Nummer dev#
bereit ist, ein Zeichen zu empfangen. Sonst ist
flag = FALSE. Die Gerätenummern sind die gleichen wie
bei BCONIN . Alle Gerätenummern sind bei dieser
Funktion erlaubt.
con! (8b --) "con-store"
gibt 8b auf die CONsolie (Bildschirm) aus. Ascii-
Werte < $20 werden als Steuercodes interpretiert.
curleft (u)
setzt den Cursor um eine Spalte nach links.
curof£f (--)
schaltet den Cursor aus.
curon
currite
display
drvo
drvil
drvinit
getkey
keyboard
rwabs
STat
STat?
STcer
2} 152E we/ibp/re/ks III-45
Glossar
=)
schaltet den Cursor ein.
sn)
setzt den Cursor um eine Spalte nach rechts.
(a)
ein mit OUTPUT: definiertes Wort, das den Bildschirm
als Ausgabegerät setzt, wenn es ausgeführt wird. Die
Worte EMIT , CR, TYPE, DEL, PAGE, AT und AT?
beziehen sich dann auf den Bildschirm.
(--)
Kurzform für 0 DRIVE .
Das Laufwerk 0 (bzw. A) wird als aktuelles Laufwerk
selektiert. Siehe DRIVE.
ee)
Wie DRVO.
( ==)
Ein Wort, das von RESTART ausgeführt wird. Dieses Wort
kann dazu verwendet werden, Floppycontroller, Files
o.Ä. zu initialieren.
(--n)
die unteren 7 Bit von n enthalten den Ascii-Code, die
unteren 8 Bit den ANSI-Code (Ach Nein! Sch... IBM) des
nächsten Tastendrucks, die oberen 8 Bit den Tastatur-
Scancode. War keine Taste gedrückt, istn = FALSE .
(Vergleiche KEY? und KEY bzw. STKEY? und STKEY .)
( ==)
ein mit INPUT: definiertes Wort, das die Tastatur als
Eingabegerät setzt. Die Worte KEY, KEY? , DECODE
und EXPECT beziehen sich auf die Tastatur. Siehe
STKEY , STKEY? , STDECODE und STEXPECT
( xr/w£f addr rec# -- flag ) "r-w-abs"
Ist r/w£ = TRUE, wird ein Block Daten ($400 bzw. &1024)
Bytes vom Disketten-Sektor mit der Nummer rec# nach
addr gelesen. Ist r/w£ = FALSE, werden Daten von addr
auf die Diskette geschrieben. Diese Routine wird von
STR/W benutzt.
( row col ==) "s-t-at"
positioniert den Cursor in die Zeile row und die Spalte
col. Ein Fehler liegt vor, wenn row > $18 (&24) oder
col >'$40 (&64) ??? ist. Vergleiche AT.
( -- row col ) "s-t-at-question"”
row ist die aktuelle Zeilennummer des Cursors, col die
aktuelle Spaltennummer. Vergleiche AT?
( Le ) "s-t-c-r"
setzt den Cursor in die erste Spalte der nächsten
Zeile. Ein PAUSE wird ausgeführt.
STdäecode
sTdel
STemit
STexpect
STkey
STkey?
STpage
STr/w
III-46 (23 BEE weibpirerks
( addr posi key -- addr pos2 ) "s-t-decode"
wertet key aus. key wird in der Speicherstelle
addr+posi1 abgelegt und als Echo auf dem Bildschirm
ausgegeben. Die Variable SPAN und pos werden inkre-
mentiert. Folgende Tasten werden besonders behandelt:
Cursor rechts und Cursor links beeinflussen nur posl
und den Cursor. Delete löscht das Zeichen unter dem
Cursor und dekrementiert SPAN . Backspace löscht das
Zeichen links vom Cursor und dekrementiert posil und
SPAN . Insert fügt an der Cursorposition ein Leer-
zeichen ein. SPAN wird inkrementiert. Return positio-
niert den Cursor auf das letzte Zeichen. Vergleiche
INPUT: und STexpect .
( -- ) "s-t-del”
löscht ein Zeichen links vom Cursor. Vergleiche DEL
(8b -- ) "s-t-emit"
gibt 8b auf dem Bildschirm aus. Ein PAUSE wird
ausgeführt. Alle Werte werden als Zeichen ausgegeben,
Steuercodes sind nicht möglich, d. h. alle Werte < $20
werden als ATARI-Spezifische Zeichen ausgegeben. Ver-
gleiche CON! und EMIT.
( addr len -- ) "s-t-expect"
erwartet len Zeichen vom Eihgabegerät, die ab addr im
Speicher abgelegt werden. Ein Echo der Zeichen wird
ausgegeben. Return beendet die Eingabe vorzeitig. Ein
abschließendes Leerzeichen wird immer ausgegeben. Die
Länge der Zeichenkette wird in der Variablen SPAN
übergeben. Vergleiche EXPECT .
( -- 16b ) "s-t-key"
wartet auf einen Tastendruck. Während der Wartezeit
wird PAUSE ausgeführt. Die unteren 7 Bit von 16b
enthalten. den Ascii-Code, die unteren 8 Bit den ANSI-
Code der Taste, die oberen 8 Bit den Tastatur-Scancode.
Steuerzeichen werden nicht ausgewertet, sondern unver-
ändert abgeliefert. Vergleiche KEY.
( -- Elag ) "s-t-key-question"
flag ist TRUE, wenn eine Taste gedrückt wurde, sonst
FALSE . Vergleiche KEY? .
{“-—-?) "s-t-page"
löscht den Bildschirm und positioniert den Cursor in
die linke obere Ecke. Vergleiche PAGE
( adr bIMk r/w file -- £ ) "s-t-r-w"
liest oder schreibt einen Block Daten ($400 oder &1024
Bytes) vom Diskettenblock blk nach adr bzw. von adr auf
den Block blilk. Ist r/w falsch, so werden die Daten von
der Adresse adr geschrieben, ist r/w wahr, so werden
sie nach Adresse adr gelesen. STR/W ermittelt das
Laufwerk, auf dem sich der Block blk befindet.
file ist die Nummer eines Files, dem der zu bearbei-
tende Block entstammt. file muß Null sein, da dieses
Wort nicht mit Files arbeiten kann !
(23 1828 Wweibo/re/ks TEL-47 Glossar |
( addr len -- ) i
gibt den String, der im Speicher bei addr beginnt und
die Länge len hat, auf dem Bildschirm aus. Ein PAUSE
wird ausgeführt. Vergleiche TYBEs ,, OUTPUT: und
STEMIT .
activate
lock
f
(23 BEE weibp/reihs |
at
Multitasking
( Tadr -- usradr ) I "tick-s"
wird benutzt in der Form:
.. <taskname> 's <username> ...
'S liest den Namen einer USERvariablen <username> und
hinterläßt die Adresse usradr dieser USERvariablen in
der durch Tadr gekennzeichneten Task. Typisch wird Tadr
durch Ausführung von <taskname> erzeugt. Eine Fehler-
bedingung liegt vor, wenn <(username> nicht der Name
einer USERvariablen ist. Vergleiche USER und TASK
5 ist für den Zugriff auf USERvariablen einer Task
durch eine andere Task vorgesehen.
( Tadr -- )
aktiviert die Task, die durch Tadr gekennzeichnet ist,
und weckt sie auf. Vergleiche SLEEP ,„ STOP ,„ PASS,
PAUSE „Ä UP@, UP! und WAKE
( semadr -- )
Der Semaphor (eine VARIABLE ), dessen Adresse auf dem
Stack liegt, wird von der Task, die LOCK ausführt,
blockiert. Dazu prüft LOCK den Inhalt des Semaphors.
Zeigt der Inhalt an, daß eine andere Task den Semaphor
blockiert hat, so wird PAUSE ausgeführt, bis der
Semaphor freigegeben ist. Ist der Semaphor freigegeben,
so schreibt LOCK das Kennzeichen der Task, die LOCK
ausführt, in den Semaphor und sperrt ihn damit für alle
anderen Tasks. Den FORTH-Code zwischen semadr LOCK ...
und ... semadr UNLOCK kann also immer nur eine Task zur
Zeit ausführen. Semaphore schützen gemeinsam benutzte
Geräte (z.B. den Drucker} vor dem gleichzeitigen
Zugriff durch verschiedene Tasks. Vergleiche UNLOCK ,
RENDEZVOUS und die Beschreibung des Taskers.
multitask { ==
pass
pause
)
schaltet das Multitasking ein. Das Wort PAUSE ist
dann keine NOOP -Funktion mehr, sondern gibt die
Kontrolle über die FORTKE-Maschine an eine andere Task
weiter.
(no .. n-ı Tadrr --)
aktiviert die Task, die durch Tadr gekennzeichnet ist,
und weckt sie auf. r gibt die Anzahl der Parameter no
bis nr-ı an, die vom Stack der PASS ausführenden Task
auf den Stack der durch Tadr gekennzeichneten Task
übergeben werden. Die Parameter no bis Nnr-ı stehen
dieser Task dann in der gleichen Reihenfolge auf ihrem
Stack zur weiteren Verarbeitung zur Verfügung. Ver-
gleiche ACTIVATE
==)
ist eine NOOP -Funktion, wenn der Singletask-Betrieb
eingeschaltet ist; bewirkt jedoch, nach Ausführung von
MULTITASK ,Ä daß die Task, die PAUSE ausführt, die
Kontrolle über die FORTH-Maschine an eine andere Task
abgibt. Existiert nur eine Task, oder schlafen alle
anderen Tasks, so wird die Kontrolle unverzüglich an
die Task zurückgegeben, die PAUSE ausführte. Ist
FÜRTH
(ce) 15856 we/bp/re/ks III-49
Glossar
mindestens eine andere Task aktiv, so wird die Kon-
trolle von dieser übernommen und erst bei Ausführung
von PAUSE oder STOP in dieser Task an eine andere
Task weitergegeben. Da die Tasks ringförmig miteinander
verkettet sind, erhält die Task, die zuerst PAUSE
ausführte, irgendwann die Kontrolle zurück. Eine
Fehlerbedingung liegt vor, wenn eine Task weder PAUSE
noch STOP ausführt. Vergleiche STOP „ MULTITASK
und SINGLETASK
rendezvous ( semadr -- )
gibt den Semaphor (die VARIABLE ) mit der Adresse
semadr frei (siehe UNLOCK ) und führt PAUSE aus, um
anderen Tasks den Zugriff auf das, durch diesen Sema-
phor geschützte, Gerät zu ermöglichen. Anschließend
wird LOCK ausgeführt, um das Gerät zurück zu erhal-
ten.
singletask (Fr
sleep
stop
Task
)
schaltet das Multitasking aus. PAUSE ist nach Aus-
führung von SINGLETASK eine NOOP -Funktion. Eine
Fehlerbedingung besteht, wenn eine Hintergrund-Task
SINGLETASK ohne anschließendes MULTITASK ausführt,
da die Main- oder Terminal-Task dann nie mehr die
Kontrolle bekommt. Vergleiche UP@ und UP! .
( Tadr -- )
bringt die Task, die durch Tadr gekennzeichnet ist, zum
Schlafen. SLEEP hat den gleichen Effekt, wie die
Ausführung von STOP durch die Task selbst. Der
Unterschied ist, daß STOP in der Regel am Ende des
Jobs der Task ausgeführt wird, SLEEP trifft die Task
zu einem nicht vorhersehbaren Zeitpunkt, so daß die
laufende Arbeit der Task abgebrochen wird. Vergleiche
WARE .
(ee)
bewirkt, daß die Task, die STOP ausführt, sich
schlafen legt. Wichtige Zeiger der FORTH-Maschine, die
den Zustand der Task kennzeichnen, werden gerettet,
dann wird die Kontrolle an die nächste Task abgegeben,
deren Zeiger wieder der FORTH-Maschine übergeben wer-
den, so daß diese Task ihre Arbeit an der alten Stelle
aufnehmen kann. PAUSE führt diese Aktionen ebenfalls
aus, der Unterschied zu STOP ist, daß die ausführende
Task bei PAUSE aktiv, bei STOP hingegen schlafend
hinterlassen wird. Vergleiche PAUSE , WAKE und
SLEEP .
( rlen slen -- )
ist ein definierendes Wort, das in der Form:
rlen slen Task <cccc>
benutzt wird. TASK erzeugt einen Arbeitsbereich für
einen weiteren Job, der gleichzeitig zu schon laufenden
Jobs ausgeführt werden soll. Die Task erhält den Namen
ccecc, hat einen Stack-Bereich der Länge slen und einen
Returnstack-Bereich der Länge rlen. Im Stack-Bereich
liegen das Task-eigene Dictionary einschließlich PAD,
das in Richtung zu höheren Adressen wächst, und der
|
Glossar E III-50 2) HREB werbp/rerks
tasks
unlock
up®@
up!
wake
eh
Daten-Stack, der zu niedrigen Adressen wächst. Im
Returnstack-Bereich befinden sich die Task-eigene USER-
Area (wächst zu höheren Adressen) und der Returnstack,
der gegen kleinere Adressen wächst. Eine Task ist ein
verkleinertes Abbild des FORTH-Systems, allerdings ohne
den Blockpuffer-Bereich, der von allen Tasks gemeinsam
benutzt wird. Zur Zeit ist es nicht zugelassen, daß
Jobs einer Hintergrundtask kompilieren. Die Task ist
nur der Arbeitsbereich für einen Hintergrund-Job, nicht
jedoch der Job selbst.
Die Ausführung von cccc in einer beliebigen Task
hinterläßt die gleiche Adresse, die die Task cccc
selbst mit UP@ erzeugt und ist zugleich die typische
Adresse, die von LOCK , UNLOCK und RENDEZVOUS im
Zusammenhang mit Semaphoren verwendet wird, bzw. von
Do: ACTIVATE , PASS ,Ä„ SLEEP und WAKE erwartet
wird.
ES)
listet die Namen aller eingerichteten Tasks und zeigt,
ob sie schlafen oder' aktiv sind.
( semadr -- )
gibt den Semaphor (die VARIABLE ), dessen Adresse auf
dem Stack ist, für alle Tasks frei. Ist der Semaphor im
Besitz einer anderen Task, so wartet UNLOCK mit
PAUSE auf die Freigabe. Vergleiche LOCK und die
Beschreibung des Taskers.
( -- Tadr ) "u-p-fetch"
liefert die Adresse Tadr des ersten Bytes der USER-Area
der Task, die UP@ ausführt. Siehe TASK . In der
USER-Area sind Variablen und andere Datenstrukturen
hinterlegt, die jede Task für sich haben muß. Ver-
gleiche UP! .
( adr --) "uU=-p-store"
richtet den UP (User Pointer) der FORTH-Maschine auf
adr. Vorsicht ist bei der Verwendung von up! in
Hintergrund-Tasks geboten. Vergleiche UP@ .
( Tadr -- )
weckt die Task, die durch Tadr gekennzeichnet ist, auf.
Die Task führt ihren Job dort weiter aus, wo sie durch
SLEEP angehalten wurde oder wo sie sich selbst durch
STOP beendet hat (Vorsicht!). Vergleiche SLEEP „,
STOP , „a ACTIVATE und PASS
#bs
(23 IEE we/bp/re/ks TTT=51 Glossar
Input und Output Worte
(5) "number-b-s"
n ist der Wert, den man durch KEY erhält, wenn die
Backspace-Taste gedrückt wird.
#cr (--n) "number-c-r"
n ist der Wert, den man durch KEY erhält, wenn die
Return- (Enter-) Taste gedrückt wird.
#tib { -- ade) 83 "number-t-i-b"
adr ist die Adresse einer Variablen, die die Länge des
aktuellen Textes im Text-Eingabe-Puffer enthält. Ver-
gleiche TIB
-trailing ( adr +nO -- adr +n1) 83 "minus-trailing"
adr ist die Anfangsadresse und +n0O die Länge eines
Strings. -TRAILING verändert +nO so zu +nl, daß even-
tuell am Ende vorhandene Leerzeichen nicht mehr in der
Stringlänge +nl1 enthalten sind. Der String selbst
bleibt unangetastet. Ist +nO = 0 oder besteht der ganze
String aus Leerzeichen, so ist +ni = 0.
h (n-) 83 "dot"
n wird vorzeichenbehaftet ausgegeben.
Fu (--) 83. /InC« "Wdot-quote"
(==) compiling
wird in :-Definitionen in der Form verwendet:
Sexnane> all süiccecee! wu 3
Der String cccc wird bis zum abschließenden " so
kompiliert, daß bei Ausführung von <name> der String
cccc ausgedruckt wird. Das Leerzeichen nach ." und das
abschließende " sind Pflicht und gehören nicht zum
String.
At (--) 83 I "dot-paren"
(—-) compiling
wird in der Form :
S,kerlnccce) 73
benutzt und druckt den String cccc bis zur
abschließenden Klammer sofort aus. Das Leerzeichen nach
.( und die schließende Klammer werden nicht mit ausge-
druckt.
ER (n+tn --) "Sst-r"
druckt die Zahl n in einem +n Zeichen langen Feld mit
Vorzeichen rechtsbündig aus. Reicht +n nicht zur
Darstellung der Zahl aus, so wird über den rechten Rand
hinaus ausgegeben. Die Zahl n wird in jedem Fall
vollständig dargestellt.
»tib ( eradr®) "to-tib"
adr ist die Adresse eines Zeigers auf den Text-Eingabe-
Puffer. Siehe TIB
Glossar
fer
at
at?
bl
e/l
col
cr
decimal
decode
11I-52 (23 1928 weibp/re/ihe
( ==) "question-c-r"
prüft, ob in der aktuellen Zeile mehr als C/L Zeichen
ausgegeben wurden und führt in diesem Fall CR aus.
( row col -- )
positioniert die Schreibstelle des Ausgabegerätes in
die Zeile row und die Spalte col. AT ist eines der über
OUTPUT vektorisierten Worte. Siehe AT?
( -- row col ) "at-question"
ermittelt die aktuelle Position der Schreibstelle des
Ausgabegerätes und legt Zeilen- und Spaltennummer auf
den Stack. Eines der OUTPUT-Worte.
{ -- adr ) 83 U
adr ist die Adresse einer Uservariablen, die die
Zahlenbasis enthält, die zur Wandlung von Zahlenein-
und -ausgaben benutzt wird.
( == m) "H-]"
n ist der ASCII-Wert für ein Leerzeichen.
( -- tn) "characters-per-line"
+n ist die Anzahl der Zeichen pro Screenzeile. Aus
historischen Gründen ist dieser Wert &64 bzw. $40 .
(-- +n)
+n ist die Spalte in der sich die Schreibstelle des
Ausgabegerätes gerade befindet. Vergleich ROW und AT?
(s„s#r) 83 NEHEN
bewirkt, daß die Schreibstelle des Ausgabegerätes an
den Anfang der nächsten Zeile verlegt wird. Eines der
OUTPUT-Worte.
da=-) "d-dot"
druckt d vorzeichenbehaftet aus.
(d+tn --) "a-dot-r"
druckt d vorzeichenbehaftet in einem +n Zeichen breiten
Feld rechtsbündig aus. Reicht +n nicht zur Darstellung
der Zahl aus, so wird über den rechten Rand des Feldes
hinaus ausgegeben. Die Zahl d wird in jedem Fall
vollständig dargestellt.
(--)
stellt BASE auf den Wert $CA bzw. &10 ein. Alle
Zahlenein- und -ausgaben erfolgen nun im dezimalen
System.
( adr +nO key -- adr +nl )
wertet key aus. Typisch werden normale druckbare ASCII-
Zeichen in die Speicherstelle adr + +nO übertragen, als
Echo zum Ausgabegerät gesandt und +nO inkrementiert.
Andere Zeichen ( #BS #CR Steuercodes) können andere
Aktionen zur Folge haben. Eines der über INPUT vektori-
sierten Worte. Wird von EXPECT benutzt. Siehe STDECODE
(<>
328 we/bp/rerks III-53 Glossar
emit
expect
hex
input
key
key?
list
1/s
ouput
(re)
löscht das zuletzt ausgegebene Zeichen. Eines der
OUTPUT-Worte. Bei Druckern ist die korrekte Funktion
nicht immer garantiert.
(„16b :--») 83
die unteren 8 Bit werden an das Ausgabegerät ausgege-
ben. Ist das Zeichen nicht druckbar (insbesondere
Steuercodes), so wird ein Punkt ausgegeben. Eines der
GUTPUT-Worte.
( adr tn -- ) 83
empfängt Zeichen und speichert sie ab Adresse adr im
Speicher. Die Übertragung wird beendet, bis ein #CR
erkannt oder +n Zeichen übertragen wurden. Ein #CR wird
nicht mit abgespeichert. Ist tn = 0 ,„ so werden keine
Zeichen übertragen. Alle Zeichen werden als Echo, statt
#CR wird ein Leerzeichen ausgegeben. Eines der INPUT-
Worte. Vergleiche SPAN
(==)
stellt BASE auf $10 bzw. &16 . Alle Zahlenein- und -
ausgaben erfolgen im hexadezimalen Zahlensysten.
( -- adr ) U
adr ist die Adresse einer Uservariablen, die einen
Zeiger auf ein Feld von vier Kompilationsadressen
enthält, die für ein Eingabegerät die Funktionen KEY
KEY? DECODE und EXPECT realisieren. Vergleiche die
gesonderte Beschreibung der INPUT- und OUTPUT-Struktur.
( -- 16b ) 83
empfängt ein Zeichen vom Eingabegerät. Die
niederwertigen 8 Bit enthalten den ASCII-Code des
zuletzt empfangenen Zeichens. Alle gültigen ASCII-Codes
können empfangen werden. Die oberen 8 Bit enthalten
systemspezifische Informationen. Es wird kein Echo
ausgesandt. KEY wartet, bis tatsächlich ein Zeichen
empfangen wurde. Eines der INPUT-Worte.
( -- flag ) "key-question"
flag ist TRUE falls ein Zeichen zur Eingabe
bereitsteht, sonst ist flag FALSE. Eines der INPUT-
Worte.
(u--) 83
zeigt den Inhalt des Screens u auf dem aktuellen
Ausgabegerät an. SCR wird auf u gesetzt. Siehe BLOCK.
( -- #n) "lines-per-screen"
+n ist die Anzahl der Zeilen pro Screen.
(-- adr ) u
adr ist die Adresse einer Uservariablen, die einen
Zeiger auf sieben Kompilationsadressen enthält, die für
ein Ausgabegerät die Funktionen EMIT CR TYPE DEL
PAGE AT und AT? realisieren. Vergleiche die geson-
derte Beschreibung der Ouput-Struktur.
I iH2E we/bp/re/ins
bewirkt, daß die Schreibstelle des Ausgabegerätes auf
eine leere neue Seite bewegt wird. Eines der OUTPUT-
Worte.
query k ==) 83
Zeichen werden von einem Eingabegerät geholt und in den
Text-Eingabe-Puffer übertragen, der bei TIB beginnt.
Die Übertragung endet beim Empfang von #CR oder wenn
die Länge des Text-Eingabe-Puffers erreicht wird. Der
Inhalt von >IN und BLK wird zu 0 gesetzt und #TIB
enthält die Zahl der empfangenen Zeichen. Um Text aus
dem Puffer zu lesen, kann WORD benutzt werden. Siehe
EXPECT.
row (>==-#+1>)
+n ist die Zeile, in der sich die Schreibstelle des
Ausgabegerätes befindet, Vergleiche COL und AT?
space (--) 83
sendet ein Leerzeichen an das Ausgabegerät.
spaces (HN == ) 83
sendet +n Leerzeichen an das Ausgabegerät.
span ( -- aär ) 83
Der Inhalt der Variablen SPAN gibt an, wieviele Zeichen
vom letzten EXPECT übertragen wurden. Siehe EXPECT .
standardi/o es) "standard-i-o"
stellt sicher, daß die beim letzten SAVE bestimmten
Ein- und Ausgabegeräte wieder eingestellt sind.
stop? ( == flag) "stop-question"
Ein komfortables Wort, das es dem Benutzer gestattet,
einen Programmablauf anzuhalten oder zu beenden. Steht
vom Eingabegerät ein Zeichen zur Verfügung, so wird es
eingelesen. Ist es #ESC oder CTRL-C ,„ so ist flag
TRUE, sonst wird auf das nächste Zeichen gewartet. Ist
dieses jetzt #ESC oder CTRL-C „ so wird STOP? mit
TRUE verlassen, sonst mit FALSE . Steht kein Zeichen
zur Verfügung, so ist flag FALSE .
tib ( -- adr ) 83
liefert die Adresse des Text-Eingabe-Puffers. Er wird
benutzt, um die Zeichen vom Quelltext des aktiven
Gerätes zu halten. Siehe >TIB .
type ( adr +tn --) 83
sendet +n Zeichen, die ab adr im Speicher abgelegt
sind, an ein Ausgabegerät. Ist +tn = 0 „ so wird nichts
ausgegeben.
u. (u--) "u-dot"
die Zahl u wird vorzeichenlos ausgegeben.
xy I32E ve/bp/ire/hz III-55
( u $n,=#) "u-dot-r"
die Zahl u wird vorzeichenlos rechtsbündig in einem
Feld der Breite +n ausgegeben. Reicht +n zur Darstel-
lung von u nicht aus, so wird über den rechten Rand
hinaus ausgegeben.
023 i
in
yr
we/ibp/refhz
Erweiterte Adressierung
Auf den modernen Rechnern stehen zumeist mehr als 64 Kbyte
Speicher zur Verfügung. Forth ist gewöhnlich auf einen Adreßbe-
reich von 64 Kbyte beschränkt, da die Stacks nur 16 Bit breit
sind. Daher kann Forth zunächst nicht sehr gut mit den 32Bit
Adressen, die für solche Betriebssysteme erforderlich sind,
umgehen.
Das Forth wird bei diesen Betriebssystemen normalerweise nicht
an den Anfang des Speichers geladen. Da die meisten Operationen
nur 16Bit Adressen verarbeiten (wie |! @ TYPE COUNT usw.),
zählen sie diese Adressen ab dem Anfang des Forthsystens.
Die folgenden Operationen verarbeiten dagegen absolute 32Bit
Adressen.
forthstart ( -- laddr )
laddr ist die (erweiterte) Anfangsadresse des Forth-
systems im Speicher des Rechners. d.h.
forthstart 1@ und
0@
lesen dieselbe Speicherzelle aus.
1! ( 16b laddr -- ) " long-store "
16b werden in den Speicher ab Adresse laddr geschrieben.
Im Gegensatz zu ! wird bei dieser Operation die Adresse
ab dem Anfang des Speichers und nicht ab dem Anfang des
Forthsystems gezählt. Siehe ! und FORTHSTART
12} ( 32b laddr -- ) " long-two-store "
Analog zu L! ,„ jedoch werden 32b geschrieben.
12@ { laddr -- 32b ) " long-two-fetch "
Analog zu L@ ,„ jedoch werden 32b gelesen.
1@ ( laddr -- 16b ) " long-fetch "
16b wurden aus dem Speicher ab Adresse laddr gelesen. Im
Gegensatz zu ! wird bei dieser Operation die Adresse ab
dem Anfang des Speichers und nicht ab dem Anfang des
Forthsystems gezählt. Siehe @ und FORTHSTART.
lc! ( 8b ladär -- ) " long-c-store "
Analog zu L! ,„ jedoch werden 8b geschrieben.
1c@ ( 8b laddr -- ) " long-c-fetch "
Analog zu L@ ,„ jedoch werden 8b gelesen.
lcmove ( laddri laddr2 u -- ) " long-cmove "
Beginnend bei Adresse laddri werden u Bytes zur Adresse
laddr2 kopiert. Wenn u Null ist, wird nichts kopiert.
Siehe L! und CMOVE .
In+! (wladdr -- ) " 1-n-plus-store "
w wird zu dem Wert in der Adresse laddr addiert. Benutzt
die + Operation. Die Summe wird in die Adresse ab laddr
geschrieben. Siehe L! und +!
und
FÜRTH
(23 15EE We/bp/ire/hs III-57 Glossar
ei Br
=
!1 Glossar E I1I-58 2) HBEE Oo We/bp/re/ks
(23 1826 we/bp/re/ts I1I-59
Wortname Sa Gruppe
! III-8 Speicher
r ISII-15 Strings
# III-15 Strings
#> TII->15 Strings
#addrin A-4 GEM
#addrout A-4 GEM
#bs III-51 In/Output
#col III-44 ST-spezifisch
#cr III-51 In/Output
#tesc III-44 ST-spezifisch
#intin A-4 GEM
#intout A-4 GEM
#1£ III-44 ST-spezifisch
#row III-44 ST-spezifisch
#s 11i-15 Strings
#tib III-51 In/Output
Sadd Strings
$Ssum Strings
® I1I-22 Dictionary
"abort III-38 Sonstiges
"cold T1I=-38 Sonstiges
"quit III-38 Sonstiges
'restart I21-38 Sonstiges
is III-48 Tasking
{ ITI-33 Interpreter
(error III-36 Fehler
(forget LI1522 Dictionary
(more Fileinterface
(quit III-38 Sonstiges
* III-3 Arithmetik
*/ TTTS3 Arithmetik
*/mod III-3 Arithmetik
+ III-3 Arithmetik
+! III-8 Speicher
+load zL1=33 Interpreter
+LOOP I1T-28 Kontroll
+thru TII-33 Interpreter
; III-22 Dictionary
= III-31 Compiler
o” Strings
= III-3 Arithmetik
-_—) 11-33 Interpreter
=1 ITII-3 Arithmetik
-roll III-12 Stack
-rot I11-12 Stack
-text Strings
-trailing IIT-51 In/Output
III-51 In/Output
.” 1IL-51 In/Output
| III-51 In/Output
.blk Diverses
.name ITE-22 Dictionary
st III-51 In/Output
.S ITII-12 Stack
.status LII1-38
Sonstiges
I1I-8
1L11I=-15
LITI-15
7171-35
A-4
A-4
LII=5]1
III-44
LII-51
III-44
A-4
A-4
III-44
III-44
1111-15
TII-51
A-47
A-47
III-22
I1I-38
TLI-38
III-33
7211-38
III-48
1111-33
III-36
III-22
A-33
I1II-33
III-3
III-3
LIr=3
ELL-3
III-8
I1I=33
III-28
L1I-33
Il1-22
ZLET-31
A-47
IIlI=3
EII-33
Ill=3
III-12
III-12
A-47
1111-51
Err=51
11-51
1211-51
"A-41
11-22
ZIL-51
TII-12
T11=38
Glossar
A Glossar
nd
Wortnane
fi
/mod
/string
0
0"
0<
0<>
0=
0>
Orc"
ı
1+
1-
2
2!
2%
2+
2-
2/
2@
2Constant
2ärop
2dup
2over
2swap
2Variable
3
3+
4
4!
r
Res
<
<#
D%
»absadär
»body
>drive
»in
>interpret
»label
>memMFDB
»name
>»x
stib
fer
?DO
?dup
?exit
?head
E III-60 (23
IS2E
weibprfrefhz
S.
211-3
T1T=3
TII=-19
III-3
III-6
III-6
III=6
LEI=6
EII=4
III-4
III-4
III-4
ITI-8
III-4
III-4
TII>&4
III-4
III-8
IIL-18
III-12
TII-12
2111-12
III-12
EITI=18
III-4
III-4
III-4
A-4
A-4
III-18
III-13
TEIT-6
IItl-15
TIE=6
III-6
III-24
III-40
TEI-33
2111-33
A-13
III-24
III-14
T1T-51
III-52
III-28
T2T-12
111-283
TRT-27
Gruppe
Arithmetik
Arithmetik
Strings
Arithmetik
Strings
Logik/Vergl
Logik/Vergl
Logik/Vergl
Logik/Vergl
Strings
Arithmetik
Arithmetik
Arithmetik
Arithmetik
Speicher
Arithmetik
Arithmetik
Arithmetik
Arithmetik
Speicher
Datentypen
Stack
Stack
Stack
Stack
Datentypen
Arithmetik
Arithmetik
Arithmetik
GEM
GEM
Datentypen
Datentypen
Assembler
Logik/Vergl
Strings
Logik/Vergl
Logik/Vergl
Diverses
Dictionary
Massenspeich
Interpreter
Interpreter
Assembler
GEM
Dictionary
Returnstack
In/Output
In/Output
Kontroll
Stack
Kontroll
Heap
111-3
111=3
1112-15
III=3
A-47
III-6
TII-6
I1I=6
I1I-6
A-47
III=3
ZIT-3
ELL-3
ELI-3
I11-8
TII-=3
111-3
ILI=-3
ELL-3
III-8
ITI-18
III-12
III-12
III-12
3211-12
ZII-28
LIT-3
ILL-3
IILL-3
A-4
A-4
IIT=18
TII-18
A-17
III-6
TII-15
I1l=6
III-6
A-41
TI1-22
III-40
EI1=33
L11-33
A-17
A-4
III-22
III-14
I1I-51
zIl=51
III-28
IITI=12
III-28
III-27
we/bp/re/hs
III-61
Wortname
?pairs
?stack
@
[l
[]
[compile]
\N
\needs
]
A:
abort
abort"
abort (
abs
accumulate
activate
addrin
addrout
AES
AESpb
Alias
align
all-buffers
allot
allotbuffer
also
and
ap_ptree
appl_exit
appl_init
arc
arguments
array!
Ascii
Assembler
assign
asterisk
at
at?
b
b/blk
b/buf
B:
b_height
b_width
bar
base
bconin
bconout
beonstat
bcostat
BEGIN
bell
bit_image
LII-36
III-36
ILL-8
III-32
III-32
I1I-32
LLL-35
T1LL-35
LIT-35
TEI-=35
III-36
11LL-36
III-4
ELI-I5
III-48
A-4
A-4
A-4
A-4
L11>28
III-22
III-40
III-22
III-40
III-25
TEEL=6
A-4
A-5
A-5
A-11
A-4
L11=31
III-25
A-12
III-52
ELL-52
III-40
III-40
A-5
A-5
A-11
TLI-52
III-44
III-44
III-44
III-44
III-28
Gruppe
Fehler
Fehler
Speicher
Compiler
Compiler
Compiler
Interpreter
Interpreter
Interpreter
Interpreter
Fileinterface
Fehler
Fehler
Diverses
Arithmetik
Strings
Tasking
GEM
GEM
GEM
GEM
Datentypen
Dictionary
Massenspeich
Dictionary
Massenspeich
Vokabular
Logik/Vergl
GEM
GEM
GEM
GEM
Diverses
GEM
Compiler
Vokabular
Fileinterface
GEM
In/Output
In/Output
Tools
Massenspeich
Massenspeich
Fileinterface
GEM
GEM
GEM
In/Output
ST-spezifisch
ST-spezifisch
ST-spezifisch
ST-spezifisch
Kontroll
Diverses
GEM
Glossar
Wortname
bl
blank
blk
bik/arv
block
bounds
buffer
buffers
bye
c
ei
Cr
e/
SE:
c>0”
c®@
c_flag
c_height
c_ width
capacity
capital
capitalize
caps
case?
circle
clear
clear_disp_list
clearstack
close
clrwk
clsvwk
cmove
cmove>
Code
col
cold
compare
compile
con!
Constant
context
contourfill
contrl
convert
convey
copy
copycpaque
core?
count
cpush
er
Create
cross
ctoggle
curdown
BE III-62
2)
y
6
ın
we/bp/re/hz
III-6
A-11
III-22
A-15
LIT-12
A-5
A-5
LLET-8
LII=8
TI1-52
TLE=38
T11>31
III-44
LTr=19
2TE-25
A-11
A-4
EFI-16
III-41
III-41
A-13
III-41
III-8
TII-52
T1ir=19
A-12
IIT-8
A-14
Gruppe
In/Output
Diverses
Interpreter
Massenspeich
Massenspeich
Kontroll
Massenspeich
Relocate
Sonstiges
Tools
Speicher
Dictionary
In/Output
Fileinterface
Strings
Speicher
GEM
GEM
GEM
Fileinterface
Strings
Strings
Strings
Logik/Vergi
GEM
Dictionary
GEM
Stack
Fileinterface
GEM
GEM
Speicher
Speicher
Assembler
In/Output
Sonstiges
Strings
Compiler
ST-spezifisch
Datentypen
Vokabular
GEM
GEM
Strings
Massenspeich
Massenspeich
GEM
Massenspeich
Speicher
Diverses
In/Output
Datentypen
GEM
Speicher
GEM
Se
III=51
A-41
TIT=33
III-40
III-40
III-28
III-40
A-45
III-38
II-41
III-8
III-22
ITI-51
A-47
A=33
LII-75
TiLl-15
A-47
III-6
A-4
III-22
A-4
III-12
A-33
A-4
A-4
III-8
III-8
A-17
LILE-51
IIT-38
A-47
ZII-31
III-44
TIT-18
III-25
A-4
A-4
I1II-15
III-40
III-40
A-4
III-40
I1II-8
A-41
217T=57
III-18
A-4
EII-8
A-4
2E Werbe/re/ks III-63
Wortname S. Gruppe
curhome A-14 GEM
curleft A-14 GEM
curleft III-44 ST-spezifisch
curoff III-44 ST-spezifisch
curon III-45 ST-spezifisch
current 11I-25 Vokabular
curright A-14 GEM
currite III-45 ST-spezifisch
curtext A-14 GEM
curup A-14 GEM
custom-remove TITL-22 Dictionary
d Tools
a* 1311-10 32-Bit-Worte
dt III-10 32-Bit-Worte
d- 1121-10 32-Bit-Worte
de TII-52 In/Output
d.r III-52 In/Output
d40= III-10 32-Bit-Worte
D* Fileinterface
a< III-10 32-Bit-Worte
d= 27-10 32-Bit-Worte
dabs III-10 32-Bit-Worte
dash A-11 GEM
dashdot A-11 GEM
dashdotdot A-1i GEM
debug Tools
decimal III-52 In/Output
decode III-52 In/Output
Defer TII-19 Datentypen
definitions III-25 Vokabular
del III-53 In/Output
delete Strings
depth TI1I-12 Stack
diamond A-12 GEM
digit? III-16 Strings
dir Fileinterface
DIRECT Fileinterface
dis Disassembler
diskerr TLI-36 Fehler
display III-45 ST-spezifisch
dnegate III-10 32-Bit-Worte
DO I1I-28 Kontroll
Does> 2002-33 Compiler
Dos Fileinterface
dot A-11 GEM
dp I1I-22 Dictionary
drive III-41 Massenspeich
drop III-12 Stack
drvo III-45 ST-spezifisch
arvi III-45 ST-spezifisch
drv? III-41 Massenspeich
drvinit III-45 ST-spezifisch
dspcur A-15 GEM
dump Tools
dup III-12 Stack
S.
A-4
A-4
III-44
III-44
III-44
T11-25
A-4
III-44
A-4
A-4
III-22
II-41
III-10
III-10
ZII-10
III-51
III-51
III-10
A-33
LT
III-10
III-10
A-4
A-4
A-4
II-41
III-51
III-51
III-18
III-25
I1I-51
A-47
III-12
A-4
IIT-L5
A=33
A-33
A-31
LII=36
III-44
TII-10
I1I-28
ITLI=31
A-33
A-4
III-22
III-40
III-12
III-44
III-44
III-40
III-44
A-4
II-41
III-12
=.
Glossar N
Wortname
eeol
eeos
ellarc
ellpie
ELSE
emit
empty
empty-buffers
end-trace
enter_cur
eof
erase
error"
errorhandler
even
events
evnt_button
evnt_dclick
evnt_keybd
evnt_mesag
evnt_mouse
evnt_multi
evnt_timer
ex_butv
ex_curv
ex_motv
ex_time
execute
exit_cur
exor
expect
extend
false
File
file?
files
files"
£111
fillarea
find
first
£flush
forget
form_adv
form_alert
form_center
form_dial
form_do
form_error
Forth
forth-83
forthfiles
freebuffer
from
£fromfile
02)
w
fi
ın
we/bpire/kz
H
H
H
N
Kr ,
WANN
en
7
5
“r
Pr
ww
A-13
221729
A-14
A-11
ZII-53
III-10
III-6
Gruppe
GEM
GEM
GEM
GEM
Kontroll
In/Output
Dictionary
Massenspeich
Sonstiges
GEM
Fileinterface
Speicher
Fehler
Fehler
Arithmetik
GEM
GEM
GEM
GEM
GEM
GEM
GEM
GEM
GEM
GEM
GEM
GEM
Kontroll
GEM
GEM
In/Output
32-Bit-Worte
Logik/Vergl
Fileinterface
Fileinterface
Fileinterface
Fileinterface
Speicher
GEM
Interpreter
Massenspeich
Massenspeich
Dictionary
GEM
GEM
GEM
GEM
GEM
GEM
Vokabular
Vokabular
Fileinterface
Masserspeich
Fileinterface
Fileinterface
un
mn
mb
A-4
III-28
III-51
III-22
III-40
I1I-38
A-4
A-33
III-8
III-36
III-36
TII-3
H
Hi
m | ee BD
BPEOBBPRPRSBPBBRABPM
D
(2) 18228 we/bp/re/iks LL1=65
Wortname S. Gruppe
fromfile III-42 Massenspeich
£fsel_input A-9 GEM
function A-4 GEM
GDP A-11 GEM
GEM A-4 GEM
get_pixel A-13 GEM
getkey III-45 ST-spezifisch
global A-4 GEM
graf_dragbox A-8 GEM
graf_growbox A-8 GEM
graf_handle A-5 GEM
graf_mkstate A-9 GEM
graf_mouse A-8 GEM
graf_movebox A-8 GEM
graf_shrinkbox A-8 GEM
graf_slidebox A-8 GEM
graf_watchbox A-8 GEM
grexit A-5 GEM
grhandle A-4 GEM
grinit A-5 GEM
gtext A-11 GEM
hallot III-27 Heap
hardcopy A-14 GEM
heap 1211-27 Heap
heap? 3111-27 Heap
here III-23 Dictionary
hex III-53 In/Output
hide TII-23 Dictionary
hide_c A-5 GEM
hold IIIl-46 Strings
I III=-29 Kontroll
IF 11-29 Kontroll
immediate III-31 Compiler
include Fileinterface
inpath A-9 GEM
input III-53 In/Output
Input: I1I-19 Datentypen
insel A-9 GEM
insert Strings
interpret LIIL-34 Interpreter
intin A-4 GEM
intout A-4 GEM
Is 11-20 Datentypen
isfile III-42 Massenspeich
J III-29 Kontroll
justified A-11 GEM
k Tools
key ZII=53 In/Output
key? I1I-53 In/Output
keyboard III-45 ST-spezifisch
3 Editor
1/s III-53 In/Output
Label Assembler
last TILI=23 Dictionary
ldis Disassembler
Glossar N
S.
III-40
ws»
H
4
H
1
[2
Et
11
2)
1
BRAD pppppAppprpp App >
Dpupyuummmn
H
H
H
D
SI
A
>
171.27
111727
III-22
III-51
III-22
A-4
1211-15
III-28
III-28
111-31
A-33
IL1r51
III-18
A-4
A-47
TII=33
A-4
TETI-18
III-40
I1I-28
A-4
II-41
I1I-51
T11-51
III-44
A-1
ZII-51
A-17
III-22
A=34
ze
I Glossar
Wortnane
ldump
LEAVE
limit
list
Literal
load
loadfile
loadfrom
lock
longdash
LOOP
m*
m/mod
m_filename
make
makedir
makefile
makeview
malloc
max
mem>scri
memMFDB1
menu_bar
menu_icheck
menu_ienable
menu_register
menu_text
menu_tnormal
message
meta_extents
m£free
min
mod
mofaddr
more
move
multitask
n
name
name>
negate
nest
next-link
nip
noop
not
notfound
nullstring?
number
number?
objce_add
objc_change
objc_delete
obje_draw
objce_edit
III-66 \
{7
-
2
im
in
werbpfre/hz
III-29
III-42
TET-53
111-31
III-34
11-34
III-48
A-ı11
III-29
III-10
I1I-10
A-15
III-39
III-4
er
ıIPr
IWW
De mn m
Gruppe
Tools
Kontroll
Massenspeich
In/Output
Compiler
Interpreter
Interpreter
Fileinterface
Tasking
GEM
Kontroll
32-Bit-Worte
32-Bit-Worte
GEM
Fileinterface
Fileinterface
Fileinterface
Sonstiges
Allocate
Arithmetik
GEM
GEM
GEM
GEM
GEM
GEM
GEM
GEM
GEM
GEM
Allocate
Arithmetik
Arithmetik
GEM
Fileinterface
Speicher
Tasking
Tools
Interpreter
Dictionary
Arithmetik
. Tools
Sonstiges
Stack
Sonstiges
Logik/Vergl
Interpreter
Strings
Strings
Strings
GEM
GEM
GEM
GEM
GEM
ıı 4
> un Ed
BBBBPBPRBE
HH
HH»
>HH
[a
> www
“c} 1, weibpe/rerhs III-67
Wortname S. Gruppe
obje_find A-7 GEM
objc_offset A-7 GEM
objc_order A-7 GEM
objc_tree A-5 GEM
off III-9 Speicher
offset III-42 Massenspeich
on III-9 Speicher
Only ILI-25 Vokabular
Onlyforth III-25 Vokabular
opcode A-4 GEM
open Fileinterface
opnvwk A-5 GEM
or III-6 Logik/Vergl
origin III-23 Dictionary
output III-53 In/Output
Output: 11120 Datentypen
output_window A-15 GEM
over I17-12 Stack
pad III-9 Speicher
page III-54 In/Output
parse III-34 Interpreter
pass III-48 Tasking
path Fileinterface
pause III-48 Tasking
perform IITI-23 Kontroll
pick III-13 Stack
pie A-11 GEM
place III-9 Speicher
pline A-11 GEM
plus A-12 GEM
pmarker A-11 GEM
point A-12 GEM
prepare A-6 GEM
prev III-42 Massenspeich
ptsin A-4 GEM
ptsout A-4 GEM
push III-14 Returnstack
q_cellarray A-14 GEM
q_chcells A-14 GEM
q_color A-14 GEM
q_curadress A-14 GEM
q_extnd A-14 GEM
q_key_s A-14 GEM
q_mouse A-13 GEM
q_tabstatus A-14 GEM
qf_attributes A-14 GEM
ain_mode A-14 GEM
ql_attributes A-14 GEM
qm_attributes A-14 GEM
qp_error A-15 GEM
ap_films A-15 GEM
ap_state A-15 GEM
gt_attributes A-14 GEM
gt_extent A-14 GEM
at_fontinfo A-14 GEM
Glossar N
un
De
rı 11
!
!
DPBPARPRPBPpPpARP$pPRRBPRIBD
Ba m Do name tret ion
Glossar
Wortname
qt_name
qat_width
query
quit
r#
r/w
ro
r>
r@
r_recfl
r_trnfm
rbox
rdepth
rdrop
recursive
relocate
remove
rendezvous
REPEAT
replace
restart
restrict
restvec
reveal
revtransparent
rfbox
rmcur
roll
rot
row
rp!
rp@
rsrc_free
rsrce_gaddr
rsrc_load
rsrce_load"
rsrc_obfix
rsrc_saddr
rvoff
rvon
rwabs
s
so
s_clip
s_curadress
s_palette
save
save-buffers
savesystem
sc_form
scan
scr
scr>mem
scr?meml
ser?scr
III-68 cc
5: Gruppe S.
A-14 GEM A-4
A-14 GEM A-4
III-54 In/Output LII-51
1411-34 Interpreter III-33
III-39 Sonstiges 1211-38
III-42 Massenspeich III-40
1111-14 Returnstack III-14
III-14 Returnstack III-14
III-14 Returnstack III-14
4-11 GEM A=4
A-13 GEM A-4
A-11 GEM A-4
2317-12 Returnstack III-14
IT3=-14 Returnstack Z1I-14
LLI-32 Compiler III-31
Relocate A-45
T11I-23 Dictionary LII=22
III-49 Tasking III-48
311729 Kontroll III-28
A-11 GEM A-4
III-39 Sonstiges III-38
III-32 Compiler I1I-31
Diverses A-41
III-23 Dictionary III-22
A-11 GEM A-4
A-11 GEM A-4
A-15 GEM A-4
IT-13 Stack III-12
2171-13 Stack III-12
III-54 In/Output III-51
III-14 Returnstack III-14
III-14 Returnstack III-14
A-10 GEM A-4
A-10 GEM A-4
A-10 GEM A-4
A-10 GEM A-4
A-10 GEM A-4
A-10 GEM A-4
A-14 GEM A-4
A-14 GEM A-4
III-45 ST-spezifisch III-4
Tools II-41
III-13 Stack III-12
A-5 GEM A-4
A-14 GEM A-4
A-15 GEM A-4
III-24 Dictionary I1I-22
III-43 Massenspeich III-40
Fileinterface A-33
A-13 GEM A-4
III-37 Strings I1I-15
III-39 Sonstiges III-38
A-13 GEM A-4
A-13 GEM A-4
A=-13 GEM A-4
(c) 1222 weibp/re/ks III-69
Wortname 5, Gruppe
scrMFDB AS GEM
seal I11-25 Vokabular
search Strings
setdrive Fileinterface
setvec Diverses
sf_color A-12 GEM
sf_interior A-12 GEM
sf_perimeter A-12 GEM
sf_style A-12 GEM
show_c A-5 GEM
sign III-17 Strings
sin_mode A-13 GEM
singletask III-49 Tasking
sizes A-5 GEM
skip III-17 Strings
sl_color A-12 GEM
sl_ends A-12 GEM
sl_type A-11 GEM
sl_udsty A-12 GEM
sl_width A-12 GEM
sleep III-49 Tasking
sm_choice A-13 GEM
sm_color A-12 GEM
sm_height A-12 GEM
sm_locator A-13 GEM
sm_string A-13 GEM
sm_type A-12 GEM
sm_valuator A-13 GEM
solid A-11 GEM
source III-34 Interpreter
sp! 11-13 Stack
sp@ TIT-13 Stack
sp_save A-15 GEM
sp_state A-15 GEM
space III-54 In/Output
spaces III-54 In/Output
span III-54 In/Output
square A-12 GEM
st_alignement A-12 GEM
st_color A-12 GEM
st_effects A-12 GEM
st_font A-12 GEM
st_height A-12 GEM
st_point A-12 GEM
standardi/o LIT-54 In/Output
STat III-45 ST-spezifisch
STat? III-45 ST-spezifisch
state 111-358 Interpreter
sTer III-45 ST-spezifisch
STdecode III-46 ST-spezifisch
sSTdel III-46 ST-spezifisch
STemit III-46 ST-spezifisch
STexpect III-46 ST-spezifisch
STkey III-46 ST-spezifisch
STkey? III-46 ST-spezifisch
MH
H
H
> 1
Ir
eu
De ep
III-4
= m = m» 5
DER ADpA$pOo——Pp pr >
HH
HH
HH
I 1 m
rw |
DD Ww
Glossar
Wortname
stop
stop?
STpage
STr/w
STtype
swap
swr_mode
Task
tasks
THEN
thru
tib
Tools
toss
trace'
transparent
true
type
üL
u.r
u/mod
ut
u>
uallot
ud/mod
udp
um*
um/mod
umax
umin
under
unlock
unnest
UNTIL
up!
up@
update
updwk
use
User
userdef
uwithin
v
Variable
VDI
VDIpb
view
voc-link
Vocabulary
vp
wake
warning
WHILE
wind_calce
wind_close
(23
iRZE
we/bp/re/hs
III-20
A-11
III-7
III-21
A-4
A-4
III-26
IIlI-21
III-26
III-50
LIT-37
121-309
A-9
Gruppe
Tasking
In/Output
ST-spezifisch
ST-spezifisch
ST-spezifisch
Stack
GEM
Tasking
Tasking
Kontroll
Interpreter
In/Output
Tools
Vokabular
Tools
GEM
Logik/Vergl
In/Output
In/Output
In/Output
Arithmetik
Logik/Vergl
Logik/Vergl
Dictionary
32-Bit-Worte
Dictionary
32-Bit-Worte
32-Bit-Worte
Arithmetik
Arithmetik
Stack
Tasking
Tools
Kontroll
Tasking
Tasking
Massenspeich
GEM
Fileinterface
Datentypen
GEM
Logik/Vergl
Editor
Datentypen
GEM
GEM
Editor
Vokabular
Datentypen
Vokabular
Tasking
Fehler
Kentroll
GEM
GEM
III-48
I111-51
III-44
III-44
III-44
1112-12
A-4
III-48
III-48
III-28
III-33
ITI-51
II-41
I11-25
II-41
A-4
III-6
1211-51
r11=51
Z11-51
111-3
III-6
III-6
III-22
ITI-10
111=22
III-10
III-10
211-3
III-3
T11-12
III-48
II-41
III-28
III-48
III-48
III-40
A-4
A-33
111-138
A-4
III-6
A-1
III-18
A-4
A-4
A-1
ZII-25
III-13
III-25
III-48
III-36
III-28
A-4
A-4
1528 werbp/rerks TITI-71
Wortname S. Gruppe
wind_create A-9 GEM
wind_delete A-9 GEM
wind_find A-9 GEM
wind_get A-9 GEM
wind_open A-9 GEM
wind_set A-9 GEM
wind_update A-9 GEM
word 1171-35 Interpreter
words III-26 Vokabular
write_meta A-15 GEM
xor ITI-7 Logik/Vergl
ı III-27 Heap
Glossar N
we/bp/re/rs
Definition der R 1 2n.conruer | 5
f D Deftaltian der Be
H-Gesellschaft eV
FORTH-Gesellschaft eV
ultraFf De er :
Wealimitlen dus race.) | Definition der Begriffe
Ki der Begriffe item 2 BERCHEESTEREL
RZ MEIRTEZTETANEN Begriffe
nm] ultraFORTH83 BEER se
Definition der Begri
< preksfre/w lahiaitiar der Begriffe 3
| Definition der » Teunhtie Rz EEE SEIEN
m nsurifie
rim m E Bee 2
BD der Begritte | 2
SEE werbprterks Begriffe
Entscheidungskriterien
Bei Konflikten läßt sich das Standardteam von folgenden Kri-
terien in Reihenfolge ihrer Wichtigkeit leiten:
10.
11.
Korrekte Funktion - bekannte Einschränkungen, Eindeu-
tigkeit
Transportabilität - wiederholbare Ergebnisse, wenn
Programme zwischen Standardsystemen portiert werden
Einfachheit
Klare, eindeutige Namen - die Benutzung beschreiben-
der statt funktionaler Namen, zB [COMPILE] statt 'c,
und ALLOT statt dp+!
Allgemeinheit
Ausführungsgeschwindigkeit
Kompaktheit
Kompilationsgeschwindigkeit
Historische Kontinuität
Aussprechbarkeit
Verständlichkeit - es muß einfach gelehrt werden
können
IV-2 (23 BEE we/bp/re/iks
Definition der Begriffe
Es werden im allgemeinen die amerikanischen Begriffe beibehal-
ten, es sei denn, der Begriff ist bereits im Deutschen
geläufig. Wird ein deutscher Begriff verwendet, so wird in
Klammern der engl. Originalbegriff beigefügt; wird der Origi-
nalbegriff beibehalten, so wird in Klammern eine möglichst
treffende Übersetzung angegeben.
Adresse, Byte (address, byte)
Eine 16bit Zahl ohne Vorzeichen, die den Ort eines 3&bit
Bytes im Bereich <0...65,535> angibt. Adressen werden wie
Zahlen ohne Vorzeichen manipuliert.
Siehe: "Arithmetik, 2er-komplement"
Adresse, Kompilation (address, compilation)
Der Zahlenwert, der zur Identifikation eines Forth Wortes
kompiliert wird. Der Adressinterpreter benutzt diesen
Wert, um den zu jedem Wort gehörigen Maschinencode aufzu-
finden. \
Adresse, Natürliche (address, native machine)
Die vorgegebene Adressdarstellung der Computerhardware.
Adresse, Parameterfeld (address, parameter field) "pfa"
Die Adresse des ersten Bytes jedes Wortes, das für das
Ablegen von Kompilationsadressen ( bei :-definitionen |}
oder numerischen Daten bzw. Textstrings usw. benutzt wird.
anzeigen (display)
Der Prozess, ein oder mehrere Zeichen zum aktuellen
Ausgabegerät zu senden. Diese Zeichen werden normalerweise
auf einem Monitor angezeigt bzw. auf einem Drucker
gedruckt.
Arithmetik, 2er-komplement (arithmetic, two's complement)
Die Arithmetik arbeitet mit Zahlen in 2er-komplementdar-
stellung; diese Zahlen sind, je nach Operation, 16bit oder
32bit weit. Addition und Subtraktion von 2er-komplement-
zahlen ignorieren Überlaufsituationen. Dadurch ist es
möglich, daß die gleichen Operatoren benutzt werden kön-
nen, gleichgültig, ob man die Zahl mit Vorzeichen (<-
32,.768...32,767% bei 16bit) oder ohne Vorzeichen
(<£0...65,535> bei 16bit) benutzt.
Block (block)
Die 1024byte Daten des Massenspeichers, auf die über
Blocknummern im Bereich <0...Anzahl_existenter_Blöcke-1>
zugegriffen wird. Die exakte Anzahl der Bytes, die je
Zugriff auf den Massenspeicher übertragen werden, und die
Übersetzung von Blocknummern in die zugehörige Adresse des
Laufwerks und des physikalischen Satzes, sind rechnerab-
hängig.
Siehe: "Blockpuffer" und "Massenspeicher"
(<> 1328 Werbp/re/ks IV-3
Begriffe |
Blockpuffer (block buffer) i
Ein 1024byte langer Hauptspeicherbereich, in dem ein Block
vorübergehend benutzbar ist. Ein Block ist in höchstens
einem Blockpuffer enthalten.
Byte (byte)
Eine Einheit von 8bit. Bei Speichern ist es die Speicher-
kapazität von 8bits.
Kompilation (compilation)
Der Prozess, den Quelltext in eine interne Form umzuwan-
deln, die später ausgeführt werden kann. Wenn sich das
System im Kompilationszustand befindet, werden die Kompi-
lationsadressen von Worten im Dictionary abgelegt, so dass
sie später vom Adresseninterpreter ausgeführt werden kön-
nen. Zahlen werden so kompiliert, daß sie bei Ausführung
auf den Stack gelegt werden. Zahlen werden aus dem
Quelltext ohne oder mit negativem Vorzeichen akzeptiert
und gemäß dem Wert von BASE umgewandelt.
Siehe: "Zahl", "Zahlenumwandlung", "Interpreter, Text"
und "Zustand"
Definition (Definition)
Siehe: "Wortdefinition"”
Dictionary (Wörterbuch)
Eine Struktur von Wortdefinitionen, die im Hauptspeicher
des Rechners angelegt ist. Sie ist erweiterbar und wächst
in Richtung höherer Speicheradressen. Einträge sind in
Vokabularen organisiert, so daß die Benutzung von
Synonymen möglich ist, d.h. gleiche Namen können, in
verschiedenen Vokabularen enthalten, vollkommen verschie-
dene Funktionen auslösen.
Siehe: "Suchreihenfolge"
Division, floored (division, floored)
Ganzzahlige Division, bei der der Rest das gleiche
Vorzeichen hat wie der Divisor oder gleich Null ist; der
Quotient wird gegen die nächstkleinere ganze Zahl gerun-
det.
Bemerkung: Ausgenommen von Fehlern durch Überlauf gilt:
N1 N2 SWAP OVER /MOD ROT * + ist identisch mit Nl.
Siehe: "floor, arithmetisch"
Beispiele: Dividend Divisor Rest Quotient
10 7 3 1
-10 7 4 u
10 7 -4 -2
-10 -7 -3 1
Empfangen (receive)
Der Prozess, der darin besteht, ein Zeichen von der
aktuellen Eingabeeinheit zu empfangen. Die Anwahl einer
Einheit ist rechnerabhängig.
Begriffe
PNPTEREpIESEIIeHe Bere E12 PEBSErBeman Be RT IE BEL
Falsch (false)
Die Zahl Null repräsentiert den "Falschzustand" eines
Flags.
Fehlerbedingung (error condition)
Eine Ausnahmesituation, in der ein Systemverhalten
erfolgt, das nicht mit der erwarteten Funktion überein-
stimmt. Im der Beschreibung der einzelnen Worte sind die
möglichen Fehlerbedingungen und das dazugehörige System-
verhalten beschrieben.
Flag (logischer Wert)
Eine Zahl, die eine von zwei möglichen Werten hat, falsch
oder wahr.
Siehe: "Falsch" "Wahr"
Floor, arithmetic
Z sei eine reelle Zahl. Dann ist der Floor von 2 die
größte ganze Zahl, die kleiner oder gleich Z ist.
Der Floor von +0,6 ist 0
Der Floor von -0,4 ist =1
Glossar (glossary)
Eine umgangssprachliche Beschreibung, die die zu einer
Wortdefinition gehörende Aktion des Computers beschreibt -
die Beschreibung der Semantik des Wortes.
Interpreter, Adressen (interpreter, address)
Die Maschinencodeinstruktionen, die die kompilierten Wort-
definitionen ausführen, die aus Kompilationsadressen
bestehen.
Interpreter, Text (interpreter, text)
Eine Wortdefinition, die immer wieder einen Wortnamen aus
dem Quelltext holt, die zugehörige Kompilationsadresse
bestimmt und diese durch den Adressinterpreter ausführen
läßt. Quelltext, der als Zahl interpretiert wird, hinter-
läßt den entsprechenden Wert auf dem Stack.
Siehe: "Zahlenumwandlung"
Kontrollstrukturen (structure, control)
Eine Gruppe von Worten, die, wenn sie ausgeführt werden,
den Programmfluss verändern.
Beispiele von Kontrollstrukturen sind:
DO ... LOOP
BEGIN ... WHILE ... REPEAT
IF ... ELSE ... THEN
laden (load)
Das Umschalten des Quelltextes zum Massenspeicher. Dies
ist die übliche Methode, dem Dictionary neue Definitionen
hinzuzufügen.
Massenspeicher (mass storage)
Speicher, der ausserhalb des durch FORTH adressierbaren
Bereiches liegen kann. Auf den Massenspeicher wird in Form
von 1024byte grossen Blöcken zugegriffen. Auf einen Block
(23 BEE weibp/re/ks LV=5 Begriffe
kann innerhalb des Forth-Adressbereichs in einem Blockpuf-
fer zugegriffen werden. Wenn ein Block als verändert
(UPDATE) gekennzeichnet ist, wird er letztendlich wieder
auf den Massenspeicher zurückgeschrieben.
Programm (program)
Eine vollständige Ablaufbeschreibung in FORTH-Quelltext,
um eine bestimmte Funktion zu realisieren.
Quelltext (input stream)
Eine Folge von Zeichen, die dem System zur Bearbeitung
durch den Textinterpreter zugeführt wird. Der Quelltext
kommt üblicherweise von der aktuellen Eingabeeinheit (über
den Texteingabepuffer) oder dem Massenspeicher (über einen
Blockpuffer). BLK, >IN, TIB und #TIB charakterisieren den
Quelltext. Worte, die BLK, >IN, TIB oder #TIB benutzen
und/oder verändern, sind dafür verantwortlich, die
Kontrolle des Quelltextes aufrechtzuerhalten oder wieder-
herzustellen.
Der Quelltext reicht von der Stelle, die durch den
Relativzeiger >IN angegeben wird, bis zum Ende. Wenn BLK
Null ist, so befindet sich der Quelltext an der Stelle,
die durch TIB adressiert wird, und er ist #TIB Bytes lang.
Wenn BLK ungleich Null ist, so ist der Quelltext der
Inhalt des Blockpuffers, der durch BLK angegeben ist, und
er ist 1024byte lang.
Rekursion (recursion)
Der Prozess der direkten oder indirekten Selbstreferenz.
Screen (Bildschirm)
Ein Screen sind Textdaten, die zum Editieren aufbereitet
sind. Nach Konvention besteht ein Screen aus 16 Zeilen zu
je 64 Zeichen, Die Zeilen werden von 0 bis 15 durchnume-
riert. Screens enthalten normalerweise Quelltext, können
jedoch auch dazu benutzt werden, um Massenspeicherdaten zu
betrachten. Das erste Byte eines Screens ist gleichzeitig
das erste Byte eines Massenspeicherblocks; dies ist auch
der Anfangspunkt für Quelltextinterpretation während des
Ladens eines Blocks.
Suchreihenfolge (search order)
Eine Spezifikation der Reihenfolge, in der ausgewählte
Vokabulare im Dictionary durchsucht werden. Die Suchrei-
henfolge besteht aus einem auswechselbaren und einem
festen Teil, wobei der auswechselbare Teil immer als
erstes durchsucht wird. Die Ausführung eines Vokabularna-
mens macht es zum ersten Vokabular in der Suchreihenfolge,
wobei das Vokabular, das vorher als erstes durchsucht
worden war, verdrängt wird. Auf dieses erste Vokabular
folgt, soweit spezifiziert, der feste Teil der Suchreihen-
folge, der danach durchsucht wird. Die Ausführung von ALSO
übernimmt das Vokabular im auswechselbaren Teil in den
festen Teil der Suchreihenfolge. Das Dictionary wird immer
dann durchsucht, wenn ein Wort durch seinen Namen aufge-
£unden werden soll.
ic 1528 we/bp/re/hs
stack, data (Datenstapel)
Eine "Zuletzt-rein, Zuerst-raus" (last-in, first-out)
Struktur, die aus einzelnen 16bit Daten besteht. Dieser
Stack wird hauptsächlich zum Ablegen von Zwischenergebnis-
sen während des Ausführens von Wortdefinitionen benutzt.
Daten auf dem Stack können Zahlen, Zeichen, Adressen,
Boole'sche Werte usw. sein.
Wenn der Begriff "Stapel" oder "Stack" ohne Zusatz benutzt
wird, so ist immer der Datenstack gemeint.
stack, return (Rücksprungstapel)
Eine "Zuletzt-rein, Zuerst-raus" Struktur, die hauptsäch-
lich Adressen von Wortdefinitionen enthält, deren Ausfüh-
rung durch den Adressinterpreter noch nicht beendet ist.
Wenn eine Wortdefinition eine andere Wortdefinition auf-
ruft, so wird die Rücksprungadresse auf dem Returnstack
abgelegt. Ir
Der Returnstack kann zeitweise auch für die Ablage anderer
Daten benutzt werden.
String, counted (abgezählte Zeichenkette)
Eine Hintereinanderfolge von 8bit Daten, die im Speicher
durch ihre niedrigste Adresse charakterisiert wird. Das
Byte an dieser Adresse enthält einen Zahlenwert im Bereich
<0...255>, der die Anzahl der zu diesem String gehörigen
Bytes angibt, die unmittelbar auf das Countbyte folgen.
Die Anzahl beinhaltet nicht das Countbyte selber. Counted
Strings enthalten normalerweise ASCII-Zeichen.
String, Text (Zeichenkette)
Eine Hintereinanderfolge von 8bit Daten, die im Speicher
durch ihre niedrigste Adresse und ihre Länge in Bytes
charakterisiert ist. Strings enthalten normalerweise
ASCII-Zeichen. Wenn der Begriff "String" alleine oder in
Verbindung mit anderen Begriffen benutzt wird, so sind
Textstrings gemeint.
Userarea (Benutzerbereich)
Ein Gebiet im Speicher, das zum Ablegen der Uservariablen
benutzt wird und für jeden einzelnen Prozeß/Benutzer
getrennt vorhanden ist.
Uservariable (Benutzervariable) Bu
Eine Variable, deren Datenbereich sich in der Userarea
befindet. Einige Systemvariablen werden in der Userarea
gehalten, sodaß die Worte, die diese benutzen, für mehrere
Prozesse/Benutzer gleichzeitig verwendbar sind.
Vokabular (vocabulary)
Eine geordnete Liste von Wortdefinitionen. Vokabulare
werden vorteilhaft benutzt, um Worte voneinander zu
unterscheiden, die gleiche Namen haben (Synonyme). In
einem Vokabular können mehrere Definitionen mit dem glei-
chen Namen existieren; diesen Vorgang nennt man redefinie-
ren. Wird das Vokabular nach einem Namen durchsucht, so
wird die jüngste Redefinition gefunden.
all
IrTH
rer
rim
c3 1B88 we/bp/re/ks IV-7 Begriffe
Vokabular, Kompilation (vocabulary, compilation)
Wahr
Wort,
Wort,
Das Vokabular, in das neue Wortdefinitionen eingetragen
werden.
(true)
Ein Wert, der nicht Null ist, wird als "wahr" interpre-
tiert. Wahrheitswerte, die von Standard-FORTH-Worten
errechnet werden, sind 16bit Zahlen, bei denen alle 16
Stellen auf "1" gesetzt sind, so daß diese zum Maskieren
benutzt werden können.
Definierendes (defining word)
Ein Wort, das bei Ausführung einen neuen Dictionary-
Eintrag im Kompilationsvokabular erzeugt. Der Name des
neuen Wortes wird dem Quelltext entnommen. Wenn der
Quelltext erschöpft ist, bevor der neue Name erzeugt
wurde, so wird die Fehlermeldung "ungültiger Name” ausge-
geben.
Beispiele von definierenden Worten sind:
$ CONSTANT CREATE
immediate (immediate word)
Ein Wort, das ausgeführt wird, wenn es während der
Kompilation oder Interpretation aufgefunden wird. Imme-
diate Worte behandeln Sondersituationen während der Kompi-
lation.
Siehe z.B. IF LITERAL ." usw.
Wortdefinition (word definition)
Eine mit einem Namen versehene, ausführbare FORTH-Proze-
dur, die ins Dictionary kompiliert wurde. Sie kann durch
Maschinencode, als eine Folge von Kompilationsadressen
oder durch sonstige kompilierte Worte spezifiziert sein.
Wenn der Begriff "Wort" ohne Zusatz benutzt wird, so ist
im allgemeinen eine Wortdefinition gemeint.
Wortname (word name)
Zahl
Der Name einer Wortdefinition. Wortnamen sind maximal 31
Zeichen lang und enthalten kein Leerzeichen. Haben zwei
Definitionen verschiedene Namen innerhalb desselben Voka-
bulars, so sind sie eindeutig auffindbar, wenn das
Vokabular durchsucht wird.
Siehe: "Vokabular"
(number)
Wenn Werte innerhalb eines größeren Feldes existieren, so
sind die höherwertigen Bits auf Null gesetzt. 16bit Zahlen
sind im Speicher so abgelegt, dass sie in zwei benachbar-
ten Byteadressen enthalten sind. Die Bytereihenfolge ist
rechnerabhängig. Doppeltgenaue Zahlen (32bit) werden auf
dem Stack so abgelegt, daß die höherwertigen 16bit (mit
dem Vorzeichenbit) oben liegen. Die Adresse der niederwer-
tigen 16bit ist um zwei größer als die Adresse der
höherwertigen 16bit, wenn die Zahl im Speicher abgelegt
ist.
Siehe: "Arithmetik, 2er-komplement" und "Zahlentypen"
2} ISEE we/ibp/re/hs
Zahlenausgabe, bildhaft (pictured numeric output)
Durch die Benutzung elementarer Worte für die Zahlenaus-
gabe ( z.B. <c# # #s #> ) werden Zahlenwerte in Textstrings
umgewandelt. Diese Definitionen werden in einer Folge
benutzt, die ein symbolisches Bild des gewünschten Ausga-
beformates darstellen. Die Umwandlung schreitet von der
niedrigstwertigen zur höchstwertigen Ziffer fort und die
umgewandelten Zeichen werden von höheren gegen niedrigere
Speicheradressen abgelegt.
Zahlenausgabe, freiformatiert (free field format)
Zahlen werden in Abhängigkeit von BASE umgewandelt und
ohne führende Nullen, aber mit einem folgenden Leerzei-
chen, angezeigt. Die Anzahl von Stellen, die angezeigt
werden, ist die Minimalanzahl von Stellen - mindestens
eine - die notwendig sind, um die Zahl eindeutig darzu-
stellen.
Siehe: "Zahlenumwandlung"
Zahlentypen (number types)
Alle Zahlentypen bestehen aus einer spezifischen Anzahl
von Bits. Zahlen mit oder ohne Vorzeichen bestehen aus
bewerteten Bits. Bewertete Bits innerhalb einer Zahl haben
den Zahlenwert einer Zweierpotenz, wobei das am weitesten
rechts stehende Bit (das niedrigstwertige) einen Wert von
zwei hoch null hat. Diese Bewertung setzt sich bis zum am
weitesten links stehenden Bit fort, wobei sich die Bewer-
tung für jedes Bit um eine Zweierpotenz erhöht. Für eine
Zahl ohne Vorzeichen ist das am weitesten links stehende
Bit in diese Bewertung eingeschlossen, sodaß für eine
solche 16bit Zahl das ganz linke Bit den Wert 32.768 hat.
Für Zahlen mit Vorzeichen wird die Bewertung des ganz
linken Bits negiert, sodaß es bei einer 16bit Zahl den
Wert -32.768 hat. Diese Art der Wertung für Zahlen mit
Vorzeichen wird 2er-komplementdarstellung genannt.
Nicht spezifizierte, bewertete Zahlen sind mit oder ohne
Vorzeichen; der Programmkontext bestimmt, wie die Zahl zu
interpretieren ist.
Zahlenumwandlung (number conversion)
Zahlen werden intern als Binärzahlen geführt und extern
durch graphische Zeichen des ASCII Zeichensatzes darge-
stellt. Die Umwandlung zwischen der internen und externen
Form wird unter Beachtung des Wertes von BASE durchge-
£ührt, um die Ziffern einer Zahl zu bestimmen. Eine Ziffer
liegt im Bereich von Null bis BASE-1. Die Ziffer mit dem
Wert Null wird durch das ASCII-zeichen "0" (Position 3/0,
dezimalwert 48) dargestellt. Diese Zifferndarstellung geht
den ASCII-code weiter aufwärts bis zum Zeichen "9", das
dem dezimalen Wert neun entspricht. Werte, die jenseits
von neun liegen, werden durch die ASCII-zeichen beginnend
mit "A", entsprechend dem Wert zehn usw. bis zum ASCII-
zeichen """, entsprechend einundsiebzig, dargestellt.Bei
einer negativen Zahl wird das ASCII-zeichen "-"” den
Ziffern vorangestellt. Bei der Zahleneingabe kann der
bs
2) 1826 weibp/terks IV-9 Begriffe
aktuelle Wert von BASE für die gerade umzuwandelnde Zahl
dadurch umgangen werden, daß den Ziffern ein
"Zahlenbasisprefix" vorangestellt wird. Dabei wird durch
das Zeichen "%" die Basis vorübergehend auf den Wert zwei
gesetzt, durch "&" auf den Wert zehn und durch "$" oder
h" auf den Wert sechzehn. Bei negativen Zahlen folgt das
Zahlenbasisprefix dem Minuszeichen. Enthält die Zahl ein
Komma oder einen Punkt, so wird sie als 32bit Zahl
umgewandelt.
Zeichen (character)
Eine 8bit Zahl, deren Bedeutung durch den ASCII-Standard
festgelegt ist. Wenn es in einem größeren Feld gespeichert
ist, so sind die höherwertigen Bits auf Null gesetzt.
Zustand (mode)
Der Textinterpreter kann sich in zwei möglichen Zuständen
befinden: dem interpretierenden oder dem kompilierenden
Zustand. Die Variable STATUS wird vom System entsprechend
gesetzt, und zwar enthält sie bei der Interpretation eine
False-flag, bei der Kompilation eine True-flag.
Siehe: "Interpreter, Text" und "Kompilation"
ISZE weicpireits
2) 1328 weibp/rerhs A-1
Anhang
Atari ST Fullscreen Editor
Ältere FORTH-Systeme enthalten meist Editoren, die diesen Namen
höchstens zu einer Zeit verdient haben, als man noch die Bits
einzeln mit Lochzange und Streifenleser an die Hardware über-
mitteln mußte. Demgegenüber bietet ein Editor, mit dem man 'im
Blindflug' jeweils eine ganze Zeile bearbeiten kann, sicher
schon einigen Komfort. Heute kann man jedoch mit solch einem
Zeileneditor keinen Staat mehr machen und erst recht nicht mit
anderen Sprachen konkurrieren.
Wir haben daher dem Atari ST einen komfortablen Fullscreen-
Editor spendiert, der vollkommen in GEM eingebunden ist. Dies
erspart uns auch umfangreiche Befehlslisten aller Editorfunk-
tionen: Der Editor hat eine Menüzeile, und beim Anklicken eines
Menüpunktes bekommt man eine kurze Erklärung der jeweiligen
Funktion. Die 'Profis' können alle Editorfunktionen auch ohne
Maus über die Tastatur erreichen, die entsprechenden Control-
codes stehen hinter den Menüeinträgen. Auch die Hilfsfunktion
ist abschaltbar, wenn man den Menüpunkt DAUERHILFE anwählt. Die
Hilfstexte erscheinen aber ohnedies nicht, wenn man die Komman-
dos von der Tastatur aus eingibt.
Im Editorfenster wird immer ein FORTH-Screen - also 1024 Bytes
- in der üblichen Aufteilung in 16 Zeilen mit je 64 Spalten
dargestellt. Es gibt einen Zeichen- und einen Zeilenstack.
Damit lassen sich Zeichen bzw. Zeilen innerhalb eines Screens
oder auch zwischen zwei Screens bewegen oder kopieren. Dabei
wird verhindert, daß versehentlich Text verloren geht, indem
Funktionen nicht ausgeführt werden, wenn dadurch Zeichen nach
unten oder zur Seite aus dem Bildschirm geschoben würden.
Der Editor unterstützt das 'Shadow-Konzept'. Zu jedem Quell-
text-Screen gibt es einen Kommentar-Screen. Dieser erhöht die
Lesbarkeit von FORTH-Programmen erheblich. (Sie wissen ja,
guter FORTH-Stil ist selbstdokumentierend !) Auf Tastendruck
stellt der Editor den Kommentar-Screen zur Verfügung. So können
Kommentare 'deckungsgleich' angefertigt werden. Die meisten
mitgelieferten Quelltexte sind übrigens mit Shadow-Screens
versehen, und auch das Printer-Interface unterstützt dieses
Konzept.
Um in den Editor zu gelangen gibt es drei Möglichkeiten:
<screennr> L
ruft den Screen mit Nummer screennr auf. Dabei muß das File
vorher z.B. mit USE ausgewählt sein.
v
ruft den zuletzt bearbeiteten Screen wieder auf. Dies ist der
zuletzt editierte oder aber, und das ist sehr hilfreich,
derjenige, der einen Abbruch beim Kompilieren verursacht hat.
Wenn Sie also ein File kompilieren, und der Compiler bricht mit
Ra
| Anhang
A-2 23 1EEE we/be/re/hs
einer Fehlermeldung ab, brauchen Sie nur ein V einzugeben. Der
fehlerhafte Screen wird in den Editor geladen, und der Cursor
steht hinter dem Wort, das den Abbruch verursacht hat.
Häufig möchte man sich die Definition eines Wortes ansehen, um
z.B. den Stackkommentar oder die genaue Arbeitsweise nachzu-
lesen. Dafür gibt es das Kommando
VIEW <wort>
Damit wird der Screen - und natürlich auch das File -
aufgerufen, auf dem wort definiert wurde. Dieses Verfahren
ersetzt (fast) einen Decompiler, weil es natürlich sehr viel
bequemer ist und Ihnen ja auch sämtliche Queiltexte des Systens
zur Verfügung stehen. Natürlich müssen die entsprechenden Files
auf den Laufwerken 'griffbereit' sein, sonst erscheint eine
Fehlermeldung. Die VIEW-Funktion steht auch innerhalb des
Editors zur Verfügung, man kann dann mit einem Tastendruck
zwischen dem gerade bearbeiteten und dem Screen, auf dem man
eine Definition gesucht hat, hin- und herschalten. Dies ist
insbesondere nützlich, wenn man eine Definition aus einem
anderen File übernehmen möchte oder nicht mehr sicher ist, wie
der Stackkommentar eines Wortes lautet oder ....
Noch ein paar Hinweise ;
=} Wie Files erzeugt und verlängert werden, steht im Teil 1
des Handbuchs und wird weiter unten in dem Kapitel über
das Fileinterface ausführlich erklärt.
-) Der Editor unterstützt nur das Kopieren von Zeilen. Man
kann auf diese Art auch Screens kopieren, aber beim
gelegentlich erforderlichen Einfügen von Screens in der
Mitte eines Files ist das etwas mühselig. Zum Kopieren
ganzer Screens innerhalb eines Files oder von einem File
in ein anderes werden im volksFORTH83 die Worte COPY und
CONVEY verwendet. Schauen Sie bitte deren genaue Funktion
im Glossar unter "Massenspeicher" nach.
Beispiel : Sie wollen in ihr File FIRST.SCR vor den
Screen 4 einen weiteren Screen einfügen. Dazu geben Sie
ein
use first.scr \ FIRST.SCR ist aktuelles File
l more \ Verlängere um einen Screen
4 capacity 2- 5 convey
\ kopiere 4..."vorletzer" nach
\ 5..."letzter" Screen
Anschließend sind die Screens 4 und 5 gleich und Sie
können den Screen 4 löschen, Beachten Sie bitte, daß Sie
bei Einfügen von Screens evtl. die Argumente von +THRU
+LOAD THERU und LOAD ändern müssen!
A-3
we/bp/re/kz
Die GEM-Bibliothek des volksFORTH83
Diese volksFORTH83-Version enthält eine umfangreiche Bibliothek
der GEM-Routinen. Diese Bibliothek gliedert sich in die Teile
AES ("Application Environment System") und VDI ("Virtual Device
Interface"). Im volksFORTH gehört auch ein Teil BASICS dazu,
der die VDI und AES gemeinsamen Teile enthält. Ferner gibt es
Files, die den Parameter-Konstanten der GEM-Routinen symbo-
lische Namen zuordnen und eine "Super"-Bibliothek.
Die Namen der von GEM zur Verfügung gestellten Funktionen
enstprechen völlig den Namen, die vom "C" des Entwicklungs-
pakets her bekannt sind. Viele Präfixe haben wir jedoch wegge-
lassen, da sie nur unnötig viel Platz verbrauchen
würden. Die Funktionen benötigen zumeist auch dieselben Argu-
mente, wobei wir uns bemüht haben, überflüssige Eingangswerte
wegzulassen (z.B. bestimmte Handles). Manche Aufrufe liefern
soviele Ausgangswerte, daß wir uns entschlossen haben, sie
nicht alle auf den Stack zu packen. In diesem Fall muß man sie
selbst aus dem enstprechenden Array holen. Wo, findet man ggf.
in der Literatur. Die Eingangswerte stehen jedoch (mit Ausnahme
von EVNT-MULTI) auf den Stack.
=) Wer Zugang zur GEM-Programmierung sucht, sollte sich die
Literatur des Enwicklungspakets von Atari verschaffen.
Dort sind (fast) alle Funktionen (viele fehlerhaft!)
beschrieben. Die Qualität ist aber nicht besonders, z.T
auch auf den IBM-PC abgestellt.
-) Empfehlenswert, wenn auch ausserordentlich knapp und daher
nur als Nachschlagewerk geeignet, ist das Handbuch zum
Megamax C-Compiler.
-) Einige Zeitschriften des Atari-Marktes beginnen Fort-
setzungsreihen zur GEM-Programmierung, die aber bisher
nicht empfehlenswert sind.
Für die GEM-Programmierung ist außerdem ein sog. Resource
Construction Set erforderlich. Das ist ein Programm, mit dem
die Menüleisten, Dialog- und Alertboxen sowie die Icons herge-
stellt werden. Das Programm erzeugt ein File, daß auf ".RSC"
endet (das sog. Resourcefile) und ein ".H"-File, daß die
Anbindung des Resourcefiles an "C"-Programme erlaubt. Dieses C-
File enthält Konstantendefinitionen für jedes "Objekt" (jedes
noch so kleine Teil eines Resourcefiles ist so ein Objekt), die
analog auch in ihrem Forth-Programm auftreten müssen. Verglei-
chen Sie dazu bitte das File EDIICON.H (für "c") mit
EDIICON.SCR, das dessen Übersetzung in Forth darstellt. Ein
Resource Construction Set gehört sowohl zum Lieferumfang des
Entwicklungspakets als auch zum Megamax-"C"-Paket.
A-4 (23 SEES weibp/reihs
Verzeichnis der Worte der GEM-Bibliothek
Die GEM-Bibliothek besteht aus den Files BASICS.SCR, VDI.SCR
und AES.SCR. Die in diesen Files enthaltenen Worte werden im
folgenden aufgeführt. Des weiteren soll sich eine Bibliothek
von "Super-worten" entwickeln, die die Handhabung der GEM-
Routinen vereinfacht. Diese Files sind über Shadowscreens
dokumentiert und daher hier nicht aufgeführt.
BASICS.SCR
Vocabulary GEM GEM definitions also
\ Das Vokabular, das die GEM-Worte enthält.
Create intin Create ptsin
Create intout Create ptsout
Create addrin Create addrout
\ Diese Arrays werden für die diversen Parameter benö-
tISE:
Variable grhandle
x Diese Variable nimmt die Handle auf, die von OPNVWK
geliefert wird.
Create contrl $16 allot
contrl 2 gemconstant opcode
gemconstant #intin
gemconstant #intout '* #intout Alias #ptsout
gemconstant #addrin
gemconstant #addrout
gemconstant function
\ Die Komponenten dieses Arrays tragen Namen und
enthalten die Zahl der Parameter, die in den betref-
fenden Arrays (s.o.) übergeben werden.
DDDDD
Create global
Constant ap_ptree
N Dieses Element des Arrays GLOBAL enthält die Adresse
eines Baumes, die von RSRC_LOAD initialisiert wird.
Create AESpb
Create VDIpb
% Diese beiden Arrays enthalten Zeiger auf die Arrays,
die die Parameter enthalten...
Code array! (n0 „.„ 'nk-1 adr k --)
\ Speichert k Werte ab Adresse adr in einem Array.
Code 4! (RE 2. md Jaddr ==)
Code 4@ ( addr -—- ni ..n4)
N Speichert bzw. liest 4 Werte ab Adresse addr. Sie
werden dazu benutzt, Rechtecke in die div. Arrays zu
schreiben bzw. herauszuholen.
Code AES ( opcode #intin #intout #addrin #addrout --
intout®)
\ Dieses Wort wickelt alle AES-Aufrufe ab.
Code VDI ( opcode #ptsin #intin --)
N Dieses Wort wickelt alle VDI-Aufrufe ab.
1825 Werbp/re/ks A-5
: appl_init
N Dieses Wort initialisiert die Applikation und sollte
vor dem ersten Aufruf einer AES-Funktion aufgerufen
werden.
: appl_exit
\ Dieses Wort sollte am Ende einer Applikation aufgeru-
fen werden.
Create sizes 8 allot
N Dieses Array enthält die Größe eines Buchstabens und
einer Box in Pixeln
Sizeconst c_width Sizeconst c_height
Sizeconst b_width Siezconst b_height
N Diese Worte lesen die Felder in SIZES aus, die die
Höhe und Breite eines Zeichens bzw. einer Box enthal-
ten.
graf_handle
\ Liefert die VDI-Handle in der Variablen GRHANDLE und
die Buchstaben- bzw. Boxgröße in SIZES
: opnvwk
\ Öffnet eine "virtual workstation" und muß zu Beginn
einer Applikation aufgerufen werden.
: clrwk
\ Löscht die Workstation. Der Hintergrund wird in der
gewählten Farbe gemalt.
: clsvwk
N Schließt die "virtual workstation". Muß vor Beenden
des Programms aufgerufen werden.
: updwk
x Update virtual workstation. Alle VDI-Kommandos werden
zuende ausgeführt.
isSheclip ( x1 yl1 x2 y2 clipflag -- )
N Setze Größe und Position des Clipping rectangle für
alle VDI-Aufrufe.
!sgrinit appl_init graf_handle opnvwk ;
\ Faßt alle benötigten Aufrufe am Anfang einer Applika-
tion zusammen.
: grexit clsvwk appl_exit B
\ dto. für die Beendigung einer Applikation.
Variable c_flag
\ gibt an, ob die Aufrufe von SHOW_C und HIDE_C
akkumuliert werden sollen.
: show_c (25 >
N Schalte die Maus an.
: hide_c ee)
Schalte die Maus aus.
2Variable objc_tree
\ Enthält den Objektbaum, auf das sich die folgenden
Worte beziehen : MENU_BAR MENU_ICHECK MENU_IENABLE
MENU_TNORMAL MENU_TNEXT FORM_DO FORM_CENTER
re}
\ Anhang E A-6 (23 1326 weibp/reins
Termemmer ae
nn
AES.SCR
Event :
: evnt_keybd ( -- key )
\ Wartet auf einen Keyboard-event. key besteht aus
scan-code und ASCII-Wert.
: evnt_button ( #clicksO bmask bstate -- #clicksi )
\ Wartet auf einen button-event. #clicks0 gibt die
Anzahl der Clicks an, bmask und bstate geben die zu
drückende Taste an. #clicksi ist die Zahl der Clicks.
: evnt_mouse ( £ leftX topY widht height -- )
\ Wartet auf einen mouse-movement-event. £ ist null für
das Betreten und 1 für das Verlassen des durch leftX
topY width und height spezifizierten Rechtecks.
Create message
\
Dieses Array ist der message-event-buffer.
: evnt_mesag =)
\
Wartet auf einen message-event.
: evnt_timer ( dtime -- )
\
Wartet auf einen Timer-event. dtime ist die (doppelt
genaue) zu wartende Zeit in msec.
Create events
\ Dieses Array enthält die Eingangsparameter des Wortes
EVNT_MULTI. Der Inhalt dieses Feldes ist wie folgt :
+0 : Art der erkannten Events :
Bit 0 Keyboard
Bit 1 Button
Bit 2 Mouse rectangle 1
Bit 3 Mouse rectangle 2
Bit 4 Message
Bit 5 Timer
+2 #clicks0 Zahl der zum "Auslösen" erforderlichen
i Mausklicks.
+4 bmask Bit 0 : linker, Bit 1 : rechter ist zu
betätigen.
+6 bstate Gibt an, ob der entsprechende Knopf
von bmask gedrückt oder gelöst sein
muß.
+8 £ leftX topY width heicht, gibt an, ob der
- Eintritt (£f=0) oder Austritt (£=1) aus dem
angegebenen Rechteck signalisiert werden soll.
#18 mn N (ek en : ao.
+28 dtime Zu wartende Zeit in msec.
prepare
\ ieses Wort kopiert den Inhalt von EVENTS in die
enstprechenden Parameterarrays und sollte vor
EVNT_MULTI aufgerufen werden.
: evnt_multi ( -- which )
\ Dieses Wort wartet auf einen von mehreren möglichen
Events. Das Array EVENTS enthält die Parameter dieser
Routine. which ist die Nummer der aufgetretenen
Events nach dem Schlüssel wie für das erste Wort von
EVENTS. Die Ausgabeparameter müssen den GEM-Arrays
entnommen werden...
(23% SEE weibp/re/ks A-7 Anhang
evnt_dclick ( dnew dgetset -- dspeed )
N Dieses Wort setzt oder liest die Zeitspanne für einen
erkannten Mehrfachclick. dgetset = 1 bedeutet, daß
adnew als neue Zeit gesetzt wird. dspeed ist die
eingestellte Zeitspanne.
Menu :
: menu_bar ( showflag -- )
N Löscht oder setzt die Menüleiste.
: menu_icheck ( item showflag -- )
\ Setzt oder löscht den Haken vor einem menu item
: menu_ienable ( item enableflag -- )
\ Schaltet einen menu item ein oder aus. Ausgeschaltete
menu items erscheinen in heller Schrift.
: menu_tnormal ( title normalflag -- )
N Stellt einen Menütitel normal oder invers dar.
: menu_text ( item laddr -- )
\ Ändert den Text eines menu item. Die Länge darf sich
aber nicht ändern !
: menu_register( apid laddr -- menuid )
\ Installiert ein Desktop Accessory in der Menüleiste.
menuid ist die Position im Menü
Object
: objc_add ( parent child -- )
\ Fügt ein Objekt child an das Ende der child list. des
Objektes parent an.
: obje_delete ( object -- )
\ Löscht ein Objekt vom Baum.
: objce_draw ( startob depth x y width height -- )
\ Zeichnet den Baum von startob mit der Tiefe depth
neu. x y width und height geben ein Clipping-
Rectangle an.
: obje_find ( startob depth x y -- obnum )
\ Sucht das Objekt unter der Mausposition x y . Liefert
die Objektnummer oder -1.
: obje_offset ( object -- xy)
\ Liefert die Bildschirmpositon eines Objektes
: objc_order ( object newpos -- )
\ Bewegt ein Objekt von einer Stelle des Baums zu einer
anderen.
: obje_edit ( object char index kind -- newindex )
\ wird zum Editieren des Textes innerhalb eines Objek-
tes benutzt.
: obje_change ( object x y width height newstate redraw -- )
\ Ändert den Objektstatus und zeichnet das Objekt neu.
Tr
fi m
|] Anhang E A-8 2) 1BEE Weibp/refns
PERraTT TORE Tre nem ES
Form :
: form_do ( startobj -- objectno )
\ Diese Routine zeigt ein Objekt an und erlaubt dem
Benutzer, es zu ändern. objectno. ist die Nummer des
exit button.
: form_dial ( diflag lix liy liw lih bix biy biw bih )
N Diese Routine besteht aus vier Routinen, ihre Funk-
tion wird von diflag bestimmt:
0 Reserviere einen Bildschirmbereich für ein
Objekt.
1 Male eine wachsende Box
2 Male eine schrumpfende Box
3 Gib den reservierten Bildschirmbereich
frei.
: £form_alert ( defbttn Ostring -- exbttn )
\ Erlaubt auf einfache Art, Alert-Boxen zu bauen.
defbttn ist der Defaultknopf, Ostring ist ein durch
$00 begrenzter String, der das Aussehen der Box
bestimmt und exbttn ist der gedrückte Knopf.
: form_error ( enum -- exbttn )
\ Malt eine Alertbox mit dem Text "TOS-Fehler-Nummer
soundso"
: form_center ( -- x y width height )
\ Rechne die Position eines in der Mitte des Bild-
schirms zentrierten Objektes aus.
Graphic :
: graf_dragbox ( startx starty width height boundx boundy
boundw boundh -- finishx finishy )
\ Malt den Umriß einer Box, die auf dem Bildschirm mit
der Maus bewegt werden kann. Die Bewegung der Maus
wird durch ein äußeres Rechteck beschränkt.
: graf_movebox ( sourcex sourcey width height destx desty
u)
\ Malt eine Box, die sich von source nach dest bewecdt.
: graf_growbox ( stx sty stw sth fix fiy fiw fih -- )
\ Malt eine expandierende Box.
: graf_shrinkbox ( £fix fiy fiw fih stx sty stw sth -- )
\ Malt eine schrumpfende Box.
: graf_watchbox ( object instate outstate --
inside/outside )
\ Überwacht die Bewegung der Maus innerhalb eines
Objektes....
ı graf_slidebox { parent object vhflaqg -- vhpos )
\ Überwacht das Ziehen einer kleinen Box in einer
großen Box mit der Maus....
2Variable mofaddr
\ Zeiger auf eine selbst definierte Mausform
graf_mouse ( mouseform -- )
Setzt die Mausform :
0 Pfeil
ı Cursor
2 Biene
3 Zeigefinger
4 Hand
5 dünnes Fadenkreuz
2) SEE werbp/re/khs A-9 Anhang
6 dickes Fadenkreuz
7 Fadenkreuz mit Umriß
255 selbst definiert
256 hide mouse
257 show mouse
: graf_mkstate (==)
\ liefert Mausposition und Knöpfe in den div. Arrays
zurück.
Fileselect :
Create inpath
N Der Defaultpath steht in diesem Array mit einem $00-
Byte abgeschlossen.
Create insel
\ Der Name des selektierten Files ...
fsel_input ( -- button )
R malt die sog. File selector box und wartet auf die
Auswahl eines Files. button ist der gedrückte Knopf
(0 = Cancel)
Window :
wind_create ( components leftX topY maxWIDTH maxHEIGTH --
handle)
\ dieses Wort erzeugt ein Fenster mit div. Bestandtei-
len und einer Maximalgröße. Liefert eine Handle für's
Fenster.
wind_open ( W-handle leftX topY width height -- )
\ Malt ein Fenster in der angegeben Größe auf dem
Bildschirm.
wind_close ( Whandle -- )
\ Schließt und löscht ein Fenster. Es kann auch wieder
geöffnet werden.
wind_delete ( Whandle -- )
\ Löscht ein Fenster, so daß es nicht mehr geöffnet
werden kann.
wind_get ( Whandle funktion# -- )
\ Liefert div. Informationen über ein Fenster...
wind_set ( Whandle funktion# parO0 parl par2 par3 -- )
\ Setzt div. Attribute eines Fenster wie Titelzeile,
Sliderpos. usw.
wind_find { mouseX mouseY -- Whandle )
\ Sucht das Fenster unter der Mausposition.
wind_update ( funktion# -- )
\ wird benutzt, um die Manipulation an anderen Fenstern
oder Menüauswahl während des Zeichnens zu unterbin-
den.
wind_calc ( 0/1 components leftX topY width height -- )
\ Konvertiert bei Fenstern die Innen- in Außenmaße (0)
oder umgekehrt (1). Die Ausgabe erfolgt in den GEM-
Arrays.
RSRC : : rsrc_load ( 0$ -- ) \ needs address of 0-termina-
ted $
\ Lädt ein Resourcefile in den Speicher.
ı rsrc_load"
\ Lädt das Resourcefile, dessen Name, durch ein "
begrenzt, auf dieses Wort folgt.
ı rsrc_free (--)
N Gibt den durch ein Resourcefile beanspruchten Spei-
cherbereich wieder frei.
ı rsrc_gaddr ( type index -- laddr )
\ Liefert die Adresse eines Objektes im Resourcefile.
ı rsrce_saddr ( type index laddr --)
\ Speichert die Adresse eines Objektes ab.
: rsrc_obfix ( index laddr --)
N Konvertiert Objektlage und Größe von Character- in
Pixeleinheiten. i
1528 wesbe/re/ns Az1l Anhang
VDI.SCR
Output Function
: pline {x1 yl x2 y2 ... xn yn count -- )
x malt eine geknickte Linie von x1,yl zu x2,y2 usw.
pmarker (x1 ylx2 y2 ... xn yn count -- )
\ Gibt Polymarker aus.
: gtext ( addr count x y --
\ Gibt Text an der angegebenen Stelle aus.
: fillarea (aXLl.y3 22442s.%. &0n yn count ==.)
\ Malt ein ausgefülltes Vieleck.
® contourfill ( color xy --)
\ füllt ein gemalten Bereich aus.
: r_recfl (x1 y1x2 y2 --)
\ Malt ein Rechteck ohne Rand.
: GDP ( #ptsin #intin functionno -- )
\ Allg. Malroutine
: bar {xl si 2 y2 —.)
N Malt ein gefülltes Rechteck mit Rand.
: are ( startwinkel endwinkel x y radius -- )
N\ Malt den Ausschnitt eines Kreises.
: pie ( startwinkel endwinkel x y radius -- )
\ Malt ein Stück Torte.
: circle (xy radius -- )
\ Malt einen Kreis
: ellarc ( startwinkel endwinkel x y xradius yradius -- )
\ Malt einen Ellipsenabschnitt
: ellpie ( startwinkel endwinkel x y xradius yradius -- )
\ Jetzt gefüllt !
: ellipse {x y xradius yradius -- )
\ Und nochmal, bloß ganz.
: xbox ' (x1y1l1x2y2--)
\ Rechteck mit abgerundeten Ecken
: r£fbox (xs1y1x2y2 --)
\ gefüllt.
: justified ( string x y length wordspace charspace -- )
\ Textausgabe mit definierter Länge, maximalem Wort-
und Buchstabenabstand.
Attribute Function :
wur
SUbHr
swr_mode
\
Setmode
Setmode
sl_type
\
Settype
Settype
Settype
Settype
( mode -- )
Setzt Ausgabemodus...
replace 2 Setmode transparent
exor 4 Setmode revtransparent
( style -- )
Setzt Polyline type
solid 2 Settype longdash
dot 4 Settype dashdot
dash 6 Settype dashdotdot
userdef
..
Anhang A-12 2) IHEE werke/reits
sl_udsty ( pattern -- )
\
setzt user defined line style
sl_width ( width -- )
\
setzt polyline line width
sl_color ( color -- )
\
setzt polyline color index
sl_ends ( begstyle endstyle -- )
\
setzt polyline end styles
sm_type ( symbol -- )
\
setzt polymarker type
Setmtype point 2 Setmtype plus
Setmtype asterisk 4 Setmtype square
Setmtype cross 6 Setmtype diamond
sm_height ( height -- )
N setzt polymarker height
sm_color (. eSlor”==)
\ setzt polymarker color index
st_height ( heicht --)
\ setzt text character height (absolut)
st_point ( point -- )
\ setzt text character height (points)
st_rotation ( winkel -- )
\ setzt character baseline rotation
st_£font ( £font -- )
\ setzt character font
st_color { veoTor +==
\ setzt text colour
st_effects ( effect -- )
\ setzt fett, kursiv usw.
st_alignement { horin vertin -- )
\ setzt character alignment
sf_interior ( style --
\ setzt fill interior style
sf_style { styleindex -- )
\ setzt fill style index
sf_color teesten«-=7)
\ setzt fill colour index für Vielecke
sf_perimeter ( pervis -- )
\ schaltet fill outline um.
Raster Operation :
\
Die Rasteroperationen dienen zum schnellen Verschieben
von Bildschirmbereichen sowohl auf dem Bildschirm selbst
als auch vom Bildschirm in den Speicher und zurück. Da
es sich um sehr schnelle Routinen handelt, sollte von
ihnen immer dann Gebrauch gemacht werden, wenn Bild-
schirminhalte restauriert werden müssen. Alle - sonst
notwendigen - Ausgaberoutinen brauchen erheblich mehr
Zeit.
(23 1928 wesbe/re/ks A-13 Anhang N
Create scrMFDB
Variable >memMFDB
\ Die Memory Form Definition Blocks beschreiben den Aufbau
eines Pixelblocks im Speicher oder auf dem Bildschirm.
Um mit mehreren Speicherbereichen arbeiten zu können,
enthält >memMFDB einen Pointer auf den gerade benutzten
Bereich.
: copyopaque ( X£fr Y£fr width height Xto Yto mode --)
\ Grundroutine für alle Rasteroperationen
scr>mem ( addr_of_memMFDB -- )
\ Definierendes Wort für Rasteroperation (Bildschirn-
>Speicher)
ı mem>scr ( addr_of_memMFDB -- )
\ Definierendes Wort für Rasteroperation (Speicher-
»Bildschirm)
ı scr>scr ( X£fr Y£fr width height Xto Yto --)
\ verschiebt ein Rechteck auf dem Bildschirm.
Create memMFDBl
\ Ein Speicherblock, der den gesamten Bildschirm speichern
kann.
: scr>meml ( Xle£ft Ytop Width Heigth -- )
\ verschiebt den gesamten Bildschirm in den Speicher.
: mem>scrl ( Xleft Ytop Width Heigth -- )
\ verschiebt den Speicherblock wieder in den Bildschirm.
ı r_trnfm (==7)
\ rechnet Standard- in gerätespezifische Koordinaten um
und umgekehrt.
: get_pixel (xy -- color flag )
\ ermittelt die Farbe eines Pixels. flag ist 1, wenn Punkt
gesetzt.
Input :
: sin_mode ( devtype mode -- )
\ legt den Inputmodus fest....
: sm_locater (xy -- status )
\ Position der Maus, Angabe der Anfangspos. erforder-
lich
sm_valuator ( val_in -- status )
\ Verwaltung von Wertänderungen ....
: sm_choice ( -- status )
\ Teste die Funktionstasten
ı sm_string ( addr max_len echomode x y -- status )
\ Eingabe eines Strings mit Echo.
: sc_form ( addr -- )
\ setzt Mausform
! ex_time ( tim_addr -- long_otim_addr )
\ Ersetzt Timerinterrupt-Vektor
! q_mouse ( -- xy status )
\ Liest den Mauszustand aus.
: ex_butv ( pusrcode -- long_psavcode )
\ Ersetzt Mausbuttoninterruptroutine
ex_motv ( pusrcode -- long_psavcode )
N ... Mausbewegungsinterruptroutine...
ex_curv ( pusrcode -- long_psavcode )
N ... Mausforminterruptroutine...
q_key_s (
\ liefert Zustand der Shift-Tasten.
Inquire :
q_extnd {
\ Diese und
festzustellen,
hat.
getätigt
daher muß
we/cp/re/rs
-- status )
info_flag -- )
die folgenden Funktionen dienen dazu,
welche der obigen VDI-Aufrufe man
Man kann sie nicht kurz beschreiben,
die Eingangs erwähnte Literatur zu Rate
gezogen werden.
q_color (
ql_attributes
qm_attributes
qf_attributes
gt_attributes
at_extent
at_width
qgt_name
q_cellarray
qin_mode
at_fontinfo
color_index info_flag )
string -- )
char -- status )
element_num -- )
cols rows x1 yl x2 y2 -- )
dev_type -- mode )
u)
Escape :
: q_chcells ( -- rows cols )
\ Größe des Bildschirms
: exit_cur (--)
\ textcursor aus
: enter_cur (==)
\ textcursor ein
: curup -—)
\ hoch
: curdown (--)
\ runter
: curright ()
”777
: curleft (--)
\ tz]
: curhome =
cursor nach links oben
: eeos (=)
\ erase to end of screen
: eeol (==)
\ " nansen- line
: s_curaddress ( zowW"ech- -—=)
\ positioniere cursor
curtext ( addr count -- )
\ textausgabe
: rvon (--)
\ reverse video on
: rvof£f {--)
\ ne off
g_curaddress (== FoWi coT- )
\ frage nach cursor adress
: q_tabstatus ( -- status )
\ frage nach Mausstatus
hardcopy {
\ screen dump
-- )
I8ZE we/bp/re/hzs A-1215
(xy--)
positioniere maus
U
entferne Maus
Die folgenden Befehle dienen zur Arbeit mit verschiedenen
Output-Devices. Dies ist ein besonders schlecht dokumentierter
Teil. Einige Hinweise findet man in der Dokumentation zum
Entwicklungspaket von Digital Research. Es ist fraglich, ob
alle Befehle tatsächlich auf dem Atari arbeiten. Versuche in
dieser Richtung sind bislang noch nicht erfolgreich gewesen.
: form_adv (==)
\ Für Drucker: Seitenvorschub
: output_window (xıyıx2y2--)
N Für Drucker: Gibt ein Fenster aus.
: clear_disp_list (==)
\ Für Drucker: bricht Ausdruck ab, wie Clear Worksta-
tion, aber ohne abschließendes Linefeed.
: bit_image ( string aspect scaling num_pts x1 yl x2 y2
he)
\ Für Drucker: Gibt ein 'Bit Image File' aus.
Die folgenden Befehle beziehen sich auf zusätzliche Output-
Treiber; ein Effekt auf dem Atari ist bisher nicht bekannt. Sie
sind nur der Vollständigkeit halber aufgeführt.
: s_palette ( palette -- selected )
x setzt Farbpalette auf IBM-Farbmonitor ??!!
: qp_films ==
: qp_state (--)
: sp_state ( addr -- )
: sp_save ==)
: sp_message (==)
! qp_error =)
: meta_extents (x1yıix2 y2 --)
: write_meta { intin num_intin ptsin num_ptsin -- )
: {
m_filename string -- )
Der Assembler
Der im volksFORTH83 für den Atari 520 ST enthaltene 68000-
Assembler entspricht im Wesentlichen dem von Michael Perry für
das F83 entwickelten. Daher bringen wir hier eine Übersetzung
eines Artikels aus 'Dr. Dobbs Journal', Nr.83 vom September
1983, in dem Michael Perry seinen Assembler beschrieben hat.
Abweichungen des volksFORTH-Assemblers werden besonders
erwähnt. Im Anschluß an die Übersetzung werden die zusätzlichen
Funktionen des volksFORTH- Assemblers beschrieben.
Ein 68000 Forth Assembler
In diesem Artikel werde ich die Eigenarten eines Assemblers in
FORTH, seinen Gebrauch und die Implementation eines Beispiels
beschreiben: Ein FORTH Assembler für den 68000. Ich hoffe, die
Leistungsfähigkeit eines solchen Assemblers darlegen zu können,
einige der damit verbundenen Eigenarten, und warum er so und
nicht anders programmiert wurde. Um den Leser nicht zu verwir-
ren, verzichte ich auf Verallgemeinerungen. Ich werde gelegent-
lich Dinge darstellen, die sich speziell auf mein System
beziehen und auf anderen Systemen leicht abweichen können.
Kurz gesagt ist ein FORTH-System eine interaktive Programmier-
umgebung, in der einzelne Module, 'Worte' genannt, in einer
Datenstruktur namens Dictionary abgelegt werden. Der Progran-
mierer kann neue Worte hinzufügen, die entweder aus vorhandenen
FORTH-Worten oder aus Maschinencodedefinitionen bestehen. Ein
Assembler in einem FORTH-System ist ein Werkzeug, um Coderouti-
nen zu definieren. Er ist nicht dazu vorgesehen, eigenständige
Applikationen in Maschinensprache zu schreiben. Ein FORTH
Cross-Assembler ist ganz ähnlich aufgebaut. Mit ihm kann man
Code erzeugen, der auf einem anderen System läuft, eventuell
sogar auf einem anderen Prozessor. Dieser Artikel bezieht sich
nur auf 'normale' FORTH-Assembler. FORTH-Assembler sind kurz,
da sie auf vorhandene FORTH-Worte zurückgreifen können; dieser
Assembler z.B. benötigt nur ca. 3 kByte, dazu kommt das System
mit 12 kByte. Zum Vergleich: Der Assembler, der zum CPM 68k
gehört, benötigt 44 kByte, zusätzlich etwa 6 kByte für die
Symboltabelle.
Wenn man Applikationen in FORTH schreibt, wird der Assembler
selten eingesetzt, bevor die einzelnen Programmteile nicht in
High-Level geschrieben und ausgetestet sind. In den Anfangssta-
dien einer Entwicklung ist die Zeit, die der Programmierer
braucht, wesentlich wertvoller als die der Maschine. Wenn eine
Applikation lauffähig ist, mag es sich herausstellen, daß sie
in High-Level zu langsam ist. In diesem Falle muß man heraus-
finden, welche Routinen zeitkritisch sind und dann nur diese in
Code neu schreiben. Diesen Vorgang wiederholt man so lange, bis
das Programm schnell genug ist. Vermeiden Sie mehr Coderoutinen
als erforderlich, da diese die Übertragbarkeit Ihres Programms
stark einschränken. In seltenen Fällen, wenn man eine sehr
zeitkritische Anwendung vor sich hat, wird man letztlich fast
alles in Code schreiben.
A-18 (23 1828 weibp/rerhs
Sogar in solchen Fällen wird die Entwicklung in der oben
beschriebenen Reihenfolge am schnellsten zu Resultaten und zur
fertigen Anwendung führen. Seien Sie immer bereit, frühere
Entwürfe über den Haufen zu werfen und von vorn zu beginnen.
Der Schlüssel zum Erfolg ist schrittweise Annäherung: Schrei-
ben, Testen, Überarbeiten, bis Sie endgültig zufrieden sind.
Das ist der Grund, warum es so wichtig ist, zunächst eine
einfache Version zu entwickeln, um zu sehen, ob die Grundidee
richtig und durchführbar ist.
Der Name eines FORTH-Wortes kann aus bis zu 31 Ascii-Zeichen
bestehen, ausgenommen sind Leerzeichen. Worte im Dictionary
sind in Gruppen zusammengefaßt, die man Vokabulare nennt. Der
Assembler ist ein solches Vokabular namens ASSEMBLER. Die
meisten Worte im Assembler haben die Namen der üblichen
Mnemonics des Prozessors, win unserem Falle des 68000. Wenn so
ein Wort ausgeführt wird, legt es die zugehörige Bytefolge im
Dictionary ab. Andere Worte im Assembler behandeln die Adres-
sierungsart, Kontrollstrukturen, Makros und möglicherweise
andere Erweiterungen. Hält man sich an eine FORTH-übliche
Syntax, ist es mit wenig Aufwand möglich, einen sehr leistungs-
fähigen Assembler zu implementieren.
Die zwei wichtigsten Einschränkungen sind die Syntax und der
Verzicht auf Vorwärtsreferenzen. Wie in FORTH üblich sind
Vorwärtsreferenzen nicht erlaubt. Das heißt, ein Wort muß vor
seinem ersten Aufruf definiert sein. Ich bin der Überzeugung,
dies ist eine gute Sache, aber diese Meinung beschwört endlose
Debatten herauf, und ich werde sie hier nicht beeenden können.
Es ist sehr viel einfacher (und damit auch erheblich schnel-
ler), wenn man eine Syntax verwendet, bei der der Operator
hinten steht. Das bedeutet, die Befehle werden in folgender
Form geschrieben:
Source Destination Operation
Wenn auch ungewöhnlich, so ist dieses Format doch sehr flexibel
und einfach zu verwenden. Ein Pre-Prozessor, der die übliche
Schreibweise verarbeiten kann, könnte relativ leicht eingebaut
werden, wenn man die damit verbundenen Geschwindigkeitsnach-
teile in Kauf nimnt.
Das Dictionary wächst in Richtung steigender Adressen, wenn
neue Worte hinzugefügt werden. Die meisten Datenstrukturen
werden ebenfalls im Dictionary abgelegt. Die Systemvariable DP
zeigt auf die nächste freie Adresse. Das Wort HERE übergibt den
Wert von DP auf dem Stack. Das Wort ,„ (comma) trägt einen 16-
Bit-Wert ins Dictionary ein, das Wort c, (c-comma) einen 8-Bit-
Wert (ein Byte). Der Assembler ist nur auf comma und c-comma
aufgebaut.
Fehlerbehandlung
Wenn ich einen Assembler benutze, erwarte ich von ihm einige
wichtige Leistungsmerkmale. An erster Stelle steht natürlich
die richtige Übersetzung: Richtige Eingaben müssen zu richtigen
Ausgaben führen. Das zweite ist die Geschwindigkeit. Ich
möchte, daß der Assembler seine Arbeit so schnell wie möglich
2) 1828 we/be/re/ks Az19 Anhang
erledigt. Das dritte ist die Genauigkeit der Übersetzung: Wenn
ich Assemblercode schreibe, möchte ich ihn selbst optimieren.
Ich möchte keinen optimierenden Assembler benutzen - ich hasse
Überraschungen. Schließlich verwende ich ungern allzu 'schlaue'
Operatoren, d.h. solche, die mir ein gewisses Maß an Denkfaul-
heit erlauben, wenn z.B. ADD manchmal ADDI, manchmal auch ADDO,
ADDA oder sonst etwas assembliert. Solche Operatoren sind
langsamer und ihr Verhalten weniger durchsichtig. Da FORTH-
Assembler erweiterbar sind, kann jeder Benutzer eigene
'schlaue' Operatoren hinzufügen, wenn er möchte.
Bei der Fehlerbehandlung kann im Assembler beliebiger Aufwand
getrieben werden. Im Idealfall sollte ein Assembler nur kor-
rekte Eingaben akzeptieren. Es kann allerdings vor allem in
Bezug auf die Geschwindigkeit teuer werden, wenn man übertrie-
bene Fehlerkontrolle einbaut. Zum Glück können viele Fehler
sehr leicht entdeckt werden. Es ist einfach zu prüfen, ob sich
die Stacktiefe während einer Definition verändert (kein Wert
bleibt unzulässigerweise übrig bzw. wird verbraucht), ob die
Kontrollstrukturen ausgeglichen sind usw.
Die nächste Stufe der Fehlererkennung ist die Prüfung auf
erlaubte Adressierungsarten bei jedem Befehl. Bei einer sehr
geradlinigen Prozessorarchitektur ist das sehr einfach.
Unglücklicherweise ist der 68000 nicht ganz dazu geeignet, auch
wenn oft das Gegenteil behauptet wird. Trotzdem können viele
Befehle einfach überprüft werden. Obwohl ich so etwas gewöhn-
lich nicht benutze, habe ich einige Worte eingebaut, die
nachprüfen, ob den Befehlen gültige Adressierungsarten zugeord-
net sind. ??DN bricht ab, wenn keine direkte Adressierung eines
Datenregisters vorliegt. ??AN führt das gleiche für ein Adreß-
register durch. ??YJMP bricht ab, wenn beim UMP-Befehl eine
ungültige Adressierung benutzt wurde.
Für weitergehende Fehlererkennung muß zunehmender Aufwand bei
abnehmender Wirkung getrieben werden.
Gebrauchsanleitung für den Assembler
Eine detaillierte und ziemlich genaue Beschreibung des Motorola
MC68000 findet man im entsprechenden User's Manual. Als
Beispiel für die Benutzung des Assemblers nehmen Sie bitte die
Definition des Wortes FILL, das einen Speicherbereich mit einen
vorgegebenen Byte füllt. Es wird folgendermaßen benutzt:
adresse länge byte FILL
Beachten Sie, daß FILL drei Parameter vom Stack benötigt und
nichts übrig läßt.
(Das folgende Beispiel wurde so abgeändert, daß es dem volks-
FORTH-83 entspricht. Näheres zu den Macros s.u. - Anm. d.
Übers.)
Code fill { adr len val -- )
SP )+ DO move \ Wert nach DO
SP }+ D1 move \ Länge nach D1
SP )+ D6 move \ Adresse nach D6,
D6 reg) AO lea \ reg) ist ein Macro, das aus der 16 Bit
A-2090 (23 1328 weibp/teiks
Systemadresse eine absolute 32-Bit Adresse
berechnet.
D1 tst 0<> IF \ Wenn Länge von 0 verschieden
1 DI subq \ decrement D1; dbra läuft bis -1, nicht O
D1 DO .b DO AO )+ move LOOP
\ Schleife bis DI = -1; jedesmal wird ein
Byte in die
\ Adresse, die in AO steht, geschrieben und
AO incrementiert.
THEN
Next \ ein Macro, das zum nächsten Wort springt.
end-code \ beendet die Definition
Das Wort CODE ist ein definierendes Wort. Es erzeugt einen Kopf
für das neue Wort FILL und setzt dessen Codefeld auf das
Parameterfeld. Das System bleibt im interpretierenden Modus.
Der Assembler benutzt den FORTH-Compiler nicht, wie häufig
fälschlich angenommen wird. Der Kopf ist so etwas wie ein
Eintrag in eine Symboltabelle. Das Codefeld eines jeden Wortes
zeigt auf den Code, den dieses Wort ausgeführen soll. Normaler-
weise zeigen alle Worte, die mit denselben defining words
erzeugt worden sind, auf den gleichen Code. Worte, die mit CODE
erzeugt werden, bestehen aus einem einzigartigen Code-Segment,
das immer auf das Parameterfeld eben dieses Wortes zeigt. Die
übrigen Worte der Codedefinition erzeugen eine Bytefolge im
Parameterfeld des Wortes.
Assembler-Opcode-Worte wie MOVE benutzen das Wort comma, um der
Reihe nach Bytes in das Parameterfeld einzutragen. Wenn das
neue Wort nach seiner Ausführung in den FORTH-Interpreter
zurückkehren soll, muß die letzte Anweisung NEXT sein. Next ist
ein Makro, das einen Sprung in den FORTH-Interpreter assem-
bliert. Seine Definition lautet (im volksFORTH83):
: Next IP )+ D7 move \ D7 enthält cfa
D7 reg) D6 move \ D6 enthält cfa@
D6 reg) jmp \ Sprung auf cfa®@
r
(Das Macro reg) wird weiter unten beschrieben. Ann. d. Übers.)
JMP benutzt comma, um den richtigen Opcode und die Adresse
einzutragen. END-CODE markiert das Ende, prüft auf Fehler und
räumt ein bißchen auf.
SP ist der Name des Stackpointers der virtuellen FORTH-
Maschine. Das Wort SP hinterläßt einen Wert auf dem Stack, der
den 'direct-adressing' Modus mit Register A6 (volksFORTH33)
darstellt. Das Wort A6 hat genau die gleiche Wirkung; beides
sind einfache Konstanten. Das Wort )+ modifiziert den Wert auf
dem Stack, den SP hinterlassen hat, um die 'indirect mit auto-
increment' Adressierung anzuzeigen. Wie das funktioniert, wird
später erklärt. Das Wort DO steilt Datenregister O dar.
Das Wort MOVE assembliert einen 68000 move-Befehl. Es benötigt
zwei Werte, die jeweils eine Adressierungsart beinhalten. In
unserem Beispiel wird der assemblierte Code 16 Bit aus der
Adresse, auf die SP zeigt, nach DO transportieren und dabei SP
ke> 1585 Wwe/bp/re/ks A-21 Anhang
um zwei erhöhen. Die Länge der Operation wird von der Variablen
SIZE festgelegt ,„ die auf 16-Bit voreingestellt ist. SIZE wird
durch .B (Byte), .W (Word) und .L (Long) entsprechend gesetzt.
Das Wort CODE schaltet das Assembler-Vokabular ein, damit bei
gleichen Worten im Assembler und im übrigen System (z.B. SWAP)
das richtige Wort gefunden wird. Das Wort LMOVE wurde zusätz-
lich definiert als Spezialfall von MOVE für die oben ange-
sprochene Registerverschiebung. LMOVE assembliert immer einen
Long move, ohne dabei SIZE zu verändern. Beachten Sie den
Gebrauch von DO und LOOP im Assembler. DO erhält ein Daten-
register zugeordnet, das den Schleifenzähler für die Ausfüh-
rungsphase enthält. DO übergibt HERE und das Register an LOOP,
welches einen dbra zurück auf DO assembliert, bei dem das
angegebene Datenregister benutzt wird. (In ähnlicher Weise
assembliert 0<> IF einen beq (!), dessen Offset beim folgen-
den THEN berechnet wird. Beachten Sie bitte, daß die Sprung-
bedingungen vor IF immer gerade entgegengesetzt den Sprung-
befehlen sind, also beq bei 0<> oder bne bei 0=. Anm. d.
Übers.)
Implementation
Es gibt viele mögliche und darunter zwei häufiger beschrittene
Wege, um einen Assembler in FORTH zu schreiben. Eine Methode
ist, viele Variable mit Status-Informationen zu benutzen, die
ihrerseits von den Mnemonic-Worten verwendet werden, um den
Assembliervorgang zu steuern. Nach jeder Instruktion werden sie
gelöscht, um von der nächsten Instruktion wieder verwendet
werden zu können. Bei diesem Assembler ist eine weiter verbrei-
tete und auch wünschenswertere Methode gewählt worden. Fast
sämtliche Informationen werden auf dem Stack übergeben, der
auch nicht initialisiert werden muß.
Ebenso gibt es zwei verbreitete Arten, die Adressierungsart an
das assemblierende Wort zu übergeben. Eine Möglichkeit besteht
in einer Art geschachtelter IF...ELSE Strukturen, die aus einer
Folge von Möglichkeiten die richtige heraussucht, Der andere
Weg, hier eingesetzt, besteht darin, daß die Worte, die die
Adressierungsart bestimmen, die Werte, die ihnen übergeben
wurden, in wäirgendeiner Form verändern. Dies geschieht durch
Ausmaskieren mit AND und Setzen einzelner Bits mit OR. Solche
Logikoperationen arbeiten bekanntlich viel schneller als
Verzweigungen, sodaß der Assembler insgesamt mit solchen Opera-
tionen schneller wird.
Wenn Sie die folgenden Beschreibungen lesen, sollten Sie sich
den Quelitext des Assemblers zur Hand nehmen. Er befindet sich
auf Ihrer Diskette im File ASSEMBLE.SCR.
Die Grundidee, die hinter diesem Assembler steckt, ist die
Betrachtung einer Maschinencodeinstruktion als Reihe von Bit-
Feldern. Diese Bit-Felder sind im Manual der CPU beschrieben.
Einige sind für viele Instruktionen gültig wie source und
destination, mode und register Felder.
Iop-code!dest reg!dest modeisource mode;source reg!
5 12111 918 615 312 0
A-22 (23 1328 werbp/re/ks
Wie bereits erwähnt, benutzen Instruktionen, die die Datenlänge
kennen müssen, die Variable SIZE. Die Position des Bit-Felds,
das die Datenlänge bestimmt, wechselt von Befehl zu Befehl mehr
als alle anderen. Fast immer werden die benutzten Werte in die
Variable SIZE übergeben, und zwar durch .B, .W oder .L.
Beachten Sie, daß ich an diesem Punkt BASE auf OCTAL umgeschal-
tet habe. Die 68000-Befehle enthalten viele 3-Bit-Felder und
können daher besonders übersichtlich als Oktalzahlen darge-
stellt werden. Ich war gezwungen, meine Vorliebe für Hexzahlen
zeitweilig zurückzustellen.
Bei der Definition der Worte, die Register und Adressierungs-
arten festlegen, habe ich zu einem kleinen Trick gegriffen. Ich
benutzte ein 'Multi-defining word' REGS, das in einer Schleife
CONSTANT ausführt, um ähnliche Konstanten zu erzeugen. REGS
wird nur zweimal benutzt. Einmal für Datenregister und einmal
für Adreßregister, die Modus O bzw. % darstellen.
Modus 0 ist 'data register direct', daher ist D5 eine
Konstante mit dem Wert 5005.
Modus 1 ist 'adress register direct', daher ist A3 eine
Konstante mit dem Wert 3113.
Worte, die mit MODE definiert wurden, werden nach einem
Adreßregister benutzt und ersetzen die zwei Modusziffern (in
unserem Fall 1) mit den neuen Modus-Werten. Dies geschieht
durch Ausmaskieren der alten Werte mit AND und Setzen der neuen
mit OR. Alle MODE-Worte sind 'adress register indirect' mit
Zusätzen.
Modus 2 ist '"adress register indirect',
daher ergibt A6 ) 6226.
Modus 3 ist dasselbe mit 'post-increment',
daher ergibt A7 )+ 7337.
Modus 4 ist dasselbe mit 'pre-decrement',
daher ergibt A7 -) 7447.
Modus 5 ist dasselbe mit 'displacement',
daher ergibt 123 Al D) 1551
mit dem 'displacement' Wert von 123, der zunächst unter
dem Register/Modus Wert auf dem Stack liegt.
Modus 6 ist dasselbe mit index und displacenment,
daher ergibt 123 D4 Al DI) 1661.
Auf dem Stack liegen darunter 4004 und 123.
Modus 7 wird für alle übrigen Adressierungsarten verwendet, die
sich durch ihre Registerfelder unterscheiden. Diese Modi sind
als Konstanten definiert.
#) ist 0770 und stellt die absolute (16-Bit) Adressierung
dar. Der Name bedeutet "'immediate indirect'. (Denken Sie
darüber nach!)
L#) ist 1771 und stellt die absolute (32-Bit) Adressierung
dar.
23 HEEE werbp/rerks A-23
PCD) ist 2772 und stellt den "program counter relative mit
displacement' Modus dar. 123 PCD) ergibt 2772 und darunter
liegt 123 auf dem Stack.
PCDI) ist 3773 und stellt den 'program counter relative
displaced, indexed' Modus dar. 123 D4 PCDI) ergibt 3773
und darunter 4004 und 123 auf dem Stack.
# ist 4774 und stellt den 'immediate data' Modus für 16
oder 32 Bit dar. 456 # ist 4774, darunter liegt 456.
(Anmerkung d. Übers.: Zusätzlich haben wir ins volksFORTH83
einige weitere Adressierungsarten aufgenommen. Mehr dazu weiter
unten.)
Beachten Sie, daß immer 1 bis 3 16-Bit-Werte auf dem Stack
hinterlassen werden, die die Adressierungsart kennzeichnen. Der
oberste Wert wird normalerweise Teil der ersten 16 Bit eines
Befehls zusammen mit dem Opcode. Falls zusätzliche Werte
vorhanden sind, werden sie im Anschluß an den Opcode assen-
bliert.
Manche 3-Bit-Felder werden häufiger (durch Ausmaskierung)
selektiert als andere. Das Wort FIELD erzeugt Worte, mit denen
man solche Felder selektieren kann. RS und RD wählen die source
und destination register Felder (s. Bild oben) aus. MS selek-
tiert das source mode Feld. Der erzeugende Ausdruck für eine
vollständig festgelegte Adressierungsart ist eine effektive
Adresse (EA). Das Wort EAS wählt die 'source effective adress',
die aus den source mode und register Feldern besteht. LOW
selektiert die unteren 8 Bits. Das Opcode-Wort enthält oft ein
EAS Feld. Das Wort SRC führt
OVER EAS OR E
aus, womit es dieses Feld ins Opcode-Wort überträgt. Das Wort
DST baut das destination register Feld ein.
Die virtuelle FORTH-Maschine enthält fünf Register. Diese sind
einzelnen 68000 Registern zugeordnet. Es ist im Assembler
möglich, sowohl die 68000 Register-Namen als auch die Namen der
Register der virtuellen Maschine zu benutzen. (Bemerkung d.
üÜbers.: Sie sollten die 68000 Registernamen nur dann benutzen,
wenn sie keine FORTH-Register meinen. Sie vermeiden so
unerklärliche Systemabstürze, falls die Registerzuordnung sich
ändert.)
Adressierungsarten, die nach dem Opcode weitere Werte assenm-
blieren, nennt man "extended adressing'. Solche Adressierungs-
arten werden mit sechs Worten und einem Buffer abgehandelt.
DOUBLE? hinterläßt ein Flag, das wahr ist, falls der Modus, der
oben auf dem Stack liegt, zusätzliche 32 Bit verlangt. INDEX?
sucht nach einer Adressierungsart und verändert seine zusätz-
lichen Werte in das passende Format, falls es sich um 'indexed'
Adressierung handelt. MORE? hinterläßt ein True-Flag, wenn die
Adressierungsart weitere Werte benötigt. MORE trägt alle
zusätzlichen Werte hinter dem Opcode-Wort ins Dictionary ein.
Einige Instruktionen brauchen zwei Adressierungsarten, eine für
source und eine für destination. Der source Modus wird zuerst
festgelegt, sodaß er unter dem destination Modus auf dem Stack
liegt. Jede Adressierungsart besteht aus ein bis drei Werten,
die auf dem Stack liegen. Der source Modus wird vor dem
destination Modus verarbeitet, daher müssen die Werte für den
destination Modus so lange in einem Buffer abgelegt werden.
EXTRA? rettet alle zusätzlichen Werte in einen Buffer namens
EXTRA und hinterläßt nur den Wert für die Adressierungsart.
EXTRA nimmt die zusätzlichen Werte aus dem Buffer und trägt
sie ins Dictionary ein.
Fast der ganze Rest des Assemblers besteht aus Definitionen und
. der Anwendung von definierenden Worten, die Gruppen von
Mnemonics herstellen. Zwei Beispiele werden genügen. Wenn Sie
mit dem Gebrauch von definierenden Worten nicht vertraut sind -
Sie sollten es sein; sie sind die leistungsfähigste Struktur in
FORTH.
Das Wort IMM erzeugt Worte, die 'immediate' Befehle assem-
blieren. Ich werde die Definition hier wiederholen und genau
erläutern:
: IMM CONSTANT
DOES>_ @ >R EXTRA? EAS R> OR
SZ3 „ LONG? ?, EXTRA ;
Gebrauch bei der Definition: 3000 IMM ADDI
Gebrauch im Assembler: n ea ADDI
Beispiel: 123 A5 ) ADDI
Jedes Mal, wenn mit IMM ein Mnemonic-Wort definiert wird,
speichert es einen konstanten Wert in der Definition dieses
Wortes ab, der es von anderen 'immediate' Worten unterscheidet.
Dieser Wert ist der Opcode des Befehls. Immediate Befehle
beinhalten folgende Bit-Felder.
I op-code | size |! mode | reg |
115 817 615 312 0
Diesen folgen 16 oder 32 Bit Daten. Wenn das Befehlswort
ausgeführt wird, führt es den Code nach DOES> in IMM aus mit
der Adresse seines eigenen Parameterfeldes auf dem Stack. An
dieser Adresse ist die Konstante (der Opcode) kompiliert. Das
Wort @ liest diesen Wert und rettet ihn mit >R auf den
Returnstack. ADDI erhält die 'immediate' Daten auf dem Stack
unterhalb der Werte für die Adressierungsart. EXTRA? rettet
alle zusätzlichen Werte, EAS selektiert die mode und register
Felder, die benutzt werden sollen. Dann wird der Opcode vom
Returnstack mit R> geholt und durch OR mit EAS verknüpft. SZ23
setzt die zugehörigen Längenbits aus SIZE, und das Wort comma
trägt das Opcode-Wort ins Dictionary ein. Jetzt liegen nur noch
die Daten auf dem Stack, und LONG? entscheidet, ob ?, 16 oder
32 Bit anhängen soll. Zum Schluß holt EXTRA die geretteten
zusätzlichen Werte, falls vorhanden, zurück und hängt sie
ebenfalls an.
Zahlreiche andere ähnlich aufgebaute definierende Worte werden
benutzt, um die meisten übrigen Befehle zu definieren. Viele
dieser kort bilden für sich eine Gruppe und sind deswegen mit
dem Kort : definiert, gerade so wie Makros. Die conditional
(c) 1828 weibp/terks A=25
Gr;
Befehle sind so regelmäßig, daß ich noch ein "trick defining
word' benutze. SETCLASS verwendet wiederholt ein vorhandenes
defining word, jedesmal mit einem anderen Argument, um mehrere
Mnemonic-Worte auf einmal zu definieren. Alle 46 conditional
Befehle werden definiert, indem jedes der drei defining words
16 mal aufgerufen wird. Dabei entstehen auch zwei ungültige
Mnemonics, die nicht weiter benutzt werden. Vielleicht wäre es
in diesem Falle besser gewesen, alle 46 Befehle einzeln zu
definieren, aber ich wollte zeigen, was alles machbar ist.
Zum Schluß kommen wir zu den structured conditionals. Betrach-
ten Sie folgendes Beispiel:
A3 )+ DI CMP 0<
IF DO AT ) MOVE
ELSE AT ) DO MOVE
THEN
BEGIN A3 D2 CMP_ 0=
WHILE AO )+ DO MOVE
REPEAT
Im ersten Beispiel beeinflußt das Ergebnis des Vergleichs
bestimmte Flags im Status-Register. IF assembliert einen
bedingten Sprung, dessen Opcode (mit Bedingung) durch 0<
festgelegt ist. Dieser assembliert also den Wert für einen BGE
(Branch greater or equal). ELSE berechnet den Sprungoffset für
IF und assembliert einen unbedingten Sprung; THEN berechnet
dessen Offset.
Ebenso berechnet WHILE einen bedingten Sprung hinter REPEAT,
welches wiederum einen unbedingten Sprung zurück auf BEGIN
assembliert.
Beachten Sie, daß keine Labels nötig sind. Der meiste Wirrwarr
in normalen Assembler-Quelltexten entsteht durch die riesige
Anzahl an bedeutungslosen Labelnamen für Sprungziele. Beachten
Sie auch, daß die structured conditionals, die wir hier
definiert haben, nur 1-Byte Offsets benutzen. Da der Assembler
nur einen Pass durchläuft, muß der Platz für den Sprungoffset
frei gehalten werden, bevor seine Größe bekannt ist. Da
Coderoutinen in FORTH immer sehr kurz sind, genügt ein Byte für
den Offset. Sollte das nicht ausreichen, ersetze ich einfach
diese Definitionen durch sehr ähnliche, die einen 16-Bit Offset
benutzen.
Schließlich sollte bemerkt werden, daß es keine Worte für die
Einrichtung von Datenstrukturen in diesem Assembler gibt. Ein
FORTH-Assembler ist Teil einer FORTH-Umgebung; und auf alle
Datenstrukturen, die mit normalen FORTH-Worten erzeugt wurden,
kann der Assembler zugreifen.
Ein Beispiel:
VARABLE FOO
CODE BAR FOO R#) NEG NEXT END-CODE
BAR negiert den Inhalt der Variablen FOO.
| Anhang E A-26 (2) 1226 werbpireiks
volksFORTH83 Assembler
wie bereits gesagt, beruht der Assembler im volksFORTH83 im
Wesentlichen auf dem von Michael Perry. Es wurden jedoch einige
neue Befehle implementiert, die die besonderen Möglichkeiten
von volksFORTH83, z.B. den Heap, ausnutzen, oder sich aufgrund
der relokatiblen Struktur als notwendig herausgestellt haben.
Struktur des relokatiblen volksFORTH83
volksFORTH83 ist ein 16-Bit-System, d.h. es lassen sich 64
kByte Speicher adressieren. Bisher lagen diese 64 kByte in
einer Speicherbank (ab $50000), sodaß die 16-Bit-Adressen im
FORTH-System mit Hilfe einer Konstanten namens mempage (=0005)
auf 32-Bit-Adressen erweitert werden konnten. Diese Struktur
hat sich jedoch als sehr unflexibel erwiesen, so war es z.B.
nicht möglich, RAM-Disks zu benutzen. Wenn man stand-alone-
Applikationen erzeugen wollte, mußte man dazu eigens ein
Ladeprogramm schreiben, dessen einziger Sinn darin bestand, das
eigentliche Programm nach $50000 zu laden und dort zu starten.
Die neue Struktur geht davon aus, daß das System an beliebiger
Stelle im Speicher lauffähig sein soll (relokatibel).
Dementsprechend dürfen keine absoluten 32-Bit-Adressen im
System mehr vorkommen, weil sonst zusätzliche Relokationsinfor-
mationen mit abgespeichert werden müßten, was ein SAVESYSTEM
nahezu unmöglich machen würde. Glücklicherweise bietet der
68000-Prozessor eine recht leistungsfähige Adressierungsart,
nämlich die "indirekte Adressierung mit Index und Displace-
ment'. Grundlage ist dabei ein Adreßregister, daß auf Byte 0
des FORTH-Systems zeigt und Forthpointer (FP) heißt. Alle
Speicheroperationen müssen nun relativ zu diesem Zeiger erfol-
gen.
Die 16-Bit-Adressen im FORTH-System werden nun als Offset zum
Byte 0 des Systens .aufgefaßt und als Index in einem Datenregis-
ter benutzt. Unglücklicherweise werden Datenregister, die als
Index verwendet werden, auf 32 Bit vorzeichenerweitert, wenn
sie nur wortweise adressiert werden. Der Assembler mußte daher
so abgeändert werden, daß bei den Adressierungsarten DI) und
PCDI)J die Länge der Operation unabhängig von der Länge des
Indexregisters angegeben werden kann. Ein Beispiel: Die
Befehlsfolge
.1 0D6 FP DI) .w DO move
addiert zu FP den Wert des Datenregisters D6 lang, also ohne
Vorzeichenerweiterung, geMOVEd werden aber nur 16 Bit. Steht
also in D6 die 16-Bit-Adresse einer FORTH-Variablen, z.B. $9000
und zeigt FP auf $12300, würde diese Befehlsfolge den 16-Bit-
Inhalt der Variablen, die absolut bei $1B300 liegt, ins
Register DO bringen.
Zusätzliche Adressierungsarten
Um das Programmieren in Assembler nun nicht noch schwieriger zu
machen als es ohnedies schon ist, haben wir einige Macros
(ce) EEE weibp/terks A-27 Anhang N
entwickelt, die den Charakter von Adressierungsarten haben.
ı reg) size push .1 O0 swap FP DI) ;
Diese Adressierungsart könnte "Datenregister indirect' benannt
werden. Ein Beispiel:
Code @ ( addr -- 16b )
SP )+ D6 move D6 reg) SP -) move Next
assembliert genau dasselbe wie
Code @ ( addr - 16b )
SP )+ D6 move .10D6E FP DI) .w SP -) move Next
Die Adresse auf dem Stack wird in D6 geladen; D6 wird lang zum
Forthpointer addiert und der Inhalt dieser Speicherstelle
wieder auf den Stack gebracht. (Anmerkung: @ im System ist
etwas komplizierter definiert, da auch der Zugriff auf ungerade
Adressen gestattet ist, was bei der obigen Definition eine
Fehlermeldung auslösen würde.)
Zum Zugriff auf Datenstrukturen, vor allem auf Variablen, dient
das Macro
: R#) ( addr -- ) size push .w
dup 0< IF # D6 move D6 reg) exit THEN
FPD) ;
Dieses Macro gab es auch schon im "alten' System, der E£[Lekt
ist auch der gleiche, sodaß vorhandene Assemblerquelltexte
nicht umgeschrieben werden müssen. Die Wirkungsweise hat sich
jedoch geändert: Ist addr negativ - also größer als S$TEFF -
wird die Adresse direkt nach D6 geladen und dann wie bereits
beschrieben mit D6 indiziert. Liegt addr jedoch in den unteren
32 kByte des FORTH-Systems, erfolgt der Zugriff mit addr als
Displacement ohne Indexregister, was erhebliche Geschwindig-
keitsvorteile bringt. Vor allem die FORTH-Systemvariablen
lassen sich auf diese Art und Weise schnell erreichen. Ein
weiteres Beispiel:
Variable test
Code test@ ( -- 16b )
test R#) SP -) move Next
TEST@ legt den Inhalt der Variablen TEST auf den Datenstack.
Schließlich gibt es noch das Macro PCREL), dessen genauere
Definition im Assemblerquelltext ASSEMBLE.SCR nachzulesen ist.
Es arbeitet analog zu R#), ist aber schneller und kürzer.
Nachteil ist, daß der 68000 die Adressierungsart PC-relativ
nicht bei allen Operatoren zuläßt, und daß nicht der gesamte 64
kByte Adreßraum erreichbar ist. PCREL) ist mit Fehlermeldungen
gegen falsche Adreßdistanzen abgesichert.
alien
ic) SEE werbp/reihs Hi"!
RIFORTHE
SL
Register der virtuellen FORTH-Maschine
Folgende Register werden vom volksFORTH83 benutzt:
A3 Forthpointer (FP). Dieses Register enthält die Start-
adresse des Systems und gibt damit die Basis für alle
relativen Adreßzugriffe ins System. Grundsätzlich
gilt: Die absolute 32-Bit-Adresse erhält man durch
Addition der 16-Bit-Forth-Adresse und FP. Die 16-Bit-
Forth-Adressen lassen sich also als Offset zum
Systemanfang auffassen.
A4 Instructionpointer (IP). Dieses Register enthält die
(absolute) 32-Bit-CFA des nächsten auszuführenden
Wortes.
A5 Returnstackpointer (RP). Dieses Register enthält den
'"Systemstackpointer' der virtuellen FORTH-Maschine.
Hier werden 'Rücksprungadressen' in aufrufende Worte
usw. abgelegt.
A6 Datenstackpointer (SP). Dieses Register enthält den
Datenstackpointer der virtuellen FORTH-Maschine. Über
diesen Stack werden bekanntlich nahezu sämtliche
Werte zwischen einzelnen Funktionen übergeben.
Neben diesen vier Adreßregistern werden noch zwei Datenregister
benutzt:
D7 Work-Register (W) der virtuellen FORTH-Maschine; der
16-Bit-Wert in diesem Register zeigt auf die CFA des
Wortes, das gerade ausgeführt wird.
D6 Ein Hilfsregister, das zur Umrechnung von relativen
16-Bit-Adressen in absolute 32-Bit-Adressen benutzt
wird. Dem Programmierer stehen also die Datenregister
DO - D5 sowie die Adreßregister AO - A2 zur freien
Verfügung. D6 und D7 dürfen verändert werden, jedoch
müssen die oberen 16 Bit immer auf 0 stehen. Sollen
weitere Register verwendet werden, müssen sie vorher
gerettet und anschließend restauriert werden.
Zusätzliche Befehle
sc: Schaltet den Assembler ab und den FORTH-Compiler an. Damit
ist es möglich, von Maschinencode in FORTH überzuwechseln.
Ein Gegenstück ist nicht vorhanden.
Ein Beispiel für die Verwendung von ;c: ist:
oe... 0<£ IF ;c: .„" Fehler" ; Assembler THEN
Ist irgendwas kleiner als Null, so wird 'Fehler' ausgedruckt
und die Ausführung des Wortes abgebrochen, sonst geht es weiter
im Code.
Schließlich gibt es noch die Worte >LABEL und LABEL. >LABEL
erzeugt eine Konstante auf dem Heap, wobei es den Wert des
(c) 1385 weibp/re/ks A-29 Anhang I
Labels vom Stack nimmt. LABEL erzeugt eine Konstante mit dem
Wert von HERE. Beispiel:
LABEL SCHLEIFE 1 DO subq SCHLEIFE BNE
SCHLEIFE verbraucht keinen Dictionaryspeicher, weil es voll-
ständig - mit Header und Wert - auf dem Heap liegt. Es sind
also echte Assemblerlabels möglich. Von der Verwendung solcher
Labels kann allerdings nur abgeraten werden, wenn wie im obigen
Beispiel ebensogut strukturiert programmiert werden könnte.
Übrigens ist >LABEL statesmart, d.h es verhält sich verschie-
den, je nachdem, ob das System kompiliert oder nicht. Während
der Kompilation werden Labels als Literals kompiliert. Damit
können Labels auch in Colon-Definitionen verwendet werden.
2) 1REE wesbp/re/iks A-31 Anhang N
Der Disassembler
Der Disassembler wird geladen mit
include disass.scr
Mit DISW <word> kann man in Code geschriebene Worte
disassemblieren. Das funktioniert natürlich mit Systemworten
ebensogut wie mit eigenen Definitionen. Die Ausgabe stoppt
automatisch, wenn ein NEXT erkannt wurde, und kann dann mit
einer beliebigen Taste fortgesetzt oder mit Escape abgebrochen
werden. Auch während der Ausgabe kann mit einer beliebigen
Taste unterbrochen oder mit Escape abgebrochen werden.
Der Disassembler disassembliert die Befehle in der üblichen
Motorola-Syntax, nicht in der Schreibweise des FORTH-
Assemblers. Wer häufiger mit Assembler-Quelltexten zu tun hat,
wird das zu schätzen wissen....
Weitere Benutzer-Worte des Disassemblers sind
dis ( addr -- )
1
und
ldis ( laddr -- )
Beide disassemblieren von einer vorgegebenen FORTH- bzw. Lang-
adresse ab. Mit LDIS lassen sich auch Routinen außerhalb von
FORTH disassemblieren, z.B. im TOS oder GEM. Die Ausgabe wird
genauso gesteuert wie bei disw.
Sonstiges
Wie im Artikel von Michael Perry bereits zu lesen war,
verzichtet der Assembler auf 'übertriebenes Errorchecking'. Im
Klartext heißt das, daß man sich schon recht gut mit dem 68000-
Befehlsumfang auskennen sollte, insbesondere mit den erlaubten
Adressierungsarten und Operandenlängen bei den einzelnen Befeh-
len. Anfängern - und nicht nur solchen (!) - sei dringend
empfohlen, grundsätzlich den erzeugten Maschinencode mit dem
Disassembler zu überprüfen. Man reduziert damit die Anzahl der
sonst unvermeidlichen Systemabstürze erheblich.
Der FORTH-Assembler ist etwas gewöhnungsbedürftig. Beispiele
für verschiedenartige Anwendungen sind vor allem im File
FORTH_83.SCR zu finden. Diese Beispiele sollte man studieren,
bevor man sich an eigene Experimente heranwagt. Man muß ja
nicht gleich mit (WORD beginnen....
be
e .
U Anhang E a-32 2) EEE werbp/re/hs
(
Fileinterface für das Voksforth83
auf dem Atari ST
Erster Einstieg !
Bevor Sie das Glossar lesen, sollten Sie diese kleine Einfüh-
rung lesen und auf einer leeren Diskette die Beispiele auspro-
bieren.
Wie erzeuge ich ein File, in das ich ein Programm eingeben
kann?
Geben Sie bitte folgendes ein:
MAKEFILE test.scr
Das File test.scr wird auf dem Laufwerk erzeugt, auf dem Sie
das Forth gebootet haben. Als nächstes schätzen Sie bitte ab,
wie lang Ihr Programm etwa wird. Beachten Sie dabei bitte, daß
der Screen O0 eines Files für Hinweise zur Handhabung ihres
Programms und der Screen 1 für einen sog. Loadscreen (das ist
ein Screen, der den Rest des Files lädt) reserviert sind.
Wollen Sie also z.B. 3 Screens Programm eingeben, so sollte das
File 5 Screens lang sein; Sie geben also ein:
5 MORE
Fertig |! Sie haben jetzt ein File, das die Screens 0..4
enthält. Geben Sie jetzt
1L
ein. Sie editieren jetzt den Screen 1 Ihres neuen Files
test.scr . Sie können, falls der Platz nicht ausreicht, Ihr
File später einfach mit MORE verlängern. Ein File kann leider
nicht verkürzt werden. Wie spreche ich ein bereits auf der
Diskette vorhandenes File an?
Das geht noch einfacher. Geben Sie einfach den Filenamen ein.
Reägiert das System mit der Meldung "Haeh ?" „ so kennt das
Forth dieses File noch nicht. Sie müssen in diesem Fall das
Wort USE vor dem Filenamen eingeben, also z.B.
USE test.scr
Jetzt können Sie wie oben beschrieben mit 1L {oder einer
anderen Zahl) das File editieren. Das Wort USE erzeugt
übrigens im Forthsystem das, Wort TEST.SCR, falls es noch nicht
vorhanden war. Wissen Sie also nicht mehr, ob Sie ein File
schon benutzt haben, so können Sie mit WORDS nachsehen oder
das Wort USE voranstellen.
»
»
I
w
>
-
r
m
2
BD
in
we/bp/re/ks
Wie erzeuge ich Files auf einem bestimmten Laufwerk, z.B. A: ?
Entweder durch Voranstellen des Pfadnamens oder durch Eingabe
von :
A: Hierbei wird A: zum aktuellen Laufwerk gemacht.
Wie spreche ich Directories an ?
Hierbei gibt es verschiedene Methoden. Für den Anfang versuchen
wir, Files in einem Directory "test.dir" zu suchen bzw. zu
erzeugen. Dazu geben Sie ein :
dir test.dir
Jetzt werden in test.dir alle Files und Directories erzeugt und
gesucht. Ist das Directory "test.dir" noch nicht vorhanden, so
erzeugen Sie es mit :
makedir test.dir
Anschließend können Sie wieder DIR benutzen.
0) Allgemeines
Im folgenden wird die Benutzung des Fileinterfaces beschrieben.
Dieses Fileinterface benutzt die Files des GEM-Dos und dessen
Subdirectories.
Benutzt man ein File von Forth aus, so wird es in Blöcke zu je
1024 Bytes aufgeteilt, die in gewohnter Weise anzusprechen
sind. Dies trifft auch für Files zu, die nicht vom Forth aus
erzeugt wurden. Als Konvention wird vorgeschlagen, daß Files,
die Forth-Screens, also Quelltexte, enthalten, mit .SCR
erweitert werden. Files, die Daten enthalten, die nicht unmit-
telbar lesbar sind, sollten auf .BLK enden.
Zum Umschalten vom Filesystem auf Direktzugriff und umgekehrt
gibt es das Wort
DIRECT (.==)
schaltet auf Direktzugriff um. Auf den Filezugriff schal-
ten wir durch das Nennen eines Filenamens um.
DOS (==)
Viele Worte des Fileinterfaces, die normalerweise nicht
benötigt werden, sind in diesem Vokabular enthalten.
(23 1928 we/bp/reiks A-35 Anhang
1) Der Directory-Mechanismus
Die Verwaltung von Directories entspricht in etwa der des GEM-
Dos Command-interpreters COMMAND.PRG
PATH ee)
Dieses Wort gestattet es, mehrere Directories nach einem
zu öÖffnenden File durchsuchen zu lassen. Das ist dann
praktisch, wenn man mit mehreren Files arbeitet, die sich
in verschiedenen Directories oder Diskstationen befinden.
Es wird in den folgenden Formen benutzt:
PATH -„.dirlizdir2;..:-
Hierbei sind <dirl1>, <dir2> etc. Pfadnamen. Wird ein File
auf dem Massenspeicher gesucht, so wird zunächst <dirl>,
dann <dir2> etc. durchsucht. Zum Schluß wird das File dann
im aktuellen Directory (siehe DIR) gesucht. Beachten Sie
bitte, daß keine Leerzeichen in der Reihe der Pfadnamen
auftreten dürfen.
Beispiel: PATH A:\;B:\COPYALL.DEM; \AUTO\
In diesem Beispiel wird zunächst die Diskstation A,
dann das Directory COPYALL.DEM auf Diskstation B und
schließlich das Directory AUTO auf dem aktuellen
Laufwerk (siehe SETDRIVE, A: und B:) gesucht.
Beachten Sie bitte das Zeichen "\" vor und hinter
AUTO . Das vordere Zeichen "\" steht für das Haupt-
directory. Wird es weggelassen, so wird AUTO\ an
das mit DIR gewählte Directory angehängt. Das
hintere Zeichen "\" trennt den Filenamen vom Pfad-
namen.
Außerdem können Sie eingeben :
PATH ;
In diesem Fall werden alle Pfade gelöscht und es wird nur
noch das aktuelle Directory durchsucht.
Schließlich geht noch :
PATH
Dann druckt PATH die Reihe der Pfadnamen aus.
Dieses Wort entspricht dem Kommando PATH des Kommando-
inteters.
MAKEDIR cccc (s==)
Erzeugt im aktuellen Directory (siehe DIR) ein Directory
mit Namen CCCC,
Dieses Wort entspricht dem Kommando MD des Kommando-
interpreters.
A: ( ==)
Macht die Diskstation A: zum aktuellen Laufwerk (siehe
SETDRIVE).
Dieses Wort entspricht dem Kommando A: des Kommando-
interpreters.
A-3& (2) ASEE Wweibp/re/ks
B: (--)
Macht die Diskstation B: zum aktuellen Laufwerk (siehe
SETDRIVE).
Dieses Kommando entspricht dem Kommando B: des Kommando-
interpreters.
C: { ==)
Di {== ")
Analog zu A: und B:
SETDRIVE ({n=>)
Macht die Diskstation mit der Nummer n zu aktuellen
Laufwerk. Hiebei entspricht n=0 der Diskstation A, n=1 der
Diskstation B usw.
Auf dem aktuellen Laufwerk werden Files und Directories
erzeugt (und nach Durchsuchen von PATH gesucht). Das
Directory, in dem Files erzeugt werden, wird mit DIR
angegeben.
DIR (--) .
Wird in den folgenden Formen benutzt:
DIR -cece
<ccecc> ist ein Pfadname, an den neu zu erzeugende Files
und Directories angehängt werden.
Beispiel:
A: DIR AUTO
erzeugt alle folgenden Files im Directory AUTO auf der
Diskstation A. In <cccc> können alle vom GEM-Dos zugelas-
senen Zeichen außer Leerzeichen verwendet werden.
Außerdem geht noch
DIR
Ohne weitere Eingaben wird der aktuelle Suchpfad ein-
schließlich des Laufwerks angezeigt.
Dieses Wort entspricht dem Kommando CD des Kommandoin-
terpreters.
FILES (#=&))
Listet den Inhalt des aktuellen Directories (siehe DIR und
SETDRIVE) auf dem Bildschirm auf. Subdirectories werden
durch ein vorangestelltes "D" gekennzeichnet.
Dieses Wort, zusammen mit dem Wort FILES" entspricht dem
Kommando DIR des Kommandointerpreters.
FILES" (--)
Benutzt in der Form
FILES” cccc"
Listet die Files auf, deren Name CCCcC ist. Der String
CCCcCc darf die bekannten Wildcards sowie einen Pfadnamen
enthalten. Wird kein Pfadname bzw. Laufwerk angegeben, so
ic} 41328 weibp/re/ks A-37 Anhang N
werden die Files des aktuellen Directories bzw. Laufwerks
ausgegeben.
SAVESYSTEM En)
Benutzt in der Form
SAVESYSTEM <name>
Damit läßt sich ein FORTH-System im gegenwärtigen Zustand
unter dem Namen <name> abspeichern. Dieses Wort wird
benutzt, um fertige Applikationen zu erzeugen. In diesem
Fall sollte das Wort, das die Applikation ausführt, in
'COLD gepatched werden. Ein Beispiel: Sie haben ein
Kopierprogramm geschrieben; das oberste ausführende Wort
heißt COPYDISK. Mit der Sequenz
' COPYDISK IS 'COLD <Return?>
SAVESYSTEM COPY.PRG <Return?>
erhalten Sie ein Progamm namens COPY.PRG, das sofort beim
Start COPYDISK ausführt.
2 ) Files
Files bestehen aus einem Forthnamen und einem GEM-Dos-Namen,
die nicht übereinstimmen müssen.
Ist das Forthwort, unter dem ein File zugreifbar ist, gemeint,
so wird im folgenden vom Forthfile gesprochen. Ist das File auf
der Diskette gemeint, das vom GEM-Dos verwaltet wird, so wird
vom GEM-File gesprochen. Durch das Nennen des Forthnamens wird
das Forthfile (und das zugeordnete GEM-File) zum aktuellen
File, auf das sich alle Operationen wie LIST, LOAD, CONVEY usw.
beziehen.
Beim Öffnen eines Files wird die mit PATH angegebene Folge von
Pfadnamen durchsucht. Ist ein File einmal geöffnet, so kann
diese Folge beliebig geändert werden, ohne daß der Zugriff auf
das File behindert wird. Aus Sicherheitsgründen empfiehlt es
sich aber, Files so oft und so lange wie irgend möglich
geschlossen zu halten. Dann kann eine Änderung der Folge von
Pfadnamen dazu führen, daß ein File nicht mehr gefunden wird.
FILE (==)
Wird in der Form:
FILE <name>
benutzt.
Erzeugt ein Forthwort mit Namen <name)>. Wird <name> später
ausgeführt, so vermerkt es sich als aktuelles File. 5
Ebenso vermerkt es sich als FROMFILE, was für CONVEY
wichtig ist. Einem Forthfile wird mit MAKE oder ASSIGN
ein GEM-File zugeordnet.
MAKE (==)
Wird in der Form:
MAKE cccc
6) iszE werbpfre/hs
benutzt. Erzeugt ein GEM-File mit Namen cccc im aktuel-
len Directory und ordnet es dem aktuellen Forthfile zu.
Das File wird auch gleich geöffnet. Es hat die Länge Null
(siehe MORE).
Beispiel: FILE test.scr test.scr MAKE test.scr
erzeugt ein Forthwort TEST.SCR und ein File gleichen
Namens. Alle Operationen wie LOAD ,„ LIST usw. beziehen
sich nun auf den entsprechenden Screen in TEST.SCR.
Beachten Sie bitte, daß dieses File noch leer ist und
daher eine Fehlerbedingung besteht, wenn Zugriffsopera-
tionen ausgeführt werden sollen.
MAKEFILE =)
wird in der folgenden Form benutzt:
MAKEFILE <name>
Erzeugt ein Forthfile mit Namen <«NAME> und erzeugt
anschließend ein GEM-File mit demselben Namen. Die Sequenz
FILE <name> <name> MAKE <name>
würde genau dasselbe bewirken.
ASSIGN (--)
wird in der Form
ASSIGN cccc
benutzt. Ordnet dem aktuellen File das GEM-File mit Namen
CCCC zu. Eine Fehlerbedingung besteht, wenn das File nicht
gefunden werden kann.
USE (--)
Dieses Wort ist das wichtigste Wort zum Auswählen von
Files.
Es wird in der folgenden Form benutzt:
USE <name>
Dieses Wort macht das File mit Namen <NAME> zum aktuel-
len File, auf das sich LOAD, LIST usw. beziehen. Es
erzeugt ein Forthfile mit Namen <NAME> ,„ falls der Name
noch nicht vorhanden war.
Anschließend wird das File in den Directories, die mit
PATH angegeben wurden, gesucht. Wird es dort nicht gefun-
den, wird das mit SETDRIVE (bzw. A: und B:) und DIR
angegebene Directory durchsucht. Wird auch dort kein GEM-
Dos File mit dem Namen <NAME> gefunden, so wird die
Fehlermeldung FILE NOT FOUND ausgegeben. Das
(automatisch) erzeugte Forthfile verbleibt im Dictionary
und muß ggf. mit FORGET vergessen werden.
CLOSE ( --)
Schließt das aktuelle File. Dabei wird das Inhaltsver-
zeichnis der Diskette aktualisiert und die sog. Handlenum-
(<>
SEE weibp/reihs A239 Anhang h
mer wieder freigegeben. Es werden die zu diesem File
gehörenden geänderten Blöcke auf die Diskette zurück-
geschrieben und alle zu diesem File gehörenden Blöcke
gelöscht.
OPEN (==)
Öffnet das aktuelle File. Eine Fehlerbedingung besteht,
wenn das File nicht gefunden werden kann. Die Benutzung
dieses Wortes ist in den meisten Fällen überflüssig, da
Files automatisch bei einem Zugriff geöffnet werden.
FROM ==)
Wird in der folgenden Form benutzt:
FROM <name>
<NAME> ist der Name eines Forthfiles, aus dem beim Aufruf
von CONVEY und COPY Blöcke herauskopiert werden
sollen.
Beispiel: filea 1 FROM fileb 3 copy
Kopiert den Block 1 aus FILEB auf den Block 3 von FILEA.
Dieses Wort benutzt USE um das File auszuwählen. Das
bedeutet, daß fileb automatisch als Forthfile angelegt
wird, wenn es noch nicht im System vorhanden ist.
LOADFROM (.n==)
Wird in der folgenden Form benutzt:
LOADFROM <name>
<NAME> ist der Name eines Forthfiles, aus dem der Block n
geladen wird.
Beispiel: 15 LOADFROM filea
Lädt den Block 15 aus FILEA. Dieses Wort ist wichtig, wenn
während des Ladens eines Files Teile eines anderen Files
geladen werden sollen. Damit kann die Funktion eines
Linkers imitiert werden. :. Dieses Wort benutzt USE , um
filea zu selektieren. Das bedeutet, daß automatisch ein
Forthfile mit Namen filea erzeugt wird, falls es im
System noch nicht vorhanden war.
Beachten Sie bitte, daß dieses Wort nichts mit FROM oder
FROMFILE zu tun hat, obwohl es ähnlich heißt !
INCLUDE ( ==)
Wird in der folgenden Form benutzt:
INCLUDE <name>
<NAME> ist der Name eines Forthfiles, das vollständig
geladen wird. Dabei ist Voraussetzung, daß auf Screen 1
dieses Files Anweisungen stehen, die zum Laden aller
Screens dieses Files führen. Siehe auch LOADFROM.
CAPACITY et)
u ist die Länge des aktuellen Files. Beachten Sie bitte,
daß die Länge des Files um eins größer ist als die Nummer
des letzten Blocks, da der Block O0 mitgezählt wird.
FORTHFILES (--)
Druckt eine Liste aller Forthfiles, zusammen mit den Namen
der zugehörigen GEM-Files, deren Länge und Handlenummer
aus.
FROMFILE { -- addr)
Addr ist die Adresse einer Variablen, die auf das Forth-
File zeigt, aus dem CONVEY und COPY Blöcke lesen. Siehe
auch FROM. Bei Nennen eines Forth-Files wird diese
Variable gesetzt.
FILE? --)
Druckt den Namen des aktuellen Forthfiles.
MORE (n--)
Verlängert das aktuelle File um n Screens. Die Screens
werden hinten angehängt. Anschließend wird das File
geschlossen. \
(MORE (n--)
Wie MORE, jedoch wird das File nicht geschlossen.
EOF )
£ ist ein Flag, das wahr ist, falls über das Ende des
Files hinaus gelesen wurde. £f ist falsch, falls auf das
zuletzt gelesene Byte im File noch weitere Bytes folgen.
3 ) Verschiedenes
Beim Vergessen eines Forth-Files mit Hilfe von FORGET, EMPTY
usw. werden automatisch alle Blockpuffer, die aus diesem File
stammen, gelöscht, und, wenn sie geändert waren, auf die
Diskette zurückgeschrieben. Das File wird anschließend
geschlossen.
Bei Verwendung von FLUSH werden alle Files geschlossen. FLUSH
sollte VOR jedem Diskettenwechsel ausgeführt werden, und zwar
nicht nur, um die geänderten Blöcke zurückzuschreiben, sondern
auch damit alle Files geschlossen werden. Sind nämlich Files
gleichen Namens auf der neuen Diskette vorhanden, so wird sonst
eine abweichende Länge des neuen Files vom Forth nicht erkannt.
Bei Verwendung von VIEW wird automatisch das richtige File
geöffnet.
(ec) 1828 weibp/re/iks A-41 Anhang N
Diverses
Im File DIVERSES.SCR sind einige Worte zusammengefaßt, die sich
nicht so recht zuordnen lassen.
»absaddr ( addr -- abs_laddr )
rechnet eine - relative - Adresse im FORTH-System in die
entsprechende absolute 32-Bit-Adresse un.
.bik (==)
gibt die Nummer des gerade kompilierten Screens aus. Wenn
Screen 1 eines Files kompiliert wird, wird zusätzlich auch
der Filename in einer neuen Zeile ausgegeben.
abort( {£f--)
Wird benutzt in der Form
Bedingung ABORT( string)
Wenn £ wahr ist, wird der String ausgegeben; entspricht
abort" , ist jedoch im Direktmodus zu benutzen.
arguments ({n-)
prüft, ob mindestens n Werte auf dem Stack liegen ;
andernfalls wird mit einer Fehlermeldung abgebrochen.
cpush ( addr len -- )
wie PUSH, aber nicht für eine Variable, sondern für
Speicherbereiche, die nach Ausführung eines Wortes auf die
alten Werte zurückgesetzt werden sollen. Auf diese Art
werden 'lokale Arrays' möglich.
bell ==)
gibt einen Piepston auf der Konsole aus.
blank ( addr len -- )
Ab addr werden len Bytes mit Leerzeichen überschrieben.
setvec (--)
setzt den Critical Error Handler des Betriebssystems auf
eine neue Routine, die die Ausgabe von Fehlerboxen bei
Schreib- oder Lesefehlern bei Diskettenzugriffen verhin-
dert. Andere Boxen, die über diesen Handler laufen,
erscheinen nach wie vor, z.B. die Aufforderung, bei einem
Laufwerk eine andere Diskette einzulegen. Damit entfällt
das Geduldsspiel, ohne sichtbare Maus das Abbruchfeld zu
finden.
restvec i ==)
setzt den Critical Error Handler auf den alten Wert
zurück. Diese Routine muß unbedingt ausgeführt werden,
bevor man FORTH verläßt, da sonst das System abstürzt.
A-42 " ke) IREE we/ibp/reiks
ic} H92E we/bp/re/ks A-43 Anhang i
Allocate
MALLOC und MFREE enthalten die Betriebssystemaufrufe, mit denen
zusätzlicher Speicher beim Betriebssystem an- und abgemeldet
werden muß.
malloc (dä -- laddr )
Es werden d Byte beim Betriebssystem angefordert; laddr
ist die Anfangsadresse des reservierten Speicherbereichs.
Eine Fehlerbedingung besteht, wenn nicht genug Speicher-
platz vorhanden ist. In diesem Fall wird mit der Meldung
'No more RAM' abgebrochen.
mfree ( laddr -- )
Gibt den reservierten Speicher ab ladär wieder frei. Eine
Fehlerbedingung besteht, falls kein Speicher reserviert
war. In diesem Fall wird mit der Meldung 'mfree Error'
abgebrochen.
Anhang
Relocate
Hier sind Worte aufgeführt, mit denen sich die Speicherauftei-
lung des volksFORTH ändern läßt. Von der Größe des Return- und
Datenstacks (also der Dictionarygröße) hängt der Platz für die
Diskbuffer ab. Wenig Buffer erlauben ein großes Dictionary,
bieten aber beim Editieren wenig Komfort, weil ständig auf das
Laufwerk zugegriffen werden muß.
relocate ( stacklen rstacklen -- )
richtet das System neu ein mit stacklen Dictionarygröße
und rstacklen Returnstackgröße (Vgl. die Memory Map des
volksFORTH im Kapitel über den Multitasker). Abschließend
wird COLD ausgeführt, um u.a. die Diskbuffer neu zu
initialisieren. Vor RELOCATE sollte daher SAVE aufgerufen
werden.
buffers (+n--)
stellt ein System mit +n Diskbuffern her. Es gilt das bei
RELOCATE Gesagte.
FT Im.
Anhang A-46 2) 1822 weibp/rerks
Strings
Hier befinden sich grundlegende Routinen zur Stringverarbei-
tung. Vor allem wurden auch Worte aufgenommen, die den Umgang
mit den vom Betriebssystem geforderten 0-terminated Strings
ermöglichen. FORTH hat hier gegenüber 'C' den Nachteil, daß
FORTH-Strings standardmäßig mit einem Count-Byte beginnen, das
die Länge des Stings enthält. Ein abschließendes Zeichen (z.B.
Null) ist daher unnötig. Da das Betriebssystem aber in 'C'
geschrieben wurde, müssen Strings entsprechend umgewandelt
werden.
Beachten Sie bitte auch im Glossar die Wortgruppe "Strings".
caps ( -- adr )
Adr ist die Adresse einer Variablen, die angibt, ob beim
Stringvergleich mit COMPARE auf Groß- und Kleinschreibung
geachtet werden soll.
-text ( addrO len addrli -- n ) " minus-text"
addrO und addri sind die Adressen von zwei counted
strings, len die Anzahl von Zeichen, die verglichen werden
soll. Die Strings werden zeichenweise voneinander subtra-
hiert. n enthält die Differenz der beiden ersten nicht
übereinstimmenden Zeichen. Ist n = 0, so sind die Strings
gleich.
compare ( addrO len addri -- n )
wie -TEXT, jedoch wird der Inhalt der Variablen CAPS
ausgewertet. Ist CAPS wahr, wird nicht auf Groß- oder
Kleinschreibung geachtet. Die Vergleichsroutine ist dann
allerdings erheblich langsamer.
search ( text textlen buf buflen -- offset £ )
Im Text ab Adresse text wird in der Länge textlen nach dem
String, der im Buffer buf mit der Länge buflen steht,
gesucht. Zurückgeliefert wird der Offset in den durch-
suchten Text an die Stelle, an der der String gefunden
wurde, sowie das Flag £f . Ist f wahr, wurde der String
gefunden, sonst nicht.
delete ( buffer size count -- )
Im Buffer der Länge size werden count Zeichen entfernt.
Der Rest des Buffers wird 'herangezogen' und das Ende mit
Leerzeichen aufgefüllt.
insert ( string len buffer size -- )
Der String ab Adresse string mit der Länge len wird in den
Buffer ab buffer mit der Größe size eingefügt. Der Rest
des Buffers wird nach hinten geschoben, Zeichen am Ende
fallen weg.
$sum ( -- adr ) " string-sum"
Adr ist die Adresse einer Variablen, die auf einen String
zeigt. An diesen String kann ein weiterer String mit SADD
hinten angefügt werden.
e>0"
O>c"
„O"
A-48 (2) 1328 weibp/rerhs
nifü
( addr len -- ) " string-add"
hängt den String ab addr mit der Länge len an den String
bei $SUM an. Der Count wird dabei addiert.
( addr -- ) " counted-to-zero-string"
wandelt den counted String ab addr in einen 0-terminated
String um. Die Länge des Strings im Speicher bleibt
gleich.
{ addr -- ) " Zero-to-counted-string"
wandelt den O-terminated String ab addr in einen counted
String um. Die Länge des Strings im Speicher bleibt
gleich.
(--) " comma-zero-string"
wird in der folgenden Form benutzt :
„o" cece"
Legt den String ccc mit führendem Countbyte und
abschließender Null im Dictionary beginnend bei HERE ab.
Vergleiche ,„"
( -- adr ) " Zero-string"
{1-= ) compiling
Wird in der folgenden Form benutzt :
0" ccc"
Liest den Quelltext bis zum nächsten " und legt ihn als
counted String mit abschließender Null im Dictionary ab.
Zur Laufzeit wird die Adresse des ersten Zeichens des
Strings adr auf dem Stack abgelegt. Dieses Wort ist
statesmart und kann daher auch im Interpretierenden
Zustand verwendet werden.
Abweichungen des volksFORTH83 von
Programmieren in Forth
Die Gründe für die zahlreichen Abweichungen des Buches
"Starting Forth"” (Prentice Hall, 1982) bzw. "Programmieren in
Forth" (Hanser, 1984) von Leo Brodie wurden bereits im Prolog
aufgeführt. Sie sollen nicht wiederholt werden. Das Referenz-
buch ist, trotz offenkundiger Mängel in Übersetzung und Satz,
die deutsche Version, da sie erheblich weiter verbreitet sein
dürfte. Im folgenden werden nicht nur Abweichungen aufgelistet,
sondern auch einige Fehler mit angegeben. Die Liste erhebt
keinen Anspruch auf Vollständigkeit. Wir bitten alle Leser, uns
weitere Tips und Hinweise mitzuteilen. Selbstverständlich gilt
das auch für alle anderen Teile dieses Handbuchs. Vielleicht
wird es in der Zukunft ein Programm geben, das es ermöglicht,
Programme aus "Starting Forth" direkt, ohne daß man diese Liste
im Kopf haben muß, einzugeben.
Kapitel 1 - Grundlagen
7 -) im volksFORTH System wurde statt "Lexikon" konsequent
der Begriff "Dictionary" verwendet.
9 -) Statt "?" durckt das volksFORTH "haeh?" , wenn
XLERB eingegeben wird.
-) Selbstverständlich akzeptiert das volksFORTH Namen
mit bis zu 31 Zeichen Länge.
ı1 -) Im volksFORTH kann auch der Hochpfeil """ als Zeichen
eines Namens verwendet werden.
-) Fußnote 6 : Der 83-Standard legt fest, daß ." nur
innerhalb von Definitionen verwendet werden darf.
Außerhalb muß man .( verwenden.
17 -) Das volksFORTH gibt bei Stackleerlauf irgendeine Zahl
aus, nicht unbedingt eine Null !
18 -) Druckfehler : Bei dem Beispiel (n -- ) muß zwischen
"(" und "n" ein Leerzeichen stehen. Das gilt auch für
viele der folgenden Kommentare.
19 -) Bei dem Wort EMIT muß man natürlich angeben, in
welchem Code das Zeichen kodiert ist. Beim volksFORTH
auf dem cC64 ist das nicht der ASCII-Zeichensatz,
sondern der Commodore-spezifische. Am Besten ist es,
statt 42 EMIT lieber ASCII * EMIT einzugeben.
23 =)
31 -)
38 -)
=}
=}
39 =)
Kapitel 2 - Wie man in Forth rechnet
Druckfehler : Selbstverständlich ist 10 1000 *
kleiner als 32767, kann also berechnet werden. Kurios
wird es nämlich erst bei 100 1000 *
Die Operatoren /MOD und MOD arbeiten laut 83-
Standard mit vorzeichenbehafteten Zahlen. Die Defini-
tion von Rest und Quotient bei negativen Zahlen
findet man unter "Division, floored"” in "Definition
der Begriffe" oder unter /MOD im Glossar.
Seien Sie bitte bei allen Multiplikations- und Divi-
sionsoperatoren äußerst mißtrauisch und schauen Sie
ins Handbuch. Es gibt keinen Bereich von Forth, wo
die Abweichungen der Systeme untereinander größer
sind als hier.
.s ist im System als Wort vorhanden. Unser 8
druckt nichts aus, wenn der Stack leer ist. Auch die
Reihenfolge der Werte ist andersherum, der oberste
Wert steht ganz links. Alle Zahlen werden vorzeichen-
los gedruckt, d.h. -1 erscheint als 65535 .
'S heißt im volksFORTH SP@ 2
Das Wort DO £unktioniert nach dem 83-Standard
anders als im Buch. .S druckt nämlich, falls kein
Wert auf dem Stack liegt, 32768 Werte aus. Ersetzt
man DO durch ?DO ,„ so funktioniert das Wort .S „
aber nur dann, wenn man 2- wegläßt. Nebenbei
bemerkt ist es sehr schlechter Stil, den Stack direkt
zu addressieren !
<ROT ist im volksFORTH unter dem Namen -ROT vor-
handen.
Kapitel 3 - Der Editor und externe Textspeicherung
Beim volksFORTH auf dem ST wird ein leistungsfähiger Bild-
schirmeditor mitgeliefert, dessen Bedienung sich von dem im
Buch benutzten Zeileneditor stark unterscheidet.
75 -)
Kapitel 4 - Entscheidungen
Die Vergleichsoperatoren müssen nach dem 83-Standard
-1 auf den Stack legen, wenn die Bedingung wahr ist.
Dieser Unterschied zieht sich durch das ganze Buch
und wird im folgenden nicht mehr extra erwähnt. Also
© -1 ist "wahr" „ O0 ist "£falsch" . Daher entspricht
0= nicht mehr NOT. NOT iäinvertiert nämlich jedes
der 16 Bit einer Zahl, während 0= falsch liefert,
84
89
91
93
98
104
1228 weibp/re/ks A=51
Anhang
wenn mindestens eins der 16 Bit gesetzt ist. Überall,
wo NOT steht, sollten Sie 0= verwenden.
Das Wort ?STACK im volksFORTH liefert keinen Wert,
sondern bricht die Ausführung ab, wenn der Stack
über- oder leerläuft. Daher ist das Wort ABORT"
überflüssig.
Statt -< muß es in der Aufgabenstellung 6 natürlich
=< heißen. Für positive Zahlen tut UWITHIN im
volksFORTH dasselbe.
Kapitel 5 - Die Philosophie der Festkomma-Arithmetik
=)
Eine Kopie des obersten Wertes auf dem Returnstack |
bekommt man beim volksFORTH mit R@ . Die Worte I
und J liefern die Indices von DO-Schleifen. Bei
einigen Forth-Systemen stimmt der Index mit dem
ersten bzw. dritten Element auf dem Returnstack
überein. Der dann mögliche und hier dokumentierte
Mißbrauch dieser Worte stellt ein Beispiel für
schlechten Programmierstil dar. Also: Benutzen sie I
und J nur in DO-Schleifen.
Die angedeutete Umschaltung zwischen Vokabularen
geschieht anders als beim volksFORTH.
Fußnote: Es trifft nicht immer zu, daß die Umsetzung
von Fließkommazahlen länger dauert als die von Inte-
gerzahlen. Insbesondere dauert die Umsetzung von
Zahlen beim volksFORTH länger als z.B. bei verschie-
denen BASIC-Interpretern. Der Grund ist darin zu
suchen, daß die BASICs nur Zahlen zur Basis 10
ausgeben und daher für dieses Basis optimierte Routi-
nen verwenden können während das volksFORTH Zahlen zu
beliebigen Basen verarbeiten kann. Es ist aber
durchaus möglich, bei Beschränkung auf die Basis 10
eine erheblich schnellere Zahlenausgabe zu program-
mieren.
* /MOD im volksFORTH arbeitet mit vorzeichen-
behafteten Zahlen. Der Quotient ist nur 16 Bit lang.
Kapitel 6 - Schleifenstrukturen
Die Graphik auf dieser Seite stellt lImplementations-
details dar, die für das polyFORTH gelten, nicht aber
£für das volksFORTH. Reißen Sie bitte diese Seite aus
dem Buch heraus.
108
110
111
114
125
130
132
137
-)
A-52 (23 1928 weibp/re/ks
J liefert zwar den Index der äußeren Schleife, aber
nicht den 3. Wert auf dem Returnstack.
Das Beispiel TEST funktioniert nicht. Beim 83-
Standard sind DO und LOOP geändert worden, so daß
sie jezt den gesamten Zahlenbereich von 0...65535
durchlaufen können. Eine Schleife nn DO ... LOOP
exekutiert also jetzt 65536 - mal und nicht nur
einmal, wie es früher war.
Beim volksFORTH wird beim Eingeben von nichtexisten-
ten Worten nicht der Stack geleert, denn der Textin-
terpreter führt nicht ABORT" aus, sondern ERROR"
Den Stack leert man durch Eingabe der Worte
CLEARSTACK oder ABORT .
LEAVE wurde im 83-Standard so geändert, daß sofort
bei Ausführen von LEAVE die Schleife verlassen wird
und nicht erst beim nächsten LOOP. Daher ändert
LEAVE auch nicht die obere Grenze.
Kapitel 7 - Zahlen, Zahlen, Zahlen
Es ist systemabhängig, ob EMIT Steuerzeichen ausge-
ben kann.
Seien Sie mißtrauisch ! Das Wort U/MOD heißt im 83-
Standard UM/MOD .
Das Wort /LOOP ist nun überflüssig geworden, da das
normale Wort LOOP bereits alle Zahlen durchlaufen
kann.
Beim volksFORTH werden nur Zahlen, die "," oder ".
enthalten, als 32-Bit Zahlen interpretiert. "/" und
":" sind nicht erlaubt.
Der 83-Standard legt fest, daß SIGN ein negatives
Vorzeichen schreibt, wenn der oberste (und nicht der
dritte) Wert negativ ist. Ersetzen Sie bitte jedes
SIGN durch ROT SIGN ,„ wenn Sie Beispiele aus dem
Buch abtippen.
Für HOLD gilt dasselbe wie das für EMIT
(Abweichung Seite 19) gesagte. Benutzen Sie statt 46
HOLD besser ASCII - HOLD
FÜRTH
178
weribp/re/iks
D- DMAX DMIN und DU< sind nicht vorhanden.
32-Bit Zahlen können in eine Definition geschrieben
werden, indem sie durch einen Punkt gekennzeichnet
werden. Die Warnung für experimentierfreudige Leser
trifft beim volksFORTH also nicht zu.
M+ M/ und M*/ sind nicht vorhanden. Für M/
können Sie M/MOD NIP einsetzen und für M+ etwa
EXTEND D+
U* heißt im 83-Standard UM* und U/MOD UM/MOD
Aufgabe 7 ist großer Quark ! Die Tatsache, daß viele
Forth-Systeme .. als doppelt genaue Null interpre-
tieren, bedeutet nicht, daß es sich um keinen Fehler
der Zahlenkonversion handelt. Das volksFORTH toler-
iert solche Fehleingaben nicht.
Kapitel 9 - Forth intern
Zu den Fußnoten 1,2 : Der 83-Standard schreibt für
das Wort FIND, ein anderes Verhalten vor, als hier
angegeben wird. Insbesondere sucht FIND nicht nach
dem nächsten Wort im Eingabestrom, sondern nimmt als
Parameter die Adresse einer Zeichenkette (counted
String), nach der gesucht werden soll. Auch die auf
dem Stack abgelegten Werte sind anders vorgeschrie-
ben.
Das Beispiel 38 ' GRENZE |! ist schlechter Forth
Stil; es ist verpönt, Konstanten zu ändern. Da das
Wort ' nach dem 83-Standard die Kompilationsadresse
des folgenden Wortes liefert (und nicht die Para-
meterfeldadresse), der Wert einer Konstanten aber
häufig in ihrem Parameterfeld aufbewahrt wird, funk-
tioniert das Beispiel auf vielen Forth Systemen, die
dem 83-Standard entsprechen, folgendermaßen: 38 '
GRENZE >BODY !
Fußnote 3 : Die Fußnote trifft für den 83-Standard
nicht zu. ' verhält sich wie im Text beschrieben.
Das volksFORTH erkennt 32-Bit Zahlen bereits serien-
mäßig, daher gibt es kein Wort "NUMBER . Wollen Sie
181
188
189
190
191
197
198
200
202
>
ı
un
[3
m
.
w
u
a
in
weibp/re/ihz
AFORTHE ef
eigene Zahlenformate erkennen (etwa Floating Point
Zahlen ,„ so können Sie dafür das deferred Wort
NOTFOUND benutzen.
Die vorgestellte Struktur eines Lexikoneintrags ist
nur häufig anzutreffen, aber weder vorgeschrieben
noch zwingend. Zum Beispiel gibt es Systeme, die
keinen Code Pointer aufweisen. Das volksFORTH sieht
jedoch ähnlich wie das hier vorgestellte polyFORTH
aus.
Druckfehler : Statt ABORT' muß es ABORT" heißen.
Der 83-Standard schreibt nicht vor, daß EXIT die
Interpretation eines Disk-Blockes beendet. Es funk-
tioniert zwar auch beim volksFORTH, aber Sie benutzen
besser das Wort \\
Die Forth Geographie gilt für das volksFORTH nicht;
einige der Abweichungen sind :
Die Variable H heißt im volksFORTH DP (=Dictionary
Pointer) .
Der Eingabepuffer befindet sich nicht bei so ,
sondern TIB liefert dessen Adresse.
Der Bereich der Benutzervariablen liegt woanders.
Zusätzliche Definitionen : Beim volksFORTH ist die
Bibliothek anders organisiert. Ein Inhaltsverzeichnis
der Disketten können Sie sich mit FILES ausgeben
lassen.
Der Multitasker beim volksFORTH ist gegenüber dem des
polyFORTH vereinfacht. So besitzen alle Terminal-
Einheiten (wir nennen sie Tasks) gemeinsam nur ein
Lexikon und einen Eingabepuffer. Es darf daher nur
der OPERATOR (wir nennen in Main- oder Konsolen-
Task) kompilieren.
Im volksFORTH sind SCR R# CONTEXT CURRENT »IN
und BLK keine Benutzervariablen.
Das über Vokabulare gesagte trifft auch für das
volksFORTH zu, genaueres finden Sie unter Vokabu-
larstruktur im Handbuch.
LOCATE heißt im volksFORTH VIEW
203
211
212
213
217
219
223
1328 we/bp/rerkhs A-55 Anhang I
EXECUTE benötigt nach dem 83-Standard die Kompila-
tionsadresse und nicht mehr die Parameterfeldadresse
eines Wortes. Im Zusammenhang mit ' stört das nicht,
da auch ' geändert wurde.
Kapitel 10 - Ein- und Ausgabeoperationen
Die angesprochene Funktion von FLUSH führt nach dem
83-Standard das Wort SAVE-BUFFERS aus. Es schreibt
alle geänderten Puffer auf die Diskette zurück. Das
Wort FLUSH existiert ebenfalls. Es unterscheidet
sich von SAVE-BUFFERS dadurch, daß es nach dem
zurückschreiben alle Puffer löscht. Die Definition
ist einfach :
£flush save-buffers empty-buffers ;
FLUSH wird benutzt, wenn man die Diskette wechseln
will, damit von BLOCK auch wirklich der Inhalt
dieser Diskette geliefert wird.
Fußnote 4 trifft für das volksFORTH nicht zu.
Der 83-Standard schreibt vor, daß BUFFER sehr wohl
darauf achtet, ob ein Puffer für diesen Block bereits
existiert. BUFFER verhält sich genauso wie BLOCK ,
mit dem einzigen Unterschied, daß das evtl. erforder-
liche Lesen des Blocks von der Diskette entfällt.
Wie schon erwähnt, muß bei den Beispielen auf dieser
Seite SO @ durch TIB ersetzt werden. Ebenso muß '
TEST durch ' TEST >BODY ersetzt werden. Das gilt
auch für das folgende Beispiel BEZEICHNUNG .
Druckfehler : WORT ist durch QUATSCH zu ersetzen.
<CMOVE heißt nach dem 83-Standard CMOVE> . Der
Pfeil soll dabei andeuten, daß man das Wort benutzt,
um im Speicher vorwärts zu kopieren. Vorher war
gemeint, daß das Wort am hinteren Ende anfängt.
Für MOVE wird im 83-Standard ein anderes Verhalten
vorgeschlagen. MOVE wählt zwischen CMOVE und
CMOVE> ,„ je nachdem ,„ in welche Richtung verschoben
wird.
Fußnote 10 : QUERY ist auch im 83-Standard vorge-
schrieben.
In
| | Anhang E A-56 (23 1326 weibp/re/hz
224
229
230
232
247
249
250
251
-)
WORD kann, muß aber nicht seine Zeichenkette bei
HERE ablegen.
Nach dem 83-Standard darf EXPECT dem Text keine
Null mehr anfügen.
Fußnote 14 : PTR heißt beim volksFORTH DPL (=
decimal point location)
Ersetzen sie WITHIN durch UWITHIN oder
?INNERHALB. NOT muß durch 0= ersetzt werden, da
die beiden Worte nicht mehr identisch sind.
Druckfehler in Fußnote 15 : Der Name des Wortes ist
natürlich -TEXT und nicht TEXT . Außerdem müssen
die ersten beiden "/" durch "@" ersetzt werden.
Das dritte "/" ist richtig.
Kapitel 11 - Wie man Compiler erweitert...
BEGIN DO usw. sehen im volksFORTR anders aus, damit
mehr Fehler erkannt werden können.
Fußnote 2 : Die Erläuterungen beziehen sich auf
polyFORTH, im volksFORTH siehts wieder mal anders
aus. Die Frage ist wohl nicht unberechtigt, warum in
einem Lehrbuch . solche implementationsabhängigen
Details vorgeführt werden.
Fußnote 3 : Eine Konstante im volksFORTH kommt, falls
sie namenlos (siehe Kapitel "Der Heap" im Handbuch)
definiert wurde, mit 2 Zellen aus.
Die zweite Definition von 4DAZU funktioniert beim
volksFORTH nicht, da das Wort : den ; während
der Kompilation Werte auf dem Stack übergibt. Das ist
aurch den 83-Standard erlaubt.
Druckfehler : Statt L[SAG-HALLO)] muß es [ SAG-HALLO
] heißen.
Die Beispiele für LITERAL auf dieser Seite funktio-
nieren, da LITERAL standardgemäß benutzt wird.
Druckfehler : Statt ICH SELBST muß es ICH-SELBST
252
255
270
239
1828 wesbp/rerhs A-57
heißen.
Bei Definitionen, die länger als eine Zeile sind,
druckt das volksFORTH am Ende jeder Zeile "compiling"
statt "ok" aus.
Die Beispiele für INTERPRET und |] entstammen dem
polyFORTH. Eine andere Lösung wurde im volksFORTH
verwirklicht. Hier gibt es zwei Routinen, je eine für
den interpretierenden und kompilierenden Zustand.
INTERPRET führt diese Routinen vektoriell aus.
Fußnote 4 trifft für das volksFORTH nicht zu.
Kapitel 12 - Drei Beispiele
Druckfehler : In WÖRTER ist ein 2DROP zuviel;
ferner sollte >- >IN sein.
In BUZZ muß es statt WORT .WORT heißen.
(Reingefallen : Es muß WÖRTER sein!)
Die Variable SEED muß wohl SAAT heißen. Ob der
Übersetzer jemals dieses Programm kompiliert hat?
Nebenbei: Im amerikanischen Original hatten die Worte
NÄCHSTES WÖRTER FÜLLWÖRTER und EINLEITUNG noch
einen Stackkommentar, ohne die das Programm unver-
ständlich wird, besonders bei diesem fürchterlichen
Satz. Also, wenn Sie an Ihren Fähigkeiten zweifeln,
sollten Sie sich das amerikanische Original besorgen.
A-58 023 1388 werbp/rerks
p.103
p.107
p.116
p.118
p.125
p.126
p.141
p.146
p.149
(c} IS2E we/icp/re/hz A-59
Abweichungen des volksFORTH83 von
'FORTH TOOLS"
von A. Anderson & M. Tracy
CLEAR macht im volksFORTH33 etwas anderes als in FORTH
TOOLS. Benutze statt CLEAR das Wort CLEARSTACK oder
definiere
' celearstack Alias clear
.S druckt die Werte auf dem Stack anders herum aus,
ausserdem fehlt der Text "Stack:"
2ROT fehlen. Benutze
2rot 5 roll 5 Toll ;
Statt DIRECTORY heißt es FILES
THRU druckt keine Punkte aus.
Der Editor funktioniert anders.
volksFORTH83 enthaelt kein Wort ? . Benutze
;? @.;
AGAIN gibt es nicht. Benutze stattdessen REPEAT oder
definiere
' REPEAT Alias AGAIN immediate restrict
Benutze ' extend Alias s>d
DU< fehlt.
SPAN enthaelt 6 Zeichen, da "SPAN ?" genau 6 Zeichen
lang ist. Das System benutzt naemlich ebenfalls
EXPECT. Daher geht das Beispiel auf Seite 117 auch
nicht. Damit es geht, muss man alle Worte in einer
Definition zusammenfassen.
CPACK entspricht dem Wort PLACE.
Benutze
: String Create dup ,„ 0 c, allot Does> 1+ count ;
kann nicht interpretiert werden. Zwei Gänsefüßchen
hintereinander sind ebenfalls nicht erlaubt.
Das Wort IS aus dem volksFORTH83 kann innerhalb von
Definitionen benutzt werden.
Es gibt keine Variable WIDTH ,„ da bei Namen alle
Zeichen gültig sind.
Benutze
: link >name 2- ;
« Zink)? 2+ name> ;
ı n>link 2- ;
l>name 2+;
ei
Anhang
p.166
p-167
p.184
A-60 i-) IBZE we/kp/re/hzs
STOP entspricht \\
Bei FIND kann das Flag auch die Werte -2 oder +2
annehmen.
ORDER ist nicht in ONLY , sondern in FORTH enthal-
ten. Außerdem druckt es auch nicht "Context:" oder
"Current:" aus. Current wird stattdessen einfach zwei
Leerzeichen hinter Context ausgegeben.
(c) 1328 we/bp/re/khs A-61 Anhang
Fehlermeldungen des volksFORTH83
Das volksFORTH83 gibt verschiedene Fehlermeldungen und Warnun-
gen aus. Zum Teil wird dabei das zuletzt eingegebene Wort
wiederholt. Diese Meldungen sind im folgenden nach Gruppen
getrennt, aufgelistet:
Kernel
Der eingegebene String konnte nicht mit NUMBER in eine
Zahl umgewandelt werden. Beachten Sie den. Inhalt von
BASE.
Adress Error !
Dies ist ein fataler Fehler. Der Prozessor hat versucht,
mit einer Wortoperation auf eine ungerade Adresse zuzu-
greifen. Sollten Sie keinen fehlerhaften Maschinencode
geschrieben haben, so ist das Forth "zerschossen".
beyond capacity
Der angesprochene Block ist physikalisch nicht vorhanden.
Beachten Sie den Inhalt von OFFSET.
Bus Error !
Der Prozessor hat versucht, auf einen nichtexistenten
Speicher zuzugreifen. Prüfen Sie bitte alle verwendeten
Langwortoperationen.
compile only
Das eingegebene Wort darf nur innerhalb von :-Definitio-
nen verwendet werden.
crash
Es wurde ein deferred Wort aufgerufen, dem noch kein
auszuführendes Wort mit IS zugewiesen wurde.
Dictionary £full
Der Speicher für das Dictionary ist erschöpft. Sie müssen
die Speicherverteilung ändern oder Worte mit FORGET
vergessen.
Division by 0 !
Es wurde versucht, durch Null zu teilen.
division overflow
Die Division zweier Zahlen wurde abgebrochen, da das
Ergebnis nicht im Zahlenbereich darstellbar ist.
exists
Das zuletzt definierte Wort ist im Definitons-Vokabular
schon vorhanden. Dies ist kein Fehler, sondern nur ein
Hinweis!
haeh?
Das eingegebene Wort konnte weder im Dictionary gefunden
noch als Zahl interpretiert werden.
MM;
| Anhang A-62 2) 1326 we/bp/ra/ks
Illegal Instruction !
Dies ist ein fataler Fehler. Der Prozessor hat versucht,
einen nicht erlaubten Befehl auszuführen. Sollten Sie
Maschinencode geschrieben haben, so prüfen Sie ihn bitte
auf unzulässige Kombinationen von Befehl und Adres-
sierungsart. Sind Sie sich keiner Schuld bewußt, so ist
das Forth zerstört.
invalid name
Der Name des definierten Wortes ist zu lang (mehr als 31
Zeichen) oder zu kurz (Der Name sollte dem definierenden
Wort unmittelbar folgen).
is symbol
Das Wort, das mit FORGET vergessen werden sollte,
befindet sich auf dem Heap. Benutzen Sie dafür CLEAR.
nein
Der Bereich von Blöcken, der mit CONVEY kopiert werden
sollte, ist leer oder viel zu groß.
no file
Auf Ihrem System sind keine Files benutzbar. Die Variable
FILE muß daher den Wert Null haben. Siehe auch die
Fehlermeldungen des Fileinterfaces
not deferred
Es wurde versucht, mit IS einem Wort, das nicht
deferred ist, eine auszuführende Prozedur zuzuweisen.
not enough parameters
Ein Wort erwartete mehr Werte auf dem Stack, als vorhan-
den waren. Dieser Fehler wird bei Ausführung des Wortes
ARGUMENTS erzeugt.
protected
Es wurde versucht, ein Wort zu vergessen, das mit SAVE
geschützt wurde. Benutzen Sie die Phrase:
' <name> >name 4 - (forget save
read error |!
Bei einem Lesezugriff auf die Diskette trat ein Fehler
auf. Der zu lesende Buffer wurde nicht markiert.
stack empty
Es wurden mehr Werte vom Stack genommen als vorhanden
waren.
tight stack
Es befanden sich zuviele Werte auf dem Stack, sodaß der
Speicher erschöpft war. Legen Sie weniger Werte auf den
Stack, oder sparen Sie Speicherplatz im Dictionary.
unstructured
Kontrollstrukturen wurden falsch verschachtelt oder weg-
gelassen. Diese Fehlermeldung wird auch ausgegeben, wenn
sich die Zahl der Werte während der Kompilation einer :-
Definition zwischen : und ; geändert hat.
Userarea full
Es wurden mehr als 124 Uservariablen definiert. Das ist
nicht zulässig.
Vocabulary stack full
Es wurden zuviele Vokabulare mit ALSO in den festen
Teil der Suchreihenfolge übernommen. Benutzen Sie ONLY
oder TOSS, um Vokabulare zu entfernen.
write error !
Siehe " read error ..."
Fileinterface
close error
Das mit SAVESYSTEM erzeugte File konnte nicht ordnungsge-
mäß geschlossen werden.
Datei nicht gefunden
Eine nach USE oder anderen Worten angegebene Datei
konnte nicht auf dem Massenspeicher gefunden werden.
Prüfen Sie bitte, ob PATH korrekt gesetzt ist.
Disk schreibgeschützt
Es wurde versucht, auf eine schreibgeschützte Diskette zu
schreiben. Prüfen Sie bitte, ob ein Block fälschlich als
UPDATEd markiert wurde.
Disk voll
Die Diskette ist voll, daher kann MORE nicht mehr
ausgeführt werden.
Dos-Error #00
Es trat ein Fehler im TOS auf. Die Nummer hat folgende
Bedeutung :
Bios 01 Error
02 Drive not ready
03 Unknown command
04 CRC Error
05 Bad request
06 Seek error
07 Unknown media
08 Sector not found
09 Out of paper
10 Write fault
11 Read fault
14 Media change detected
15 Unknown device
16 Bad sectors on format
17 Insert other disk (request)
GEM-Dos 32 Invalid function number
35 Handle pool exhausted
36 Acess denied
40 Invalid memory block adress
Le} vRzE we/bp/re/bz
46 Invalid drive specificaticen
47 No more files
64 Range error
65 GEMDOS internal error
66 Invalid executable file format
67 Memory block growth failure
Wenn Sie mit diesen Fehlerbeschreibungen nicht viel
anfangen können, so trösten Sie sich: wir können es auch
nicht. Es ist auch nicht erforderlich; erscheinen doch
die Fehlernummern ziemlich unmotiviert und selten feh-
lerspezifisch, oft liefern sie keinerlei Hinweis auf die
Art des auftretenden Fehlers.
missing filename
Auf das Wort SAVESYSTEM muß ein Filename folgen, der
aber nicht vorhanden war.
no device
SAVESYSTEM konnte nicht das gewünschte File erzeugen.
Prüfen Sie bitte, ob die Diskette vorhanden, fehlerfrei
und nicht schreibgeschützt ist.
No file !
Es wurde versucht, die Diskette im Directmodus mit MORE
zu verlängern oder ihr mit ASSIGN ein File zuzuweisen.
Prüfen Sie bitte mit FILE? das aktuelle File.
Pfad nicht gefunden
Der mit DIR angegebene Pfad existiert nicht. Überzeugen
Sie sich bitte, daß die richtige Diskette im Laufwerk
steckt.
string too long
Der nach ASSIGN, USE, MAKEFILE, LOADFROM, MARE oder
INCLUDE angegebene Filename ist zu lang. Entfernen sie
bitte Subdirectories aus dem Pfadnamen, und setzen Sie
DIR entsprechend.
Ungültige Handle#
Es liegt ein Fehler bei der Verwaltung der Files vor. Das
Forth versucht, mit Hilfe einer durch das TOS vergebenen
Zahl, der "Handle", auf ein File zuzugreifen, das bereits
wieder geschlossen worden ist. Versuchen Sie, von Hand
die Handle in der Liste der FCBs zu löschen.
Ungültiges Laufwerk
Das durch SETDRIVE bzw. A: B: C: oder D: angegebene
Laufwerk existiert nicht.
write error
SAVESYSTEM konnte nicht das gesamte System speichern,
Prüfen Sie bitte, ob die Diskette voll ist.
Wrong range
CONVEY kann die angegebenen Blöcke nicht kopieren, da sie
nicht existieren. Prüfen Sie bitte, ob das File, in das
kopiert werden soll, ausreichend lang ist.
(2) 1385 werbp/re/ks A-65 Anhang i
Zugriff nicht möglich
Es wurde versucht, auf einen Block zuzugreifen, der nicht
vorhanden ist. Überprüfen Sie bitte den Inhalt von OFFSET
sowie das File, auf das zugegriffen werden sollte.
ALLOCATION
No more RAM
Der Arbeitsspeicher des ST ist aufgebraucht, so daß kein
Speicher mehr angefordert werden kann.
mfree Error!
Der Speicherbereich, der mit MFREE freigegeben werden
sollte, wurde nicht allokiert. Prüfen Sie bitte, ob MFREE
zweimal aufgerufen wurde oder ob sich die Anfangsadresse,
die sie bei MALLOC erhalten haben und die Adresse, die
sie MFREE mitgeben, übereinstimmen.
GEM-Library
Menu-Error
Object-Error
Graphic-Error
File Error
Window-Error
Resource-Error
Eine Routine der entsprechenden AES-Bibliothek signali-
sierte einen Fehler.
RELOCATION
a ticket to the moon with no return ...
Der Speicherplatz, der nach Ausführung von RELOCATE für
den Returnstack übrig bliebe, ist zu klein.
cuts the dictionary
Der Speicherplatz, der nach Ausführung von BUFFERS oder
RELOCATE für das Dictionary übrig bliebe, ist zu klein.
kills all buffers
Bei Ausführung würde RELOCATE keinen Blockbuffer im
System lassen. Prüfen Sie die Argumente von RELOCATE. Die
Anweisung 0 BUFFERS ist ebenfalls nicht zulässig.
m
| An I =
hang A-66 423 ABEE weibp/re/iks
Targetcompiler-Worte
Das volksFORTH83-System wurde mit einem sog. Targetcopiler
erzeugt. Dieser Targetcompiler compiliert ähnlichen Quelltext
wie das volksFORTH33-System. Es gibt jedoch Unterschiede.
Insbesondere sind im Quelltext des volksFORTH83 Worte enthal-
ten, die der Steuerung des Targetcompilers dienen, also nicht
im Quelltext definiert werden. Wenn Sie sich also über eine
Stelle des Quelltextes sehr wundern, sollten Sie in der
folgenden Liste die fragwürdigen Worte suchen.
Eine andere Besonderheit betrifft Uservariablen. Wenn im Quell-
text der Ausdruck [ <name> ] LITERAL auftaucht und <name>
eine Uservariable ist, so wird bei der späteren Ausführung des
Ausdrucks NICHT die Adresse der Uservariablen in der Userarea
sondern die Adresse in dem Speicherbereich, in dem sich die
Kaltstartwerte der Uservariablen befinden, auf den Stack
gelegt.
Wenn die Kaltstartwerte von Uservariablen benötigt werden, wird
dieser Ausdruck benutzt.
Folgende, im Quelltext oft auftretende Worte sind im Target-
compiler definiert:
displace Target here! .unresolved origin! Compiler H T
there Tnext-link Onlypatch Host Tudp Tvoc-link Tnext-
link move-threads
datiert. nor
IRntzind - art
32...
Zn nn nn a 2 \ . i
ae eh ee u ne Teiet wi
se si mt ade Eure er safe liTeun _uGE et
\ Brei Fi rar £ eier ze nee ae
keusa” DER AAN” ans E77 K El 32 r a ar "TER I (u JaTEn
bh Dar werriger u > Bra un ar Geht zer
HAarätnt. Duhmn 4 Sue et ae Fi Tu Fee
Fi . . . i u. .
* a
a
j “
De ee re re PeerndernE ar a
I At Dan
5 2
m, set Zt de se var 2 u rk
PR i E ee am ra ne u etieisand nt
wein, ea euere
hear Selig nr
me"
i a nu leg Bann x ve,
ö en _ za e
z 5 . Get ; =
. ner BER ee E22 Tr
Ak,
nr
Be
en
=