 F6  nderungen, Erg€nzungen, Korrekturen und ein paar Tips in loser Folge,
 erg€nzend zur Dokumentation "forth_gls" in der Version vom 4.8.1993,
 Reihenfolge mit den j‡ngsten  nderungen zuerst.
 Beschreibung der Funktion des Hilfs-Jobs s. Vers. 7.15
        7.23     1.2.95   j‡ngste hier behandelte Version, damit hat
 dieser Text neben den allgemeinen Beispielen nurmehr "historischen" Wert.
        8.08    20.8.96   j‡ngste in "F6WORDS_txt" beschriebene Version,
 auf die hier nicht gesondert eingegangen wird.

 Neben dem F6 steht (kostenlos) noch ein fig-Standardsystem zur Verf‡gung,
 das mit weniger als 6K Bytes f‡r den Kern extrem kompakt ist.
 Autor ist Laurence Reeves, der die f.i.g.-Standard-Installation f‡r den QL
 zurechtgemacht hat. Das System wurde an einigen wenigen Stellen von Fehlern
 befreit und erg€nzt, sodaœ es nun auch ‡ber bis zu 64K Adressbereich verf‡gt.

 Wer geneigt ist, die F6-Beschreibungen in eine andere Sprache zu ‡bersetzen,
 wird gebeten, dies zu tun, und sich mit dem Autor in Verbindung zu setzen.

 Kennzeichnung:
 disp    displacement, Abstand z.B. von einer Adresse
 {namen} zwischen "{" und "}" ohne Kennzeichnung geh„ren dem Forth-Vocabular an
 (a)     assembler-Vocabular asm68
 (D)     deferred
 (h)     hidden-vocabular
 (I)     immediate
 (r)     root-Vocabular
 (S)     vom Screenfile "forth_scr" zu compilieren

 * ++ 1994 ++ ab Version 7.15 +++++++

 Copyright (C) 1996 by
        H.-Peter Recktenwald, D-12159 Berlin, Albestr. 21
        Tel.: 030 8520413  -  inet  phpr@berlin.snafu.de

 * ++ Praeliminarien ++++++++++++++++

 Nach dem Muster des (ziemlich vollgestpften) F-PC zum ibm-PC zuerst mal eine
 Liste, wie sich das System am effizientesten zum ZUSAMMENBRUCH bringen l€œt,
 und wie NICHT, wo aber andere Systeme sich ‡blicherweise verabschieden. Zuerst
 die problematischen Operationen, die dort mit groœer Sicherheit zum Desaster
 f‡hren, die aber im F6 erlaubt sind, oder abgefangen werden:
        -1 @            ungerade Adressen sind im F6 erlaubt,
        -1 !            kann Probleme verursachen, wenn dort compilierte
                        Worte stehen (-1 ist etwa die Mitte des Dictionary).
        -1 >r           endet in einer ausf‡hrlichen Fehlermeldung, ausgel„st
                        normalerweise durch die trap-redirection des QDOS, die
                        das F6-System sch‡tzt, oder wird durch den zus€tzlichen
                        §berwachungsjob des F6 abgefangen (Super-GC/qxl);
        perform         bei (versehentlich) ungeraden Adressen gleichermaœen.
        >r              wird fast immer abgefangen („fter Fehler bei SMSQ).
        r>              was f‡r alle Returnstack-Operationen gilt.
        0 0 DO          kehrt nach einmaliger Ausf‡hrung der Schleife zur‡ck.
        multitasking    mit mehreren F6-Jobs ist dank QDOS v„llig problemlos,
                        mit einzelnen 4th-Worten durch die Tasker-Erweiterung
                        gibt es nur selten Schwierigkeiten.
        forget          des Ziels von {deferred}-Worten wird abgefangen, das
                        Wort kehrt dann mit Fehlermeldung nach {quit} zur‡ck.
                        Anwenderdefinitionen k„nnen denselben Schutz mittels
                        einer Aufrufverkettung ‡ber das deferred-Wort {doforget}
                        erreichen (s. u.a. ARRAY und HEAPMEM aus "forth_scr").
        BEGIN .. AGAIN  neben allen anderen Schleifen, auch direkt in Assembler-
                        Code (versehentlich) programmierten, kann unterbrochen
                        werden, solange {break} nicht auf -1 gesetzt wurde.
                        UND sofern nicht irgendwer das Multitasking des QL
                        "verbesert" hat...

 Hier kann auch im F6 nichts mehr helfen:
        !               irgendwohin in das Dictionary ist (meist) t„dlich,
        !l              an falsche absolute Adresse erst recht.


 * ++ Verzeichnis der wichtigsten Zusatzdefinitionen
 aus "forth_scr" mit den vorrangig zur Auswahl durch {l-load} zu verwendenden
 Namen - {l-load} ist im Kern nur als Rumpf vorhanden, der beim erstmaligen
 Aufruf den Versuch startet, die volle Definition aus "flp1_forth_scr" zu laden.
 Ist diese Datei nicht vorhanden, l€dt man z.B.
        1 s-load {dirname}_forth_scr
 oder legt vorher einen Filenamen nach {(boot)}, z.B. mit
        " n1_flp2_forth_utl_forth_scr" (boot) over @ f/n min 2+ cmove

array   Variablenfelder auœerhalb des Dictionary (im Speicher-Heap)
backup  Dateien copieren
#chan   standardisierte Kanaldefiniton
c-load  laden bereits compilierter Worte
c-save  sichern eines Blockes 4th-Worte f‡r {c-load}, l€dt auch {c-load}
debugger debug-Aktionen zur Ausf‡hrung/Compilation bei {is-debug} =/= 0
dir     Directory und Filedaten anzeigen
dump    Inhalt des 4th-Speichers anzeigen
label   Hilfsdefinitionen f‡r Assembler-Labels
ldump   dto., Inhalt beliebiger Speicherbereiche
enter   besonderer Schleifeneinsprung
heapmem abgesicherte Speicherzuweisung und Adressenspeicherung
history macht die command-line-history von "Oktagon" f‡r F6 aufrufbar
.jobs   alle QDOS-Jobs und ihre Basisdaten anzeigen
minerva erzeugt ein paar nur in Minerva aufrufbare f.p.-Rechenoperatoren
printer Worte zum Drucken, ggf. zusammen mit der Bildausgabe
q.      vierfachgenaue Zahlen in Strings umwandeln/ausgeben
.s      Stack-Dump (ab 7.22 nicht mehr im Kern), auch mit {debugger} geladen.
sort    "tag-sort" Sortierverfahren f‡r 4th-Pointer
sort-l  oder beliebige Speicher- und Fileadressen
turtle  Worte zur Kr„ten- (Krabbel- oder  auch "turtle"-) Graphik
.vocs   Anzeige der aktuellen Vocabularstruktur
where   Hilfe bei Fehlerabbruch in den {load}-Varianten
words   alphabetisch sortierte und durch Auswahl einschr€nkbare Wortliste


 * ++ SYSTEMSPERRUNG f‡r SICHERUNG und WEITERGABE eigener F6-PROGRAMME

 Eine recht sichere Sperrung des Systems wird erreicht mit:
        ' quit also hidden is [cpl]
 Diese Programm-Versiegelung macht den Compiler unwirksam. Direkte Eingabe ist
 weiter m„glich. Soll das Programm selbst gegen "Spionageversuche" gesch‡tzt
 werden, aber z.B. auch gegen (versehentliche) Fehleingaben, sind darum weitere
 Maœnahmen erforderlich.

        ' {wort} also hidden is [interpret]
 Dann werden nur noch Zahlen in direkter Eingabe erkannt, jede andere Eingabe
 ruft das o.g. {wort} auf. Da aber das Eingabeende, das ja auch durch <enter>
 signalisiert wird, stets das <nul>-Wort aufruft und interpretiert, l„st auch
 eine direkte Zahleneingabe sogleich wieder das vorgegeben {wort} aus. Nur die
 Text- oder Zahleneingabe innerhalb eines Programms bleibt weiter m„glich.
 Diese letzte Umstellung kann darum nicht vor dem Sichern als Job-File erfolgen,
 sondern muœ in das Programm selbst eingebaut werden, m„glichst an einer Stelle,
 bis zu der nach dem Start Unterbrechungen nicht m„glich sind.

 Eine weitere Variante zeigt der kleine Beispiel-Job "f6hnoi", der die "T‡rme
 von Hanoi" einmal mehr zum Programmtest strapaziert. Durch Umstellen des
 <nul>-Wortes wird hier eine einzelne Eingabezeile ordentlich interpretiert,
 dann aber sofort das Wort {hanoi} aufgerufen. Vorteil dabei ist, daœ so der
 Programmstart auch interaktiv mit Parameter‡bergabe erfolgen kann, und kleine
 Sequenzen, wie z.B. { 0 wmov } noch aufrufbar bleiben. Wurde, wie im Beispiel,
 zus€tzlich {[cpl]} ge€ndert, ist ein solches Programm sehr sicher gesch‡tzt:
        ' {wort} cfa    also hidden also assembler
                     dup dup dup ' [cpl] 2! [nul-pfa] 2!

Nat‡rlich gibt es auch hier M„glichkeiten, den Schutz aufzubrechen. Doch ist
das mit soviel M‡he verbunden, daœ der Preis vielleicht gerechtfertigt ist.
So soll also dem siegreichen "Knacker" sein Lohn dann geg„nnt sein, er wird
lediglich gebeten, sein Ergebnis nicht excessiv unter die Leute zu bringen.


 * ++ NICHT KORRIGIERTE FEHLER ++++++

headr   muœ die Angabe der zu lesenden Anzahl Bytes separat erhalten:
                ( ptr -- len flg )  14 d2w! headr
        Die lt. Beschreibung fest vorgegebene Zahl 14, und darum wurde dies
        nicht im Code korrigiert, kann somit auch ge€ndert werden, wodurch
        sich ggf. noch Filename und Datumsangaben lesen lassen.
        Ein der Dokumentation entsprechender Ersatz kann definiert werden:
                qdos definitions
        : headr 14 literal -compile d2w! -compile headr ; immediate


 * ++ VERSIONEN +++++++++++++++++++++

 * ++ 20. 8.96 ++ v8.08 +++++++++++++

 NEU: ist die Umstellung von QUERY auf eine deferred-Definition, ebenso
 (EXPER), das die Fehlerbehandlung in EXPECT und QUERY besorgt, um die
 Erweiterung auf die File-Worte des ANS-Standard zu erleichtern. Weiter
 wurden einige Fehler korrigiert, andere  nderungen gibt es nicht.

 * ++  1. 2.95 ++ v7.24 +++++++++++++

$8000   Inhalt dieser Adresse auf $8000 ge€ndert.
-0      als Constante mit dem Wert $8000 eingef‡hrt und als Null-Referenz
        der Adressierung benutzt. Sonderfall:  $8000 ABS liefert 0.

 NEU: U.a. ein universeller Stackoperator und Locale Variable.

stack   (I)( n1...nn -- nx...ny )       stack abcDEf..|abcdeFABc
           ( d1...dn -- dx...dy )       stack ABCDEF..|abCDefAbC
        Ein universell anstelle von Stackmanipulationen in einer Stacktiefe von
        bis zu 26 Quellen-Posten anwendbarer Aufruf. So, wie irgendeine Folge
        von Buchstaben hingschrieben wird, wird die Reihenfolge von Datenposten
        aus dem Buchstabenwert entsprechenden Positionen im Stack neu angeord-
        net. Groœ- und Kleinschreibung sind gleichwertig, mit der Ausnahme, daœ
        doppelte Posten transportiert werden, wenn der Quellenteil nur(!) groœe
        Buchstaben enth€lt. "a" gilt f‡r den Quellenposten 0, "z" f‡r 25. Diese
        werden mit der nach dem "|" notierten Indizierung entnommen und in den
        Datenstack copiert. Quellen- und Zielangabe zusammen k„nnen bis zu 62
        Zeichen umfassen. Ohne "|" Strich bleibt der Aufruf wirkungslos.
        Ein paar Beispiele mit Standard-Entsprechung:
                stack a|aa                      dup
                stack abc|bca                   rot
                stack abcd|abcdaabb             over >r dup dup r r>
                stack abcdefghij|abcdefghijab   9 pick 9 pick
                stack abcdefghij|cdefghijab     9 roll 9 roll
        1 2 3 4 stack abcd|abcdac (    -->   )  1 2 3 4 1 3
        1 2 3 4 stack abcd|aacc   (    -->   )  1 1 3 3
                stack abc|                      2drop drop
        Die Angabe entspricht also genau der Form, wie bei der Beschreibung
        von Forth-Worten ‡blicherweise die Stackver€nderungen notiert werden.

        Die Ausf‡hrungszeit entspricht bei kleineren Listen ungef€hr der von
        zwei {roll}-Aufrufen, bietet, da im gef€delten (interpretive) Forth-
        Compiler hier nur wenig optimierbar ist, also nichts Sensationelles:
                2rot 8 ndup             braucht nur ein Drittel der Zeit von
                stack abcdefgh|cdefghabcdefhgab
        Dagegen ist die Schreibweise so viel ‡bersichtlicher, daœ bei kompli-
        zierten Anordnungen und bei groœer Anzahl Daten im Stack Prorammier-
        fehler sehr sicher zu vermeiden und evtl. ung‡nstige Einzeloperatoren
        dann doch recht effizient zu ersetzen sind. Auf jeden Fall aber hilft
        {stack} beim Ausprobieren von Worten mit umfangreichen und komplizierten
        Parameterstrukturen und dem Herantasten an die g‡nstigste §bergabe, bis
        dann ggf. mit den Standardoperatoren Compatibilit€t geschaffen und die
        Ausf‡hrungsgeschwindigkeit optimiert werden kann.
        Die Anordnung der Indices hat keinen Einfluœ auf die Ausf‡hrungszeit.

        Damit sind die zusammengesetzten Stackoperatoren ‡berfl‡ssig, wie z.B.
        {sdup}, {sover}, aber auch alle anderen nicht-trivialen Aufrufe, etwa
        {2rot} u.dgl., die aber der geringeren Ausf‡hrungszeit wegen beibehalten
        wurden. Zur §bersetzung kann leicht die Darstellung der Datenanordnung
        vor und nach dem jeweiligen Aufruf herangezogen werden, die, ‡bertragen
        in buchstabenweise Bezeichnung, direkt als Operatorenstring dient:
                stack ab|baa    folgt f‡r {sdup} aus ( n1 n2 -- n2 n1 n1 )
                stack ab|bab              {sover}    ( n1 n2 -- n2 n1 n2 )

        Compiliert wird nach der Runtime-cfa die in Indices und "|"-Markierung
        umgewandelte Zeichenfolge samt Countbyte, am Ende ggf. f‡r gerade Folge-
        adresse mit einem Byte aufgef‡llt. Als Indices ausgewertet werden die 5
        niederwertigen Bits jedes Zeichens mit Ausnahme des Quellen- und Zielan-
        ordnung trennenden Striches "|". Gesetztes h„chstwertiges Bit im Count-
        byte markiert doppelte Postengr„œe. Der "|" wird durch ein negatives
        Byte ersetzt, das den §bergang von Ablage- zu Lese-Indices markiert.

        Diese Ablageform ist angeregt durch ein FIFTH-System zum IBM-PC ent-
        standen, dessen Programme damit sehr leicht in einen F6-Aufbau ‡ber-
        tragbar waren: Das Beispiel der "T‡rme von Hanoi" lieœ sich mit dem
        neuen Stack-Wort ohne  nderung ‡bernehmen!

