! X-Forth
Author: Carsten Strotmann \\
Language: FORTH \\
Compiler/Interpreter: X-FORTH /ATASM \\
Published: 10.2003 \\
Sourcecode of X-Forth for Atari 800/800XL/130XE, indirect threaded Forth based on FIG-Forth
Code compiles with ATASM -> http://atasm.sf.net
{{{
; -------------------------------------------------------------------------
; X-FORTH 1.1b
; RELEASE 18.10.2003
; Homepage: http://www.strotmann.de/twiki/bin/view/APG/ProjXForth
; License: GNU Public License (GPL)
;
; based on Sources from fig-forth and Andreas Jung
;
; compiles with ATASM --> http://atasm.sourceforge.net
;--------------------------------------------------------------------------
; Flags
DEBUG = 0
KEYWAIT = 1
FINDDEBUG = 0
FILE = 1
DYNMEMTOP = 0
; Startadresse im Speicher
.BANK
* = $2000
; Kernal-Routinen des Atari800
DOSVEC = $000A
DOSINI = $000C
; FORTH-Systemkonstanten. Sie muessen gegebenenfalls an die jeweilige
; Hardware angepasst werden.
BOS = $8E ; Start des Daten-Stacks in der Zeropage
TOS = $C6 ; Zeiger auf den TOS ($C6)
N = $F0 ; temporaerer Arbeitsspeicher ($F0) (orig TOS+8)
IP = N+8 ; Instruction Pointer IP ($F8)
W = IP+3 ; Codefeld-Pointer W ($FB)
UP = W+2 ; User-Pointer UP ($FD)
XSAVE = UP+2 ; temporaerer Speicher fuer das X-Register ($FF)
;
TIBX = $0100 ; Terminal Input Buffer, 84 Bytes
MEM = $B800 ; Ende des FORTH-Speichers
UAREA = MEM-128 ; User-Area, 128 Bytes
; Der Speicher zwischen dem Ende des Dictionaries und DAREA steht fuer
; Benutzerprogramme zur Verfuegung.
; Es folgen nun die Boot-up-Parameter, d.h. Sprungvektoren und
; Parameter zur Systembeschreibung.
ORIG NOP ; 0+ORIGIN: Kaltstart ueber COLD
JMP PFA_COLD ;
REENTR NOP ; 4+ORIGIN: Warmstart ueber WARM
JMP WARM ;
.WORD $0004 ; 8+ORIGIN: "6502" zur Basis 36
.WORD $5ED2 ;
.WORD NFA_LASTWORD ; 12+ORIGIN: NFA des letzten Wortes
.WORD 126 ; 14+ORIGIN: externer Backspace-Charakter
.WORD UAREA ; 16+ORIGIN: initialer User-Pointer UP
.WORD TOS ; 18+ORIGIN: Startwert fuer S0
.WORD $1FF ; 20+ORIGIN: Startwert fuer R0
.WORD TIBX ; 22+ORIGIN: Startwert fuer TIB
.WORD 31 ; 24+ORIGIN: Startwert fuer WIDTH
.WORD 0 ; 26+ORIGIN: Startwert fuer WARNING
.WORD TOP ; 28+ORIGIN: Startwert fuer FENCE
.WORD TOP ; 30+ORIGIN: Startwert fuer DP
.WORD PFA_FORTH+6 ; 32+ORIGIN: Startwert fuer VOC-LINK
; Die folgenden NOP's bewirken eine Verschiebung des Dictionaries, so
; dass kein Codefeld auf eine Adresse der Form $XXFF faellt. Aufgrund
; eines Bugs im 6502-Prozessor wuerde dann naemlich der indirekte
; Sprung an der Adresse W-1 nicht richtig funktionieren. Bei jeder
; Aenderung des Dictionaries muessen die folgenden Zeilen gegebenenfalls
; geaendert werden.
; NOP
; NOP
NOP
; >>>>>>>>>>>>>>>> LIT <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( LIT [ -> n ] legt die inline folgende Zahl auf den Stack. )
;( ========================================================================= )
NFA_LIT .CBYTE $83, "LIT"
LFA_LIT .WORD 0
CFA_LIT .WORD PFA_LIT
PFA_LIT
LDA (IP),Y ; Lo-Byte der inline folgenden Zahl holen
PHA ; und auf den Stack retten
INC IP ; Instruction-Pointer inkrementieren
BNE L30
INC IP+1
L30
LDA (IP),Y ; Hi-Byte der inline folgenden Zahl holen
L31
INC IP ; Instruction-Pointer inkrementieren
BNE PUSH
INC IP+1
PUSH
DEX ; Datenstack-Pointer dekrementieren
DEX
PUT
STA 1,X ; Hi-Byte (ist in A) auf den Datenstack legen
PLA ; Lo-Byte vom Stack holen
STA 0,X ; und auf den Datenstack legen
; =========================================================================
; Der Adressinterpreter NEXT holt die Adresse des naechsten Secondaries
; und fuehrt es aus.
; =========================================================================
NEXT
LDY #1
LDA (IP),Y ; Hi-Byte der Wortadresse
STA W+1 ; im W-Register ablegen
DEY
LDA (IP),Y ; Lo-Byte der Wortadresse
STA W ; im W-Register ablegen
.IF debug
PHA
LDA DEBUGFLG
BEQ DL1
PLA
JSR TRACE ; DEBUG
PHA
DL1 PLA
.ENDIF
CLC
LDA IP ; IP um 2 inkrementieren
ADC #2
STA IP
BCC L54
INC IP+1
L54
JMP W-1 ; indirekten Sprung nach (W) ausfuehren
; >>>>>>>>>>>>>>>> CLIT <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( CLIT [ -> b ] legt das inline folgende Byte auf den Stack. )
;( ========================================================================= )
NFA_CLIT .CBYTE $84,"CLIT"
LFA_CLIT .WORD NFA_LIT
CFA_CLIT .WORD PFA_CLIT
PFA_CLIT
LDA (IP),Y ; inline folgendes Byte holen
PHA ; und auf den Stack legen
TYA ; Akkumulator (Hi-Byte) mit Y=0 laden
BEQ L31 ; und in die Routine LIT verzweigen
; =========================================================================
; Die Routine SETUP poppt n Zellen vom Datenstack und schreibt sie in den
; temporaeren Speicher ab Adresse N. Die Zahl n wird im Akkumulator
; uebergeben.
; =========================================================================
SETUP
ASL A ; n verdoppeln, ergibt Anzahl zu poppender Bytes
STA N-1 ; Anzahl zu poppender Bytes sichern
L63
LDA 0,X ; ein Byte vom Datenstack holen (zu Anfang ist Y=0)
STA N,Y ; und im Speicherbereich ab Adresse N ablegen
INX ; Datenstack-Pointer inkrementieren
INY ; Zielindex inkrementieren
CPY N-1 ; sind bereits 2*n Bytes gepoppt?
BNE L63 ; nein, dann weitermachen
LDY #0 ; Y.=0 wiederherstellen
RTS ; und fertig
; >>>>>>>>>>>>>>>> EXECUTE <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( EXECUTE [ addr -> ] fuehrt das Wort aus, dessen CFA auf dem Stack liegt. )
;( ========================================================================= )
NFA_EXECUTE .CBYTE $87,"EXECUTE"
LFA_EXECUTE .WORD NFA_CLIT
CFA_EXECUTE .WORD PFA_EXECUTE
PFA_EXECUTE
LDA 0,X ; Lo-Byte von addr
STA W ; in das W-Register schreiben
LDA 1,X ; Hi-Byte von addr
STA W+1 ; in das W-Register schreiben
INX ; addr vom Datenstack nehmen
INX
JMP W-1 ; Secondary ab addr ausfuehren
; >>>>>>>>>>>>>>>> BRANCH <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( BRANCH [ ] bewirkt einen relativen Sprung, abhaengig vom inline folgenden )
;( Offset. )
;( ========================================================================= )
NFA_BRANCH .CBYTE $86, "BRANCH"
LFA_BRANCH .WORD NFA_EXECUTE
CFA_BRANCH .WORD PFA_BRANCH
PFA_BRANCH
CLC
LDA (IP),Y ; Lo-Byte des Offsets holen
ADC IP ; zu aktuellem IP hinzuaddieren
PHA ; und auf den Stack retten
INY
LDA (IP),Y ; Hi-Byte des Offsets holen
ADC IP+1 ; zu aktuellem IP hinzuaddieren
STA IP+1 ; und im IP-Register ablegen
PLA ; Lo-Byte des neuen IP-Inhaltes vom Stack holen
STA IP ; und im IP-Register ablegen
JMP NEXT+2 ; dort weitermachen, LDY #1 kann uebersprungen werden
; >>>>>>>>>>>>>>>> 0BRANCH <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( 0BRANCH [ f -> ] bewirkt einen relativen Sprung, abhaengig vom inline )
;( folgenden Offset, wenn f Null ist. )
;( ========================================================================= )
NFA_0BRANCH .CBYTE $87, "0BRANCH"
LFA_0BRANCH .WORD NFA_BRANCH
CFA_0BRANCH .WORD PFA_0BRANCH
PFA_0BRANCH
INX ; f vom Datenstack nehmen
INX
LDA $FE,X ; f testen
ORA $FF,X
BEQ PFA_BRANCH ; verzweigen, falls f=0
BUMP CLC
LDA IP ; sonst IP ueber den Offset hinwegsetzen
ADC #2
STA IP
BCC L122
INC IP+1
L122 JMP NEXT ; und weitermachen
; >>>>>>>>>>>>>>>> (LOOP) <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( [LOOP] [ ] inkrementiert den Loop-Index um 1 und testet auf Erreichen der )
;( Abbruchbedingung. Eventuell wird gemaess einem inline folgenden Offset )
;( verzweigt. )
;( ========================================================================= )
NFA_BRACKETLOOP .CBYTE $86, "(LOOP)"
LFA_BRACKETLOOP .WORD NFA_0BRANCH
CFA_BRACKETLOOP .WORD PFA_BRACKETLOOP
PFA_BRACKETLOOP
L130 STX XSAVE ; X-Register retten
TSX ; Stackpointer nach X bringen
INC $101,X ; Loop-Index I inkrementieren
BNE PL1
INC $102,X
PL1 CLC
LDA $103,X ; Hi(Schleifenlimit-I-1) berechnen
SBC $101,X
LDA $104,X
SBC $102,X
PL2 LDX XSAVE ; X-Register wiederherstellen
ASL A ; falls obige Differenz nicht negativ:
BCC PFA_BRANCH ; an den Schleifenanfang verzweigen
PLA ; sonst Schleifenlimit und I vom Stack nehmen
PLA
PLA
PLA
JMP BUMP ; und Offset uebergehen
; >>>>>>>>>>>>>>>> (+LOOP) <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( [+LOOP] [ n -> ] inkrementiert den Loop-Index um n und testet auf Errei- )
;( chen der Abbruchbedingung. Eventuell wird gemaess einem inline folgenden )
;( Offset verzweigt. )
;( ========================================================================= )
NFA_BRACKETPLUSLOOP .CBYTE $87, "(+LOOP)"
LFA_BRACKETPLUSLOOP .WORD NFA_BRACKETLOOP
CFA_BRACKETPLUSLOOP .WORD PFA_BRACKETPLUSLOOP
PFA_BRACKETPLUSLOOP
INX ; Datenstackpointer inkrementieren
INX
STX XSAVE ; X-Register retten
LDA $FF,X ; Hi-Byte von n
PHA ; zweimal auf den Stack legen
PHA
LDA $FE,X ; Lo-Byte von n holen
TSX ; Stackpointer nach X holen
INX ; Hi-Byte von n interessiert momentan nicht
INX
CLC
ADC $101,X ; Lo-Byte von n auf I aufaddieren
STA $101,X
PLA ; Hi-Byte von n holen
ADC $102,X ; und auf I aufaddieren
STA $102,X
PLA ; nochmal Hi-Byte von n holen
BPL PL1 ; falls n positiv: bei (LOOP) weitermachen
CLC
LDA $101,X ; sonst Hi(I-Schleifenlimit-1) berechnen
SBC $103,X
LDA $102,X
SBC $104,X
JMP PL2 ; und hiermit bei (LOOP) weitermachen
; >>>>>>>>>>>>>>>> (DO) <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( [DO] [ n1 n2 -> ] bringt die Loop-Parameter [Startindex, Limit] zum )
;( Return-Stack. )
;( ========================================================================= )
NFA_BRACKETDO .CBYTE $84, "(DO)"
LFA_BRACKETDO .WORD NFA_BRACKETPLUSLOOP
CFA_BRACKETDO .WORD PFA_BRACKETDO
PFA_BRACKETDO
LDA 3,X ; Limit zum Returnstack bringen
PHA
LDA 2,X
PHA
LDA 1,X ; Startindex zum Returnstack bringen
PHA
LDA 0,X
PHA
POPTWO
INX ; n2 von Datenstack poppen
INX
POP
INX ; n1 vom Datenstack poppen
INX
JMP NEXT ; und weitermachen
; >>>>>>>>>>>>>>>> R <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( R [ -> n ] kopiert das oberste Element des Return-Stacks zum Parameter- )
;( Stack. )
;( ========================================================================= )
NFA_R .CBYTE $81, "R"
LFA_R .WORD NFA_BRACKETDO
CFA_R .WORD PFA_R
PFA_R
STX XSAVE ; Datenstackpointer retten
TSX ; X-Register als Index in den Returnstack benutzen
LDA $101,X ; Lo-Byte vom Returnstack holen
PHA ; und merken
LDA $102,X ; Hi-Byte vom Returnstack holen
LDX XSAVE ; Datenstackpointer wiederherstellen
JMP PUSH ; n auf den Datenstack pushen und fertig
; >>>>>>>>>>>>>>>> I <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( I [ -> n ] legt den aktuellen Loop-Index auf den Stack. )
;( ========================================================================= )
NFA_I .CBYTE $81, "I"
LFA_I .WORD NFA_R
CFA_I .WORD PFA_R ; Link zu "R", Befehl identisch
PFA_I
; >>>>>>>>>>>>>>>> J <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( J [ -> n ] kopiert den Zaehlindex der aesseren Scheife auf den Datenstack )
;( )
;( ========================================================================= )
NFA_J .CBYTE $81, "J"
LFA_J .WORD NFA_I
CFA_J .WORD PFA_J
PFA_J
STX XSAVE ; Datenstackpointer retten
TSX ; X-Register als Index in den Returnstack benutzen
LDA $105,X ; Lo-Byte vom Returnstack holen
PHA ; und merken
LDA $106,X ; Hi-Byte vom Returnstack holen
LDX XSAVE ; Datenstackpointer wiederherstellen
JMP PUSH ; n auf den Datenstack pushen und fertig
; >>>>>>>>>>>>>>>> DIGIT <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( DIGIT [ c n1 -> n2 tf ] falls ok, [ c n1 -> ff ] falls schlecht. Wandelt )
;( den ASCII-Charakter c in sein Zahlen-Aequivalent n2 um. Als Basis wird )
;( n1 benutzt. Ist c ein gueltiges Ziffernsymbol im n1-System, so wird tf=1 )
;( zurueckgegeben, sonst ff=0. )
;( ========================================================================= )
NFA_DIGIT .CBYTE $85, "DIGIT"
LFA_DIGIT .WORD NFA_J
CFA_DIGIT .WORD PFA_DIGIT
PFA_DIGIT
SEC
LDA 2,X ; Zeichen c holen
SBC #$30 ; und '0' subtrahieren
BMI L234 ; falls negativ: Misserfolg melden
CMP #$A ; mit 10 vergleichen
BMI L227 ; kleiner, dann weiter
SEC
SBC #7 ; sonst weitere 7 abziehen
CMP #$A ; falls kleiner als 10:
BMI L234 ; Misserfolg melden
L227
CMP 0,X ; ermittelte Zahl mit Basis n1 vergleichen
BPL L234 ; Zahl groesser oder gleich Basis, dann Misserfolg melden
STA 2,X ; sonst Zahl in n2 zurueckgeben
LDA #1 ; tf zurueckgeben (Y=0)
PHA
TYA
JMP PUT
L234 TYA ; Misserfolg: ff zurueckgeben (Y=0)
PHA
INX
INX
JMP PUT
; >>>>>>>>>>>>>>>> (FIND) <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( [FIND] [ addr1 addr2 -> pfa b tf ] falls ok, [ addr1 addr2 -> ff ] sonst. )
;( Sucht im Dictionary, beginnend bei der NFA addr2, nach dem String addr1. )
;( Wird das Wort gefunden, so wird seine PFA, das Count-Byte und ein true- )
;( Flag uebergeben, sonst lediglich ein false-Flag. )
;( ========================================================================= )
NFA_BRACKETFIND .CBYTE $86, "(FIND)"
LFA_BRACKETFIND .WORD NFA_DIGIT
CFA_BRACKETFIND .WORD PFA_BRACKETFIND
PFA_BRACKETFIND
LDA #2 ; addr1 und addr2
JSR SETUP ; in den Speicher ab Adresse N poppen
STX XSAVE ; Datenstackpointer retten
L249 LDY #0 ; Vergleich beginnt beim Count-Byte
LDA (N),Y ; Count-Byte des Woerterbucheintrages holen
EOR (N+2),Y ; und mit Count-Byte des Strings vergleichen
AND #$3F ; dabei die beiden obersten Bits ignorieren
BNE L281 ; bei Ungleichheit verzweigen
L254 INY ; naechstes Zeichen anvisieren
LDA (N),Y ; naechstes Zeichen des Woerterbucheintrages holen
EOR (N+2),Y ; und mit naechstem Zeichen des Strings vergleichen
ASL A ; hoechstes Bit in den Uebertrag schieben
BNE L280 ; bei Ungleichheit verzweigen
BCC L254 ; weiter vergleichen falls String-Ende noch nicht erreicht
LDX XSAVE ; bei Gleichheit Datenstackpointer wiederherstellen
DEX ; auf dem Datenstack Platz fuer pfa und b schaffen
DEX
DEX
DEX
CLC
TYA ; Offset des letzten String-Zeichens
ADC #5 ; plus 5 ergibt Offset des Parameterfeldes
ADC N ; plus NFA ergibt PFA
STA 2,X ; Lo-Byte der PFA in den Datenstack schreiben
LDY #0
TYA ; eventuell aufgetretenen Uebertrag
ADC N+1 ; in Hi-Byte der PFA beruecksichtigen
STA 3,X ; Hi-Byte der PFA in den Datenstack schreiben
STY 1,X ; Hi-Byte von b auf Null setzen
LDA (N),Y ; Count-Byte des gefundenen Wortes holen
STA 0,X ; und in den Datenstack schreiben
LDA #1 ; True-Flag vorbereiten
PHA
JMP PUSH ; auf den Datenstack legen und fertig
L280 BCS L284 ; Suche ueberspringen falls String-Ende erreicht
L281 INY ; naechstes Zeichen anvisieren
LDA (N),Y ; naechstes Zeichen des Woerterbucheintrages holen
.IF finddebug
JSR OUTCH ; debug - Druckt die Suche nach einem Word
LDA (N),Y ; debug - wenn Fehler in der Verkettung bestehen,
; debug - Woerter nicht gefunden werden
.ENDIF
BPL L281 ; hoechstes Bit nicht gesetzt, dann weitersuchen
L284 INY ; sonst Byte hinter dem Namenfeld anvisieren
LDA (N),Y ; Lo-Byte des Linkfeldes holen
TAX ; und in das X-Register laden
INY ; Hi-Byte des Linkfeldes anvisieren
LDA (N),Y ; und holen
STA N+1 ; und anstelle des alten Wertes von addr2 ablegen
STX N ; das gleiche mit dem Lo-Byte des Linkfeldes
ORA N ; im Linkfeld angegebene Adresse testen
BNE L249 ; ungleich Null, dann erneut vergleichen
LDX XSAVE ; sonst Datenstackpointer wiederherstellen
LDA #0 ; False-Flag vorbereiten
PHA
JMP PUSH ; auf den Datenstack legen und fertig
; >>>>>>>>>>>>>>>> ENCLOSE <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( ENCLOSE [ addr1 c -> addr1 n1 n2 n3 ] separiert einen Text beginnend ab )
;( der Adresse addr1 mit dem Delimiter c. n1 ist der Byte-Offset zum ersten )
;( von c verschiedenen ASCII-Charakter, n2 der Byte-Offset zum ersten )
;( Delimiter-Charakter c hinter dem Text und n3 der Byte-Offset zum ersten )
;( Charakter, der auf diesen Delimiter folgt. Das Zeichen ASCII-Null dient )
;( als unbedingter Delimiter, ab dem nicht mehr weitergesucht wird. )
;( ========================================================================= )
NFA_ENCLOSE .CBYTE $87,"ENCLOSE"
LFA_ENCLOSE .WORD NFA_BRACKETFIND
CFA_ENCLOSE .WORD PFA_ENCLOSE
PFA_ENCLOSE
LDA #2 ; Parameter addr1 und c
JSR SETUP ; in den Speicher ab N poppen
TXA
SEC ; Platz im Datenstack fuer addr1, n1, n2 und n3
SBC #8 ; bereitstellen
TAX
STY 3,X ; Hi-Byte von n2 auf Null setzen (Y=0)
STY 1,X ; Hi-Byte von n1 ebenso
DEY
L313 INY ; naechstes Zeichen im Text ab addr1 anvisieren
LDA (N+2),Y ; Zeichen holen
CMP N ; mit c vergleichen
BEQ L313 ; alle c's am Anfang ueberlesen
STY 4,X ; Position des ersten Nicht-c in n1 ablegen
L318 LDA (N+2),Y ; naechstes Zeichen im Text ab addr1 holen
BNE L327 ; nicht Null, dann verzweigen
STY 2,X ; sonst Position der Null in n2
STY 0,X ; und in n3 ablegen
TYA
CMP 4,X ; Position mit Position des ersten Nicht-c vergleichen
BNE L326 ; andere Position, dann verzweigen
INC 2,X ; sonst n2 inkrementieren
L326 JMP NEXT ; und fertig
L327 STY 2,X ; aktuelle Position in n2 ablegen
INY ; naechstes Zeichen anvisieren
CMP N ; aktuelles Zeichen mit c vergleichen
BNE L318 ; bei Ungleichheit weitersuchen
STY 0,X ; sonst naechste Position im n3 ablegen
JMP NEXT ; und fertig
; >>>>>>>>>>>>>>>> EMIT <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( EMIT [ c -> ] sendet den ASCII-Charakter c zum Standard-Ausgabegeraet und )
;( erhoeht die USER-Variable OUT um 1. )
;( ========================================================================= )
NFA_EMIT .CBYTE $84, "EMIT"
LFA_EMIT .WORD NFA_ENCLOSE
CFA_EMIT .WORD PFA_EMIT
PFA_EMIT
XEMIT
TYA ; A.=0 (Y=0)
SEC
LDY #$1A ; Offset der User-Variablen OUT
ADC (UP),Y ; OUT inkrementieren
STA (UP),Y
INY
LDA #0
ADC (UP),Y ; auch Hi-Byte von OUT beruecksichtigen
STA (UP),Y
TYA ; Y Register auf den Stack retten
PHA
LDA 0,X ; Zeichen c holen
STX XSAVE ; Datenstackpointer retten
JSR OUTCH ; Zeichen ausgeben
LDX XSAVE ; Datenstackpointer wiederherstellen
PLA
TAY ; Y Register wiederherstellen
JMP POP ; c vom Datenstack entfernen und fertig
; >>>>>>>>>>>>>>>> KEY <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( KEY [ -> c ] wartet auf eine Tastaturbetaetigung und uebergibt den ASCII- )
;( Code der gedrueckten Taste. )
;( ========================================================================= )
NFA_KEY .CBYTE $83, "KEY"
LFA_KEY .WORD NFA_EMIT
CFA_KEY .WORD PFA_KEY
PFA_KEY
XKEY
STX XSAVE ; Datenstackpointer retten
XKEY1
JSR GETCH ; Zeichen von der Tastatur einlesen (im accu)
LDX XSAVE ; Datenstackpointer wiederherstellen
JMP PUSHOA ; Akkumulator als c auf den Datenstack und fertig
; >>>>>>>>>>>>>>>> ?TERMINAL <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( ?TERMINAL [ -> f ] liefert f=1 zurueck, wenn eine Taste betaetigt wurde, )
;( sonst f=0. )
;( ========================================================================= )
NFA_QUERYTERMINAL .CBYTE $89, "?TERMINAL"
LFA_QUERYTERMINAL .WORD NFA_KEY
CFA_QUERYTERMINAL .WORD PFA_QUERYTERMINAL
PFA_QUERYTERMINAL
XQTER
CH = $02FC
LDA CH ; wenn $FF dann keine Taste gedrückt
CLC
ADC #1 ; +1 = 0 wenn keine Taste gedrückt
BEQ XQTER1
LDA #1 ; ansonsten 1
XQTER1
JMP PUSHOA ; Akkumulator auf den Datenstack legen und fertig
; >>>>>>>>>>>>>>>> CR <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( CR [ ] gibt einen Zeilenvorschub auf den Bildschirm aus. )
;( ========================================================================= )
NFA_CR .CBYTE $82, "CR"
LFA_CR .WORD NFA_QUERYTERMINAL
CFA_CR .WORD PFA_CR
PFA_CR
XCR STX XSAVE ; Datenstackpointer retten
TYA
PHA ; Y Register retten
LDA #155 ; Carriage Return
JSR OUTCH ; auf dem Bildschirm ausgeben
LDX XSAVE ; Datenstackpointer wiederherstellen
PLA ; Y Register wiederherstellen
TAY
JMP NEXT ; und fertig
; >>>>>>>>>>>>>>>> CMOVE <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( CMOVE [ from to count ] kopiert von Adresse from nach Adresse to genau )
;( count Bytes in aufsteigender Richtung. )
;( ========================================================================= )
NFA_CMOVE .CBYTE $85, "CMOVE"
LFA_CMOVE .WORD NFA_CR
CFA_CMOVE .WORD PFA_CMOVE
PFA_CMOVE
LDA #3 ; alle drei Parameter
JSR SETUP ; in den Speicherbereich ab Adresse N poppen
L370 CPY N ; noch nicht count Bytes kopiert?
BNE L375 ; dann verzweigen
DEC N+1 ; auch Hi-Byte von count beruecksichtigen
BPL L375 ; und verzweigen, wenn noch Bytes zu kopieren sind
JMP NEXT ; sonst fertig
L375 LDA (N+4),Y ; ein Byte holen
STA (N+2),Y ; und im Zielbereich ablegen
INY ; naechstes Byte anvisieren
BNE L370 ; bei Ueberlauf des Y-Registers:
INC N+5 ; Hi-Byte von from inkrementieren
INC N+3 ; Hi-Byte von to inkrementieren
JMP L370 ; und weiterkopieren
; >>>>>>>>>>>>>>>> U* <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( U* [ u1 u2 -> ud ] multipliziert die beiden vorzeichenlosen Zahlen u1 und )
;( u2 und gibt das Ergebnis als doppeltgenaue, vorzeichenlose Zahl ud )
;( zurueck. )
;( ========================================================================= )
NFA_UMULT .CBYTE $82, "U*"
LFA_UMULT .WORD NFA_CMOVE
CFA_UMULT .WORD PFA_UMULT
PFA_UMULT
LDA 2,X ; u1 nach N/N+1 retten
STA N ; und ud auf Null setzen (Y=0)
STY 2,X
LDA 3,X
STA N+1
STY 3,X
LDY #16 ; Y-Register als Zaehler (16 Bit)
L396 ASL 2,X ; Zwischenergebnis ud verdoppeln
ROL 3,X
ROL 0,X ; und rechts in u2 hineinschieben
ROL 1,X ; dabei das jetzt hoechste Bit von u2 holen
BCC L411 ; Bit=0, dann verzweigen
CLC
LDA N ; sonst das gerettete u1 auf ud aufaddieren
ADC 2,X
STA 2,X
LDA N+1
ADC 3,X
STA 3,X
LDA #0 ; auch das Hi-Word von ud beruecksichtigen
ADC 0,X
STA 0,X
L411 DEY ; naechstes Bit anvisieren
BNE L396 ; noch nicht alle Bits durch, dann weiterrechnen
JMP NEXT ; sonst fertig
; >>>>>>>>>>>>>>>> U/ <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( U/ [ ud u1 -> u2 u3 ] dividiert die doppelt genaue, vorzeichenlose Zahl )
;( ud durch die vorzeichenlose Zahl u1 und uebergibt den Quotienten u3 und )
;( den Rest u2 als vorzeichenlose Zahlen. )
;( ========================================================================= )
NFA_UDIV .CBYTE $82, "U/"
LFA_UDIV .WORD NFA_UMULT
CFA_UDIV .WORD PFA_UDIV
PFA_UDIV
LDA 4,X ; Hi-Word von ud nach [4/5,X] bringen
LDY 2,X ; und Lo-Word von ud nach [2/3,X]
STY 4,X ; wobei das Lo-Word bereits einmal verdoppelt wird
ASL A
STA 2,X
LDA 5,X
LDY 3,X
STY 5,X
ROL A
STA 3,X
LDA #16 ; Schleife wird 16 mal durchlaufen
STA N ; N ist Schleifenzaehler
L433 ROL 4,X ; Hi-Word von ud verdoppeln
ROL 5,X
SEC
LDA 4,X ; u1 vom Hi-Word von ud abziehen
SBC 0,X ; Ergebnis nach Y/A
TAY
LDA 5,X
SBC 1,X
BCC L444 ; falls Ergebnis nicht negativ:
STY 4,X ; Subtraktion an ud tatsaechlich durchfuehren
STA 5,X
L444 ROL 2,X ; Lo-Word von ud nach links schieben
ROL 3,X ; dabei eventuell eine 1 in den Quotienten hineinschieben
DEC N ; naechstes Bit anvisieren
BNE L433 ; noch nicht alle Bits durch, dann weitermachen
JMP POP ; sonst u1 vom Datenstack entfernen und fertig
; >>>>>>>>>>>>>>>> AND <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( AND [ n1 n2 -> n3 ] ermittelt die bitweise Und-Verknuepfung der Zahlen n1 )
;( und n2. )
;( ========================================================================= )
NFA_AND .CBYTE $83, "AND"
LFA_AND .WORD NFA_UDIV
CFA_AND .WORD PFA_AND
PFA_AND
LDA 0,X ; Lo-Byte von n1 AND n2 berechnen
AND 2,X
PHA
LDA 1,X ; Hi-Byte von n1 AND n2 berechnen
AND 3,X
BINARY
INX ; n2 vom Datenstack entfernen
INX
JMP PUT ; Ergebnis auf den Datenstack legen und fertig
; >>>>>>>>>>>>>>>> OR <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( OR [ n1 n2 -> n3 ] ermittelt die bitweise Oder-Verknuepfung der Zahlen )
;( n1 und n2. )
;( ========================================================================= )
NFA_OR .CBYTE $82, "OR"
LFA_OR .WORD NFA_AND
CFA_OR .WORD PFA_OR
PFA_OR
LDA 0,X ; Lo-Byte von n1 OR n2 berechnen
ORA 2,X
PHA
LDA 1,X ; Hi-Byte von n1 OR n2 berechnen
ORA 3,X
INX ; n2 vom Datenstack entfernen
INX
JMP PUT ; Ergebnis auf den Datenstack legen und fertig
; >>>>>>>>>>>>>>>> XOR <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( XOR [ n1 n2 -> n3 ] ermittelt die bitweise Exklusiv-Oder-Verknuepfung der )
;( Zahlen n1 und n2. )
;( ========================================================================= )
NFA_XOR .CBYTE $83, "XOR"
LFA_XOR .WORD NFA_OR
CFA_XOR .WORD PFA_XOR
PFA_XOR
LDA 0,X ; Lo-Byte von n1 XOR n2 berechnen
EOR 2,X
PHA
LDA 1,X ; Hi-Byte von n1 XOR n2 berechnen
EOR 3,X
INX ; n2 vom Datenstack entfernen
INX
JMP PUT ; Ergebnis auf den Datenstack legen und fertig
; >>>>>>>>>>>>>>>> SP@ <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( SP@ [ -> addr ] ermittelt die Adresse des TOS [vor dem Aufruf]. )
;( ========================================================================= )
NFA_SPFETCH .CBYTE $83, "SP@"
LFA_SPFETCH .WORD NFA_XOR
CFA_SPFETCH .WORD PFA_SPFETCH
PFA_SPFETCH
TXA ; Adresse des TOS wird durch das X-Register angegeben
PUSHOA
PHA ; Akkumulator als Lo-Byte
LDA #0 ; und 0 als Hi-Byte
JMP PUSH ; auf den Datenstack legen und fertig
; >>>>>>>>>>>>>>>> SP! <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( SP! [ ] reinitialisiert den Stack-Pointer. )
;( ========================================================================= )
NFA_SPSTORE .CBYTE $83, "SP!"
LFA_SPSTORE .WORD NFA_SPFETCH
CFA_SPSTORE .WORD PFA_SPSTORE
PFA_SPSTORE
LDY #6 ; User-Variable S0 enthaelt Initialwert des Datenstackpointers
LDA (UP),Y ; Inhalt der User-Variablen holen
TAX ; in den Datenstackpointer X laden
JMP NEXT ; und fertig
; >>>>>>>>>>>>>>>> RP! <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( RP! [ ] reinitialisiert den Return-Stack-Pointer. )
;( ========================================================================= )
NFA_RPSTORE .CBYTE $83, "RP!"
LFA_RPSTORE .WORD NFA_SPSTORE
CFA_RPSTORE .WORD PFA_RPSTORE
PFA_RPSTORE
STX XSAVE ; Datenstackpointer retten
LDY #8 ; User-Variable R0 enthaelt Initialwert des Returnstackpointers
LDA (UP),Y ; Inhalt der User-Variablen holen
TAX ; und in den Returnstackpointer laden
TXS
LDX XSAVE ; Datenstackpointer wiederherstellen
JMP NEXT ; und fertig
; >>>>>>>>>>>>>>>> ;S <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( ;S [ ] beendet die Ausfuehrung des aktuellen Wortes und kehrt zum aufru- )
;( fenden Wort zurueck. )
;( ========================================================================= )
NFA_EXIT .CBYTE $82, ";S"
LFA_EXIT .WORD NFA_RPSTORE
CFA_EXIT .WORD PFA_EXIT
PFA_EXIT
PLA ; Returnadresse vom Returnstack poppen
STA IP ; und in den IP laden
PLA
STA IP+1
JMP NEXT ; und fertig
; >>>>>>>>>>>>>>>> LEAVE <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( LEAVE [ ] erzwingt das Verlassen der aktuellen DO ... LOOP - oder DO ... )
;( +LOOP - Schleife, indem der Abbruchwert auf den Stand des aktuellen )
;( Index-Wertes gesetzt wird. )
;( ========================================================================= )
NFA_LEAVE .CBYTE $85, "LEAVE"
LFA_LEAVE .WORD NFA_EXIT
CFA_LEAVE .WORD PFA_LEAVE
PFA_LEAVE
STX XSAVE ; Datenstackpointer retten
TSX ; X-Register als Index in den Returnstack benutzen
LDA $101,X ; Limit auf den Wert des Schleifenzaehlers I setzen
STA $103,X
LDA $102,X
STA $104,X
LDX XSAVE ; Datenstackpointer wiederherstellen
JMP NEXT ; und fertig
; >>>>>>>>>>>>>>>> >R <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( >R [ n -> ] legt die Zahl n auf den Return-Stack. )
;( ========================================================================= )
NFA_RPUSH .CBYTE $82, ">R"
LFA_RPUSH .WORD NFA_LEAVE
CFA_RPUSH .WORD PFA_RPUSH
PFA_RPUSH
LDA 1,X ; HI-Byte von n
PHA ; auf den Returnstack pushen
LDA 0,X ; Lo-Byte von n
PHA ; auf den Returnstack pushen
INX ; n vom Datenstack entfernen
INX
JMP NEXT ; und fertig
; >>>>>>>>>>>>>>>> R> <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( R> [ -> n ] poppt das oberste Element vom Return-Stack und legt es auf )
;( den Parameterstack. )
;( ========================================================================= )
NFA_RPOP .CBYTE $82, "R>"
LFA_RPOP .WORD NFA_RPUSH
CFA_RPOP .WORD PFA_RPOP
PFA_RPOP
DEX ; Platz auf dem Datenstack fuer n schaffen
DEX
PLA ; Lo-Byte vom Returnstack poppen
STA 0,X ; und in den Datenstack schreiben
PLA ; Hi-Byte vom Returnstack poppen
STA 1,X ; und in den Datenstack schreiben
JMP NEXT ; und fertig
; >>>>>>>>>>>>>>>> 0= <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( 0= [ n -> f ] uebergibt f=true, wenn die Zahl n gleich Null ist, sonst )
;( false. )
;( ========================================================================= )
NFA_NULLEQUAL .CBYTE $82, "0="
LFA_NULLEQUAL .WORD NFA_RPOP
CFA_NULLEQUAL .WORD PFA_NULLEQUAL
PFA_NULLEQUAL
LDA 0,X ; n testen
ORA 1,X
STY 1,X ; Hi-Byte von f auf Null setzen (Y=0)
BNE L613 ; Lo-Byte von f auf 1 setzen, falls n=0
INY
L613 STY 0,X
JMP NEXT ; und fertig
; >>>>>>>>>>>>>>>> 0< <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( 0< [ n -> f ] uebergibt f=true, wenn die Zahl n kleiner Null ist, sonst )
;( false. )
;( ========================================================================= )
NFA_LTNULL .CBYTE $82, "0<"
LFA_LTNULL .WORD NFA_NULLEQUAL
CFA_LTNULL .WORD PFA_LTNULL
PFA_LTNULL
ASL 1,X ; hoechstes Bit von n holen
TYA ; und im Akkumulator zu 1 oder 0 werden lassen (Y=0)
ROL A
STY 1,X ; Hi-Byte von f auf Null setzen
STA 0,X ; Lo-Byte von f auf obiges Ergebnis setzen
JMP NEXT ; und fertig
; >>>>>>>>>>>>>>>> + <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( + [ n1 n2 -> n3 ] berechnet die Summe der Zahlen n1 und n2. )
;( ========================================================================= )
NFA_PLUS .CBYTE $81, "+"
LFA_PLUS .WORD NFA_LTNULL
CFA_PLUS .WORD PFA_PLUS
PFA_PLUS
CLC
LDA 0,X ; Summe n3.=n1+n2 berechnen und in den Datenstack schreiben
ADC 2,X
STA 2,X
LDA 1,X
ADC 3,X
STA 3,X
INX ; n3 vom Datenstack entfernen
INX
JMP NEXT ; und fertig
; >>>>>>>>>>>>>>>> D+ <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( D+ [ d1 d2 -> Summe ] berechnet die doppeltgenaue Summe der beiden )
;( doppeltgenauen Zahlen d1 und d2. )
;( ========================================================================= )
NFA_DPLUS .CBYTE $82, "D+"
LFA_DPLUS .WORD NFA_PLUS
CFA_DPLUS .WORD PFA_DPLUS
PFA_DPLUS
CLC
LDA 2,X ; Lo-Word der Summe berechnen
ADC 6,X
STA 6,X
LDA 3,X
ADC 7,X
STA 7,X
LDA 0,X ; Hi-Word der Summe berechnen
ADC 4,X
STA 4,X
LDA 1,X
ADC 5,X
STA 5,X
JMP POPTWO ; d2 vom Stack entfernen und fertig
; >>>>>>>>>>>>>>>> MINUS <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( MINUS [ n1 -> n2 ] negiert die Zahl n1. )
;( ========================================================================= )
NFA_NEGATE .CBYTE $85, "MINUS"
LFA_NEGATE .WORD NFA_DPLUS
CFA_NEGATE .WORD PFA_NEGATE
PFA_NEGATE
SEC
MINUS1
TYA
SBC 0,X ; Differenz 0-n1 berechnen (Y=0)
STA 0,X
TYA
SBC 1,X
STA 1,X
JMP NEXT ; und fertig
; >>>>>>>>>>>>>>>> DMINUS <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( DMINUS [ d1 -> d2 ] negiert die doppeltgenaue Zahl d1. )
;( ========================================================================= )
NFA_DMINUS .CBYTE $86, "DMINUS"
LFA_DMINUS .WORD NFA_NEGATE
CFA_DMINUS .WORD PFA_DMINUS
PFA_DMINUS
SEC
TYA
SBC 2,X ; Lo-Word der Differenz 0-d1 berechnen (Y=0)
STA 2,X
TYA
SBC 3,X
STA 3,X
JMP MINUS1 ; Hi-Word der Differenz berechnen und fertig
; >>>>>>>>>>>>>>>> OVER <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( OVER [ n1 n2 -> n1 n2 n1 ] legt den Second auf den Stack. )
;( ========================================================================= )
NFA_OVER .CBYTE $84, "OVER"
LFA_OVER .WORD NFA_DMINUS
CFA_OVER .WORD PFA_OVER
PFA_OVER
LDA 2,X ; n1 holen
PHA
LDA 3,X
JMP PUSH ; auf den Datenstack legen und fertig
; >>>>>>>>>>>>>>>> DROP <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( DROP [ n -> ] entfernt das oberste Element vom Stack. )
;( ========================================================================= )
NFA_DROP .CBYTE $84, "DROP"
LFA_DROP .WORD NFA_OVER
CFA_DROP .WORD POP
PFA_DROP
; >>>>>>>>>>>>>>>> SWAP <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( SWAP [ n1 n2 -> n2 n1 ] vertauscht die beiden obersten Stack-Elemente. )
;( ========================================================================= )
NFA_SWAP .CBYTE $84, "SWAP"
LFA_SWAP .WORD NFA_DROP
CFA_SWAP .WORD PFA_SWAP
PFA_SWAP
LDA 2,X ; Lo-Byte von n1 holen
PHA ; und merken
LDA 0,X ; Lo-Byte von n2 holen
STA 2,X ; und damit das Lo-Byte von n1 ueberschreiben
LDA 3,X ; Hi-Byte von n1 holen und im Akkumulator merken
LDY 1,X ; Hi-Byte von n2 holen
STY 3,X ; und damit das Hi-Byte von n1 ueberschreiben
JMP PUT ; gemerktes n1 in den Datenstack schreiben und fertig
; >>>>>>>>>>>>>>>> PICK <<<<<<<<<<<<<<<
;( ========================================================================= )
;( PICK [ n1 -> n2 ] holt das n-te Element des Stacks )
;( ========================================================================= )
NFA_PICK .CBYTE $84, "PICK"
LFA_PICK .WORD NFA_SWAP
CFA_PICK .WORD PFA_PICK
PFA_PICK
STX XSAVE ; Stackzeiger sichern
TXA ; Stackzeiger in den Accu
SEC
ADC 0,X ; Lo-Byte von n1 holen,
ADC 0,X ; verdoppeln und zum Stackzeiger addieren
TAX
DEX ; in den Stackzeiger schieben, zeigt nun auf Element n1
LDA 0,X ; Lo-Byte von n2 holen
PHA ; und merken
LDA 1,X ; Hi-Byte von n2 holen
LDX XSAVE
JMP PUT ; gemerktes n2 in den Datenstack schreiben und fertig
; >>>>>>>>>>>>>>>> DUP <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( DUP [ n -> n n ] dupliziert das oberste Stack-Element. )
;( ========================================================================= )
NFA_DUP .CBYTE $83, "DUP"
LFA_DUP .WORD NFA_PICK
CFA_DUP .WORD PFA_DUP
PFA_DUP
LDA 0,X ; n holen
PHA
LDA 1,X
JMP PUSH ; auf den Datenstack pushen und fertig
; >>>>>>>>>>>>>>>> +! <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( +! [ n addr -> ] inkrementiert die Zahl, auf die die Adresse addr zeigt, )
;( um n. )
;( ========================================================================= )
NFA_PLUSSTORE .CBYTE $82,"+!"
LFA_PLUSSTORE .WORD NFA_DUP
CFA_PLUSSTORE .WORD PFA_PLUSSTORE
PFA_PLUSSTORE
CLC
LDA (0,X) ; Lo-Byte der durch addr adressierten Zahl
ADC 2,X ; plus Lo-Byte von n
STA (0,X) ; an der Adresse addr ablegen
INC 0,X ; addr inkrementieren
BNE L754
INC 1,X
L754 LDA (0,X) ; Hi-Byte der durch addr adressierten Zahl
ADC 3,X ; plus Hi-Byte von n
STA (0,X) ; an der Adresse addr+1 ablegen
JMP POPTWO ; n und addr vom Datenstack entfernen und fertig
; >>>>>>>>>>>>>>>> TOGGLE <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( TOGGLE [ addr b -> ] fuehrt eine bitweise Exklusiv-Oder-Verknuepfung des )
;( durch addr adressierten Bytes mit dem Bitmuster b durch. )
;( ========================================================================= )
NFA_TOGGLE .CBYTE $86, "TOGGLE"
LFA_TOGGLE .WORD NFA_PLUSSTORE
CFA_TOGGLE .WORD PFA_TOGGLE
PFA_TOGGLE
LDA (2,X) ; durch addr adressiertes Byte holen
EOR 0,X ; mit b XOR-verknuepfen
STA (2,X) ; und wieder im Speicher ablegen
JMP POPTWO ; addr und b vom Datenstack entfernen und fertig
; >>>>>>>>>>>>>>>> @ <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( @ [ addr -> n ] ermittelt die durch addr adressierte Zahl. )
;( ========================================================================= )
NFA_FETCH .CBYTE $81, "@"
LFA_FETCH .WORD NFA_TOGGLE
CFA_FETCH .WORD PFA_FETCH
PFA_FETCH
LDA (0,X) ; Lo-Byte der durch addr adressierten Zahl holen
PHA ; und merken
INC 0,X ; addr inkrementieren
BNE L781
INC 1,X
L781 LDA (0,X) ; Hi-Byte holen und im Akkumulator merken
JMP PUT ; gemerkte Zahl in den Datenstack schreiben und fertig
; >>>>>>>>>>>>>>>> C@ <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( C@ [ addr -> b ] ermittelt das durch addr adressierte Byte. )
;( ========================================================================= )
NFA_CFETCH .CBYTE $82, "C@"
LFA_CFETCH .WORD NFA_FETCH
CFA_CFETCH .WORD PFA_CFETCH
PFA_CFETCH
LDA (0,X) ; durch addr adressiertes Byte holen
STA 0,X ; und in den Datenstack schreiben
STY 1,X ; Hi-Byte auf Null setzen (Y=0)
JMP NEXT ; und fertig
; >>>>>>>>>>>>>>>> ! <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( ! [ n addr -> ] speichert die Zahl n an die Adresse addr. )
;( ========================================================================= )
NFA_STORE .CBYTE $81, "!"
LFA_STORE .WORD NFA_CFETCH
CFA_STORE .WORD PFA_STORE
PFA_STORE
LDA 2,X ; Lo-Byte von n holen
STA (0,X) ; und bei addr abspeichen
INC 0,X ; addr inkrementieren
BNE L806
INC 1,X
L806 LDA 3,X ; Hi-Byte von n holen
STA (0,X) ; und bei addr+1 abspeichern
JMP POPTWO ; n und addr vom Datenstack entfernen
; >>>>>>>>>>>>>>>> C! <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( C! [ b addr -> ] speichert das Byte b an die Adresse addr. )
;( ========================================================================= )
NFA_CSTORE .CBYTE $82, "C!"
LFA_CSTORE .WORD NFA_STORE
CFA_CSTORE .WORD PFA_CSTORE
PFA_CSTORE
LDA 2,X ; Byte b holen
STA (0,X) ; und bei addr abspeichern
JMP POPTWO ; b und addr vom Datenstack entfernen und fertig
; >>>>>>>>>>>>>>>> : <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( : [ ] leitet eine Colon-Definition ein. )
;( ========================================================================= )
NFA_COLON .BYTE $81+$40, 186 ; IMMEDIATE
LFA_COLON .WORD NFA_CSTORE
CFA_COLON .WORD DOCOL
PFA_COLON
.WORD CFA_QUERYEXEC ; ?EXEC
.WORD CFA_STORECSP ; !CSP
.WORD CFA_CURRENT ; CURRENT
.WORD CFA_FETCH ; @
.WORD CFA_CONTEXT ; CONTEXT
.WORD CFA_STORE ; !
.WORD CFA_CREATE ; CREATE
.WORD CFA_RIGHTBRACKET ; ]
.WORD CFA_BRACKETCODE ; (;CODE)
; das neue Wort fuehrt zunaechst folgenden Code aus:
DOCOL
LDA IP+1 ; Instruction Pointer IP auf den Returnstack pushen
PHA
LDA IP
PHA
.IF debug
PHA
LDA DEBUGFLG
BEQ DL2
JSR TCOLON ; DEBUG
DL2 PLA
.ENDIF
CLC
LDA W ; Wortadressregister
ADC #2 ; plus zwei ergibt Adresse des ersten Tokens
STA IP ; dort mit der Interpretation fortfahren
TYA
ADC W+1 ; auch Hi-Byte des IP beruecksichtigen (Y=0)
STA IP+1
JMP NEXT ; Interpretation an neuer Stelle fortsetzen
; >>>>>>>>>>>>>>>> ; <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( ; [ ] schliesst eine Colon-Definition ab. )
;( ========================================================================= )
; : ;
; ?CSP ( ueberpruefen, ob die Stackposition noch die alte ist )
; COMPILE ;S ( Semis an das Ende des Wortes kompilieren )
; SMUDGE ( Wort gueltig machen )
; [COMPILE] [ ( in den Execute-Mode uebergehen )
; ; IMMEDIATE
NFA_SEMIS .BYTE $81+$40, 187 ; IMMEDIATE
LFA_SEMIS .WORD NFA_COLON
CFA_SEMIS .WORD DOCOL
PFA_SEMIS
.WORD CFA_QUERYCSP ; ?CSP
.WORD CFA_COMPILE ; COMPILE
.WORD CFA_EXIT ; ;S
.WORD CFA_SMUDGE ; SMUDGE
.WORD CFA_LEFTBRACKET ; [
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> CONSTANT <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( CONSTANT [ n -> ] definiert eine Konstante. )
;( ========================================================================= )
NFA_CONSTANT .CBYTE $88, "CONSTANT"
LFA_CONSTANT .WORD NFA_SEMIS
CFA_CONSTANT .WORD DOCOL
PFA_CONSTANT
.WORD CFA_CREATE ; CREATE
.WORD CFA_SMUDGE ; SMUDGE
.WORD CFA_COMMA ; ,
.WORD CFA_BRACKETCODE ; (;CODE)
; das neue Wort fuehrt den folgenden Code aus:
DOCON LDY #2
LDA (W),Y ; Lo-Byte des Wertes n im Parameterfeld holen
PHA ; und merken
INY ; Hi-Byte von n anvisieren
LDA (W),Y ; und holen
JMP PUSH ; n auf den Datenstack pushen und fertig
; >>>>>>>>>>>>>>>> VARIABLE <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( VARIABLE [ n -> ] definiert und initialisiert eine Variable. )
;( ========================================================================= )
NFA_VARIABLE .CBYTE $88,"VARIABLE"
LFA_VARIABLE .WORD NFA_CONSTANT
CFA_VARIABLE .WORD DOCOL
PFA_VARIABLE
.WORD CFA_CONSTANT ; CONSTANT
.WORD CFA_BRACKETCODE ; (;CODE)
; aber bei Aufruf den folgenden Code ausfuehren:
DOVAR CLC
LDA W ; Lo-Byte der PFA der Variablen ermitteln
ADC #2
PHA ; und merken
TYA
ADC W+1 ; Hi-Byte der PFA ermitteln und merken
JMP PUSH ; PFA auf den Datenstack pushen und fertig
; >>>>>>>>>>>>>>>> USER <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( USER [ n -> ] definiert eine User-Variable mit dem Offset n. )
;( ========================================================================= )
NFA_USER .CBYTE $84, "USER"
LFA_USER .WORD NFA_VARIABLE
CFA_USER .WORD DOCOL
PFA_USER
.WORD CFA_CONSTANT ; CONSTANT
.WORD CFA_BRACKETCODE ; (;CODE)
; aber bei Aufruf den folgenden Code ausfuehren:
DOUSE
LDY #2
CLC
LDA (W),Y ; Lo-Byte des Offsets der Uservariablen
ADC UP ; plus Userpointer ergibt Adresse der Uservariablen
PHA ; merken
LDA #0
ADC UP+1 ; Hi-Byte holen und im Akkumulator merken
JMP PUSH ; gemerkte Adresse auf den Datenstack legen und fertig
NFA_PREV .= NFA_USER
;( ========================================================================= )
;( Definition diverser Konstanten. )
;( ========================================================================= )
; >>>>>>>>>>>>>>>> 0 <<<<<<<<<<<<<<<<
; CONSTANT 0 ( Null )
NFA_0 .CBYTE $81, "0"
LFA_0 .WORD NFA_PREV
CFA_0 .WORD DOCON
PFA_0 .WORD 0
; >>>>>>>>>>>>>>>> 1 <<<<<<<<<<<<<<<<
; CONSTANT 1 ( Eins )
NFA_1 .CBYTE $81, "1"
LFA_1 .WORD NFA_0
CFA_1 .WORD DOCON
PFA_1 .WORD 1
; >>>>>>>>>>>>>>>> 2 <<<<<<<<<<<<<<<<
; CONSTANT 2 ( Zwei )
NFA_2 .CBYTE $81,"2"
LFA_2 .WORD NFA_1
CFA_2 .WORD DOCON
PFA_2 .WORD 2
; >>>>>>>>>>>>>>>> 3 <<<<<<<<<<<<<<<<
; CONSTANT 3 ( Drei )
NFA_3 .CBYTE $81, "3"
LFA_3 .WORD NFA_2
CFA_3 .WORD DOCON
PFA_3 .WORD 3
; >>>>>>>>>>>>>>>> BL <<<<<<<<<<<<<<<<
; CONSTANT BL ( Blank )
NFA_BL .CBYTE $82, "BL"
LFA_BL .WORD NFA_3
CFA_BL .WORD DOCON
PFA_BL .WORD 32
; >>>>>>>>>>>>>>>> ABORTINIT <<<<<<<<<<<<<<<<
; CONSTANT ABORTINIT ( ABORT INIT ADRESSE )
NFA_ABORTINIT .CBYTE $89, "ABORTINIT"
LFA_ABORTINIT .WORD NFA_BL
CFA_ABORTINIT .WORD DOCON
PFA_ABORTINIT .WORD ABORTINIT
NFA_PREV .= NFA_ABORTINIT
.IF debug
;( ========================================================================= )
;( Definition Debug Flag. )
;( ========================================================================= )
; >>>>>>>>>>>>>>>> DEBUGFLAG <<<<<<<<<<<<<<<<
; CONSTANT 0 ( Null )
NFA_DEBUGFLAG .CBYTE $89, "DEBUGFLAG"
LFA_DEBUGFLAG .WORD NFA_PREV
CFA_DEBUGFLAG .WORD DOCON
PFA_DEBUGFLAG .WORD DEBUGFLG
NFA_PREV .= NFA_DEBUGFLAG
; >>>>>>>>>>>>>>>> DEBUGON <<<<<<<<<<<<<<<<
NFA_DEBUGON .CBYTE $87, "DEBUGON"
LFA_DEBUGON .WORD NFA_PREV
CFA_DEBUGON .WORD DOCOL
PFA_DEBUGON
.WORD CFA_CLIT
.BYTE 1 ; 1
.WORD CFA_DEBUGFLAG ; DEBUGFLAG
.WORD CFA_STORE ; !
.WORD CFA_EXIT ; ;S
NFA_PREV .= NFA_DEBUGON
; >>>>>>>>>>>>>>>> DEBUGOFF <<<<<<<<<<<<<<<<
NFA_DEBUGOFF .CBYTE $88, "DEBUGOFF"
LFA_DEBUGOFF .WORD NFA_PREV
CFA_DEBUGOFF .WORD DOCOL
PFA_DEBUGOFF
.WORD CFA_CLIT
.BYTE 0 ; 0
.WORD CFA_DEBUGFLAG ; DEBUGFLAG
.WORD CFA_STORE ; !
.WORD CFA_EXIT ; ;S
NFA_PREV .= NFA_DEBUGOFF
.ENDIF ; DEBUG
; >>>>>>>>>>>>>>>> +ORIGIN <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( +ORIGIN [ n -> addr ] uebergibt die Adresse Origin+n. Origin ist die )
;( tiefste Adresse im Forth-Kern. )
;( ========================================================================= )
NFA_PLUSORIGIN .CBYTE $87, "+ORIGIN"
LFA_PLUSORIGIN .WORD NFA_PREV
CFA_PLUSORIGIN .WORD DOCOL
PFA_PLUSORIGIN
.WORD CFA_LIT ; LIT
.WORD ORIG
.WORD CFA_PLUS ; +
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> S0 <<<<<<<<<<<<<<<<
; 6 USER S0 ( Initialisierungswert fuer Daten-Stack-Pointer )
NFA_S0 .CBYTE $82, "S0"
LFA_S0 .WORD NFA_PLUSORIGIN
CFA_S0 .WORD DOUSE
PFA_S0 .WORD 6
; >>>>>>>>>>>>>>>> R0 <<<<<<<<<<<<<<<<
; 8 USER R0 ( Initialisierungswert fuer Return-Stack-Pointer )
NFA_R0 .CBYTE $82, "R0"
LFA_R0 .WORD NFA_S0
CFA_R0 .WORD DOUSE
PFA_R0 .WORD 8
; >>>>>>>>>>>>>>>> TIB <<<<<<<<<<<<<<<<
; 10 USER TIB ( Startadresse des Terminal-Input-Buffers )
NFA_TIB .CBYTE $83, "TIB"
LFA_TIB .WORD NFA_R0
CFA_TIB .WORD DOUSE
PFA_TIB .WORD 10
; >>>>>>>>>>>>>>>> WIDTH <<<<<<<<<<<<<<<<
; 12 USER WIDTH ( Maximallaenge von Forth-Namen )
NFA_WIDTH .CBYTE $85, "WIDTH"
LFA_WIDTH .WORD NFA_TIB
CFA_WIDTH .WORD DOUSE
PFA_WIDTH .WORD 12
; >>>>>>>>>>>>>>>> WARNING <<<<<<<<<<<<<<<<
; 14 USER WARNING ( Kontrollvariable fuer Systembotschaften )
NFA_WARNING .CBYTE $87, "WARNING"
LFA_WARNING .WORD NFA_WIDTH
CFA_WARNING .WORD DOUSE
PFA_WARNING .WORD 14
; >>>>>>>>>>>>>>>> FENCE <<<<<<<<<<<<<<<<
; 16 USER FENCE ( unterste Adresse des mit FORGET loeschbaren Bereichs )
NFA_FENCE .CBYTE $85, "FENCE"
LFA_FENCE .WORD NFA_WARNING
CFA_FENCE .WORD DOUSE
PFA_FENCE .WORD 16
; >>>>>>>>>>>>>>>> DP <<<<<<<<<<<<<<<<
; 18 USER DP ( Dictionary Pointer )
NFA_DP .CBYTE $82, "DP"
LFA_DP .WORD NFA_FENCE
CFA_DP .WORD DOUSE
PFA_DP .WORD 18
; >>>>>>>>>>>>>>>> VOC-LINK <<<<<<<<<<<<<<<<
; 20 USER VOC-LINK ( Adresse einer Zelle in der Definition des letzten Vokab. )
NFA_VOCLINK .CBYTE $88, "VOC-LINK"
LFA_VOCLINK .WORD NFA_DP
CFA_VOCLINK .WORD DOUSE
PFA_VOCLINK .WORD 20
; >>>>>>>>>>>>>>>> SOURCE-ID <<<<<<<<<<<<<<<<
; 22 USER SOURCE-ID ( Nummer des geoffneten Kanals )
NFA_SOURCEID .CBYTE $89,"SOURCE-ID"
LFA_SOURCEID .WORD NFA_VOCLINK
CFA_SOURCEID .WORD DOUSE
PFA_SOURCEID .WORD 22
; >>>>>>>>>>>>>>>> IN <<<<<<<<<<<<<<<<
; 24 USER IN ( Byte-Offset im gegenwaertigen Eingabe-Textbuffer )
NFA_IN .CBYTE $82, "IN"
LFA_IN .WORD NFA_SOURCEID
CFA_IN .WORD DOUSE
PFA_IN .WORD 24
; >>>>>>>>>>>>>>>> OUT <<<<<<<<<<<<<<<<
; 26 USER OUT ( Anzahl mittels EMIT ausgegebener Zeichen )
NFA_OUT .CBYTE $83, "OUT"
LFA_OUT .WORD NFA_IN
CFA_OUT .WORD DOUSE
PFA_OUT .WORD 26
; >>>>>>>>>>>>>>>> SCR <<<<<<<<<<<<<<<<
; 28 USER SCR ( Nummer des zuletzt aufgerufenen Screens )
NFA_SCR .CBYTE $83, "SCR"
LFA_SCR .WORD NFA_OUT
CFA_SCR .WORD DOUSE
PFA_SCR .WORD 28
; >>>>>>>>>>>>>>>> OFFSET <<<<<<<<<<<<<<<<
; 30 USER OFFSET ( Block-Offset zum Disk-Drive, auf das zugegriffen wird )
NFA_OFFSET .CBYTE $86, "OFFSET"
LFA_OFFSET .WORD NFA_SCR
CFA_OFFSET .WORD DOUSE
PFA_OFFSET .WORD 30
; >>>>>>>>>>>>>>>> CONTEXT <<<<<<<<<<<<<<<<
; 32 USER CONTEXT ( Pointer zum Context-Vokabular )
NFA_CONTEXT .CBYTE $87, "CONTEXT"
LFA_CONTEXT .WORD NFA_OFFSET
CFA_CONTEXT .WORD DOUSE
PFA_CONTEXT .WORD 32
; >>>>>>>>>>>>>>>> CURRENT <<<<<<<<<<<<<<<<
; 34 USER CURRENT ( Pointer zum Current-Vokabular )
NFA_CURRENT .CBYTE $87,"CURRENT"
LFA_CURRENT .WORD NFA_CONTEXT
CFA_CURRENT .WORD DOUSE
PFA_CURRENT .WORD 34
; >>>>>>>>>>>>>>>> STATE <<<<<<<<<<<<<<<<
; 36 USER STATE ( ungleich Null, wenn System im Compile-Mode )
NFA_STATE .CBYTE $85, "STATE"
LFA_STATE .WORD NFA_CURRENT
CFA_STATE .WORD DOUSE
PFA_STATE .WORD 36
; >>>>>>>>>>>>>>>> BASE <<<<<<<<<<<<<<<<
; 38 USER BASE ( gegenwaertig vereinbarte Zahlenbasis )
NFA_BASE .CBYTE $84, "BASE"
LFA_BASE .WORD NFA_STATE
CFA_BASE .WORD DOUSE
PFA_BASE .WORD 38
; >>>>>>>>>>>>>>>> DPL <<<<<<<<<<<<<<<<
; 40 USER DPL ( Anzahl der Digits rechts vom Dezimalpunkt )
NFA_DPL .CBYTE $83, "DPL"
LFA_DPL .WORD NFA_BASE
CFA_DPL .WORD DOUSE
PFA_DPL .WORD 40
; >>>>>>>>>>>>>>>> FLD <<<<<<<<<<<<<<<<
; 42 USER FLD ( Kontrollvariable fuer formatierte I/O )
NFA_FLD .CBYTE $83, "FLD"
LFA_FLD .WORD NFA_DPL
CFA_FLD .WORD DOUSE
PFA_FLD .WORD 42
; >>>>>>>>>>>>>>>> CSP <<<<<<<<<<<<<<<<
; 44 USER CSP ( gesicherter Stackpointer-Stand )
NFA_CSP .CBYTE $83, "CSP"
LFA_CSP .WORD NFA_FLD
CFA_CSP .WORD DOUSE
PFA_CSP .WORD 44
; >>>>>>>>>>>>>>>> R# <<<<<<<<<<<<<<<<
; 46 USER R# ( Position des Editor-Cursors )
NFA_RNUM .CBYTE $82, "R#"
LFA_RNUM .WORD NFA_CSP
CFA_RNUM .WORD DOUSE
PFA_RNUM .WORD 46
; >>>>>>>>>>>>>>>> HLD <<<<<<<<<<<<<<<<
; 48 USER HLD ( Adresse des letzten Zeichens bei Umwandlung Zahl->String )
NFA_HLD .CBYTE $83, "HLD"
LFA_HLD .WORD NFA_RNUM
CFA_HLD .WORD DOUSE
PFA_HLD .WORD 48
; >>>>>>>>>>>>>>>> 1+ <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( 1+ [ n1 -> n2 ] inkrementiert die oberste Zahl auf dem Stack. )
;( ========================================================================= )
;
; : 1+ 1 + ;
NFA_1PLUS .CBYTE $82,"1+"
LFA_1PLUS .WORD NFA_HLD
CFA_1PLUS .WORD DOCOL
PFA_1PLUS
.WORD CFA_1 ; 1
.WORD CFA_PLUS ; +
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> 2+ <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( 2+ [ n1 -> n2 ] inkrementiert die oberste Zahl auf dem Stack um 2. )
;( ========================================================================= )
;
; : 2+ 2 + ;
NFA_2PLUS .CBYTE $82,"2+"
LFA_2PLUS .WORD NFA_1PLUS
CFA_2PLUS .WORD DOCOL
PFA_2PLUS
.WORD CFA_2 ; 2
.WORD CFA_PLUS ; +
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> HERE <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( HERE [ -> addr ] uebergibt die Adresse der ersten freien Stelle im )
;( Dictionary. )
;( ========================================================================= )
;
; : HERE DP @ ; ( Adresse, auf die der Dictionary Pointer zeigt, zurueckgeben )
NFA_HERE .CBYTE $84,"HERE"
LFA_HERE .WORD NFA_2PLUS
CFA_HERE .WORD DOCOL
PFA_HERE
.WORD CFA_DP ; DP
.WORD CFA_FETCH ; @
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> ALLOT <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( ALLOT [ n -> ] vergroessert das Dictionary um n Bytes. Hierbei ist n eine )
;( vorzeichenbehaftete Zahl, kann also auch negativ sein. )
;( ========================================================================= )
;
; : ALLOT DP +! ; ( Dictionary-Pointer um n inkrementieren )
NFA_ALLOT .CBYTE $85,"ALLOT"
LFA_ALLOT .WORD NFA_HERE
CFA_ALLOT .WORD DOCOL
PFA_ALLOT
.WORD CFA_DP ; DP
.WORD CFA_PLUSSTORE ; +!
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> , <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( , [ n -> ] fuegt die Zahl n an das Dictionary an. )
;( ========================================================================= )
;
; : , HERE ! 2 ALLOT ; ( n hinter das Dictionary schreiben und DP erhoehen )
NFA_COMMA .CBYTE $81,","
LFA_COMMA .WORD NFA_ALLOT
CFA_COMMA .WORD DOCOL
PFA_COMMA
.WORD CFA_HERE ; HERE
.WORD CFA_STORE ; !
.WORD CFA_2 ; 2
.WORD CFA_ALLOT ; ALLOT
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> C, <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( C, [ b -> ] fuegt das Byte b an das Dictionary an. )
;( ========================================================================= )
;
; : C, HERE C! 1 ALLOT ; ( b hinter das Dictionary schreiben und DP erhoehen )
NFA_CCOMMA .CBYTE $82,"C,"
LFA_CCOMMA .WORD NFA_COMMA
CFA_CCOMMA .WORD DOCOL
PFA_CCOMMA
.WORD CFA_HERE ; HERE
.WORD CFA_CSTORE ; C!
.WORD CFA_1 ; 1
.WORD CFA_ALLOT ; ALLOT
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> - <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( - [ n1 n2 -> n3 ] berechnet die Differenz n1-n2. )
;( ========================================================================= )
;
; : - MINUS + ; ( n2 negieren und auf n1 aufaddieren )
NFA_MINUS .CBYTE $81,"-"
LFA_MINUS .WORD NFA_CCOMMA
CFA_MINUS .WORD DOCOL
PFA_MINUS
.WORD CFA_NEGATE ; MINUS
.WORD CFA_PLUS ; +
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> = <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( = [ n1 n2 -> f ] vergleicht die Zahlen n1 und n2 und gibt true zurueck, )
;( wenn sie gleich sind, sonst false. )
;( ========================================================================= )
;
; : = - 0= ; ( Differenz von n1 und n2 auf Gleichheit mit 0 testen )
NFA_EQUAL .CBYTE $81,"="
LFA_EQUAL .WORD NFA_MINUS
CFA_EQUAL .WORD DOCOL
PFA_EQUAL
.WORD CFA_MINUS ; -
.WORD CFA_NULLEQUAL ; 0=
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> U< <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( U< [ u1 u2 -> f ] liefert f=true, wenn u1<u2 ist, wobei u1 und u2 als )
;( vorzeichenlose Zahlen aufgefasst werden. )
;( ========================================================================= )
;
; : U< - 0< ; ( vergleichen durch Subtraktion )
NFA_ULT .CBYTE $82,"U<"
LFA_ULT .WORD NFA_EQUAL
CFA_ULT .WORD DOCOL
PFA_ULT
.WORD CFA_MINUS ; -
.WORD CFA_LTNULL ; 0<
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> < <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( < [ n1 n2 -> f ] liefert f=true, wenn n1<n2 ist. )
;( ========================================================================= )
NFA_LT .CBYTE $81,"<"
LFA_LT .WORD NFA_ULT
CFA_LT .WORD PFA_LT
PFA_LT
SEC
LDA 2,X ; Testsubtraktion n1-n2 durchfuehren
SBC 0,X
LDA 3,X
SBC 1,X
STY 3,X ; Hi-Byte von f auf Null setzen (Y=0)
BVC L1258 ; kein Ueberlauf, dann verzweigen
EOR #$80 ; sonst Vorzeichenbit der Differenz umdrehen
L1258 BPL L1260 ; Differenz positiv, dann verzweigen (Y=0)
INY ; sonst true-Flag vorbereiten
L1260 STY 2,X ; ermitteltes Flag in den Datenstack schreiben
JMP POP ; n2 vom Stack entfernen und fertig
; >>>>>>>>>>>>>>>> > <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( > [ n1 n2 -> f ] liefert f=true, wenn n1>n2 ist. )
;( ========================================================================= )
;
; : > SWAP < ; ( n1>n2 gdw n2<n1 )
NFA_GT .CBYTE $81,">"
LFA_GT .WORD NFA_LT
CFA_GT .WORD DOCOL
PFA_GT
.WORD CFA_SWAP ; SWAP
.WORD CFA_LT ; <
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> ROT <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( ROT [ n1 n2 n3 -> n2 n3 n1 ] rotiert die drei obersten Stackelemente. )
;( ========================================================================= )
;
; : ROT >R SWAP R> SWAP ; ( n1 mit Hilfe des Returnstacks nach vorne holen )
NFA_ROT .CBYTE $83,"ROT"
LFA_ROT .WORD NFA_GT
CFA_ROT .WORD DOCOL
PFA_ROT
.WORD CFA_RPUSH ; >R
.WORD CFA_SWAP ; SWAP
.WORD CFA_RPOP ; R>
.WORD CFA_SWAP ; SWAP
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> SPACE <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( SPACE [ ] sendet ein ASCII-Space zum Ausgabegeraet. )
;( ========================================================================= )
;
; : SPACE BL EMIT ;
NFA_SPACE .CBYTE $85,"SPACE"
LFA_SPACE .WORD NFA_ROT
CFA_SPACE .WORD DOCOL
PFA_SPACE
.WORD CFA_BL ; BL
.WORD CFA_EMIT ; EMIT
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> -DUP <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( -DUP [ n1 -> n1 ] falls n1=0, [ n1 -> n1 n1 ] sonst. Dupliziert den TOS, )
;( wenn er ungleich Null ist. )
;( ========================================================================= )
;
; : -DUP DUP IF DUP ENDIF ;
NFA_MINUSDUP .CBYTE $84,"-DUP"
LFA_MINUSDUP .WORD NFA_SPACE
CFA_MINUSDUP .WORD DOCOL
PFA_MINUSDUP
.WORD CFA_DUP ; DUP
.WORD CFA_0BRANCH ; 0BRANCH
.WORD LBL1-*
.WORD CFA_DUP ; DUP
LBL1
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> TRAVERSE <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( TRAVERSE [ addr1 n -> addr2 ] gibt mit addr2 die Adresse des jeweils )
;( anderen Ende eines Namens an, Laengenbyte inklusive. Ist n=1, so wird )
;( aufsteigend gesucht, ist n=-1, so wird absteigend gesucht. )
;( ========================================================================= )
;
; : TRAVERSE
; SWAP
; BEGIN OVER + 127 OVER C@ < UNTIL ( solange suchen bis Byte>127 )
; SWAP DROP
; ;
NFA_TRAVERSE .CBYTE $88,"TRAVERSE"
LFA_TRAVERSE .WORD NFA_MINUSDUP
CFA_TRAVERSE .WORD DOCOL
PFA_TRAVERSE
.WORD CFA_SWAP ; SWAP
LBL2
.WORD CFA_OVER ; OVER
.WORD CFA_PLUS ; +
.WORD CFA_CLIT ; CLIT
.BYTE 127
.WORD CFA_OVER ; OVER
.WORD CFA_CFETCH ; C@
.WORD CFA_LT ; <
.WORD CFA_0BRANCH ; 0BRANCH
.WORD LBL2-*
.WORD CFA_SWAP ; SWAP
.WORD CFA_DROP ; DROP
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> LATEST <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( LATEST [ -> addr ] uebergibt die NFA des zuletzt im Current-Vokabular )
;( definierten Wortes. )
;( ========================================================================= )
;
; : LATEST CURRENT @ @ ;
NFA_LATEST .CBYTE $86,"LATEST"
LFA_LATEST .WORD NFA_TRAVERSE
CFA_LATEST .WORD DOCOL
PFA_LATEST
.WORD CFA_CURRENT ; CURRENT
.WORD CFA_FETCH ; @
.WORD CFA_FETCH ; @
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> LFA <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( LFA [ pfa -> lfa ] wandelt die PFA eines Wortes in die entsprechende LFA )
;( um. )
;( ========================================================================= )
;
; : LFA 4 - ;
NFA_LFA .CBYTE $83,"LFA"
LFA_LFA .WORD NFA_LATEST
CFA_LFA .WORD DOCOL
PFA_LFA
.WORD CFA_CLIT ; CLIT
.BYTE 4
.WORD CFA_MINUS ; -
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> CFA <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( CFA [ pfa -> cfa ] wandelt die PFA eines Wortes in die entsprechende CFA )
;( um. )
;( ========================================================================= )
;
; : CFA 2 - ;
NFA_CFA .CBYTE $83,"CFA"
LFA_CFA .WORD NFA_LFA
CFA_CFA .WORD DOCOL
PFA_CFA
.WORD CFA_2 ; 2
.WORD CFA_MINUS ; -
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> NFA <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( NFA [ pfa -> nfa ] wandelt die PFA eines Wortes in die entsprechende NFA )
;( um. )
;( ========================================================================= )
;
; : NFA 5 - -1 TRAVERSE ;
NFA_NFA .CBYTE $83,"NFA"
LFA_NFA .WORD NFA_CFA
CFA_NFA .WORD DOCOL
PFA_NFA
.WORD CFA_CLIT ; CLIT
.BYTE 5
.WORD CFA_MINUS ; -
.WORD CFA_LIT ; LIT
.WORD -1
.WORD CFA_TRAVERSE ; TRAVERSE
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> PFA <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( PFA [ nfa -> pfa ] wandelt die NFA eines Wortes in die entsprechende PFA )
;( um. )
;( ========================================================================= )
;
; : PFA 1 TRAVERSE 5 + ;
NFA_PFA .CBYTE $83,"PFA"
LFA_PFA .WORD NFA_NFA
CFA_PFA .WORD DOCOL
PFA_PFA
.WORD CFA_1 ; 1
.WORD CFA_TRAVERSE ; TRAVERSE
.WORD CFA_CLIT ; CLIT
.BYTE 5
.WORD CFA_PLUS ; +
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> !CSP <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( !CSP [ ] rettet die aktuelle Stackpointer-Position in die User-Variable )
;( CSP. )
;( ========================================================================= )
;
; : !CSP SP@ CSP ! ;
NFA_STORECSP .CBYTE $84,"!CSP"
LFA_STORECSP .WORD NFA_PFA
CFA_STORECSP .WORD DOCOL
PFA_STORECSP
.WORD CFA_SPFETCH ; SP@
.WORD CFA_CSP ; CSP
.WORD CFA_STORE ; !
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> ?ERROR <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( ?ERROR [ f n -> ] gibt die Fehlermeldung Nummer n aus, wenn f=true ist. )
;( ========================================================================= )
;
; : ?ERROR SWAP IF ERROR ELSE DROP ENDIF ;
NFA_QUERYERROR .CBYTE $86,"?ERROR"
LFA_QUERYERROR .WORD NFA_STORECSP
CFA_QUERYERROR .WORD DOCOL
PFA_QUERYERROR
.WORD CFA_SWAP ; SWAP
.WORD CFA_0BRANCH ; 0BRANCH
.WORD LBL3-*
.WORD CFA_ERROR ; ERROR
.WORD CFA_BRANCH ; BRANCH
.WORD LBL4-*
LBL3
.WORD CFA_DROP ; DROP
LBL4
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> ?COMP <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( ?COMP [ ] gibt eine entsprechende Fehlermeldung aus, wenn sich das System )
;( nicht im Compile-Mode befindet. )
;( ========================================================================= )
;
; : ?COMP STATE @ 0= 17 ?ERROR ;
NFA_QUERYCOMP .CBYTE $85,"?COMP"
LFA_QUERYCOMP .WORD NFA_QUERYERROR
CFA_QUERYCOMP .WORD DOCOL
PFA_QUERYCOMP
.WORD CFA_STATE ; STATE
.WORD CFA_FETCH ; @
.WORD CFA_NULLEQUAL ; 0=
.WORD CFA_CLIT ; CLIT
.BYTE 17
.WORD CFA_QUERYERROR ; ?ERROR
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> ?EXEC <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( ?EXEC [ ] gibt eine entsprechende Fehlermeldung aus, wenn sich das System )
;( nicht im Execute-Mode befindet. )
;( ========================================================================= )
;
; : ?EXEC STATE @ 18 ?ERROR ;
NFA_QUERYEXEC .CBYTE $85,"?EXEC"
LFA_QUERYEXEC .WORD NFA_QUERYCOMP
CFA_QUERYEXEC .WORD DOCOL
PFA_QUERYEXEC
.WORD CFA_STATE ; STATE
.WORD CFA_FETCH ; @
.WORD CFA_CLIT ; CLIT
.BYTE 18
.WORD CFA_QUERYERROR ; ?ERROR
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> ?PAIRS <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( ?PAIRS [ n1 n2 -> ] gibt eine entsprechende Fehlermeldung aus, wenn n1 )
;( und n2 ungleich sind. Das Wort wird waehrend der Kompilation benutzt, um )
;( festzustellen, ob zwei strukturierte Sprachelemente zusammengehoeren. )
;( ========================================================================= )
;
; : ?PAIRS - 19 ?ERROR ;
NFA_QUERYPAIRS .CBYTE $86,"?PAIRS"
LFA_QUERYPAIRS .WORD NFA_QUERYEXEC
CFA_QUERYPAIRS .WORD DOCOL
PFA_QUERYPAIRS
.WORD CFA_MINUS ; -
.WORD CFA_CLIT ; CLIT
.BYTE 19
.WORD CFA_QUERYERROR ; ?ERROR
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> ?CSP <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( ?CSP [ ] gibt eine entsprechende Fehlermeldung aus, wenn die aktuelle )
;( Stack-Position von der in der User-Variablen CSP geretteten abweicht. )
;( ========================================================================= )
;
; : ?CSP SP@ CSP @ - 20 ?ERROR ;
NFA_QUERYCSP .CBYTE $84,"?CSP"
LFA_QUERYCSP .WORD NFA_QUERYPAIRS
CFA_QUERYCSP .WORD DOCOL
PFA_QUERYCSP
.WORD CFA_SPFETCH ; SP@
.WORD CFA_CSP ; CSP
.WORD CFA_FETCH ; @
.WORD CFA_MINUS ; -
.WORD CFA_CLIT ; CLIT
.BYTE 20
.WORD CFA_QUERYERROR ; ?ERROR
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> ?LOADING <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( ?LOADING [ ] gibt eine entsprechende Fehlermeldung aus, falls nicht )
;( geladen wird. )
;( ========================================================================= )
;
; : ?LOADING SOURCE-ID @ 0= 22 ?ERROR ;
NFA_QUERYLOADING .CBYTE $88,"?LOADING"
LFA_QUERYLOADING .WORD NFA_QUERYCSP
CFA_QUERYLOADING .WORD DOCOL
PFA_QUERYLOADING
.WORD CFA_SOURCEID ; SOURCE-ID
.WORD CFA_FETCH ; @
.WORD CFA_NULLEQUAL ; 0=
.WORD CFA_CLIT ; CLIT
.BYTE 22
.WORD CFA_QUERYERROR ; ?ERROR
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> COMPILE <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( COMPILE [ ] kompiliert das inline folgende Wort in das Dictionary. )
;( ========================================================================= )
;
; : COMPILE
; ?COMP ( nur im Compile-Mode erlaubt )
; R> ( Fortsetzungsadresse holen )
; DUP 2+ >R ( inline folgendes Wort in der Ausfuehrung ueberspringen )
; @ , ( inline folgendes Wort an das Dictionary anfuegen )
; ;
NFA_COMPILE .CBYTE $87,"COMPILE"
LFA_COMPILE .WORD NFA_QUERYLOADING
CFA_COMPILE .WORD DOCOL
PFA_COMPILE
.WORD CFA_QUERYCOMP ; ?COMP
.WORD CFA_RPOP ; R>
.WORD CFA_DUP ; DUP
.WORD CFA_2PLUS ; 2+
.WORD CFA_RPUSH ; >R
.WORD CFA_FETCH ; @
.WORD CFA_COMMA ; ,
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> [ <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( [ [ ] schaltet in den Execute-Mode um. )
;( ========================================================================= )
;
; : [ 0 STATE ! ; IMMEDIATE
NFA_LEFTBRACKET .CBYTE $81+$40, "[" ; IMMEDIATE
LFA_LEFTBRACKET .WORD NFA_COMPILE
CFA_LEFTBRACKET .WORD DOCOL
PFA_LEFTBRACKET
.WORD CFA_0 ; 0
.WORD CFA_STATE ; STATE
.WORD CFA_STORE ; !
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> ] <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( ] [ ] schaltet in den Compile-Mode um. )
;( ========================================================================= )
;
; : ] 192 STATE ! ;
NFA_RIGHTBRACKET .CBYTE $81,"]"
LFA_RIGHTBRACKET .WORD NFA_LEFTBRACKET
CFA_RIGHTBRACKET .WORD DOCOL
PFA_RIGHTBRACKET
.WORD CFA_CLIT ; CLIT
.BYTE 192
.WORD CFA_STATE ; STATE
.WORD CFA_STORE ; !
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> SMUDGE <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( SMUDGE [ ] dreht das SMUDGE-Bit im Header des zuletzt definierten Wortes )
;( um, d.h. macht das Wort gueltig, wenn es vorher ungueltig war, und )
;( umgekehrt. )
;( ========================================================================= )
;
; : SMUDGE LATEST 32 TOGGLE ;
NFA_SMUDGE .CBYTE $86,"SMUDGE"
LFA_SMUDGE .WORD NFA_RIGHTBRACKET
CFA_SMUDGE .WORD DOCOL
PFA_SMUDGE
.WORD CFA_LATEST ; LATEST
.WORD CFA_CLIT ; CLIT
.BYTE 32
.WORD CFA_TOGGLE ; TOGGLE
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> HEX <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( HEX [ ] setzt die I/O-Zahlenbasis auf 16. )
;( ========================================================================= )
;
; : HEX 16 BASE ! ;
NFA_HEX .CBYTE $83,"HEX"
LFA_HEX .WORD NFA_SMUDGE
CFA_HEX .WORD DOCOL
PFA_HEX
.WORD CFA_CLIT ; CLIT
.BYTE 16
.WORD CFA_BASE ; BASE
.WORD CFA_STORE ; !
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> DECIMAL <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( DECIMAL [ ] setzt die I/O-Zahlenbasis auf 10. )
;( ========================================================================= )
;
; : DECIMAL 10 BASE ! ;
NFA_DECIMAL .CBYTE $87,"DECIMAL"
LFA_DECIMAL .WORD NFA_HEX
CFA_DECIMAL .WORD DOCOL
PFA_DECIMAL
.WORD CFA_CLIT ; CLIT
.BYTE 10
.WORD CFA_BASE ; BASE
.WORD CFA_STORE ; !
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> (;CODE) <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( [;CODE] [ ] ueberschreibt das Codefeld des soeben definierten Wortes mit )
;( der unmittelbar auf [;CODE] folgenden Adresse und kehrt zum aufrufenden )
;( Wort zurueck. )
;( ========================================================================= )
;
; : (;CODE) R> LATEST PFA CFA ! ;
NFA_BRACKETCODE .CBYTE $87,"(;CODE)"
LFA_BRACKETCODE .WORD NFA_DECIMAL
CFA_BRACKETCODE .WORD DOCOL
PFA_BRACKETCODE
.WORD CFA_RPOP ; R>
.WORD CFA_LATEST ; LATEST
.WORD CFA_PFA ; PFA
.WORD CFA_CFA ; CFA
.WORD CFA_STORE ; !
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> ;CODE <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( ;CODE [ ] beendet die Colon-Definition eines Definitionswortes und )
;( beginnt die Spezifikationsphase des Assemblerteiles. )
;( ========================================================================= )
;
; : ;CODE
; ?CSP ( Stackpointer-Position ueberpruefen )
; COMPILE (;CODE) ( [;CODE] kompilieren )
; [COMPILE] [ ( in den Execute-Mode umschalten )
; SMUDGE ( soeben definiertes Wort gueltig machen )
; ; IMMEDIATE
NFA_CODE .CBYTE $85+$40,";CODE" ; IMMEDIATE
LFA_CODE .WORD NFA_BRACKETCODE
CFA_CODE .WORD DOCOL
PFA_CODE
.WORD CFA_QUERYCSP ; ?CSP
.WORD CFA_COMPILE ; COMPILE
.WORD CFA_BRACKETCODE ; (;CODE)
.WORD CFA_LEFTBRACKET ; [
.WORD CFA_SMUDGE ; SMUDGE
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> <BUILDS <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( <BUILDS [ ] beginnt die Definitionsphase eines High-Level-Definitions- )
;( wortes. )
;( ========================================================================= )
;
; : <BUILDS 0 CONSTANT ; ( provisorischen Konstanten-Header aufbauen )
NFA_BUILDS .CBYTE $87,"<BUILDS"
LFA_BUILDS .WORD NFA_CODE
CFA_BUILDS .WORD DOCOL
PFA_BUILDS
.WORD CFA_0 ; 0
.WORD CFA_CONSTANT ; CONSTANT
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> DOES> <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( DOES> [ ] beendet die Definitionsphase eines High-Level-Definitionswortes )
;( und leitet die Definitionsphase des entsprechenden Ausfuehrungsteils ein. )
;( ========================================================================= )
;
; : DOES>
; R> ( Adresse des auf DOES> folgenden High-Level-Codes )
; LATEST PFA ! ( in das Parameterfeld des soeben def. Wortes schreiben )
; ;CODE ; das neue Wort fuehrt den folgenden Code aus:
; DODOE LDA IP+1 ; Instruction-Pointer IP auf den Returnstack pushen
; PHA
; LDA IP
; PHA
; LDY #2
; LDA (W),Y ; IP mit der Adresse laden, die als erstes im
; STA IP ; Parameterfeld des Wortes abgelegt ist.
; INY ; Dies ist die Adresse unmittelbar hinter dem DOES>
; LDA (W),Y ; des definierenden Wortes.
; STA IP+1
; CLC
; LDA W ; Adresse des zweiten Eintrags im Parameterfeld des
; ADC #4 ; Wortes holen
; PHA
; LDA W+1
; ADC #0
; JMP PUSH ; auf den Datenstack legen und fertig
; END-CODE
NFA_DOES .CBYTE $85,"DOES>"
LFA_DOES .WORD NFA_BUILDS
CFA_DOES .WORD DOCOL
PFA_DOES
.WORD CFA_RPOP ; R>
.WORD CFA_LATEST ; LATEST
.WORD CFA_PFA ; PFA
.WORD CFA_STORE ; !
.WORD CFA_BRACKETCODE ; (;CODE)
; das neue Wort fuehrt den folgenden Code aus:
DODOE LDA IP+1 ; Instruction-Pointer IP auf den Returnstack pushen
PHA
LDA IP
PHA
LDY #2
LDA (W),Y ; IP mit der Adresse laden, die als erstes im
STA IP ; Parameterfeld des Wortes abgelegt ist.
INY ; Dies ist die Adresse unmittelbar hinter dem DOES>
LDA (W),Y ; des definierenden Wortes.
STA IP+1
CLC
LDA W ; Adresse des zweiten Eintrags im Parameterfeld des
ADC #4 ; Wortes holen
PHA
LDA W+1
ADC #0
JMP PUSH ; auf den Datenstack legen und fertig
; >>>>>>>>>>>>>>>> COUNT <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( COUNT [ addr1 -> addr2 n ] ermittelt zum String, auf dessen Count-Byte )
;( addr1 zeigt, die eigentliche Startadresse addr2 und die Anzahl n der )
;( Zeichen. )
;( ========================================================================= )
;
; : COUNT DUP 1+ SWAP C@ ; ( addr2=addr1+1 und n=[addr1] )
NFA_COUNT .CBYTE $85,"COUNT"
LFA_COUNT .WORD NFA_DOES
CFA_COUNT .WORD DOCOL
PFA_COUNT
.WORD CFA_DUP ; DUP
.WORD CFA_1PLUS ; 1+
.WORD CFA_SWAP ; SWAP
.WORD CFA_CFETCH ; C@
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> TYPE <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( TYPE [ addr count -> ] gibt den aus count Zeichen bestehenden String, )
;( beginnend ab Adresse addr, auf die Standardausgabe aus. )
;( ========================================================================= )
;
; : TYPE
; -DUP IF ( falls count<>0, d.h. falls Zeichen auszugeben sind: )
; OVER + SWAP DO ( fuer alle I von addr bis addr+count-1: )
; I C@ EMIT ( Zeichen in Adresse I ausgeben )
; LOOP
; ELSE ( falls count=0: )
; DROP ( nichts ausgeben, addr vom Stack nehmen )
; ENDIF
; ;
NFA_TYPE .CBYTE $84,"TYPE"
LFA_TYPE .WORD NFA_COUNT
CFA_TYPE .WORD DOCOL
PFA_TYPE
.WORD CFA_MINUSDUP ; -DUP
.WORD CFA_0BRANCH ; 0BRANCH
.WORD LBL5-*
.WORD CFA_OVER ; OVER
.WORD CFA_PLUS ; +
.WORD CFA_SWAP ; SWAP
.WORD CFA_BRACKETDO ; (DO)
LBL6
.WORD CFA_I ; I
.WORD CFA_CFETCH ; C@
.WORD CFA_EMIT ; EMIT
.WORD CFA_BRACKETLOOP ; (LOOP)
.WORD LBL6-*
.WORD CFA_BRANCH ; BRANCH
.WORD LBL7-*
LBL5
.WORD CFA_DROP ; DROP
LBL7
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> -TRAILING <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( -TRAILING [ addr n1 -> addr n2 ] verkuerzt den durch addr und n1 bezeich- )
;( neten String um Blanks am Textende, d.h. die Zeichen in addr+n2 bis )
;( addr+n1-1 sind Blanks. )
;( ========================================================================= )
;
; : -TRAILING
; DUP 0 DO ( wiederhole die folgende Schleife maximal n1-mal )
; OVER OVER + 1 - C@ ( Zeichen an der Adresse addr+n-1 )
; BL - IF ( falls es kein Blank ist: )
; LEAVE ( Suche beenden )
; ELSE ( sonst: )
; 1 - ( n dekrementieren )
; ENDIF
; LOOP
; ;
NFA_MINUSTRAILING .CBYTE $89,"-TRAILING"
LFA_MINUSTRAILING .WORD NFA_TYPE
CFA_MINUSTRAILING .WORD DOCOL
PFA_MINUSTRAILING
.WORD CFA_DUP ; DUP
.WORD CFA_0 ; 0
.WORD CFA_BRACKETDO ; (DO)
LBL8
.WORD CFA_OVER ; OVER
.WORD CFA_OVER ; OVER
.WORD CFA_PLUS ; +
.WORD CFA_1 ; 1
.WORD CFA_MINUS ; -
.WORD CFA_CFETCH ; C@
.WORD CFA_BL ; BL
.WORD CFA_MINUS ; -
.WORD CFA_0BRANCH ; 0BRANCH
.WORD LBL9-*
.WORD CFA_LEAVE ; LEAVE
.WORD CFA_BRANCH ; BRANCH
.WORD LBL10-*
LBL9
.WORD CFA_1 ; 1
.WORD CFA_MINUS ; -
LBL10
.WORD CFA_BRACKETLOOP ; (LOOP)
.WORD LBL8-*
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> (.") <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( [."] [ ] gibt den inline folgenden String auf die Standardausgabe aus. )
;( ========================================================================= )
;
; : (.")
; R COUNT ( Adresse und Laenge des inline folgenden Strings )
; DUP 1+ R> + >R ( Returnadresse um die Gesamtlaenge des Strings erhoehen )
; TYPE ( String auf die Standardausgabe ausgeben )
; ;
NFA_BRAKETDOTQUOTE .CBYTE $84,"(.",34,")"
LFA_BRAKETDOTQUOTE .WORD NFA_MINUSTRAILING
CFA_BRAKETDOTQUOTE .WORD DOCOL
PFA_BRAKETDOTQUOTE
.WORD CFA_R ; R
.WORD CFA_COUNT ; COUNT
.WORD CFA_DUP ; DUP
.WORD CFA_1PLUS ; 1+
.WORD CFA_RPOP ; R>
.WORD CFA_PLUS ; +
.WORD CFA_RPUSH ; >R
.WORD CFA_TYPE ; TYPE
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> ." <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( ." [ ] gibt den im Eingabestrom folgenden String auf die Standardausgabe )
;( aus. Im Compile-Mode werden [."] und der String kompiliert. )
;( ========================================================================= )
;
; : ."
; 34 ( Zeichen '"' )
; STATE @ IF ( falls Compile-Mode: )
; COMPILE (.") ( [."] kompilieren )
; WORD ( folgenden String kompilieren )
; HERE C@ 1+ ALLOT ( Dictionary-Pointer entsprechend erhoehen )
; ELSE ( falls Execute-Mode: )
; WORD ( folgenden String holen )
; HERE COUNT TYPE ( und auf die Standardausgabe ausgeben )
; ENDIF
; ; IMMEDIATE
NFA_DOTQUOTE .BYTE $C2,".",$A2
LFA_DOTQUOTE .WORD NFA_BRAKETDOTQUOTE
CFA_DOTQUOTE .WORD DOCOL
PFA_DOTQUOTE
.WORD CFA_CLIT ; CLIT
.BYTE 34
.WORD CFA_STATE ; STATE
.WORD CFA_FETCH ; @
.WORD CFA_0BRANCH ; 0BRANCH
.WORD LBL11-*
.WORD CFA_COMPILE ; COMPILE
.WORD CFA_BRAKETDOTQUOTE ; (.")
.WORD CFA_WORD ; WORD
.WORD CFA_CFETCH ; C@
.WORD CFA_1PLUS ; 1+
.WORD CFA_ALLOT ; ALLOT
.WORD CFA_BRANCH ; BRANCH
.WORD LBL12-*
LBL11
.WORD CFA_WORD ; WORD
.WORD CFA_COUNT ; COUNT
.WORD CFA_TYPE ; TYPE
LBL12
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> EXPECT <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( EXPECT [ addr count -> ] holt bis zu count Zeichen vom Keyboard - wenn )
;( nicht vorher CR eingegeben wird - und legt sie ab Adresse addr ab, durch )
;( ein oder mehrere Null-Bytes abgeschlossen. )
;( ========================================================================= )
;
; : EXPECT
; OVER + OVER DO ( fuer I von addr bis addr+count-1 tue: )
; KEY ( Taste holen )
; DUP 126 +ORIGIN @ = IF ( falls externes Backspace: )
; DROP 8 ( Taste durch internes Backspace ersetzen )
; OVER I = ( 1 falls am linken Anschlag, sonst 0 )
; DUP R> 2 - + >R ( I um 1 [falls Anfang] oder 2 dekrementieren )
; - ( ASCII 8 [BS] oder ASCII 7 [BEL] zuruecklassen )
; ELSE ( falls kein externes Backspace: )
; DUP 155 = IF ( falls CR: )
; LEAVE DROP BL 0 ( Eingabe beenden, Blank ausgeben, 0 speichern )
; ELSE ( falls kein CR: )
; DUP ( Zeichen ausgeben und speichern )
; ENDIF
; I C! ( eingegebenes Zeichen speichern )
; 0 I 1+ ! ( 0 in der darauffolgenden Zelle speichern )
; ENDIF
; EMIT ( eingegebenes Zeichen ausgeben )
; LOOP
; DROP ( Adresse addr vergessen )
; ;
NFA_EXPECT .CBYTE $86,"EXPECT"
LFA_EXPECT .WORD NFA_DOTQUOTE
CFA_EXPECT .WORD DOCOL
PFA_EXPECT
.WORD CFA_OVER ; OVER
.WORD CFA_PLUS ; +
.WORD CFA_OVER ; OVER
.WORD CFA_BRACKETDO ; (DO)
LBL13
.WORD CFA_KEY ; KEY
.WORD CFA_DUP ; DUP
.WORD CFA_CLIT ; CLIT
.BYTE $0E
.WORD CFA_PLUSORIGIN ; +ORIGIN
.WORD CFA_FETCH ; @
.WORD CFA_EQUAL ; =
.WORD CFA_0BRANCH ; 0BRANCH
.WORD LBL14-*
.WORD CFA_DROP ; DROP
.WORD CFA_CLIT ; CLIT
.BYTE 126
.WORD CFA_OVER ; OVER
.WORD CFA_I ; I
.WORD CFA_EQUAL ; =
.WORD CFA_DUP ; DUP
.WORD CFA_RPOP ; R>
.WORD CFA_2 ; 2
.WORD CFA_MINUS ; -
.WORD CFA_PLUS ; +
.WORD CFA_RPUSH ; >R
.WORD CFA_MINUS ; -
.WORD CFA_BRANCH ; BRANCH
.WORD LBL15-*
LBL14
.WORD CFA_DUP ; DUP
.WORD CFA_CLIT ; CLIT
.BYTE 155
.WORD CFA_EQUAL ; =
.WORD CFA_0BRANCH ; 0BRANCH
.WORD LBL16-*
.WORD CFA_LEAVE ; LEAVE
.WORD CFA_DROP ; DROP
.WORD CFA_BL ; BL
.WORD CFA_0 ; 0
.WORD CFA_BRANCH ; BRANCH
.WORD LBL17-*
LBL16
.WORD CFA_DUP ; DUP
LBL17
.WORD CFA_I ; I
.WORD CFA_CSTORE ; C!
.WORD CFA_0 ; 0
.WORD CFA_I ; I
.WORD CFA_1PLUS ; 1+
.WORD CFA_STORE ; !
LBL15
.WORD CFA_EMIT ; EMIT
.WORD CFA_BRACKETLOOP ; (LOOP)
.WORD LBL13-*
.WORD CFA_DROP ; DROP
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> QUERY <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( QUERY [ ] holt bis zu 80 Zeichen - wenn nicht vorher CR eingegeben wird - )
;( vom Terminal und legt sie im Terminal-Input-Buffer TIB ab. Ausserdem wird )
;( die User-Variable IN auf 0 gesetzt. )
;( ========================================================================= )
;
; : QUERY
; TIB @ 80 EXPECT ( bis zu 80 Zeichen in den Terminal-Input-Buffer einlesen )
; 0 IN ! ( Interpretation beginnt beim Offset 0 )
; ;
NFA_QUERY .CBYTE $85,"QUERY"
LFA_QUERY .WORD NFA_EXPECT
CFA_QUERY .WORD DOCOL
PFA_QUERY
.WORD CFA_TIB ; TIB
.WORD CFA_FETCH ; @
.WORD CFA_CLIT ; CLIT
.BYTE 80
.WORD CFA_EXPECT ; EXPECT
.WORD CFA_0 ; 0
.WORD CFA_IN ; IN
.WORD CFA_STORE ; !
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> X <<<<<<<<<<<<<<<<
; ( ========================================================================= )
; ( X [ ] bricht die Interpretation einer Zeile Text bedingungslos ab. X ist )
; ( ein Pseudonym fuer den Namen, der nur aus dem ASCII-0-Zeichen besteht. )
; ( ========================================================================= )
;
; ( 32897 HERE ) ( hex 8081 und aktuelle Adresse merken )
;
; : X
; SOURCE-ID @ IF ( falls von Disk geladen wird: )
; 1 BLK +! ( naechsten Block interpretieren )
; 0 IN ! ( beginnend beim Offset 0 )
; BLK @ 0 B/SCR U/ DROP 0= IF ( falls Screen-Ende erreicht wurde: )
; ?EXEC R> DROP ( Interpretation ganz abbrechen )
; ENDIF
; ELSE ( falls nicht von Disk geladen wird: )
; R> DROP ( Interpretation ganz abbrechen )
; ENDIF
; ; IMMEDIATE
NFA_X .BYTE $C1, $80
LFA_X .WORD NFA_QUERY
CFA_X .WORD DOCOL
PFA_X
;.WORD CFA_BLK ; BLK
;.WORD CFA_FETCH ; @
;.WORD CFA_0BRANCH ; 0BRANCH
;.WORD LBL18-*
;.WORD CFA_1 ; 1
;.WORD CFA_BLK ; BLK
;.WORD CFA_PLUSSTORE ; +!
;.WORD CFA_0 ; 0
;.WORD CFA_IN ; IN
;.WORD CFA_STORE ; !
;.WORD CFA_BLK ; BLK
;.WORD CFA_FETCH ; @
;.WORD CFA_0 ; 0
;.WORD CFA_BSCR ; B/SCR
;.WORD CFA_UDIV ; U/
;.WORD CFA_DROP ; DROP
;.WORD CFA_NULLEQUAL ; 0=
;.WORD CFA_0BRANCH ; 0BRANCH
;.WORD LBL19-*
;.WORD CFA_QUERYEXEC ; ?EXEC
;.WORD CFA_RPOP ; R>
;.WORD CFA_DROP ; DROP
;LBL19
;.WORD CFA_BRANCH ; BRANCH
;.WORD LBL20-*
LBL18
.WORD CFA_RPOP ; R>
.WORD CFA_DROP ; DROP
LBL20
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> FILL <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( FILL [ addr n b -> ] fuellt n Bytes ab Adresse addr mit dem Wert b. )
;( ========================================================================= )
;
; : FILL
; SWAP >R OVER C! ( Byte b in Adresse addr speichern )
; DUP 1+ R> 1 - CMOVE ( n-1 Bytes aufsteigend von addr nach addr+1 kopieren )
; ;
NFA_FILL .CBYTE $84,"FILL"
LFA_FILL .WORD NFA_X
CFA_FILL .WORD DOCOL
PFA_FILL
.WORD CFA_SWAP ; SWAP
.WORD CFA_RPUSH ; >R
.WORD CFA_OVER ; OVER
.WORD CFA_CSTORE ; C!
.WORD CFA_DUP ; DUP
.WORD CFA_1PLUS ; 1+
.WORD CFA_RPOP ; R>
.WORD CFA_1 ; 1
.WORD CFA_MINUS ; -
.WORD CFA_CMOVE ; CMOVE
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> ERASE <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( ERASE [ addr n -> ] fuellt n Bytes ab Adresse addr mit Nullen. )
;( ========================================================================= )
;
;: ERASE 0 FILL ;
NFA_ERASE .CBYTE $85,"ERASE"
LFA_ERASE .WORD NFA_FILL
CFA_ERASE .WORD DOCOL
PFA_ERASE
.WORD CFA_0 ; 0
.WORD CFA_FILL ; FILL
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> BLANKS <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( BLANKS [ addr count -> ] fuellt count Bytes ab Adresse addr mit Blanks. )
;( ========================================================================= )
;
; : BLANKS BL FILL ;
NFA_BLANKS .CBYTE $86,"BLANKS"
LFA_BLANKS .WORD NFA_ERASE
CFA_BLANKS .WORD DOCOL
PFA_BLANKS
.WORD CFA_BL ; BL
.WORD CFA_FILL ; FILL
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> HOLD <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( HOLD [ c -> ] fuegt das Zeichen c in einen Ziffernstring ein. Das Wort )
;( wird in Verbindung mit <# und #> gebraucht. )
;( ========================================================================= )
;
;: HOLD
; -1 HLD +! ( Zeiger im Ziffernstring weitersetzen )
; HLD @ C! ( Zeichen c in das Byte, auf das HLD zeigt, speichern )
; ;
NFA_HOLD .CBYTE $84,"HOLD"
LFA_HOLD .WORD NFA_BLANKS
CFA_HOLD .WORD DOCOL
PFA_HOLD
.WORD CFA_LIT ; LIT
.WORD -1
.WORD CFA_HLD ; HLD
.WORD CFA_PLUSSTORE ; +!
.WORD CFA_HLD ; HLD
.WORD CFA_FETCH ; @
.WORD CFA_CSTORE ; C!
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> PAD <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( PAD [ -> addr ] uebergibt die Startadresse des Text-Ausgabe-Buffers PAD. )
;( ========================================================================= )
;
; : PAD HERE 68 + ;
NFA_PAD .CBYTE $83, "PAD"
LFA_PAD .WORD NFA_HOLD
CFA_PAD .WORD DOCOL
PFA_PAD
.WORD CFA_HERE ; HERE
.WORD CFA_CLIT ; CLIT
.BYTE 68
.WORD CFA_PLUS ; +
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> WORD <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( WORD [ c -> c-addr ] bringt das im Input-Strom folgende, durch das )
;( Zeichen c abgeschlossene Wort als String nach HERE. Der String beginnt )
;( mit einem Count-Byte. )
;( ========================================================================= )
;
;: WORD
; TIB @ ( Adresse des Terminal-Input-Buffers )
; IN @ + ( Adresse, ab der gelesen wird )
; SWAP ENCLOSE ( Wort separieren )
; HERE 34 BLANKS ( Bereich HERE ... HERE+33 mit Blanks fuellen )
; IN +! ( IN zeigt jetzt auf Offset hinter dem Wort )
; OVER - >R ( Wortlaenge auf den Return-Stack legen )
; R HERE C! ( Wortlaenge als Count-Byte nach HERE speichern )
; + ( Startadresse des separierten Wortes )
; HERE 1+ ( Zieladresse des Wortes )
; R> ( Anzahl der zu kopierenden Zeichen )
; CMOVE ( separiertes Wort kopieren )
; HERE ( HERE auf dem Stack hinterlassen )
; ;
NFA_WORD .CBYTE $84, "WORD"
LFA_WORD .WORD NFA_PAD
CFA_WORD .WORD DOCOL
PFA_WORD
.WORD CFA_TIB ; TIB
.WORD CFA_FETCH ; @
.WORD CFA_IN ; IN
.WORD CFA_FETCH ; @
.WORD CFA_PLUS ; +
.WORD CFA_SWAP ; SWAP
.WORD CFA_ENCLOSE ; ENCLOSE
.WORD CFA_HERE ; HERE
.WORD CFA_CLIT ; CLIT
.BYTE 34
.WORD CFA_BLANKS ; BLANKS
.WORD CFA_IN ; IN
.WORD CFA_PLUSSTORE ; +!
.WORD CFA_OVER ; OVER
.WORD CFA_MINUS ; -
.WORD CFA_RPUSH ; >R
.WORD CFA_R ; R
.WORD CFA_HERE ; HERE
.WORD CFA_CSTORE ; C!
.WORD CFA_PLUS ; +
.WORD CFA_HERE ; HERE
.WORD CFA_1PLUS ; 1+
.WORD CFA_RPOP ; R>
.WORD CFA_CMOVE ; CMOVE
.WORD CFA_HERE ; HERE
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> (NUMBER) <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( [NUMBER] [ d1 addr1 -> d2 addr2 ] akkumuliert den Ziffernstring ab )
;( Adresse addr1+1 zur doppeltgenauen, vorzeichenlosen Zahl d2 auf. addr2 )
;( ist die Adresse des ersten gefundenen Zeichens, das keine gueltige Ziffer )
;( darstellt. )
;( ========================================================================= )
;
; : (NUMBER)
; BEGIN
; 1+ ( auf naechstes Zeichen zeigen )
; DUP >R ( diesen Zeiger auf dem Return-Stack merken )
; C@ ( Zeichen holen )
; BASE @ DIGIT ( und in Ziffer umwandeln )
; WHILE ( solange es sich um eine gueltige Ziffer handelt: )
; SWAP BASE @ U* ( Hi-Word von d mit der Basis multiplizieren )
; DROP ( Hi-Word dieses Produktes vergessen )
; ROT BASE @ U* ( Lo-Word von d mit der Basis multiplizieren )
; D+ ( Summe Basis*d+n berechnen )
; DPL @ 1+ IF ( falls DPL nicht den Wert -1 enthaelt: )
; 1 DPL +! ( DPL inkrementieren )
; ENDIF
; R> ( neuen Zeiger vom Return-Stack zurueckholen )
; REPEAT ( wiederholen )
; R> ( falls fertig: Zeiger vom Returnstack holen )
; ;
NFA_PARENTNUMBER .CBYTE $88,"(NUMBER)"
LFA_PARENTNUMBER .WORD NFA_WORD
CFA_PARENTNUMBER .WORD DOCOL
PFA_PARENTNUMBER
LBL23
.WORD CFA_1PLUS ; 1+
.WORD CFA_DUP ; DUP
.WORD CFA_RPUSH ; >R
.WORD CFA_CFETCH ; C@
.WORD CFA_BASE ; BASE
.WORD CFA_FETCH ; @
.WORD CFA_DIGIT; DIGIT
.WORD CFA_0BRANCH ; 0BRANCH
.WORD LBL24-*
.WORD CFA_SWAP ; SWAP
.WORD CFA_BASE ; BASE
.WORD CFA_FETCH ; @
.WORD CFA_UMULT ; U*
.WORD CFA_DROP ; DROP
.WORD CFA_ROT ; ROT
.WORD CFA_BASE ; BASE
.WORD CFA_FETCH ; @
.WORD CFA_UMULT ; U*
.WORD CFA_DPLUS ; D+
.WORD CFA_DPL ; DPL
.WORD CFA_FETCH ; @
.WORD CFA_1PLUS ; 1+
.WORD CFA_0BRANCH ; 0BRANCH
.WORD LBL25-*
.WORD CFA_1 ; 1
.WORD CFA_DPL ; DPL
.WORD CFA_PLUSSTORE ; +!
LBL25
.WORD CFA_RPOP ; R>
.WORD CFA_BRANCH ; BRANCH
.WORD LBL23-*
LBL24
.WORD CFA_RPOP ; R>
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> NUMBER <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( NUMBER [ addr -> d ] wandelt den String, auf dessen Count-Byte addr )
;( zeigt, in eine doppeltgenaue Zahl d um. Das Count-Byte selbst wird nicht )
;( beruecksichtigt, der Ziffernstring muss durch ein Blank abgeschlossen )
;( sein. )
;( ========================================================================= )
;
; : NUMBER
; 0 0 ROT ( Anfangsbedingungen fuer [NUMBER] schaffen )
; DUP 1+ C@ ( erstes Zeichen nach dem Count-Byte holen )
; 45 = ( Vorzeichenflag: 1 falls Minuszeichen, sonst 0 )
; DUP >R ( Vorzeichenflag auf den Returnstack legen )
; + ( falls Vorzeichen: Adresse inkrementieren )
; -1 ( noch kein Dezimalpunkt gefunden )
; BEGIN ( Ziffern und Punkte einlesen und umwandeln: )
; DPL ! ( Dezimalpunkt-Position in DPL speichern )
; (NUMBER) ( folgende Ziffern in d aufakkumulieren )
; DUP C@ BL - ( Abbruch der Schleife, falls Blank angetroffen )
; WHILE ( sonst weitermachen )
; DUP C@ 46 - 0 ?ERROR ( Fehler falls kein Punkt )
; 0 ( Punkt gefunden, dann 0 in DPL speichern [s.o.] )
; REPEAT
; DROP ( Adresse vergessen )
; R> IF ( falls Minuszeichen am Anfang: )
; DMINUS ( Zahl negieren )
; ENDIF
; ;
NFA_NUMBER .CBYTE $86,"NUMBER"
LFA_NUMBER .WORD NFA_PARENTNUMBER
CFA_NUMBER .WORD DOCOL
PFA_NUMBER
.WORD CFA_0 ; 0
.WORD CFA_0 ; 0
.WORD CFA_ROT ; ROT
.WORD CFA_DUP ; DUP
.WORD CFA_1PLUS ; 1+
.WORD CFA_CFETCH ; C@
.WORD CFA_CLIT ; CLIT
.BYTE 45
.WORD CFA_EQUAL ; =
.WORD CFA_DUP ; DUP
.WORD CFA_RPUSH ; >R
.WORD CFA_PLUS ; +
.WORD CFA_LIT ; LIT
.WORD -1
LBL26
.WORD CFA_DPL ; DPL
.WORD CFA_STORE ; !
.WORD CFA_PARENTNUMBER ; (NUMBER)
.WORD CFA_DUP ; DUP
.WORD CFA_CFETCH ; C@
.WORD CFA_BL ; BL
.WORD CFA_MINUS ; -
.WORD CFA_0BRANCH ; 0BRANCH
.WORD LBL27-*
.WORD CFA_DUP ; DUP
.WORD CFA_CFETCH ; C@
.WORD CFA_CLIT ; CLIT
.BYTE 46
.WORD CFA_MINUS ; -
.WORD CFA_0 ; 0
.WORD CFA_QUERYERROR ; ?ERROR
.WORD CFA_0 ; 0
.WORD CFA_BRANCH ; BRANCH
.WORD LBL26-*
LBL27
.WORD CFA_DROP ; DROP
.WORD CFA_RPOP ; R>
.WORD CFA_0BRANCH ; 0BRANCH
.WORD LBL28-*
.WORD CFA_DMINUS ; DMINUS
LBL28
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> -FIND <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( -FIND [ -> pfa b tf ] falls Suche erfolgreich, sonst [ -> ff ]. Liest das )
;( naechste Wort und bringt es, mit Count-Byte versehen, nach HERE. )
;( Anschliessend wird das CONTEXT- und das CURRENT-Vokabular nach dem Wort )
;( abgesucht. Wird es gefunden, so wird seine PFA, das Count-Byte b und ein )
;( true-Flag uebergeben, sonst lediglich ein false-Flag. )
;( ========================================================================= )
;
; : -FIND
; BL WORD ( naechstes Wort lesen und nach HERE bringen )
; HERE CONTEXT @ @ (FIND) ( CONTEXT-Vokabular nach dem Wort absuchen )
; DUP 0= IF ( falls nicht gefunden: )
; DROP ( false-Flag vergessen )
; HERE LATEST (FIND) ( CURRENT-Vokabular nach dem Wort absuchen )
; ENDIF
; ;
NFA_MINUSFIND .CBYTE $85,"-FIND"
LFA_MINUSFIND .WORD NFA_NUMBER
CFA_MINUSFIND .WORD DOCOL
PFA_MINUSFIND
.WORD CFA_BL ; BL
.WORD CFA_WORD ; WORD
.WORD CFA_CONTEXT ; CONTEXT
.WORD CFA_FETCH ; @
.WORD CFA_FETCH ; @
.WORD CFA_BRACKETFIND ; (FIND)
.WORD CFA_DUP ; DUP
.WORD CFA_NULLEQUAL ; 0=
.WORD CFA_0BRANCH ; 0BRACH
.WORD LBL29-*
.WORD CFA_DROP ; DROP
.WORD CFA_HERE ; HERE
.WORD CFA_LATEST ; LATEST
.WORD CFA_BRACKETFIND ; (FIND)
LBL29
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> (ABORT) <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( [ABORT] [ ] wird im Anschluss an eine Fehlermeldung ausgefuehrt, wenn die )
;( User-Variable WARNING den Wert -1 hat. Es wird lediglich das Wort ABORT )
;( aufgerufen. )
;( ========================================================================= )
;
; : (ABORT) ABORT ;
NFA_PARENTABORT .CBYTE $87,"(ABORT)"
LFA_PARENTABORT .WORD NFA_MINUSFIND
CFA_PARENTABORT .WORD DOCOL
PFA_PARENTABORT
.WORD CFA_ABORT ; ABORT
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> ERROR <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( ERROR [ n -> in blk ] gibt je nach Inhalt der User-Variablen WARNING den )
;( Text der Zeile n relativ zu Zeile 0 in Screen 4 aus [WARNING=1] oder )
;( lediglich eine verkuerzte Fehlermeldung unter Angabe der Fehlernummer n )
;( [WARNING=0]. Ist WARNING=-1, so wird [ABORT] aufgerufen. Schliesslich )
;( wird der Inhalt der User-Variablen IN und BLK zurueckgegeben. )
;( ========================================================================= )
; : ERROR
; WARNING @ 0< IF (ABORT) THEN
; HERE COUNT TYPE ."?" MESSAGE SP!
; IN @ BLK @ QUIT ;
NFA_ERROR .CBYTE $85, "ERROR"
LFA_ERROR .WORD NFA_PARENTABORT
CFA_ERROR .WORD DOCOL
PFA_ERROR
.WORD CFA_WARNING ; WARNING
.WORD CFA_FETCH ; @
.WORD CFA_LTNULL ; 0<
.WORD CFA_0BRANCH ; 0BRANCH
.WORD LBL30-*
.WORD CFA_PARENTABORT ; (ABORT)
LBL30
.WORD CFA_HERE ; HERE
.WORD CFA_COUNT ; COUNT
.WORD CFA_TYPE ; TYPE
.WORD CFA_BRAKETDOTQUOTE ; (.")
.BYTE 2
.BYTE 63
.BYTE 32
.WORD CFA_MESSAGE ; MESSAGE
.WORD CFA_SPSTORE ; SP!
;.WORD CFA_IN ; IN ; auskommentiert da wir keine blockbefehle haben
;.WORD CFA_FETCH ; @ ; to do --> umsetzen fuer Dateizugriff
;.WORD CFA_BLK ; BLK
;.WORD CFA_FETCH ; @
.WORD CFA_QUIT ; QUIT
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> ID. <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( ID. [ addr -> ] kopiert das Namenfeld des Wortes, auf dessen NFA addr )
;( zeigt, nach PAD und gibt den Namen, gefolgt von einem Blank, auf die )
;( Standardausgabe aus. )
;( ========================================================================= )
;
;( Die mit [*] gekennzeichneten Zeilen sind hinzugefuegt worden, damit auch )
;( auf Rechnern mit einem erweiterten 8-Bit-Zeichensatz der Name korrekt )
;( ausgegeben wird. )
;
; : ID.
; PAD 32 95 FILL ( PAD mit 32 Underscores fuellen )
; DUP PFA LFA ( LFA des Wortes ermitteln )
; OVER - ( Differenz mit NFA ergibt Laenge des Namenfeldes )
; SWAP OVER ( Laenge noch mal retten [*] )
; PAD SWAP CMOVE ( gesamtes Namenfeld nach PAD kopieren )
; 1 - PAD + 128 TOGGLE ( MS-Bit des letzten Zeichens loeschen [*] )
; PAD COUNT 31 AND TYPE ( Namen mit korrigiertem Count-Byte ausgeben )
; SPACE ( Blank ausgeben )
; ;
NFA_IDDOT .CBYTE $83,"ID."
LFA_IDDOT .WORD NFA_ERROR
CFA_IDDOT .WORD DOCOL
PFA_IDDOT
.WORD CFA_PAD ; PAD
.WORD CFA_CLIT ; CLIT
.BYTE 32
.WORD CFA_CLIT ; CLIT
.BYTE 95
.WORD CFA_FILL ; FILL
.WORD CFA_DUP ; DUP
.WORD CFA_PFA ; PFA
.WORD CFA_LFA ; LFA
.WORD CFA_OVER ; OVER
.WORD CFA_MINUS ; -
.WORD CFA_SWAP ; SWAP
.WORD CFA_OVER ; OVER
.WORD CFA_PAD ; PAD
.WORD CFA_SWAP ; SWAP
.WORD CFA_CMOVE ; CMOVE
.WORD CFA_1 ; 1
.WORD CFA_MINUS ; -
.WORD CFA_PAD ; PAD
.WORD CFA_PLUS ; +
.WORD CFA_CLIT ; CLIT
.BYTE 128
.WORD CFA_TOGGLE ; TOGGLE
.WORD CFA_PAD ; PAD
.WORD CFA_COUNT ; COUNT
.WORD CFA_CLIT ; CLIT
.BYTE 31
.WORD CFA_AND ; AND
.WORD CFA_TYPE ; TYPE
.WORD CFA_SPACE ; SPACE
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> CREATE <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( CREATE [ ] erzeugt einen Wort-Header im Dictionary. )
;( ========================================================================= )
;
; : CREATE
; TIB HERE 160 + U< 2 ?ERROR ( nur 6502: Fehler falls kein Platz mehr )
; -FIND IF ( Namenstring ablegen; falls schon vorhanden: )
; DROP NFA ID. ( Namen ausgeben )
; 4 MESSAGE SPACE ( Fehlermeldung 4 und Blank ausgeben )
; ENDIF
; HERE DUP C@ WIDTH @ MIN ( Laenge des evtl. gekuerzten Namen )
; 1+ ALLOT ( plus Count-Byte: ins Dictionary einverleiben )
; DP C@ 253 = ALLOT ( nur 6502: Codefeld darf nicht auf FF liegen )
; DUP 160 TOGGLE ( hoechstes und SMUDGE-Bit setzen )
; HERE 1 - 128 TOGGLE ( hoechstes Bit im letzten Buchstaben setzen )
; LATEST , ( Link-Feld auf vorheriges Wort zeigen lassen )
; CURRENT @ ! ( Current-Kette beginnt b. NFA d. neuen Wortes )
; HERE 2+ , ( naechste Adresse in das Codefeld schreiben )
; ;
NFA_CREATE .CBYTE $86,"CREATE"
LFA_CREATE .WORD NFA_IDDOT
CFA_CREATE .WORD DOCOL
PFA_CREATE
.WORD CFA_TIB ; TIB
.WORD CFA_HERE ; HERE
.WORD CFA_CLIT ; CLIT
.BYTE 160
.WORD CFA_PLUS ; +
.WORD CFA_ULT ; U<
.WORD CFA_2 ; 2
.WORD CFA_QUERYERROR ; ?ERROR
.WORD CFA_MINUSFIND ; -FIND
.WORD CFA_0BRANCH ; 0BRANCH
.WORD LBL31-*
.WORD CFA_DROP ; DROP
.WORD CFA_NFA ; NFA
.WORD CFA_IDDOT ; ID.
.WORD CFA_CLIT ; CLIT
.BYTE 4
.WORD CFA_MESSAGE ; MESSAGE
.WORD CFA_SPACE ; SPACE
LBL31
.WORD CFA_HERE ; HERE
.WORD CFA_DUP ; DUP
.WORD CFA_CFETCH ; C@
.WORD CFA_WIDTH ; WIDTH
.WORD CFA_FETCH ; @
.WORD CFA_MIN ; MIN
.WORD CFA_1PLUS ; 1+
.WORD CFA_ALLOT ; ALLOT
.WORD CFA_DP ; DP
.WORD CFA_CFETCH ; C@
.WORD CFA_CLIT ; CLIT
.BYTE 253
.WORD CFA_EQUAL ; =
.WORD CFA_ALLOT ; ALLOT
.WORD CFA_DUP ; DUP
.WORD CFA_CLIT ; CLIT
.BYTE 160
.WORD CFA_TOGGLE ; TOGGLE
.WORD CFA_HERE ; HERE
.WORD CFA_1 ; 1
.WORD CFA_MINUS ; -
.WORD CFA_CLIT ; CLIT
.BYTE 128
.WORD CFA_TOGGLE ; TOGGLE
.WORD CFA_LATEST ; LATEST
.WORD CFA_COMMA ; ,
.WORD CFA_CURRENT ; CURRENT
.WORD CFA_FETCH ; @
.WORD CFA_STORE ; !
.WORD CFA_HERE ; HERE
.WORD CFA_2PLUS ; 2+
.WORD CFA_COMMA ; ,
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> [COMPILE] <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( [COMPILE] [ ] kompiliert das im Input-Stream folgende Wort in das )
;( Dictionary. )
;( ========================================================================= )
;
; : [COMPILE]
; -FIND 0= 0 ?ERROR ( Fehlermeldung ausgeben, falls Wort nicht vorhanden )
; DROP CFA , ( sonst CFA des Wortes in das Dictionary kompilieren )
; ; IMMEDIATE
NFA_BRACKETCOMPILE .CBYTE $89+$40,"[COMPILE]" ; IMMEDIATE
LFA_BRACKETCOMPILE .WORD NFA_CREATE
CFA_BRACKETCOMPILE .WORD DOCOL
PFA_BRACKETCOMPILE
.WORD CFA_MINUSFIND ; -FIND
.WORD CFA_NULLEQUAL ; 0=
.WORD CFA_0 ; 0
.WORD CFA_QUERYERROR ; ?ERROR
.WORD CFA_DROP ; DROP
.WORD CFA_CFA ; CFA
.WORD CFA_COMMA ; ,
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> LITERAL <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( LITERAL [ n -> n ] falls Execute-Mode, [ n -> ] falls Compile-Mode. )
;( Im Compile-Mode wird die Zahl n mitsamt einem LIT in das Dictionary )
;( kompiliert. Im Execute-Mode hat der Aufruf keinen Effekt. )
;( ========================================================================= )
;
; : LITERAL
; STATE @ IF ( falls Compile-Mode: )
; COMPILE LIT ( Wort LIT in das Dictionary kompilieren )
; , ( Zahl n in das Dictionary kompilieren )
; ENDIF
; ; IMMEDIATE
NFA_LITERAL .CBYTE $87+$40,"LITERAL" ; IMMEDIATE
LFA_LITERAL .WORD NFA_BRACKETCOMPILE
CFA_LITERAL .WORD DOCOL
PFA_LITERAL
.WORD CFA_STATE ; STATE
.WORD CFA_FETCH ; @
.WORD CFA_0BRANCH ; 0BRANCH
.WORD LBL32-*
.WORD CFA_COMPILE ; COMPILE
.WORD CFA_LIT ; LIT
.WORD CFA_COMMA ; ,
LBL32
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> DLITERAL <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( DLITERAL [ d -> d ] falls Execute-Mode, [ d -> ] falls Compile-Mode. )
;( Im Compile-Mode wird die doppeltgenaue Zahl d mitsamt entsprechenden )
;( LITs in das Dictionary kompiliert. Im Execute-Mode hat der Aufruf keinen )
;( Effekt. )
;( ========================================================================= )
;
; : DLITERAL
; STATE @ IF ( falls Compile-Mode: )
; SWAP ( Hi- und Lo-Word von d vertauschen )
; [COMPILE] LITERAL ( LIT und Lo-Word von d kompilieren )
; [COMPILE] LITERAL ( LIT und Hi-Word von d kompilieren )
; ENDIF
; ; IMMEDIATE
NFA_DLITERAL .CBYTE $88+$40,"DLITERAL" ; IMMEDIATE
LFA_DLITERAL .WORD NFA_LITERAL
CFA_DLITERAL .WORD DOCOL
PFA_DLITERAL
.WORD CFA_STATE ; STATE
.WORD CFA_FETCH ; @
.WORD CFA_0BRANCH ; 0BRANCH
.WORD LBL33-*
.WORD CFA_SWAP ; SWAP
.WORD CFA_LITERAL ; LITERAL
.WORD CFA_LITERAL ; LITERAL
LBL33
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> ?STACK <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( ?STACK [ ] gibt eine Fehlermeldung aus, falls der Stack ueber seine )
;( Grenzen gewachsen ist. )
;( ========================================================================= )
;
; : ?STACK
; SP@ ASM TOS SWAP U< 1 ?ERROR ( Fehlermeldung falls Stack-Unterlauf )
; SP@ ASM BOS U< 7 ?ERROR ( Fehlermeldung falls Stack-Ueberlauf )
; ;
NFA_QUERYSTACK .CBYTE $86,"?STACK"
LFA_QUERYSTACK .WORD NFA_DLITERAL
CFA_QUERYSTACK .WORD DOCOL
PFA_QUERYSTACK
.WORD CFA_SPFETCH ; SP@
.WORD CFA_LIT ; LIT
.WORD TOS
.WORD CFA_SWAP ; SWAP
.WORD CFA_ULT ; U<
.WORD CFA_1 ; 1
.WORD CFA_QUERYERROR ; ?ERROR
.WORD CFA_SPFETCH ; SP@
.WORD CFA_LIT ; LIT
.WORD BOS
.WORD CFA_ULT ; U<
.WORD CFA_CLIT ; CLIT
.BYTE 7
.WORD CFA_QUERYERROR ; ?ERROR
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> INTERPRET <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( INTERPRET [ ] ist der Kern des aeusseren Interpreters. Text wird geholt )
;( und, je nach Systemzustand, ausgefuehrt oder kompiliert. ASCII Null been- )
;( det die Prozedur. )
;( ========================================================================= )
;
; : INTERPRET
; BEGIN ( Endlosschleife )
; -FIND IF ( Wort lesen; falls vorhanden: )
; STATE @ < IF ( falls Compile-Mode und nicht IMMEDIATE: )
; CFA , ( CFA des Wortes kompilieren )
; ELSE ( sonst: )
; CFA EXECUTE ( Wort ausfuehren )
; ENDIF
; ?STACK ( Stack ueberpruefen )
; ELSE ( falls Wort nicht vorhanden: )
; HERE NUMBER ( Wort in Zahl umwandeln )
; DPL @ 1+ IF ( falls Dezimalpunkt vorhanden: )
; [COMPILE] DLITERAL ( doppelt-genaue Zahl kompilieren )
; ELSE ( falls kein Dezimalpunkt vorhanden: )
; DROP [COMPILE] LITERAL ( einfach genaue Zahl kompilieren )
; ENDIF
; ?STACK ( Stack ueberpruefen )
; ENDIF
; AGAIN ( Ende der Endlosschleife )
; ;
NFA_INTERPRET .CBYTE $89,"INTERPRET"
LFA_INTERPRET .WORD NFA_QUERYSTACK
CFA_INTERPRET .WORD DOCOL
PFA_INTERPRET
LBL34
.WORD CFA_MINUSFIND ; -FIND
.WORD CFA_0BRANCH ; 0BRANCH
.WORD LBL35-*
.WORD CFA_STATE ; STATE
.WORD CFA_FETCH ; @
.WORD CFA_LT ; <
.WORD CFA_0BRANCH ; 0BRANCH
.WORD LBL36-*
.WORD CFA_CFA ; CFA
.WORD CFA_COMMA ; ,
.WORD CFA_BRANCH ; BRANCH
.WORD LBL37-*
LBL36
.WORD CFA_CFA ; CFA
.WORD CFA_EXECUTE ; EXECUTE
LBL37
.WORD CFA_QUERYSTACK ; ?STACK
.WORD CFA_BRANCH ; BRANCH
.WORD LBL38-*
LBL35
.WORD CFA_HERE ; HERE
.WORD CFA_NUMBER ; NUMBER
.WORD CFA_DPL ; DPL
.WORD CFA_FETCH ; @
.WORD CFA_1PLUS ; 1+
.WORD CFA_0BRANCH ; 0BRANCH
.WORD LBL39-*
.WORD CFA_DLITERAL ; DLITERAL
.WORD CFA_BRANCH ; BRANCH
.WORD LBL40-*
LBL39
.WORD CFA_DROP ; DROP
.WORD CFA_LITERAL ; LITERAL
LBL40
.WORD CFA_QUERYSTACK ; ?STACK
LBL38
.WORD CFA_BRANCH ; BRANCH
.WORD LBL34-*
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> IMMEDIATE <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( IMMEDIATE [ ] dreht das Precedence-Bit des zuletzt definierten Wortes um. )
;( ========================================================================= )
;
; : IMMEDIATE LATEST 64 TOGGLE ;
NFA_IMMEDIATE .CBYTE $89, "IMMEDIATE"
LFA_IMMEDIATE .WORD NFA_INTERPRET
CFA_IMMEDIATE .WORD DOCOL
PFA_IMMEDIATE
.WORD CFA_LATEST ; LATEST
.WORD CFA_CLIT ; CLIT
.BYTE 64
.WORD CFA_TOGGLE ; TOGGLE
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> VOCABULARY <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( VOCABULARY [ ] definiert ein Vokabular. )
;( ========================================================================= )
;
; : VOCABULARY
; <BUILDS ( provisorischen Header des Vokabulars aufbauen )
; -24447 , ( Header 81 A0 eines Dummy-Wortes " " aufbauen )
; CURRENT @ CFA , ( NFA des letzten " "-Dummys in LFA von " " eintragen )
; HERE ( aktueller Wert von DP = CFA von " " )
; VOC-LINK @ , ( Link zum letzten Vokabular in CFA von " " eintragen )
; VOC-LINK ! ( CFA von " " in der User-Variablen VOC-LINK sichern )
; DOES> ( das neue Vokabular-Wort tut bei Aufruf folgendes: )
; 2+ CONTEXT ! ( LFA von " " in CONTEXT ablegen )
; ;
NFA_VOCABULARY .CBYTE $8A, "VOCABULARY"
LFA_VOCABULARY .WORD NFA_IMMEDIATE
CFA_VOCABULARY .WORD DOCOL
PFA_VOCABULARY
.WORD CFA_BUILDS ; <BUILDS
.WORD CFA_LIT ; LIT
.WORD -24447
.WORD CFA_COMMA ; ,
.WORD CFA_CURRENT ; CURRENT
.WORD CFA_FETCH ; @
.WORD CFA_CFA ; CFA
.WORD CFA_COMMA ; ,
.WORD CFA_HERE ; HERE
.WORD CFA_VOCLINK ; VOC-LINK
.WORD CFA_FETCH ; @
.WORD CFA_COMMA ; ,
.WORD CFA_VOCLINK ; VOC-LINK
.WORD CFA_STORE ; !
.WORD CFA_DOES ; DOES>
DOES156
.WORD CFA_2PLUS ; 2+
.WORD CFA_CONTEXT ; CONTEXT
.WORD CFA_STORE ; !
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> FORTH <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( FORTH [ ] macht das FORTH-Vokabular zum CONTEXT-Vokabular. )
;( ========================================================================= )
;
; VOCABULARY FORTH IMMEDIATE
;
; FORTH DEFINITIONS
NFA_FORTH .CBYTE $85+$40, "FORTH"
LFA_FORTH .WORD NFA_VOCABULARY
CFA_FORTH .WORD DODOE
PFA_FORTH
.WORD DOES156
.BYTE 129
.BYTE 160
.WORD NFA_MON
.WORD 0
; >>>>>>>>>>>>>>>> DEFINITIONS <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( DEFINITIONS [ ] macht das Context-Vokabular auch current. )
;( ========================================================================= )
;
; : DEFINITIONS CONTEXT @ CURRENT ! ;
NFA_DEFINITIONS .CBYTE $8B, "DEFINITIONS"
LFA_DEFINITIONS .WORD NFA_FORTH
CFA_DEFINITIONS .WORD DOCOL
PFA_DEFINITIONS
.WORD CFA_CONTEXT ; CONTEXT
.WORD CFA_FETCH ; @
.WORD CFA_CURRENT ; CURRENT
.WORD CFA_STORE ; !
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> ( <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( [ [ ] leitet einen Kommentar ein, der bis zur naechsten schliessenden )
;( Klammer reicht. )
;( ========================================================================= )
;
; : ( 41 WORD DROP ; IMMEDIATE ( bis zur naechsten "Klammer zu" ueberlesen )
NFA_LEFTPAREN .CBYTE $81+$40, "(" ; IMMEDIATE
LFA_LEFTPAREN .WORD NFA_DEFINITIONS
CFA_LEFTPAREN .WORD DOCOL
PFA_LEFTPAREN
.WORD CFA_CLIT ; CLIT
.BYTE 41
.WORD CFA_WORD ; WORD
.WORD CFA_DROP ; DROP
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> QUIT <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( QUIT [ ] schaltet auf Keyboard-Eingabe um, beendet den Compile-Mode und )
;( tritt in eine Endlosschleife ein, in der der Benutzer Eingaben macht und )
;( diese anschliessend interpretiert werden. )
;( ========================================================================= )
; : QUIT
; 0 SOURCE-ID ! ( auf Keyboard-Eingabe umschalten )
; [COMPILE] [ ( auf Execute-Mode umschalten )
; BEGIN ( Endlosschleife: )
; RP! ( Returnstack-Pointer reinitialisieren )
; CR ( Zeilenvorschub ausgeben )
; QUERY ( eine Zeile Text in den Terminal-Input-Buffer einlesen )
; INTERPRET ( Zeile interpretieren, ASCII 0 beendet Interpretation )
; STATE @ 0= IF ( falls Execute-Mode: )
; ." OK" ( "OK" ausgeben )
; ENDIF
; AGAIN ( Ende der Endlosschleife )
; ;
NFA_QUIT .CBYTE $84, "QUIT"
LFA_QUIT .WORD NFA_LEFTPAREN
CFA_QUIT .WORD DOCOL
PFA_QUIT
.WORD CFA_0 ; 0
.WORD CFA_SOURCEID ; SOURCE-ID
.WORD CFA_STORE ; !
.WORD CFA_LEFTBRACKET ; [
LBL41
.WORD CFA_RPSTORE ; RP!
.WORD CFA_CR ; CR
.WORD CFA_QUERY ; QUERY
.WORD CFA_INTERPRET ; INTERPRET
.WORD CFA_STATE ; STATE
.WORD CFA_FETCH ; @
.WORD CFA_NULLEQUAL ; 0=
.WORD CFA_0BRANCH ; 0BRANCH
.WORD LBL42-*
.WORD CFA_BRAKETDOTQUOTE ; (.")
.BYTE 2
.BYTE 79
.BYTE 75
LBL42
.WORD CFA_BRANCH ; BRANCH
.WORD LBL41-*
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> ABORT <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( ABORT [ ] reinitialisiert die Stacks, schaltet in den Execute-Mode um und )
;( geht in den aeusseren Interpreter QUIT ueber. )
;( ========================================================================= )
;
; : ABORT
; SP! DECIMAL DR0 ( Initialisierungen vornehmen )
; CR ." X-FORTH 1.1" ( Systemmeldung ausgeben )
; [COMPILE] FORTH DEFINITIONS ( FORTH zum aktuellen Vokabular machen )
; QUIT ( zum aeusseren Interpreter QUIT )
; ;
NFA_ABORT .CBYTE $85,"ABORT"
LFA_ABORT .WORD NFA_QUIT
CFA_ABORT .WORD DOCOL
PFA_ABORT
.WORD CFA_SPSTORE ; SP!
.WORD CFA_DECIMAL ; DECIMAL
.WORD CFA_CR ; CR
.WORD CFA_FORTH ; FORTH
.WORD CFA_DEFINITIONS ; DEFINITIONS
;.WORD CFA_BRAKETDOTQUOTE ; (.")
;.BYTE 22,"X-FORTH 1.1c 040410/cs"
ABORTINIT
.WORD CFA_QUIT ; QUIT
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> COLD <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( COLD [ ] fuehrt einen Kaltstart des Systems durch. )
;( ========================================================================= )
NFA_COLD .CBYTE $84, "COLD"
LFA_COLD .WORD NFA_ABORT
CFA_COLD .WORD PFA_COLD
PFA_COLD
SEI ; maskierbare Interrupts sperren
; USERAREA default siehe ORIGIN+16
.IF DYNMEMTOP ; USERAREA nach MEMTOP ($2E5)-$100 setzen
LDA $02E5
STA ORIG+16
LDA $02E6
SEC
SBC #2
STA ORIG+17
.ENDIF
RESET
LDA DOSINI
STA DOSIN+1
LDA DOSINI+1
STA DOSIN+2
LDA ORIG+12 ; NFA des letzten Wortes im Dictionary
STA PFA_FORTH+4 ; in das Vokabular-Wort FORTH eintragen
LDA ORIG+13
STA PFA_FORTH+5
LDY #21 ; Kaltstart: Uservariablen 0 bis VOC-LINK init.
BNE L2433 ; d.h. zusaetzlich FENCE, DP und VOC-LINK
WARM
DOSIN
JSR $E474 ; wird ueberschrieben!
LDY #15 ; Warmstart: nur Uservariablen 0 bis WARNING init.
L2433
LDA ORIG+16 ; User-Pointer UP initialisieren
STA UP
LDA ORIG+17
STA UP+1
L2437
LDA ORIG+12,Y ; Uservariablen mit Werten ab 12+ORIGIN initialis.
STA (UP),Y
DEY
BPL L2437
LDA #>PFA_ABORT ; Instruction-Pointer IP initialisieren:
STA IP+1 ; Interpretation beginnt mit dem Wort ABORT
LDA #<PFA_ABORT
STA IP
CLD ; Dezimalarithmetik ausschalten
LDA #$6C ; Opcode fuer JMP (), d.h. indirekten Sprung
STA W-1 ; unmittelbar vor das W-Register schreiben
CLI ; maskierbare Interrupts zulassen
LDA #<WARM
STA DOSINI
LDA #>WARM
STA DOSINI+1
JMP PFA_RPSTORE ; Returnstackpointer initialisieren und ABORT
; >>>>>>>>>>>>>>>> S>D <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( S>D [ n -> d ] wandelt die Zahl n in eine doppeltgenaue Zahl d um. )
;( ========================================================================= )
;
; : S>D DUP 0< MINUS ; ( $0000 oder $FFFF als Hi-Word erzeugen )
NFA_STOD .CBYTE $83, "S>D"
LFA_STOD .WORD NFA_COLD
CFA_STOD .WORD DOCOL
PFA_STOD
.WORD CFA_DUP ; DUP
.WORD CFA_LTNULL ; 0<
.WORD CFA_NEGATE ; MINUS
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> +- <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( +- [ n1 n2 -> n3 ] gibt n3=-n1 zurueck, wenn n2 negativ ist, sonst n3=n1. )
;( ========================================================================= )
;
; : +- 0< IF MINUS ENDIF ;
NFA_PLUSMINUS .CBYTE $82,"+-"
LFA_PLUSMINUS .WORD NFA_STOD
CFA_PLUSMINUS .WORD DOCOL
PFA_PLUSMINUS
.WORD CFA_LTNULL ; 0<
.WORD CFA_0BRANCH ; 0BRANCH
.WORD LBL43-*
.WORD CFA_NEGATE ; MINUS
LBL43
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> D+- <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( D+- [ d1 n -> d2 ] gibt d2=-d1 zurueck, wenn n negativ ist, sonst d2=d1. )
;( Hierbei sind d1 und d2 doppeltgenaue Zahlen. )
;( ========================================================================= )
;
; : D+- 0< IF DMINUS ENDIF ;
NFA_DPLUSMINUS .CBYTE $83,"D+-"
LFA_DPLUSMINUS .WORD NFA_PLUSMINUS
CFA_DPLUSMINUS .WORD DOCOL
PFA_DPLUSMINUS
.WORD CFA_LTNULL ; 0<
.WORD CFA_0BRANCH ; 0BRANCH
.WORD LBL44-*
.WORD CFA_DMINUS ; DMINUS
LBL44
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> ABS <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( ABS [ n -> u ] berechnet den absoluten Betrag der Zahl n. )
;( ========================================================================= )
;
; : ABS DUP +- ;
NFA_ABS .CBYTE $83,"ABS"
LFA_ABS .WORD NFA_DPLUSMINUS
CFA_ABS .WORD DOCOL
PFA_ABS
.WORD CFA_DUP ; DUP
.WORD CFA_PLUSMINUS ; +-
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> DABS <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( DABS [ d -> ud ] berechnet den absoluten Betrag der doppeltgenauen )
;( Zahl d. )
;( ========================================================================= )
;
; : DABS DUP D+- ;
NFA_DABS .CBYTE $84,"DABS"
LFA_DABS .WORD NFA_ABS
CFA_DABS .WORD DOCOL
PFA_DABS
.WORD CFA_DUP ; DUP
.WORD CFA_DPLUSMINUS ; D+-
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> MIN <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( MIN [ n1 n2 -> min ] berechnet das Minimum der Zahlen n1 und n2. )
;( ========================================================================= )
;
; : MIN
; OVER OVER > IF ( falls n1>n2 ist: )
; SWAP ( n1 in den TOS tauschen )
; ENDIF
; DROP ( groessere Zahl im TOS vergessen )
; ;
NFA_MIN .CBYTE $83,"MIN"
LFA_MIN .WORD NFA_DABS
CFA_MIN .WORD DOCOL
PFA_MIN
.WORD CFA_OVER ; OVER
.WORD CFA_OVER ; OVER
.WORD CFA_GT ; >
.WORD CFA_0BRANCH ; 0BRANCH
.WORD LBL45-*
.WORD CFA_SWAP ; SWAP
LBL45
.WORD CFA_DROP ; DROP
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> MAX <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( MAX [ n1 n2 -> max ] berechnet das Maximum der Zahlen n1 und n2. )
;( ========================================================================= )
;
; : MAX
; OVER OVER < IF ( falls n1<n2 ist: )
; SWAP ( n1 in den TOS tauschen )
; ENDIF
; DROP ( kleinere Zahl im TOS vergessen )
; ;
NFA_MAX .CBYTE $83,"MAX"
LFA_MAX .WORD NFA_MIN
CFA_MAX .WORD DOCOL
PFA_MAX
.WORD CFA_OVER ; OVER
.WORD CFA_OVER ; OVER
.WORD CFA_LT ; <
.WORD CFA_0BRANCH ; 0BRANCH
.WORD LBL46-*
.WORD CFA_SWAP ; SWAP
LBL46
.WORD CFA_DROP ; DROP
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> M* <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( M* [ n1 n2 -> d ] multipliziert die beiden einfachgenauen Zahlen n1 und )
;( n2 und gibt das Ergebnis als doppeltgenaue Zahl d zurueck. )
;( ========================================================================= )
;
; : M*
; OVER OVER XOR >R ( Vorzeichen-Flag auf den Return-Stack bringen )
; ABS SWAP ABS U* ( absolute Betraege von n1 und n2 multiplizieren )
; R> D+- ( eventuell Ergebnis negieren )
; ;
NFA_MSTAR .CBYTE $82,"M*"
LFA_MSTAR .WORD NFA_MAX
CFA_MSTAR .WORD DOCOL
PFA_MSTAR
.WORD CFA_OVER ; OVER
.WORD CFA_OVER ; OVER
.WORD CFA_XOR ; XOR
.WORD CFA_RPUSH ; >R
.WORD CFA_ABS ; ABS
.WORD CFA_SWAP ; SWAP
.WORD CFA_ABS ; ABS
.WORD CFA_UMULT ; U*
.WORD CFA_RPOP ; R>
.WORD CFA_DPLUSMINUS ; D+-
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> M/ <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( M/ [ d n1 -> n2 n3 ] berechnet zur doppeltgenauen Zahl d und zur einfach- )
;( genauen Zahl n1 den Quotienten n3=d/n1 sowie den Rest n2, der das Vorzei- )
;( chen des Zaehlers d erhaelt. )
;( ========================================================================= )
;
; : M/
; OVER >R >R ( Hi-Wort von d und n1 auf den Return-Stack bringen )
; DABS R ABS U/ ( |d| durch |n1| teilen, Quotient liegt auf dem TOS )
; R> R XOR +- ( Quotient negieren, falls sign[d]<>sign[n1] )
; SWAP R> +- ( Rest negieren, falls d negativ ist )
; SWAP ( Quotient wieder in den TOS tauschen )
; ;
NFA_MSLASH .CBYTE $82,"M/"
LFA_MSLASH .WORD NFA_MSTAR
CFA_MSLASH .WORD DOCOL
PFA_MSLASH
.WORD CFA_OVER ; OVER
.WORD CFA_RPUSH ; >R
.WORD CFA_RPUSH ; >R
.WORD CFA_DABS ; DABS
.WORD CFA_R ; R
.WORD CFA_ABS ; ABS
.WORD CFA_UDIV ; U/
.WORD CFA_RPOP ; R>
.WORD CFA_R ; R
.WORD CFA_XOR ; XOR
.WORD CFA_PLUSMINUS ; +-
.WORD CFA_SWAP ; SWAP
.WORD CFA_RPOP ; R>
.WORD CFA_PLUSMINUS ; +-
.WORD CFA_SWAP ; SWAP
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> * <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( * [ n1 n2 -> n3 ] multipliziert die Zahlen n1 und n2. )
;( ========================================================================= )
;
; : * U* DROP ; ( multiplizieren und Hi-Word des Produktes vergessen )
NFA_STAR .CBYTE $81,"*"
LFA_STAR .WORD NFA_MSLASH
CFA_STAR .WORD DOCOL
PFA_STAR
.WORD CFA_UMULT ; U*
.WORD CFA_DROP ; DROP
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> /MOD <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( /MOD [ n1 n2 -> Rest Quot ] teilt die Zahl n1 durch die Zahl n2 und )
;( uebergibt den Rest und den Quotienten. )
;( ========================================================================= )
;
; : /MOD >R S>D R> M/ ; ( n1 doppeltgenau machen und M/ aufrufen )
NFA_SLASHMOD .CBYTE $84,"/MOD"
LFA_SLASHMOD .WORD NFA_STAR
CFA_SLASHMOD .WORD DOCOL
PFA_SLASHMOD
.WORD CFA_RPUSH ; >R
.WORD CFA_STOD ; S>D
.WORD CFA_RPOP ; R>
.WORD CFA_MSLASH ; M/
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> / <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( / [ n1 n2 -> Quotient ] berechnet den Quotienten n1/n2. )
;( ========================================================================= )
;
; : / /MOD SWAP DROP ;
NFA_SLASH .CBYTE $81,"/"
LFA_SLASH .WORD NFA_SLASHMOD
CFA_SLASH .WORD DOCOL
PFA_SLASH
.WORD CFA_SLASHMOD ; /MOD
.WORD CFA_SWAP ; SWAP
.WORD CFA_DROP ; DROP
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> MOD <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( MOD [ n1 n2 -> mod ] berechnet den Rest der Division n1/n2. )
;( ========================================================================= )
;
; : MOD /MOD DROP ;
NFA_MOD .CBYTE $83,"MOD"
LFA_MOD .WORD NFA_SLASH
CFA_MOD .WORD DOCOL
PFA_MOD
.WORD CFA_SLASHMOD ; /MOD
.WORD CFA_DROP ; DROP
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> */MOD <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( */MOD [ n1 n2 n3 -> n4 n5 ] berechnet [n1*n2]/n3 und uebergibt in n4 den )
;( Rest und in n5 den Quotienten. Es wird mit einem doppeltgenauen Zwischen- )
;( produkt n1*n2 gerechnet. )
;( ========================================================================= )
;
; : */MOD >R M* R> M/ ;
NFA_STARSLASHMOD .CBYTE $85, "*/MOD"
LFA_STARSLASHMOD .WORD NFA_MOD
CFA_STARSLASHMOD .WORD DOCOL
PFA_STARSLASHMOD
.WORD CFA_RPUSH ; >R
.WORD CFA_MSTAR ; M*
.WORD CFA_RPOP ; R>
.WORD CFA_MSLASH ; M/
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> */ <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( */ [ n1 n2 n3 -> n4 ] berechnet den Quotienten [n1*n2]/n3. Es wird mit )
;( einem doppeltgenauen Zwischenprodukt n1*n2 gerechnet. )
;( ========================================================================= )
;
; : */ */MOD SWAP DROP ;
NFA_STARSLASH .CBYTE $82,"*/"
LFA_STARSLASH .WORD NFA_STARSLASHMOD
CFA_STARSLASH .WORD DOCOL
PFA_STARSLASH
.WORD CFA_STARSLASHMOD ; */MOD
.WORD CFA_SWAP ; SWAP
.WORD CFA_DROP ; DROP
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> M/MOD <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( M/MOD [ ud1 u2 -> u3 ud4 ] dividiert die vorzeichenlose, doppeltgenaue )
;( Zahl ud1 durch die vorzeichenlose Zahl u2 und uebergibt den Rest u3 sowie )
;( den doppeltgenauen Quotienten ud4. )
;( ========================================================================= )
;
;( Funktionsweise des Algorithmus: Seien B=2^16 und ud1=a*B+b. Mit / sei die )
;( ganzzahlige Division bezeichnet, mit % die Restbildung. Dann gilt: )
;( ud4 = ud1/u2 = [a*B+b]/u2 = [a/u2]*B + [[a%u2]*B+b]/u2 und )
;( u3 = ud1%u2 = [a*B+b]%u2 = [[a%u2]*B+b]%u2. )
;( Im untenstehenden Kommentar bezeichne q=[[a%u2]*B+b]/u2. )
;
;: M/MOD ( b a u2 )
; >R ( b a RS: u2 )
; 0 R ( b a 0 u2 RS: u2 )
; U/ ( b a%u2 a/u2 RS: u2 )
; R> SWAP >R ( b a%u2 u2 RS: a/u2 )
; U/ ( u3 q RS: a/u2 )
; R> ( u3 q a/u2 )
; ;
NFA_MMOD .CBYTE $85, "M/MOD"
LFA_MMOD .WORD NFA_STARSLASH
CFA_MMOD .WORD DOCOL
PFA_MMOD
.WORD CFA_RPUSH ; >R
.WORD CFA_0 ; 0
.WORD CFA_R ; R
.WORD CFA_UDIV ; U/
.WORD CFA_RPOP ; R>
.WORD CFA_SWAP ; SWAP
.WORD CFA_RPUSH ; >R
.WORD CFA_UDIV ; U/
.WORD CFA_RPOP ; R>
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> MESSAGE <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( MESSAGE [ n -> ] gibt die Meldung Nummer n auf die Standardausgabe aus. )
;( Hat die User-Variable WARNING einen Wert ungleich Null, so ist dies der )
;( Inhalt der n-ten Zeile relativ zur Zeile 0 in Screen 4, Laufwerk 0. )
;( ========================================================================= )
NFA_MESSAGE .CBYTE $87, "MESSAGE"
LFA_MESSAGE .WORD NFA_MMOD
CFA_MESSAGE .WORD DOCOL
PFA_MESSAGE
.WORD CFA_BRAKETDOTQUOTE ; (.")
.BYTE 6,"MSG # "
.WORD CFA_DOT ; .
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> ' <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( ' [ -> addr ] ermittelt die PFA des folgenden Wortes. Im Compile-Mode )
;( wird die PFA des folgenden Wortes zusammen mit einem LIT kompiliert. )
;( ========================================================================= )
;
; : '
; -FIND ( Wort im Dictionary suchen )
; 0= 0 ?ERROR ( Fehlermeldung ausgeben, falls nicht gefunden )
; DROP ( Count-Byte des Wortes vergessen )
; [COMPILE] LITERAL ( PFA auf dem Stack lassen oder mit LIT kompilieren )
; ; IMMEDIATE
NFA_TICK .BYTE $81+$40, 167 ; IMMEDIATE
LFA_TICK .WORD NFA_MESSAGE
CFA_TICK .WORD DOCOL
PFA_TICK
.WORD CFA_MINUSFIND ; -FIND
.WORD CFA_NULLEQUAL ; 0=
.WORD CFA_0 ; 0
.WORD CFA_QUERYERROR ; ?ERROR
.WORD CFA_DROP ; DROP
.WORD CFA_LITERAL ; LITERAL
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> FORGET <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( FORGET [ ] loescht alle Woerter ab dem im Input-Strom folgenden aus dem )
;( Dictionary. Sind das Current- und das Context-Vokabular nicht identisch, )
;( so wird eine Fehlermeldung ausgegeben. )
;( ========================================================================= )
;
; : FORGET
; CURRENT @ CONTEXT @ - 24 ?ERROR ( Fehlermeldung falls CURRENT<>CONTEXT )
; [COMPILE] ' ( PFA des folgenden Wortes )
; DUP FENCE @ < 21 ?ERROR ( Fehlermeldung falls geschuetzt )
; DUP NFA DP ! ( Dictionary-Pointer herabsetzen )
; LFA @ CURRENT @ ! ( jetzt letztes Wort im Curr.-V. merken )
; ;
NFA_FORGET .CBYTE $86,"FORGET"
LFA_FORGET .WORD NFA_TICK
CFA_FORGET .WORD DOCOL
PFA_FORGET
.WORD CFA_CURRENT ; CURRENT
.WORD CFA_FETCH ; @
.WORD CFA_CONTEXT ; CONTEXT
.WORD CFA_FETCH ; @
.WORD CFA_MINUS ; -
.WORD CFA_CLIT ; CLIT
.BYTE 24
.WORD CFA_QUERYERROR ; ?ERROR
.WORD CFA_TICK ; '
.WORD CFA_DUP ; DUP
.WORD CFA_FENCE ; FENCE
.WORD CFA_FETCH ; @
.WORD CFA_LT ; <
.WORD CFA_CLIT ; CLIT
.BYTE 21
.WORD CFA_QUERYERROR ; ?ERROR
.WORD CFA_DUP ; DUP
.WORD CFA_NFA ; NFA
.WORD CFA_DP ; DP
.WORD CFA_STORE ; !
.WORD CFA_LFA ; LFA
.WORD CFA_FETCH ; @
.WORD CFA_CURRENT ; CURRENT
.WORD CFA_FETCH ; @
.WORD CFA_STORE ; !
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> BACK <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( BACK [ addr -> ] kompiliert die Distanz von HERE nach addr in das )
;( Dictionary. )
;( ========================================================================= )
;
; : BACK HERE - , ;
NFA_BACK .CBYTE $84,"BACK"
LFA_BACK .WORD NFA_FORGET
CFA_BACK .WORD DOCOL
PFA_BACK
.WORD CFA_HERE ; HERE
.WORD CFA_MINUS ; -
.WORD CFA_COMMA ; ,
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> BEGIN <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( BEGIN [ -> addr n ] legt die aktuelle Adresse HERE und die Strukturken- )
;( nung n=1 auf den Stack. Das Wort wird innerhalb von Colon-Definitionen )
;( verwendet und leitet eine der Strukturen BEGIN...UNTIL, BEGIN...AGAIN )
;( oder BEGIN...WHILE...REPEAT ein. )
;( ========================================================================= )
;
; : BEGIN ?COMP HERE 1 ; IMMEDIATE
NFA_BEGIN .CBYTE $85+$40,"BEGIN" ; IMMEDIATE
LFA_BEGIN .WORD NFA_BACK
CFA_BEGIN .WORD DOCOL
PFA_BEGIN
.WORD CFA_QUERYCOMP ; ?COMP
.WORD CFA_HERE ; HERE
.WORD CFA_1 ; 1
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> ENDIF <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( ENDIF [ addr n -> ] korrigiert die in der Adresse addr angelegte proviso- )
;( rische Sprungdistanz auf ihren korrekten Wert, naemlich nach HERE. Eine )
;( Fehlermeldung wird ausgegeben, wenn die Strukturkennung n<>2 ist und )
;( somit kein IF-Konstrukt abgeschlossen wurde. )
;( ========================================================================= )
;
; : ENDIF
; ?COMP ( Fehlermeldung falls nicht Compile-Mode )
; 2 ?PAIRS ( Fehlermeldung falls kein IF-Konstrukt abgeschlossen wurde )
; HERE OVER - ( Sprungdistanz berechnen )
; SWAP ! ( und in die durch addr bezeichnete Zelle eintragen )
; ; IMMEDIATE
NFA_ENDIF .CBYTE $85+$40, "ENDIF" ; IMMEDIATE
LFA_ENDIF .WORD NFA_BEGIN
CFA_ENDIF .WORD DOCOL
PFA_ENDIF
.WORD CFA_QUERYCOMP ; ?COMP
.WORD CFA_2 ; 2
.WORD CFA_QUERYPAIRS ; ?PAIRS
.WORD CFA_HERE ; HERE
.WORD CFA_OVER ; OVER
.WORD CFA_MINUS ; -
.WORD CFA_SWAP ; SWAP
.WORD CFA_STORE ; !
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> THEN <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( THEN [ addr n -> ] ist ein Alias fuer ENDIF. )
;( ========================================================================= )
;
; : THEN [COMPILE] ENDIF ; IMMEDIATE
NFA_THEN .CBYTE $84+$40, "THEN" ; IMMEDIATE
LFA_THEN .WORD NFA_ENDIF
CFA_THEN .WORD DOCOL
PFA_THEN
.WORD CFA_ENDIF ; ENDIF
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> DO <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( DO [ -> addr n ] legt die aktuelle Adresse HERE und die Strukturkennung )
;( n=3 auf den Stack und kompiliert ein [DO] in das Dictionary. Das Wort )
;( wird innerhalb von Colon-Definitionen verwendet und leitet eine der )
;( beiden Strukturen DO...LOOP oder DO...+LOOP ein. )
;( ========================================================================= )
;
; : DO
; COMPILE (DO) ( Runtime-Exekutive [DO] kompilieren )
; HERE 3 ( Adresse HERE und Strukturkennung n=3 auf den Stack legen )
; ; IMMEDIATE
NFA_DO .CBYTE $82+$40, "DO" ; IMMEDIATE
LFA_DO .WORD NFA_THEN
CFA_DO .WORD DOCOL
PFA_DO
.WORD CFA_COMPILE ; COMPILE
.WORD CFA_BRACKETDO ; (DO)
.WORD CFA_HERE ; HERE
.WORD CFA_3 ; 3
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> LOOP <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( LOOP [ addr n -> ] kompiliert die Runtime-Exekutive [LOOP] zusammen mit )
;( einer Ruecksprung-Distanz nach addr in das Dictionary und ueberprueft, ob )
;( die Strukturkennung n=3 uebergeben und somit eine DO-Struktur korrekt )
;( abgeschlossen wurde. )
;( ========================================================================= )
;
; : LOOP
; 3 ?PAIRS ( Fehler falls kein DO-Konstrukt abgeschlossen wurde )
; COMPILE (LOOP) ( Runtime-Exekutive [LOOP] kompilieren )
; BACK ( Ruecksprung-Distanz kompilieren )
; ; IMMEDIATE
NFA_LOOP .CBYTE $84+$40,"LOOP" ; IMMEDIATE
LFA_LOOP .WORD NFA_DO
CFA_LOOP .WORD DOCOL
PFA_LOOP
.WORD CFA_3 ; 3
.WORD CFA_QUERYPAIRS ; ?PAIRS
.WORD CFA_COMPILE ; COMPILE
.WORD CFA_BRACKETLOOP ; (LOOP)
.WORD CFA_BACK ; BACK
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> +LOOP <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( +LOOP [ addr n -> ] kompiliert die Runtime-Exekutive [+LOOP] zusammen mit )
;( einer Ruecksprung-Distanz nach addr in das Dictionary und ueberprueft, ob )
;( die Strukturkennung n=3 uebergeben und somit eine DO-Struktur korrekt )
;( abgeschlossen wurde. )
;( ========================================================================= )
;
; : +LOOP
; 3 ?PAIRS ( Fehler falls kein DO-Konstrukt abgeschlossen wurde )
; COMPILE (+LOOP) ( Runtime-Exekutive [+LOOP] kompilieren )
; BACK ( Ruecksprung-Distanz kompilieren )
; ; IMMEDIATE
NFA_ADDLOOP .CBYTE $85+$40, "+LOOP" ; IMMEDIATE
LFA_ADDLOOP .WORD NFA_LOOP
CFA_ADDLOOP .WORD DOCOL
PFA_ADDLOOP
.WORD CFA_3 ; 3
.WORD CFA_QUERYPAIRS ; ?PAIRS
.WORD CFA_COMPILE ; COMPILE
.WORD CFA_BRACKETPLUSLOOP ; (+LOOP)
.WORD CFA_BACK ; BACK
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> UNTIL <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( UNTIL [ addr n -> ] kompiliert einen bedingten Ruecksprung nach Adresse )
;( addr in das Dictionary und ueberprueft, ob die Strukturkennung n=1 ueber- )
;( geben und somit eine BEGIN-Struktur korrekt abgeschlossen wurde. )
;( ========================================================================= )
;
; : UNTIL
; 1 ?PAIRS ( Fehler falls kein BEGIN-Konstrukt abgeschlossen wurde )
; COMPILE 0BRANCH ( bedingten Sprung kompilieren )
; BACK ( Ruecksprung-Distanz kompilieren )
; ; IMMEDIATE
NFA_UNTIL .CBYTE $85+$40, "UNTIL" ; IMMEDIATE
LFA_UNTIL .WORD NFA_ADDLOOP
CFA_UNTIL .WORD DOCOL
PFA_UNTIL
.WORD CFA_1 ; 1
.WORD CFA_QUERYPAIRS ; ?PAIRS
.WORD CFA_COMPILE ; COMPILE
.WORD CFA_0BRANCH ; 0BRANCH
.WORD CFA_BACK ; BACK
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> END <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( END [ addr n -> ] ist ein Alias fuer UNTIL. )
;( ========================================================================= )
;
; : END [COMPILE] UNTIL ; IMMEDIATE
NFA_END .CBYTE $83+$40, "END" ; IMMEDIATE
LFA_END .WORD NFA_UNTIL
CFA_END .WORD DOCOL
PFA_END
.WORD CFA_UNTIL ; UNTIL
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> AGAIN <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( AGAIN [ addr n -> ] kompiliert einen unbedingten Ruecksprung nach Adresse )
;( addr in das Dictionary und ueberprueft, ob die Strukturkennung n=1 ueber- )
;( geben und somit eine BEGIN-Struktur korrekt abgeschlossen wurde. )
;( ========================================================================= )
;
; : AGAIN
; 1 ?PAIRS ( Fehler falls kein BEGIN-Konstrukt abgeschlossen wurde )
; COMPILE BRANCH ( unbedingten Sprung kompilieren )
; BACK ( Ruecksprung-Distanz kompilieren )
; ; IMMEDIATE
NFA_AGAIN .CBYTE $85+$40,"AGAIN" ; IMMEDIATE
LFA_AGAIN .WORD NFA_END
CFA_AGAIN .WORD DOCOL
PFA_AGAIN
.WORD CFA_1 ; 1
.WORD CFA_QUERYPAIRS ; ?PAIRS
.WORD CFA_COMPILE ; COMPILE
.WORD CFA_BRANCH ; BRANCH
.WORD CFA_BACK ; BACK
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> REPEAT <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( REPEAT [ addr1 n1 addr2 n2 -> ] kompiliert einen unbedingten Ruecksprung )
;( nach Adresse addr1 in das Dictionary und korrigiert die Sprungdistanz bei )
;( Adresse addr2 derart, dass hinter den soeben kompilierten Sprung gesprun- )
;( gen wird. Darueberhinaus wird ueberprueft, ob mit n1=1 ein BEGIN- )
;( Konstrukt abgeschlossen wurde, der wegen n2=4 ein WHILE enthielt. )
;( ========================================================================= )
;
; : REPEAT
; >R >R ( addr2 und n2 auf den Return-Stack retten )
; [COMPILE] AGAIN ( unbedingten Ruecksprung nach addr1 kompilieren )
; R> R> ( addr2 und n2 zurueckholen )
; 2 - [COMPILE] ENDIF ( Vorwaertssprung bei Adresse addr2 korrigieren )
; ; IMMEDIATE
NFA_REPEAT .CBYTE $86+$40, "REPEAT" ; IMMEDITE
LFA_REPEAT .WORD NFA_AGAIN
CFA_REPEAT .WORD DOCOL
PFA_REPEAT
.WORD CFA_RPUSH ; >R
.WORD CFA_RPUSH ; >R
.WORD CFA_AGAIN ; AGAIN
.WORD CFA_RPOP ; R>
.WORD CFA_RPOP ; R>
.WORD CFA_2 ; 2
.WORD CFA_MINUS ; -
.WORD CFA_ENDIF ; ENDIF
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> IF <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( IF [ -> addr n ] kompiliert einen bedingten Sprung mit noch provisori- )
;( scher Sprungdistanz und legt die Adresse, an der die Distanz steht, sowie )
;( die Strukturkennung n=2 auf den Stack. Das Wort wird in Colon-Definitio- )
;( nen zur Einleitung eines IF...ENDIF- oder IF...ELSE...ENDIF-Konstruktes )
;( benutzt. )
;( ========================================================================= )
;
; : IF
; COMPILE 0BRANCH ( bedingten Sprung kompilieren )
; HERE ( Adresse addr, an der die Distanz steht )
; 0 , ( provisorische Sprungdistanz kompilieren )
; 2 ( Strukturkennung n=2 )
; ; IMMEDIATE
NFA_IF .CBYTE $82+$40,"IF" ; IMMEDIATE
LFA_IF .WORD NFA_REPEAT
CFA_IF .WORD DOCOL
PFA_IF
.WORD CFA_COMPILE ; COMPILE
.WORD CFA_0BRANCH ; 0BRANCH
.WORD CFA_HERE ; HERE
.WORD CFA_0 ; 0
.WORD CFA_COMMA ; ,
.WORD CFA_2 ; 2
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> ELSE <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( ELSE [ addr1 n1 -> addr2 n2 ] kompiliert einen unbedingten Sprung mit )
;( noch provisorischer Sprungdistanz und korrigiert die Sprungdistanz in )
;( addr1 derart, dass hinter den soeben kompilierten Sprung gesprungen wird. )
;( Darueberhinaus wird ueberprueft, ob mit n1=2 ein IF-Konstrukt um einen )
;( ELSE-Zweig ergaenzt wurde. Auf dem Stack werden die Adresse addr2, an der )
;( sich die soeben kompilierte provisorische Distanz befindet, und die )
;( Strukturkennung n2=2 hinterlassen. )
;( ========================================================================= )
;
; : ELSE
; 2 ?PAIRS ( Fehler falls kein IF-Konstrukt )
; COMPILE BRANCH ( unbedingten Sprung kompilieren )
; HERE ( Adresse addr2, an der die Distanz steht )
; 0 , ( provisorische Distanz kompilieren )
; SWAP 2 [COMPILE] ENDIF ( Sprungdistanz bei addr1 korrigieren )
; 2 ( Strukturkennung n2=2 )
; ; IMMEDIATE
NFA_ELSE .CBYTE $84+$40,"ELSE" ; IMMEDIATE
LFA_ELSE .WORD NFA_IF
CFA_ELSE .WORD DOCOL
PFA_ELSE
.WORD CFA_2 ; 2
.WORD CFA_QUERYPAIRS ; ?PAIRS
.WORD CFA_COMPILE ; COMPILE
.WORD CFA_BRANCH ; BRANCH
.WORD CFA_HERE ; HERE
.WORD CFA_0 ; 0
.WORD CFA_COMMA ; ,
.WORD CFA_SWAP ; SWAP
.WORD CFA_2 ; 2
.WORD CFA_ENDIF ; ENDIF
.WORD CFA_2 ; 2
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> WHILE <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( WHILE [ -> addr n ] kompiliert einen bedingten Vorwaertssprung mit noch )
;( provisorischer Sprungdistanz und hinterlaesst auf dem Stack die Adresse )
;( addr, an der die provisorische Sprungdistanz steht, und die Strukturken- )
;( nung n=4. )
;( ========================================================================= )
;
; : WHILE [COMPILE] IF 2+ ; IMMEDIATE
NFA_WHILE .CBYTE $85+$40, "WHILE" ; IMMEDIATE
LFA_WHILE .WORD NFA_ELSE
CFA_WHILE .WORD DOCOL
PFA_WHILE
.WORD CFA_IF ; IF
.WORD CFA_2PLUS ; 2+
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> SPACES <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( SPACES [ n -> ] gibt n Spaces auf die Standardausgabe aus. )
;( ========================================================================= )
;
; : SPACES
; 0 MAX -DUP IF ( falls n>0 ist: )
; 0 DO ( wiederhole n-mal: )
; SPACE ( Blank ausgeben )
; LOOP
; ENDIF
; ;
NFA_SPACES .CBYTE $86,"SPACES"
LFA_SPACES .WORD NFA_WHILE
CFA_SPACES .WORD DOCOL
PFA_SPACES
.WORD CFA_0 ; 0
.WORD CFA_MAX ; MAX
.WORD CFA_MINUSDUP ; -DUP
.WORD CFA_0BRANCH ; 0BRANCH
.WORD LBL50-*
.WORD CFA_0 ; 0
.WORD CFA_BRACKETDO ; (DO)
LBL51
.WORD CFA_SPACE ; SPACE
.WORD CFA_BRACKETLOOP ; (LOOP)
.WORD LBL51-*
LBL50
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> <# <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( <# [ ] leitet die Umwandlung einer doppeltgenauen Zahl in einen String, )
;( der von PAD-1 an abwaerts erzeugt wird, ein. )
;( ========================================================================= )
;
; : <# PAD HLD ! ; ( Laufzeiger HLD initialisieren )
NFA_LTSHARP .CBYTE $82,"<#"
LFA_LTSHARP .WORD NFA_SPACES
CFA_LTSHARP .WORD DOCOL
PFA_LTSHARP
.WORD CFA_PAD ; PAD
.WORD CFA_HLD ; HLD
.WORD CFA_STORE ; !
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> #> <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( #> [ ud -> addr n ] beendet die Umwandlung einer doppeltgenauen Zahl in )
;( einen String und uebergibt seine Startadresse addr und seine Laenge n. )
;( ========================================================================= )
;
; : #>
; DROP DROP ( evtl. noch vorhandenen Rest ud vergessen )
; HLD @ ( Startadresse addr des Strings )
; PAD OVER - ( Laenge n des Strings )
; ;
NFA_SHARPGT .CBYTE $82,"#>"
LFA_SHARPGT .WORD NFA_LTSHARP
CFA_SHARPGT .WORD DOCOL
PFA_SHARPGT
.WORD CFA_DROP ; DROP
.WORD CFA_DROP ; DROP
.WORD CFA_HLD ; HLD
.WORD CFA_FETCH ; @
.WORD CFA_PAD ; PAD
.WORD CFA_OVER ; OVER
.WORD CFA_MINUS ; -
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> SIGN <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( SIGN [ n d -> d ] fuegt an den im Aufbau befindlichen Zahlenstring ein )
;( Minuszeichen an, falls n negativ ist. Die doppeltgenaue Zahl d bleibt )
;( unveraendert. )
;( ========================================================================= )
;
; : SIGN
; ROT 0< IF ( falls n<0 ist: )
; 45 HOLD ( Zeichen "-" an den String anfuegen )
; ENDIF
; ;
NFA_SIGN .CBYTE $84,"SIGN"
LFA_SIGN .WORD NFA_SHARPGT
CFA_SIGN .WORD DOCOL
PFA_SIGN
.WORD CFA_ROT ; ROT
.WORD CFA_LTNULL ; 0<
.WORD CFA_0BRANCH ; 0BRANCH
.WORD LBL52-*
.WORD CFA_CLIT ; CLIT
.BYTE 45
.WORD CFA_HOLD ; HOLD
LBL52
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> # <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( # [ ud1 -> ud2 ] ermittelt aus der vorzeichenlosen, ganzen Zahl die )
;( niederwertigste Ziffer und fuegt sie an den im Aufbau befindlichen )
;( Zahlenstring an. Der verbleibende Rest ud2 wird auf dem Stack uebergeben. )
;( ========================================================================= )
;
; : #
; BASE @ M/MOD ( einfachgenaue Ziffer und doppeltgenauen Rest ermitteln )
; ROT ( Ziffer nach vorne holen )
; 9 OVER < IF ( falls Ziffer groesser als 9 ist: )
; 7 + ( 7 addieren, um im Buchstabenbereich zu landen )
; ENDIF
; 48 + ( "0" addieren; ergibt Ziffer als ASCII-Zeichen )
; HOLD ( Ziffer an den String anfuegen )
; ;
NFA_SHARP .CBYTE $81,"#"
LFA_SHARP .WORD NFA_SIGN
CFA_SHARP .WORD DOCOL
PFA_SHARP
.WORD CFA_BASE ; BASE
.WORD CFA_FETCH ; @
.WORD CFA_MMOD ; M/MOD
.WORD CFA_ROT ; ROT
.WORD CFA_CLIT ; CLIT
.BYTE 9
.WORD CFA_OVER ; OVER
.WORD CFA_LT ; <
.WORD CFA_0BRANCH ; 0BRANCH
.WORD LBL53-*
.WORD CFA_CLIT ; CLIT
.BYTE 7
.WORD CFA_PLUS ; +
LBL53
.WORD CFA_CLIT ; CLIT
.BYTE 48
.WORD CFA_PLUS ; +
.WORD CFA_HOLD ; HOLD
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> #S <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( #S [ ud1 -> ud2 ] fuegt solange Ziffern an den im Aufbau befindlichen )
;( Zahlenstring an, bis der Rest, der als ud2 uebergeben wird, 0 geworden )
;( ist. )
;( ========================================================================= )
;
; : #S
; BEGIN
; # ( eine Ziffer erzeugen und an den String anfuegen )
; OVER OVER OR 0= ( solange bis der verbleibende Rest 0 geworden ist )
; UNTIL
; ;
NFA_SHARPS .CBYTE $82,"#S"
LFA_SHARPS .WORD NFA_SHARP
CFA_SHARPS .WORD DOCOL
PFA_SHARPS
LBL54
.WORD CFA_SHARP ; #
.WORD CFA_OVER ; OVER
.WORD CFA_OVER ; OVER
.WORD CFA_OR ; OR
.WORD CFA_NULLEQUAL ; 0=
.WORD CFA_0BRANCH ; 0BRANCH
.WORD LBL54-*
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> D.R <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( D.R [ d n -> ] gibt die doppeltgenaue Zahl d rechtsbuendig in einem Feld )
;( der Breite n auf die Standardausgabe aus. )
;( ========================================================================= )
;
; : D.R
; >R ( Feldbreite n auf den Return-Stack retten )
; SWAP OVER ( [ hi d ] erzeugen; hi enthaelt das Vorzeichen von d )
; DABS ( absoluten Betrag von d ermitteln )
; <# #S SIGN #> ( d in einen String umwandeln und Vorzeichen beruecks. )
; R> OVER - SPACES ( zunaechst entsprechend viele Blanks ausgeben )
; TYPE ( anschliessend erzeugten String ausgeben )
; ;
NFA_DDOTR .CBYTE $83, "D.R"
LFA_DDOTR .WORD NFA_SHARPS
CFA_DDOTR .WORD DOCOL
PFA_DDOTR
.WORD CFA_RPUSH ; >R
.WORD CFA_SWAP ; SWAP
.WORD CFA_OVER ; OVER
.WORD CFA_DABS ; DABS
.WORD CFA_LTSHARP ; <#
.WORD CFA_SHARPS ; #S
.WORD CFA_SIGN ; SIGN
.WORD CFA_SHARPGT ; #>
.WORD CFA_RPOP ; R>
.WORD CFA_OVER ; OVER
.WORD CFA_MINUS ; -
.WORD CFA_SPACES ; SPACES
.WORD CFA_TYPE ; TYPE
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> .R <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( .R [ n1 n2 -> ] gibt die Zahl n1 rechtsbuendig in einem Feld der Breite )
;( n2 auf die Standardausgabe aus. )
;( ========================================================================= )
;
; : .R >R S>D R> D.R ; ( Zahl n1 doppeltgenau machen und mit D.R ausgeben )
NFA_DOTR .CBYTE $82,".R"
LFA_DOTR .WORD NFA_DDOTR
CFA_DOTR .WORD DOCOL
PFA_DOTR
.WORD CFA_RPUSH ; >R
.WORD CFA_STOD ; S>D
.WORD CFA_RPOP ; R>
.WORD CFA_DDOTR ; D.R
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> D. <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( D. [ d -> ] gibt die doppeltgenaue Zahl d auf die Standardausgabe aus. )
;( ========================================================================= )
; : D. 0 D.R SPACE ; ( Zahl in einem Feld der Breite 0 ausgeben )
NFA_DDOT .CBYTE $82,"D."
LFA_DDOT .WORD NFA_DOTR
CFA_DDOT .WORD DOCOL
PFA_DDOT
.WORD CFA_0 ; 0
.WORD CFA_DDOTR ; D.R
.WORD CFA_SPACE ; SPACE
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> . <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( . [ n -> ] gibt die Zahl n auf die Standardausgabe aus. )
;( ========================================================================= )
;
;: . S>D D. ; ( Zahl n doppeltgenau machen und mit D. ausgeben )
NFA_DOT .CBYTE $81,"."
LFA_DOT .WORD NFA_DDOT
CFA_DOT .WORD DOCOL
PFA_DOT
.WORD CFA_STOD ; S>D
.WORD CFA_DDOT ; D.
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> ? <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( ? [ addr -> ] gibt die Zahl, die an der Adresse addr gespeicher ist, aus. )
;( ========================================================================= )
;
;: ? @ . ;
NFA_QUEST .CBYTE $81, "?"
LFA_QUEST .WORD NFA_DOT
CFA_QUEST .WORD DOCOL
PFA_QUEST
.WORD CFA_FETCH ; @
.WORD CFA_DOT ; .
.WORD CFA_EXIT ; ;S
; >>>>>>>>>>>>>>>> U. <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( U. [ u -> ] gibt die vorzeichenlose Zahl u auf die Standardausgabe aus. )
;( ========================================================================= )
; : U. 0 D. ; ( Zahl vorzeichenlos doppeltgenau machen und mit D. ausgeben )
NFA_UDOT .CBYTE $82,"U."
LFA_UDOT .WORD NFA_QUEST
CFA_UDOT .WORD DOCOL
PFA_UDOT
.WORD CFA_0 ; 0
.WORD CFA_DDOT ; D.
.WORD CFA_EXIT ; ;S
PREVLINK .= NFA_UDOT
;( ========================================================================= )
;( Definition diverser Konstanten und Variablen, die zur Verwaltung des )
;( Disk-Systems benoetigt werden. )
;( ========================================================================= )
; >>>>>>>>>>>>>>>> C/L <<<<<<<<<<<<<<<<
; 64 CONSTANT C/L ( Zeichen pro Eingabezeile )
NFA_C_L .CBYTE $83, "C/L"
LFA_C_L .WORD PREVLINK
CFA_C_L .WORD DOCON
PFA_C_L .WORD 32
PREVLINK .= NFA_C_L
; >>>>>>>>>>>>>>>> CALL <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( CALL Sprung zur ASM Subroutine )
;( ========================================================================= )
NFA_CALL .CBYTE $84, "CALL"
LDA_CALL .WORD PREVLINK
CFA_CALL .WORD PFA_CALL
PFA_CALL
STX XSAVE
LDA 0,X
STA PFA_CALL1
LDA 1,X
STA PFA_CALL1+1
.BYTE $20 ; JSR
PFA_CALL1
.WORD 0
LDX XSAVE
STA 0,X
STY 1,X
JMP NEXT
PREVLINK .= NFA_CALL
; >>>>>>>>>>>>>>>> WORDS <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( WORDS [ ] gibt die Namen aller Worte, beginnend beim Context-Volabular, )
;( auf die Standardausgabe aus. Die Ausgabe kann mit einer beliebigen Taste )
;( abgebrochen werden. )
;( ========================================================================= )
;: WORDS
; 128 OUT ! ( Initialisierung, damit zu Anfang ein CR erfolgt )
; CONTEXT @ @ ( NFA des letzten Wortes im Context-Vokabular )
; BEGIN
; OUT @ C/L > IF ( falls Zeilenende ueberschritten wurde: )
; CR ( in neue Zeile gehen )
; 0 OUT ! ( Ausgabe in Spalte 0 der neuen Zeile beginnen )
; ENDIF
; DUP ID. SPACE SPACE ( Namen des aktuellen Wortes ausgeben )
; PFA LFA @ ( NFA des naechsten Wortes ermitteln )
; DUP 0= ?TERMINAL OR ( Ende der Linkerkette oder Taste gedrueckt? )
; UNTIL ( ja dann fertig, sonst weiter ausgeben )
; DROP ( letzte NFA vergessen )
;
NFA_WORDS .CBYTE $85, "WORDS"
LFA_WORDS .WORD PREVLINK
CFA_WORDS .WORD DOCOL
PFA_WORDS
.WORD CFA_CLIT ; CLIT
.BYTE 128
.WORD CFA_OUT ; OUT
.WORD CFA_STORE ; !
.WORD CFA_CONTEXT ; CONTEXT
.WORD CFA_FETCH ; @
.WORD CFA_FETCH ; @
LBL74
.WORD CFA_OUT ; OUT
.WORD CFA_FETCH ; @
.WORD CFA_C_L ; C/L
.WORD CFA_GT ; >
.WORD CFA_0BRANCH ; 0BRANCH
.WORD LBL75-*
.WORD CFA_CR ; CR
.WORD CFA_0 ; 0
.WORD CFA_OUT ; OUT
.WORD CFA_STORE ; !
LBL75
.WORD CFA_DUP ; DUP
.WORD CFA_IDDOT ; ID.
;.WORD CFA_SPACE ; SPACE
;.WORD CFA_SPACE ; SPACE
.WORD CFA_PFA ; PFA
.WORD CFA_LFA ; LFA
.WORD CFA_FETCH ; @
.WORD CFA_DUP ; DUP
.WORD CFA_NULLEQUAL ; 0=
.WORD CFA_QUERYTERMINAL ; ?TERMINAL
.WORD CFA_OR ; OR
.WORD CFA_0BRANCH ; 0BRANCH
.WORD LBL74-*
.WORD CFA_DROP ; DROP
.WORD CFA_EXIT ; ;S
PREVLINK .= NFA_WORDS
.IF FILE
;( ========================================================================= )
;( Definitionen fuer Dateibefehle )
;( ========================================================================= )
FAM_R = 4
FAM_W = 8
FAM_RW = FAM_R + FAM_W
IO_OPEN = $3
IO_GETREC = $5
IO_GETCHR = $7
IO_PUTREC = $9
IO_PUTCHR = $B
IO_CLOSE = $C
ICFLG = $340
ICCOM = $342
ICSTA = $343
ICBAL = $344
ICBAH = $345
ICBLL = $348
ICBLH = $349
ICAX1 = $34A
ICAX2 = $34B
CIOV = $E456
;( ========================================================================= )
;( Hilfsroutinen fuer die Dateibefehle )
;( ========================================================================= )
GETFILEID
LDA 0,X ; get fileid
GETFILEID0
ASL
ASL
ASL
ASL
TAY
RTS
JCIOV
STX XSAVE
TYA
TAX
JSR CIOV
TXA
TAY
LDX XSAVE
RTS
;( ========================================================================= )
;( Hilfswoerter fuer die Dateibefehle )
;( ========================================================================= )
; >>>>>>>>>>>>>>>> R/O <<<<<<<<<<<<<<<<
; CONSTANT R/O 4
NFA_RO .CBYTE $83, "R/O"
LFA_RO .WORD PREVLINK
CFA_RO .WORD DOCON
PFA_RO .WORD FAM_R
PREVLINK .= NFA_RO
; >>>>>>>>>>>>>>>> R/W <<<<<<<<<<<<<<<<
; CONSTANT R/O 12
NFA_RW .CBYTE $83, "R/W"
LFA_RW .WORD PREVLINK
CFA_RW .WORD DOCON
PFA_RW .WORD FAM_RW
PREVLINK .= NFA_RW
; >>>>>>>>>>>>>>>> W/O <<<<<<<<<<<<<<<<
; CONSTANT R/O 8
NFA_WO .CBYTE $83, "W/O"
LFA_WO .WORD PREVLINK
CFA_WO .WORD DOCON
PFA_WO .WORD FAM_W
PREVLINK .= NFA_WO
; >>>>>>>>>>>>>>>> CIO <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( CIO [ ] Schnittstelle zur ATARI CIO )
;( ========================================================================= )
NFA_CIO .CBYTE $83, "CIO"
LDA_CIO .WORD PREVLINK
CFA_CIO .WORD PFA_CIO
PFA_CIO
JMP NEXT
PREVLINK .= NFA_CIO
; >>>>>>>>>>>>>>>> FREEIOCB <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( FreeIOCB [ -- freeiocb ] ermittelt naechsten freien IOCB )
;( ========================================================================= )
NFA_FREEIOCB .CBYTE $88, "FREEIOCB"
LDA_FREEIOCB .WORD PREVLINK
CFA_FREEIOCB .WORD PFA_FREEIOCB
PFA_FREEIOCB
JSR FREEIOCB0
LSR A
LSR A
LSR A
LSR A ; div 16
PHA ; iocb und
LDA #0 ; highbyte
JMP PUSH ; auf den Datenstack legen
FREEIOCB0
LDA #$70 ; bei IOCB 7 anfangen
L_FREEIOCB2
TAY
LDA ICFLG,Y ; Flag holen und
CMP #$FF
BEQ L_FREEIOCB1 ; testen ob frei (ICFLG = $FF)
TYA ; nicht frei!
SEC
SBC #$10
BNE L_FREEIOCB2
L_FREEIOCB1
TYA
RTS
PREVLINK .= NFA_FREEIOCB
; >>>>>>>>>>>>>>>> CLOSE-FILE <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( CLOSE-FILE [fileid -- ior ] Datei schliessen )
;( ========================================================================= )
NFA_CLOSEFILE .CBYTE $8A, "CLOSE-FILE"
LDA_CLOSEFILE .WORD PREVLINK
CFA_CLOSEFILE .WORD PFA_CLOSEFILE
PFA_CLOSEFILE
JSR GETFILEID
LDA #IO_CLOSE
STA ICCOM,Y
JSR JCIOV
LDA ICSTA,Y
BMI CLOSEFILE1
LDA #0
CLOSEFILE1
PHA
LDA #0 ; Store ior highbyte
JMP PUT
PREVLINK .= NFA_CLOSEFILE
; >>>>>>>>>>>>>>>> CREATE-FILE <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( CREATE-FILE [caddr u fam -- ior ] Datei anlegen )
;( ========================================================================= )
NFA_CREATEFILE .CBYTE $8B, "CREATE-FILE"
LDA_CREATEFILE .WORD PREVLINK
CFA_CREATEFILE .WORD PFA_CREATEFILE
PFA_CREATEFILE
JMP NEXT
PREVLINK .= NFA_CREATEFILE
; >>>>>>>>>>>>>>>> DELETE-FILE <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( DELETE-FILE [caddr u -- ior ] Datei loeschen )
;( ========================================================================= )
NFA_DELETEFILE .CBYTE $8B, "DELETE-FILE"
LDA_DELETEFILE .WORD PREVLINK
CFA_DELETEFILE .WORD PFA_DELETEFILE
PFA_DELETEFILE
JMP NEXT
PREVLINK .= NFA_DELETEFILE
; >>>>>>>>>>>>>>>> FLUSH-FILE <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( FLUSH-FILE [fileid -- ior ] Dateibuffer schreiben )
;( ========================================================================= )
NFA_FLUSHFILE .CBYTE $8A, "FLUSH-FILE"
LDA_FLUSHFILE .WORD PREVLINK
CFA_FLUSHFILE .WORD PFA_FLUSHFILE
PFA_FLUSHFILE
JMP NEXT
PREVLINK .= NFA_FLUSHFILE
; >>>>>>>>>>>>>>>> OPEN-FILE <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( OPEN-FILE [caddr u fam -- fileid ior ] Datei oeffnen )
;( ========================================================================= )
NFA_OPENFILE .CBYTE $89, "OPEN-FILE"
LDA_OPENFILE .WORD PREVLINK
CFA_OPENFILE .WORD PFA_OPENFILE
PFA_OPENFILE
JSR FREEIOCB0 ; get free iocb
LDA #IO_OPEN
STA ICCOM,Y
LDA 4,X ; Lowbyte Filename
STA ICBAL,Y
LDA 5,X ; HighByte Filename
STA ICBAH,Y
LDA 0,X ; fam
STA ICAX1,Y
LDA #0
STA ICAX2,Y
JSR JCIOV
INX
INX
LDA ICSTA,Y
STA 0,X
BMI OPENFILE1
DEC 0,X ; ior = 0 = ok
OPENFILE1
LDA #0 ; Store ior
STA 1,X
STA 3,X
; DIV $10
TYA
CLC
LSR A
LSR A
LSR A
LSR A
STA 2,X ; Store fileid
JMP NEXT
PREVLINK .= NFA_OPENFILE
; >>>>>>>>>>>>>>>> RENAME-FILE <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( RENAME-FILE [caddr1 u1 caddr2 u2 -- ior ] Datei umbenennen )
;( ========================================================================= )
NFA_RENAMEFILE .CBYTE $8B, "RENAME-FILE"
LDA_RENAMEFILE .WORD PREVLINK
CFA_RENAMEFILE .WORD PFA_RENAMEFILE
PFA_RENAMEFILE
JMP NEXT
PREVLINK .= NFA_RENAMEFILE
; >>>>>>>>>>>>>>>> READ-FILE <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( READ-FILE [caddr u1 fileid -- u2 ior ] Datei an Adresse Lesen )
;( ========================================================================= )
NFA_READFILE .CBYTE $89, "READ-FILE"
LDA_READFILE .WORD PREVLINK
CFA_READFILE .WORD PFA_READFILE
PFA_READFILE
JSR GETFILEID
LDA 2,X ; get lowbyte length
STA ICBLL,Y
LDA 3,X ; get highbyte length
STA ICBLH,Y
LDA 4,X ; get lowbyte address
STA ICBAL,Y
LDA 5,X ; get highbyte address
STA ICBAH,Y
LDA #IO_GETCHR ; Get Characters CIO Command
STA ICCOM,Y
JSR JCIOV
INX
INX
LDA ICSTA,Y
STA 0,X
BMI READFILE1
DEC 0,X ; OK, ior = 0
READFILE1
CLC
LDA ICBLL,Y ; get real length
STA 2,X
LDA ICBLH,Y ; get real length
STA 3,X
LDA #0
STA 1,X
JMP NEXT
PREVLINK .= NFA_READFILE
; >>>>>>>>>>>>>>>> READ-LINE <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( READ-LINE [caddr u1 fileid -- u2 flag ior ] Datei zeilenweise lesen )
;( ========================================================================= )
NFA_READLINE .CBYTE $89, "READ-LINE"
LDA_READLINE .WORD PREVLINK
CFA_READLINE .WORD PFA_READLINE
PFA_READLINE
JSR GETFILEID
LDA 2,X ; get lowbyte length
STA ICBLL,Y
LDA 3,X ; get highbyte length
STA ICBLH,Y
LDA 4,X ; get lowbyte address
STA ICBAL,Y
LDA 5,X ; get highbyte address
STA ICBAH,Y
LDA #IO_GETREC ; Get Record CIO Command
STA ICCOM,Y
JSR JCIOV
LDA ICSTA,Y
STA 0,X
BMI READLINE1
DEC 0,X ; OK, ior = 0
READLINE1
CLC
LDA ICBLL,Y ; get real length
STA 4,X
ADC ICBAL,Y ; calculate end of string
STA 2,X
DEC 2,X
LDA ICBLH,Y
STA 5,X
ADC ICBAH,Y
STA 3,X
LDA #0
STA (2,X)
STA 1,X
STA 2,X ; store flag = true
STA 3,X
JMP NEXT
PREVLINK .= NFA_READLINE
; >>>>>>>>>>>>>>>> REFILL <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( REFILL [ fileid -- flag ] Eingabebuffer fuellen )
;( ========================================================================= )
; : REFILL
; TIB @ 128 SOURCE-ID @ READ-LINE SWAP IN ! SWAP DROP
; ;
NFA_REFILL .CBYTE $86, "REFILL"
LDA_REFILL .WORD PREVLINK
CFA_REFILL .WORD DOCOL
PFA_REFILL
.WORD CFA_TIB
.WORD CFA_FETCH ; get Terminal Input Buffer (TIB)
.WORD CFA_LIT
.WORD $80 ; 80 Char. max
.WORD CFA_SOURCEID
.WORD CFA_FETCH ; get Channel
.WORD CFA_READLINE
.WORD CFA_SWAP
.WORD CFA_IN
.WORD CFA_STORE
.WORD CFA_SWAP
.WORD CFA_DROP
.WORD CFA_EXIT
PREVLINK .= NFA_REFILL
; >>>>>>>>>>>>>>>> WRITE-FILE <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( WRITE-FILE [caddr u fileid -- ior ] Datei von Adresse schreiben )
;( ========================================================================= )
NFA_WRITEFILE .CBYTE $8A, "WRITE-FILE"
LDA_WRITEFILE .WORD PREVLINK
CFA_WRITEFILE .WORD PFA_WRITEFILE
PFA_WRITEFILE
JSR GETFILEID
LDA #IO_PUTCHR ; Put Characters CIO Command
STA ICCOM,Y
WRITE
LDA 2,X ; get lowbyte length
STA ICBLL,Y
LDA 3,X ; get highbyte length
STA ICBLH,Y
LDA 4,X ; get lowbyte address
STA ICBAL,Y
LDA 5,X ; get highbyte address
STA ICBAH,Y
JSR JCIOV
INX
INX
INX
INX
LDA ICSTA,Y
STA 0,X
BMI WRITEFILE1
DEC 0,X ; OK, ior = 0
WRITEFILE1
LDA #0
STA 1,X
JMP NEXT
PREVLINK .= NFA_WRITEFILE
; >>>>>>>>>>>>>>>> WRITE-LINE <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( WRITE-LINE [caddr u fileid -- ior ] Datei zeilenweise schreiben )
;( ========================================================================= )
NFA_WRITELINE .CBYTE $8A, "WRITE-LINE"
LDA_WRITELINE .WORD PREVLINK
CFA_WRITELINE .WORD PFA_WRITELINE
PFA_WRITELINE
JSR GETFILEID
LDA #IO_PUTREC ; Put Record CIO Command
STA ICCOM,Y
JMP WRITE
PREVLINK .= NFA_WRITELINE
; >>>>>>>>>>>>>>>> INCLUDE-FILE <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( INCLUDE-FILE [fileid -- ] Liest und interpretiert Datei aus fileid )
;( ========================================================================= )
; : INCLUDE-FILE
; SOURCE-ID !
; BEGIN
; REFILL
; 128 <
; WHILE
; INTERPRET
; REPEAT
; SOURCE-ID @ CLOSE-FILE
; QUIT ;
NFA_INCLUDEFILE .CBYTE $8C, "INCLUDE-FILE"
LDA_INCLUDEFILE .WORD PREVLINK
CFA_INCLUDEFILE .WORD DOCOL
PFA_INCLUDEFILE
.WORD CFA_SOURCEID ; SOURCE-ID
.WORD CFA_STORE ; !
INCLUDEFILE1 ; BEGIN
.WORD CFA_REFILL ; REFILL
.WORD CFA_LIT ; LITERAL
.WORD $80 ; 128
.WORD CFA_LT ; <
.WORD CFA_0BRANCH ; WHILE
.WORD INCLUDEFILE2-*
.WORD CFA_INTERPRET ; INTERPRET
.WORD CFA_BRANCH
.WORD INCLUDEFILE1-* ; REPEAT
INCLUDEFILE2 ;
.WORD CFA_SOURCEID ; SOURCE-ID
.WORD CFA_FETCH ; @
.WORD CFA_CLOSEFILE ; CLOSE-FILE
.WORD CFA_QUIT ; QUIT
.WORD CFA_EXIT ; S;
PREVLINK .= NFA_INCLUDEFILE
; >>>>>>>>>>>>>>>> INCLUDED <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( INCLUDED [caddr u -- ] Liest und interpretiert Datei - Name an caddr )
;( ========================================================================= )
; : INCLUDED
; R/O
; OPEN-FILE
; 128 < IF
; INCLUDE-FILE
; SOURCE-ID @ CLOSE-FILE
; 0 SOURCE-ID ! ( Input-Buffer SOURCE-ID zuruecksetzen )
; ENDIF
NFA_INCLUDED .CBYTE $88, "INCLUDED"
LDA_INCLUDED .WORD PREVLINK
CFA_INCLUDED .WORD DOCOL
PFA_INCLUDED
.WORD CFA_RO
.WORD CFA_OPENFILE
.WORD CFA_LIT
.WORD $80
.WORD CFA_LT
.WORD CFA_0BRANCH
.WORD INCLUDED1-*
.WORD CFA_INCLUDEFILE
.WORD CFA_SOURCEID
.WORD CFA_FETCH
.WORD CFA_CLOSEFILE
.WORD CFA_0
.WORD CFA_SOURCEID
.WORD CFA_STORE
INCLUDED1
.WORD CFA_EXIT ; S;
PREVLINK .= NFA_INCLUDED
; >>>>>>>>>>>>>>>> FILE" <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( FILE" [ -- u caddr ] Ermittelt Filename im Input Strom )
;( ========================================================================= )
; : FILE"
; 1536 BL BLANKS
; HERE BL BLANKS
; 34 WORD HERE COUNT 1536 SWAP CMOVE
; 1536 0 ;
NFA_FILE .BYTE $85,"FILE",$A2
LDA_FILE .WORD PREVLINK
CFA_FILE .WORD DOCOL
PFA_FILE
.WORD CFA_LIT ;
.WORD 1536 ; $600
.WORD CFA_BL ; BL (32)
.WORD CFA_BLANKS ; BLANKS
.WORD CFA_HERE ; HERE
.WORD CFA_BL ; BL (32)
.WORD CFA_BLANKS ; BLANKS
.WORD CFA_CLIT
.BYTE 34 ; 34 (")
.WORD CFA_WORD ; WORD
.WORD CFA_COUNT ; COUNT
.WORD CFA_LIT
.WORD 1536 ; $600
.WORD CFA_SWAP ; SWAP
.WORD CFA_CMOVE ; CMOVE
.WORD CFA_LIT
.WORD 1536 ; $600
.WORD CFA_0 ; 0
.WORD CFA_EXIT ; S;
PREVLINK .= NFA_FILE
; >>>>>>>>>>>>>>>> INCLUDE" <<<<<<<<<<<<<<<<
;( ========================================================================= )
;( INCLUDE" Liest und interpretiert Datei - Name folgt im Input Strom )
;( ========================================================================= )
; : INCLUDE"
; FILE" INCLUDED ;
; IMMEDIATE
NFA_INCLUDE .BYTE $C8,"INCLUDE",$A2
LDA_INCLUDE .WORD PREVLINK
CFA_INCLUDE .WORD DOCOL
PFA_INCLUDE
.WORD CFA_FILE ; FILE"
.WORD CFA_INCLUDED ; INCLUDED
.WORD CFA_EXIT ; ;S
PREVLINK .= NFA_INCLUDE
.ENDIF ; FILE COMMANDS
; >>>>>>>>>>>>>>>> MON <<<<<<<<<<<<<<<<
NFA_MON .CBYTE $83, "MON"
LFA_MON .WORD PREVLINK
CFA_MON .WORD PFA_MON
PFA_MON
; Im originalen FIG-Listing wird davon ausgegangen, dass das aufrufende
; Programm ein Monitor ist.
STX XSAVE ; Datenstackpointer retten
LDA DOSIN+1 ; Resetvector zurueck
STA DOSINI
LDA DOSIN+2
STA DOSINI+1
JMP (DOSVEC) ; zum DOS zurueckkehren
NOP ; nach BRK wird ein Byte uebersprungen
LDX XSAVE ; Datenstackpointer wiederherstellen
JMP NEXT ; und fertig
NFA_LASTWORD = NFA_MON
;------------------------------------------------------------------------------------------
; Hilfsroutinen
;------------------------------------------------------------------------------------------
GETCH
TYA ; Y Register retten
PHA
JSR GETCHK
TAX
PLA ; Y Register wiederherstellen
TAY
TXA
RTS
GETCHK
LDA $E425 ; PUSH address of GETKEY OS Routine
PHA ; to returnstack
LDA $E424
PHA
RTS
OUTCH
STX XSAVE
TAX
TYA ; Y Register retten
PHA
JSR OUTCHK
PLA ; Y Register wiederherstellen
TAY
LDX XSAVE
RTS
OUTCHK ; in das ATARI OS springen (CIO Routine)
LDA $E407
PHA
LDA $E406
PHA
TXA
RTS
.IF debug
;
; This is a temporary trace routine, to be used until FORTH
; is generally operating. Then NOP the terminal query
; "JSR ONEKEY". This will allow user input to the text
; interpreter. When crashes occur, the display shows IP, W,
; and the word locations of the offending code. When all is
; well, remove : TRACE, TCOLON, PRNAM, DECNP, and the
; following monitor/register equates.
;
;
;
; Monitor routines needed to trace.
;
;XBLANK EQU $D0AF ; print one blank
;CRLF EQU $D0D2 ; print a carriage return and line feed.
;HEX2 EQU $D2CE ; print accum as two hex numbers
;LETTER EQU $D2C1 ; print accum as one ASCII character
;ONEKEY EQU $D1DC ; wait for keystroke
XW = $43 ; scratch reg. to next code field add
NP = $45 ; scratch reg. pointing to name field
;
;
DEBUGFLG .BYTE 0 ; debugflg
DXSAVE .BYTE 0 ; X Register Sicherungsplatz
TRACE STX DXSAVE ; X Register Retten
PHA ; Accu retten
TYA
PHA ; Y Register retten
JSR CRLF
LDA IP+1
JSR HEX2
LDA IP
JSR HEX2 ; print IP, the interpreter pointer
JSR XBLANK
;
;
LDY #0
LDA (IP),Y
STA XW
STA NP ; fetch the next code field pointer
INY
LDA (IP),Y
STA XW+1
STA NP+1
JSR PRNAM ; print dictionary name
;
LDA XW+1
JSR HEX2 ; print code field address
LDA XW
JSR HEX2
JSR XBLANK
;
LDX DXSAVE ; print TOS Cell
LDA 1,X
JSR HEX2
LDX DXSAVE
LDA 0,X
JSR HEX2
JSR XBLANK
;
LDA DXSAVE ; print stack location in zero-page
JSR HEX2
JSR XBLANK
;
LDA #1 ; print return stack bottom in page 1
JSR HEX2
TSX
INX
TXA
JSR HEX2
JSR XBLANK
;
.IF keywait
JSR ONEKEY ; wait for operator keystroke
.ENDIF
LDX DXSAVE ; just to pinpoint early problems
PLA ; Y Register wiederherstellen
TAY
PLA ; Accu wiederherstellen
RTS
;
; TCOLON is called from DOCOLON to label each point
; where FORTH 'nests' one level.
;
TCOLON STX DXSAVE ; X Register retten
PHA ; Accu retten
TYA
PHA ; Y Register retten
LDA W
STA NP ; locate the name of the called word
LDA W+1
STA NP+1
JSR CRLF
LDA #$3A ; ':
JSR LETTER
JSR XBLANK
JSR PRNAM
;@ JSR ONEKEY ; wait for operator keystroke
LDX DXSAVE ; X Register weiderherstellen
PLA
TAY ; Y Register wiederherstellen
PLA ; Accu wiederherstellen
RTS
;
; Print name by it's code field address in NP
;
PRNAM
ysave = $3FF
JSR DECNP
JSR DECNP
JSR DECNP
LDY #0
PN1
JSR DECNP
LDA (NP),Y ; loop till D7 in name set
BPL PN1
PN2 INY
LDA (NP),Y
STY YSAVE
JSR LETTER ; print letters of name field
LDY YSAVE
LDA (NP),Y
BPL PN2
JSR XTAB
LDY #0
RTS
;
; Decrement name field pointer
;
DECNP LDA NP
BNE DECNP1
DEC NP+1
DECNP1 DEC NP
RTS
;
;**********************************************************
; Monitor routines needed to trace.
;
; print a carriage return and line feed.
;
CRLF
LDA #155
JMP OUTCH
; print one blank
;
XBLANK LDA #$20
JMP OUTCH
; print one TAB
;
XTAB LDA #127
JMP OUTCH
; print accum as two hex digits
HEX2 PHA
LSR A
LSR A
LSR A
LSR A
JSR HEX2A
PLA
HEX2A AND #$0F
JSR HXDGT
JMP OUTCH
;
;convert hex digit to ASCII
;
HXDGT CMP #$0A
BCC HXDGT1
CLC
ADC #7
HXDGT1 ADC #'0
RTS
;
; print accum as one ASCII character
;
LETTER
AND #$7F
CMP #$20 ;compare ASCII space
BCS LETTER1 ;good if >= ' '
LDA #'.
LETTER1 JMP OUTCH
;
; wait for keystroke
;
ONEKEY JMP GETCH
.ENDIF ; DEBUG
TOP .END ; Ende des Assemblerlistings
.BANK
* = $2E0
.WORD ORIG
}}}