Powrót do spisu treści |
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 LOOPPierwszym 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 RTSTeraz 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 RTSJeś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 RTSNastę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 STOVERPo 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 ;STRIGPo 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 RTSTakż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 |