local   (I)  entry:  LOCAL abc..|       compiling: ( ptr 9 -- ) resolved by {;}
             call:   LOCAL b
        Nun (endlich?) steht eine mit dem f.i.g.-Standard V¤LLIG KONFLIKTFREI
        verwendbare Installation von Localen Variablen zur Verf‡gung:

        Die Operationen in beiden Stacks bleiben von Localen Variablen g€nzlich
        unbeeinfluœt. Einzig der Datenstack-Ursprungspointer {s0} darf nicht
        ver€ndert werden - was mit wenigen h„chst speziellen Ausnahmen bedeu-
        tungslos ist. Die betr. Worte sind zudem unbedingt regul€r zu beenden,
        sie d‡rfen also nicht mit {;s} oder {-exit} vorzeitig verlassen werden.
        Die Localen Variablen sind recursiv aufrufbar; sie eignen sich auch f‡r
        tasker-Definitionen (Ausf‡hrung von Forth-Worten als selbst€ndige Jobs).

        Von anderswo beschriebenen Installationen unterscheiden sich die Localen
        Variablen des F6 insbesondere z.B. dadurch, daœ sie unver€ndert und ohne
        Einfluœ auf die Schleifenindices innerhalb von DO..LOOPs aufrufbar sind.
        S€mtliche Returnstack-Manipulationen bleiben weiterhin einsetzbar, ein-
        schlieœlich so schlimmer Sachen, wie {rdrop} zur R‡ckkehr "vor" das auf-
        rufende Wort. Der Datenstack bleibt unver€ndert zug€nglich und wird in
        den regul€ren Grenzen ‡berwacht, d.h. der Local-Bereich ist gesch‡tzt.

        Bei {warm} und {cold} werden die Localen Variablen aufgegeben, nicht
        aber bei {abort} und {error} mit allen Varianten, solange ihre Basis-
        Definitionen mit R‡ckkehr nach {quit} erhalten bleiben.

         hnlich den mit {constant} definierten Zahlen sind die einzelnen Posten
        durch ihren Namen (hier aus nur einem Buchstaben bestehend) abrufbar.
        Sie werden zu Beginn einer Hi-Level-Definition eingerichtet und mit den
        im Stack vorhandenen Posten initiiert. Die Namen sind zugleich Index in
        den Bereich, der auch die Localen Variablen aufrufender Worte enth€lt.
        Eine Grenzenkontrolle wurde nicht eingebaut, und so sind €uœere Locale
        Variable mit Indices erreichbar, die ‡ber die der eigenen Definition
        hinausweisen. {tib} kann zusammen mit der Local-Adresse aus {-loc} zur
        Pr‡fung auf die absolute Obergrenze herangezogen werden, da der Stack-
        ursprung ohne Locale Variable mit dem Anfang des t.i.b. identisch ist
        (solange dessen Lage nicht ver€ndert wurde).

        Die Benennung bezeichnet in alphabetischer Reihenfolge, beginnend mit
        "A" oder "a", die einzelnen Variablen, die vom unteren (j‡ngsten) Stack-
        posten angefangen in den localen Bereich ‡bertragen wurden.
        Es lassen sich in jedem Wort maximal 26 Locale Variable definieren, die
        Liste kann insgesamt bis zu 62 Datenposten (lang oder kurz) indizieren.
        Die Werte k„nnen wie Variable mit Hilfe ihrer Adressen ver€ndert werden.

        HINWEIS: In Laufzeit-kritischen Sequenzen sollte die Einrichtung Localer
        Variabler m„glichst vermieden werden, da dies mit zunehmender Stacktiefe
        einen u.U. recht erheblichen Zeitaufwand fordert.

local abc..|                            sys: --  stringptr 9
local ABC..|    ( nX.. nC nB nA -- nX ) loc: ..nn  -- ..nn nC nB nA
        Wenn seit dem Definitionsanfang noch keine Compilerdaten im Systemstack
        (identisch dem Datenstack) abgelegt sind, erwartet der erste Aufruf von
        {local} in einem Hi-Level-Wort eine Buchstabenfolge wie f‡r {stack},
        jedoch nur bis zum Strich "|". Wie dort bestimmt deren Schreibweise die
        Ablage als einfache oder doppelte Integer. Die der Anzahl an Localen
        Variablen entsprechende Anzahl Stackposten wird bei der Ausf‡hrung mit
        §bernahme in die locale Ablage zugleich vom Datenstack abgehoben.
local | Gibt man nur den Strich an, werden keine eigenen Posten eingerichtet.
        Der Compiler empf€ngt hierdurch lediglich das Signal, fortan {local}
        als Lese-Aufruf zu compilieren. In einem solchen Wort indizieren die
        Localen Variablen die Posten des ‡bergeordneten Aufrufs mit denselben
        Namen, die sie f‡r entsprechende Stellen im eigenen Bereich h€tten.
IF .. local .. ELSE                     sys: nn -- nn
        Innerhalb von Compiler-Strukturen ist die Deklaration einer Local-Gruppe
        nicht m„glich. Die {local}-Aufrufe werden nur als Lese-Variante (s.u.)
        compiliert, da die einfache Signalisierungsmethode das Vorhandensein der
        Initiierung vort€uscht: Sobald seit dem Wortanfang irgendwelche Daten
        in den Stack gebracht worden sind, gilt dies als Signal, nur noch Lese-
        aufrufe zu compilieren.
local a                                 sys: nn  -- nn  ( nn beliebig )
local A Jeder weitere Aufruf von {local} wertet den ersten folgenden Buchstaben
        als Bezeichnung (Index) einer Localen Variablen aus und holt die Zahl
        zum Datenstack. Auch hier bestimmt die Schreibweise, ob einfache oder
        doppelte Integer gelesen werden. f.p.-Zahlen werden nicht verarbeitet.
-loc A  (I)( -- ptr )                   sys: nn -- nn   ( nn beliebig )
-loc a  liefert den ptr auf die Speicherstelle einer Localen Variablen, die
        damit wie die gew„hnlichen Forth-Variablen nicht nur gelesen, sondern
        auch ver€ndert werden kann.
