Serwis Edukacyjny w I-LO w Tarnowie Materiały dla uczniów liceum |
Wyjście Spis treści Wstecz Dalej Autorzy: dr Ian Logan i dr Frank O'Hara |
©2024 mgr Jerzy Wałaszek |
Procedura ta jest używana do obliczania wartości 'następnego wyrażenia'.
Wynik jest zwracany jako 'ostatnia wartość' na stosie kalkulatora. Dla wyniku liczbowego będzie to liczba zmiennoprzecinkowa. Jednakże przy wyniku łańcuchowym ostatnia wartość będzie złożona z zestawu parametrów. Pierwszy z pięciu bajtów jest nieokreślony, drugi i trzeci zawierają adres początku tego łańcucha, a czwarty i piąty jego długość.
Bit 6 zmiennej systemowej FLAGS jest ustawiony na 1 przy wyniku liczbowym, a wyzerowany przy wyniku łańcuchowym.
Gdy następne wyrażenie składa się tylko z pojedynczego argumentu, np. ... A ..., ... RND ..., ... A$ (4, 3 TO 7) ... , to ostatnią wartością jest po prostu wartość otrzymana z obliczenia tego argumentu.
Jednakże, gdy następne wyrażenie zawiera funkcję i jej argument, np. ... CHR$ A..., ... NOT A ... , SIN 1 ..., to kod operacyjny tej funkcji jest przechowywany na stosie maszynowym aż do obliczenia ostatniej wartości argumentu. Wtedy ta ostatnia wartość jest wykorzystywana do wykonania odpowiedniej operacji, aby otrzymać nową ostatnią wartość.
W przypadku wykonywania operacji arytmetycznej lub logicznej, np. ... A+B ... , A*B ..., ... A=B ... , zarówno ostatnia wartość pierwszego argumentu jak i kod operacji są pamiętane aż do momentu, gdy zostanie obliczony drugi argument. W rzeczywistości wyliczanie ostatniej wartości drugiego argumentu może również wymagać zapamiętania ostatnich wartości oraz kodów operacji na czas rachunków.
Można w ten sposób pokazać, że w trakcie wyliczania złożonego wyrażenia, np. ... CHR$ (T+A - 26*INT ((T+A)/26)+65)..., budowana jest hierarchia operacji, które należy jeszcze wykonać aż do momentu, gdy hierarchia ta zostanie rozłożona w celu otrzymania ostatecznej ostatniej wartości.
Każdy kod operacji posiada powiązany z sobą odpowiedni priorytet i operacje o wyższym priorytecie są zawsze wykonywane przed tymi, których priorytet jest niższy.
Procedura rozpoczyna się od pobrania do rejestru A pierwszego znaku wyrażenia i od umieszczenia na stosie maszynowym znacznika początkowego priorytetu – zero.
24FB SCANNING RST 0018,GET-CHAR Pierwszy znak zostaje pobrany. LD B,+00 Znacznik początkowego priorytetu. PUSH BC jest umieszczany na stosie. 24FF S-LOOP-1 LD C,A Główny punkt ponownego wejścia. LD HL,+2596 Indeks do tablicy funkcji skanowania CALL 16DC,INDEXER z kodem w C. LD A,C Odtwórz kod w A. JP NC,2684,S-ALPHNUM Skocz, jeśli kodu nie ma w tablicy. LD B,+00 Użyj pozycji znalezionej w tablicy LD C,(HL) do utworzenia wymaganego adresu ADD HL,BC w parze rejestrów HL. JP (HL) i skocz pod ten adres |
Następnie pojawiają się cztery procedury; są one wywoływane przez procedury umieszczone w tablicy skanowania funkcji. Pierwsza z nich, 'procedura skanowania cudzysłowów', jest wykorzystywana przez S-QUOTE do sprawdzenia, czy każdy cudzysłów łańcucha posiada swój odpowiednik.
250F S-QUOTE-S CALL 0074,CH-ADD+1 Wskaż na następny znak. INC BC Zwiększ licznik długości o jeden. CP +0D Czy to powrót karetki? JP Z,1C8A,REPORT-C Jeśli tak, zgłoś błąd. CP +22 Czy to kolejny '"'? JR NZ,250F,S-QUOTE-S Jeśli nie, wróć na początek pętli. CALL 0074,CH-ADD+1 Wskaż następny znak; ustaw CP +22 znacznik zera, jeśli jest to kolejny '"'. RET Skończone. |
Następna procedura, 'przeglądanie dwóch współrzędnych', wywoływana jest przez S-SCREEN$, S-ATTR i S-POINT w celu upewnienia się, że wymagane dwie współrzędne są podane we właściwej postaci.
2522 S-2-COORD RST 0020, NEXT-CHAR Pobierz następny znak.. CP +28 Czy jest to '('? JR NZ,252D,S-RPORT-C Jeśli nie, zgłoś błąd. CALL 1C79,NEXT-2NUM Współrzędne na stos kalkulatora. RST 0018,GET-CHAR Pobierz bieżący znak. CP +29 Czy jest to ')'? 252D S-RPORT-C JP NZ,1C8A,REPORT-C Jeśli nie, zgłoś błąd. |
Procedura ta jest wywoływana 32 razy, dając oszczędność 1 bajtu na każde z wywołań. Wykonywany jest prosty test bitu 7 zmiennej FLAGS, który zeruje znacznik zera w trakcie wykonywania programu, a ustawia go w czasie sprawdzania składni.
2530 SYNTAX-Z BIT 7,(FLAGS) Test bitu 7 zmiennej FLAGS. RET Skończone. |
Następna procedura rozpoznaje znaki na ekranie i jest używany przez S-SCREENS$ do identyfikacji znaku, który pojawia się w wierszu x i kolumnie y ekranu. Przeszukiwany jest tylko zestaw znaków 'wskazywanych przez' zmienną CHARS.
Uwaga: Są to normalnie znaki od +20 (spacja) do +7F (©), chociaż użytkownik może zmienić zawartość CHARS, aby przeszukiwać również inne zestawy znaków, łącznie z grafiką definiowaną przez użytkownika.
2535 S-SCRN$-S CALL 2307,STK-TO-BC x do C, y do B; 0<=x<=23 dziesiętnie; LD HL,(CHARS) O<=y<=31 dziesiętnie. LD DE,+0100 CHARS plus 256 dziesiętnie daje ADD HL,DE HL wskazujące na zestaw znaków. LD A,C x jest zapisywane w A. RRCA Liczba 32 (dziesietnie) * (x mod 8) + y RRCA jest tworzona w A i zapisywana w E. RRCA Jest to młodszy bajt pożądanego AND +E0 adresu na ekranie. XOR B LD E,A LD A,C x jest ponownie zapisywane w A. AND +18 Teraz liczba 64 (dziesiętnie) + 8*INT (x/8) XOR +40 jest wstawiana do D. LD D,A DE teraz zawiera adres ekranu. LD B,+60 B zlicza 96 znaków. 254F S-SCRN-LP PUSH BC Zapamiętaj licznik. PUSH DE Oraz wskaźnik ekranu. PUSH HL I wskaźnik zestawu znaków. LD A,(DE) Pobierz pierwszy wiersz znaku ekranowego. XOR (HL) Porównaj go z wierszem z zestawu znaków. JR Z,255A,S-SC-MTCH Skocz, jeśli znaleziono bezpośrednią zgodność. INC A Teraz testuj zgodność z negatywem znaku (ustaw +00 w A z +FF). JR NZ,2573,S-SCR-NXT Skocz, jeśli nie było żadnej z tych dwóch zgodności. DEC A Przywróć +FF w A. 255A S-SC-MTCH LD C,A Stan negatywowy (+00 lub +FF) do C. LD B,+07 B zlicza przez kolejne 7 wierszy. 255D S-SC-ROWS INC D Przesuń DE na następny wiersz (dodaj 256 dziesiętnie). INC HL Przesuń HL na następny wiersz (tj. na następny bajt). LD A,(DE) Pobierz wiersz ekranowy. XOR (HL) Porównaj go z wierszem z ROM. XOR C Uwzględniaj stan negatywowy. JR NZ,2573,S-SCR-NXT Skocz, jeśli nie ma zgodności. DJNZ 255D,S-SC-ROWS Skocz wstecz, aż wszystkie wiersze będą porównane. POP BC Usuń ze stosu wskaźnik zestawu znaków. POP BC Oraz wskaźnik ekranu. POP BC Na koniec licznik do BC. LD A,+80 Kod ostatniego znaku w zestawie plus jeden. SUB B A zawiera teraz pożądany kod. LD BC,+0001 Jedno miejsce jest teraz potrzebne w obszarze roboczym. RST 0030,BC-SPACES Zrób to miejsce. LD (DE),A Wstaw w nie ten znak. JR 257D,S-SCR-STO Skocz, aby umieścić znak na stosie. 2573 S-SCR-NXT POP HL Odtwórz wskaźnik zestawu znaków. LD DE,+0008 Przesuń go o 8 bajtów na następny znak w zestawie. ADD HL,DE POP DE Odtwórz wskaźnik ekranu. POP BC Oraz licznik. DJNZ 254F,S-SCRN-LP Skocz na początek pętli dla 96 znaków. LD C,B Umieść na stosie pusty łańcuch (długość zero). 257D S-SCR-STO JP 2AB2,STK-STO-$ Skocz, aby umieścić na stosie znaleziony znak lub pusty łańcuch, jeśli znak nie został rozpoznany. |
Uwaga: To wyjście poprzez STK-STO-$ jest pomyłką, ponieważ prowadzi ono do podwojonego zapisywania wyniku łańcuchowego (zobacz na S-STRING, 25DB). Powinien tutaj znaleźć się rozkaz RET.
Ostatnim z tych czterech procedur jest skanowanie atrybutów. Zostaje ono wywoływane przez S-ATTR, aby zwrócić wartość ATTR (x,y), co koduje atrybuty wiersza x i kolumny y na ekranie telewizyjnym.
2580 S-ATTR-S CALL 2307,STK-TO-BC x do C, y do B. znów, 0<=x<=23 dziesiętnie; LD A,C 0<=y<=31 dziesiętnie. RRCA x jest zapisywane do A, a liczba RRCA 32 (dziesiętnie)*x (mod 8)+y jest RRCA tworzona w A i zapisywana do L. LD C,A 32*x(mod 8)+INT (x/8) zostaje również AND +E0 zapisane do C. XOR B LD L,A L zawiera młodszy bajt adresu atrybutu. LD A,C 32*x(mod 8)+INT (x/8) jest zapisywane w A. AND +03 88 (dziesiętnie)+INT (x/8) jest XOR +58 tworzone w A i zapisywane do H. LD H,A H zawiera starszy bajt adresu atrybutu. LD A,(HL) Bajt atrybutu zostaje pobrany do A. JP 2D28,STACK-A Wyjście z umieszczeniem wyniku na stosie. |
Tablica ta zawiera 8 funkcji i 4 operatory. Wprowadza ona zatem 5 nowych funkcji Spectrum i udostępnia zgrabną metodę dostępu do niektórych funkcji i operatorów, które już istniały na komputerze ZX81.
położenie kod odstęp nazwa adres procedury obsługującej 2596 22 1C S-QUOTE 25B3 2598 28 4F S-BRACKET 25E8 259A 2E F2 S-DECIMAL 268D 259C 2B 12 S-U-PLUS 25AF 259E A8 56 S-FN 25F5 25A0 A5 57 S-AND 25F8 25A2 A7 84 S-PI 2627 25A4 A6 8F S-INKEY$ 2634 25A6 C4 E6 S-BIN (EQU. S-DECIMAL) 268D 25A8 AA BF S-SCREEN$ 2668 25AA AB C7 S-ATTR 2672 25AC A9 CE S-POINT 267B 25AE 00 znacznik końca |
25AF S-U-PLUS RST 0020,NEXTCHAR Przy plusie po prostu przejdź JP 24FF,S-LOOP-1 do następnego znaku i skocz wstecz do głównego wejścia do SCANNING. |
Procedura 'szukania CUDZYSŁOWU' zajmuje się cudzysłowami łańcuchów tekstowych, czy to prostymi w stylu "nazwa", czy bardziej złożonymi jak "taki ""zielony"" domek", czy też na pozur nadmiarowymi VAL$ """a""".
25B3 S-QUOTE RST 0018,GET-CHAR Pobierz bieżący znak. INC HL Wskaż na początek łańcucha. PUSH HL Zapamiętaj adres początku. LD BC,+0000 Ustaw długość na zero. CALL 250F,S-QUOTE-S Wywołaj procedurę "porównania". JR NZ,25D9,S-Q-PRMS Skocz przy skasowanym znaczniku zera - brak dalszych cudzysłowów. 25BE S-Q-AGAIN CALL 250F,S-QUOTE-S Wywołaj go ponownie dla trzeciego cudzysłowu. JR Z,25BE,S-Q-AGAIN I ponownie dla piątego, siódmego, itd. CALL 2530,SYNTAX-Z Przy sprawdzaniu składni skocz, aby wyzerować JR Z,25D9,S-Q-PRMS bit 6 zmiennej FLAGS i aby kontynuować skanowanie. RST 0030,BC-SPACES Zrób miejsce w obszarze roboczym na łańcuch oraz zamykający cudzysłów. POP HL Pobierz wskaźnik początku. PUSH DE Zapamiętaj wskaźnik pierwszego miejsca. 25CB S-Q-COPY LD A,(HL) Pobierz znak z łańcucha. INC HL Wskaż na następny. LD (DE),A Skopiuj ostatni do obszaru roboczego. INC DE Wskaż na następne miejsce. CP +22 Czy ostatnim znakiem jest '"'? JR NZ,25CB,S-Q-COPY Jeśli nie, skocz, aby skopiować następny. LD A,(HL) Lecz jeśli tak, nie kopiuj następnego; INC HL jeśli następnym jest '"', skocz, CP +22 aby skopiować znak umieszczony za nim; JR Z,25CB,S-Q-COPY inaczej zakończ kopiowanie. 25D9 S-Q-PRMS DEC BC Wstaw prawdziwą długość do BC. |
Zwróć uwagę, że pierwszy cudzysłów nie został wliczony w długość; ostatni został i jest teraz pomijany. Wewnątrz łańcucha pierwszy, trzeci, piaty, itd. cudzysłów został wliczony, lecz drugi, czwarty, itd. nie został.
POP DE Odtwórz początek kopiowanego łańcucha. 25DB S-STRING LD HL,+5C3B To jest FLAGS; ten punkt wejścia RES 6,(HL) jest używany, gdy ma zostać skasowany bit 6 BIT 7,(HL) a łańcuch zapisany w pamięci, jeśli CALL NZ,2AB2,STK-STO-S przetwarza się wiersz. Teraz jest to wykonywane. JP 2712,S-CONT-2 Skocz, aby kontynuować skanowanie wiersza. |
Zwróć uwagę, że przy kopiowaniu łańcucha do obszaru roboczego każde dwa cudzysłowy wewnątrz tego łańcucha ("") zostały zredukowane do jednego cudzysłowu (").
25E8 S-BRACKET RST 0020,NEXT-CHAR Procedura 'szukania NAWIASU' CALL 24FB,SCANNING po prostu pobiera znak CP +29 i wywołuje rekurencyjnie SCANNING. JP NZ,1C8A,REPORT-C Zgłoś błąd, jeśli nie ma pasującego nawiasu; RST 0020,NEXT-CHAR Kontynuuj skanowanie. JP 2712,S-CONT-2 |
25F5 S-FN JP 27BD,S-FN-SBRN 'Procedura skanowania FN'. |
25F8 S-RND CALL 2530,SYNTAX-Z Jeśli nie sprawdzana jest składnia, JR Z,2626,S-RND-END skocz, aby obliczyć liczbę pseudolosową. LD BC,(SEED) Pobierz bieżącą wartość zmiennej SEED. CALL 2D2B,STACK-BC Umieść ją na stosie kalkulatora. RST 0028,FP-CALC Teraz użyj kalkulatora. DEFB +A1,stk-one Ostatnią wartością jest teraz DEFB +0F,addition SEED+1. DEFB +34,stk-data Umieść na stosie liczbę dziesiętną 75. DEFB +37,exponent+87 DEFB +16,(+00,+00,+00) DEFB +04,multiply (SEED+1)*75. DEFB +34,stk-data Zobacz na UMIESZCZANIE LITERAŁÓW, aby zobaczyć, DEFB +80,(four bytes) jak bajty są rozwijane w celu umieszczenia DEFB +41,exponent +91 liczby dziesiętnej 65537 DEFB +00,+00,+80,(+00) na stosie kalkulatora. DEFB +32,n-mod-m Podziel (SEED+1)*75 przez 65537, aby dostać 'resztę' i 'odpowiedź'. DEFB +02,delete Usuń 'odpowiedź'. DEFB +A1,stk-one Teraz ostatnią wartością jest DEFB +03,subtract 'reszta' - 1. DEFB +31,duplicate Zrób kopię z 'ostatniej wartości'. DEFB +38,end-calc Rachunki zakończone. CALL 2DA2,FP-TO-BC Użyj 'ostatniej wartości', aby nadać LD (SEED),BC nową wartość zmiennej SEED. LD A,(HL) Pobierz wykładnik 'ostatniej wartości'. AND A Skocz naprzód, jeśli wykładnik jest JR Z,2625,S-RND-END równy zero. SUB +10 Zmniejsz wykładni, tj. podziel LD (HL),A 'ostatnią wartość' przez 65536, aby dostać wymaganą 'ostatnią wartość'. 2625 S-RND-END JR 2630,S-PI-END Przeskocz przez procedurę 'PI'. |
'Procedura skanowania-PI': jeśli nie jest sprawdzana składnia, to wartość 'PI' zostaje obliczona i tworzy 'ostatnią wartość' na stosie kalkulatora.
2627 S-PI CALL 2530,SYNTAX-Z Testuj sprawdzanie składni. JR Z,2630,S-PI-END Skocz, jeśli trzeba. RST 0028,FP-CALC Teraz użyj kalkulatora. DEFB +A3,stk-pi/2 Na stos kalkulatora trafia PI/2 jako DEFB +3B,end-calc 'ostatnia wartość'. INC (HL) Wykładnik jest zwiększany, co odpowiada podwojeniu 'ostatniej wartości', dając PI. 2630 S-PI-END RST 0020,NEXT-CHAR Przesuń się na następny znak. JP 26C3,S-NUMERIC Skocz naprzód. 2634 S-INKEY$ LD BC,+105A Priorytet +10 szesnastkowo, kod operacji RST 0020,NEXT-CHAR +5A dla procedury 'wczytania'. CP +23 Jeśli następnym znakiem jest '#', skocz. JP Z,270D,S-PUSH-PO Będzie argument liczbowy. LD HL,+5C3B To jest zmienna FLAGS. RES 6,(HL) Resetuj bit 6 dla wyniku łańcuchowego. BIT 7,(HL) Testuj sprawdzanie składni. JR Z,2665,S-INK$-EN Skocz, jeśli trzeba. CALL 028E,KEY-SCAN Pobierz wartość klawisza do DE. LD C,+00 Przygotuj pusty łańcuch; umieść go na stosie, JR NZ,2660,S-IK$-STK jeśli naciśnięto zbyt wiele klawiszy. CALL 031E,K-TEST Testuj wartość klawisza; jeśli jest zła, JR NC,2660,S-IK$-STK umieść na stosie pusty łańcuch. DEC D +FF do D dla przygotowanego L (bit 3 ustawiony). LD E,A Wartość klawisza do E w celu dekodowania. CALL 0333,K-DECODE Dekoduj wartość klawisza. PUSH AF Zachowaj krótko wartość ASCII. LD BC,+0001 W obszarze roboczym potrzeba jednego miejsca. RST 0030,BC-SPACES Zrób je teraz. POP AF Odtwórz wartość ASCII. LD (DE),A Przygotuj się do zapisania go na stosie jako łańcucha. LD C,+01 Jego długość wynosi jeden. 2660 S-IK$-STK LD B,+00 Skompletuj parametr długości. CALL 2AB2,STK-STO-$ Umieść na stosie pożądany łańcuch. 2665 S-INK$-EN JP 2712,S-CONT-2 Skocz naprzód. 2668 S-SCREEN$ CALL 2522,S-2-COORD Sprawdź, czy są podane dwie współrzędne. CALL NZ,2535,S-SCRN$-S Wywołaj tą procedurę, o ile nie jest RST 0020,NEXT-CHAR sprawdzana składnia; następnie pobierz JP 25DB,S-STRING kolejny znak i skocz wstecz. 2672 S-ATTR CALL 2522,5-2-COORD Sprawdź, czy są podane dwie współrzędne. CALL NZ,2580,S-ATTR-S Wywołaj tą procedurę, o ile nie jest RST 0020,NEXT-CHAR sprawdzana składnia; następnie pobierz JR 26C3,S-NUMERIC kolejny znak i skocz naprzód. 267B S-POINT CALL 2522,S-2-COORD Sprawdź, czy są podane dwie współrzędne. CALL NZ,22CB,POINT-SUB Wywołaj tą procedurę, o ile nie jest RST 0020,NEXT-CHAR sprawdzana składnia; następnie pobierz JR 26C3,S-NUMERIC kolejny znak i skocz naprzód. 2684 S-ALPHNUM CALL 2C88,ALPHANUM Czy znak jest alfanumeryczny? JR NC,26DF,S-NEGATE Skocz, jeśli nie jest to litera lub cyfra. CP +41 Teraz skocz, jeśli jest to litera; JR NC,26C9,S-LETTER inaczej kontynuuj w S-DECIMAL. |
Procedura 'skanowania liczby dziesiętnej', która znajduje się tutaj, zajmuje się kropką dziesiętną lub liczbą rozpoczynającą się od cyfry. Troszczy się ona również o wyrażenie 'BIN', które jest obsługiwane w procedurze zamiany 'liczby dziesiętnej na zmiennoprzecinkową'.
268D S-DECIMAL CALL 2530,SYNTAX-Z Skocz naprzód, jeśli wiersz (EQU. S-BIN) JR NZ,2685,S-STK-DEC jest wykonywany. |
Podejmowane działanie różni się teraz istotnie przy sprawdzaniu składni i przy wykonywaniu wiersza. Jeśli jest sprawdzana składnia, to postać zmiennoprzecinkowa musi być obliczona i wstawiona do bieżącego wiersza języka BASIC. Jednakże przy wykonywaniu wiersza postać zmiennoprzecinkowa zawsze będzie dostępna, zatem jest kopiowana na stos kalkulatora, aby utworzyć 'ostatnią wartość'.
Podczas sprawdzania składni:
CALL 2C9B,DEC-TO-FP Zostaje znaleziona postać zmiennoprzecinkowa. RST 0018,GET-CHAR Ustaw HL na adres o jeden większy od adresu ostatniej cyfry. LD BC,+0006 Potrzebne jest sześć miejsc. CALL 1655,MAKE-ROOM Zrób miejsce w wierszu języka BASIC. INC HL Wskaż pierwsze wolne miejsce. LD (HL),+0E Wprowadź kod znacznika liczby. INC HL Wskaż na drugie miejsce. EX DE,HL Ten wskaźnik jest potrzebny w DE. LD HL,(STKEND) Pobierz 'stare' STKEND. LD C,+05 Pięć bajtów do przesłania. AND A Wyczyść znacznik przeniesienia. SBC HL,BC 'nowe' STKEND='stare' STKEND-5. LD (STKEND),HL Przenieś liczbę zmiennoprzecinkową LDIR ze stosu kalkulatora do wiersza. EX DE,HL Wstaw wskaźnik wiersza do HL. DEC HL Wskaż ostatni dodany bajt. CALL 0077,TEMP-PTR1 To ustawia CH-ADD. JR 26C3,S-NUMERIC Skocz naprzód. |
Podczas wykonania:
26B5 S-STK-DEC RST 0018,GET-CHAR Pobierz bieżący znak. 26B6 S-SD-SKIP INC HL Teraz przesuwaj się po znakach, aż LD A,(HL) do znalezienia kodu znacznika liczby. CP +0E JR NZ,26B6,S-SD-SKIP INC HL Wskaż pierwszy bajt tej liczby. CALL 33B4,STACK-NUM Przenieś liczbę zmiennoprzecinkową. LD (CH-ADD),HL Ustaw CH-ADD. |
Wynik liczbowy został właśnie zidentyfikowany, pochodzący z RND, PI, ATTR, POINT lub z liczby dziesiętnej, dlatego należy ustawić bit 6 zmiennej FLAGS.
26C3 S-NUMERIC SET 6,(FLAGS) Ustaw znacznik wyniku liczbowego. JR 26DD,S-CONT-1 Skocz naprzód. |
Gdy zostaje rozpoznana nazwa zmiennej jest wykonywane wywołanie procedury LOOK-VARS, która przeszukuje zmienne już istniejące w obszarze zmiennych (lub w obszarze programu przy poleceniach DEF FN dla funkcji FN definiowanej przez użytkownika). Jeśli zostanie znaleziona odpowiednia wartość liczbowa, to jest ona umieszczana na stosie kalkulatora za pomocą STACK-NUM. Jednakże łańcuch lub tablica łańcuchów wymaga przekazania odpowiednich parametrów na stos kalkulatora przez procedurę STK-VAR (lub w przypadku funkcji definiowanej przez użytkownika przez procedurę STK-F-ARG wywoływaną z LOOK-VARS).
26C9 S-LETTER CALL 28B2,LOOK-VARS Szukaj wśród istniejących zmiennych pasującego elementu. JP C,1C2E,REPORT-2 Zgłaszany jest błąd, jeśli taki element nie istnieje. CALL Z,2996,STK-VARS Umieść na stosie parametry łańcucha/zwróć adres bazowy elementu liczbowego. LD A,(FLAGS) Pobierz FLAGS. CP +C0 Testuj razem bity 6 i 7. JR C,26DD,S-CONT-1 jeden lub oba bity są zerowe. INC HL Należy pobrać wartość liczbową. CALL 33B4,STACK-NUM Przenieś tę liczbę. 26DD S-CONT-1 JR 2712,S-CONT-2 Skocz naprzód. |
Znak sprawdza się z '-', aby w ten sposób zidentyfikować operację 'pojedynczego minusa'.
Przed wykonaniem testu rejestr B jest ustawiany na priorytet +09 a rejestr C na kod operacji +D8, co jest wymagane przez procedurę.
26DF S-NEGATE LD BC,+09DB Priorytet +09, kod operacji +D8. CP +2D Czy jest to '-'? JR Z,270D,S-PUSH-PO Skocz naprzód przy 'pojedynczym minusie'. |
Następnie znak sprawdza się na zgodność z kodem 'VAL$', z priorytetem 16 i kodem operacji 18 szesnastkowo.
LD BC,+1018 Priorytet 16 dziesiętnie, kod operacji +18 szesnastkowo. CP +AE Czy to jest 'VAL$'? JR Z,270D,S-PUSH-PO Skocz naprzód, jeśli to 'VAL$'. |
Bieżący znak musi teraz reprezentować jedną z funkcji od CODE do NOT o kodach od +AF do +C3.
SUB +AF Zakres funkcji jest zmieniany z +AF do +C3 na zakres od +00 do +14 szesnastkowo. JP C,1C8A,REPORT-C Zgłoś błąd, jeśli poza zakresem. |
Funkcja 'NOT' jest identyfikowana i obsługiwana osobno od pozostałych.
LD BC,+04F0 Priorytet +04, kod operacji +F0. CP +14 Czy to funkcja 'NOT'? JR Z,270D,S-PUSH-PO Skocz, jeśli tak. JP NC,1C8A,REPORT-C Sprawdź ponownie zakres. |
Pozostałe funkcje posiadają priorytet 16 dziesiętnie. teraz zostają obliczone kody operacyjne dla tych funkcji. Funkcje operujące na łańcuchach muszą w swoim kodzie operacyjnym posiadać ustawiony na zero bit 6, funkcje dające wynik w postaci łańcucha muszą w kodzie operacyjnym posiadać bit 7 ustawiony na 0.
LD B,+10 Priorytet 16 dziesiętnie. ADD A,+DC teraz zakres funkcji wynosi od +DC do +EF. LD C,A Przenieś kod operacyjny. CP +DF Oddziel CODE, VAL i LEN, które JR NC,2707,S-NO-TO-$ operują na łańcuchach i dają RES 6,C wyniki liczbowe. 2707 S-NO-TO-$ CP +EE Oddziel STR$ i CHR$, JR C,2700,S-PUSH-PO które operują na liczbach i dają wyniki łańcuchowe. RES 7,C Zaznacz kody operacyjne. Pozostałe kody operacyjne mają oba bity 6 i 7 ustawione na 1. |
Kody priorytetu i operacyjny dla przetwarzanej funkcji są teraz umieszczane na stosie maszynowym. W ten sposób jest budowana hierarchia operacji.
270D S-PUSH-PO PUSH BC Umieść na stosie kody priorytetu oraz RST 0020,NEXT-CHAR operacyjny przed przejściem do przetwarzania JP 24FF,S-LOOP-1 następnej części wyrażenia. |
Kontynuowane jest przeglądanie wiersza. Za obecnym argumentem mogą wystąpić '(', operator podwójny lub po osiągnięciu końca wyrażenia znak powrotu karetki, przecinek, separator lub 'THEN'.
2712 S-CONT-2 RST 0018,GET-CHAR Pobierz bieżący znak. 2713 S-CONT-3 CP +28 Skocz naprzód, jeśli nie jest to '(', JR NZ,2723,S-OPERTR co oznacza wyrażenie w nawiasach. |
Jeśli 'ostatnia wartość' jest liczbą, to wyrażenie w nawiasach jest prawdziwym podwyrażeniem i samo musi zostać obliczone. Jednakże, jeśli 'ostatnia wartość' jest łańcuchem, to wyrażenie w nawiasach oznacza element tablicy lub podłańcuch. Wymagane jest wywołanie procedury SLICING modyfikującej wg potrzeb parametry łańcucha.
BIT 6,(FLAGS) Skocz naprzód, jeśli mamy do czynienia JR NZ,2734,S-LOOP wyrażeniem liczbowym w nawiasach. CALL 2A52,SLICING Zmodyfikuj parametry 'ostatniej wartości'. RST 0020,NEXT-CHAR Idź dalej, aby przetworzyć kolejny JR 2713,S-CONT-3 znak. |
Jeśli bieżący znak jest faktycznie operatorem podwójnym, to zostanie mu nadany kod w zakresie od +C3 do +CF szesnastkowo, oraz odpowiedni kod priorytetu.
2723 S-OPERTR LD B,+00 Oryginalny kod do BC, aby indeksować nim LD C,A w tablicy operatorów. LD HL,+2795 Wskaźnik tej tablicy. CALL 16DC,INDEXER Indeksuj tablicę. JR NC,2734,SLOOP Skocz naprzód, jeśli nie znaleziono operacji. LD C,(HL) Pobierz wymagany kod z tablicy. LD HL,+26ED Wskaźnik tablicy priorytetów: tj. 26ED +C3 daje 27B0 jako pierwszy adres. ADD HL,BC Indeksuj tablicę. LD B,(HL) Pobierz odpowiedni priorytet. |
Teraz następuje wejście do głównej pętli tej procedury. Na tym etapie mamy:
i. 'Ostatnią wartość' na stosie kalkulatora.
ii. Początkowy priorytet na stosie maszynowym pod hierarchią, niewiadomego
rozmiaru, funkcji i kodów binarnych. Hierarchia ta może być pusta.
iii. Para rejestrów BC zawiera 'obecną' operację i priorytet, który po
osiągnięciu końca wyrażenia stanie się priorytetem zero.
Na początku 'ostatnia' operacja i priorytet są pobierane ze stosu maszynowego i porównywane z 'bieżącą' operacją i priorytetem.
Jeśli 'bieżący' priorytet jest wyższy od 'ostatniego', to wykonywane jest opuszczenie tej pętli, ponieważ 'bieżący' priorytet mocniej wiąże od 'ostatniego'.
Jednakże jeśli bieżący priorytet jest mniej wiążący, to operacja określona jako 'ostatnia' zostaje wykonana. 'Bieżąca' operacja i priorytet wracają na stos maszynowy, aby trafić z powrotem do pętli w następnym jej obiegu. W ten sposób hierarchia funkcji i operacji dwuargumentowych, które zostały ustawione w kolejkę, jest przetwarzana we właściwej kolejności.
2734 S-LOOP POP DE Pobierz 'ostatnią' operację i priorytet. LD A,D Priorytet idzie do rejestru A. CP B Porównaj 'ostatni' z 'bieżącym'. JR C,2773,S-TIGHTER Wyjdź, aby zaczekać na argument. AND A Czy oba priorytety są zerami? JP Z,0018,GET-CHAR Wyjdź poprzez GET-CHAR, czyniąc w ten sposób 'ostatnią' wartość pożądanym wynikiem. |
Zanim zostanie wykonana 'ostatnia' operacja, funkcja 'USR' zostaje podzielona na 'USR liczba' i 'USR łańcuch', zgodnie z ustawieniem bądź wyzerowaniem bitu 6 zmiennej FLAGS, gdy argument funkcji był umieszczany na stosie jako 'ostatnia wartość'.
PUSH BC Umieść na stosie 'bieżące' wartości. LO HL,+5C3B To jest zmienna FLAGS. LD A,E 'Ostatnia' operacja jest porównywana CP +ED z kodem USR, co da wynik JR NZ,274C,S-STK-LST 'USR liczba', jeśli nie zostanie zmienione; skocz, jeśli kod nie jest kodem 'USR'. BIT 6,(HL) Testuj bit 6 zmiennej FLAGS. JR NZ,274C,S-STK-LST Skocz, jeśli jest ustawiony ('USR liczba'). LD E,+99 Zmień kod 'ostatniej' operacji: 'przesunięcie' 19, +80 dla danych łańcuchowych z wynikiem liczbowym ('USR string'). 274C S-STK-LST PUSH DE Przechowaj krótko na stosie 'ostatnie' wartości. CALL 2530,SYNTAX-Z Nie wykonuj operacji przy sprawdzaniu składni. JR Z,275B,S-SYNTEST LD A,E Kod 'ostatniej' operacji. AND +3F Usuń bity 6 i 7, aby zamienić kod operacji LD B,A na offset kalkulatora. RST 0028,FP-CALC Teraz użyj kalkulatora. DEFB +3B,fp-calc-2 Wykonaj właściwą operację. DEFB +38,end-calc Zrobione. JR 2764,S-RUNTEST Skocz naprzód. |
Ważną częścią sprawdzania składni jest przetestowanie operacji, aby upewnić się, że natura 'ostatniej wartości' jest poprawnego typu dla danej operacji.
275B S-SYNTEST LD A,E Pobierz kod 'ostatniej' operacji. XOR (FLAGS) To ustawia naturę 'ostatniej wartości' AND +40 względem wymagań operacji. Aby składnia była poprawna, muszą być takie same. 2761 S-RPORT-C JP NZ,1C8A,REPORT-C Skocz, jeśli składnia jest zła. |
Przed wykonaniem skoku wstecz, aby ponownie wejść w pętlę, natura 'ostatniej' wartości musi zostać odnotowana w zmiennej FLAGS.
2764 S-RUNTEST POP DE Pobierz kod 'ostatniej' operacji. LD HL,+5C3B To jest zmienna FLAGS. SET 6,(HL) Załóż wynik liczbowy. BIT 7,E Skocz naprzód, jeśli natura JR NZ,2770,S-LOOPEND 'ostatniej wartości' jest liczbowa. RES 6,(HL) To jest łańcuch. 2770 S-LOOPEND POP BC Pobierz 'bieżące' wartości do BC. JR 2734,S-LOOP Skocz wstecz. |
Whenever the 'present' operation binds tighter, the 'last' and the 'present' values go back on the machine stack. However if the 'present' operation requires a string as its operand then the operation code is modified to indicate this requirement.
2773 S-TIGHTER PUSH DE 'Ostatnie' wartości idą na stos. LD A,C Pobierz 'bieżący' kod operacji. BIT 6,(FLAGS) Nie zmieniaj kodu operacji, jeśli mamy do czynienia JR NZ,2790,S-NEXT z liczbowym argumentem. AND +3F Wyczyść bity 6 i 7. ADD A,+08 Zwiększ kod o +08. LD C,A Zwróć kod de rejestru C. CP +10 Czy operacją jest 'AND'? JR NZ,2788,S-NOT-AND Skocz, jeśli tak nie jest. SET 6,C 'AND' wymaga argumentu liczbowego. JR 2790,S-NEXT Skocz naprzód. 2788 S-NOT-AND JR C,2761,S-RPORT-C Operacje -, *, /, ^ i OR nie są możliwe na łańcuchach. CP +17 Czy operacją jest '+'? JR Z,2790,S-NEXT Skocz, jeśli tak jest. SET 7,C Pozostałe operacje dają wynik liczbowy. 2790 S-NEXT PUSH BC 'Bieżące' wartości idą na stos maszynowy. RST 0020,NEXT-CHAR Przetwarzaj następny znak. JP 24FF,S-LOOP-1 Wróć do pętli. |
adres kod kod operator adres kod kod operator 2795 2B CF + 27A3 3C CD < 2797 2D C3 - 27A5 C7 C9 <= 2799 2A C4 * 27A7 C8 CA >= 279B 2F C5 / 27A9 C9 CB <> 279D 5E C6 ^ 27AB C5 C7 OR 279F 3D CE = 27AD C6 C8 AND 27A1 3E CC > 27AF 00 Znacznik końca |
adres priorytet operator adres priorytet operator 27B0 06 - 27B7 05 >= 27B1 08 * 27B8 05 <> 27B2 08 / 27B9 05 > 27B3 0A ^ 27BA 05 < 27B4 02 OR 27BB 05 = 27B5 03 AND 27BC 06 + 27B6 05 <= |
Procedura ta wywoływana jest przez 'procedurę skanowania funkcji FN' w celu obliczenia wartości funkcji zdefiniowanej przez użytkownika w wierszu programu w języku BASIC. Procedurę można rozważyć w czterech etapach:
i. Składnia polecenia FN jest sprawdzana podczas fazy sprawdzania składni.
ii. Podczas wykonywania wiersza dokonuje się przeszukania obszaru programu w celu znalezienia rozkazu DEF FN, a następnie porównuje się nazwy funkcji, aż będą takie same – lub zostanie zgłoszony błąd.
iii. Argumenty FN są obliczane przez wywołania do SCANNING.
iv. Sama funkcja również jest wyliczana przez wywołanie SCANNING, które z kolei wywołuje procedury LOOK-VARS oraz 'UMIESZCZENIE NA STOSIE ARGUMENTU FUNKCJI'.
27BD S-FN-SBRN CALL 2530,SYNTAX-Z O ile nie jest sprawdzana składnia, JR NZ,27F7,SF-RUN wykonaj skok do SF-RUN. RST 0020,NEXT-CHAR Pobierz pierwszy znak nazwy. CALL 2C8D,ALPHA Jeśli nie jest to litera alfabetu, JP NC,1C8A,REPORT-C to zgłoś błąd. RST 0020,NEXT-CHAR Pobierz następny znak. CP +24 Czy jest to '$'? PUSH AF Zapamiętaj znacznik zera na stosie. JR NZ,27D0,SF-BRKT-1 Skocz, jeśli to nie był znak '$'. RST 0020,NEXT-CHAR Lecz jeśli był, to pobierz następny znak. 27D0 SF-BRKT-1 CP +28 Jeśli znakiem nie jest '(', JR NZ,27E6,SF-RPRT-C to zgłoś błąd. RST 0020,NEXT-CHAR Pobierz następny znak. CP +29 Czy jest to ')'? JR Z,27E9,SF-FLAG-6 Skocz, jeśli tak; nie ma argumentów. 27D9 SF-ARGMTS CALL 24FB,SCANNING Wewnątrz pętli wywołaj SCANNING, aby sprawdzić składnię każdego argumentu i wstawić liczby zmiennoprzecinkowe. RST 0018,GET-CHAR Pobierz znak, który jest za argumentem. CP +2C Jeśli nie jest nim ',', JR NZ,27E4,SF-BRKT-2 to skocz - nie ma więcej argumentów. RST 0020,NEXT-CHAR Pobierz pierwszy znak w następnym argumencie. JR 27D9,SF-ARGMTS Wróć na początek pętli, aby przetworzyć ten argument. 27E4 SF-BRKT-2 CP +29 Czy bieżący znak to ')'? 27E6 SF-RPRT-C JP NZ,1C8A,REPORT-C Jeśli nie, zgłoś błąd. 27E9 SF-FLAG-6 RST 0020,NEXT-CHAR Wskaż następny znak w wierszu BASIC. LD HL.+5C3B To zmienna FLAGS; załóż funkcję łańcuchową RES 6,(HL) i wyzeruj bit 6 zmiennej FLAGS. POP AF Odtwórz znacznik zera, skocz, jeśli JR Z,27F4,SF-SYN-EN FN jest faktycznie funkcją łańcuchową. SET 6,(HL) Inaczej ustaw bit 6 zmiennej FLAGS 27F4 SF-SYN-EN JP 2712,S-CONT-2 Skocz wstecz, aby kontynuować skanowanie wiersza. |
ii. Podczas wykonywania wiersza należy wyszukać polecenie DEF FN.
27F7 SF-RUN RST 0020,NEXT-CHAR Pobierz pierwszy znak nazwy. AND +DF Zresetuj bit 5, aby otrzymać duże litery. LD B,A Skopiuj nazwę do B. RST 0020,NEXT-CHAR Pobierz następny znak. SUB +24 Odejmij 24 szesnastkowo, kod znaku '$'. LD C,A Skopiuj wynik do C (zero dla łańcucha, różne od zera dla funkcji liczbowej). JR NZ,2802,SF-ARGMT1 Skocz przy wartości różnej od zera: funkcja liczbowa. RST 0020,NEXT-CHAR Pobierz następny znak, '('. 2802 SF-ARGMT1 RST 0020,NEXT-CHAR Pobierz pierwszy znak pierwszego argumentu. PUSH HL Zapamiętaj na stosie wskaźnik do niego. LD HL,(PROG) Wskaż początek programu. DEC HL Cofnij się o jedną komórkę. 2808 SF-FND-DF LD DE,+00CE Szukane będzie 'DEF FN'. PUSH BC Zapamiętaj nazwę oraz 'stan łańcuchowy'. CALL 1D86,LOOK-PROG Teraz przeszukaj program. POP BC Odtwórz nazwę i stan. JR NC,2814,SF-CP-DEF Skocz przy znalezionym rozkazie DEF FN. |
RAPORT P - FN bez DEF.
2812 REPORT-P RST 0008,ERROR-1 Wywołaj procedurę obsługi błędów. DEFB +18 |
Gdy zostanie znaleziony rozkaz DEF FN, będzie porównana nazwa oraz stan tych dwóch funkcji: jeśli nie będą do siebie pasować, poszukiwanie zostanie wznowione.
2814 SF-CP-DEF PUSH HL Zapamiętaj wskaźnik znaku DEF FN na wypadek potrzeby wznowienia poszukiwań. CALL 28AB,FN-SKPOVR Pobierz nazwę funkcji DEF FN. AND +DF Wyzeruj bit 5, aby otrzymać duą literę. CP B Czy pasuje do nazwy funkcji FN? JR NZ,2825,SF-NOT-FD Skocz, jeśli nie pasuje. CALL 28AB,FN-SKPOVR Pobierz następny znak w DEF FN. SUB +24 Odejmij 24 szesnastkowo, kod znaku '$'. CP C Porównaj stan ze stanem FN. JR Z,2831,SF-VALUES Skocz, jeśli znaleziono teraz pełną zgodność. 2825 SF-NOT-FD POP HL Odtwórz wskaźnik do 'DEF FN'. DEC HL Cofnij się o jedną komórkę. LD DE,+0200 Użyj procedury poszukującej, aby znaleźć koniec PUSH BC polecenia DEF FN, CALL 198B,EACH-STMT przygotowując się na następne poszukiwanie; POP BC w międzyczasie zapamiętaj nazwę oraz stan. JR 2808,SF-FND-DF Skocz wstecz, aby szukać dalej. |
ii. Teraz znalezione zostało poprawne polecenie DEF FN. Argumenty polecenia FN zostaną obliczone przez powtarzające się wywołania SCANNING, a ich 5-cio bajtowe wartości (lub parametry dla łańcuchów) zostaną wstawione w polecenie DEF FN w miejscach zarezerwowanych tam podczas sprawdzania składni. HL będzie wykorzystywane do wskazywania pozycji wzdłuż polecenia DEF FN (przez wywoływanie w razie konieczności FN-SKPOVR), podczas gdy CH-ADD wskazuje wzdłuż polecenia FN (przez wywoływanie wg potrzeb RST 0020, NEXT-CHAR).
2831 SF-VALUES AND A Jeśli HL teraz wskazuje '$',
CALL Z,28AB,FN-SKPOVR przesuń się do '('.
POP DE Usuń wskaźnik do 'DEF FN'.
POP DE Pobierz wskaźnik do pierwszego
LD (CH-ADD),DE argumentu FN i skopiuj go do CH-ADD.
CALL 28AB,FN-SKPOVR Teraz przejdź za znak '('.
PUSH HL Zapamiętaj ten wskaźnik na stosie.
CP +29 Czy wskazuje na ')'?
JR Z,2885,SF-R-BR-2 Jeśli tak, skocz: FN nie ma argumentów.
2843 SF-ARG-LP INC HL Wskaż następny kod.
LD A,(HL) Umieść ten kod w A.
CP +0E Czy jest to kod 'znacznika liczby', 0E szesnastkowo?
LD D,+40 Ustaw bit 6 rejestru D przy argumencie liczbowym.
JR Z,2852,SF-ARG-VL Skocz przy zerze: argument liczbowy.
DEC HL Teraz upewnij się, że HL wskazuje na
znak '$' (a nie, przykładowo, na kod sterujący)
CALL 28AB,FN-SKPOVR
INC HL Teraz HL wskazuje na 'znacznik liczby'.
LD D,+00 Bit 6 rejestru D jest zerowany: argument łańcuchowy.
2852 SF-ARG-VL INC HL Wskaż pierwszy z pięciu bajtów w DEF FN.
PUSH HL Zapamiętaj ten wskaźnik na stosie.
PUSH DE Zapamiętaj 'status łańcuchowy' argumentu.
CALL 24FB,SCANNING Teraz oblicz ten argument.
POP AF Pobierz znacznik liczba/łańcuch do A.
XOR (FLAGS) Testuj jego bit 6 względem wyniku
AND +40 zwróconego przez SCANNING.
JR NZ,288B,REPORT-Q Jeśli się nie zgadzają, zgłoś raport Q.
POP HL Pobierz do DE wskaźnik pierwszego bajtu z 5 pustych
EX DE,HL w DEF FN.
LD HL,(STKEND) Ustaw HL na STKEND.
LD BC,+0005 BC będzie zliczało 5 bajtów do przesunięcia.
SBC HL,BC Najpierw zmniejsz STKEND o 5,
LD (STKEND),HL usuwając w ten sposób 'ostatnią wartość' ze stosu.
LDIR Skopiuj te 5 bajtów do pustego miejsca w DEF FN.
EX DE,HL Ustaw HL na następny kod.
DEC HL Upewnij się, że HL wskazuje na znak
CALL 28AB,FN-SKPOVR po tych 5 bajtach.
CP +29 Czy jest to ')'?
JR Z,2885,SF-R-BR-2 Jeśli tak, skocz: nie ma więcej argumentów w DEF FN.
PUSH HL To jest ',': zapamiętaj wskaźnik do tego znaku.
RST 0018,GET-CHAR Pobierz znak za ostatnim argumentem,
który był obliczany z FN.
CP +2C Jeśli nie jest to ',' skocz: argumenty
JR NZ,288B,REPORT-Q FN i DEF FN nie są zgodne ze sobą.
RST 0020,NEXT-CHAR Ustaw CH-ADD na następny argument w FN.
POP HL Ustaw HL ponownie na ',' w DEF FN.
CALL 28AB,FN-SKPOVR Przesuń HL na następny argument w DEF FN.
JR 2843,SF-ARG-LP Skocz wstecz, aby przetworzyć ten argument.
2885 SF-R-BR-2 PUSH HL Zapamiętaj wskaźnik do znaku ')' w DEF FN.
RST 0018,GET-CHAR Pobierz znak za ostatnim argumentem w FN.
CP +29 Czy jest to ')'?
JR Z,288D,SF-VALUE Jeśli tak, skocz, aby obliczyć funkcję;
lecz jeśli nie, zgłoś błąd Q. |
RAPORT Q - Błąd parametru.
288B REPORT-Q RST 0008,ERROR-1 Wywołaj procedurę obsługi błędów. DEFB +19 |
iv. Na koniec sama funkcja jest obliczana przez wywołanie SCANNING, po wcześniejszym ustawieniu w DEFADD adresu argumentów tak, jak występują one w poleceniu DEF FN. Zagwarantuje to, że procedura LOOK-VARS po wywołaniu z wnętrza SCANNING najpierw przeszuka te argumenty dla potrzebnych wartości przed wykonaniem poszukiwań w obszarze zmiennych.
288D SF-VALUE POP DE Odtwórz wskaźnik do znaku ')' w DEF FN. EX DE,HL Umieść ten wskaźnik w HL. LD (CH-ADD),HL Wstaw go w CH-ADD. LD HL,(DEFADD) Pobierz starą wartość DEFADD. EX (SP),HL Umieść ją na stosie i wstaw do DEFADD adres startowy LD (DEFADD),HL obszaru argumentów z DEF FN. PUSH DE Zapamietaj adres znaku ')' w FN. RST 0020,NEXT-CHAR Przesuń CH-ADD za znaki ')' i RST 0020,NEXT-CHAR '=' na początek wyrażenia dla funkcji w DEF FN. CALL 24FB,SCANNING Teraz oblicz tę funkcję. POP HL Odtwórz adres znaku ')' w FN. LD (CH-ADD),HL Umieść go w CH-ADD. POP HL Odtwórz pierwotną wartość DEFADD. LD (DEFADD),HL Umieść ją z powrotem w DEFADD. RST 0020,NEXT-CHAR Pobierz następny znak w wierszu programu. JP 2712,S-CONT-2 Skocz wstecz, aby kontynuować przeszukiwanie. |
Procedura ta jest wykorzystywana przez FN i STK-F-ARG w celu przesunięcia HL wzdłuż polecenia DEF FN bez niszczenia CH-ADD, ponieważ wskazuje ona na zawartość polecenia FN.
28AB FN-SKPOVR INC HL Wskaż na następny kod w poleceniu. LD A,(HL) Skopiuj ten kod do A. CP +21 Skocz wstecz, aby go ominąć, jeśli jest to JR C,28AB,FN-SKPOVR kod sterujący lub spacja. RET Skończone. |
Tę procedurę wywołuje się zawsze przy potrzebie przeszukania obszaru zmiennych lub obszaru argumentów polecenia DEF FN. Wejście do procedury następuje ze zmienną systemową CH-ADD wskazującą na pierwszą literę nazwy zmiennej, której położenie jest poszukiwane. Nazwa ta będzie się znajdowała w obszarze programu lub w przestrzeni roboczej. Procedura początkowo tworzy bajt dyskryminatora w rejestrze C, który opiera się na pierwszej literze nazwy zmiennej. Bity 5 i 6 tego bajtu wskazują rodzaj obsługiwanej zmiennej.
Rejestr B jest uzywany jako rejestr bitowy do przechowywania znaczników.
28B2 LOOK-VARS SET 6,(FLAGS) Załóż zmienną liczbową. RST 0018,GET-CHAR Pobierz pierwszy znak do A. CALL 2C8D,ALPHA Czy jest to litera? JP NC,1C8A,REPORT-C Zgłoś błąd, jeśli nie. PUSH HL Zapamiętaj wskaźnik do pierwszej litery. AND +1F Przenieś bity od 0 do 4 litery LD C,A do rejestru C; bity 5 i 7 są zawsze wyzerowane. RST 0020,NEXT-CHAR Pobierz drugi znak do A. PUSH HL Ten wskaźnik również zapamiętaj. CP +28 Czy drugim znakiem jest '('? JR Z,28EF,V-RUN/SYN Tablice liczb potraktuj osobno. SET 6,C Teraz ustaw bit 6. CP +24 Czy drugim znakiem jest '$'? JR Z,28DE,V-STR-VAR Wszystkie łańcuchy potraktuj osobno. SET 5,C Teraz ustaw bit 5. CALL 2C88,ALPHANUM Jeśli nazwa zmiennej składa się tylko JR NC,28E3,V-TEST-FN z jednej litery, to skocz naprzód. |
Teraz znajdź końcowy znak nazwy zbudowanej z więcej niż jednego znaku.
28D4 V-CHAR CALL 2C88,ALPHANUM Czy znak jest literą lub cyfrą? JR NC,28EF,V-RUN/SYN Wyskocz z pętli po znalezieniu końca nazwy. RES 6,C Oznacz bajt dyskryminatora. RST 0020,NEXT-CHAR Pobierz następny znak. JR 28D4,V-CHAR Wróć, aby go przetestować. |
Proste łańcuchy oraz tablice łańcuchów wymagają wyzerowania bitu 6 zmiennej systemowej FLAGS.
28DE V-STR-VAR RST 0020,NEXT-CHAR Ustaw CH-ADD za znakiem '$'. RES 6,(FLAGS) Zeruj bit 6, aby oznaczyć łańcuch. |
Jeśli starszy bajt DEFADD ma wartość różną od zera, co oznacza obliczanie 'funkcji' (FN), oraz jeśli jest czas wykonania programu, to zostanie wykonane przeszukanie argumentów w poleceniu DEF FN.
28E3 V-TEST-FN LD A,(DEFADD-hi) Czy starszy bajt DEFADD wynosi zero? AND A JR Z,28EF,V-RUN/SYN Jeśli tak, skocz naprzód. CALL 2530,SYNTAX-Z Czy 'czas wykonania'? JP NZ,2951,STK-F-ARG Jeśli tak, skocz naprzód, aby przeszukać polecenie DEF FN. |
W przeciwnym razie (lub gdy zmienna nie została znaleziona wewnątrz polecenia DEF FN) zostanie wykonane przeszukanie obszaru zmiennych, o ile nie jest właśnie sprawdzana składnia.
28EF V-RUN/SYN LD B,C Skopiuj bajt dyskryminatora do rejestru B. CALL 2530,SYNTAX-Z Skocz naprzód przy wykonywaniu programu. JR NZ,28FD,V-RUN LD A,C Przenieś dyskryminator do A. AND +E0 Usuń część związaną ze znakiem. SET 7,A Zaznacz sprawdzanie składni przez ustawienie bitu 7. LD C,A Odtwórz dyskryminator. JR 2934,V-SYNTAX Skocz naprzód, aby kontynuować. |
Wiersz języka BASIC jest wykonywany, zatem przeszukaj obszar zmiennych.
28FD V-RUN LD HL,(VARS) Pobierz wskaźnik VARS. |
Teraz wejdź do pętli, aby zająć się nazwami istniejących zmiennych.
2900 V-EACH LD A,(HL) Pierwsza litera każdej istniejącej zmiennej. AND +7F Usuń najstarszy bit. JR Z,2932,V-80-BYTE Jeśli otrzymasz zero, to osiągnięty został bit znacznika końca. CP C Właściwe porównanie. JR NZ,292A,V-NEXT Skocz naprzód, jeśli pierwsze znaki są różne. RLA Obróć A w lewo, a następnie podwój je, ADD A,A aby sprawdzić bity 5 i 6. JP P,293F,V-FOUND-2 Zmienne łańcuchów i tablic łańcuchów. JR C,293F,V-FOUND-2 Proste zmienne liczbowe oraz zmienne FOR-NEXT. |
Długie nazwy należy sprawdzić do końca.
POP DE Skopiuj znacznik do drugiego znaku PUSH DE PUSH HL Zapamiętaj znacznik pierwszej litery. 2912 V-MATCHES INC HL Przetwórz następny znak. 2913 V-SPACES LD A,(DE) Pobieraj kolejno każdy znak. INC DE Wskaż na następny znak. CP +20 Czy znak jest 'spacją'? JR Z,2913,V-SPACES Spacje ignoruj. OR +20 Ustaw bit 5, aby zrównać duże i małe litery. CP (HL) zrób porównanie. JR Z,2912,V-MATCHES Jeśli jest zgodność, wróć dla kolejnego znaku. OR +80 Czy będzie zgodność z ustawionym bitem 7? CP (HL) Sprawdź. JR NZ,2929,V-GET-PTR Skocz naprzód, jeśli 'ostatnie znaki' są różne. LD A,(DE) Sprawdź, czy osiągnięto koniec nazwy CALL 2C88,ALPHANUM przed skokiem naprzód. JR NC,293E,V-FOUND-1 |
W każdym przypadku, gdy nazwy są różne, para rejestrów HL musi zostać ustawiona na początek nazwy kolejnej zmiennej w obszarze zmiennych.
2929 V-GET-PTR POP HL Pobierz wskaźnik. 292A V-NEXT PUSH BC Na krótko zapamiętaj B i C. CALL 19B8,NEXT-ONE DE zostanie ustawione na adres następnej zmiennej. EX DE,HL Zamień ze sobą te dwa wskaźniki. POP BC Odtwórz z powrotem B i C. JR 2900,V-EACH Wróć ponownie na początek pętli. |
Tutaj trafia się, gdy żadna ze zmiennych nie posiadała pożądanej nazwy.
2932 V-80-BYTE SET 7,B Sygnalizuj 'zmienna nieznaleziona'. |
Tutaj trafia się przy sprawdzaniu składni.
2934 V-SYNTAX POP DE Usuń wskaźnik do drugiego znaku. RST 0018,GET-CHAR Pobierz bieżący znak. CP +28 Czy jest to '('? JR Z,2943,V-PASS Jeśli tak, skocz naprzód. SET 5,B Zaznacz, że nie mamy do czynienia JR 294B,V-END z tablicą i skocz naprzód. |
Tutaj trafia się po znalezieniu właściwej nazwy.
293E V-FOUND-1 POP DE Usuń zapamiętany wskaźnik zmiennej. 293F V-FOUND-2 POP DE Usuń wskaźnik drugiego znaku. POP DE Usuń wskaźnik pierwszej litery. PUSH HL Zapamiętaj wskaźnik 'ostatniej' litery. RST 0018,GET-CHAR Pobierz bieżący znak. |
Jeśli znaleziona nazwa zmiennej składa się z więcej niż jednej litery, to pozostałe znaki należy przeskoczyć.
Uwaga: wygląda na to, że zostało to już zrobione w V-CHAR.
2943 V-PASS CALL 2C88,ALPHANUM Czy jest to znak alfanumeryczny? JR NC,294B,V-END Skocz, jeśli znaleziono koniec nazwy. RST 0020,NEXT-CHAR Pobierz następny znak. JR 2943,V-PASS Wróć i sprawdź go. |
Teraz są ustawiane parametry wyjściowe.
294B V-END POP HL HL zawiera wskaźnik litery krótkiej nazwy lub 'ostatniego' znaku nazwy długiej. RL B Obróć cały rejestr. BIT 6,B Określ stan bitu 6. RET Skończone. |
Parametry wyjściowe tej procedury można podsumować następująco: Zmienna systemowa CH-ADD wskazuje na pierwszą komórkę za nazwą zmiennej, jak występuje w wierszu języka BASIC.
Gdy 'zmienna nie została znaleziona':
i. Znacznik przeniesienia jest ustawiony.
ii. Znacznik zera jest ustawiony tylko przy poszukiwaniu zmiennej
tablicowej.
iii. Para rejestrów HL wskazuje na pierwszy znak nazwy zmiennej, jak
występuje w wierszu języka BASIC.
Gdy 'zmienna została znaleziona':
i. Znacznik przeniesienia jest wyzerowany.
ii. Znacznik zera jest ustawiony zarówno dla zmiennych łańcuchowych jak i
wszystkich zmiennych tablicowych.
iii. Para rejestrów HL wskazuje na literę 'krótkiej' nazwy lub na ostatnią
literę 'długiej' nazwy zmiennej znalezionej w obszarze zmiennych.
We wszystkich przypadkach bity 5 i 6 rejestru C wskazują rodzaj przetwarzanej zmiennej. Bit 7 jest zaprzeczeniem znacznika SYNTAX/RUN. Lecz jedynie przy korzystaniu z tej procedury w czasie wykonania programu bity od 0 do 4 będą zawierały kod pierwszej litery nazwy zmiennej.
W czasie sprawdzania składni powrót zawsze następuje z wyzerowanym znacznikiem przeniesienia. Znacznik zera jest ustawiony dla tablic, a wyzerowany dla wszystkich innych zmiennych, z wyjątkiem tego, że nazwa prostej zmiennej łańcuchowej niepoprawnie zakończona znakiem '$' ustawia znacznik zera, w tym przypadku SAVE "nazwa" DATA a$() również przechodzi etap sprawdzania składni.
Procedura ta jest wywoływana przez LOOK-VARS przy DEFADD-hi różnym od zera w celu przeszukania obszaru argumentów polecenia DEF FN przed przeszukaniem obszaru zmiennych. Jeśli dana zmienna zostanie znaleziona w poleceniu DEF FN, to parametry zmiennej łańcuchowej są umieszczane na stosie i sygnalizowany jest brak konieczności wywołania STK/VAR. Lecz umieszczanie na stosie wartości zmiennych liczbowych jest pozostawianie procedurze SCANNING pod adresem 26DA w sposób standardowy.
2951 STK-F-ARG LD HL,(DEFADD) Wskaż pierwszy znak w obszarze LD A,(HL) argumentów i umieść go w A. CP +29 Czy jest to ')'? JP Z,28EF,V-RUN/SYN Skocz, aby przeszukać obszar zmiennych. 295A SFA-LOOP LD A,(HL) W pętli pobieraj kolejny argument. OR +60 Ustaw bity 5 i 6, zakładając prostą LD B,A zmienną liczbową; skopiuj ją do B. INC HL Wskaż następny kod. LD A,(HL) Umieść go w rejestrze A. Czy jest to CP +0E kod 0E szesnastkowo 'znacznika liczby'? JR Z,296B,SFA-CP-VR Jeśli tak, to skocz: zmienna liczbowa. DEC HL Upewnij się, że HL wskazuje znak, a nie CALL 28AB,FN-SKPOVR spację lub kod sterujący. INC HL Teraz HL wskazuje na 'znacznik liczby'. RES 5,B Wyzeruj bit 5 rejestru B: zmienna łańcuchowa. 296B SFA-CP-VR LD A,B Pobierz nazwę zmiennej do A. CP C Czy jest to ta poszukiwana? JR Z,2981,SFA-MATCH Skocz przy zgodności. INC HL Teraz pomiń 5 bajtów INC HL liczby zmiennoprzecinkowej lub INC HL parametrów łańcucha, aby przejść INC HL do następnego argumentu. INC HL CALL 28AB,FN-SKPOVR Przejdź do następnego znaku. CP +29 Czy jest to ')'? JP Z,28EF,V-RUN/SYN Jeśli tak, skocz, aby przeszukać obszar zmiennych. CALL 28AB,FN-SKPOVR Wskaż następny argument. JR 295A,SFA-LOOP Skocz wstecz, aby go rozważyć. |
Znaleziono zgodność. Parametry zmiennej łańcuchowej zostają umieszczone na stosie, unikając potrzeby wywołania procedury STK-VAR.
2981 SFA-MATCH BIT 5,C Sprawdź, czy zmienna jest liczbowa.
JR NZ,2991,SFA-END Skocz, jeśli tak; SCANNING umieści ją na stosie.
INC HL Wskaż pierwszy z pięciu bajtów do umieszczenia na stosie.
LD DE,(STKEND) Wskaż DE na STKEND.
CALL 33C0,MOVE-FP Umieść na stosie 5 bajtów.
EX DE,HL Wskaż HL na nową pozycję STKEND
LD (STKEND),HL i uaktualnij zmienną systemową.
2991 SFA-END POP DE Pozbądź się wskaźników LOOK-VARS
POP DE (wskaźniki pierwszego i drugiego znaku).
XOR A Powróć z poszukiwania z wyzerowanymi oboma
INC A znacznikami przeniesienia i zera – sygnalizując, że
wywołanie STK-VAR nie jest wymagane.
RET Skończone. |
Procedura ta jest zwykle używana albo do znalezienia parametrów definiujących istniejącą zmienną w obszarze zmiennych, albo do zwrócenia w parze rejestrów HL adresu bazowego określonego elementu lub ciągu liczb. Gdy zostanie wywołana z DIM, to procedura sprawdza jedynie składnię polecenia języka BASIC.
Zwróć uwagę, że parametry definiujące pewien łańcuch mogą zostać zmienione przez wywołanie procedury SLICING.
Początkowo rejestry A i B zostają wyzerowane, a bit 7 rejestru C jest sprawdzany w celu określenia, czy jest sprawdzana składnia.
2996 STK-VAR XOR A Wyzeruj znacznik ciągu. LD B,A Wyzeruj rejestr B na później. BIT 7,C Skocz naprzód, jeśli właśnie jest JR NZ,29E7,SV-COUNT sprawdzana składnia. |
Następnie proste łańcuchy są oddzielane od zmiennych tablicowych.
BIT 7,(HL) Skocz naprzód, jeśli mamy do czynienia JR NZ,29AE,SV-ARRAYS z jakąś zmienną tablicową. |
Znajdowane są gotowe parametry prostego łańcucha.
INC A Sygnalizuj 'prosty łańcuch'. 29A1 SV-SIMPLE$ INC HL Przesuń się wzdłuż elementu. LD C,(HL) Pobierz młodszy bajt licznika długości. INC HL Przesuń do przodu wskaźnik. LD B,(HL) Pobierz starszy bajt licznika długości. INC HL Przesuń wskaźnik. EX DE,HL Przekaż wskaźnik do właściwego łańcucha. CALL 2AB2,STK-STORE Przekaż te parametry na stos kalkulatora. RST 0018,GET-CHAR Pobierz bieżący znak i skocz naprzód, aby JP 2A49,SV-SLICE? sprawdzić, czy jest potrzebne dzielenie łańcucha. |
Teraz zostaje znaleziony adres bazowy elementu w ciągu. Początkowo pobrana zostaje 'liczba wymiarów'.
29AE SV-ARRAYS INC HL Przejdź poza bajty długości. INC HL INC HL LD B,(HL) Zbierz 'liczbę wymiarów'. BIT 6,C Skocz naprzód, jeśli obsługujemy JR Z,29C0,SV-PTR ciąg liczb. |
Jeśli ciąg łańcuchów posiada swoją 'liczbę wymiarów' równą '1', to taki ciąg można obsłużyć jak prosty łańcuch.
DEC B Zmniejsz 'liczbę wymiarów' JR Z,29A1,SV-SIMPLE$ i skocz, jeśli jest teraz równa zero. |
Teraz sprawdza się, czy faktycznie w wierszu języka BASIC po tej zmiennej występuje indeks.
EX DE,HL Zapamiętaj wskaźnik w DE. RST 0018,GET-CHAR Pobierz obecny znak. CP +28 Czy jest to '('? JR NZ,2A20,REPORT-3 Jeśli nie, zgłoś błąd. EX DE,HL Odtwórz wskaźnik. |
Zarówno dla ciągów liczbowych jak i dla ciągów łańcuchów wskaźnik zmiennej jest przekazywany do pary rejestrów DE przed wyliczeniem indeksu.
29C0 SV-PTR EX DE,HL Przekaż wskaźnik do DE. JR 29E7,SV-COUNT Skocz naprzód. |
Poniższa pętla jest używana do znalezienia parametrów określonego
elementu wewnątrz ciągu. Wejście do pętli następuje w punkcie środkowym -
SV-COUNT -, gdzie licznik elementów jest ustawiany na zero.
Pętla jest używana 'B' razy, co dla ciągu liczbowego odpowiada liczbie
używanych wymiarów, lecz dla ciągu łańcuchów 'B' ma wartość o jeden mniejszą
od liczby używanych wymiarów, ponieważ ostatni indeks jest wykorzystywany do
określenia podziału łańcucha.
29C3 SV-COMMA PUSH HL Zapamiętaj licznik. RST 0018,GET-CHAR Pobierz obecny znak. POP HL Odtwórz znak. CP +2C Czy bieżący znak to','? JR Z,29EA,SV-LOOP Jeśli tak, to skocz naprzód, aby przetworzyć kolejny indeks. BIT 7,C Jeśli wiersz jest wykonywany, JR Z,2A20,REPORT-3 to powstaje błąd. BIT 6,C Skocz naprzód, jeśli mamy do czynienia JR NZ,29D8,SV-CLOSE z ciągiem łańcuchów. CP +29 Czy bieżący znak to ')'? JR NZ,2A12,SV-RPT-C Jeśli nie, zgłoś błąd. RST 0020,NEXT-CHAR Zwiększ CH-ADD. RET Wróć, skoro składnia jest poprawna. |
Dla ciągu łańcuchów obecny indeks może przedstawiać 'podział' albo indeks z 'podziałem' może wciąż występować w wierszu języka BASIC.
29D8 SV-CLOSE CP +29 Czy obecny znak to ')'? JR Z,2A48,SV-DIM Skocz naprzód i sprawdź, czy jest kolejny indeks. CP +CC Czy obecny znak to 'TO'? JR NZ,2A12,SV-RPT-C Nie powinno być inaczej. 29E0 SV-CH-ADD RST 0018,GET-CHAR Pobierz obecny znak. DEC HL Wskaż na poprzedzający znak LD (CH-ADD),HL i ustaw CH-ADD. JR 2A45,SV-SLICE Oblicz ten 'podział'. |
Tutaj jest wejście do pętli.
29E7 SV-COUNT LD HL,+0000 Wyzeruj licznik. 29EA SV-LOOP PUSH HL Zapamiętaj na krótko licznik. RST 0020,NEXT-CHAR Zwiększ CH-ADD. POP HL Odtwórz licznik. LD A,C Pobierz bajt dyskryminatora. CP +C0 Skocz o ile nie jest sprawdzana JR NZ,29FB,SV-MULT składnia ciągu łańcuchów. RST 0018,GET-CHAR Pobierz obecny znak. CP +29 Czy jest to ')'? JR Z,2A48,SV-DIM Skocz naprzód, skoro zliczanie elementów jest skończone. CP +CC Czy jest to 'TO'? JR Z,29E0,SV-CH-ADD Skocz wstecz, jeśli mamy do czynienia z 'podziałem'. 29FB SV-MULT PUSH BC Zachowaj licznik liczby wymiarów oraz bajt dyskryminatora. PUSH HL Zachowaj licznik elementów. CALL 2AEE,DE,(DE+1) Pobierz rozmiar wymiaru do DE. EX (SP),HL Licznik idzie do HL, a wskaźnik zmiennej na stos. EX DE,HL Licznik idzie do DE a rozmiar wymiaru do HL. CALL 2ACC,INT-EXP1 Oblicz następny indeks. JR C,2A20,REPORT-3 Jeśli poza zakresem, zgłoś błąd. DEC BC Wynik obliczenia jest zmniejszany o 1, ponieważ licznik ma zliczać elementy występujące przed określonym elementem. CALL 2AF4,GET-HL*DE Pomnóż licznik przez rozmiar wymiaru. ADD HL,BC Dodaj wynik 'INT-EXP1' do obecnego licznika. POP DE Pobierz wskaźnik zmiennej. POP BC Pobierz liczbę wymiarów oraz bajt dyskryminatora. DJNZ 29C3,SV-COMMA Wykonuj pętlę aż do wyzerowania rejestru 'B'. |
Znacznik składnia/uruchomienie jest sprawdzany przed rozdzieleniem ciągów łańcuchów od ciągów liczb.
BIT 7,C Jeśli jest sprawdzana składnia, to w tym miejscu 2A12 SV-RPT-C JR NZ,2A7A,SL-RPT-C zgłoś błąd. PUSH HL Zachowaj licznik. BIT 6,C Skocz naprzód, jeśli mamy do czynienia JR NZ,2A2C,SV-ELEM$ z ciągiem łańcuchów. |
Jeśli mamy do czynienia z ciagiem liczb, to bieżącym znakiem musi być ')'.
LD B,D Przenieś wskaźnik zmiennej LD C,E pary rejestrów BC. RST 0018,GET-CHAR Pobierz bieżący znak. CP +29 Czy jest to ')'? JR Z,2A22,SV-NUMBER Przeskocz zgłoszenie błędu, chyba że jest potrzebne. |
Raport 3 - Indeks poza zakresem
2A20 REPORT-3 RST 0008,ERROR-1 Wywołaj procedurę obsługi błędów. DEFB +02 |
Teraz może zostać obliczony adres przed właściwą postacią zmiennoprzecinkową.
2A22 SV-NUMBER RST 0020,NEXT-CHAR Zwiększ CH-ADD. POP HL Pobierz licznik. LD DE,+0005 Każdy element ciagu liczbowego ma 5 bajtów. CALL 2AF4,GET-HL*DE Oblicz całkowitą liczbę bajtów przed wymaganym elementem. ADD HL,BC Ustaw HL na wskazywanie miejsca przed elementem. RET Wróć z tym adresem. |
Gdy mamy do czynienia z ciągiem łańcuchów, to długość elementu jest podana jako ostatni 'rozmiar wymiaru'. Odpowiednie parametry są obliczane i umieszczane na stosie kalkulatora.
2A2C SV-ELEM$ CALL 2AEE,DE,(DE+1) Pobierz rozmiar ostatniego wymiaru. EX (SP),HL Wskaźnik zmiennej idzie na stos, a licznik do HL. CALL 2AF4,GET-HL*DE Pomnóż 'licznik' przez 'rozmiar wymiaru'. POP BC Pobierz wskaźnik zmiennej. ADD HL,BC To spowoduje, że HL wskaże komórkę przed łańcuchem. INC HL Ustaw HL na faktyczny 'początek'. LD B,D Przekaż ostatni rozmiar wymiaru do BD LD C,E aby utworzyć 'długość'. EX DE,HL Przenieś 'początek' do DE. CALL 2AB1,STK-ST-0 Przekaż te parametry na stos kalkulatora. Uwaga: pierwszy parametr ma wartość zero oznaczającą, łańcuch z 'ciągu łańcuchów', a stąd istniejący element nie będzie zwracany do puli pamięci systemu. |
Istnieją trzy możliwe postacie ostatniego indeksu. Pierwsza to - A$(2,4 TO 8) -, druga - A$(2)(4 TO 8) - i trzecia - A$(2) - co jest standardową postacią i oznacza, że wymagany jest cały łańcuch.
RST 0018,GET-CHAR Pobierz obecny znak. CP +29 Czy jest to ')'? JR Z,2A48,SV-DIM Skocz, jeśli tak jest. CP +2C Czy jest to ','? JR NZ,2A20,REPORT-3 Zgłoś błąd, jeśli tak nie jest. 2A45 SV-SLICE CALL 2A52,SLICING Użyj SLICING do zmiany zestawu parametrów. 2A48 SV-DIM RST 0020,NEXT-CHAR Pobierz następny znak.. 2A49 SV-SLICE? CP +28 Czy to '('? JR Z,2A45,SV-SLICE Skocz wstecz, jeśli jest 'podział' do obsłużenia. |
Po obsłużeniu ostatniego indeksu można wykonać powrót.
RES 6,(FLAGS) Sygnalizuj - wynik łańcuchowy. RET Wróć z parametrami łańcucha jako 'ostatnia wartość' na stosie kalkulatora. |
Łańcuch znakowy może być poddawany podziałowi za pomocą tej procedury. Wejście następuje z parametrami łańcucha obecnymi na szczycie stosu kalkulatora oraz w rejestrach A, B, C, D i E. Na początku testowany jest znacznik składnia/uruchomienie, a parametry łańcucha są pobierane tylko w czasie wykonywania się programu.
2A52 SLICING CALL 2530,SYNTAX-Z Sprawdź znacznik. CALL NZ,2BF1,STK-FETCH W 'czasie wykonania' pobierz parametry ze stosu. |
Sprawdza się możliwość wystąpienia pustego podziału '()'.
RST 0020,NEXT-CHAR Pobierz następny znak. CP +29 Czy jest to ')'? JR Z,2AAD,SL-STORE Skocz naprzód, jeśli tak jest. |
Przed rozpoczęciem operacji w rejestrach są umieszczane następujące dane:
PUSH DE 'początek' idzie na stos maszynowy. XOR A Rejestr A zostaje wyzerowany i zapamiętany. PUSH AF PUSH BC Chwilowo zapamiętana zostaje 'długość'. LD DE,+0001 Zakładamy, że 'podział' rozpocznie się od pierwszego znaku. RST 0018,GET-CHAR Pobierz ten pierwszy znak. POP HL Przekaż 'długość' do HL. |
Teraz zostaje wyliczony pierwszy parametr podziału.
CP +CC Czy obecny znak to 'TO'? JR Z,2A81,SL-SECOND Jeśli zostanie wykonany skok, to pierwszy parametr standardowo przyjmie wartość '1'. POP AF Na tym etapie A ma wartość zero. CALL 2ACD,INT-EXP2 Pierwszy parametr trafi do BC. Jeśli wystąpił błąd wyjścia poza zakres, to A będzie zawierać +FF. PUSH AF W każdym wypadku zachowujemy tę wartość. LD D,B Przenieś pierwszy parametr do DE. LD E,C PUSH HL Chwilowo zapamiętaj 'długość'. RST 0018,GET-CHAR Pobierz obecny znak. POP HL Odtwórz 'długość'. CP +CC Czy bieżącym znakiem jest 'TO'? JR Z,2A81,SL-SECOND Jeśli tak, to skocz naprzód, aby obsłużyć drugi parametr; CP +29 inaczej upewnij się, że istnieje nawias 2A7A SL-RPT-C JP NZ,1C8A,REPORT-C zamykający. |
W tym miejscu został zidentyfikowany podział dotyczący pojedynczego znaku łańcucha, np. – A$(4).
LD H,D Ostatni znak 'podziału' jest LD L,E również pierwszym znakiem. JR 2A94,SL-DEFINE Skocz naprzód. |
Tutaj zostaje wyznaczony drugi parametr 'podziału'.
2A81 SL-SECOND PUSH HL Chwilowo zapamiętaj 'długość'. RST 0020,NEXT-CHAR Pobierz następny znak. POP HL Odtwórz 'długość'. CP +29 Czy obecny znak to ')'? JR Z,2A94,SL-DEFINE Skocz, jeśli brak drugiego parametru. POP AF jeśli pierwszy parametr był w zakresie, rejestr A będzie zawierał zero; inaczej +FF. CALL 2ACD,INT-EXP2 Wstaw drugi parametr do BC. PUSH AF Zapamiętaj 'rejestr błędu'. RST 0018,GET-CHAR Pobierz obecny znak. LD H,B Przekaż wynik otrzymany w LD L,C INT-EXP2 do pary rejestrów HL. CP +29 Sprawdź, czy teraz jest nawias zamykający. JR NZ,2A7A,SL-RPT-C |
Teraz 'nowe' parametry są zdefiniowane.
2A94 SL-DEFINE POP AF Pobierz 'rejestr błędu'. EX (SP),HL Drugi parametr idzie na stos, a 'początek do HL. ADD HL,DE Pierwszy parametr jest dodawany do 'początku'. DEC HL Cofnij się o komórkę, aby otrzymać poprawny adres. EX (SP),HL 'Nowy początek' idzie na stos, a drugi parametr do HL. AND A Odejmij pierwszy parametr od drugiego, aby otrzymać SBC HL,DE długość fragmentu łańcucha. LD BC,+0000 Ustaw 'nową długość'. JR C,2AA8,SL-OVER Ujemny 'podział' daje pusty łańcuch. INC HL Zezwól na dodatkowy bajt. AND A Tylko teraz testuj 'rejestr błędu'. JP M,2A20,REPORT-3 Skocz, jeśli dowolny z parametrów był poza zakresem dla łańcucha. LD B,H Prześlij 'nową długość' do BC. LD C,L 2AA8 SL-OVER POP DE Pobierz 'nowy start'. RES 6,(FLAGS) Upewnij się, że łańcuch jest wciąż oznaczony. 2AAD SL-STORE CALL 2530,SYNTAX-Z Wróć w tym punkcie, jeśli sprawdzana jest składnia; RET Z inaczej przejdź do procedury STK-STORE. |
Ta procedura umieszcza wartości przechowywane w rejestrach A, B, C, D i E na stos kalkulatora. Dlatego stos ten rośnie o 5 bajtów przy każdym wywołaniu tej procedury.
Procedura jest zwykle wykorzystywana do przekazywania parametrów łańcuchów, lecz używają jej również procedury STACK-BC i LOG (2^A) do przesyłania 'małych liczb całkowitych' na stos.
Zwróć uwagę, że przy zapisywaniu parametrów łańcucha pierwszą zapamiętaną wartością (pochodzącą z rejestru A) będzie zero, jeśli łańcuch pochodzi z tablicy łańcuchów lub jest łańcuchem poddanym 'podziałowi'. Wartość ta będzie równa 1 przy kompletnym łańcuchu. 'Znacznik' ten jest używany w procedurze rozkazu 'LET', gdzie '1' sygnalizuje potrzebę usunięcia z pamięci starej kopii łańcucha.
2AB1 STK-ST-0 XOR A Sygnalizuj - łańcuch z tablicy lub łańcuch 'podzielony'. 2AB2 STK-STO-$ RES 6,(FLAGS) Upewnij się, że znacznik oznacza wynik łańcuchowy. 2AB6 STK-STORE PUSH BC Zapamiętaj na krótko B i C. CALL 33A9,TEST-5-SP Czy jest miejsce na 5 bajtów? Nie wracaj, jeśli brak miejsca. POP BC Odtwórz B i C. LD HL,(STKEND) Pobierz adres pierwszej komórki ponad obecnym stosem. LD (HL),A Prześlij pierwszy bajt. INC HL Przejdź dalej. LD (HL),E Prześlij drugi i trzeci bajt; INC HL dla łańcucha będzie to jego 'początek'. LD (HL),D INC HL Przejdź dalej. LD (HL),C Prześlij czwarty i piaty bajt; INC HL dla łańcucha będzie to jego 'długość'. LD (HL),B INC HL Przejdź dalej, aby wskazać komórkę ponad stosem. LD (STKEND),HL Adres ten zapamiętaj w STKEND RET i powróć. |
Ta procedura zwraca wynik obliczenia 'następnego wyrażenia' jako wartości całkowitej przechowywanej przez parę rejestrów BC. Procedura również sprawdza, czy wynik ten nie przekroczył wartości granicznej dostarczonej w parze rejestrów HL. Znacznik przeniesienia jest ustawiany, jeśli jest błąd 'przekroczenia zakresu'.
Rejestr A jest używany jako 'rejestr błędu' i przechowuje +00, jeśli nie ma 'poprzedniego błędu' lub +FF, jeśli taki błąd wystąpił.
2ACC INT-EXP1 XOR A Wyzeruj 'rejestr błędu'. 2ACD INT-EXP2 PUSH DE Zapamiętaj pary rejestrów DE i HL PUSH HL na czas wykonywania procedury. PUSH AF Zapamiętaj tymczasowo 'rejestr błędu'. CALL 1C82,EXPT-1NUM 'Następne wyrażenie' zostaje obliczone w celu utworzenia 'ostatniej wartości' na stosie kalkulatora. POP AF Odtwórz 'rejestr błędu'. CALL 2530,SYNTAX-Z Skocz naprzód przy sprawdzaniu składni. JR Z,2AEB,I-RESTORE PUSH AF Ponownie zapamiętaj 'rejestr błędu'. CALL 1E99,FIND-INT2 'Ostatnia wartość' jest kompresowana do BC. POP DE Rejestr błędu do D. LD A,B 'Następne wyrażenie' o wartości zero OR C jest zawsze w zakresie, zatem skocz do przodu, SCF jeśli tak jest. JR Z,2AE8,I-CARRY POP HL Pobierz kopię wartości granicznej. PUSH HL Będzie to 'rozmiar wymiaru', 'granica DIM' lub 'długość łańcucha'. AND A Teraz porównaj wynik obliczenia wyrażenia SBC HL,BC z wartością graniczną. |
Stan znacznika przeniesienia oraz wartość przechowywana w rejestrze D są teraz przetwarzane, aby otrzymać odpowiednią wartość dla 'rejestru błędu'.
2AE8 I-CARRY LD A,D Pobierz 'starą wartość błędu'. SBC A,+00 Utwórz 'nową wartość błędu'; +00, jeśli nie było wcześniej błędu +FF lub mniej, jeśli w tym lub poprzednim przebiegu pojawił się błąd przekroczenia zakresu. |
Przed powrotem odtwórz rejestry.
2AEB I-RESTORE POP HL Odtwórz HL i DE. POP DE RET Wróć, 'rejestr błędu' w A. |
Procedura wykonuje operację – LD DE,(DE+1) – i zwraca HL wskazujące na 'DE+2'.
2AEE DE,(DE+1) EX DE,HL Użyj HL do operacji. INC HL Wskaż na 'DE+1'. LD E,(HL) W wyniku - LD E,(DE+1). INC HL Wskaż na 'DE+2'. LD D,(HL) W wyniku - LD D,(DE+2). RET Skończone. |
O ile nie jest sprawdzana składnia, procedura wywołuje procedurę 'HL=HL*DE', która wykonuje wymagane mnożenie.
Nadmiar poza 16 bitów dostępnych w parze rejestrów HL daje raport błędu 'brak pamięci'. Nie jest to dokładnie ta sytuacja, lecz implikuje ona, że pamięć jest zbyt mała do przeprowadzenia zadania zamierzonego przez programistę.
2AF4 GET-HL*DE CALL 2530,SYNTAX-Z Jeśli jest sprawdzana składnia, RET Z wróć bezpośrednio. CALL 30A9,HL=HL*DE Wykonaj mnożenie. JP C,1F15,REPORT-4 Raport 'brak pamięci'. RET Skończone. |
Jest to rzeczywista procedura przypisująca dla rozkazów LET, READ i INPUT.
Jeśli docelowa zmienna jest 'nowo zadeklarowaną zmienną', to DEST będzie wskazywało pierwszą literę jej nazwy w wierszu języka BASIC. Bit 1 zmiennej systemowej FLAGX zostanie ustawiony na 1.
Jednakże, jeśli zmienna docelowa 'już istnieje', to bit 1 FLAGX zostanie wyzerowany, a DEST będzie wskazywało pozycję przed pięcioma bajtami 'starej wartości', a dla zmiennej łańcuchowej będzie wskazywało na pierwszy znak 'starego łańcucha'. Używanie DEST w ten sposób odnosi się do prostych zmiennych oraz do elementów tablic.
Bit 0 FLAGX jest ustawiany, jeśli docelowa zmienna jest 'pełną' zmienną łańcuchową (sygnalizując potrzebę usunięcia starej kopii).
Początkowo pobrana zostaje bieżąca wartość DEST i testowany jest bit 1 zmiennej systemowej FLAGS.
2AFF LET LD HL,(DEST) Pobierz bieżący adres w DEST. BIT 1,(FLAGX) Skocz, jeśli jest obsługiwana JR Z,2B66,L-EXISTS 'istniejąca już zmienna'. |
Jest używana 'nowo zadeklarowana zmienna'. Zatem najpierw zostaje znaleziona długość jej nazwy.
LD BC,+0005 Załóż zmienną liczbową - 5 bajtów. |
Wejdź do pętli zajmującej się znakami długiej nazwy. Spacje oraz kody kolorów w nazwie są ignorowane.
2B0B L-EACH-CH INC BC Dodaj '1' do licznika przy każdym znaku nazwy. 2B0C L-NO-SP INC HL Idź wzdłuż nazwy zmiennej. LD A,(HL) Pobierz 'obecny kod'. CP +20 Skocz wstecz, jeśli jest nim 'spacja'; JR Z,2B0C,L-NO-SP co w efekcie spowoduje jej zignorowanie. JR NC,2B1F,L-TEST-CH Skocz naprzód, jeśli kod jest w zakresie od +21 do +FF. CP +10 Zaakceptuj jako końcowy kod kody JR C,2B29,L-SPACES w zakresie od +00 do +0F. CP +16 Również zaakceptuj zakres JR NC,2B29,L-SPACES od +16 do +1F. INC HL Przejdź poza kod sterujący po kodach od INK do OVER. JR 2B0C,L-NO-SP Skocz wstecz, ponieważ kody te są traktowane jak spacje. |
Rozdziel nazwy zmiennych 'liczbowych' od 'łańcuchowych'.
2B1F L-TEST-CH CALL 2C88,ALPHANUM Czy kod jest alfanumeryczny? JR C,2B0B,L-EACH-CH Jeśli tak, to zaakceptuj go jako znak 'długiej nazwy'. CP +24 Czy obecny kod to '$'? JP Z,2BC0,L-NEWS Skocz naprzód przy obsłudze 'nowo zadeklarowanego' prostego łańcucha. |
'Nowo zadeklarowana zmienna liczbowa' obecnie obsługiwana będzie wymagała 'BC bajtów' w obszarze zmiennych na swoją nazwę oraz wartość. Tworzone jest to miejsce i nazwa zmiennej zostaje skopiowana wraz ze znakami 'oznaczanymi' jako wymagane.
2B29 L-SPACES LD A,C Skopiuj 'długość' do A. LD HL,(E-LlNE) Ustaw HL na adres 'bajtu 80' na końcu obszaru zmiennych. CALL 1655,MAKE-ROOM Teraz zrób miejsce w obszarze zmiennych. Uwaga: 'BC' bajtów zostaje udostępnionych przed przesuniętym 'bajtem 80'. INC HL Wskaż pierwszy z 'nowych' bajtów. INC HL DE ustaw na drugi z 'nowych bajtów. EX DE,HL PUSH DE Zapamiętaj ten wskaźnik. LD HL,(DEST) Pobierz wskaźnik początku nazwy. DEC DE Ustaw DE na adres pierwszego 'nowego' bajtu. SUB +06 Ustaw w B 'liczbę dodatkowych znaków', które LD B,A znajdują się w 'długiej nazwie'. JR Z,2B4F,L-SINGLE Skocz naprzód przy zmiennej o 'krótkiej nazwie'. |
'Dodatkowe' znaki długiej nazwy są przekazywane do obszaru zmiennych.
2B3E L-CHAR INC HL Wskaż każdy z 'dodatkowych' znaków. LD A,(HL) Pobierz znak. CP +21 Akceptuj kody od +21 do +FF; JR C,2B3E,L-CHAR ignoruj kody od +00 do +20. OR +20 Ustaw bit 5 dla małych liter. INC DE Umieszczaj po kolei te kody LD (DE),A od drugiego 'nowego' bajtu dalej. DJNZ 2B3E,L-CHAR Wróć na początek pętli, aby przesłać wszystkie 'dodatkowe' kody. |
Ostatni znak 'długiej' nazwy musi być poddany operacji LUB z +80.
OR +80 Oznacz ten kod jako wymagany LD (DE),A i nadpisz ostatni kod. |
Teraz zostanie obsłużona pierwsza litera nazwy zmiennej.
LD A,+C0 Przygotuj się do oznaczenia znaku 'długiej' nazwy. 2B4F L-SINGLE LD HL,(DEST) Pobierz wskaźnik znaku. XOR (HL) A zawiera +00 dla nazwy 'krótkiej' lub +C0 dla 'długiej'. OR +20 Ustaw bit 5 dla małych liter. POP HL Teraz usuń wskaźnik. |
Procedura L-FIRST jest teraz wywoływany, aby wprowadzić tę 'literę' na jej właściwe miejsce.
CALL 2BEA,L-FIRST Wstaw literę i wróć z HL wskazującym 'nowy bajt 80'. |
Teraz 'ostatnia wartość' może zostać przeniesiona do obszaru zmiennych. Zwróć uwagę, że w tym miejscu HL zawsze wskazuje na adres za pięcioma bajtami przydzielonymi liczbie..
Instrukcja 'RST 0028' jest wykorzystywana do wywołania KALKULATORA i ostatnia wartość zostaje usunięta. Jednakże nie jest ona nadpisana..
2B59 L-NUMERIC PUSH HL Zapamiętaj wskaźnik 'docelowy'. RST 0028,FP-CALC Użyj kalkulatora. DEFB +02,delete To przesunie STKEND wstecz o pięć bajtów. DEFB +38,end-calc POP HL Odtwórz wskaźnik. LD BC,+0005 Na liczbę potrzebne jest pięć bajtów. AND A Ustaw HL na adres pierwszego z nich SBC HL,BC JR 2BA6,L-ENTER i skocz naprzód, aby przesłać liczbę. |
W to miejsce przychodzi się, jeśli zmienna 'już istnieje'. Najpierw testowany jest bit 6 zmiennej systemowej FLAGS, aby rozdzielić zmienne liczbowe od łańcuchowych lub od tablic łańcuchów.
2B66 L-EXISTS BIT 6,(FLAGS) Skocz naprzód, jeśli mamy do czynienia z JR Z,2B72,L-DELETES jakąkolwiek zmienną łańcuchową. |
Przy zmiennych liczbowych 'nowa' liczba nadpisuje 'starą'. Zatem najpierw należy ustawić HL na adres za pięcioma bajtami istniejącej wartości. Obecnie HL wskazuje adres przed tymi pięcioma bajtami.
LD DE,+0006 Pięć bajtów liczby + '1'. ADD HL,DE Teraz HL wskazuje 'za'. JR 2B59,L-NUMERIC Skocz wstecz, aby dokonać właściwego przesyłu. |
Parametry zmiennej łańcuchowej są pobierane, a pełne proste łańcuchy zostają odseparowane od łańcuchów 'dzielonych' lub od tablic łańcuchów.
2B72 L-DELETE$ LD HL,(DEST) Pobierz 'początek'. Uwaga: ten rozkaz jest nadmiarowy. LD BC,(STRLEN) Pobierz 'długość'. BIT 0,(FLAGX) Skocz, jeśli mamy do czynienia z pełnym, prostym łańcuchem; JR NZ,2BAF,L-ADD$ stary łańcuch będzie musiał zostać 'usunięty' tylko w tym przypadku. |
Jeśli mamy do czynienia z 'podziałem' istniejącego łańcucha prostego, z 'podziałem' łańcucha z tablicy łańcuchów lub pełnym łańcuchem z tablicy łańcuchów, to potrzebne są dwa różne etapy. W pierwszym zostaje utworzony 'nowy' łańcuch w obszarze roboczym, skrócony lub wydłużony wg potrzeb. W drugim etapie 'nowy' łańcuch zostaje skopiowany do przeznaczonego mu miejsca w obszarze zmiennych.
Jednakże nic nie robimy w przypadku łańcucha o zerowej długości.
LD A,B Wróć, jeśli łańcuch jest pusty OR C RET Z |
Następnie utwórz w obszarze roboczym odpowiednie miejsce.
PUSH HL Zapamiętaj 'początek' (DEST).
RST 0030,BC-SPACES Utwórz potrzebne miejsce w obszarze roboczym.
PUSH DE Zapamiętaj wskaźnik do pierwszej komórki.
PUSH BC Zapamiętaj 'długość' do późniejszego użytku.
LD D,H Ustaw DE na adres ostatniej komórki.
LD E,L
INC HL Ustaw HL na adres 'o jeden większy' od nowego obszaru.
LD (HL),+20 Wstaw znak 'spacji'.
LDDR Skopiuj ten znak na wszystkie komórki.
Zakończ z HL wskazującym pierwszą nową komórkę. |
Teraz zostają pobrane ze stosu kalkulatora parametry obsługiwanego łańcucha.
PUSH HL Zapamiętaj tymczasowo wskaźnik. CALL 2BF1,STK-FETCH Pobierz 'nowe' parametry. POP HL Odtwórz wskaźnik. |
Uwaga: W tym miejscu wymagana ilość miejsca została udostępniona w przestrzeni roboczej dla 'przypisywanej zmiennej', np. dla polecenia LET A$(4 to 8)="abcdefg" - utworzono obszar pięciu bajtów.
Parametry pobrane wyżej jako 'ostatnia wartość' reprezentują łańcuch, który ma zostać skopiowany do nowego miejsca z wydłużeniem lub skróceniem wg potrzeb.
Długość 'nowego' łańcucha jest porównywana z długością udostępnionego mu miejsca.
EX (SP),HL 'Długość' nowego obszaru do HL. 'Wskaźnik' nowego obszaru na stos. AND A Porównaj te dwie 'długości' SBC HL,BC i skocz naprzód, jeśli 'nowy' ADD HL,BC łańcuch zmieści się w przydzielony obszar. JR NC,2B9B,L-LENGTH tj. nie potrzeba go skracać. LD B,H Jednakże zmodyfikuj 'nową' LD C,L długość, jeśli jest zbyt długi. 2B9B L-LENGTH EX (SP),HL 'Długość' nowego obszaru na stos. 'Wskaźnik' nowego obszaru do HL. |
Nowy łańcuch zostaje skopiowany do obszaru roboczego, jeśli nie jest pusty. Wydłużenie jest osiągane automatycznie, jeżeli 'nowy' łańcuch jest krótszy od udostępnionego mu miejsca.
EX DE,HL 'Początek' nowego łańcucha do HL. 'Wskaźnik' nowego obszaru do DE. LD A,B Skocz naprzód, jeśli OR C 'nowy' łańcuch jest JR Z,2BA3,L-IN-W/S łańcuchem pustym. LDIR Inaczej przenieś 'nowy' łańcuch do przestrzeni roboczej. |
Wartości umieszczone na stosie są odtwarzane.
2BA3 L-IN-W/S POP BC 'Długość' nowego obszaru. POP DE 'Wskaźnik' nowego obszaru. POP HL Początek - wskaźnik 'przypisywanej zmiennej', który pierwotnie znajdował się w DEST. L-ENTER jest teraz wykorzystywane do przekazania 'nowego' łańcucha do obszaru zmiennych. |
Ta krótka procedura jest używana do przekazania albo wartości liczbowej ze stosu kalkulatora lub łańcucha z przestrzeni roboczej do odpowiedniego miejsca w obszarze zmiennych.
Stąd procedury tej używa się do wszystkich przypadków z wyjątkiem 'nowo zadeklarowanych' oraz 'pełnych i istniejących' łańcuchów prostych.
2BA6 L-ENTER EX DE,HL Wymień wskaźniki. LD A,B Jeszcze raz sprawdź, że długość jest niezerowa. OR C RET Z PUSH DE Zapamiętaj wskaźnik przeznaczenia. LDIR Przenieś wartość liczbową lub łańcuch. POP HL Wróć z parą rejestrów HL wskazującą na pierwszy bajt RET tej wartości liczbowej lub tego łańcucha. |
Gdy jest obsługiwany 'pełny i istniejący' łańcuch prosty, to nowy łańcuch zostaje wprowadzony tak, jakby był 'nowo zadeklarowanym' łańcuchem prostym, zanim istniejąca wersja będzie 'usunieta' z pamięci.
2BAF L-ADD$ DEC HL Ustaw HL na adres litery DEC HL nazwy zmiennej. DEC HL tj. DEST - 3. LD A,(HL) Pobierz tę literę. PUSH HL Zapamiętaj wskaźnik do 'istniejącej wersji'. PUSH BC Zapamiętaj 'długość' 'istniejącego łańcucha'. CALL 2BC6,L-STRING Użyj L-STRING do dodania nowego łańcucha do obszaru zmiennych. POP BC Odtwórz 'długość'. POP HL Odtwórz wskaźnik. INC BC Do długości dodaj 3 na bajt litery oraz dwa bajty długości. INC BC INC BC JP 19E8,RECLAIM-2 Wyjdź przez skok do RECLAIM-2, które usunie całość istniejącej wersji. |
'Nowo zadeklarowane' łańcuchy są obsługiwane w sposób następujący:
2BC0 L-NEW$ LD A,+DF Przygotuj się na oznaczenie litery zmiennej. LD HL,(DEST) Pobierz wskaźnik do litery. AND (HL) Oznacz literę wg potrzeb. L-STRING zostanie teraz użyte do dodania nowego łańcucha do obszaru zmiennych. |
Parametry 'nowego' łańcucha zostają pobrane, tworzy się wystarczające miejsce dla niego, a następnie kopiuje.
2BC6 L-STRING PUSH AF Zapamiętaj literę zmiennej CALL 2BF1,STK-FETCH Pobierz 'początek' i 'długość' 'nowego' łańcucha. EX DE,HL Umieść 'początek' w HL. ADD HL,BC Ustaw HL na adres o 1 większy od końca łańcucha. PUSH BC Zapamiętaj 'długość'. DEC HL Ustaw HL na adres końca łańcucha. LD (DEST),HL Zapamiętaj wskaźnik na krótko. INC BC Do długości dodaj 3 na literę zmiennej INC BC oraz na dwa bajty długości łańcucha. INC BC LD HL,(E-LINE) Ustaw HL na adres 'bajtu 80' na końcu obszaru zmiennych. CALL 1655,MAKE-ROOM Zrób miejsce w obszarze zmiennych. Uwaga: W rezultacie 'BC' bajtów zostaje zarezerwowanych przed przemieszczonym 'bajtem 80'. LD HL,(DEST) Odtwórz wskaźnik końca 'nowego' łańcucha. POP BC Utwórz kopię długości PUSH BC 'nowego' łańcucha. INC BC Dodaj jeden do długości w przypadku, gdyby 'nowy' łańcuch był pusty. LDDR Skopiuj 'nowy' łańcuch + jeden bajt. EX DE,HL Ustaw HL na adres starszego bajtu długości łańcucha. INC HL POP BC Pobierz 'długość'. LD (HL),B Wprowadź starszy bajt. DEC HL Do tyłu o jeden. LD (HL),C Wprowadź młodszy bajt. POP AF Pobierz znak zmiennej. |
Wejście do tej procedury następuje z literą nazwy zmiennej, odpowiednio oznaczoną, w rejestrze A. Litera nadpisuje 'stary bajt 80' w obszarze zmiennych. Powrót jest wykonywany z parą rejestrów HL wskazującą 'nowy bajt 80'.
2BEA L-FIRST DEC HL Ustaw HL na adres 'starego bajtu 80'. LD (HL),A Zostaje on nadpisany przez literę zmiennej. LD HL,(E-LINE) Ustaw HL na adres 'nowego bajtu 80'. DEC HL Zakończone ze wszystkimi RET 'nowo zadeklarowanymi zmiennymi'. |
Ta ważna procedura pobiera 'ostatnią wartość' ze stosu kalkulatora. Pięć bajtów może reprezentować albo liczbę zmiennoprzecinkową w postaci 'długiej' lub 'krótkiej', albo zestaw parametrów definiujących łańcuch.
2BF1 STK-FETCH LD HL,(STKEND) Pobierz STKEND. DEC HL O jeden adres do tyłu; LD B,(HL) Piąta wartość. DEC HL Wstecz o jeden. LD C,(HL) Czwarta wartość. DEC HL Wstecz o jeden. LD D,(HL) Trzecia wartość. DEC HL Wstecz o jeden. LD E,(HL) Druga wartość. DEC HL Wstecz o jeden. LD A,(HL) Pierwsza wartość. LD (STKEND),HL Ustaw STKEND na nowy adres. RET Skończone. |
Ta procedura tworzy nową tablicę w obszarze zmiennych. Zaczyna od przeszukania istniejących zmiennych w celu określenia, czy istnieje wśród nich tablica o takiej samej nazwie. Jeśli taka tablica zostanie znaleziona, to procedura usuwa ją przed utworzeniem nowej.
Nowa tablica będzie zawierała wszystkie elementy wyzerowane, jeśli jest tablicą liczbową, lub z wpisanymi spacjami, jeśli jest tablicą łańcuchów.
2C02 DIM CALL 28B2,LOOK-VARS Przeszukaj obszar zmiennych. 2C05 D-RPORT-C JP NZ,1C8A,REPORT-C Zgłoś raport C, ponieważ wystąpił błąd. CALL 2530,SYNTAX-Z Skocz naprzód, jeśli trwa wykonywanie programu. JR NZ,2C15,D-RUN RES 6,C Sprawdź składnię tablic łańcuchów, jakby były tablicami liczbowymi. CALL 2996,STK-VAR Sprawdź składnię wyrażenia w nawiasach. CALL 1BEE,CHECK-END Przejdź do następnego rozkazu w wierszu, skoro składnia była dobra. |
'Istniejąca tablica' jest usuwana z pamięci.
2C15 D-RUN JR C,2C1F,D-LETTER Skocz naprzód, jeśli nie ma 'istniejącej tablicy'. PUSH BC Zapamiętaj bajt dyskryminatora. CALL 19B8,NEXT-ONE Znajdź początek następnej zmiennej. CALL 19E8,RECLAIM-2 Usuń 'istniejącą tablicę'. POP BC Odtwórz bajt dyskryminatora. |
Znajdowane są początkowe parametry nowej tablicy.
2C1F D-LETTER SET 7,C Ustaw bit 7 w bajcie dyskryminatora. LD B,+00 Wyzeruj licznik wymiarów. PUSH BC Zapamiętaj licznik i bajt dyskryminatora. LD HL,+0001 Para rejestrów HL będzie przechowywała BIT 6,C rozmiar elementów w tablicy, JR NZ,2C2D,D-SIZE '1' dla tablicy łańcuchów/'5' dla tablicy liczbowej. LD L,+05 2C2D D-SIZE EX DE,HL Rozmiar elementu do DE. |
Poniższa pętla jest wykonywana dla każdego wymiaru wyszczególnionego w wyrażeniu objętym nawiasami w rozkazie DIM. Całkowita liczba bajtów potrzebnych dla elementów tablicy jest tworzona w parze rejestrów DE.
2C2E D-NO-LOOP RST 0020,NEXT-CHAR Przesuwaj do przodu CH-ADD przy każdym obiegu. LD H,+FF Ustaw 'wartość graniczną'. CALL 2ACC,INT-EXP1 Oblicz parametr. JP C,2A20,REPORT-3 Zgłoś błąd, jeśli 'jest poza zakresem'. POP HL Pobierz licznik wymiarów i bajt dyskryminatora. PUSH BC Zapamiętaj parametr przy każdym obiegu pętli. INC H Również zwiększ przy każdym obiegu licznik wymiarów. PUSH HL Ponownie umieść na stosie licznik wymiarów i bajt dyskryminatora. LD H,B Parametr jest przenoszony do LD L,C pary rejestrów HL. CALL 2AF4,GET-HL*DE Całkowita liczba bajtów jest tworzona w HL EX DE,HL i zostaje przeniesiona do DE. RST 0018,GET-CHAR Pobierz obecny znak CP +2C i wróć na początek pętli, jeśli JR Z,2C2E,D-NO-LOOP jest kolejny wymiar. |
Uwaga: W tym punkcie para rejestrów DE wskazuje liczbę bajtów potrzebnych na elementy nowej tablicy, a rozmiar każdego wymiaru jest umieszczany na stosie maszynowym.
Teraz sprawdź, czy rzeczywiście jest nawias zamykający wyrażenie w nawiasach.
CP +29 Czy jest to ')'? JR NZ,2C05,D-REPORT-C Jeśli nie, to skocz wstecz. RST 0020,NEXT-CHAR Zwiększ CH-ADD, aby go minąć. |
Teraz sprawdzane są podane wymiary nowej tablicy.
POP BC Pobierz licznik wymiarów oraz bajt dyskryminatora. LD A,C Przekaż bajt dyskryminatora do rejestru A na później. LD L,B Licznik przenieś do L. LD H,+00 Wyzeruj rejestr H. INC HL Zwiększ liczbę wymiarów o 2 INC HL ADD HL,HL i podwój wynik, a następnie utwórz całkowitą ADD HL,DE długość zmiennej, dodając całkowitą liczbę bajtów. JP C,1F15,REPORT-4 Jeśli trzeba, zgłoś błąd 'Brak pamięci'. PUSH DE Zapamiętaj całkowitą liczbę bajtów dla elementów. PUSH BC Zapamiętaj licznik wymiarów i bajt dyskryminatora. PUSH HL Również zapamiętaj całkowitą długość. LD B,H Przenieś całkowitą długość do BC. LD C,L |
Na końcu obszaru zmiennych zostaje utworzone miejsce na nową tablicę.
LD HL,(E-LINE) Ustaw parę rejestrów HL DEC HL na adres 'bajtu 80'. CALL 1655,MAKE-ROOM Udostępnij to miejsce. INC HL HL zostaje ustawione na adres pierwszej komórki w nowym obszarze. |
Teraz zostają wstawione parametry.
LD (HL),A Najpierw jest wstawiana litera, odpowiednio oznaczona. POP BC Całkowita długość zostaje pobrana DEC BC i zmniejszona o '3'. DEC BC DEC BC INC HL Przesuń do przodu adres w HL. LD (HL),C Wstaw młodszy bajt długości. INC HL Przesuń HL. LD (HL),B Wstaw starszy bajt długości. POP BC Pobierz licznik wymiarów. LD A,B Przenieś go do rejestru A. INC HL Przesuń HL. LD (HL),A Wprowadź licznik wymiarów. |
Elementy nowej tablicy są teraz 'czyszczone'.
LD H,D HL jest ustawiane na LD L,E adres końca tablicy, DEC DE a DE na adres o jedną komórkę niższy. LD (HL),+00 Wstaw zero na ostatnią pozycję, BIT 6,C lecz nadpisz je spacją, JR Z,2C7C,DIM-CLEAR jeśli mamy do czynienia LD (HL),+20 z tablicą łańcuchów. 2C7C DIM-CLEAR POP BC Pobierz całkowitą liczbę bajtów dla elementów tablicy. LDDR Wyczyść tablicę + jedną dodatkową komórkę. |
Teraz zostają wstawione 'rozmiary-wymiarów'.
2C7F DIM-SIZES POP BC Pobierz rozmiar wymiaru. LD (HL),B Wstaw starszy bajt. DEC HL Do tyłu o jeden. LD (HL),C Wstaw młodszy bajt. DEC HL Do tyłu o jeden. DEC A Zmniejsz licznik wymiarów. JR NZ,2C7F,DIM-SIZES Powtarzaj tę operację dla wszystkich wymiarów; RET po czym powróć. |
Ta procedura wraca z ustawionym znacznikiem przeniesienia, jeśli obecna zawartość rejestru A reprezentuje kod cyfry lub litery.
2C88 ALPHANUM CALL 2D1B,NUMERIC Sprawdź, czy mamy cyfrę; przy cyfrze przeniesienie będzie wyzerowane. CCF Neguj przeniesienie. RET C Wróć przy cyfrze, inaczej kontynuuj w 'ALPHA'. |
Ta procedura wraca z ustawionym znacznikiem przeniesienia, jeśli obecna wartość w rejestrze A reprezentuje literę alfabetu.
2C8D ALPHA CP +41 Sprawdź z kodem litery 'A'. CCF Neguj znacznik przeniesienia. RET NC Jeśli zły kod, wróć. CP +5B Sprawdź z kodem litery 'Z'. RET C Jeśli duża litera, wróć. CP +61 Sprawdź z kodem litery 'a'. CCF Neguj znacznik przeniesienia. RET NC Wróć przy złym kodzie znaku. CP +7B Sprawdź z kodem o 1 większym od kodu 'z'. RET Skończone. |
Jako część procesu sprawdzania składni liczby dziesiętne pojawiające się w wierszach języka BASIC są zamieniane na odpowiadające im liczby zmiennoprzecinkowe. Ta procedura czyta liczbę dziesiętną cyfra po cyfrze i daje jej wartość jako 'ostatnią wartość' na stosie kalkulatora. Lecz najpierw zajmuje się alternatywnym zapisem BIN, który wprowadza ciąg zer i jedynek, dając dwójkową reprezentację pożądanej liczby.
2C9B DEC-TO-FP CP +C4 Czy znak to 'BIN'? JR NZ,2CB8,NOT-BIN Skocz, jeśli to nie 'BIN'. LD DE,+0000 Ustaw wynik zero w DE. 2CA2 BIN-DIGIT RST 0020,NEXT-CHAR Pobierz następny znak. SUB +31 Odejmij kod cyfry '1'. ADC A,+00 0 teraz da 0 z ustawionym znacznikiem przeniesienia; 1 daje 0 z wyzerowanym przeniesieniem. JR NZ,2CB3,BIN-END Każdy inny znak powoduje skok do BIN-END, gdzie jest sprawdzana składnia w czasie lub po przeglądnięciu wiersza. EX DE,HL Obecny wynik teraz do HL. CCF Neguj znacznik przeniesienia. ADC HL,HL Przesuń wynik w lewo z przeniesieniem wskakującym na bit 0. JP C,31AD,REPORT-6 Zgłoś błąd przy wyniku większym od 65535. EX DE,HL Zwróć dotychczasowy wynik do DE. JR 2CA2,BIN-DIGIT Skocz wstecz dla następnego 0 lub 1. 2CB3 BIN-END LD B,D Skopiuj wynik do BC dla umieszczenia na stosie. LD C,E JP 2D2B,STACK-BC Skocz naprzód, aby umieścić wynik na stosie. |
Dla pozostałych liczb najpierw zamieniana jest część całkowita; jeśli następnym znakiem jest kropka dziesiętna, to przetworzona zostanie część ułamkowa.
2CB8 NOT-BIN CP +2E Czy pierwszym znakiem jest '.'? JR Z,2CCB,DECIMAL Jeśli tak, to skocz naprzód. CALL 2D3B,INT-TO-FP Inaczej utwórz 'ostatnią wartość' części całkowitej. CP +2E Czy następnym znakiem jest '.'? JR NZ,2CEB,E-FORMAT Skocz naprzód, aby sprawdzić, czy jest to 'E'. RST 0020,NEXT-CHAR Pobierz następny znak. CALL 2D1B,NUMERIC Czy to cyfra? JR C,2CEB,E-FORMAT Skocz, jeśli nie (np. 1.E4 jest dozwolone). JR 2CD5,DEC-STO-1 Skocz naprzód, aby zająć się cyframi po kropce dziesiętnej. 2CCB DECIMAL RST 0020,NEXT-CHAR Jeśli liczba rozpoczęła się od kropki dziesiętnej, CALL 2D1B,NUMERIC to sprawdź, czy następnym znakiem jest cyfra. 2CCF DEC-RPT-C JP C,1C8A,REPORT-C Jeśli nie, zgłoś błąd. RST 0028,FP-CALC Użyj kalkulatora, aby umieścić na stosie zero DEFB +A0,stk-zero jako część całkowitą takich liczb. DEFB +38,end-calc 2CD5 DEC-STO-1 RST 0028,FP-CALC Ponownie użyj kalkulatora. DEFB +A1,stk-one Znajdź postać zmiennoprzecinkową DEFB +C0,st-mem-0 liczby dziesiętnej '1' DEFB +02,delete i zapamiętaj ją w obszarze pamięci. DEFB +38,end-calc 2CDA NXT-DGT-1 RST 0018,GET-CHAR Pobierz obecny znak. CALL 2D22,STK-DIGIT Jeśli to cyfra, to umieść ją na stosie. JR C,2CEB,E-FORMAT Jeśli nie, skocz naprzód. RST 0028,FP-CALC Teraz użyj kalkulatora. DEFB +E0,get-mem-0 Przy każdym obiegu pętli DEFB +A4,stk-ten liczba zapamiętana w obszarze pamięci DEFB +05,division jest pobierana, dzielona przez 10 DEFB +C0,st-mem-0 i zapamiętywana ponownie: tj. idzie od .1 do .01 do .001 itd. DEFN +04,multiply Obecna cyfra jest mnożona DEFB +0F,addition przez 'zapamiętaną liczbę' DEFB +38,end-calc i dodawana do 'ostatniej wartości'. RST 0020,NEXT-CHAR Pobierz następny znak. JR 2CDA,NXT-DGT-1 Skocz wstecz (o jeden bajt za dużo), aby go przetworzyć. |
Następnie zajmij się 'zapisem E', tj. postacią xEm lub xem, gdzie m jest liczbą całkowitą.
2CEB E-FORMAT CP +45 Czy obecny znak to 'E'? JR Z,2CF2,SIGN-FLAG Skocz naprzód, jeśli tak. CP +65 Czy to jest 'e'? RET NZ Zakończ, jeśli nie. 2CF2 SIGN-FLAG LD B,+FF Użyj B jako znacznika znaku, FF dla '+'. RST 0020,NEXT-CHAR Pobierz następny znak. CP +2B Czy jest to '+'? JR Z,2CFE,SIGN-DONE Skocz naprzód. CP +2D Czy jest to '-'? JR NZ,2CFF,ST-E-PART Skocz, jeśli ani '+', ani '-'. INC B Zmień znak znacznika. 2CFE SIGN-DONE RST 0020,NEXT-CHAR Wskaż pierwszą cyfrę. 2CFF ST-E-PART CALL 2D1B,NUMERIC Czy faktycznie to cyfra? JR C,2CCF,DEC-RPT-C Jeśli nie, zgłoś błąd. PUSH BC Tymczasowo zapamiętaj znacznik w B. CALL 2D3B,INT-TO-FP Umieść na stosie ABS m, gdzie m jest wykładnikiem. CALL 2DD5,FP-TO-A Przenieś ABS m do A. POP BC Odtwórz znacznik znaku w B. JP C,31AD,REPORT-6 Zgłoś teraz przepełnienie, jeśli AND A ABS m jest większe od 255 lub większe od 127 JP M,31AD,REPORT-6 (inne wartości większe od 39 zostaną rozpoznane później). INC B Testuj znak w B; '+' (tj. +FF) ustawi teraz znacznik zera. JR Z,2D18,E-FP-JUMP Skocz, jeśli znakiem m jest '+'. NEG Neguj m, jeśli znakiem jest '-'. 2D18 E-FP-JUMP JP 2D4F,E-TOO-FP Skocz, aby przypisać 'ostatniej wartości' wynik x*10^m. |
Ta procedura wraca z wyzerowanym znacznikiem przeniesienia, jeśli wartość w rejestrze A oznacza poprawną cyfrę.
2D1B NUMERIC CP +30 Sprawdź na kod cyfry '0'. RET C Wróć, jeśli niepoprawny znak. CP +3A Sprawdź ponownie z górną granicą. CCF Neguj znacznik przeniesienia. RET Skończone. |
Ta procedura po prostu wraca, jeśli bieżąca wartość przechowywana w rejestrze A nie przedstawia cyfry, jednakże jeśli jest to cyfra, to jej wartość zmiennoprzecinkowa staje się 'ostatnią wartością' na stosie kalkulatora.
2D22 STK-DIGIT CALL 2D1B,NUMERIC Czy znak jest cyfrą? RET C Wróć, jeśli poza zakresem. SUB +30 Zastąp kod przez wartość cyfry. |
Ta procedura umieszcza na stosie kalkulatora zawartość akumulatora traktowaną jako liczbę dodatnią.
2D28 STACK-A LD C,A Przenieś wartość do rejestru C. LD B,+00 Wyzeruj rejestr B. |
Ta procedura umieszcza na stosie kalkulatora liczbę zmiennoprzecinkową odpowiadającą zawartości pary rejestrów BC traktowanej jako dodatnia liczba całkowita.
Postać zmiennoprzecinkowa używana w tym oraz również w dwóch poprzednich
procedurach jest postacią zarezerwowaną w Spectrum dla małych liczb
całkowitych n, gdzie
2D2B STACK-BC LD IY,+5C3A Ponownie ustaw IY na ERR-NR. XOR A Wyzeruj rejestr A LD E,A oraz rejestr E, aby oznaczyć '+'. LD D,C Skopiuj mniej znaczący bajt do D. LD C,B A bardziej znaczący bajt do C. LD B,A Wyzeruj rejestr B. CALL 2AB6,STK-STORE Teraz umieść liczbę na stosie. RST 0028,FP-CALC Ustaw HL na wskazywanie DEFB +38,end-calc STKEND-5. AND A Wyzeruj znacznik przeniesienia. RET Skończone. |
Ta procedura zwraca 'ostatnią wartość' na stosie kalkulatora, która jest wynikiem przekształcenia liczby całkowitej w wierszu języka BASIC, tj. części całkowitej liczby dziesiętnej lub numeru wiersza na jej odpowiednik zmiennoprzecinkowy.
Wywołania do CH-ADD+1 pobierają kolejne cyfry liczby. Wyjście następuje po pobraniu kodu, który nie jest cyfrą.
2D3B INT-TO-FP PUSH AF Zapamiętaj pierwszą cyfrę przechowywaną w A. RST 0028,FP-CALC Użyj kalkulatora. DEFB +A0,stk-zero Teraz 'ostatnia wartość' jest zerem. DEFB +38,end-calc POP AF Odtwórz pierwszą cyfrę. |
Teraz tworzona jest pętla. Dopóki kod przedstawia cyfrę, znajdowana jest jej postać zmiennoprzecinkowa i umieszczana na stosie jako 'ostatnia wartość', którą następnie mnoży się przez 10 i dodaje do 'liczby', otrzymując 'ostatnią wartość, która z kolei jest przenoszona na początek pętli.
2D40 NXT-DGT-2 CALL 2D22,STK-DIGIT Jeśli kod przedstawia cyfrę, to umieść na stosie jej postać zmiennoprzecinkową. RST 0028,FP-CALC Użyj kalkulatora. DEFB +01,exchange 'Cyfra' idzie pod 'ostatnią wartość'. DEFB +A4,stk-ten Umieść na stosie 10. DEFB +04,multiply 'Ostatnia wartość' = 'ostatnia wartość' *10. DEFB +0F,addition 'Ostatnia wartość' = 'ostatnia wartość' + 'cyfra'. DEFB +38,end-calc CALL 0074,CH-ADD+1 Następny kod idzie do A. JR 2D40,NXT-DGT-2 Kontynuuj pętlę z tym kodem. |
Zespół Przedmiotowy Chemii-Fizyki-Informatyki w I Liceum Ogólnokształcącym im. Kazimierza Brodzińskiego w Tarnowie ul. Piłsudskiego 4 ©2024 mgr Jerzy Wałaszek |
Materiały tylko do użytku dydaktycznego. Ich kopiowanie i powielanie jest dozwolone
pod warunkiem podania źródła oraz niepobierania za to pieniędzy.
Pytania proszę przesyłać na adres email:
Serwis wykorzystuje pliki cookies. Jeśli nie chcesz ich otrzymywać, zablokuj je w swojej przeglądarce.
Informacje dodatkowe.