Autor: Daniel Novotný
V tomto dokumentu bych rád popsal interní Basic počítače Sinclair ZX Spectrum.
Basic je programovací jazyk určený zejména pro začátečníky. Jeho jméno je údajně zkratkou z "Begginer's All-purpose Symbolic Instruction Code", ale toto je prý backronym, což znamená, že to, že je název zkratkou bylo vymyšleno až dodatečně. Původní význam jména jazyka je prostě anglické slovo "basic", znamenající "elementární, základní". Nyní se jazyk používá zejména v prostředí Windows, například jako makrojazyk kancelářského balíku MS Office.
Sinclair ZX Spectrum je osmibitový domácí počítač z osmdesátých let, řízený procesorem Z80, disponující 48kB RAM a 16kB ROM. Právě ROM tohoto počítače obsahuje interpret Basicu, o kterém budu hovořit.
Basic na Spectru plní dvě, částečně se prolínající, funkce. Jednak je programovacím jazykem a jednak funguje jako řídící jazyk "operačního systému". Pokud před příkaz napíšeme číslo řádku, bere se jako součást programu, v opačném případě se příkaz spustí ihned - proto Basic Spectra obsahuje příkazy jako "nahraj program z kazety", "spusť program", "zresetuj paměť" a podobně.
Aby se domácí počítač nemusel příliš zatěžovat lexikální analýzou, nejsou příkazy jazyka složeny z jednotlivých znaků, ale jsou kódovány zvlášť (v horních pozicích 128-255, které původní ASCII kód nedefinuje) a vypisují se stisknutím jediné klávesy, případně stiskem přeřaďovače (Symbol shift, Extended mode) a klávesy. Příkazy je nutno zapisovat tímto způsobem, příkaz vypsaný jednotlivými písmeny systém nepřijme. Například příkaz PRINT je vlastně znak s kódem 245 a vypíše se klávesou "P" stisknutou v kontextu zadávání příkazu.
Obecně je vždy řádek programu ve tvaru <číslo řádku> <příkaz> <parametry>. Číslo řádku je v tomto dialektu BASICu povinné, doporučuje se nečíslovat řádky 1,2,3... ale po pěti (5,10,15...) či po deseti - a to z toho důvodu, abyste mohli mezi dva programové řádky vložit řádek další bez nutnosti přečíslování celého programu. Parametry příkazu se většinou oddělují čárkami, ale ne vždy: některé příkazy mají složitější syntaxi, například PRINT nebo FOR.
Základní datové typy jsou pouze dva: číslo a řetězec.
Čísla jsou všechna v pohyblivé řádové čárce, proměnné se nerozlišují na
celočíselné a reálné. Číselné konstanty se zapisují tak, jak je zvykem ve
většině programovacích jazyků, je možno použít i vědeckou notaci - např. 2.5e3
je 2500. Na čísla se dají aplikovat běžné aritmetické operace +,-,*,/ , šipka
nahoru slouží pro mocninu, další aritmetické funkce viz níže.
Řetězce se zapisují do uvozovek, jejich velikost je omezena pouze pamětí
počítače. Je možno je spojovat (řetězit) operátorem +, další funkce včetně pro
Spectrum unikátního adresování částí řetězce budou uvedeny níže.
Jedinou složitější datovou strukturou je pole - tím se budeme zabývat
později.
Proměnné mohou být buď číselné nebo řetězcové. Nemusí (ani nedají) se
deklarovat, systém je deklaruje automaticky při jejich prvním použití v
přiřazovacím příkazu (LET, INPUT, READ). Pokud se v programu objeví použití
proměnné bez této automaticky proběhlé deklarace (tedy např. v příkazu PRINT),
vede to k chybě Variable not found.
Jména číselných proměnných se skládají z libovolného počtu čísel a
písmen, první musí být písmeno. V tomto Spectrum "boduje" nad jinými
"konkurenčními" mikropočítači - umožňuje jako identifikátory proměnných celá
slova, zatímco ostatní soudobé srovnatelné systémy nabízely většinou pouze jedno písmeno a číslici.
Naproti tomu jména řetězcových proměnných se skládají pouze z jednoho
písmena a znaku $. Tento znak se používá i k označení funkcí
vracejících řetězce - viz níže. Z uvedeného vyplývá, že řetězcových proměnných
může být v programu maximálně 26.
Na velikosti písmen ve jménech proměnných nezáleží.
Příkazů je velká řada. Postupně si probereme nejdůležitější z nich.
Příkaz PRINT slouží k výstupu na obrazovku. Ukážeme vám v klasickém programu "Hello, world" jeho základní podobu:
10 PRINT "Hello, world!"
Další základní příkazy jsou INPUT pro vstup řetězce/čísla, přiřazovací příkaz LET a příkaz REM, který slouží pro poznámky - počítač jej ignoruje:
10 REM zakladni aritmetika 20 INPUT "Zadej prvni cislo: ";a 30 INPUT "Zadej druhe cislo: ";b 40 LET c=a+b 50 PRINT "Vysledny soucet: ";c
Vidíme, že u příkazu INPUT můžeme použít i jakýsi "prompt" - legendu pro uživatele, aby věděl, co má vlastně zadávat. Položky INPUTu a PRINTu je možno oddělovat středníkem (pak budou na sebe těsně "nalepené"), čárkou (vzdálenost půl řádku) či apostrofem (každá na nový řádek).
Řídící struktury jsou v BASICu následující: podmínkový příkaz
IF, cyklus FOR, příkaz GOTO a "podprogramové" příkazy GO SUB a RETURN.
Příkaz GOTO má jako parametr číselný výraz určující číslo řádku,
na které počítač skočí. Narozdíl od "konkurenčních" mikropočítačů této
doby, které uznávaly pouze tvar GOTO číslo, na Spectru bylo možno použít
i GOTO proměnná, nebo třeba GOTO proměnná*100...
Díky absenci některých struktur (WHILE cyklu, ELSE...) je tolik diskutovaný
a haněný příkaz GOTO nutno používat. To může vést k nepřehlednému programu,
"špagetovému kódu".
Příkaz IF má syntaxi IF podmínka THEN příkaz.
Podmínka se může skládat z relačních operátorů (větší než, rovno...), případně
spojených logickými operátory AND, OR, NOT. Řetězce lze nejen testovat na
rovnost, ale i lexikograficky porovnávat.
Dvě připomínky: THEN nemůžeme vypsat z klávesnice, ale musíme jej napsat
"naráz" jako Symbol shift + G, toto se týká i ostatních "vícesložkových"
příkazů, stejně jako operátorů AND, OR, >= atd. A za druhé: v příkazu
po THEN můžeme využít znaku :, který slouží k napsání více příkazů za
sebou - pro všechny pak bude platit podmínka IF. Příkaz ELSE zde není, ale dá se
nahradit právě skládáním příkazů s využitím příkazu GOTO:
100 IF vek>=18 THEN PRINT "Muzu nalit alkohol." : GOTO 120 110 PRINT "Smula, mladej." 120 REM zde program pokracuje
Cyklus FOR je ve tvaru FOR i=číslo1 TO číslo2 STEP krok . Čítač příkazu FOR je číselná proměnná, postupně probíhá hodnoty od čísla1 k číslu2, při každé iteraci se proměnná zvýší o krok. STEP je nepovinný, při neuvedení je rovný jedné. Konec iterace se označuje příkazem NEXT i, kde i je proměnná daného cyklu FOR. Příkládek:
10 FOR i=1 TO 9 20 FOR j=1 TO i 30 PRINT j; 40 NEXT j 50 PRINT 60 NEXT i
Zde vidíme nové vlastnosti příkazu PRINT - pokud končíme středníkem, znamená to "neukončuj řádek", naopak samotný PRINT bez parametrů nám pouze odřádkuje. Basicový způsob "cyklení" je poněkud nerobustní: stačí splést NEXT i a NEXT j a máme sémantickou chybu...
Příkazy GO SUB číslo řádku a RETURN nám umožňují vytvářet podprogramy - GO SUB nám skočí na řádek s daným číslem (které může být rovněž vypočítáno výrazem) a uloží do zásobníku, kam se má program nazpět vrátit. RETURN naopak vybere ze zásobníku číslo řádku, které tam uložilo předchozí GO SUB a skočí na něj. Příklad (nic lepšího mě nenapadlo...):
5 REM promennou "a" pouzijeme jako parametr 10 LET a=3 20 GO SUB 1000 30 LET a=6 40 GO SUB 1000 45 INPUT "Zadej pocet:"; a 50 GO SUB 1000 60 GOTO 2000 900 REM konec hlavniho programu, zacatek podprogramu 1000 FOR i=1 TO a 1010 PRINT "ha "; 1020 NEXT i 1030 PRINT 1040 RETURN 2000 REM konec programu
Dalším přiřazovacím příkazem je READ, používá se spolu s příkazy DATA a RESTORE. Řádek označený DATA obsahuje skladiště dat - čárkou oddělená čísla a řetězce, která tvoří jakýsi "datový soubor", z něhož READ postupně čte a přiřazuje. Příkaz RESTORE obnoví již přečtená DATA tak, že následující READ je čte znovu od začátku. Následující příklad jsem převzal z knížky "Jak se domluvíme s počítačem" - zkuste bez spuštění vyčíst, co vám vypíše:
10 REM albatros 15 FOR p=1 TO 8 20 FOR q=1 TO p 25 READ a$ 30 PRINT a$; 35 NEXT q 40 PRINT 42 RESTORE 45 NEXT p 50 FOR m=1 TO 8 55 FOR n=1 TO m 60 READ x$ 62 PRINT " "; 65 NEXT n 70 FOR o=m+1 TO 8 75 READ a$ 80 PRINT a$; 85 NEXT o 90 PRINT 92 RESTORE 95 NEXT m 100 DATA "A","L","B","A","T","R","O","S"
Pole se alokují příkazem DIM. Mohou být vícerozměrná, název pole je jednoznakový. Indexy se píší v kulatých závorkách, začínají od jedničky - narozdíl např. od jazyka C. Pole řetězců se alokují speciálním způsobem: poslední "rozměr" není rozměr, ale délka jednoho řetězce daného pole. Prvek pole řetězců je pak vždy takhle dlouhý, doplňuje se mezerami nebo ořezává. Toto zacházení s poli řetězců je specialita ZX Spectra. Příklady:
5 REM alokace: 10 DIM a(100) 15 REM prirazeni: 20 LET a(1)=42 25 REM ok, vypise nulu: 30 PRINT a(100) 35 REM hodi chybu - mimo meze: 40 PRINT a(101) 45 REM dtto - nulty prvek neexistuje: 50 PRINT a(0) 55 REM trojrozmerne pole: 60 DIM b(10,10,10) 65 REM pole 6x6 desetiznakovych stringu: 70 DIM x$(6,6,10) 75 REM alokuje retezec fixni delky 7 znaku: 80 DIM f$(7)
Nyní bych zmínil funkce pro práci s čísly a řetězci. Kvůli snaze o relativní stručnost tohoto článku je uvedu tabulkou. Uvádím i počet a typ parametrů. Návratový typ funkce se pozná podle toho, že funkcím vracející řetězec vždy končí název písmenem $.
funkce | význam |
---|---|
SIN a | trigonometrická funkce (i COS, TAN atd.) |
ABS a | absolutní hodnota. |
LN a | přirozený logaritmus |
SQR a | druhá odmocnina (pozor! V Pascalu je sqr druhá mocnina a druhá odmocnina je sqrt) |
INT a | celá část reálného čísla (zaokrouhluje vždy dolů) |
SGN a | -1 pro záporná čísla, 1 pro kladná, 0 pro nulu |
PI | číslo pí |
RND | pseudonáhodné reálné číslo mezi 0 a 1 |
LEN a$ | délka řetězce |
STR$ a | konverze čísla na řetězec obsahující toto číslo |
VAL a$ | konverze čísla/výrazu zapsaného v řetězci na číslo (opak STR$) |
CHR$ a | znak s ASCII kódem a (jednoznakový řetězec) |
CODE a$ | ASCII kód prvního znaku a$ (opak CHR$) |
Na Spectru se nepoužívají ke "krájení" řetězců řetězcové funkce LEFT$, RIGHT$ a MID$ jako v jiných dialektech Basicu. Místo toho se používá indexování: a$(3 TO 5) je třetí až pátý znak a$, a$(8 TO) osmý až poslední, a$(7) pouze sedmý znak atd. Do těchto výrazů lze i přiřazovat. Řetězec se nebude zkracovat ani natahovat - v případě neshodné délky se doplní mezerami respektive se konec přiřazovaného usekne.
Generátor náhodných čísel RND se inicializuje příkazem RANDOMIZE, který vezme "seed" ze systémového časovače. Je také možnost inicializovat sekvenci pevným číslem příkazem RANDOMIZE číslo
Příkladů na funkce jistě spoustu vymyslíte sami - uvedu třeba program realizující jednoduchou kalkulačku, ve které můžete používat právě i funkce Spectrum Basicu - nesmíte je však vypsat po písmenech, ale "vcelku" stiskem příslušného tlačítka. Za řádkem 20 lze implementovat další interní příkazy kalkulačky kromě "quit", zbytek výrazů se prostě předá interpretu Basicu.
5 REM klauzule LINE umozni lepsi vstup retezce - neobjevuji se uvozovky 6 REM obvykle se objevujici po INPUT a$ 10 INPUT "kalkulacka>"; LINE a$ 20 IF a$ = "quit" THEN GOTO 50 30 PRINT VAL a$ 40 GOTO 10 50 REM konec programu
Pomocí příkazu DEF FN lze definovat vlastní uživatelské funkce, s jednopísmenným názvem a libovolným rozumným počtem parametrů. Funkce vracející řetězec končí název znakem $. Například:
10 REM zaokrouhleni na cele 20 DEF FN z(x) = INT (x+0.5) 30 REM maximum dvou cisel 40 DEF FN m(a,b) = ( a+b+ABS(a-b) )/2 50 REM nahodne cislo od nuly do n-1 60 DEF FN r(n) = INT (RND * n) 50 REM funkce "LEFT$" jiných dialektu 60 DEF FN l$(a$,n) = a$( TO n) 70 REM priklad volani takovychto fci 80 LET a = FN r(100) 90 LET a$ = FN l$("foobar",3)
Pro práci s kazetovým magnetofonem slouží příkazy LOAD "název programu", SAVE "název programu". Příkaz LOAD "" načte první nalezený program na kazetě. Existuje též "vychytávka" SAVE "program" LINE . Takto uložený program se po nahrání z kazety automaticky spustí - není třeba zadávat RUN.
Nyní něco napíšu o "multimediálních" možnostech Spectráckých programů, tedy schopnosti dělat něco více než řádkový vstup a výstup.
Za prvé - příkaz PRINT lze doplnit o klauzuli AT označující, na kterou pozici obrazovky se bude tisknout. Opak dělá funkce SCREEN$(x,y), která vrátí znak na souřadnicích (x,y) - a to pouze jestli tam skutečně je znak a ne například jemná grafika - pak vrátí prázdný řetězec. Pěkný příklad na AT, CHR$ a RND:
3 RANDOMIZE 5 REM nahodny zobrazitelny znak 10 LET a$ = CHR$ (32 + INT ( RND * (128-32) ) ) 15 REM nahoda v rozmezich obrazovky 20 LET x = INT ( RND * 22 ) 30 LET y = INT ( RND * 32 ) 35 REM vypis to 40 PRINT AT x,y ; a$ 50 GOTO 10
Za druhé - jemná grafika se kreslí příkazy PLOT, DRAW a CIRCLE. PLOT x,y nakreslí bod o souřadnicích (x,y) . DRAW x,y nakreslí úsečku od minulého PLOTu či DRAWu na nové souřadnice, posunuté o x a y - souřadnice DRAW se totiž nepočítají absolutně vzhledem k bodu (0,0) obrazovky, ale relativně vzhledem k bodu kam se naposledy kreslilo - mohou tedy být i záporné. Následující příklad (takový "šetřič obrazovky") proto musí absolutní souřadnice přepočítávat na relativní. Borland Pascal toto řeší o něco lépe - má dvě funkce line a lineRel, takže se každý může rozhodnout zda kreslit čáru "absolutně" či "relativně".
5 RANDOMIZE 6 REM pocatecni bod 10 LET x1=INT(RND*256) 20 LET y1=INT(RND*176) 25 REM konecny bod 30 LET x2=INT(RND*256) 40 LET y2=INT(RND*176) 45 REM uprava absolutnich souradnic na relativni 50 LET x2=x2-x1 60 LET y2=y2-y1 70 PLOT x1,y1 80 DRAW x2,y2 90 GOTO 10Nyní vám doplním znalosti k tomu, abych tu mohl uvést jeden z vůbec prvních programů, které jsem na Spectru kdysi coby dítě školou povinné napsal. CLS maže obrazovku, PAPER a INK určují barvičky "podkladu" a písma/kresby, CIRCLE je kružnice. V programu obratně využívám zaokrouhlovacích chyb při kreslení kružnice. "Animace" znázorňuje hvězdnou noc a přílet UFO.
10 PAPER 0 : INK 7 : CLS 15 REM hvezdy: 20 FOR i=1 TO 50 30 PLOT INT (RND*256), INT (RND*176) 40 NEXT i 45 REM ufo: 50 INK 3 60 FOR i=1 TO 40 70 CIRCLE 128,88,i 80 NEXT i
Bohužel barvy se neváží k jednotlivým pixelům, ale k oblasti 8x8 pixelů (velikost jednoho znaku), což si můžeme ověřit následujícím jednoduchým prográmkem:
10 INK INT (RND*8) 20 PLOT INT (RND*256), INT (RND*176) 30 GOTO 10
Další příkazy a funkce využitelné např. v počítačových hrách jsou tyto:
Na závěr: pokud vám nestačí možnosti Basicu, můžete využít funkci PEEK adresa pro čtení z paměti, příkaz POKE adresa,bajt pro zápis do paměti a analogickou funkci IN a příkaz OUT pro práci s porty. Pokud se vám povede do paměti "nacpat" program ve strojovém kódu, spustíte ho GOTO USR (adresa). Ale tyto věci jsou již nad rámec tohoto článku a Basicu vůbec.
To je ode mě všechno, doufám, že si nyní se svými emulátory užijete nejenom hraní her, ale i trochu toho spectráckého programování...
Použitá literatura:
Stránka byla už zobrazena: 165 ×
Aktualizováno: 2. 5. 2018, 18:13
Stránka načtena za 0.00185 sekund.