;       (I)( -- ) erg€nzt               sys: -- | stringptr 9 --
        Wenn der Systemstack (noch) nicht leer ist, und die  Markierung passt,
        wird am Ende der Definition durch {;} automatisch ein zus€tzliches Wort
        compiliert, das bei der Ausf‡hrung die Localen Variablen l„scht.

        Compiliert werden bei der Deklaration:
                lv! count.b+chars[+f‡llbyte]    Deklaration, oder
                (nichts)                        bei { local | }
        zum Lesen des Wertes:
                lv@ disp                        disp aus dem Index ermittelt als
                                                Abstand von s0 zum Datenposten.
        zurm Holen des Variablen-Pointers:
                lv  disp                        4th-Adresse, mit Abstand wie lv@
        zur Freigabe bei Wortende:
                lvr count                       count als Anzahl freizugebender
                                                Bytes im Local-Speicher, oder
                (nichts)                        wenn keine eigenen Localen
                                                Variablen eingerichtet wurden.

        Die Namen {lv!}, {lv@}, {lvr} und {lv} sind nicht aufrufbar. Dennoch
        l€œt sich mit dem Runtime-Wort zum Aufl„sen des Local-Bereichs eine
        Compileranweisung definieren,
                : end-loc [ ' -loc nfa even 6-  ] literal , , ; immediate
        die dann auch unstrukturiertes Verlassen von Worten erlaubt, in denen
        Locale Variale deklariert  wurden:
                : probe local ABC| ...
                        ... IF ... [ 12 ] end-loc ;s ENDIF ... ;

        Notfalls kann der gesamte Local-Bereich freigegeben werden durch:
                tib @ s0 !

        Ein kleines Beispiel, das belegt, daœ die Localen Variablen auch zu
        recursivem Einsatz taugen:
                : fak local A|
                  local A -1 m+ 2dup -2 m+ d0< 0= IF recurse ENDIF local A d* ;
        Damit z.B.
                12. fak d.
        liefert 479001600.

n>r     ( nn n(n0).. n1 n0 -- nn ) bringt n0 Zellen zum Returnstack;
nr>     ( n0 -- n(n0).. n1)        holt sie zur‡ck.

m>r     ( ptr n0 -- )   RP: ( nn -- nn n(n0)..n1 )
        bringt n0 Zellen aus dem 4th-Adressenbereich ab ptr in den Returnstack;
r>m     ( ptr n0 -- )   RP: ( nn n(n0)..n1 -- nn )
        legt n0 Zellen aus dem Returnstack an ptr+ im 4th-Adressenbereich ab.

dataspace (h) Variable
        Wenn hier ein Wert eingetragen wurde, der kleiner als der gr„œtm„gliche
        Datenbereich f‡r einen mit {w-save} oder {save} zu erzeugenden F6-Job
        ist, wird dieser f‡r die entspr. Angabe im Fileheader und sp€ter zur
        Einrichtung des Jobs benutzt. Damit lassen sich, insbes. bei kleinen
        Programmen, Jobs erzeugen, die nur das f‡r sie n„tige Minimum an Platz
        im Speicher belegen.
        {dataspace} wird vorzeichenlos ausgewertet, der Wert ist mit 65536
        vorgegeben, und bewirkt zun€chst immer Eintragung des Maximalwertes.
        Jenen ermittelt das System mit
                here minus 72 $8000 or -
        Keinesfalls sollten weniger als 2000 Bytes vorgesehen werden.

ch-num  ( d.chan.id -- chan.no | -1 )
        liefert die F6-Kanalnummer zu einer ‡bergebenen Kanal-id. Findet diese
        sich nur in {work}, oder geh„rt sie zu keinem F6-Kanal, kommt -1 zur‡ck.
work-num ( -- chan.no | -1 )
        liefert die F6-Kanalnummer des Kanals, der gerade {work}-Kanal ist.

 OPTIMIERUNG:
 Dazu sind die u.g. Operatoren "immediate", sie d‡rfen darum nicht in den Listen
 von {case:} etc. aufgerufen werden. {lit} kommt daf‡r ohnehin nicht in Betracht
 und die anderen sollten darin ebensowenig Verwendung finden, da sie den jeweils
 ersten Returnstack-Posten betreffen, wo bei den Listenaufrufen sinnvolle Werte
 nicht zu erwarten sind.

lit     zwei aufeinanderfolgende einfache Integer-Literale werden durch Compi-
        lieren von {dlit} und den beiden Zahlenwerten zusamengefaœt.
>r      Ablage im Returnstack,
r>      §bertrag vom Returnstack,
i r     beide funktional identisch, liefern in DO..LOOPs den Laufindex.


 GE NDERT:

(find)  (h) als urspr‡ngliche Vorgabe f‡r [find] ersetzt dessen Definition, und
        stellt so die Benennung nach dem f.i.g.-Modell wieder her. Es dient der
        Wortsuche innerhalb eines einzelnen Vocabulars.
[find]  (D)(h) bleibt als leeres deferred Wort erhalten, das in allen Varianten
        von {find} zuerst ausgef‡hrt wird, und damit Gelegenheit zu besonderen
        Aktionen einer Anwenderderfinition noch vor dem Systemaufruf bietet.
        Hier k„nnte z.B. die Wortsuche auf ein Menu-Vocabular beschr€nkt und so
        eine besonders hohe Sicherheit gegen Fehlbedienung erreicht werden.
        Im Urzustand ist eine ungerade Adresse eingetragen, wodurch [find] bei
        minimal m„glichem Zeitaufwand als inaktiv erkannt und ‡bersprungen wird.

(update) auf 0 gesetzt sperrt {r/w} f‡r Schreiboperationen.
        {ernum} liefert dann ggf. auch den Fehlercode err.ef (-10).

w-save  (I) nun "immediate".

        N.b.: Der "immediate"-Status eines jeden Wortes l€œt sich umschalten:
                ' {name} nfa $40 toggle
        oder, z.B. mit Bitmuster-Flag, definiert setzen:
                :  >imm [compile] ' nfa
                   dup c@ $40 and rot = IF drop ELSE $40 toggle ENDIF ;
        daraus:
                : set-imm $40 >imm ;    ( use: SET-IMM {name} --
                : not-imm   0 >imm ;

l<i     ( -- dn )
        damit kann unmittelbar nach den folgenden Operationen f‡r weiterf‡hrende
        Berechnungen das §berlauf-Flag als Wert =/= 0 gelesen werden:.
                * d2*
                + d+ q+ qm+
                - d- d+- q- q+-
                abs +- over-
                f>q f>d

[donext] (assembler) (-- ptr)
        ist die 4th-Adresse des Inneren Interpreters, 2 Bytes danach ist der
        Einsprung zum Ausf‡hren einer im [w]-Register befindlichen cfa (z.B.
        f‡r execute), weitere 2 Bytes danach wird auf den 16-Bit-Inhalt der
        cfa zugegriffen, und es folgt der Sprung an die mit diesem vorzeichen-
        behaftet zur Basisadresse [bp] addierten Ort in den auszuf‡hrenden Code.
        Es gibt (nunmehr) im gesamten F6-Kern keinen direkten Sprung dorthin,
        die Adressierung erfolgt stets durch [nx] und ggf. den genannten Offset.
        Solange also diese Abst€nde erhalten bleiben, kann der next-Einsprung
        an beliebiger Adresse stehen, d.h. f‡r Jobs z.B. auch umgesetzt werden.
        [bp] wird durch A6 repr€sentiert, [nx] durch A3 und [w] ist A2, der
        Datenstack [sp] ist A5, [ip] ist A4, und der Returnstack [rp] bleibt A7.
        Diese Register, bedingt auch [up] in D7, m‡ssen (normalerweise) unver-
        €ndert erhalten bleiben: Sie d‡rfen nur f‡r neue Tasks rsp. QDOS-Jobs
        neu besetzt werden. Mehr hierzu s. "f6asm_scr" und "f6task_scr".


 ENTFERNT

0drop   wurde mangels sinnvoller Anwendung gestrichen; je einmal in "fig_scr"
        und "forth_scr" aufgerufen, und gelegentlich n‡tzlich f‡r z.B.
                ernum 0drop IF message ENDIF
        Man kann es leicht ersetzen:
                -dup drop

 Da mit o.a. neuen Worten wieder einmal das Fassungsverm„gen des GST-Assemblers
 an Labels ‡berschritten wurde, muœten weitere weniger nutzbringende Worte aus
 dem Kern entfernt werden:

(-ffind) Der Wortheader dieses Vorgabeaufrufs f‡r {-find} wurde entfernt.
        Seine cfa kann, z.B. zur Restituierung von {-find}, ermittelt werden:
                ' -find 4+ ' -find !
(#boot) ist f‡r selbststartende Programme nicht mehr erforderlich.
(fop)   (D) ersatzlos entfernt.
0in!    kann ersetzt werden durch
                in off
local   als Variablentyp und
loc:    deren Fehlen kaum ein schmerzlicher Verlust sein wird, da die Pseudo-
        {local}-Variablen sich nicht als sonderlich wertvoll erwiesen haben,
        dies umsomehr, nachdem neben o.a. Stackoperator nun auch "echte" und
        g€nzlich problemlose Locale Variable zur Verf‡gung stehen.
local   auch das Vocabular wurde entfernt. Die vorrangige Suche nach einem
        Vocabular kann z.B. in {[find]} untergebracht werden.
2forth+ Gleichwertig ist
                ( d.memadr )   0 base+ d-   ( d.forthadr )
        oder, da headerlos vorhanden, notfalls nachzusetzen:
                create 2forth+ -2 allot ' 2base+ nfa even 2- @ ,
?found  ist in {if-found} und {if-nfound} enthalten. Diese reichen zusammen mit
        {+continue}, {ftest}, {-find} und {if-true} zum bedingten Compilieren
        oder f‡r sonstige Pr‡fungen vollkommen aus.
<i      muœ ggf. ersetzt werden durch
                l<i drop
        wie z.B. f‡r den Editor in "fig_scr" bei {JL}.
-drop   ersatzlos gestrichen
chk     Der zugrundeliegende Processorbefehl mag in speziellen F€llen ben„tigt
        werden, hat sich hier aber als v„llig nutzlos und ineffizient erwiesen.
t-regs  (h) Auf die Registerablage der QDOS-Trap-Redirection wird nur selten
        zuzugreifen sein. Der ptr kann hilfsweise gelesen werden:
                ' open nfa even 2- @
<move   Die Varianten sind
move>   ‡berfl‡ssig, und selbst
move    hat nur unwesentlich an Ausf‡hrungszeit eingespart.
cmove>  {cmove} arbeitet nicht-‡berschreibend, und {fill} dient dem Eintragen
        von Bitmustern. Die {cmove}-Varianten sind also ‡berfl‡ssig. {<cmove}
        wurde dennoch beibehalten, da es nun einmal im Standard existiert...
save    wegen {w-save} ‡berfl‡ssig.


 FEHLER korrigiert bei:

*/      (f) (f1 f2 f3 -- f4) f4:=f1*f2/f3
call    (q) (dA4..dD0 d.calladr -- dA4..dD0) Datenanordnung.
cmove   Transportrichtung bei 4th-Adressen ungleicher Vorzeichen.
(find)  (Sehr seltener Fehler im) Abbruchkriterium bei Vocabularende.
expect  und
query   bei Abbruch durch i/o-Fehler oder Erreichen der Eingabepuffergrenze
        trat ein Adressierungsfehler beim Restaurieren der i/o-Kanalnummern
        auf. Voller Eingabepuffer gilt nicht mehr als Fehler.


 SCREENFILE: U.a. mit einer Definition f‡r beliebig dimensionierbare Arrays.

 In "forth_scr" korrigiert rsp. neu:

heapmem ( dn -- ) ge€ndert
        erwartet als doppelte Integer die wirklich geforderte Bereichsgr„œe.
        Da der Speicher vom QDOS ohnehin nur in Achtergruppen zugeteilt wird,
        ist die Stufung nun 8, wonach maximal 512K reserviert werden k„nnen.

o-prt   enthielt das o.a. {0drop}, welches entsprechend ersetzt wurde.

turtle  bis zu 16 Kr„ten k„nnen auf eigenen Bahnen bewegt werden.
#turtle (turtle) (-- nn) cons, enth€lt die Kr„ten-Nummer
penup
pendown ‡berwachen beide (als einzige der turtle-Aufrufe) den Nummernbereich
        und justieren die Nummer ggf. auf einen Wert im Bereich 0 bis 15.
move    (turtle) (f1 --) hatte Fehler.
deg     (turtle) (f1 -- f2)
        neu: Umrechnung Bogenmaœ nach Grad.
rad     (turtle) (f1 -- f2)
        neu: Umrechnung Grad nach Bogenmaœ.

l-load  ohne Namen nach vollst€ndiger Aktivierung zeigt alle Kopfzeilen des
        library-file an, die eine mit l-load auffindbare Eintragung enthalten.
        Wird die Anzeige nicht mit ESC abgebrochen, muœ der {screen}-Kanal
        u.u. durch gesonderten Aufruf geschlossen werden.

stack:  define: STACK: {name} abc...|abc...
        use:    n1...nn {name} nx...ny
        Definitionswort f‡r Stackoperatoren nach dem Verfahren von {stak}.

array   define:             n.dims size ARRAY {name}
        initiate: dim.n ... dim.2 dim.1   DIM {name}
        use:      dim.1 dim.2 ... dim.n       {name} -- d.memaddr
        Allgemeine Definition f‡r im freien Ram angeordnete Datenfelder:
                        2 32768  array  Bilder
                    6 1          dim    Bilder          ( 12 * Bildschirminhalt
                        3     4  array  doubles
                99 99 1          dim    doubles         ( 20000 doppelte integer

        Mit {dim} wird im Rahmen der festgelegten Anzahl und der Postengr„œe
        jedes Array (neu) dimensioniert. War es bereits eingerichtet, werden
        seine Daten vorher aus dem Speicher entfernt. Der Speicherblock wird
        dem Array erst mit einem Aufruf des definierten {namen} zugewiesen.
        Als Schutzmaœnahme erh€lt ein noch un-{dim}ensioniertes Array beim
        Aufruf einen Speicherblock von 16 Bytes zuz‡glich dem Produkt aus
        Dimensionenanzahl und Postengr„œe, Indices =/= 0 werden abgewiesen.
        F‡r das Produkt aller Dimensionen gilt als Maximum 65535, das Format
        der einzelnen Posten ist auf 65536 Bytes begrenzt (in welch letzterem
        Fall der Wert 0 anzugeben ist) und das Produkt aus Postengr„œe und
        Dimensionen muœ kleiner als 512K Bytes sein.
        Die Dimensionsgr„œe z€hlt ab Null.
        Die Anzahl Dimensionen und die Postengr„œe z€hlen ab Eins.
a'      (I) use: A' {name}      ( -- array-pfa )
        liefert den Datenptr in eine Array-Definition oder bricht mit dem Text
        "?not an array" ab; compiliert ggf. den ptr als Literal.
-array  ( dn -- array-pfa | 0 )
        ermittelt den Datenptr der mit einer Speicheradresse korrespondierenden
        Array-Definition. Gibt es diese nicht, kommt Null zur‡ck.
dim     (I) use: ( dim.n ... dim.2 dim.1 )  DIM {name}  ( -- )
        dimensioniert ein Array und gibt zuvor ggf. einen schon bestehenden
        Speicherblock frei; in derselben Schreibweise auch compilierbar.
a'clr   (I) use: A'CLR {name}   ( -- )
        erwartet einen Array-Namen und l„st den zugeh„rigen Speicherblock auf;
        er wird mit dem n€chsten Aufruf von {name} leer wieder eingerichtet.
?arrays zeigt Namen und Dimensionierung aller Arrays an.

        Weitere Hinweise zu Definition und Anwendung in "forth_scr".


 * ++  1. 1.95 ++ v7.22 +++++++++++++

 SCREENFILE:
 U.a. mit TURTLE-Graphik im Stil des QL-Basic, und zwei Aufrufen zum Sichern und
 Laden assemblierter Bl„cke (auch f‡r einige Vorg€ngerversionen geeignet):

 Die turtle-Kommandos und -Variablen sind in "forth_scr" beschrieben:
penup pendown move moveto turn turnto arc-t x-cor y-cor angle pen

 Sichern und Laden compilierter 4th-Sequenzen:
c-save {file} {wort1} {wort2}
        Aufruf: C-SAVE {filename} anfang ende
        Sichert den compilierten Code ab {anfang} bis vor {ende}.
c-load {file}
        AUFRUF: C-LOAD {filename}
        L€dt den compilierten Code aus {filename}, f‡gt die gefundenen und im
        Bildschirm angezeigten Worte dem {current}-Vocabular hinzu.

                l-load c-load flp1_forth_scr
        spart Speicher und l€dt nur C-LOAD, beide Worte werden geladen mit:
                l-load c-save flp1_forth_scr

 Auœer der Zeitersparnis beim Compilieren scheint der Nutzen dieser Aufrufe zu-
 n€chst ausgesprochen begrenzt, ist doch normalerweise die einzige Folge der
 zus€tzliche Speicherbedarf hierf‡r (520 Bytes). Ganz anders sieht es aber aus,
 wenn ein Hilfsprogramm einen Code erzeugt, in den es selbst nicht eingebaut
 ist, und dieser Code dann mit C-SAVE zum Nachladen separiert werden kann. Das
 wichtigste Beispiel hierzu bildet der Assembler. Zu beachten ist:
        1. Das erste und das letzte Wort dieses Blocks m‡ssen zum selben Voca-
           bular geh„ren; ebenso das dem letzten zu sichernden folgende, da aus
           diesem das Ende des wirklichen letzten Wortes ermittelt wird. Dazu
           sind Kopf- und Schluœdresse erforderlich, die sp€teren {latest} und
           {here}, welche nur aus den Daten eines unmittelbar danach definierten
           Wortes zuverl€ssig und bei geringstem Platzbedarf zu gewinnen sind.
        2. Das Vocabular kann beliebig gew€hlt werden, es muœ zum Zeitpunkt des
           Sicherns rsp. Ladens lediglich zugleich auch {context} sein.
           Die Worte werden beim Laden dem {current}-Vocabular hinzugef‡gt.
           Das Vocabular muœ dabei nicht dasselbe sein, wie beim Sichern.
        3. Alle Worte, auf die bei der Ausf‡hrung zugegriffen wird, m‡ssen beim
           Laden an derselben Stelle stehen. Die Bl„cke k„nnen nur in ein System
           geholt werden, das ‡ber exakt dieselben dort aufgerufenen Ausgangs-
           definitionen verf‡gt, wie beim Sichern. Bl„cke, die jeweils einzeln
           zum Kern hinzucompiliert wurden, lassen sich in beliebiger Reihenfol-
           ge einf‡gen. Auch die F6-Version muœ dieselbe sein, da Unterschiede
           der Adressenlage im Kern von Version zu Version sehr wahrscheinlich
           sind. In der vorliegenden Form bricht {c-load} bei unterschiedlichen
           Versionsnummern mit der Fehlermeldung "? F6-Version" ab.
        4. Worte im Block, die in fremde Vocabulare hineincompiliert wurden,
           sind nach dem Laden von auœerhalb des Blocks nicht mehr aufrufbar,
           sie erscheinen nicht in den Wortlisten der betr. Vocabulare.
        5. Innerhalb des Blocks d‡rfen nur Worte aufgerufen werden, die schon
           vorher definiert wurden. Einzige Ausnahme sind Definitionen mittels
           im Block formulierter Definitionsworte, die einen {does>}-Teil ent-
           halten. C-LOAD ist dadurch im wesentlichen auf die Anwendung zusammen
           mit dem Assembler beschr€nkt. {interpret} verf‡gt jedoch ‡ber zwei
           vectorisierte (deferred) Aufrufe als Verankerung f‡r Erg€nzungen,
           sodaœ hier evtl. eine entsprechende Erweiterung m„glich ist (s.u.).
        6. Zur m„glichst vielseitigen Verwendung sind beide Worte "immediate".
           Sie lassen sich mit bereits vorgegebenen Namen compilieren, in Worte
           einbauen, die dann ihrerseits beim Aufruf die Namen erwarten, oder
           mit direkter Tastatureingabe aufrufen.
                : {name} ... [compile] c-save ..worte.. ;
           {name} empf€ngt dann die zugeh„rigen Namen aus dem Eingabestrom.
           Dagegen mit vorgegebenen Namen:
                : {name} ... c-save erstes letztes filename ..worte.. ;
        8. Der Header des erzeugten File darf auf keinen Fall ver€ndert werden:
           Wo bei Job-Files die Zahl f‡r den Datenbereich steht, sind die Adres-
           sen f‡r die Vocabularverkettung, danach ggf. die F6-Versionsnummer,
           eingetragen. Manipulation dieser Angaben macht das File unbrauchbar!
           Solch ein File wird mit der Typen-Kennung 3 markiert.

 Zu 5.: Dies ist die hi-level-Definition von {interpret} aus dem Kern, wo an
        entsprechender Stelle die Sonderbehandlung eingesetzt werden kann:
        : interpret
           BEGIN -find
            IF [interpret] state@ 0= IF db-on IF [debug] ENDIF ENDIF
             state@ uc< IF [cpl] cfa , ELSE cfa execute ENDIF
            ELSE here [convert] ENDIF
            ?stack
           AGAIN ;
        {[interpret]} z.B. k„nnte bei erneutem Compilieren des zu sichernden
        Teils die Referenzen auf intern aufgerufene Worte des Blocks einsammeln.
        {c-save} h€tte sie dann zus€tzlich zum Code mitzusichern, und {c-load}
        diese dann beim Laden auf die ge€nderte Adressenlage umzustellen. Was
        aber bei der Struktur des F6-Systems etliche Probleme aufwirft, weshalb
        eine solche M„glichkeit des Aufwandes wegen nicht vorgesehen wurde.

[interpret] (h)(D)(pfa countbyte -- pfa countbyte)
        Das Countbyte enth€lt auœerdem smudge- und precedence-Bit, letzteres
        ist die "immediate"-Makierung. Das h„chstwerige Bit ist immer gesetzt.
[cpl]       (h)(D)(pfa -- pfa)
        Beide m‡ssen die empfangenen Daten in gleichwertiger Form weitergeben.

 Ein Beispiel:
 Die Assemblerroutinen aus "f6task_scr" f‡r den F6-Tasker k„nnen mit {c-load}
 geladen werden, wodurch dann der Assembler nicht mehr vorhanden sein muœ:
        c-save flp1_tasker_4th tasker tcb
 sichert zun€chst aus einem regul€r compilierten F6-Job die betr. Aufrufe.
    e$='l-load l-load c-load c-load flp1_tasker_4th l-load tcb flp1_f6task_scr'
    EX flp1_qf;e$
 ruft nun ein neues F6-System auf und l€dt den gesamten Tasker ohne Assembler,
 wodurch an die 14K Bytes mehr an Platz f‡r andere Programmteile frei bleiben.


 * ++ 31.12.94 ++ v7.21 +++++++++++++

 nderungen:

l-load  Mit Hilfe der weiter unten angegebenen neuen Aufrufe zum Datentransport
        wird bei auch der Vorg€nger-Suchname im Returnstack gesichert, sodaœ
        er bei geschachtelten Aufrufen erhalten bleibt. Damit erh„ht sich der
        Platzbdarf mit jeder Schachtelungsstufe um die jeweilige Namensl€nge
        zuz‡glich 2 Bytes f‡r die L€ngenangabe, ggf. geradzahlig aufgerundet.
        Bei durchschnittlicher L€nge von 20 Bytes f‡r Filenamen und 10 Bytes
        f‡r Suchnamen sowie 10 Bytes Daten f‡r den Aufruf selbst bietet der
        Returnstack damit noch Platz f‡r 25 Schachtelungsstufen; bei Maximal-
        l€nge f‡r beide Namen bleiben es noch immer mindestens 12. Hinzuzurech-
        nen ist ggf. die Datenanzahl, die andere Ladeaufrufe zwischenspeichern:
        LOAD beansprucht 6 Bytes, S-LOAD 10 und Platz f‡r den Filenamen.

db-on   ist zun€chst wirkungslos. Da der Speicher f‡r rein produktive Zwecke
        ben„tigt wurde, sind die (ca. 200 Bytes umfassenden ) Debugger-Routi-
        nen nach "forth_scr" ausgelagert worden, von wo sie unter dem Namen
        {debugger} geladen und in den Interpreter eingebaut werden k„nnen.
        An der Debugging-Ausf‡hrung hat sich nichts ge€ndert, sie ist nun
        jedoch in weiten Grenzen auch vom Anwender modifizierbar.

(debug) (D)(h) (--)                     (neu)
        Zun€chst inaktiv definierte Runtime zum Debugging. Wird vor das aus-
        zuf‡hrende Wort compiliert und kann auch auf v„llig andere Aktionen
        vectorisiert werden, als das in "forth_scr" angegebene Debugging.
        Die 'deferred'-Definition wurde vor allem deshalb gew€hlt, weil sie ein
        zuverl€ssiges Hilfmittel zur Kontrolle des ‡bergebenen Aufrufs auf die
        m„gliche Ausf‡hrbarkeit ist, und auch Sicherheit gegen {forget} bietet,
        falls der eigentliche Aufruf damit gel„scht worden sein sollte.

[debug] (D)(h) (--)                     (neu)
        Anweisung zum Einbau der Debugging-Runtime. Wird vom Interpreter vor
        dem Compileraufruf ausgef‡hrt, wenn {db-on} und {state} nicht Null
        sind. Ist ebenfalls auf beliebige andere Aktionen vectorisierbar.

$8000   ist die erste (niedrigste) Forth-Adresse. Sie wird von der 'deferred'-
        Runtime und anderen Code-ausf‡hrenden Teilen abgewiesen. An dieser
        Stelle steht ein 'no op'-Sprung, sodaœ sie auch gegen versehentlichen
        Aufruf, z.B. nach Einbau durch den Compiler, abgesichert ist.

where   wurde zur Platzersparnis aus dem Standard-Aufbau f‡r den Editor her-
        ausgenommen. Es kann aus "forth_scr" nachgeladen werden. Ersatzweise:
                b/scr /mod . . .        <enter>
        womit unmittelbar nach Fehlerabbruch die {scr}-Nummer sowie Zeile und
        Spalte darin (alles ab 0 z€hlend) der Fehlerstelle ausgegeben werden.
                edif drop -print
        oder nach {l-load} und {s-load}
                (dir) -print
        gibt den zugeh„rigen Screenfile-Namen an.

safety  (r) wurde durch den Hilfs-Job zur Adressierungs‡berwachung entbehrlich,
        da dieser nun die gesamte (erg€nzend zur 'address error exception trap'
        des Processors) programmierte Kontrolle ‡bernimmt, und ist darum nicht
        mehr vorhanden.

basic   arbeitet unabh€ngig vom MEM-Device aus "dvs_byt". Es muœ daf‡r nicht
        mehr geladen werden. Dasselbe gilt f‡r die vordefinierten Worte, die
        im Basic resident definierte Aufrufe aktivieren:
                lngbad  cache-on  cache-off
        "dvs_byt" ist nur noch f‡r {>fount} erforderlich, und die vier Zeichen-
        s€tze, die sich damit den Fensterkan€len zuweisen lassen.

basic   (h)(ptr -- flg)
        Liefert nur einen Fehlercode, falls der betr. Name unbekannt ist. Wenn
        er eine parameterlos im (ersten) Basic aufrufbare residente Procedur
        bezeichnet, wird diese ausgef‡hrt, sonst bleibt {basic} ohne Aktion.
        Der Anwender muœ darauf achten, daœ die Aufrufe bei gesperrten Inter-
        rupts ausf‡hrbar sind, da programmierte Kontrolle nicht m„glich ist.
        flg:=0 wird angegeben, wenn der betr. Name existiert.
        Damit lassen sich, entsprechende Sachkenntnis vorausgesetzt, z.B. Vari-
        able aus dem Basic lesen und (in Grenzen) auch €ndern, was weitreichende
        Kommunikationsm„glichkeiten zwischen Basic und F6-Jobs sowie diesen un-
        tereinander er„ffnet. Mit den folgenden {qdos}-Worten sind dann die
        Daten (aus) der zugeh„rigen 'name table' lesbar:
d1l@    Aufrufadresse, Variablenptr oder Basic-Zeile.
        Z.B. den Inhalt einer im Basic definierten Variablen 'adr' gibt aus:
                forth hidden qdos also forth
                " adr" basic dup ?error d1l@ 2dup 2 m+ 2@l 2swap @l \.
        und ein neuer fp-Wert aus dem Stack wird an sie ‡bergeben:
                ( fp-zahl ) " adr" basic dup ?error d1l@ 2>rr !l 2r> 2 m+ 2!
a1w@    im niederwertigen Byte die Verwendungscodierung
a2w@    im h„herwertigen Byte die Typencodierng.
a1l@    Ptr zur 'name table', wo die beschreibenden Daten verzeichnet sind.
a2l@    disp vom Forth-Basisptr. zur Basic-Datenreferenz.
        Die wirkliche Referenzadresse erh€lt man dann mit { a2l@ 2base+ }.


 Optimierung:

 Compiler:
 Durch  nderungen bei {find} konnte die Compilezeit um ca 25% verringert werden.

 Programmausf‡hrung:

 Die Datenanordnung im Stack ist von entscheidender Bedeutung f‡r die Ausf‡h-
 rungszeit. Darum lohnt es sich immer, deren §bergabe besondere Sorgfalt zu
 widmen, ebenso, wie dann der Wahl der bestgeeigeten Stackoperatoren.
 Obwohl eine groœe Zahl Logik-Operatoren angegeben ist, sind diese nicht immer
 die beste Wahl, da ihre Realisierung zusammen mit der Flagerzeugung umst€nd-
 licher ausfallen muœte, als die zugrundeliegende elementare Rechenoperation.
 Der Datenvergleich mit {=} oder {=/=} ist solch ein Fall. Die Subtraktion ist
 stets schneller und kann, insbes. zusammen mit der optimierenden Funktion von
 {IF}, vorteilhaft stattdessen benutzt werden. Weil {IF} jeden Wert =/= 0 als
 'true'-Flag auswertet, gen‡gt das {-} immer dann, wenn ein {IF}-Teil bei Un-
 gleichheit durchlaufen werden soll. {0=} im Anschluœ wird von {IF} optimiert,
 sodaœ im F6 auch Gleichheit auf diese Weise erfaœt werden kann.

 Grunds€tzlich reichen {u<}, {0<} und {0=} zur Vergleichsauswertung aus; w€ren
 aber nur diese drei vorhanden, ginge das zulasten der Ausf‡hrungszeit. Doch es
 ist unn‡tz, f‡r jeden Einzelfall einen eigenen Operator vorzusehen. Da in sehr
 vielen F€llen ein bedingter Sprung folgt, bietet sich erg€nzend die Variation
 der Sprungbedingungen an, was im F6 mit den verschiedenen Sprung-Worten aus dem
 {hidden}-Vocabular verwirklicht wurde. Damit die Texte standardkonform hinge-
 schrieben und dennoch die zus€tzlichen bedingten Spr‡nge des F6 genutzt werden
 k„nnen, wurde die Optimierung von {IF} bei vorangestellten Flagoperatoren {0<},
 {0>} und {0=} eingef‡hrt. Die modifizierten Spr‡nge werden hiermit in derselben
 Zeit ausgef‡hrt und mit demselben Speicherbedarf compiliert, wie {IF} allein.
 Dasselbe gilt f‡r {UNTIL} und {WHILE}.

 {+IF} und {0IF} sind nun ‡berfl‡ssig und nicht mehr im Kern enthalten.
0IF wird getrennt als { 0= IF } hingeschrieben, und
+IF ersetzt man durch { 0< 0= IF }.

 Die Worte     compilieren kompakt als Sprung hinter ELSE (oder ENDIF)
 0= IF           -branch                  =/= Null
 0> IF           0-branch                 kleiner oder gleich Null
 0< 0= IF        0<branch                 kleiner Null
 0< IF           +branch                  gr„œer oder gleich Null
 0> 0= IF        0>branch                 gr„œer Null
    und entsprechend:
 {bedingung} UNTIL                               und
 {bedingung} WHILE ..            REPEAT          sowie
 {bedingung} WHILE .. {bedingung} UNTIL          als F6-spezifische Erg€nzung.

 Mitunter kann es erforderlich werden, die IF-Optimierung stillzulegen. Das
 betrifft z.B. unstrukturierte Einspr‡nge in den Code an Stellen innerhalb der
 normalerweise durch Optimierung zusammengefaœten Worte. F‡r ENDIF und CASE:,
 RANGE:, ASSOCIATIVE: werden entsprechende Vorkehrungen automatisch getroffen,
 die anderen Strukturworte compilieren eigene Codes und trennen sich dadurch
 selbst; "handgestrickte" Strukturen kann der Compiler aber nicht sch‡tzen.
 Daf‡r ist ein Wort vorhanden, das ggf. vor ein IF oder UNTIL zu schreiben ist,
 oder in eine Compiler-Anweisung einzubauen, wie z.B. bei ENTRY in "forth_scr":

if-off  (I)(--)
        Schaltet die Optimierung f‡r das n€chste IF, UNTIL oder WHILE ab.
          .. 0branch [ here 0 , ] BEGIN .. 0< [ rot >resolve ] if-off 0= IF ..
        In diesem Beispiel wird {0=} mit {IF} zusammengefaœt, das {0<} davor
        bleibt stehen. Ohne {if-off} w‡rde auch dieses Wort in den Code f‡r
        {IF} eingearbeitet und {0branch} direkt in den Code nach IF f‡hren.

 Neu:

 'Trickprogrammiererei' d‡rfte zumeist nur ein Symptom der Dummheit sein, und,
 wo eine Aufgabe sich angeblich strukturiert nicht l„sen l€œt, ist der Ansatz
 falsch, oder die Aufgabenstellung wurde nicht begriffene. Was nicht heiœen
 soll, daœ sie unbedingt und in sturem Purismus stets in strukturierter Form
 bew€ltigt werden muœ. Gerade z.B. das bedingte Verlassen eines Aufrufs, eine
 im Sinne strenger Strukturiertheit verwerfliche Tat, erlaubt es nicht nur,
 Proceduren ‡bersichtlich hinzuschreiben, sie werden automatisch dabei auch
 kurz und effizient programmiert. Drum:

-exit   (flg --)                entspricht: .. ( flg ) IF ;s ENDIF ..
        f‡r durch flg =/= 0 bedingten vorzeitigen Abbruch eines Wortes.
 IF .. ;S ENDIF ..   ;
        anstelle von
 IF .. ELSE .. ENDIF ;
        spart ebenfalls etwas Speicherplatz und Ausf‡hrungszeit. Wie auch bei
        {-exit} lohnt sich diese Abk‡rzung insbs. bei kurzen Aufrufen, oder
        wenn sich damit verwickelte Schachtelungen aufl„sen lassen.

#case   (-- nn) liefert den Index, mit dem das Wort, das {#case} enth€lt, in
        einer {case:}-Liste ermittelt und aufgerufen wurde, wenn es das erste
        Wort in dieser Definition ist. Ansonsten ist der Wert (nn) ungewiœ.

edif    (e) (-- ptr cn)
        liefert abh€ngig von {offset} Kanalnummer ( cn ) und 4th-Adresse ( ptr )
        des Namen zum gerade editierten File, rsp. die Daten zu {screen}, wenn
        kein File editiert wird und (offset) Null ist. {screen} und {(screen)}
        gelten auch nach Aufruf von {dr0}, {file} und {(file)} nach {dr1}.

dr?     ( -- f)
        liefert 0 wenn {offset} < 16384 ist (z.B. nach {dr0}), sonst 1

 Datentransport zwischen Speicher und Returnstack:
        Die geradzahlig aufgerundete Anzahl Bytes wird geholt, die genaue Anzahl
        abgelegt. Bei §berschreiten der Maximalzahl von 512 Bytes oder negativer
        Zahl brechen die Aufrufe ohne Aktion oder Fehlermeldung ab.

m>r     (ptr cn --)
        holt von 4th-Adresse ( ptr ) die Anzahl ( cn ) Bytes zum Returnstack.
r>m     (ptr cn --)
        legt die Anzahl ( cn ) Bytes vom Returnstack an 4th-Adresse ( ptr ) ab.


 * ++ 28.11.94 ++ v7.15 +++++++++++++

 Ab dieser Version ‡bernimmt ein Secund€r-Job die <break>-Abfrage, die nun vom
 Programmverlauf v„llig unabh€ngig und immer aktiv ist, selbst, wenn sich das
 Programm irgendwo in einer Endlos-Schleife aufh€lt, auf die normalerweise kein
 Zugriff mehr m„glich ist. Auœerdem lieœ sich ein Teil der zus€tzlichen Adressie-
 rungs-Sicherheit dorthin verlagern. Erfolg ist die um bis zu 45% gesteigerte
 Ausf‡hrungsgeschwindigkeit trotz gegen‡ber den Vorg€ngerversionen erheblich er-
 weiterter Absicherung und st€ndiger Abbruch-Abfrage. Die bisher sehr vorsichtig
 eingesch€tzte Geschwindigkeit liegt nun bei etwa dem Vierfachen des C1-Forth.
 So kann sich das F6 mittlerweile auch mit den schnelleren Systemen messen, ist
 dabei aber von ungleich h„herer Betriebssicherheit, vom entschieden gr„œeren
 Leistungsumfang ganz abgesehen.

 Alle F6-Jobs werden unabh€ngig voneinander ‡berwacht und der Abbruch ist mit
 jeweils frei w€hlbarer Testencodierung gesondert ausl„sbar.
 Weil die §berwachung durch einen Job stattfindet, zudem, um das Gesamtsystem
 m„glichst wenig zu belasten, mit geringster Priorit€t, kann es einen Moment
 dauern, bis die <break>-Anforderung erkannt und die Aktion ausgel„st wird.

 Erste Versuche in Gestalt Compilierens einiger gr„œerer Programme haben neben
 den Standardsystemen die Verwendbarkeit selbst mit den qxl-Produkten (Version
 2.16 und 2.31) best€tigt, doch ist dies mit endg‡ltiger Sicherheit noch nicht
 zugrundezulegen.

  nderungen:

 Die F6 Versionsnummer allein kann als ASCII-String gelesen werden
                2 code+ 2@l
 oder ausgegeben
                2 code+ 4 type-l

 Bislang namenlos und nicht programmiert nutzbar waren die user-Variablen, die
 das befristete Compilieren mittels {|} aus direkter Eingabe unterst‡tzen:

tail    (-- ptr)
                erh€lt durch den ersten {|} den Wert aus {last}, welches mit dem
                abschlieœenden {|} hieraus restauriert wird.
head    (-- ptr)        und     head 2-  (-- ptr) f‡r den Langwort-Wert
                erh€lt durch den ersten {|} den Wert aus {dp}, der abschlieœende
                {|} restauriert {dp} hieraus.

|       (--)    wurde bereits beschrieben, hier noch der Hinweis, daœ {state}
                dann der besondere Wert $ffc0 zugewiesen wird. Dadurch werden
                besondere Aktionen ausgel„st, die den Eingabe- vom regul€ren
                Compile-Zustand unterscheiden, und den gemischten Gebrauch mit
                den Compile- rsp. Interpret-Klammern, {]} und {[}, unterbinden.
                Genaueres ist dem Assemblertext zu entnehmen; die Versionen sind
                unver€ndert - abweichend wird {head} mit <uword> adressiert.

 Neue Worte sind:

btst    (dn1 n2 -- f)           tf wenn Bit n2 in dn1 gesetzt ist.
bset    (dn1 n2 --)             Bit n2 in dn1 setzen.
bclr    (dn1 n2 --)             Bit n2 in dn1 l„schen.

f>q     (fn1     -- qn2)        Flieœkommazahl in quad Integer umwandeln.

        F‡r quad Integer zur Datenablage/-Gewinnung:
4@      (ptr -- qn1)            vier Zellen von (auch ungerader) 4th-Adresse
4@l     (dadr -- qn1)           vier Zellen von wirklicher Adresse lesen
4!      (qn1 ptr --)            vier Zellen an (auch ungerade) 4th-Adresse
4!l     (qn1 dadr --)           vier Zellen an wirklicher Adresse ablegen

abort"  wurde ge€ndert. Dieses Wort steht nun auf derselben Reinitiierungsstufe
        wie {quit}, das von {(abort")} aufgerufen wird; im Gegensatz zu {abort},
        das den Datenstack erneuert und dann {(abort)} ausf‡hrt, vordefiniert
        mit weitgehender Reinitiierung des Systems.

,       as Compile-Komma kann auch an ungerader Adresse angesetzt werden.

perform (ptr -- (action)        79-Standard-Wort, f‡hrt aus: @ cfa execute
        zur Erleichterung bei der §bernahme anderer Programme eingerichtet.
        Kann zusammen mit einer einfachen Variablen auch die {deferred} Worte
        ersetzen, wenn deren ausf‡hrliche Sicherheitsmaœnahmen unn„tig sind.
        Die Ausf‡hrung ist dann u.U. wesentlich schneller.

 Runtime-Executives f‡r bedingte Spr‡nge:
0+branch (h)(flg --)    Sprung bei positivem Flagwert oder Null.
0>branch (h)(flg --)    Sprung bei Flagwert gr„œer Null.
0-branch (h)(flg --)    Sprung bei negativem Flagwert oder Null.


 ENTER BEGIN .. ENTRY .. { .. WHILE .. } .. 0= UNTIL  oder .. UNTIL
enter   und
entry   k„nnen von "forth_scr" dazugeladen werden. Sie bieten eine Alternative
        zur ‡blichen begin..while..until-Konstruktion, die mit einem gewissen
        Ausf‡hrungszeit-Gewinn verbunden ist, weil der immere bedingte Sprung
        entf€llt: Bei genauerem Hinsehen f€llt auf, daœ nur beim Einsprung in
        die standardm€œige Schleife der unbedingte Teil zuerst ausgef‡hrt werden
        muœ, und daœ danach eine Struktur durchlaufen wird, die der Schleife
        BEGIN .. 0= UNTIL entspricht. Genau dies erm„glicht die Kombination von
        ENTER BEGIN und ENTRY:
                BEGIN ..unbedingt.. WHILE ..bedingt.. REPEAT
        wird bei identischer Programmausf‡hrung ersetzt durch
                ENTER BEGIN ..bedingt.. ENTRY ..unbedingt.. 0= UNTIL

?1branch (h)(n1 n2 -- | n1)
        Runtime-Wort f‡r eine weitere IF-Variante:
case?   (n1 n2 -- | n1)
        Zus€tzlich zu den Listen-Konstrukten {case:} etc. ein Hilfsmittel f‡r
        einfache Fallunterscheidungen, das nach Art der {if}-Varianten anzu-
        wenden ist: {case?} compiliert den Vergleich zweier Zahlen miteinander,
        der bei Gleichheit beide vom Stack nimmt und in die unmittelbar folgen-
        den Worte bis zum n€chsten ELSE oder ENDIF f‡hrt. Bei fehlgeschlagenem
        Vergleich bleibt die (als erste ‡bergebene) Vergeichszahl im Stack und
        nach einem ELSE oder ENDIF k„nnen weitere {case?}-s folgen. Jedes ein-
        zelne {case?} muœ mit einem ENDIF abgeschlossen werden; Schachtelung
        und ELSE-Teile sind in derselben Weise zul€ssig, wie bei {if}. F‡r den
        Fall, daœ kein Vergleich Erfolg hatte, kann in einer geschachtelten
        Folge dem letzten ELSE noch eine abschlieœende Aktion folgen. Auf jeden
        Fall ist am Schluœ die verbliebene Vergleichszahl vom Stack zu nehmen:
                n1  n2.erste.auswahl  CASE? ..1st-case.. ELSE ..
                    n2.zweite.auswahl CASE? ..2nd-case.. ELSE ..
                                ...
                    n2.letzte.auswahl CASE? ..nth-case.. ELSE ..
                    ausfallaktion drop ENDIF .. ENDIF .. ENDIF


l-load  aus "forth_scr" wird in seinen Suchfunktionen mit Hilfe dreier Text-
        variabler (variable Byte-Datenfelder) gesteuert:
(boot)  liefert bei fehlender oder unbrauchbarer Angabe f‡r den Filenamen den
        Text f‡r einen erneuten Leseversuch. Danach bricht der Aufruf ggf. ab.
(dir)   erh€lt den erfolgreich zum ¤ffnen benutzten Filenamen zugewiesen.
l-word  nimmt den jeweils j‡ngsten Suchnamen auf.

-lword  {name}
        liefert tf, wenn der angegebene gleich dem j‡ngsten Suchnamen ist.


 Da der GST-Assembler mit dem F6-Quelltext an der Grenze seiner Kapzit€t ange-
 langt ist und aufgrund zuvieler Labels Fehler produziert, wurden zugunsten der
 o.a. nicht so einfach als Hi-Level-Worte nachsetzbaren Definitionen folgende
 Namen aus dem {hidden}-Vocabular gestrichen, die nur runtimes bezeichnen und
 auœer der Namensausgabe beim debugging keine weitere Verwendung haben:
        (save)  (d.r)   (is)
        (cfa@)  (cfa,)  (csel)  (case)
        (asv@)  (asv,)  (asvl)  (asvr)  (range)
 sowie die inzwischen ‡berfl‡ssigen
        is-in   is-out  is-work is-io   is-screen is-file  move>  <move
 und das in sp€teren Standards enthaltene Wort
        exit
 welches zur Ausf‡hrung ohne Laufzeitverlust nachgetragen werden kann
        : exit compile ;s ;   immediate
 und nur ein geschw€tziger Ersatz f‡r das direkt hingeschriebene {;s} ist.

 Sowie die (nicht standardm€œigen) Forth-Worte
        #chan   report  in><out  0if  +if  move
 die vor allem des relativ seltenen Gebrauchs wegen aus dem Kern nach "forth_scr"
 ausgelagert wurden. Und schlieœlich das f.i.g.-Editor-Wort {-text}, das mit iden-
 tischer Aktion als Forth-Wort {w=} vorhanden ist. Wird es f‡r fremde Quelltexte
 ben„tigt, l€œt es sich mit gleicher Ausf‡hrungsgeschwindigkeit leicht nachsetzen:
        editor definitions forth
        create -text -2 allot ' w= 2- count-w , 2@ , , smudge

 Die Alternative der Aufteilung in mehrere Teiltexte, der reine Codeteil am
 Anfang b„te sich daf‡r an, wurde wegen der vielen ‡bergreifenden Labels und
 der l€stigen Procedur zum Erzeugen des vollst€ndigen Programms verworfen.


 * ++ 18.11.94 ++ v7.14 +++++++++++++

 Auœer der Reihe hier ein ganz simpler kleiner De-Compiler:
        : nxid. count-w dup $. 2+ nfa id. space ;
        : see [compile] ' BEGIN nxid. key 27 = UNTIL drop ;
 der aufgerufen wird
        see {wortname}
 und mit jeder Tastenbet€tigung einen Wortnamen der untersuchten Definition
 hinschreibt, und den eigentlichen Inhalt der gelesenen Zelle. Verlassen wird
 das Wort nur durch die Escape-Taste.
 Dabei gibt es allerdings noch keine Erkennung der besonderen 4th-Worte wie
 {literal}, wo z.B. die folgende Zelle einen Zahlenwert enth€lt, nicht eine
 cfa; oder {branch}, wo die folgende Zelle die relative Sprungdistanz angibt.
 Entsprechende Erweiterungen sind leicht m„glich, bleiben aber dem Anwender
 ‡berlassen.

 Die in dem nicht ‡ber 4th-Adressen erreichbaren Teil liegenden Primitive-
 Aufrufe umfassen mittlerweile gut 8K, wodurch trotz zahlreicher Erg€nzungen
 der f‡r Programme und Daten nutzbare Bereich auf rund 45K angewachsen ist.
 Am Rande hat sich dadurch auch eine Steigerung der Ausf‡hrungsgeschwindigkeit
 ergeben, die abh€ngig vom Systemzustand bis zu 45% betr€gt. Nur in extrem un-
 g‡nstigen F€llem und bei zugleich aktiver Abbruchtasten-Abfrage f€llt sie
 in etwa auf das bei Qliberator-Programmen Erreichbare ab. Das Compilieren geht
 sehr viel schneller vonstatten, als das Laden gleichwertiger Basic-Programme.

 Neben geringf‡gigen Anpassungen an die Weichware zur QXL-Karte gibt es ein
 paar weitere  nderungen/Erg€nzungen:

message { 16 message } gibt einen Text mit der F6-Version aus.

break   ist eine Variable, an die der Code einer Taste ‡bergeben werden kann,
        bei deren Bet€tigung ein evtl. gerade in Ausf‡hrung begriffenes Wort
        abgebrochen wird. Zusammen mit ALT wird der Warmstart ausgl„st, sonst
        §bergang nach {quit}. Das System f‡hrt die Abfrage immer nach der R‡ck-
        kehr aus einem 4th-Wort durch. Endlosschleifen, die in reinen Codeteilen
        entstanden sind, k„nnen darum also nicht unterbrochen werden.
        Soll die {break}-Abfrage stillgelegt werden, ‡bergibt man den Wert -1
        an die Variable. Zur Unterst‡tzung ist eine Constante definiert:
never   (-- wf)
        wf, im F6-Slang als "wrong flag" bezeichnet, hat den Wert -1.
                break never
        legt z.B. die {break}-Abfrage still - und beschleunigt den Programm-
        ablauf erheblich. Vorgabe ist die Taste  CTR/a, einstellbar mit
                break on

safety  ist eine weitere Variable zum Programmablauf. Ist sie positiv und nicht
        Null, so werden nach jeden 4th-Wort die Register des virtuellen 4th-
        Processors auf Geradzahligkeit gepr‡ft und ggf. der Warmstart ausgel„st.
        Ein hierdurch abgefangener Fehler ist daran Erkennbar, daœ das System
        nur die Fehlermeldung gibt, nicht aber die Registerwerte anzeigt, wie
        das beim Abbruch durch die Exception-Trap des Processors geschieht.

        Diese Kontrolle kostet etwa 1/8 der Zeit der {break}-Abfrage. Sie wurde
        vor allem f‡r die qxl-Systeme eingerichtet, da der Processor dort nur
        beim Sprung auf eine ungerade Code-Adresse die entsprechende Trap aus-
        l„st, und so nicht mehr alle im F6 als solche geltenden Adressierungs-
        fehler erkannt werden. In den Standard-QL-Systemen ist diese zus€tzliche
        Sicherung von untergeordnetem Nutzen, sodaœ es sich dort empfiehlt, sie
        stillzulegen:
                safety off
        wonach die {break}-Abfrage noch einstellbar bleibt, oder
                safety never
        welches auch die {break}-Abfrage stillegt, unabh€ngig von der Codierung
        in {break}. Der Zustand {off} ist Vorgabe beim Programmstart.
        Der Unterschied in der Ausf‡hrungszeit liegt im Extremfall (alles frei-
        gegeben und aktiv oder alles gesperrt) bei 1:9 (!).

t-regs  (-- disp)  (im hidden-Vocabular)
        ist eine Constante, die auf die Adresse weist, an der der Inhalt der
        Processorregister abgelegt wird, wenn ein Adressierungsfehler erkannt
        wurde. Der Ablagebereich liegt auœerhalb der 4th-Adressen und kann
        mit seiner wirklichen Speicheradresse z.B. ermittelt werden:
                t-regs code+
        {ldump} aus "forth_scr" ist dann eine M„glichkeit, die Daten anzuzeigen.

empty   l„scht alle Worte, die nach der in {fence} stehenden Adresse
        compiliert wurden (danach ist nun auch der Aufruf von {cold} sicher).

forget  Ausf‡hrung allgemein sicherer und im Zusammenhang mit {safe!} treten
        die Fehler von {cold} nicht mehr auf (Verlust des Dictionary).

safe!   sichert den aktuellen Wortschatz gegen {forget} und bereitet das System
        f‡r die Aufrufe {empty} und {cold} mit den entsprechenden Grenzen vor.
        Um die durch das f.i.g.-Modell bedingte Unsicherheit des {cold}-Aufrufs
        in F€llen unvollst€ndig vorbereiteter Systemdaten zu vermeiden, insbes.
        nach Umstellung des mittels {fence} gesch‡tzten Bereichs, ruft man auf:
                ' {wort} lfa fence ! empty
        oder unmittelbar nach Compilieren des letzten zu sch‡tzenden Wortes nur
                safe!

!a @a   Daten an gerade Adresse ablegen/Lesen von gerader Adresse
2!a 2@a dasselbe f‡r doppelte Posten (32-Bit, Langworte)
+!a     Addition in den Speicher (auch f‡r f.p.-Zahlen)
        Die Aufrufe sind immer dann vorteilhaft, wenn die jeweilige Adresse
        mit Sicherheit nicht ungerade sein kann, und auch Fehler bei der
        Tastatureingabe diesbez‡glich auszuschlieœen sind. Z.B.
                #36 base !a
        oder
                out @a
        Da hier der Datentransport in Wort- rsp. Langwortposten erfolgt, ergibt
        sich ein Laufzeitvorteil von ca. 20% (bis 60%) gegen‡ber den byteweise
        organisierten Standard-Aufrufen des Systems.

.(r)    (n1 n2 -- n1)
        Hiermit kann auch Text formatiert ausgegeben werden (s. "forth_txt").
        n1 ist Z€hler z.B. einer Stringausgabe, die rechtsb‡ndig ins Bild (oder
        zu Papier) gebracht werden soll, und n2 die verf‡gbare Feldbreite. Dann
        f‡llt der Aufruf eine Zeile von links an mit den in (r) als ASCII-Code
        angegebenen Zeichen, die z.B. auch f‡r {.r} benutzt werden, so auf, daœ
        ein String der L€nge n1 rechtsb‡ndig in das Feld der Breite n2 gesetzt
        wird:
           | cr date$ 30 .(r) type cr \1000,01 f>$ 27 .(r) type space ." DM" |
        schreibt am 1.12.1994 abends um Acht Uhr:
                  1994 Dec 01 20:00:00
                            1000.01 DM

a>h     (c1 -- c2) Umwandlung ASCII-Zeichen nach sedecimaler Ziffer.
h>a     (c1 -- c2) Umwandlung sedecimaler Ziffer anch ASCII-Zeichen.

skip    (ptr1 n1 c1 -- ptr2 n2)
        liefert ptr2 auf den n2 Zeichen langen String, der ab der ersten im
        Code von c1 abweichenden Position verbleibt. Bis dahin im String ent-
        haltene (Steuer-)Codes < 32 werden ‡bersprungen.

scan    (ptr1 n1 c1 -- ptr2 n2)
        liefert ptr2 auf den n2 Zeichen langen String ab der ersten Position,
        an der der Zeichencode c1 gefunden wurde.

 * Vierfachgenaue Integer-Arithmetik:
        Eine Gruppe Operatoren f‡r vorzeichenbehaftete 64-Bit-Zahlen, hier mit
        "quad" abgek‡rzt, ist hinzugekommen (doppeltgenaue mit "double"). Dies
        erm„glicht schnelle Rechenoperationen im Bereich ca +/- 10^18.

q+      (qn1 qn2 -- qn3)        Addition
q-      (qn1 qn2 -- qn3)        Subtraktion
qminus  (qn1     -- qn2)        Negation
qabs    (qn1     -- +qn2)       positiver Betrag einer quad Integer
qm+     (qn1 n2  -- qn3)        vorzeichen-richtige Addition
                                einer einfachen zu einer quad Integer.
q+-     (qn1 n2 -- qn3)         qn3:=qn1*sgn(n2) : Vorzeichen einer einfachen
                                auf die darunterliegende quad Integer anwenden.
qm/mod  (qn1 dn2 -- qrm dqt)    Division quad durch double mit quad Rest
                                und double Quotienten.
uq/mod  (+qn1 dn2 -- drm dqt)   quad durch double nach double Rest und Quotient.

q>f     (qn1     -- fn2)        quad Integer in Flieœkomma-Zahl umwandeln.
d>q     (dn1     -- qn2)        double vorzeichenerweitert in quad umwandeln.

        Mit vierfachgenauem Zwischenergebnis rechnet der Scalierungsoperator
udm/mod (dn1 dn2 dn3 -- drm dqt) Multiplikation dn1 mit dn2 und Division des
                                quad Produkts durch dn2 nach double Rest & Quot.

        Ein "Abfallprodukt" der quad-Division ist
d/      (dn1 dn2 -- dqt)        Division zweier doubles mit double Quotient

        Zur Ausgabe der quad-Zahlen k„nnen die notwendigen Operatoren aus
        "forth_scr" dazugeladen werden:
 <q# q# q#s q#> q. uq.           entsprechend den Standardoperationen.
 uq# q#                          stellen einen zu {type} passenden String bereit.

 Die zugeh„rigen Speicheroperationen lassen sich z.B. mit den doppeltgenauen
 Operatoren definieren:
        : 4@l  2dup 4 m+ 2@l 2swap 2@l ;        : 4!l  2>rr 2!l 2r> 4 m+ 2!l ;
        : 4@   2base+ 4@l ;                     : 4!   2base+ 4!l ;


        F‡r die Adressierbarkeit aus mit dem f6-Tasker gebildeten 4th-tasks,
        die einzelne 4th-Worte unabh€ngig als QDOS-Jobs ausf‡hren, wurden
        einige Systemadressen auf 32-Bit-Format umgestellt:
u0
s0
r0
dp
hld
        lassen sich mit Abstand -2 als doppeltgenaue Werte lesen:
                dp 2- 2@
pad
hold
<#
#
#>
        arbeiten intern mit doppeltgenauen Adressen


[dojump] (a) ist die cfa f‡r auœerhalb des 4th-Adressenbereichs liegende
        primitives. Damit kann f‡r Synonym-Definitionen kontrolliert werden,
        ob der direkte Sprung in eine ausf‡hrbare Routine m„glich ist. Die
        Codeadresse eines lang adressierten Primitive-Aufrufs erh€lt man mit
                ' {name} 2@ 2base+
        Die unten angegebene Sequenz hinterl€œt tf (1), wenn das untersuchte
        Wort eine solche Definition ist. Dann enth€lt die auf die cfa folgende
        doppelte Speicherzelle die zur 4th-Basisadresse relative Adresse
        der betr. Routine und kann zur Bildung eines Synonyms ohne Verlust
        an Ausf‡hrungszeit benutzt werden.
        Dazu ist aber u.U. immernoch genaue Kenntnis des Worttyps erforderlich.
        Denn nur, falls der Vergleich mit [dojump] oder des cfa-Inhalts mit der
        pfa desselben Wortes Gleichheit ergibt, ist das untersuchte Wort mit
        Sicherheit eine primitive-Definition.

            : alias:            ( use: ALIAS: {neuername} {altername}
              ?exec             ( Abbruch, wenn im Compile-Betrieb aufgerufen
              create            ( wortheader anlegen
              -2 allot          ( primitive standard-cfa entfernen
              [compile] '       ( pfa des zu ersetzenden wortes holen
              dup cfa @ also assembler [dojump] = ( cfa-typenvergleich
              IF [dojump] ,  previous 2@ ,        ( worttyp und langen sprung
              ELSE              ( NUR wenn der Worttyp bekannt ist, oder
               dup              ( zus€tzliche Pr‡fung vorbereiten
               cfa @            ( sprung auf standard primitive
               dup rot - 3 ?error ( unbekannten Worttypen abfangen
              ENDIF ,           ( compilieren
              smudge ;          ( und aufrufbar machen.

        Damit definiert man z.B.:
              also forth definitions fp also
              alias: fswap swap
              previous previous
        und kann nun mit {fswap} im forth-vocabular auf das fp-wort swap
        zugreifen, welches zwei dreiergruppen datenposten im stack vertauscht.

error
warm
cold
        kehren auch aus Aufrufen richtig zur‡ck, bei denen der Fehler im
        supervisor-Mode des Processors ausgel„st wurde.

fopen   Um Konflikte mit dem Pointer-IF zu vermeiden, rufen alle Worte dieser
        Gruppe bei erfolgreich ge„ffnetem Kanal auch noch { 0 paper } auf.
        Ein dabei evtl. erzeugter Fehler €ndert den R‡ckgabecode nicht, bei
        Filekan€len wird aber {ernum} nicht mehr null sein. Zuverl€ssige Aus-
        wertung erlaubt also nur der vom Aufruf zum Stack gelieferte Code.

fop-over l„scht zuerst eine ggf. existierende Datei des angegebenen Namens
        und legt sie dann neu an. Dadurch wird der Aufruf von Minerva oder
        TK2 unabh€ngig, auch scheint die Anordung der Dateien auf Disketten
        damit g‡nstiger und weniger fehleranf€llig verwaltet zu werden.

 In "forth_scr" sind einige Definitionen hinzugekommen, insbesondere eine
 vollst€ndige Gruppe von Worten zum (Simultan-)Drucken der Eingabe und von
 beliebigen anderen Texten. Diese wird z.B. geladen mit
                L-LOAD printer flp2_forth_scr

l-load
s-load
        wurden so modifiziert, daœ sie auch ohne Dateiangabe arbeiten. Es
        gilt dann die j‡ngste Datei, die bei einem Aufruf von s-load oder
        l-load benutzt wurde. Damit lassen sich nun Quelltexte zusammen-
        stellen, die unabh€ngig vom jeweiligen Laufwerk/Ger€t arbeiten.

        Der Filename wird mit (boot) adressiert und kann ge€ndert werden:
                (boot) fname" n1_flp2_forth_scr"
        Sind also s-load oder l-load einmal aufgerufen worden, und ist die
        4th-Datei dieselbe, so gen‡gt f‡r o.a. Beispiel dann:
                L-LOAD printer
        oder etwa einen dem JOBS des TK2 €hnlichen (erweiterten) Aufruf:
                L-LOAD .jobs

        Dadurch, daœ jeder nicht als zug€ngliches File erkannte Name nun als
        4th-Wort behandelt wird, brechen L-/S-LOAD ab, wenn es solch ein Wort
        (noch) nicht gibt. Definiert man aber den Filenamen selbst als 4th-Wort,
        so kann er dann aktiv werden, und alle m„glichen Aktionen einleiten,
        die in diesen Falle sinnvoll sein m„gen; im einfachsten Falle z.B die
        Suche nach einem alternativen screenfile:
                : flp1_probe_scr
                  [compile] \
                  [ latest ] literal cr id. ."  nicht gefunden" cr
                  [ latest pfa ] literal w-forget ;
                1 s-load flp1_probe_scr       .( Probe geladen ) ;s

                : flp2_alternative_scr
                  bell screen close
                  cr (screen) -print ."  => "
                  [ latest ] literal id. ."  War nix! "
                  [ latest pfa ] literal w-forget
                  quit ;
                1 s-load flp2_alternative_scr .(  Alternative geladen )
                                ;s
        Wonach nur, wenn eines der Files gefunden wurde, das betr. Wort noch
        weiterbesteht, alle evtl. Vorg€nger l„schen sich selbst€tig aus dem
        Dictionary, sobald sie ihre "Notfall-Aktion" erledigt haben.

c-load  (n.i.)
        zum Einbau fertig compilierter Segmente ist in Vorbereitung, weshalb
        gebeten wird, diesen Namen nicht f‡r Anwenderdefinitionen zu werwenden.

words   wurde um eine Anzahl Auswahlm„glichkeiten erweitert. Damit lassen sich
        nun bestimmte Wort- oder Definitionstypen oder alphabetisch ausgew€hlte
        Listen zusammenstellen. Neben dem Folgenden mehr dazu in "forth_txt":
selected
        kann vor {words} aufgerufen werden, um die Ausgabe auf bestimmte Gruppen
        zu beschr€nken. Es beeinfluœt {words} nur f‡r diesen einen Aufruf.
        Grunds€tzlich gelten die nach {selected} folgenden max. 7 Zeichen bis
        zum n€chsten Leerzeichen als alphabetisches Auswahlkriterium f‡r den
        Wortanfang der Ausgabe. Daneben gibt es Sondergruppen mit:
                selected imed           f‡r die "immediate"-Worte;
                selected prim           die Standard- und die mit Langwort-Ptr
                                        aufgerufenen Primitives;
                selected defn {name}    faœt die Worte zusammen, deren pfa den-
                                        selben Inhalt wie {name} hat, z.B. also
                                        die Worte aus demselben Definitionswort;
                selected wtyp {name}    die Worte vom selben Typen wie {name}.


 Speziell f‡r den Betrieb im System der QXL-Karte:

sysflg  (-- dn) hat bei qxl-Systemen in den h„herwertigen 16-Bit die Zahl -2.

cache   (-- f)
        gibt 1 zur‡ck bei aktiver Cache, sonst 0, auch in Standard-QLs.
cache-on  (-- ernum)
cache-off (-- ernum)
        entsprechend den Basic-Aufrufen zum Ein- oder Ausschalten der
        Cache-Speicherung - wirkungslos in Standard-QL-Systemen, oder
        wenn das MEM-Device aus IO2 rsp. "dvs_byt" fehlt. In diesen
        F€llen geht in ernum der entsprechende QDOS-Fehlercode zur‡ck.
-cache    (f -- ernum)
        stellt den Zustend entsprechend der z.B. aus {cache} erhaltenen
        Flag ein. Dabei gilt jeder Wert =/= 0 als tf zum Einschalten.

forget  und sein Varianten schalten ggf. vor‡bergehend die Caches ab. Da hier
        deren einziger kritischer Punkt liegt, kann das F6-System ohne beson-
        dere Maœnahmen mit aktiven Caches betrieben werden.


 * ++  8. 8.94 ++ v6.14 +++++++++++++

 Ein paar Fehler wurden korrigiert:
s#      empf€ngt auch negative Zahlen,
        f‡hrende Leerzeichen k„nnen die Zahlen nicht mehr verf€lschen.
s@      schlieœt den Text in {pad} mit dem Begrenzungszeichen ab.
\.      und {.} im fp-Vocabular sind gegen unbrauchbare Daten abgesichert durch
        L„schen der oberen 4 Bits des Exponenten, wo der qdos-Vector sonst in
        eine Endlos-Schleife geraten kann. {fp-err} wird dann -17.


 * ++ 15. 1.93 ++ v6.12 +++++++++++++

w-forget und forget
        gehen durch ALLE Vocabulare unabh€ngig von der aktuellen Suchfolge.
-forget ber‡cksichtigt allein das context-Vocabular.

trap1a  (da1 dd3 dd2 dd1 op -- dd1)
        Im qdos-Vocabular; Trap#1-Aufruf mit §bergabe auch von A1.

vlist   Ausgabe nach {out-cons}; h€lt an, wenn eine Tate bet€tigt wurde, nach
        erneutem Tastendruck wird die Ausgabe fortgesetzt. Abbruch mit <esc>.
words   (S) gibt die Wortliste alphabetisch sortiert aus.
        Die Ordnung kann mit {(upper)} so modifiziert werden, daœ sie nur nach
        der L€nge erfolgt (0), nach L€nge getrennt f‡r Groœ- und Kleinschrei-
        bung (32), strikt alphabetisch und zweitrangig nach der L€nge (-33),
        schlieœlich alphabetisch mit L€nge, getrennt nach Schreibweise (-1).

.s      Ausgabe geht nach {in-cons}

[number] ( ptr -- nn|dn|fn tf | ff )
        Hilfsaufruf f‡r den headerlosen Standardaufruf in {number}. Bricht bei
        Fehlern nicht mit abort ab, sondern liefert Flag 0, rsp. die Zahl mit 1.
        - {number} darf nur mit {default-is} restauriert werden -

        S€mtliche Primitive-Routinen liegen nun, soweit sinnvoll, auœerhalb des
        4th-Adressenbereichs. Damit sind dort weitere ca. 2K freigeworden.
        Vom Kern liegen jetzt ca. 17K im 4th-Adressenbereich und 7K 'darunter'.

 $8000   ist die NIEDRIGSTE Forth-Adresse, $7fff die h„chste.
 $8000 @ liefert den Abstand von der Job-Basis zur niedrigsten Forth-Adresse,
 $8000 base+ $8000 @ s->d d-
         liefert die wirkliche Speicheradresse der Job-Basis.
 $8000 base+ $8000 @ 0 d- 2 m+ @l $8000 @ = .
        als Kontrolle muœ 1 ausgeben.

 * ++ 26.12.93 ++ v6.08 +++++++++++++

 Gegen‡ber der Vorg€ngerversion unterscheidet diese sich darin, daœ einige Code-
 teile nach auœerhalb der 4th-Adressen verlegt wurden. Damit wurde der nutzbare
 Bereich des 4th-Dictionary um ca. 5K gr„œer. Ein 4th-Wort muœte ge€ndert werden:

disp+   ( nn -- dn )
        Der Aufruf zum Umrechnen eines Forth-Pointers in den wirklichen Abstand
        zur Job-Basis liefert nun eine doppelt genaue Zahl, denn, da er 64K
        ‡berschreiten kann, w€re er mit 16 Bit ggf. nicht mehr darstellbar.

 Als Effekt nebenbei hat sich gezeigt, daœ das System nun auch mit dem Kommando
        EXEP
 aus der Hotkey-Erweiterung aufgerufen werden kann. Ausf‡hrlich wurde das nicht
 untersucht, jedoch verliefen Aufrufe mit Angabe eines neuen Jobnamen fehlerlos:
        EXEP'flp2_f6ed','editor'
 erzeugt den F6-Job aus dem File flp2_f6ed und gibt ihm den Namen 'editor'.

 Da aber der Codebereich des Jobs selber erweiterbar ist, und dort auch Variable
 angelegt werden, sind Kommandos wie HOT_CHP und HOT_RES ohne besondere Maœnahmen
 ungegeignet. HOT_LOAD ist brauchbar.
 Mehrfachnutzung des F6-Kerns ist durch die 16-Bit-Forth-Struktur nicht m„glich.
 Die Hotkey-Aufrufe sind nur von begrenztem Nutzen:
 F‡r eine Job-Copie im aktuellen Zustand ist {clone-4th} besser geeignet, und
 den nicht erweiterten Job startet man mit EX o.dgl.

 Die Speichereinteilung ist:

 -----------------------
 vom forth aus adressierbarer bereich
 4th-obergrenze  -------    obergrenze kanal-id-tabelle
                        16 langwort-tabellenpl€tze
           limit                obergrenze blockpuffer, anfang kanal-id-tabelle
                        16 bl„cke zu 2+64+2 bytes
           first                anfang des blockpuffers
                        256 bytes 'user-area'
           (u0)¾ und (r0)¿
                        1088 bytes returnstack. 'abw€rts' bauend,
                         170 bytes 'aufw€rts' f‡r den terminal input buffer
           (s0)¿ und (tib)¾
           .............
                        freier dictionarybereich und datenstack
                        im F6-Kern stehen hier ca 43K bytes zur verf‡gung
           .............
           pad          hilfsadresse f‡r einen zwischenpuffer 80 bytes ‡ber here
           here         erste freie stelle im dictionary
           .............
                        von forth-definitionen besetzter bereich
                        der kern beansprucht hier ca. 19K bytes
           .............
 4th-untergrenze ------- ab hier 'aufw€rts' 64K 4th-adressenbereich
           .............
            codebereich ca 5K f‡r processorcode-routinen benutzt, die aus dem
                        system direkt angesprungen werden, standardm€œig von
                        neu compilierten forth-worten nicht adressierbar.
           .............
 jobanfang - qdos-header mit sprung in das 4th-system
 -----------------------

 * ++ 26.12.93 ++ v6.07 +++++++++++++

 Ein paar Worte sind, u.a. angeregt durch f83 und das aktuelle ans-4th-Dokument,
 entstanden:

source  ( -- ptr nn )   wird z.B. von {word} ausgef‡hrt,
                        gibt Adresse und Puffergr„œe f‡r die aktuelle Eingabe an
blk+    ( -- f )        wird von <nul> am Zeilenende ausgef‡hrt,
                        mit f= -1:tib 0:neues screenfile +ve:n€chste blocknummer
#tib    ( -- nn )       Anzahl der gerade aufgenommenen Eingabezeichen ein-
                        schlieœlich ggf. eines abschlieœenden <cr>.
baud    ( -- nn )       Constante f‡r die aktuelle Baudrate (Vorgabe ist 19200).

 Bei den fp-Worten {lit}, {literal} und {@} wurde die Exponenten-Absicherung
 entfernt, sodaœ diese auch auf beliebige Datengruppierungen zu drei Zellen
 anwendbar sind. Zum Ausgleich wird diese Kontrolle nun bei {constant}, und
 unver€ndert bei {$>f}, durchgef‡hrt - sie begrenzt den Exponenten auf 12 Bits.

dpl     wird durch die fp-Worte {$>f}, {2*}, {2/} und {constant} wie bei der
        direkten Zahleneingabe auf -2 gesetzt.

2nd-voc ( -- ptr )
        Da fehleranf€llig, und durch die neue Vocabular-Suchfolge ‡berfl‡ssig,
        wurde eine M„glichkeit geschaffen, das den Vocabularen direkt, ggf.
        mit {search}, eingepr€gte zweite Such-Vocabular unwirksam zu machen.
                2nd-voc off
        stellt diesen Zustand ein, der beim Programmstart auch vorgegeben ist.
        Dabei wird es aber nun wichtig, immer wirklich alle erforderlichen
        Vocabulare anzugeben und sie zum Schluœ mit einen weiteren {also} in
        eine sichere Position zu schieben. Der Grund wird aus den ausf‡hrliche-
        ren Bemerkungen zu v6.01 ersichtlich.
        Der bisherige Zustand kann mit jedem Wert =/= 0 in der Variablen
        {2nd-voc} wiederhergestellt werden.

vocabulary
        Der zweite 'freie' Posten in der Vocabulardefinition (pfa+10) wird von
        den find-Varianten markiert, nachdem das betr. Vocabular erstmals durch-
        sucht wurde. Dadurch ist sichergestellt, daœ dies bei jedem Vocabular
        immer nur einmal geschieht, unabh€ngig davon, wie oft es mit {also} in
        den Vocabularstack gebracht wurde, oder ob es in der fixierten secun-
        d€ren Suchfolge der einzelnen Vocabulare mehrfach vorkommt (s. v6.01).
        Dies hatte ebensooft das Durchsuchen desselben Vocabulars zur Folge,
        und demgem€œ erheblichen ‡berfl‡ssigen Zeitaufwand, da dann immer das
        gesamte (weil gerade darin das Wort ja nicht vohanden sein konnte)
        jeweilige Vocabular mehrmals abgesucht wurde.
        Da die Compilezeit aber ganz wesentlich von der Anzahl zu pr‡fender
        Wortnamen abh€ngt, erspart die  nderung einen damit und mit der in
        diesen enthaltenen Anzahl Worte zunehmenden betr€chtlichen Zeitanteil,
        erfahrungsgem€œ oft weit mehr als 10% der Zeit, die beim Suchlauf durch
        allein das Forth-Vocabular erfordert.
        Damit k„nnen nun bedenkenlos beliebig viele Vocabulare beliebig oft
        genannt werden, ohne daœ das die Compilezeit beeintr€chtigt.


 * ++  2.12.93 ++ v6.04 +++++++++++++

id.     hebt immediate-Worte mit vertauschten ink- und strip-Farben hervor.
vlist   ruft id. auf, stellt die worte darum in derselben weise dar.

(find)  wurde an einer Fehlerstelle korrigiert,
        wo die Suche sich vorher in einer Endlosschleife fangen konnte.

shift   (n1 n2 -- n3 n4) liefert n3 als den um +n2 bits nach links geschobenen
        wert von n1, ‡berlauf wird in n4 aufgefangen. -n2 schiebt nach rechts.
        Als einfache Schiebeoperatoren mit Fehlerabbruch bei §berlauf k„nnen
        damit z.B. definiert werden:
                : << abs shift -18 ?error ;
                : >> abs minus shift -18 ?error ;
        Und zur Untersuchung einzelner Bits:
                : BIT minus shift sdrop ;


 * ++ 16.10.93 ++ v6.01 +++++++++++++

 Wichtigste Erg€nzungen: Vocabularstack und Compilieren aus Bibliothek-Files.

 Ab Version 6.01 existiert ein Vocabularstack nach f-83-Vorbild, der bis zu
 15 Vocabulare aufnehmen kann, und den Context der Suchordnung erweitert.
 "forth_scr" wurde erg€nzt. Es kann nun auch mit Namensangabe des zu compi-
 lierenden Wortes anstelle der Screen-Nummer aus einer Quelltext-Bibliothek
 (in Gestalt eines Screenfile) compiliert werden.

 Zus€tzliche Worte sind:

also        (r)(I) reiht das €ltere Context-Vocabular in die Suchfolge ein.
previous    (r)(I) nimmt das j‡ngste Vocabular aus der Suchfolge heraus.
only        (r)(I) bel€œt nur das Vocabular root in der Suchfolge.
#vocs              liefert als Constante die maximale Anzahl Vocabulare, die
                   in die Suchfolge aufgenommen werden k„nnen. Der Wert (16)
                   kann, solange noch keine neuen {user}-Variablen definiert
                   worden sind, erh„ht werden. {up} muœ dann f‡r jeden Posten
                   um 2 Bytes weitergez€hlt werden, wobei die absolute Grenze
#user          (h) mit der Maximalgr„œe des {user}-Bereichs zu beachten ist.
                   Vor {w-save} kann {#user} mit IS ver€ndert werden, muœ
                   danach aber sicherheitshalber restauriert werden. Die
                   neue Bereichsgr„œe gilt dann f‡r den damit erzeugten Job.

 Diese Erg€nzung €ndert dar‡ber hinaus nichts an der bew€hrten Vocabularbehand-
 lung des f.i.g.-Modells; die j‡ngeren Standards haben nur wenig beigetragen,
 was diese Konzept in irgendeiner Form bereichern oder verbessern k„nnte.
 Im Unterschied zu jenen unbeholfenen Versuchen der Zusammenfassung g€ngiger
 Praxis gibt es z.B. keinerlei Probleme bei {forget}, das durch alle Vocabulare
 geht, und auch die gerade nicht im Vocabularstack greifbaren ber‡cksichtigt.

 Das Wort {postpone} ist z.B. so eine Stilbl‡te der Nachfolgestandards, die
 nicht in das F6 nicht ‡bernommen wird. Sie ist sinnlos und irref‡hrend.
        compile [compile] forth
 zeigt z.B. entschieden klarer, daœ und wie ein Wort aufgebaut wird, welches
 den Aufruf eines immediate-Wortes in ein anderes Wort einbauen soll, als
        postpone postpone postpone forth
 - das erste {postpone} compiliert das zweite, da {postpone} immediate sein muœ.

 Die im Kern enthaltenen Vocabulare sind weiterhin s€mtlich "immediate", und es
 empfiehlt sich, dies konventionell auch bei neuen Vocabularen so zu handhaben.
 Das erspart viel Schreiberei bei h€ufigem Context-Wechsel:
        ..worte.. {vocname} ..worte.. {vocname} ..worte..
 statt der l€stigen Schreibweise mit Compile-Klammern z.B. im f83:
        ..worte.. [ {vocname} ] ..worte.. [ {vocname} ] ..worte..

 Der im allgemeinen seltene Fall, wo das neue Vocabular erst beim Aufruf des
 gerade definierten Wortes Context wird, wird im f.i.g.-Forth so abgehandelt:
        ..worte.. [compile] {vocname} ..worte..

 {-find} durchsucht nun der Reihe nach zuerst {context} und dann die ggf. mit
 {also} zuvor auf den Vocabularstack geschobenen Vocabulare. Im Compile-Betrieb
 wird wie bisher zuerst das {local}-Vocabular durchsucht. Die alte Suchordnung
 mit der vocabularspezifischen Nachfolge und der automatischen Bildung eines
 neuen Vocabulars als Untervocabular des gerade {current} vereinbarten bleiben
 erhalten. Ebenso die §bertragung des Current-Vocabulars in den Context bei
 Colon-Definitionen, wodurch dieses Vocabular dann zuerst durchsucht wird.

 Bei Erreichen der Maximalzahl durch den Aufruf {also} ‡berlaufende Vocabulare
 fallen aus der Suchordnung heraus. Dies wird nicht als Fehlersituation behan-
 delt, kann aber anhand der Constanten {#vocs} gesondert ‡berwacht werden.

 Bestehende Quelltexte bed‡rfen darum nur geringer  nderungen. Zus€tzlich gibt
 es noch die M„glichkeit, die besondere Nachfolge-Suche zu unterbinden:

no-search       (I) l„scht eine mit search ‡bergebene Eintragung im Context-Voc.

 Weil das ansich sehr einfache Verfahren der Ordnung nach Vocabularen vielleicht
 zun€chst etwas un‡bersichtlich scheint, mag dies die Ver€nderungen der Suchord-
 nung veranschaulichen:
 Anordnung im Speicher   Verwendung

        ocurrent        Ablage des vor {definitions} g‡ltigen {current}-Voc.
  ½¾    current         aktuelles Definitionsvocabular
 ocurrent @ current !   restauriert ggf. das vorherige Definitionsvocabular

 vocabularstack, vom 'unteren' Posten an:
  ½¿    context         aktuelles Lexikon-Vocabular (Wortsuche nach current)
   ¿    ocontext        Ablage des alten bei Nennung eines neuen Vocablulars
   ¿    [ ...           max. 14 weitere Posten werden ab {context} mit
            ...]        Aufruf von {also} 'hoch'geschoben.
 ende voc.stack ('oben')

        {definitions}   sichert das alte Definitionsvocabular in {ocurrent}
                        und tr€gt das Context-Vocabular in {current} ein.
        vocabular       Nennung des Namen tr€gt {current} in {ocurrent} ein,
                        danach wird das eben genannte Vocabular {current}.
        {also}          tr€gt alle Vocabulare einen Posten 'h„her' ein, dabei
                        bleibt {context} erhalten und wird zugleich {ocontext}.
        {rvoc}          copiert {ocurrent} nach {current}.
        {previous}      wie {rvoc}, schiebt auœerdem alle weiteren Vocabulare
                        einen Posten zur‡ck. Die 'obere' Stelle wird gel„scht.

 Solange noch keine neuen {user}-Variablen definiert wurden, kann der Vocabular-
 Stack erweitert werden. Z.b:
        8                       \ anzahl weiterer vocabulare der suchfolge
        dup #vocs + IS #vocs    \ neues maximum festlegen
        dup + up +!             \ datenbereich daf‡r reservieren
        w-save flp1_f6          \ ge€ndertes system sichern

 {search} und {no-search} wirken sich direkt auf das Context-Vocabular aus, mit
 dem sie ein unmittelbares Nachfolge-Vocabular fest verkn‡pfen rsp es abkoppeln.
 Die allgemeine Suchordnung aus {also} und {previous} bleibt davon unber‡hrt.

 Die Vocabulareinstellung sieht nun also etwas so aus:

        only            \ suchfolge gel„scht, nur {root} gilt noch
        forth           \ suchfolge nun: 1. {forth} 2. {root}
        definitions     \ {forth} wird current
        editor          \ root verschwindet, es gilt:{editor}{forth}
                        \ da abschlieœend aber immer auch {root}
                        \ durchsucht wird, bleiben dessen worte
                        \ stets auffindbar.
        also            \ alle vocs eins 'hoch'schieben
                        \ nun gilt: {editor} {forth} {forth}
                        \ und innerhalb einer {:}-Definition entsteht:
                        \           {forth} {editor forth}
                        \ was danach erhalten bleibt!

        only forth fp editor also forth also also definitions
 erzeugt
        forth forth forth editor fp
 womit auch bei beliebig h€ufigem Vocabularwechsel, z.B. durch {:} bei abwei-
 chendem {current} und durch einfache Namensnennung, die Suchfolge ab dem
 dritten Namen erhalten bleibt:
                                forth   forth   forth  editor fp
        qdos            =>      qdos    forth   forth  editor fp
        pif             =>      pif     qdos    forth  editor fp
        minerva         =>      minerva pif     forth  editor fp
 und:
        rvoc            =>      pif     pif     forth  editor fp
        rvoc            =>      pif     pif     forth  editor fp
 dagegen:
        previous        =>      pif     forth   editor fp
        previous        =>      forth   editor  fp

 Soll einmal f‡r einen begrenzten Zeitraum genau nur ein Vocabular gelten, und
 anschlieœend die urspr‡ngliche Ordnung wiederhergestellt werden, die aber selbst
 (in Compileraufrufen eines Programms z.B.) nicht bekannt ist, gibt man ein:
        also {name} also context 2+ off
 Damit wird die Suche allein auf das Vocabular {name} begrenzt.
 Die alte Ordnung stellt man dann wieder her mit:
        previous previous
 Und wenn auch das Vocabular aus der Suche ausgeschlossen sein soll, in dem das
 Context-Vocabular definiert wurde, ruft man auch noch {no-search} auf. So l€œt
 sich nun die Suchordnung in jeder Weise beeinflussen. Sicherheitshalber kann
 aber das {root}-Vocabular keinesfalls von der Suchfolge ausgenommen werden.

 Da hierzu Eingriffe ins System erforderlich waren, w€ren diese  nderungen nur
 mit groœem Aufwand von auœen nachsetzbar, sie sind darum nicht in "forth_scr"
 enthalten. F‡r m„glicherweise erneute  nderungen sind nun die wichtigsten
 Stellen vectorisiert oder deferrred eingerichtet.

[interpret]     (h)(D) Vorspann im Wort interpret
[find]          (h)(D) ( stg nfa -- pfa chr f | 0 ) in -find, Vorgabe (find)
[convert]       (h)(D) ( ptr -- ) Zahlenermittlung im Wort interpret.
                Aufruf immer, wenn ein Wort ab ptr nicht gefunden wurde.
number          (D) mit Vorgabe [number], Abbruch bei miœlungener Wandlung
[number]        (h) ( ptr -- dn | err) Standardaufruf in {number}.
buffer          (D)
block           (D)

 Wieder aktiviert wurden:

assembler       (r)(I)(D) f‡r Assembler-Vocabular (vormals code-voc)
asm68           (r)(I) als Assemblervocabular (a)
[donext]        (a) assembler-label zum next-Einsprung.
[doexec]        (a) dto, Ausf‡hrungs-Ptr. im W-Register (A2.w)
doforget        (h)(D) ( n1 n2 -- n1 n2 )
                Erh€lt die j‡ngste Vocabular-Verkettung in n1 und in n2 die nfa
                des mit einer der {forget}-Varianten freizugebenden Wortes und
                muœ diese unver€ndert (oder in gleichwertiger Form) weitergeben.
                In diesem {forget}-Vorspann k„nnen vorbereitende Aktionen aus-
                gef‡hrt werden; Verwendung z.B. bei {heapmem} in "forth_scr".
forget-lk       (-- ptr) vorbereitet zur Verkettung optionaler forget-Aktionen.

w-find          (D) und
-find           (D) in deferred Worte umgewandelt.

 Das Compilieren aus einer Bibliothek wird durch den aus s-load modifizierten
 Aufruf L-LOAD um die M„glichkeit der namentlichen Suche erg€nzt. Die daf‡r
 geeigneten Screenfiles m‡ssen das gesuchte Wort in der Seite, wo das Compi-
 lieren beginnen soll, in der ersten Zeile enthalten, weiter markiert durch
 vorangestellten Doppelpunkt und jenem folgendes Leerzeichen. In dieser Form
 darf das Wort bis dahin in keiner anderen Kopfzeile auftreten.
 Viele Beispiele dazu finden sich in "forth_scr".

 F‡r heikle F€lle sind {s-load} und {l-load} so eingerichtet, daœ sie im Un-
 terschied zu {load} auch mit schreibgesch‡tzten Disketten arbeiten k„nnen.

 In "forth_scr" ist definiert:

l-load {wortname} {screenfilename}
        (S) Im angegebenen Screenfile wird eine Kopfzeile (erste Zeile
        einer Seite) gesucht, in der das gesuchte Wort mit f‡hrendem
        Doppelpunkt und Space verzeichnet ist. Die so ermittelte
        (ganze) Seite wird compiliert.
        Dazu geht sie als Screen-Nummer an den schon bekannten Aufruf
        s-load, f‡r den der hier genannte Filename weitergilt.

 1 s-load flp1_forth_scr
        l€dt L-LOAD,
        und hiermit wird nun z.B. der Aufruf ?imm compilert:
  l-load ?imm flp1_forth_scr

 Da dies eine allzuh€ufige Fehlerquelle scheint, wurde 'h' als Zahlenpraefix
 gestrichen. Es gelten
 Zeichen         temp. Zahlenbasis
   {             256     nur das erste Zeichen wird bewertet (statt ascii)
   $             16
   #             10
   &             8
   %             2
   \             erzeugt eine qdos-Flieœkommazahl

 Der Wert dieser Kennzeichen muœ sich noch erweisen:
   ¶             12     erleichtert das Rechnen ohne Bruchzahlen (dagegen er-
                        weist sich der Gebrauch des Dezimalsystems schon fast
                        als epochaler Schwachsinn).
   '             5
   "             6
   !             4

 * ++ 24.9.93 +++++++++++++++++++++++

 In "forth_scr" finden sich alle Definitionen, die zur urspr‡nglichen Version
 hinzugekommen sind, als Hi-Level-Worte zur Anpassung nach Bedarf. Die j‡ngste
 Original-Version ist dann u.U. entbehrlich. Dazu noch einige weitere Worte, die
 von Fall zu Fall gebraucht werden k„nnen - n€here Erl€uterungen im Quelltext:
        EX und EW       fremde Jobs aufrufen, ohne Parameter‡bergabe an den Job
        (clone-jdt)     ( d.job.id -- d.job.id)
                        wird innerhalb des Aufrufs unmittelbar vor dem Aktivie-
                        ren des Jobs durchlaufen - auch bei {clone-4th}.
                        {a2@l} liefert dann die Speicherbasis des Jobs, sodaœ
                        hieraus auch die Startwerte der Register des Jobs be-
                        einfluœt werden k„nnen. Damit wird auch die §bergabe
                        von Parametern nach qdos-Standard m„glich.
        DATAD$ DATA_USE etc. - die vom Basic mit TK2 bekannten Device-Vorgaben
        DIR             wie im Glossar beschrieben
        BACKUP          dto.
        HEAPMEM         und unterst‡tzende Worte zum Einrichten eines Speicher-
                        bereichs im Heap. Das Wort ist gegen Mehrfachaufruf und
                        {forget} abgesichert und erneuert ggf. auch einen zuvor
                        aufgegebenen Speicherbereich einer bekannten Definition.
        .VIEW           Erweiterung f‡r die VIEW-Felder nach f-83-Muster.
        DUMP LDUMP      Speicherauszug darstellen.


 Damit Programme mit automatischer Anpassung an verschiedene Systemkonstella-
 tionen versehen werden k„nnen, liefert das neue Wort {sysflg} als 32-bit-Wert
 byteweise gepackt:
     hi    -1  bei 68010+, sonst 0
      ¿    -1  emu, 1 JM und €lter, 0 sonst
      ¿   char qdos Nationen-Markierung
     lo    -1  Minerva (ver. > 1.50, f‡r ri-exec), 0 sonst

         sysflg drop >< emit
 gibt z.b. das Kennzeichen f‡r die nationale Rom-Version aus.


 Blockfile-Adressierung:

 Das File-System holt nun auch in den Kerndefinitionen alle Daten zu den Blocks
 und der Screen-Gr„œe aus den zugeh„rigen Constanten {b/buf} und {b/scr}. Es gibt
 damit keine Festwerte im System mehr, die 'gewuœt' werden m‡ssen. Bei konsequen-
 ter Unterscheidung dieser Daten und der Hilfsvariablen/-Constanten {c/l}, {scr}
 und {blk} sollten damit unterschiedliche Formate und beliebige Verh€ltnisse zwi-
 schen Block-Gr„œe, Zeilenl€nge und Editor-Screens verwaltet werden k„nnen.
 "Sollten" deshalb, weil diese Dinge nicht untersucht wurden.

 Kan€le:
        Eine dem Basic €hnliche Kanalwahl ist vorbereitet durch das
        DefinitionsWort {#chan}:

#chan   use: ( d.ernum -- )  #CHAN {name}  ( -- | abort)
        erwartet die Fehlernumer aus einem vorangegangenen Aufruf der fopen-
        Gruppe, wertet diese ggf. durch Abbruch und Fehlermeldung aus, und
        bildet ein Wort, bei dessen Aufruf {in-cons}, {out-cons} und {work}
        auf den Kanal gestellt werden, der zum Zeitpunkt der Definition der
        {work}-Kanal war - welches nach einem der fopen-Aufrufe der gerade
        ge„ffnete Kanal ist. Der Aufruf von hiermit gebildeten Worten bricht
        ab, wenn der ‡bergebene Kanal nicht (mehr) zug€nglich ist. Die betr.
        Fehleraktion l€œt sich in {error} nach Bedarf re-vectorisieren.

                fopen con_100x50a40x30 #chan w#1
        oder
                fop-over flp2_ein_34_zeichen_langer_name... #chan kanal#2
        und nun gehen nach z.B.
                kanal#2 <enter>
        alle Operationen der i/o- und work-Aufrufe, insbes. also auch die des
        qdos-Vocabulars, an den dem neuen Wort {kanal#2} zugewiesenen Kanal.
        Irgendein bereits offener Kanal kann mit einem Platzhalter f‡r den
        Fehlercode an die #chan-Definition folgendermaœen ‡bergeben werden:
                ( kanalnummer )  to-work
        oder    ( d.kanal-id  ) set-work
        dann                    0. #chan {name}

        Sollen f‡r {in-cons}, {out-cons} und {work} verschiedene Kan€le gelten,
        so ‡bergibt man nach der Ur-Definition deren id-Zahlen an das mit #chan
        gebildete Wort. Ein Beispiel mit den jeweils gerade g‡ltigen Kan€len:
                0. #chan {name}                 zuerst das Wortgerippe erzeugen
                ' {name}                        seine pfa ermitteln und erstmal
                2+                              das [dodoes] ‡berspringen,
                   dup in-cons  ch-id rot 2!    aktuellen input-Kanal eintragen
                4+ dup out-cons ch-id rot 2!    desgl. System-Ausgabe (Prompts)
                4+     work     ch-id rot 2!    und aktuellen {work}-Kanal.
        Beim Aufruf werden die drei Kan€le gesondert auf Zug€nglichkeit gepr‡ft.

        Ein weiteres Beispiel steht in "forth_scr" bei der Definition von {w#0}.


 * ++++++++++++++++++++++++++++++++++

 Sichere Speicherzuweisungen und automatische Freigabe bei {forget}:

 {heapmem} und zugeh„rige Worte werden in "forth_scr" definiert und besorgen
 Speicherreservierung und geordnete Freigabe im Heap. Das Definitionswort legt
 zun€chst nur ein Variablenfeld an, wo ggf. die Basisadresse der Heap-Zuweisung
 und ein Verkettungspointer eingetragen wird. Sooft das damit definierte Wort
 nun aufgerufen wird, liefert es stets eine g‡ltige (absolute) Speicheradresse
 zum Stack, die zu einem bereits vorhandenen Bereich geh„rt oder zu einer durch
 diesen Aufruf veranlaœten neuen Zuweisung. {heap-rmv} nimmt eine Reservierung
 zur‡ck. Erneuter Aufruf des Speicherwortes nach vorheriger Freigabe legt den
 zugeh„rigen Speicherbereich sofort wieder neu an. Ob eine Adresse tats€chlich
 auf einen zum Job geh„renden Speicherbereich zeigt, l€œt sich mit {4th-heap}
 ‡berpr‡fen. {clchp} nimmt s€mtliche Zuweisungen zur‡ck, und {heap?} zeigt die
 Adressen aller mit {heap-mem} eingerichteten Speicherbl„cke an.

 Auœerdem wird {forget} samt seinen Varianten so erweitert, daœ Bereiche, deren
 definierende Aufrufe zu den zu entfernenden Worten geh„ren, gleichzeitig frei-
 gegeben werden. Sp€ter ist dies ohne besondere Vorkehrungen nicht mehr m„glich,
 weil nach {forget} die Basisadresse der Heap-Reservierung 'vergessen' ist.
 Auch {empty}, in scr# 8 als {forget}-Variante f‡r alle Worte 'oberhalb' von
 {fence} definiert, l„st die Freigabe solcher Heap-Bereiche aus.

 Beispiele:
                        1024 heapmem speicher   ( gr„œe/4 HEAPMEM {name}
 definiert eine 'aktive' Variable, die zun€chst nur die angegebene Zahl enth€lt.
 Beim Aufruf veranlaœt sie die Zuweisung eines Heap-Blocks von vierfacher Gr„œe
 der Zahl, mit der sie definiert wurde, und gibt die Speicheradresse des reser-
 vierten Bereiches zum Stack. Solange dieser Block nicht aufgegeben wird, kommt
 von nun an immer dieselbe Adresse zur‡ck:

                        speicher                ( -- d.adresse
 liefert dann also die Basisadresse eines 4K Bytes groœen Speicherblocks.
 Bedingt durch die Gr„œenangabe als 16-Bit-Zahl k„nnen mit {heapmem} Speicher-
 bl„cke von 4 bis 262140 Bytes definiert werden.

 Sollen anderweitig definierte Speicherzuweisungen in o.g. Automatik zur Heap-
 freigabe aufgenommen werden, sind sie ‡ber {heap-lk} zu verketten:
        ( d.adresse -- ) here 1 and allot       ( geradzahlige 4th-adresse
                         here 6 allot 2!        ( speicheradresse, 16-bit-dummy
                         here heap-lk dup @ , ! ( verketten
 Diese Verkettung gen‡gt, Wortheader o.a. Referenzen sind nicht erforderlich.

 Einzel-Freigabe mittels {heap-rmv} ber‡cksichtigt diese Liste nicht, kann also
 beliebig f‡r jeden Speicherbereich aufgerufen werden, den der augenblickliche
 4th-Job besitzt. Die 'Automatik' wiederum pr‡ft, ob die ihr ‡bergebene Adresse
 zu einem noch existierenden eigenen Speicherblock geh„rt. Widrigenfalls sucht
 sie einfach nur weiter nach der n€chsten Adresse. 'Fremde' Bereiche l„st auch
 {heap-rmv} darum nicht auf, dazu ist das QDOS-Wort {rechp} geeignet, wobei aber
 im QDOS nicht gepr‡ft wird, ob die ‡bergebene Adresse (noch) g‡ltig ist. Dadurch
 bedingt kann es zu schwerwiegenden Fehlern kommen, die auch vor File-Daten nicht
 halt machen! Gesonderte Pr‡fung ist darum unbedingt ratsam, etwa mittels der vom
 System gef‡hrten Listen aus beispielsweise sv.cheap { 4 qsys+ 2@l }.


 Gruœ von mir, .hpr

 » .hpr'12/93 » eof »
