Rozdział 4INSTRUKCJA PRZYPISANIAW każdym programie najczęściej wykonywana jest instrukcja przypisania (LET). Od niej zaczniemy więc opis działania poszczególnych procedur wykonawczych Atari Basic. Ponieważ jest ona często wykorzystywana przez procedury pozostałych instrukcji, a sama wykorzystuje procedury operatorów i funkcji, to jej opis został umieszczony w oddzielnym rozdziale.
0100 ;eXecute LET statement
0110 ;
0120 EXEOP = $AB18
0130 LOMEM = $80
0140 OPCT = $AC35
0150 PUTVAR = $ABB2
0160 RECVAL = $AB36
0170 RSTPTR = $AB26
0180 STIX = $A9
0190 TIX = $AC
0200 TOX = $AB
0210 ;
0220 *= $AADA
0230 ;
0240 XLET JSR RSTPTR
0250 LOOP JSR RECVAL
0260 BCS OPER
0270 JSR PUTVAR
0280 BMI LOOP
0290 OPER STA TOX
0300 TAX
0310 LDA OPCT-$10,X
0320 LSR A
0330 LSR A
0340 LSR A
0350 LSR A
0360 STA TIX
0370 GETT LDY STIX
0380 LDA (LOMEM),Y
0390 TAX
0400 LDA OPCT-$10,X
0410 AND #$0F
0420 CMP TIX
0430 BCC SAVT
0440 TAX
0450 BEQ $AB35 ;RTS
0460 ;
0470 ;PRoCeed OPerator
0480 ;
0490 PRCOP LDA (LOMEM),Y
0500 INC STIX
0510 JSR EXEOP
0520 JMP GETT
0530 SAVT LDA TOX
0540 DEY
0550 STA (LOMEM),Y
0560 STY STIX
0570 JMP LOOP
Pierwszym krokiem jest odpowiednie ustawienie liczników i
innych rejestrów. W tym celu wywoływana jest procedura RSTPTR.
Zeruje ona rejestry STPTR (STack PoinTeR), BHLD1 i BHLD2 (Basic
HoLD register) oraz wpisuje wartość $FF do licznika STIX (STack
IndeX). Ponadto na koniec bufora tokenizacji wpisywana jest
wartość $11.
0100 ;ReSeT PoinTeRs
0110 ;
0120 BHLD1 = $B0
0130 BHLD2 = $B1
0140 LOMEM = $80
0150 STIX = $A9
0160 STPTR = $AA
0170 ;
0180 *= $AB26
0190 ;
0200 LDY #$FF
0210 LDA #$11
0220 STA (LOMEM),Y
0230 STY STIX
0240 INY
0250 STY BHLD1
0260 STY STPTR
0270 STY BHLD2
0280 ;
0290 ;eXecute PLUS sign
0300 ;
0310 XPLS RTS
Teraz rozpoczyna się główna pętla procedury przypisania
XLET. Wywoływana jest tu procedura RECVAL, której zadaniem jest
rozpoznanie wartości do przypisania. Najpierw odczytywany jest
token do rozpoznania. Wartość tego tokena większa od $7F
oznacza zmienną i powoduje skok do etykiety VARBL umieszczonej
na końcu procedury. Wartość $0F oznacza stałą tekstową, a $0E -
stałą liczbową. W tych przypadkach wykonywane są odpowiednie
fragmenty procedury. Każdy inny token powoduje opuszczenie
RECVAL z ustawionym bitem Carry, co sygnalizuje, że badany
token nie oznacza wartości (stałej lub zmiennej).
0100 ;RECognize VALue
0110 ;
0120 CALPC = $AC1E
0130 FR0 = $D4
0140 INIX = $A8
0150 PCNTC = $9D
0160 STMCUR = $8A
0170 VARN = $D3
0180 VART = $D2
0190 ;
0200 *= $AB36
0210 ;
0220 RECVAL LDY INIX
0230 INC INIX
0240 LDA (STMCUR),Y
0250 BMI VARBL
0260 CMP #$0F
0270 BCC NUMBER
0280 BEQ TEXT
0290 RTS
0300 ;
0310 ;NUMBER
0320 ;
0330 NUMBER LDX #$00
0340 NXT1 INY
0350 LDA (STMCUR),Y
0360 STA FR0,X
0370 INX
0380 CPX #$06
0390 BCC NXT1
0400 INY
0410 LDA #$00
0420 TAX
0430 BEQ STORE
0440 TEXT INY
0450 LDA (STMCUR),Y
0460 LDX #STMCUR
0470 ;
0480 ;STore TeXT
0490 ;
0500 STTXT STA FR0+2
0510 STA FR0+4
0520 INY
0530 TYA
0540 CLC
0550 ADC $00,X
0560 STA FR0
0570 LDA #$00
0580 STA FR0+3
0590 STA FR0+5
0600 ADC $01,X
0610 STA FR0+1
0620 TYA
0630 ADC FR0+2
0640 TAY
0650 LDX #$00
0660 LDA #$83
0670 STORE STA VART
0680 STX VARN
0690 STY INIX
0700 CLC
0710 RTS
0720 ;
0730 ;VARiaBLe
0740 ;
0750 VARBL JSR CALPC
0760 NXT2 LDA (PCNTC),Y
0770 STA VART,Y
0780 INY
0790 CPY #$08
0800 BCC NXT2
0810 CLC
0820 RTS
Jeśli rozpoznana została stała liczbowa, to jej sześć
bajtów jest przepisywane z tablicy instrukcji do rejestru
operacji zmiennoprzecinkowych FR0. Po rozpoznaniu stałej
tekstowej jej długość jest zapisywana do trzeciego i piątego
bajtu rejestru FR0, a w dwóch pierwszych bajtach zapisywany
jest adres pierwszego znaku stałej. Taki format zapisu
odpowiada dokładnie zapisowi zmiennej tekstowej w tablicy
wartości zmiennych. Na zakończenie do rejestru VARN (VARiable
Number) wpisywane jest zero, co oznacza stałą, a do rejestru
VART (VARiable Type) - $00 dla stałej liczbowej lub $83 dla
stałej tekstowej.W przypadku zmiennej najpierw wywoływana jest procedura CALPC, która oblicza adres zmiennej w tablicy wartości. W tym celu numer zmiennej (bez najstarszego bitu) jest mnożony przez osiem (długość wpisu w tablicy wartości zmiennych) i dodawany do adresu tej tablicy. Uzyskany wynik umieszczany jest w liczniku PCNTC.
0100 ;CALculate Program Counter
0110 ;
0120 PCNTC = $9D
0130 VVTP = $86
0140 ;
0150 *= $AC1E
0160 ;
0170 LDY #$00
0180 STY PCNTC+1
0190 ASL A
0200 ASL A
0210 ROL PCNTC+1
0220 ASL A
0230 ROL PCNTC+1
0240 CLC
0250 ADC VVTP
0260 STA PCNTC
0270 LDA VVTP+1
0280 ADC PCNTC+1
0290 STA PCNTC+1
0300 RTS
Następnie według obliczonego adresu wartość zmiennej jest
odczytywana z tablicy i przepisywana do rejestru operacji
zmiennoprzecinkowych. Po wykonaniu tej czynności w rejestrze
VART znajduje się kod typu zmiennej, a w rejestrze VARN - jej
numer. Rejestr FR0 zawiera wartość zmiennej w przypadku prostej
zmiennej liczbowej lub parametry zmiennej w przypadku zmiennej
tablicowej.W przypadku napotkania wartości w instrukcji przypisania wywoływana jest procedura PUTVAR. Przepisuje ona znalezioną wartość z rejestrów VART, VARN i FR0 (razem osiem bajtów) do bufora tokenizacji. Odpowiednio zwiększany jest przy tym licznik STPTR. Jeśli nastąpi przepełnienie bufora, co jest sprawdzane na początku procedury, to następuje skok do STOVER i sygnalizowany jest błąd (STack OVerflow ERror). Wynika z tego, że jednocześnie można zapisać w buforze 256/8=32 wartości. Nie jest to jednak prawda, gdyż część bufora zajmują tokeny operatorów i funkcji, a ponadto podczas obliczania wyrażenia niektóre wartości i tokeny mogą być usuwane z bufora jeszcze przed zapisaniem następnych.
0100 ;PUT VARiable
0110 ;
0120 LOMEM = $80
0130 STIX = $A9
0140 STOVER = $B920
0150 STPTR = $AA
0160 VART = $D2
0170 ;
0180 *= $ABB2
0190 ;
0200 INC STPTR
0210 LDA STPTR
0220 ASL A
0230 ASL A
0240 ASL A
0250 CMP STIX
0260 BCS ERR
0270 TAY
0280 DEY
0290 LDX #$07
0300 LOOP LDA VART,X
0310 STA (LOMEM),Y
0320 DEY
0330 DEX
0340 BPL LOOP
0350 RTS
0360 ERR JMP STOVER
Po przepisaniu wartości przez procedurę PUTVAR pętla XLET
jest powtarzana od wywołania RECVAL. Ponieważ składnia
instrukcji jest sprawdzana podczas wprowadzania wiersza, to
niemożliwe jest rozpoznanie bezpośrednio po sobie dwóch
wartości.Gdy badany token nie oznacza wartości, to jest zapisywany do rejestru TOX (Temporary Output indeX). Według niego jest następnie odczytywany z tablicy OPCT kod, którego starsza połowa jest umieszczana w rejestrze TIX (Temporary Input indeX). Teraz według licznika STIX odczytywany jest token z bufora (w pierwszym przejściu jest to zawsze $11). Według tego tokena ponownie pobierany jest kod z OPCT, a jego młodsza połowa jest porównywana z zawartością rejestru TIX. Jeżeli zawartość TIX jest większa, to token operacji jest zapisywany na końcu bufora (licznik STIX jest przy tym zmniejszany). W przeciwnym przypadku procedura XLET kończy się, jeśli w akumulatorze jest wartość zero. Trzeba tu zwrócić uwagę na sposób wykorzystania bufora tokenizacji. Od jego początku kolejno są umieszczane wartości, a od końca tokeny operacji. Licznik STPTR wskazuje przy tym liczbę zapisanych wartości, a licznik STIX - token pierwszej operacji do wykonania. Tablica OPCT jest skonstruowana w taki sposób, że w odpowiednim momencie następuje przejście do części oznaczonej etykietą PRCOP. Wartości w tej tablicy wyznaczają jednocześnie priorytet operatorów i funkcji.
0100 ;OPerator's Coefficients Table
0110 ;
0120 *= $AC35
0130 ;
0140 .BYTE $00 ;niewykorzystany
0150 .BYTE $00 ;niewykorzystany
0160 .BYTE $00 ;,
0170 .BYTE $00 ;$
0180 .BYTE $00 ;: -koniec instrukcji
0190 .BYTE $00 ;;
0200 .BYTE $00 ;EOL -koniec wiersza
0210 .BYTE $00 ;GOTO
0220 .BYTE $00 ;GOSUB
0230 .BYTE $00 ;TO
0240 .BYTE $00 ;STEP
0250 .BYTE $00 ;THEN
0260 .BYTE $00 ;#
0270 .BYTE $88 ;<= |
0280 .BYTE $88 ;<> |
0290 .BYTE $88 ;>= |operatory
0300 .BYTE $88 ;< |liczbowe
0310 .BYTE $88 ;> |
0320 .BYTE $88 ;= |
0330 .BYTE $CC ;^
0340 .BYTE $AA ;*
0350 .BYTE $99 ;+
0360 .BYTE $99 ;-
0370 .BYTE $AA ;/
0380 .BYTE $DD ;NOT
0390 .BYTE $55 ;OR
0400 .BYTE $66 ;AND
0410 .BYTE $F2 ;(
0420 .BYTE $4E ;)
0430 .BYTE $F1 ;= -LET liczbowe
0440 .BYTE $F1 ;= -LET tekstowe
0450 .BYTE $EE ;<= |
0460 .BYTE $EE ;<> |
0470 .BYTE $EE ;>= |operatory
0480 .BYTE $EE ;< |tekstowe
0490 .BYTE $EE ;> |
0500 .BYTE $EE ;= |
0510 .BYTE $DD ;+ -znak
0520 .BYTE $DD ;- -znak
0530 .BYTE $F2 ;( -wyr. tekstowe
0540 .BYTE $F2 ;( -zm. indeksowana
0550 .BYTE $F2 ;( -wym. zm. ind.
0560 .BYTE $F2 ;( -wyr. funkcyjne
0570 .BYTE $F2 ;( -wym. zm. tekst.
0580 .BYTE $43 ;, -w indeksie
0590 .BYTE $F2 ;STR$
0600 .BYTE $F2 ;CHR$
0610 .BYTE $F2 ;USR
0620 .BYTE $F2 ;ASC
0630 .BYTE $F2 ;VAL
0640 .BYTE $F2 ;LEN
0650 .BYTE $F2 ;ADR
0660 .BYTE $F2 ;ATN
0670 .BYTE $F2 ;COS
0680 .BYTE $F2 ;PEEK
0690 .BYTE $F2 ;SIN
0700 .BYTE $F2 ;RND
0710 .BYTE $F2 ;FRE
0720 .BYTE $F2 ;EXP
0730 .BYTE $F2 ;LOG
0740 .BYTE $F2 ;CLOG
0750 .BYTE $F2 ;SQR
0760 .BYTE $F2 ;SGN
0770 .BYTE $F2 ;ABS
0780 .BYTE $F2 ;INT
0790 .BYTE $F2 ;PADDLE
0800 .BYTE $F2 ;STICK
0810 .BYTE $F2 ;PTRIG
0820 .BYTE $F2 ;STRIG
Po rozpoznaniu operatora o priorytecie wyższym niż
poprzednie, jego token jest odczytywany z bufora tokenizacji, a
licznik STIX jest zwiększany. Teraz w celu wykonania operacji
lub funkcji wywoływana jest procedura EXEOP. Działanie jej jest
identyczne, jak wcześniej opisanej procedury EXESTM. Adres
procedury wykonawczej jest jednak w tym przypadku pobierany z
tabeli wektorów OPVTAB. Zmniejszenie wartości tokena o $1D jest
konieczne dla pominięcia operatorów, które są integralnymi
częściami instrukcji.
0100 ;EXEcute OPerator
0110 ;
0120 OPVTAV = $AA6A
0130 ;
0140 *= $AB18
0150 ;
0160 SEC
0170 SBC #$1D
0180 ASL A
0190 TAX
0200 LDA OPVTAB,X
0210 PHA
0220 LDA OPVTAB+1,X
0230 PHA
0240 RTS
Także tablica OPVTAB jest zbudowana identycznie jak STVTAB.
Z podanego wyżej powodu zawiera ona jedynie wektory operacji i
funkcji, których tokeny mają wartości od $1D do $54.
0100 ;OPerator Vectors TABle
0110 ;
0120 XABS = $B099
0130 XADD = $BDFA
0140 XADR = $B007
0150 XAND = $ACCF
0160 XASC = $AFFD
0170 XATN = $B118
0180 XCHR = $B052
0190 XCLOG = $B13D
0200 XCOM = $AD64
0210 XCOS = $B10F
0220 XDIV = $AC8C
0230 XEPAR = $AD66
0240 XEQU = $ACC9
0250 XEXP = $B14A
0260 XFRE = $AFD6
0270 XGEQ = $ACC2
0280 XGRT = $ACB9
0290 XINT = $B0C8
0300 XLEN = $AFB5
0310 XLEQ = $ACA3
0320 XLES = $ACB2
0330 XLOG = $B121
0340 XMIN = $AC95
0350 XMUL = $AC83
0360 XNEQ = $ACAC
0370 XNLET = $AD4A
0380 XNOT = $ACE4
0390 XOR = $ACD9
0400 XPADDL = $B00D
0410 XPDIM = $AD6D
0420 XPEEK = $AFCC
0430 XPIXV = $AD71
0440 XPLS = $AB35
0450 XPSEX = $AE11
0460 XPTRIG = $B015
0470 XRND = $B076
0480 XRPW = $B15E
0490 XSGN = $AD04
0500 XSIN = $B106
0510 XSLET = $AE8E
0520 XSQR = $B153
0530 XSTICK = $B011
0540 XSTR = $B034
0550 XSTRIG = $B019
0560 XSUB = $AC7A
0570 XUSR = $B0A5
0580 XVAL = $AFEB
0590 ;
0600 *= $AA6A
0610 ;
0620 .DBYTE XLEQ-1 ;<= |
0630 .DBYTE XNEQ-1 ;<> |
0640 .DBYTE XGEQ-1 ;>= |operatory
0650 .DBYTE XLES-1 ;< |liczbowe
0660 .DBYTE XGRT-1 ;> |
0670 .DBYTE XEQU-1 ;= |
0680 .DBYTE XRPW-1 ;^
0690 .DBYTE XMUL-1 ;*
0700 .DBYTE XADD-1 ;+
0710 .DBYTE XSUB-1 ;-
0720 .DBYTE XDIV-1 ;/
0730 .DBYTE XNOT-1 ;NOT
0740 .DBYTE XOR-1 ;OR
0750 .DBYTE XAND-1 ;AND
0760 .DBYTE XPLS-1 ;(
0770 .DBYTE XEPAR-1 ;)
0780 .DBYTE XNLET-1 ;= -liczbowy
0790 .DBYTE XSLET-1 ;= -tekstowy
0800 .DBYTE XLEQ-1 ;<= |
0810 .DBYTE XNEQ-1 ;<> |
0820 .DBYTE XGEQ-1 ;>= |operatory
0830 .DBYTE XLES-1 ;< |tekstowe
0840 .DBYTE XGRT-1 ;> |
0850 .DBYTE XEQU-1 ;= |
0860 .DBYTE XPLS-1 ;+ znak
0870 .DBYTE XMIN-1 ;- znak
0880 .DBYTE XPSEX-1 ;( -wyr. tekst.
0890 .DBYTE XPIXV-1 ;( -zm. indeks.
0900 .DBYTE XPDIM-1 ;( -wym. zm. ind.
0910 .DBYTE XEPAR-1 ;( -wyr. funkc.
0920 .DBYTE XPDIM-1 ;( -wym. zm. tekst.
0930 .DBYTE XCOM-1 ;, -indeks
0940 .DBYTE XSTR-1 ;STR$
0950 .DBYTE XCHR-1 ;CHR$
0960 .DBYTE XUSR-1 ;USR
0970 .DBYTE XASC-1 ;ASC
0980 .DBYTE XVAL-1 ;VAL
0990 .DBYTE XLEN-1 ;LEN
1000 .DBYTE XADR-1 ;ADR
1010 .DBYTE XATN-1 ;ATN
1020 .DBYTE XCOS-1 ;COS
1030 .DBYTE XPEEK-1 ;PEEK
1040 .DBYTE XSIN-1 ;SIN
1050 .DBYTE XRND-1 ;RND
1060 .DBYTE XFRE-1 ;FRE
1070 .DBYTE XEXP-1 ;EXP
1080 .DBYTE XLOG-1 ;LOG
1090 .DBYTE XCLOG-1 ;CLOG
1100 .DBYTE XSQR-1 ;SQR
1110 .DBYTE XSGN-1 ;SGN
1120 .DBYTE XABS-1 ;ABS
1130 .DBYTE XINT-1 ;INT
1140 .DBYTE XPADDL-1 ;PADDLE
1150 .DBYTE XSTICK-1 ;STICK
1160 .DBYTE XPTRIG-1 ;PTRIG
1170 .DBYTE XSTRIG-1 ;STRIG
|