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 ı1 Auf die Aufforderung 'Enter your ID :' antworten Sie zunächst mit . 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 . 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 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 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 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 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 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 -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 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 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 ’ noop Is custom-remove ‘ STr/w Is r/w direct 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 Damit haben Sie ein System 'ohne alles'. Speichern Sie es mit savesystem minimal.prg 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 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 Ist das System fertig kompiliert, legen Sie die Systemdiskette ein und schreiben: savesystem 4dth.prg 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 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 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: Is Hierbei ist ein durch DEFER erzeugtes Wort und der Name des Wortes, das in Zukunft bei Aufruf von ausgeführt wird. Wird 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 ; 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 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 2° 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 __ok Hierbei ist das zu tracende Wort. Zunächst geschieht noch gar nichts. DEBUG hat nur den Tracer "scharf gemacht". Geben Sie nun eine Sequenz ein, die enthält, unter- bricht der Tracer die Ausführung, wenn er auf stößt. Es erscheint folgendes Bild. addri addr2 (Werte) Hierbei ist addrl eine Adresse im Parameterfeld von , nämlich die, in der addr2 steht. addr2 ist die Kompilations- Adresse von . 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 , 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 : stack full wobei 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 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 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£ 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 ( 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 ! 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: : an benutzt wird. Es erzeugt die Wortdefinition für 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. wird als "colon-definition" oder ":-Definition" bezeichnet. Die neue Wortdefinition für kann nicht im Dictionary gefunden werden, bis das zugehörige ; oder ;CODE erfolgreich ausge- führt wurde. RECURSIVE macht 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 benutzt wird. Erzeugt einen Kopf für und legt 32b in dessen Parameterfeld so ab, daß bei Ausführung von 32b wieder auf den Stack gelegt wird. 2Variable ==) 83 Alias ein definierendes Wort, das in der Form: 2Variable benutzt wird. Erzeugt einen Kopf für und hält 4 Byte in seinem Parameterfeld frei, die den Inhalt der 2VARIABLEN aufnehmen. Die 2VARIABLE wird nicht initialisiert. Wenn ausgeführt wird, wird die Adresse des Parameterfelds auf den Stack gelegt. Siehe VARIABLE (cfa -- ) ein definierendes Wort, das typisch in der Form: ' Alias benutzt wird. ALIAS erzeugt einen Kopf für im Dictionary. Wird aufgerufen, so verhält es sich wie , sondern im Dictionary ein- (2> 1828 we/bp/re/ks Irr-19 getragen. Im Unterschied zu ! ; 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 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 benutzt wird. Wird später ausgeführt, so wird i6b auf den Stack gelegt. (ea) 83 ein definierendes Wort, das in der Form: Create benutzt wird. Erzeugt einen Kopf für . Die nächste freie Stelle im Dictionary (vergleiche HERE und DP ) ist nach einem CREATE das erste Byte des Parameterfelds von . Wenn ausgeführt wird, legt es die Adresse seines Parameterfelds auf den Stack. CREATE reserviert keinen Speicherplatz im Parameterfeld von . (==) ein definierendes Wort, das in der Form: Defer benutzt wird. Erzeugt den Kopf für ein neues Wort im Dictionary, hält 2 Byte in dessen Parameter- feld frei und speichert dort zunächst die Kompila- tionsadresse einer Fehlerroutine. Wird nun aus- geführt, so wird eine Fehlerbehandlung eingeleitet. Man kann dem Wort jedoch zu jeder Zeit eine andere Funktion zuweisen mit der Sequenz: ' Is Nach dieser Zuweisung verhält sich wie . Mit diesem Mechanismus kann man zwei Probleme elegant lösen: Einerseits läßt sich 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 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: newKEY newKEY? newDECODE newEXPECT ; r Output: User 2) IREE we/bp/re/hs INPUT: erzeugt einen Kopf für im Dictionary und kompiliert einen Satz von Zeigern auf Worte, die für die Eingabe von Zeichen zuständig sind. Wird ausgeführt, so wird ein Zeiger auf das Parameterfeld von in die Uservariable INPUT geschrieben. Alle Eingaben werden jetzt über die neuen Eingabewörte abgewickelt. Die Reihenfolge der Worte nach INPUT: 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: ' « Is benutzt. Wenn kein deferred Wort ist, wird eine Fehlerbehandlung eingeleitet, sonst verhält sich anschließend wie (action). Siehe DEFER . (ir) "output-colon" ein definierendes Wort, benutzt in der Form: Output: newEMIT newCR newTYPE newDEL newPAGE newAT newAT? ; OUTPUT: erzeugt einen Kopf für im Dictionary und kompiliert einen Satz von Zeigern auf Worte, die für die Ausgabe von Zeichen zuständig sind. Wird ausgeführt, so wird ein Zeiger auf das Parameterfeld von 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 USER erzeugt einen Kopf für 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 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 VARIABLE erzeugt einen Kopf für ) 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 ausgeführt, so wird die Adresse des Parame- terfeldes von auf den Stack gelegt. Mit ® und ! kann der Wert von gelesen und geschrieben werden. Siehe auch +! . Vocabulary (e==%) 83 ein definierendes Wort, das in der Form: Vocabulary benutzt wird. VOCABULARY erzeugt einen Kopf für , das den Anfang einer neuen Liste von Worten bildet. Wird ausgeführt, so werden bei der Suche im Dictionary zuerst die Worte in der Liste von berücksichtigt. wird das VOCABULARY durch die Sequenz: DEFINITIONS zum Kompilations-Vokabular, so werden neue Wort-Defi- nitionen in die Liste von 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 ' benutzt. adär ist die Kompilationsadresse von name). Wird 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 : : [ ' custom-remove >body @ , ] @ remove ; ' 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 benutzt. Falls in der Suchreihenfolge gefunden wird, so werden und alle danach definierten Worte aus dem Dictionary entfernt. Wird nicht gefunden, so wird eine Fehlerbehandlung eingeleitet. Liegt 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: : ... compile ...; Wird ausgeführt, so wird die Kompilationsadresse von zum Dictionary hinzugefügt und nicht ausge- führt. Typisch ist immediate und 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?" „.% u... Doesy u... } und später: wobei 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 aufgerufen wird. In diesem Fall ist addr die Parameterfeldadresse von 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: ['] Kompiliert die Kompilationsadresse von als eine Konstante. Wenn die :-definition später ausgeführt wird, so wird addr auf den Stack gebracht. Ein Fehler tritt auf, wenn in der Suchreihenfolge nicht gefunden wird. [compile] ( == ) 83,1,C "bracket-compile" =) compiling wird in der folgenden Art benutzt: [compile] Erzwingt die Kompilation des folgenden Wortes . 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 Wird in der Suchreihenfolge gefunden, so wird der auf folgende Text bis zum Ende der Zeile ignoriert. Wird nicht gefunden, so wird die Interpretation hinter 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: .. 's ... 'S liest den Namen einer USERvariablen und hinterläßt die Adresse usradr dieser USERvariablen in der durch Tadr gekennzeichneten Task. Typisch wird Tadr durch Ausführung von 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 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 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! L® 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. ) 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: 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 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 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 , etc. Pfadnamen. Wird ein File auf dem Massenspeicher gesucht, so wird zunächst , dann 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 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 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 Damit läßt sich ein FORTH-System im gegenwärtigen Zustand unter dem Namen 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 SAVESYSTEM COPY.PRG 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 benutzt. Erzeugt ein Forthwort mit Namen . Wird 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 Erzeugt ein Forthfile mit Namen <«NAME> und erzeugt anschließend ein GEM-File mit demselben Namen. Die Sequenz FILE MAKE 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 Dieses Wort macht das File mit Namen zum aktuel- len File, auf das sich LOAD, LIST usw. beziehen. Es erzeugt ein Forthfile mit Namen ,„ 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 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 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 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 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 ! 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. . 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 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 [ ] LITERAL auftaucht und 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 =