Príručka jazyka Action! pre 8-bitové počítače Atari, písaná pre ľudí, ktorí s Atari ani s Action! nikdy nerobili a programujú málo alebo vôbec. Programy sa píšu na dnešnom počítači s Windows, preloží ich prekladač action26 a bežia na Atari alebo v jeho emulátore.
Každá kapitola vysvetlí jeden príkaz alebo jednu tému a obsahuje celý program, ktorý si môžeš hneď preložiť a spustiť. Všetky programy sú aj hotové v priečinku examples/.
Predlohou je pôvodný manuál Action! od Optimized Systems Software. Časti o editore a monitore cartridge tu nie sú – action26 ich nepotrebuje.
Čítaj od začiatku. Kapitoly sú krátke a každá stavia na predošlých. Program z kapitoly si prelož, spusti a potom v ňom niečo zmeň – časť Vyskúšaj si na konci kapitoly dáva nápady.
Kapitoly 1 až 31 platia aj pre pôvodný Action! na Atari. Kapitoly 32 až 42 sú o tom, čo vie action26 navyše.
voľby príkazového riadka, simulátor, výpisy, nečitateľný súbor (--scramble, silnejšie --scramble-level 2) a efekty pri štarte, zbalený súbor (--pack-xex, aj zakódovaný)
Atari 800XL a 130XE sú domáce počítače z osemdesiatych rokov. Majú procesor 6502, 64 alebo 128 kilobajtov pamäte a pripájali sa k televízoru. Po zapnutí na nich nebeží žiadny Windows – počítač čaká, kým mu dáš program z kazety, z diskety alebo zo zásuvného modulu (cartridge).
Dnes tie počítače stále fungujú a kto ich nemá, používa emulátor: program, ktorý sa na dnešnom počítači správa ako Atari.
Action! je programovací jazyk, ktorý pre Atari v roku 1983 vydala firma Optimized Systems Software. Predával sa ako cartridge. Stal sa obľúbeným, lebo programy v ňom sú skoro také rýchle ako programy písané priamo v strojovom kóde, a pritom sa čítajú ako obyčajný text:
Action!
PROCMain()
PrintE("Hello, Atari!")
RETURN
Ak poznáš Pascal alebo C, veľa vecí ti bude povedomých. Ak nepoznáš nič, nevadí – táto kniha začína od nuly.
Pôvodný Action! bežal priamo na Atari: písalo sa na jeho klávesnici a prekladalo sa na ňom. action26 je prekladač toho istého jazyka, ktorý beží na počítači s Windows.
Program píšeš v ľubovoľnom textovom editore (Poznámkový blok, Visual Studio Code, Sublime Text …).
action26 ho preloží za zlomok sekundy.
Výsledok je súbor, ktorý sa dá spustiť na Atari alebo v emulátore.
Jazyk je ten istý. Program z tejto knihy preloží aj pôvodný Action! (okrem kapitol 35 až 42, ktoré ukazujú, čo vie action26 navyše).
Súbor action26.exe. Je to jeden súbor, nič sa neinštaluje. Skopíruj si ho do priečinka, kde budeš mať svoje programy, alebo do priečinka, ktorý máš v systémovej ceste (PATH) – potom ho môžeš volať odkiaľkoľvek.
Textový editor. Stačí Poznámkový blok. Pohodlnejší je editor, ktorý čísluje riadky, lebo prekladač hlási chyby číslom riadka.
Príkazový riadok – okno, do ktorého sa píšu príkazy. Vo Windows je to Terminál alebo PowerShell (nájdeš ho v ponuke Štart).
Na kapitoly o grafike, zvuku a joysticku navyše:
Emulátor atari800 v priečinku atari800 vedľa action26.exe. Do kapitoly 26 ho nepotrebuješ. Emulátor potrebuje operačný systém Atari ako súbor ROM (ATARIXL.ROM vedľa atari800.exe). Namiesto neho poslúži aj voľná náhrada AltirraOS od Averyho Leeho – knižnica action26 volá operačný systém len cez jeho oficiálne vstupné body, takže s ňou funguje rovnako. Keď vedľa emulátora ATARIXL.ROM nie je a action26 nájde súbor external\Altirra\altirraos-xl.rom, použije pri --run sám AltirraOS.
Na prvom riadku je číslo verzie; posledné číslo (revízia) sa s každou novou verziou zväčšuje.
Ak namiesto toho príde hlásenie, že príkaz action26 nie je známy, príkazový riadok nevie, kde action26.exe leží. Najjednoduchšia náprava: prejdi v príkazovom riadku do priečinka, kde ten súbor máš, a píš .\action26 namiesto action26.
Prejdeš celú cestu od prázdneho súboru po bežiaci program: napísať, uložiť, preložiť, spustiť. Všetky ďalšie kapitoly robia to isté, len s inými príkazmi.
Riadok, ktorý začína bodkočiarkou, je komentár. Prekladač ho preskočí. Je to poznámka pre človeka.
Action!
PROCMain()
PROC začína procedúru – pomenovaný kus programu. Táto sa volá Main. Prázdne zátvorky hovoria, že procedúra nedostáva žiadne údaje. Meno si môžeš zvoliť sám; Main (anglicky „hlavná“) je zvyk.
Action!
PrintE("Hello, Atari!")
PrintE je hotová rutina z knižnice: vypíše text v zátvorkách a prejde na nový riadok. Text sa píše do úvodzoviek.
Action!
RETURN
RETURN končí procedúru. Keďže Main je jediná procedúra, končí tým aj celý program.
Medzery na začiatku riadka nie sú povinné. Píšu sa preto, aby bolo vidieť, čo patrí dovnútra procedúry.
Po preklade pribudol vedľa zdrojáka súbor hello.xex. To je hotový program pre Atari – má 277 bajtov. Dá sa skopírovať na disketu alebo spustiť v emulátore.
Keď chceš program len preložiť a nespúšťať, voľbu --sim vynechaj:
Bash
action26hello.act
Keď sa preklad podarí, prekladač nevypíše nič. Ticho znamená „v poriadku“.
Simulátor ukáže len to, čo program vypíše. Emulátor ukáže celé Atari. Ak ho máš (priečinok atari800 vedľa action26.exe), spustíš program takto:
Bash
action26hello.act--run
Tento program však skončí hneď po výpise a Atari po skončení programu ukáže svoju vlastnú obrazovku, takže text nestihneš prečítať. Preto sa do programov pre emulátor na koniec pridáva čakanie na kláves (examples/hello-key.act):
Action!
; Hello for the emulator: it waits for a key before it endsPROCMain()
PrintE("Hello, Atari!")
PutE()
Print("Press any key")
GetD(7)
RETURN
Bash
action26hello-key.act--run
GetD(7) čaká, kým na klávesnici Atari stlačíš kláves. Čo presne znamená sedmička, vysvetlí kapitola 30; zatiaľ ber GetD(7) ako „počkaj na kláves“.
Veľké a malé písmená prekladač nerozlišuje: PrintE, printe aj PRINTE je to isté. V knihe sú slová jazyka veľkými písmenami (PROC, RETURN) a mená rutín s veľkým začiatočným písmenom, aby sa program dobre čítal.
; Three routines. The program starts in the last one.PROCLine()
PrintE("--------------------")
RETURNPROCGreet()
PrintE("Good morning!") ; a comment may follow a statementRETURNPROCMain()
Line()
Greet()
Greet()
Line()
RETURN
Program začína v poslednej procedúre. To je pravidlo Action! – nezáleží na mene, ale na poradí. Tu je posledná Main, takže program začne v nej.
Main postupne zavolá Line(), dvakrát Greet() a znova Line(). Pri každom volaní program odskočí do volanej procedúry, vykoná jej príkazy a po RETURN pokračuje za volaním.
Keď RETURN vykoná posledná procedúra (tá, v ktorej program začal), program končí.
Procedúra musí byť napísaná skôr, než ju niekto zavolá. Prekladač číta súbor zhora nadol a meno, ktoré ešte nevidel, nepozná. Preto sú pomocné procedúry hore a Main dole.
error ACT007: invalid argument list: expected '(' after the routine name
chýbajú zátvorky pri volaní (Greet namiesto Greet())
error ACT010: illegal assignment: expected '=', '==' or '(' after 'Greet'
dve procedúry majú rovnaké meno
error ACT006: 'Greet' is already declared
Chýbajúci RETURN prekladač nehlási. Procedúra bez RETURN neskončí a program pokračuje príkazmi nasledujúcej procedúry, čo skoro nikdy nechceš. Keby v tomto programe chýbal RETURN za Greet, program by z Greet „prepadol“ do Main, tá by znova zavolala Greet – a Good morning! by sa vypisovalo donekonečna. Na konci každej procedúry preto píš RETURN.
Program, ktorý nič nevypíše, nevieš skontrolovať. Rutiny na výpis preto potrebuješ v každej kapitole. Sú súčasťou knižnice – netreba ich deklarovať, stačí ich zavolať.
; Writing texts, characters and numbersPROCMain()
Print("One ") ; a text, the cursor stays on the linePrint("line.")
PutE() ; the end of the linePrintE("A line of its own.")
Put('A) ; one characterPut('B)
Put('C)
PutE()
Print("A small number: ")
PrintBE(200) ; BYTE: 0 to 255Print("A big number: ")
PrintCE(50000) ; CARD: 0 to 65535Print("A number below zero: ")
PrintIE(-150) ; INT: -32768 to 32767PrintB(1) Put(' ) PrintB(2) Put(' ) PrintB(3)
PutE()
RETURN
warning ACT215: value 300 does not fit into a BYTE a vypíše sa 44
znak s apostrofom aj za ním (Put('A'))
error ACT018: unmatched parentheses – druhý apostrof začal nový znak )
text v Put (Put("A"))
prekladač mlčí, program vypíše nezmysel
číslo v PrintE (PrintE(5))
prekladač mlčí, program vypíše nezmysel
Posledné dva riadky stoja za zapamätanie: Action! nekontroluje, či rutine dávaš to, čo čaká. Text patrí do Print, znak do Put, číslo do PrintB, PrintC alebo PrintI. Keď program vypíše niečo čudné, pozri najprv, či si nepomiešal tieto rutiny.
Odkiaľ sa vzalo 44? Do BYTE sa zmestí 256 hodnôt (0 až 255). 300 je o 44 viac ako 256, a práve ten zvyšok ostane.
V desiatkovej sústave máš desať číslic (0–9) a ďalšie miesto znamená desaťnásobok. V šestnástkovej je číslic šestnásť: 0 1 2 3 4 5 6 7 8 9 A B C D E F, kde A je desať a F pätnásť. Ďalšie miesto znamená šestnásťnásobok.
Šestnástkovo
Výpočet
Desiatkovo
$0A
10
10
$10
1 × 16 + 0
16
$41
4 × 16 + 1
65
$FF
15 × 16 + 15
255
$FFFF
65535
Prečo sa to používa: dve šestnástkové číslice sú presne jeden bajt (0 až 255) a adresy v pamäti Atari sa v knihách a časopisoch píšu takmer vždy takto. Počítať v nej nemusíš – stačí vedieť, že $41 a 65 je to isté číslo.
Počítač si znaky pamätá ako čísla – každý znak má svoj kód. Písmeno A má kód 65, B 66, medzera 32, číslica 0 48. Zápis 'A je teda len pohodlnejší spôsob, ako napísať 65.
Atari používa vlastnú tabuľku kódov, ATASCII. Pre písmená, číslice a bežné znamienka je rovnaká ako ASCII na dnešných počítačoch. Tabuľka je v prílohe D.
; The four ways to write a valuePROCMain()
Print("Decimal 65: ")
PrintBE(65)
Print("Hexadecimal $41: ")
PrintBE($41) ; the same number, written in base 16Print("Character 'A: ")
PrintBE('A) ; a character is a number too - its codePrint("Put(65): ")
Put(65) ; and a number can be written as a characterPutE()
Print("$FFFF: ")
PrintCE($FFFF) ; the biggest CARDPrintE("A text with ""quotes"" inside.")
RETURN
Premenná je pomenované miesto v pamäti, do ktorého si program odloží hodnotu, aby ju mohol neskôr použiť alebo zmeniť. Bez premenných by program vedel len vypisovať to, čo máš napísané v zdrojáku.
Premennú treba najprv deklarovať – povedať, ako sa volá a aký druh hodnoty v nej bude:
Action!
BYTEageCARDyear, score; viac premenných toho istého typu, oddelené čiarkouINTtemperatureCHARgradeBYTElives=[3] ; premenná, ktorá má hodnotu hneď od začiatku
Druh hodnoty sa volá typ. Action! má štyri základné:
Typ
Veľkosť v pamäti
Aké hodnoty
Na čo sa hodí
BYTE
1 bajt
0 až 255
malé čísla: vek, počet životov, súradnica na obrazovke
CHAR
1 bajt
0 až 255
jeden znak; je to to isté ako BYTE, len meno hovorí, že ide o znak
CARD
2 bajty
0 až 65535
väčšie čísla bez znamienka: rok, skóre, adresa
INT
2 bajty
−32768 až 32767
čísla, ktoré môžu byť záporné
CARD je skratka z cardinal (číslo bez znamienka), INT z integer (celé číslo).
Hodnotu do premennej vloží priradenie: meno=hodnota.
Deklarácie patria na začiatok procedúry, pred prvý príkaz.
; Variables of the four basic typesPROCMain()
BYTEage; 0 to 255CARDyear; 0 to 65535INTtemperature; -32768 to 32767CHARgrade; one characterBYTElives=[3] ; a variable with a value from the startage=12year=1983temperature=-5grade='APrint("Age: ") PrintBE(age)
Print("Year: ") PrintCE(year)
Print("Temperature: ") PrintIE(temperature)
Print("Grade: ") Put(grade) PutE()
Print("Lives: ") PrintBE(lives)
age=13; a variable can changePrint("Next year: ") PrintBE(age)
RETURN
premenná nie je deklarovaná, alebo je v mene preklep
error ACT008: undeclared name 'ag'
deklarácia až za príkazom
error ACT006: declaration error: declarations must come before the statements
chýba čiarka medzi menami (BYTE a b)
chyba na prvom príkaze, ktorý premennú použije
hodnota sa do typu nezmestí (age=300)
warning ACT215: value 300 does not fit into a BYTE; v premennej bude 44
INT t a t=40000
prekladač mlčí; v premennej bude −25536
BYTE lives=3 bez hranatých zátvoriek
prekladač mlčí – a je to niečo celkom iné
Posledný riadok je najzákernejší. BYTE lives=3nedá premennej hodnotu 3. Znamená „premenná lives leží v pamäti na adrese 3“. Na to sa hodí pri práci s pamäťou počítača (kapitola 24), ale začiatočník tým prepíše niečo, čo patrí systému. Počiatočná hodnota sa píše vždy do hranatých zátvoriek: BYTE lives=[3].
Premenná, ktorej si nič nepriradil, má po nahraní programu hodnotu 0. Nespoliehaj sa na to – keď program spustíš druhýkrát bez nového nahrania, ostane v nej to, čo tam bolo naposledy.
Program počíta: sčíta skóre, zistí, koľko ostáva životov, prepočíta súradnice. Zápis výpočtu sa volá výraz a jeho výsledok sa zvyčajne uloží do premennej.
Znak = tu neznamená „rovná sa“ ako v matematike. Znamená „vypočítaj to, čo je vpravo, a ulož to do premennej vľavo“. Preto dáva zmysel aj x=x+1: zober x, pripočítaj 1 a ulož späť do x.
Operátor
Význam
Príklad
Výsledok
+
sčítanie
17+5
22
-
odčítanie
17-5
12
*
násobenie
17*5
85
/
delenie bez zvyšku
17/5
3
MOD
zvyšok po delení
17 MOD 5
2
( )
zátvorky – počíta sa najprv to, čo je v nich
(2+3)*4
20
Poradie: najprv zátvorky, potom *, / a MOD, nakoniec + a -. Operátory rovnakej sily sa počítajú zľava doprava.
1. Typ výsledku určujú typy vo výraze, nie premenná, do ktorej ukladáš.
diff=b-a počíta 5 − 17. Obe premenné sú BYTE, preto sa aj výsledok počíta ako BYTE – a ten záporný byť nemôže. Vyjde 244 a až táto hodnota sa uloží do diff. To, že diff je INT, už nepomôže.
V druhom výpočte sú x a y typu INT, výsledok je INT a vyjde správnych −12.
Pravidlo:
Vo výraze je
Výsledok je
len BYTE
BYTE
BYTE a INT, alebo len INT
INT
aspoň jeden CARD
CARD
Keď výsledok môže vyjsť mimo 0 až 255, musí byť aspoň jedna premenná vo výraze väčšieho typu.
2. Pretečenie sa nehlási.
small=250 a small=small+10 dá 4, nie 260. BYTE má len 256 hodnôt a po 255 nasleduje znova 0 – ako počítadlo kilometrov, ktoré sa pretočí. Program nezastane ani nič nevypíše. Rovnako pretečie CARD za 65535 a INT za 32767.
Doteraz program vedel len to, čo si mu napísal do zdrojáka. Rutiny vstupu počkajú, kým používateľ niečo napíše na klávesnici a stlačí RETURN (Enter), a napísanú hodnotu odovzdajú programu.
Prvé tri sú funkcie: vrátia hodnotu a tú priradíš do premennej. Písmená B, C, I znamenajú zase BYTE, CARD, INT.
InputS je procedúra: text uloží do premennej, ktorú jej dáš v zátvorkách. Na text nestačí BYTE ani CARD – treba miesto pre viac znakov:
Action!
CHARARRAYname(40)
To je pole znakov s miestom pre 40 bajtov: jeden si Action! vezme na dĺžku textu, ostane 39 znakov. Poliam a reťazcom sa venujú kapitoly 18 a 19; tu stačí vedieť, že takto sa deklaruje premenná na text a že sa dá vypísať cez Print(name).
; A program that asksPROCMain()
CHARARRAYname(40) ; room for a text of up to 39 charactersBYTEageCARDyearPrint("What is your name? ")
InputS(name)
Print("How old are you? ")
age=InputB()
Print("What year is it? ")
year=InputC()
PutE()
Print("Hello, ")
Print(name)
PrintE("!")
Print("You were born in ")
PrintC(year-age)
PrintE(" or the year before.")
RETURN
Print("What is your name? ") vypíše otázku a nechá kurzor na riadku, aby sa odpoveď písala hneď za ňu. Preto tu nie je PrintE.
InputS(name) počká na riadok textu a uloží ho do name.
age=InputB() počká na riadok, prevedie ho na číslo a uloží do age. Prázdne zátvorky za InputB sú povinné – je to volanie funkcie.
PrintC(year-age) ukazuje, že do zátvoriek rutiny nemusí ísť len premenná: môže tam byť celý výraz. year je CARD, takže výsledok je CARD a patrí do PrintC.
používateľ napíše písmená tam, kde program čaká číslo
funkcia vráti 0
číslo sa nezmestí (300 do InputB)
vráti zvyšok, 44 – ako pri priradení
chýbajú zátvorky (age=InputB)
prekladač mlčí; do age sa uloží kus adresy rutiny, nie odpoveď
text je dlhší ako miesto v poli
program si prepíše vlastnú pamäť a zvyčajne spadne
Rutiny vstupu nekontrolujú, čo používateľ napísal. Číselný vstup číta číslice, kým nenarazí na iný znak: 12abc dá 12, abc dá 0.
Pole na text rob radšej väčšie. Riadok na obrazovke Atari má 40 znakov, ale používateľ môže písať ďalej – jeden vstup môže mať až 120 znakov. Kto chce mať istotu, použije CHAR ARRAY name(121).
; DecisionsPROCMain()
BYTEagePrint("How old are you? ")
age=InputB()
PutE()
IFage<6THENPrintE("You do not go to school yet.")
ELSEIFage<15THENPrintE("You go to primary school.")
ELSEIFage<19THENPrintE("You go to secondary school.")
ELSEPrintE("You are grown up.")
FIIFage>=13ANDage<=19THENPrintE("You are a teenager.")
FIIFage=0ORage>120THENPrintE("Is that really your age?")
FIIFage#18THENPrintE("You are not 18.")
FIRETURN
Prvý IF je reťaz. Podmienky sa skúšajú zhora nadol a vykoná sa len prvá vetva, ktorá platí. Pri veku 14 neplatí age<6, platí age<15 – vypíše sa „primary school“ a ostatné vetvy sa preskočia, hoci aj age<19 by platilo. Preto v druhej vetve netreba písať age>=6 AND age<15: keby bol vek menší ako 6, program by sa sem nedostal.
Ďalšie tri IF sú samostatné. Každý sa vyhodnotí zvlášť, takže sa môžu vypísať aj všetky.
age>=13 AND age<=19 je spôsob, ako zapísať „medzi 13 a 19“. Matematický zápis 13<=age<=19 Action! nepozná.
AND má prednosť pred OR.a=5 OR a=6 AND b=7 znamená a=5 OR (a=6 AND b=7). Keď miešaš AND a OR, daj zátvorky – aj tam, kde nie sú nutné, pomôžu čitateľovi.
Podmienka bez porovnania.IF lives THEN platí, keď lives nie je nula. Je to dovolené a používa sa to, ale začiatočníkovi sa odporúča písať porovnanie celé: IF lives>0 THEN.
; A loop: add numbers until the user enters 0PROCMain()
CARDsum, numbersum=0PrintE("Enter numbers, 0 ends.")
DOPrint("? ")
number=InputC()
IFnumber=0THENEXITFIsum==+numberODPutE()
Print("The sum is ")
PrintCE(sum)
RETURN
v slučke nie je EXIT, alebo jeho podmienka nikdy nenastane
program beží donekonečna
Nekonečná slučka nie je chyba prekladu – niekedy ju chceš (hra beží, kým ju niekto nevypne). Keď sa ti to stane omylom:
v simulátore sa program po chvíli zastaví sám a vypíše simulation stopped: instruction limit reached. Simulátor má poistku – po desiatich miliónoch inštrukcií skončí. Kým čaká na vstup z klávesnice, zastavíš ho klávesmi Ctrl+C;
v emulátore zatvor okno alebo stlač kláves, ktorým emulátor resetuje Atari.
; WHILE: the condition is tested before each turnPROCMain()
CARDvalueBYTEcountvalue=1count=0WHILEvalue<1000DOPrintC(value) Put(' )
value==*2count==+1ODPutE()
Print("Doubled ") PrintB(count) PrintE(" times.")
count=10WHILEcount>20DOPrintE("This line is never written.")
ODPrintE("Done.")
RETURN
Prvá slučka zdvojnásobuje value, kým je menšie ako 1000. Vypíše 1, 2, 4 … 512. Po poslednom zdvojnásobení je value 1024, podmienka value<1000 prestane platiť a slučka skončí. Číslo 1024 sa už nevypíše – test je pred výpisom.
Druhá slučka sa nevykoná ani raz. count je 10, podmienka count>20 neplatí hneď na začiatku, a tak program telo preskočí. To je hlavná vlastnosť WHILE: telo sa nemusí vykonať vôbec.
V tele slučky sa musí meniť niečo, od čoho podmienka závisí. Keby v prvej slučke chýbalo value==*2, podmienka by platila navždy.
EXIT funguje aj vo WHILE – slučku ukončí predčasne.
Pozor na pretečenie (kapitola 7): keby value bolo BYTE, po 128 by nasledovalo 0 (256 sa do bajtu nezmestí), 0*2 je stále 0 a value<1000 platí vždy. Slučka by sa nikdy neskončila.
; UNTIL: the condition is tested after each turnPROCMain()
BYTEnumberDOPrint("Enter a number from 1 to 10: ")
number=InputB()
UNTILnumber>=1ANDnumber<=10ODPutE()
Print("Thank you, you entered ")
PrintBE(number)
RETURN
Program sa opýta, načíta číslo a až potom skúša, či je medzi 1 a 10. Ak nie, opýta sa znova. Za slučkou má program istotu, že number je v poriadku – inak by sa cez UNTIL nedostal.
Tu je UNTIL prirodzenejšie ako WHILE: pred prvou otázkou ešte žiadne číslo nie je, takže podmienku na začiatku nie je s čím vyhodnotiť.
Všimni si podmienku: hovorí, kedy slučka skončí („až kým je číslo medzi 1 a 10“), nie kedy pokračuje.
Prvá slučka:i ide od 1 do 10 vrátane. Počítadlo sa dá v tele normálne používať – tu sa vypisuje.
Druhá slučka:STEP 5 zväčšuje i po piatich: 0, 5, 10, 15, 20.
Násobilka: počítadlo row vstupuje do výpočtu row*7.
Trojuholník: slučka v slučke. Vonkajšia ide po riadkoch, vnútorná vypíše toľko hviezdičiek, aké je číslo riadka. Vnútorná slučka má ako koniec premennúrow – koniec nemusí byť číslo.
Začiatočníci často volajú počítadlá i, j, k. Je to zvyk z matematiky; meno ako row alebo col však hovorí viac.
1. Koniec a krok sa vyhodnotia raz, pri vstupe do slučky. Keď v tele zmeníš premennú, ktorá bola koncom, počet prechodov sa už nezmení.
2. FOR nepočíta nadol.FOR i=10 TO 1 sa nevykoná ani raz, lebo 10 je už na začiatku väčšie ako koniec. Nepomôže ani STEP -1. Na odpočítavanie použi WHILE:
Action!
i=10WHILEi>0DOPrintBE(i)
i==-1OD
3. BYTE počítadlo a koniec 255 je nekonečná slučka.
Action!
BYTEiFORi=0TO255; never endsDOOD
Slučka končí, keď je počítadlo väčšie ako koniec. BYTE však väčší ako 255 byť nemôže – po 255 sa pretočí na 0 a ide sa odznova. Ak potrebuješ prejsť všetkých 256 hodnôt, použi počítadlo typu CARD.
Procedúra Line z kapitoly 3 vedela nakresliť čiaru len jednej dĺžky. S parametrom jej pri každom volaní povieš, akú dlhú. Jedna procedúra tak zvládne veľa podobných úloh.
Change(n) odovzdá procedúre hodnotu premennej n, nie premennú samotnú. Parameter value je vlastná premenná procedúry, do ktorej sa trojka skopíruje. Keď ju procedúra prepíše na 99, n v Main sa nezmení.
Ak má procedúra zmeniť premennú volajúceho, treba jej odovzdať adresu premennej – to je téma kapitoly 20. Častejšie stačí, aby rutina výsledok vrátila; to vie funkcia z nasledujúcej kapitoly.
Procedúra niečo spraví. Funkcia niečo vypočíta a vráti – jej volanie sa dá napísať všade, kde môže stáť číslo. Poznáš ich už z knižnice: InputB() je funkcia.
; Functions: routines that give back a valueBYTEFUNCMax(BYTEa, b)
IFa>bTHENRETURN(a)
FIRETURN(b)
CARDFUNCSquare(CARDn)
RETURN(n*n)
BYTEFUNCIsEven(CARDn)
IFnMOD2=0THENRETURN(1)
FIRETURN(0)
PROCMain()
CARDi, sumPrint("The bigger of 7 and 12: ")
PrintBE(Max(7, 12))
Print("12 squared: ")
PrintCE(Square(12))
sum=0FORi=1TO10DOsum==+Square(i)
ODPrint("Squares of 1 to 10 added: ")
PrintCE(sum)
FORi=1TO4DOPrintC(i)
IFIsEven(i)=1THENPrintE(" is even")
ELSEPrintE(" is odd")
FIODRETURN
error ACT028: illegal RETURN: expected '(' with the function result
funkcia končí holým RETURN
to isté hlásenie
RETURN(5) v procedúre
error ACT028: illegal RETURN: a PROC cannot return a value
chýba typ pred FUNC
error ACT006: FUNC needs a result type (BYTE, CHAR, CARD or INT)
Funkciu možno zavolať aj ako procedúru (Max(1, 2) na vlastnom riadku). Výsledok sa vtedy zahodí. Pri Max to nemá zmysel; pri funkcii, ktorá okrem výsledku aj niečo robí, niekedy áno.
Typ funkcie rozhoduje o tom, čo sa vráti. BYTE FUNC, ktorá vráti 300, vráti 44.
Doteraz si premenné deklaroval vnútri procedúry. Taká premenná patrí len tej procedúre. Keď má hodnotu vidieť viac rutín – skóre, počet životov – deklaruje sa mimo rutín.
BYTEscore; globálna: pred prvou rutinouPROCSomething()
BYTEhelper; lokálna: na začiatku rutiny
…
RETURNMODULE; dovolí ďalšie globálne deklarácie za rutinouBYTElivesPROCMain()
…
RETURN
Druh
Kde sa deklaruje
Kto ju vidí
globálna
na začiatku súboru pred prvou rutinou, alebo za slovom MODULE
všetky rutiny, ktoré sú v súbore pod ňou
lokálna
na začiatku rutiny (aj parametre sú lokálne)
len tá rutina
MODULE je potrebné, keď chceš deklarovať globálne premenné až za nejakou rutinou. Bez neho by prekladač ohlásil, že deklarácie musia byť pred príkazmi.
; Where a variable livesBYTEscore=[0] ; global: every routine below sees itPROCAddPoints(BYTEpoints)
BYTEbonus; local: only AddPoints sees itbonus=points/10score==+points+bonusRETURNPROCCounter()
BYTEcalls=[0] ; a local keeps its value between callscalls==+1Print("Counter was called ")
PrintB(calls)
PrintE(" times")
RETURNPROCHide()
BYTEscore; a local with the name of a global hides itscore=200Print("Inside Hide: ")
PrintBE(score)
RETURNMODULE; global declarations after a routine need MODULEBYTElives=[3]
PROCMain()
AddPoints(20)
AddPoints(50)
Print("Score: ")
PrintBE(score)
Counter()
Counter()
Counter()
Hide()
Print("Score after Hide: ")
PrintBE(score)
Print("Lives: ")
PrintBE(lives)
RETURN
score je globálna.AddPoints ju mení, Main ju vypisuje – obe pracujú s tou istou premennou. Po dvoch volaniach je v nej 20 + 2 + 50 + 5 = 77.
bonus je lokálna. Mimo AddPoints neexistuje; keby si ju použil v Main, prekladač ohlási neznáme meno.
calls v Counter si pamätá hodnotu medzi volaniami. To je zvláštnosť Action!, o ktorej je ďalšia časť.
score v Hide je iná premenná. Lokálna premenná s rovnakým menom globálnu zakryje: vnútri Hide znamená score tú lokálnu. Globálna ostane nedotknutá – po návrate je v nej stále 77.
lives je deklarovaná za MODULE a vidí ju len Main, lebo len tá je pod ňou.
V mnohých jazykoch lokálna premenná vznikne pri volaní rutiny a po návrate zmizne. V Action! má každá lokálna premenná svoje pevné miesto v pamäti po celý čas behu programu. Z toho plynú tri veci:
Hodnota prežije medzi volaniami.Counter to využíva: calls sa pri každom volaní zväčší a pamätá si to.
Počiatočná hodnota =[0] sa nastaví len raz – pri nahraní programu, nie pri každom volaní. Ak má premenná začínať pri každom volaní od nuly, priraď jej nulu príkazom (calls=0).
Rutina nesmie volať samu seba. Volanie rutiny zo seba samej (rekurzia) v Action! prepíše jej vlastné parametre a lokálne premenné, lebo existujú len raz. Program sa preloží, ale počíta zle. Namiesto rekurzie použi slučku.
error ACT006: declaration error: declarations must come before the statements
dve premenné s rovnakým menom v tej istej rutine
error ACT006: 'x' is already declared
lokálna premenná, ktorú nikde nepoužiješ
warning ACT212: local variable 'x' is never used
Zakrytie globálnej premennej lokálnou prekladač nehlási – je to dovolené. Keď sa ti „nemení“ globálna premenná, pozri, či si v rutine omylom nedeklaroval lokálnu s rovnakým menom.
Číslo 20 v programe nič nehovorí. WIDTH hovorí, že ide o šírku. DEFINE dá menu text, ktorým ho prekladač pri preklade nahradí. Keď sa šírka zmení, opravíš ju na jednom mieste.
Text je vždy v úvodzovkách, aj keď je to číslo: DEFINE WIDTH="20".
Viac mien naraz sa oddeľuje čiarkou. Deklarácia môže pokračovať na ďalšom riadku.
Všade, kde prekladač v programe nájde MENO, dosadí namiesto neho text – ako keby si ho tam napísal sám.
Mená z DEFINE sa zvyčajne píšu veľkými písmenami, aby sa odlíšili od premenných.
DEFINE nie je premenná. Nezaberá pamäť, nedá sa do neho nič priradiť a za behu programu neexistuje. Je to pokyn pre prekladač: „toto slovo čítaj ako tento text“.
; DEFINE: names for numbers and pieces of the programDEFINEWIDTH="20",
HEIGHT="4",
FRAME="'#",
STRING="CHAR ARRAY"PROCMain()
BYTEx, ySTRINGtitle="A box of WIDTH by HEIGHT"PrintE(title)
FORy=1TOHEIGHTDOFORx=1TOWIDTHDOIFy=1ORy=HEIGHTORx=1ORx=WIDTHTHENPut(FRAME)
ELSEPut(' )
FIODPutE()
ODPrint("Characters in the box: ")
PrintBE(WIDTH*HEIGHT)
RETURN
WIDTH a HEIGHT sú čísla. FOR x=1 TO WIDTH prekladač číta ako FOR x=1 TO 20.
FRAME je znak: Put(FRAME) je Put('#).
STRING nahrádza dve slová naraz. STRING title=… je CHAR ARRAY title=…. Tento DEFINE je medzi programátormi v Action! bežný zvyk – nájdeš ho v mnohých starých programoch.
V reťazcoch sa nenahrádza. Text "A box of WIDTH by HEIGHT" sa vypíše tak, ako je. Úvodzovky chránia svoj obsah.
Podmienka y=1 OR y=HEIGHT OR x=1 OR x=WIDTH platí pre prvý a posledný riadok a prvý a posledný stĺpec – teda pre okraj.
Skús zmeniť WIDTH na 30 a HEIGHT na 6: rám, slučky aj výpočet počtu znakov sa prispôsobia samy.
Vyzerá to ako 10 × 2 = 20, ale vypíše sa 15. Prekladač dosadí text a číta 5+5*2 – a násobenie má prednosť. Keď je v DEFINE výpočet, daj ho do zátvoriek: DEFINE SIZE="(5+5)".
Dvanásť mesiacov, sto nepriateľov, tisíc bodov obrazovky – na to nechceš dvanásť, sto ani tisíc premenných. Pole je rad hodnôt rovnakého typu pod jedným menom. Jednotlivé hodnoty (prvky) sa rozlišujú číslom – indexom.
BYTEARRAYscores(10) ; 10 prvkov typu BYTECARDARRAYsquares(10) ; 10 prvkov typu CARDINTARRAYheights(50) ; 50 prvkov typu INTBYTEARRAYdays=[31283130] ; pole s hodnotami; veľkosť sa spočíta sama
Použitie prvku:
Action!
scores(0)=100; zápis do prvého prvkux=scores(3) ; čítanie štvrtého prvkuscores(i)=scores(i)+1
Číslo v zátvorke pri deklarácii je počet prvkov.
Indexy idú od 0. Pole s 10 prvkami má prvky (0) až (9). Prvok (10) neexistuje.
Index môže byť číslo, premenná aj výraz.
Počiatočné hodnoty sa píšu do hranatých zátvoriek a oddeľujú sa medzerami (čiarky medzi nimi prekladač tiež prijme).
; Arrays: many values under one namePROCMain()
BYTEARRAYdays=[312831303130313130313031]
CARDARRAYsquares(10) ; 10 elements: squares(0) to squares(9)BYTEi, biggestCARDtotalFORi=0TO9; fill the array in a loopDOsquares(i)=i*iODPrint("Squares: ")
FORi=0TO9DOPrintC(squares(i)) Put(' )
ODPutE()
Print("Days in March: ")
PrintBE(days(2)) ; January is days(0)total=0FORi=0TO11DOtotal==+days(i)
ODPrint("Days in a year: ")
PrintCE(total)
days(1)=29; an element can be changedPrint("February in a leap year: ")
PrintBE(days(1))
biggest=0FORi=0TO11DOIFdays(i)>biggestTHENbiggest=days(i)
FIODPrint("The longest month has ")
PrintB(biggest)
PrintE(" days")
RETURN
Volanie: Fill(scores, 10). Na rozdiel od obyčajnej premennej (kapitola 14) sa pole nekopíruje – rutina pracuje priamo s poľom volajúceho a zmeny v ňom ostanú. Veľkosť poľa rutina nepozná, preto sa odovzdáva zvlášť.
Action! nekontroluje, či je index v rozsahu poľa. Zápis za koniec poľa prepíše to, čo leží v pamäti za ním – zvyčajne iné premenné:
Action!
BYTEARRAYa(3)
BYTExx=7a(3)=9; a má len prvky 0, 1, 2PrintBE(x) ; vypíše 9
Prekladač nič nehlási, program beží a chyba sa prejaví inde a neskôr. Keď sa premenná „sama“ mení, hľadaj pole pred ňou a slučku, ktorá ide o jeden prvok ďalej (TO 10 namiesto TO 9).
The text: Atari
Its length: 5
First letter: A
Spelled: A t a r i
Changed copy: Stari
The original: Atari
A part: Action!
Joined: Hello, Atari
apple comes before banana
pear is the same as pear
zebra comes after ant
name(0) je dĺžka, name(1) prvý znak. Slučka FOR i=1 TO name(0) prejde všetky znaky – to je bežný spôsob, ako spracovať text znak po znaku.
SCopy(copy, name) – cieľ je prvý, zdroj druhý. Tak je to pri všetkých rutinách na reťazce.
copy(1)='S mení jeden znak ako prvok poľa. Originál name ostáva nedotknutý, lebo copy je vlastné pole.
SCopyS(part, "Action! language", 1, 7) vyberie znaky 1 až 7. Zdrojom môže byť aj text priamo v úvodzovkách.
Spojenie dvoch reťazcov Action! nemá ako jednu rutinu. Skladá sa zo SCopy (prvá časť) a SAssign (druhá časť za koniec prvej). line(0)+1 je prvá voľná pozícia; SAssign reťazec podľa potreby predĺži.
SCompare porovnáva podľa abecedy – presnejšie podľa kódov znakov. Na presnej hodnote výsledku nezáleží, len na tom, či je záporný, nulový alebo kladný.
Procedúra Order ukazuje reťazec ako parameter: CHAR ARRAY a bez veľkosti. Ako každé pole sa nekopíruje.
Každá premenná leží niekde v pamäti – na svojej adrese. Adresa je číslo od 0 do 65535, ako číslo domu na dlhej ulici. Ukazovateľ je premenná, v ktorej je adresa inej premennej. Cez ukazovateľ sa dá k tej premennej dostať, aj keď nepoznáš jej meno.
Hodí sa to v dvoch prípadoch: keď má rutina zmeniť premennú volajúceho, a keď sa prechádza pamäťou bajt po bajte.
; Pointers: variables that hold an addressPROCSwap(BYTEPOINTERa, b)
BYTEkeepkeep=a^a^=b^b^=keepRETURNPROCMain()
BYTEx, y, iBYTEPOINTERpBYTEARRAYdata=[581321]
x=10y=20p=@x; p holds the address of xPrint("p points at x: ") PrintBE(p^)
p^=15; store through the pointerPrint("x is now ") PrintBE(x)
p=@y; the same pointer, another variablePrint("p points at y: ") PrintBE(p^)
Swap(@x, @y) ; the routine changes our variablesPrint("After Swap: x=") PrintB(x)
Print(" y=") PrintBE(y)
p=data; the name of an array is its addressPrint("The array: ")
FORi=1TO4DOPrintB(p^) Put(' )
p==+1; move to the next byteODPutE()
RETURN
Z kapitoly 14 vieš, že procedúra dostáva kópie. Swap má premenné vymeniť, takže kópie jej nestačia. Dostane preto ich adresy (Swap(@x, @y)) a cez a^ a b^ pracuje priamo s premennými x a y v Main.
Meno poľa bez indexu je adresa jeho prvého prvku. Preto p=data (bez @) nastaví p na začiatok poľa. p==+1 potom posunie ukazovateľ o jeden bajt a slučka prejde pole bez indexov.
Platí to aj naopak: ukazovateľ sa dá indexovať ako pole, p(2) je bajt dva miesta za adresou v p.
Pole deklarované bez veľkosti a bez hodnôt (BYTE ARRAY a) je vlastne ukazovateľ: nemá vlastné prvky a treba mu najprv priradiť adresu.
Hráč má polohu, počet životov a skóre. Sú to štyri premenné, ktoré patria k sebe. Záznam (record) ich spojí do jedného celku s vlastným menom, takže sa dajú odovzdať rutine naraz.
TYPE Meno=[ … ] – v hranatých zátvorkách sú položky, zapísané ako deklarácie premenných.
Položky toho istého typu oddeľuje čiarka. Medzi skupinami typov sa čiarka nepíše – za lives nasleduje rovno CARD.
Položky môžu byť len základných typov: BYTE, CHAR, CARD, INT.
TYPE sa píše mimo rutín, na začiatok súboru.
Potom sa meno typu používa ako každý iný typ:
Action!
Playerhero, enemy; dve premenné typu PlayerPlayerPOINTERwho; ukazovateľ na záznamhero.x=10; položka sa píše za bodkuwho.score==+100; cez ukazovateľ rovnako, bez ^
Player hero, enemy vytvorí dva záznamy. Každý má vlastné x, y, lives a score.
hero.x=10 zapíše do položky x záznamu hero.
Záznam sa rutine odovzdáva cez ukazovateľ. Parameter je Player POINTER who. Pri volaní stačí napísať meno záznamu: Show(hero) – meno záznamu bez bodky je, podobne ako meno poľa, jeho adresa.
Vnútri rutiny sa položky píšu rovnako: who.x. Znak ^ tu netreba.
Hit(hero, 250) záznam mení. Keďže rutina dostala adresu, mení priamo hero v Main.
Jedna rutina Show obslúži hrdinu aj nepriateľa. To je hlavný zmysel záznamov: rutiny sa píšu pre typ, nie pre jednu konkrétnu premennú.
Action! nemá Player ARRAY. Viac záznamov za sebou sa robí poľom bajtov a ukazovateľom, ktorý sa posúva o veľkosť záznamu. Meno typu vo výraze je veľkosť záznamu v bajtoch.
; An array of records: a block of bytes and a pointer that walks through itTYPEStar=[BYTEx, yCARDpoints]
DEFINECOUNT="3"PROCMain()
BYTEARRAYroom(12) ; room for COUNT records of 4 bytesStarPOINTERsBYTEiFORi=0TOCOUNT-1DOs=room+i*Star; the address of record number is.x=i*10s.y=i+1s.points=(i+1)*100ODFORi=0TOCOUNT-1DOs=room+i*StarPrint("Star ") PrintB(i)
Print(": x=") PrintB(s.x)
Print(" y=") PrintB(s.y)
Print(" points=") PrintCE(s.points)
ODPrint("One record takes ")
PrintB(Star)
PrintE(" bytes")
RETURN
Bash
action26records-array.act--sim
Star 0: x=0 y=1 points=100
Star 1: x=10 y=2 points=200
Star 2: x=20 y=3 points=300
One record takes 4 bytes
s=room+i*Star vypočíta adresu záznamu číslo i: začiatok poľa plus i-krát veľkosť záznamu. Záznam Star má dva BYTE a jeden CARD, teda 4 bajty; tri záznamy potrebujú 12 bajtov.
error ACT010: illegal assignment: cannot assign to Player 'enemy' – kopíruj položku po položke
ukazovateľ na záznam bez priradenej adresy
zápis na náhodné miesto v pamäti
meno typu a meno premennej sa líšia len veľkosťou písmen (TYPE P, premenná p)
je to to isté meno – veľké a malé písmená sa nerozlišujú
pole pre záznamy je malé
záznamy za koncom poľa prepíšu inú pamäť
Mená položiek sú mená ako každé iné. Dva typy záznamov v jednom programe preto nemôžu mať položku s rovnakým menom – prekladač ohlási error ACT006: 'x' is already declared. Pomáha predpona: px, py pre hráča, sx, sy pre hviezdu.
Bajt je osem bitov – ôsmich prepínačov, z ktorých každý je buď 0, alebo 1. Počítač Atari má veľa nastavení uložených tak, že každý bit bajtu znamená niečo iné: jeden zapína inverzné písmo, iný hovorí, či je stlačené tlačidlo. Bitové operácie dovolia pracovať s jednotlivými bitmi.
Kapitolu môžeš pri prvom čítaní preskočiť a vrátiť sa k nej, keď budeš bity potrebovať.
a 00001100 = 12
b 00001010 = 10
a AND b 00001000 = 8
a OR b 00001110 = 14
a XOR b 00000110 = 6
a LSH 1 00011000 = 24
a RSH 2 00000011 = 3
bit 7 on 10000101 = 133
bit 7 off 00000101 = 5
a 00001100
b 00001010
a AND b 00001000 jednotka len tam, kde ju majú obe
a OR b 00001110 jednotka tam, kde ju má aspoň jedno
a XOR b 00000110 jednotka tam, kde sa líšia
a LSH 1 posunie všetko o miesto doľava: z 12 je 24, dvojnásobok.
a RSH 2 posunie o dve miesta doprava: 12 delené 4 je 3. Bity, ktoré „vypadnú“ z kraja, sa stratia.
a==%128 zapne bit 7 a ostatné nechá: z 5 je 133.
a==&127 – 127 je 01111111, všetky bity okrem siedmeho. AND s ním bit 7 vypne a ostatné nechá.
Procedúra Bits ukazuje, ako sa bity čítajú: maska začne na 128 (bit 7) a každým krokom sa posunie doprava (mask==RSH 1). value&mask je nenulové práve vtedy, keď je daný bit v value zapnutý – a podmienka bez porovnania platí, keď je výsledok nenulový.
Rutiny, ktoré sa hodia do viacerých programov, nechceš zakaždým kopírovať. Dáš ich do vlastného súboru a program si ho vloží príkazom INCLUDE. Tak vzniká vlastná knižnica.
Druhá polovica kapitoly je o SET – pokyne, ktorým sa v starých programoch nastavuje prekladač.
Prekladač na tomto mieste prečíta celý súbor MENO.ACT, akoby bol jeho text napísaný priamo tu. Potom pokračuje ďalším riadkom.
D: je označenie disketovej jednotky na Atari. action26 ho preskočí – zaujíma ho len meno súboru. Píše sa preto, aby program preložil aj pôvodný Action!.
Súbor sa hľadá v priečinku, kde leží program, ktorý ho vkladá.
Meno bez prípony dostane .ACT.
INCLUDE patrí tam, kde by mohol stáť obsah súboru – rutiny knižnice teda vkladaj na začiatok, pred rutiny, ktoré ich volajú.
; A small library: routines that draw with characters.; This file is not a program of its own. Other programs INCLUDE it.PROCShapeLine(BYTEwidth, CHARc)
BYTEiFORi=1TOwidthDOPut(c)
ODPutE()
RETURNPROCShapeBox(BYTEwidth, height, CHARc)
BYTErowFORrow=1TOheightDOShapeLine(width, c)
ODRETURN
; A program in two filesINCLUDE"D:SHAPES.ACT"; the routines of shapes.act are now knownPROCMain()
ShapeLine(12, '=)
ShapeBox(6, 2, '#)
ShapeLine(12, '=)
RETURN
Keď prekladač narazí na INCLUDE "D:SHAPES.ACT", otvorí shapes.act, preloží obe procedúry a vráti sa do include.act. Pre Main sú potom ShapeLine a ShapeBox známe, ako keby boli v tom istom súbore nad ňou.
Mená v knižnici začínajú rovnakým slovom (Shape…). Action! nemá oddelené priestory mien – všetky rutiny všetkých vložených súborov sú na jednej hromade. Spoločná predpona bráni tomu, aby sa meno z knižnice zrazilo s menom v programe.
Nie celkom. Rutiny z knižnice jazyka (Print, Graphics …) action26 pribalí len tie, ktoré program volá. Rutiny z tvojho vloženého súboru sa preložia všetky, aj nepoužité. Veľkú knižnicu sa preto oplatí deliť do menších súborov.
Pôvodný Action! bežal na Atari a jeho nastavenia boli bajty v pamäti. SET počas prekladu zapísal hodnotu na danú adresu a tým prekladač prestavil. action26 týmto zápisom rozumie.
Stretneš najmä túto dvojicu – hovorí, od ktorej adresy má byť program v pamäti:
; SET: this program is placed at address $5000 instead of $2000SET$E=$5000SET$491=$5000PROCMain()
Print("This routine starts at address ")
PrintCE(Main)
RETURN
Bash
action26set.act--sim
This routine starts at address 20480
20480 je desiatkovo $5000. Bez dvoch riadkov SET by program začínal na $2000 (8192).
Vo vlastných programoch SET nepotrebuješ. To isté spraví voľba prekladača --org $5000 alebo riadok ;@ORG $5000 na začiatku zdrojáka (kapitoly 32 a 33). Dobré je SET poznať, aby ťa v cudzom programe neprekvapil.
Atari sa ovláda cez pamäť. Farba pozadia, poloha kurzora, posledný stlačený kláves, stav joysticku – to všetko sú bajty na známych adresách. Kto vie čítať a zapisovať pamäť, vie z počítača dostať všetko, čo knižnica neponúka.
Adresy premenných v RAM ($0000–$05FF) a registrov sú vo všetkých verziách operačného systému rovnaké. Vnútro ROM nie: Atari 800, Atari XL/XE aj voľná náhrada AltirraOS majú na tých istých adresách v ROM iný kód. Do ROM sa preto skáče len cez oficiálne vstupné body – tabuľku od $E450 (napríklad $E456 pre vstup a výstup). Program, ktorý volá rutinu z vnútra ROM na pevnej adrese, beží len s jednou verziou systému.
To je deklarácia z kapitoly 6, pred ktorou si mal byť opatrný: číslo bez hranatých zátvoriek je adresa. Premenná background nedostane vlastné miesto – je bajtom na adrese 710. Zápis background=148 robí to isté ako Poke(710, 148), len sa lepšie číta a je rýchlejší.
; Memory: reading and writing bytes by their addressBYTEbackground=710; this variable IS the byte at address 710BYTEARRAYpage6(256)=1536; an array placed at address 1536 ($600)PROCMain()
BYTEvalueCARDwordPoke(1536, 65) ; write 65 to address 1536value=Peek(1536) ; read it backPrint("Address 1536 holds ")
PrintBE(value)
PokeC(1538, 50000) ; a CARD takes two bytes: 1538 and 1539word=PeekC(1538)
Print("Addresses 1538-1539 hold ")
PrintCE(word)
Print("Low byte ") PrintB(Peek(1538))
Print(", high byte ") PrintBE(Peek(1539))
page6(4)=7; the same memory through the arrayPrint("page6(4) is address 1540: ")
PrintBE(Peek(1540))
Print("page6(0) is address 1536: ")
PrintBE(page6(0))
background=148; the same as Poke(710, 148)Print("Address 710 holds ")
PrintBE(Peek(710))
RETURN
Poke(1536, 65) a Peek(1536) – zápis a čítanie jedného bajtu. Adresa 1536 je začiatok šiestej stránky, kde programu nič nezavadzia.
CARD zaberá dva bajty a nižší je prvý. 50000 je 195 × 256 + 80. Na adrese 1538 je 80 (nižší bajt), na 1539 je 195 (vyšší). Toto poradie platí na Atari všade.
page6 je pole položené na šiestu stránku. page6(4) a adresa 1540 sú to isté miesto. page6(0) ukazuje 65, ktoré tam zapísal Poke na začiatku.
background=148 zapíše na adresu 710. V simulátore vidíš len číslo; v emulátore sa zmení farba pozadia na modrú, lebo 710 je bunka, z ktorej systém berie farbu pozadia textovej obrazovky.
Skús to v emulátore – pridaj na koniec GetD(7), aby program počkal na kláves (kapitola 2):
Procesor Atari (6502) rozumie len číslam – strojovému kódu. Prekladač mení tvoj program práve na také čísla. Action! dovoľuje vložiť strojový kód do programu aj priamo, a zavolať rutinu, ktorá už niekde v pamäti je (napríklad v operačnom systéme).
Túto kapitolu nemusíš vedieť použiť. Stačí vedieť, čo ten zápis znamená, keď ho stretneš v cudzom programe. Staré programy z časopisov ho používajú často – na miestach, kde záležalo na rýchlosti.
Čísla v hranatých zátvorkách prekladač vloží do programu presne tak, ako sú, bajt za bajtom. Nič nekontroluje. Číslo väčšie ako 255 sa vloží ako dva bajty (nižší prvý). V bloku môže stáť aj meno premennej alebo rutiny – vloží sa jej adresa.
Blok môže stáť medzi príkazmi rutiny alebo tvoriť celé jej telo.
=* znamená „táto rutina začína práve tu a jej telo si napíšem sám“. Prekladač k nej nepridá nič – ani uloženie parametrov. Kód musí sám skončiť inštrukciou návratu ($60).
Hovorí: „na adrese $E456 už rutina je, len jej dávam meno“. Žiadne telo nenasleduje. Takto sa volajú rutiny operačného systému. Argumenty sa odovzdajú v registroch procesora: prvý bajt v registri A, druhý v X, tretí v Y.
; Machine code inside an Action! programBYTEcounter=1536; a byte at address $0600PROCBump=*() ; a routine written in machine code
[$EE$00$06; INC $0600 - add 1 to the byte at $0600$60] ; RTS - returnPROCMain()
counter=5Bump()
Bump()
Print("After two calls: ")
PrintBE(counter)
[$CE$00$06] ; DEC $0600 - a code block between statementsPrint("After the code block: ")
PrintBE(counter)
RETURN
$EE $00 $06 je inštrukcia procesora INC $0600: pripočítaj 1 k bajtu na adrese $0600. Prvý bajt je kód inštrukcie, ďalšie dva adresa (nižší bajt prvý – ako v kapitole 24).
$60 je RTS, návrat z rutiny.
counter je premenná položená na adresu $0600 (1536), takže strojový kód a program v Action! menia ten istý bajt.
Bump() sa volá ako každá iná procedúra.
[$CE $00 $06] uprostred Main je DEC $0600 – odčítaj 1. Vykoná sa v poradí medzi okolitými príkazmi.
Komentáre za bajtmi hovoria, aká inštrukcia to je. Bez nich je blok kódu len rad čísel, ktorým nikto nerozumie – ani autor o mesiac neskôr.
Skoro nikdy. action26 prekladá Action! do rýchleho kódu a to, čo sa kedysi písalo v strojovom kóde, dnes zvyčajne netreba. Výnimky:
obsluha prerušení (napríklad zmena farby na každom riadku obrazovky),
volanie rutiny operačného systému, ktorú knižnica nemá,
prepis starého programu, ktorý bloky kódu už obsahuje.
Ak sa chceš strojovému kódu venovať, action26 má pohodlnejší spôsob než čísla: blok ASM … ENDASM, do ktorého sa píšu inštrukcie menami (inc counter). Je to rozšírenie nad rámec pôvodného Action! a opisuje ho kapitola 37.
Zmeň prvý bajt bloku v Main z $CE na $EE. Čo sa vypíše?
Prelož program s voľbou --listing machine.lst a otvor vzniknutý súbor v editore. Nájdi v ňom svoje bajty – a pozri, ako prekladač preložil ostatné riadky.
Veta „Pedro is 12 years old.“ potrebovala doteraz štyri príkazy: Print, Print, PrintB, PrintE. PrintF to zvládne jedným. Druhá polovica kapitoly je o prevode čísla na text a späť.
Prvý parameter je formát: text, v ktorom sú na miestach hodnôt značky začínajúce znakom %. Ďalšie parametre sú hodnoty, ktoré sa na miesta značiek dosadia – v poradí, v akom idú.
; PrintF and the conversions between numbers and stringsPROCMain()
CHARARRAYname="Pedro", text(10)
BYTEageCARDscore, numberINTchangeage=12score=40000change=-25PrintF("%S is %U years old.%E", name, age)
PrintF("Score %U, change %I%E", score, change)
PrintF("%U in hexadecimal is %H%E", score, score)
PrintF("A character: %C, a percent sign: %%%E", 'A)
StrC(score, text) ; a number into a stringPrint("As a string: ")
PrintE(text)
Print("It has ")
PrintB(text(0))
PrintE(" characters")
number=ValC("1234") ; a string into a numberPrint("ValC(""1234"") plus 1 is ")
PrintCE(number+1)
change=ValI("-77")
Print("ValI(""-77"") times 2 is ")
PrintIE(change*2)
RETURN
Pedro is 12 years old.
Score 40000, change -25
40000 in hexadecimal is $9C40
A character: A, a percent sign: %
As a string: 40000
It has 5 characters
ValC("1234") plus 1 is 1235
ValI("-77") times 2 is -154
V prvom PrintF sú dve značky a dve hodnoty: %S dostane name, %U dostane age. %E na konci ukončí riadok – PrintF to sám nespraví.
%U a %I sa líšia tým, ako číslo čítajú. −25 vypísané cez %U by bolo 65511.
%H vypíše to isté číslo šestnástkovo. Hodí sa pri práci s adresami.
StrC(score, text) uloží do text reťazec "40000". Od tej chvíle je to obyčajný reťazec: má dĺžku 5 v text(0) a dá sa s ním robiť všetko z kapitoly 19.
ValC("1234") vráti číslo 1234, s ktorým sa dá počítať.
Kedy prevody potrebuješ: keď chceš číslo zarovnať, vložiť do dlhšieho textu, alebo spracovať vstup znak po znaku. InputB() z kapitoly 8 nerobí nič iné ako InputS a potom ValB.
Atari vie okrem textu kresliť body a čiary vo farbe. Táto kapitola ukáže textovú obrazovku s farbami a kurzorom na ľubovoľnom mieste a potom obrázok z čiar.
Od tejto kapitoly potrebuješ emulátor. Simulátor (--sim) obrazovku nekreslí. Programy sa spúšťajú voľbou --run a na konci čakajú na kláves.
Režimy 1 až 8 nechávajú dole textové okno so štyrmi riadkami, do ktorého píše Print. Keď k číslu režimu pripočítaš 16 (Graphics(7+16)), okno zmizne a grafika zaberie celú obrazovku.
; The text screen: colours and the place of the cursorPROCMain()
BYTEiGraphics(0) ; clear the screenSetColor(2, 9, 4) ; the background is blueSetColor(1, 0, 14) ; the letters are brightSetColor(4, 9, 4) ; the border is the same bluePosition(12, 2)
Print("THE TEXT SCREEN")
FORi=0TO9DOPosition(5+i*3, 5+i) ; column, rowPrintB(i)
ODPosition(2, 19)
Print("Press any key")
GetD(7)
RETURN
Bash
action26textscreen.act--run
Uvidíš modrú obrazovku s nadpisom hore a číslicami 0 až 9 usporiadanými šikmo nadol. Position postaví kurzor a nasledujúci Print píše od toho miesta.
V režime 0 má register 2 farbu pozadia, register 1 jas písma (odtieň písma je vždy rovnaký ako pozadie) a register 4 okraj.
; Graphics: a house in graphics mode 7 (160 x 80 points, 4 colours)PROCMain()
BYTEi, foundGraphics(7) ; 160 x 80 points and 4 lines of text belowSetColor(0, 2, 8) ; colour 1 is orangeSetColor(1, 12, 10) ; colour 2 is greenSetColor(2, 9, 6) ; colour 3 is blueSetColor(4, 0, 0) ; the background is blackcolor=1; a frame around the picturePlot(0, 0)
DrawTo(159, 0)
DrawTo(159, 79)
DrawTo(0, 79)
DrawTo(0, 0)
color=2; the wallsPlot(50, 60)
DrawTo(50, 35)
DrawTo(110, 35)
DrawTo(110, 60)
DrawTo(50, 60)
color=3; the roofPlot(45, 35)
DrawTo(80, 15)
DrawTo(115, 35)
color=1; a filled doorPlot(86, 59)
DrawTo(86, 45)
DrawTo(74, 45)
Fill(74, 59)
color=3; a dotted pathFORi=0TO9DOPlot(80+i*4, 70)
ODfound=Locate(50, 40) ; which colour has the point 50,40?PrintE("A house in graphics mode 7")
Print("The point 50,40 has colour ")
PrintBE(found)
Print("Press any key")
GetD(7)
Graphics(0)
RETURN
Čiernu obrazovku s oranžovým rámom. V strede domček: zelené steny, modrá strecha, oranžové vyplnené dvere a pod ním bodkovaná modrá cestička. V textovom okne dole:
A house in graphics mode 7
The point 50,40 has colour 2
Press any key
Graphics(7) prepne režim. Obrazovka má 160 stĺpcov (0–159) a 80 riadkov (0–79).
Štyri SetColor určia, čo znamenajú čísla farieb.
color=1 vyberie farbu pre nasledujúce kreslenie. Platí, kým ju nezmeníš.
Čiara sa kreslí dvojicou Plot a DrawTo: Plot položí prvý bod, DrawTo ťahá čiaru do ďalšieho. Ďalší DrawTo pokračuje tam, kde predošlý skončil – tak vznikne lomená čiara.
Locate(50, 40) prečíta farbu bodu. Na tom mieste je ľavá stena, kreslená farbou 2.
kreslí sa farbou, ktorá ostala naposledy; ak je to 0 – pozadie –, nie je nič vidieť
zámena riadka a stĺpca
obrázok je preklopený alebo mimo obrazovky
SetColor(1, …) v nádeji, že zmení color=1
color=1 je register 0
nepárny jas
zaokrúhli sa nadol; jas 9 je to isté ako 8
program vlastní premennú color
zakryje premennú knižnice a kreslenie prestane meniť farbu
Posledný riadok je všeobecná pasca: meno premennej nesmie byť rovnaké ako meno rutiny alebo premennej knižnice, a veľké a malé písmená sa nerozlišujú. Premenná stick zakryje funkciu Stick, premenná position procedúru Position.
10 je čistý tón; ostatné dávajú šum a bzučanie (výbuchy, motory)
hlasitosť
0 až 15
0 je ticho
Tón znie, kým ho nezmeníš alebo nevypneš. Sound hlas len nastaví a program beží ďalej. Ako dlho tón znie, určuje to, čo program robí potom – preto treba čakanie.
; Sound: a scale and a sirenBYTEclock=20; this byte grows by 1 fifty times a secondPROCWait(BYTEticks)
clock=0WHILEclock<ticksDOODRETURNPROCMain()
BYTEARRAYnotes=[121108969181726460] ; C D E F G A B CBYTEi, pitchPrintE("A scale...")
FORi=0TO7DOSound(0, notes(i), 10, 8) ; voice, pitch, pure tone, volumeWait(15)
ODSndRst() ; silenceWait(25)
PrintE("A siren...")
FORi=1TO3DOFORpitch=40TO100STEP4DOSound(0, pitch, 10, 10)
Wait(1)
ODODSndRst()
PrintE("Two voices together...")
Sound(0, 121, 10, 8)
Sound(1, 81, 10, 8)
Wait(50)
SndRst()
PutE()
Print("Press any key")
GetD(7)
RETURN
Sound nečaká, takže dĺžku tónu si program musí odmerať sám. Atari má na adrese 20 počítadlo, ktoré operačný systém zväčší o 1 pri každom obrázku na obrazovke – v Európe 50-krát za sekundu, v USA 60-krát.
Action!
BYTEclock=20
je premenná na tejto adrese (kapitola 24). Procedúra Wait ju vynuluje a v prázdnej slučke čaká, kým nenarastie na požadovanú hodnotu. Wait(50) je teda asi sekunda, Wait(15) necelá tretina.
Túto procedúru budeš používať stále – v hrách určuje rýchlosť.
Hra potrebuje vedieť, čo robí hráč, a potrebuje náhodu. Táto kapitola ukazuje čítanie joysticku a náhodné čísla.
Oba programy sú pre emulátor. V emulátore atari800 sa joystick zvyčajne ovláda šípkami alebo číselnou klávesnicou a tlačidlo pravým klávesom Ctrl – presné nastavenie nájdeš v jeho ponuke (kláves F1).
Stred je 15, hore 14, dole 13, vľavo 11, vpravo 7; šikmé smery sú medzi nimi.
Čísla nie sú náhodné. Každý smer je jeden bit, ktorý sa pri vychýlení vynuluje:
Bit
Hodnota
Smer
0
1
hore
1
2
dole
2
4
vľavo
3
8
vpravo
15 je 1111 – nič nie je vychýlené. 14 je 1110 – bit „hore“ je nula. Preto sa smer najpohodlnejšie skúša bitovým & z kapitoly 22: (joy&1)=0 znamená „hore“. Šikmý smer tak vyjde sám – platia dve podmienky naraz.
; Joystick: move a star around the screen, the button ends the programBYTEclock=20; grows by 1 fifty times a secondBYTEcursorOff=752; 1 hides the cursorPROCWait(BYTEticks)
clock=0WHILEclock<ticksDOODRETURNPROCMain()
BYTEx, y, joyGraphics(0)
cursorOff=1Position(2, 0)
Print("Joystick moves, the button ends")
x=20y=10DOPosition(x, y)
Put('*)
Wait(3)
IFSTrig(0)=0THEN; 0 means the button is pressedEXITFIjoy=Stick(0)
IFjoy#15THEN; 15 means the stick is in the middlePosition(x, y)
Put(' ) ; rub out the old starIF (joy&1)=0ANDy>2THENy==-1FI; upIF (joy&2)=0ANDy<22THENy==+1FI; downIF (joy&4)=0ANDx>2THENx==-1FI; leftIF (joy&8)=0ANDx<37THENx==+1FI; rightFIODPosition(2, 23)
Print("Bye!")
RETURN
Bash
action26joystick.act--run
Na obrazovke je hviezdička, ktorá sa hýbe podľa joysticku. Tlačidlo program ukončí.
Toto je hlavná slučka hry v najjednoduchšej podobe. Každý prechod:
nakreslí hviezdičku na aktuálne miesto,
chvíľu počká (Wait(3) – bez toho by hviezdička lietala rýchlejšie, než sa dá ovládať),
pozrie na tlačidlo a prípadne skončí,
prečíta joystick; ak je vychýlený, zmaže starú hviezdičku medzerou a zmení súradnice.
Podmienky y>2, y<22, x>2, x<37 držia hviezdičku na obrazovke.
Premenná sa volá joy, nie stick. Meno stick by zakrylo funkciu Stick (veľké a malé písmená sa nerozlišujú) a prekladač by Stick(0) odmietol s error ACT021: illegal array.
Rand(6) dá číslo 0 až 5. Kocka má 1 až 6, preto +1.
counts je pole počítadiel: counts(throw)==+1 zväčší počítadlo pre hodené číslo. Pole má 7 prvkov, aby sa dali použiť indexy 1 až 6 priamo; prvok 0 ostane nevyužitý.
Zero(counts, 7) pole pred použitím vynuluje (kapitola 31).
V simulátore náhoda nefunguje.Rand číta zvukový čip, ktorý simulátor nemá, a vracia stále to isté číslo. Programy s Rand skúšaj v emulátore.
Paddle je otočný ovládač – koliesko. Paddle(0) vráti číslo podľa natočenia, približne 1 až 228. Typické použitie je pálka v hre Breakout: x=Paddle(0)/2 prevedie natočenie na stĺpec v režime 7. Paddle sa pripájali po dvoch do jedného portu, preto je ich až osem (0 až 7).
Čo program vypočíta, sa po vypnutí stratí – pokiaľ to neuloží do súboru na disketu. Rovnakým spôsobom, akým sa číta a píše súbor, komunikuje Atari so všetkými zariadeniami: s obrazovkou, klávesnicou aj tlačiarňou.
Každé zariadenie má meno z jedného písmena a dvojbodky:
Meno
Zariadenie
E:
editor – obrazovka a klávesnica spolu (to, cez čo si doteraz písal a čítal)
K:
klávesnica – jeden stlačený kláves, bez čakania na RETURN
S:
obrazovka v grafickom režime
P:
tlačiareň
D:
disketa; za dvojbodkou je meno súboru: D:NOTES.TXT
C:
kazeta
Meno súboru na diskete má najviac 8 znakov, bodku a najviac 3 znaky prípony, veľkými písmenami.
Program so zariadením nehovorí priamo, ale cez kanál – očíslovanú „linku“ 0 až 7. Najprv kanál otvorí, potom cez neho číta alebo píše, a nakoniec ho zavrie.
Kanál
Kto ho používa
0
E: – otvorený od začiatku; sem píše Print a odtiaľ číta InputS
; Files: write three lines to a disk file and read them backPROCMain()
CHARARRAYline(80)
BYTEcountOpen(1, "D:NOTES.TXT", 8, 0) ; 8 = write (a new file)PrintDE(1, "The first line")
PrintDE(1, "The second line")
PrintD(1, "Number ")
PrintBDE(1, 42)
Close(1)
PrintE("The file is written.")
PutE()
count=0Open(1, "D:NOTES.TXT", 4, 0) ; 4 = readDOInputSD(1, line)
IFEOF(1) THENEXITFIcount==+1PrintB(count)
Print(": ")
PrintE(line)
ODClose(1)
PutE()
PrintB(count)
PrintE(" lines read.")
RETURN
Simulátor má „disketu“ len v pamäti: súbor existuje, kým program beží, a potom zmizne.
V emulátore potrebuje program skutočnú disketu s operačným systémom diskov (DOS). Ako sa to robí, je v kapitole 34; v skratke – skopíruj si obraz diskety s DOS-om (napríklad dos25.atr) a napíš:
Bash
action26files.act--atrdos25.atr--run
Program sa uloží na disketu tak, aby sa po zapnutí Atari sám spustil, a súbor NOTES.TXT na nej ostane.
Zápis.Open(1, "D:NOTES.TXT", 8, 0) otvorí na kanáli 1 nový súbor. PrintDE(1, …) doň píše presne to, čo by PrintE napísal na obrazovku. Tretí riadok vznikne z dvoch príkazov, ako na obrazovke. Close(1) súbor zavrie – až vtedy je naozaj celý na diskete.
Čítanie. Súbor sa otvorí znova, tentoraz v režime 4. Slučka číta riadok po riadku cez InputSD. Po každom čítaní sa pozrie na EOF(1): keď je nenulové, riadok sa už neprečítal a slučka končí.
Test konca súboru je za čítaním a pred spracovaním riadka. Koniec sa totiž zistí až pri pokuse čítať ďalej.
Posledný parameter Open je pri bežnej práci vždy 0.
zapamätá si miesto v otvorenom súbore (do CARD sektor a BYTE posun)
Point(k, sektor, posun)
vráti sa na zapamätané miesto
XIO je všeobecný príkaz pre zariadenie; kanál k musí byť voľný (zatvorený). Tieto operácie a zoznam súborov (režim 6) skúšaj v emulátore s disketou – simulátor vie spoľahlivo len čítať, písať a pripisovať. Note a Point dovoľujú skákať v súbore – napríklad vrátiť sa na začiatok záznamu bez čítania všetkého pred ním.
InputSD prepíše pamäť; použi InputMD(k, pole, veľkosť), ktorá dĺžku stráži
Chyba pri práci so zariadením program ukončí výpisom Err: a čísla. Ako ju zachytiť a pokračovať, ukáže nasledujúca kapitola. Čísla chýb sú v prílohe C.
Prvá polovica kapitoly: tri rutiny, ktoré spravia naraz to, na čo by si inak písal slučku – vynulujú, vyplnia alebo skopírujú kus pamäte. Sú napísané v strojovom kóde a sú mnohonásobne rýchlejšie ako slučka FOR.
Druhá polovica: čo sa stane, keď za behu programu nastane chyba, a ako ju zachytiť.
Keď rutina knižnice narazí na problém – súbor neexistuje, bod je mimo obrazovky –, zavolá procedúru Error s číslom chyby. Tá, ktorá je v knižnici, vypíše
Err: 170
a program ukončí.
Error sa dá vymeniť za vlastnú:
Action!
PROCMyError(BYTEcode)
…
RETURN
…
Error=MyError
Priradenie Error=MyError presmeruje všetky ďalšie chyby do tvojej procedúry. Tá dostane číslo chyby ako parameter. Keď sa vráti, program pokračuje za rutinou, v ktorej chyba nastala.
Break() je rutina, ktorá sama vyvolá chybu 128 – tú istú, ako keď používateľ stlačí kláves BREAK.
; Blocks of memory, and an error handler of our ownBYTEARRAYa(10), b(10)
PROCShow(BYTEARRAYt)
BYTEiFORi=0TO9DOPrintB(t(i)) Put(' )
ODPutE()
RETURNPROCMyError(BYTEcode)
PutE()
Print("Something went wrong, error ")
PrintBE(code)
IFcode=170THENPrintE("The file does not exist.")
FIRETURNPROCMain()
Zero(a, 10) ; ten bytes of zerosPrint("Zero: ") Show(a)
SetBlock(a, 10, 7) ; ten bytes with the value 7Print("SetBlock: ") Show(a)
a(0)=1a(1)=2a(2)=3MoveBlock(b, a, 10) ; copy ten bytes from a to bPrint("MoveBlock: ") Show(b)
Error=MyError; from now on errors call MyErrorOpen(1, "D:MISSING.TXT", 4, 0)
Close(1)
PrintE("The program goes on.")
RETURN
Zero(a, 10) – desať núl. Hodí sa pred každým použitím poľa počítadiel.
SetBlock(a, 10, 7) – desať sedmičiek.
MoveBlock(b, a, 10) – pole b je kópiou poľa a. Takto sa kopírujú polia; priradenie b=a nefunguje (kapitola 18).
Error=MyError – od tohto riadka chyby neukončia program. Open neexistujúceho súboru zavolá MyError(170), tá vypíše hlásenie a po jej RETURN program ide ďalej.
Vlastná obsluha chýb má jednu povinnosť: program po nej beží ďalej, aj keď sa operácia nepodarila. Tu sa súbor neotvoril, takže čítať z neho nemá zmysel. Skutočný program si preto v obsluhe poznačí, že nastala chyba (do globálnej premennej), a za rizikovou operáciou sa na ňu pozrie:
Action!
BYTEfailedPROCMyError(BYTEcode)
failed=codeRETURN
…
failed=0Open(1, "D:DATA.TXT", 4, 0)
IFfailedTHENPrintE("Cannot open the file.")
ELSE
… ; čítaj súborClose(1)
FI
Doteraz si z prekladača používal tri veci: action26 program.act, --sim a --run. Táto kapitola prejde ostatné voľby. Od tejto kapitoly ide o veci, ktoré pôvodný Action! na Atari nemal.
Pri väčšom programe, napríklad textovke, sa hodí vedieť, či sa ešte zmestí ďalší text. --memory to po preklade napíše:
action26: memory [######################--------] 76 % full
used by the program: 35121 bytes
still free: 11215 bytes
biggest free piece: 5826 bytes (a new text or routine has to fit into one piece)
free under the ROM: 1380 bytes (biggest piece 1060)
Voľná pamäť je rozdelená na kúsky. Nový text alebo rutina sa musí zmestiť do jedného, preto je dôležité hlavne číslo „biggest free piece“. Počíta sa po preklade, takže pamäť, ktorú program alokuje až za behu, v ňom nie je. Polia deklarované na pevnej adrese (ARRAY a(256)=$0700) sa započítajú samé. Buffery, ktoré program používa len za behu a nemá ich ako polia, povedz cez --reserve, napríklad --reserve $A100-$B7BF; inak by sa počítali ako voľné. Rozsah, v ktorom sa počíta, zúž cez --mem-lo a --mem-top.
Pamäť pod ROM ($C000–$CFFF a $D800–$FFF9) a v bankách program zvyčajne využíva na texty a tabuľky; jej voľné miesto je v prehľade na samostatnom riadku, lebo je to iný kus pamäte ako hlavná RAM.
Chceš vidieť, kde presne sú voľné kúsky, použi --memory-map. Každý kúsok je na vlastnom riadku, s adresou od–do:
Pri väčšom programe si podľa toho nájdeš diery, ktoré sa dajú vyplniť, a vidíš aj hranicu, od ktorej voľné miesto pokračuje až po koniec pamäte (tam sa dá umiestniť halda pre Alloc/Free).
spustí program vo vstavanom simulátore; klávesnica je klávesnica tvojho počítača
--sim-stats
ako --sim, na konci vypíše počet vykonaných inštrukcií
--sim-limit n
simulátor skončí najneskôr po n miliónoch inštrukcií (predvolene 10)
--sim-mem druh
akú pamäť má simulovaný počítač: 64, 130xe a väčšie (kapitola 38)
--run
spustí program v emulátore atari800
--emulator súbor
kde je atari800.exe, ak nie je v priečinku atari800 vedľa prekladača
Čo simulátor vie a čo nie:
Vie
Nevie
výpis textu a vstup z klávesnice
kresliť obrazovku, farby, grafické režimy
súbory na D: (len v pamäti, počas behu)
zvuk
výpočty, polia, reťazce, ukazovatele
joystick a paddle
rozšírenú pamäť (--sim-mem)
náhodné čísla (Rand vracia stále to isté)
časovač na adrese 20
Simulátor je rýchly spôsob, ako skúšať logiku programu. Na všetko, čo má byť vidieť a počuť, je emulátor.
--sim-stats sa hodí na porovnanie dvoch verzií programu – ktorá je rýchlejšia:
Bash
action26for.act--sim-stats
action26: 6900 instruction(s) executed
Program, ktorý beží dlhšie ako desať miliónov inštrukcií, simulátor zastaví hlásením instruction limit reached. Ak to nie je nekonečná slučka, limit zväčši: --sim-limit 100.
; A name given on the command line: action26 stars-count.act -D COUNT=7PROCMain()
BYTEiFORi=1TOCOUNTDOPut('*)
ODPutE()
RETURN
Bash
action26stars-count.act-DCOUNT=7--sim
*******
Bez -D prekladač ohlási error ACT008: undeclared name 'COUNT'. Hodí sa to, keď z jedného zdrojáka robíš viac verzií programu – skúšobnú a ostrú, anglickú a slovenskú.
Program sa správa vo všetkých troch prípadoch rovnako, líši sa veľkosť a rýchlosť. Pre for.act z kapitoly 13: 665 bajtov s -O0, 612 s -O1 a 589 s -O2.
-O0 má zmysel, keď porovnávaš výsledok s pôvodným prekladačom alebo keď program obsahuje strojový kód, ktorý sa spolieha na presný tvar okolitého kódu.
zakóduje výsledný súbor, aby sa v ňom nedalo nič prečítať
--scramble-fx meno
to isté, a kým sa program po nahratí dekóduje, na obrazovke beží efekt
--scramble-level číslo
to isté, s úrovňou zakódovania: 1 (predvolená) alebo silnejšia 2
--scramble-key číslo
kľúč, od ktorého sa kóduje (napríklad $3A7F); s ním dá každý preklad rovnaký súbor
Texty, ktoré program vypisuje, ležia v súbore XEX tak, ako si ich napísal. Kto súbor otvorí v editore, prečíta si ich – pri textovej hre aj riešenie. Súbor examples/secret.act:
Action!
; A file nobody can read: action26 secret.act --scramblePROCMain()
PrintE("The password is SESAME.")
RETURN
Prelož ho najprv obyčajne a nechaj Windows pohľadať v súbore slovo SESAME:
Bash
action26secret.actfindstr/mSESAMEsecret.xex
secret.xex
findstr /m vypíše meno súboru, v ktorom slovo našiel. Teraz to isté s --scramble:
Hotový program prekódoval bajt po bajte a pridal k nemu krátky dekodér. Ten sa po nahratí súboru spustí ako prvý, vráti pamäť do pôvodného stavu a až potom spustí tvoj program. V zdrojáku nemeníš nič a program o dekodéri nevie. Aj samotný dekodér je v súbore zakódovaný: pred ním leží krátky prvý stupeň (24 bajtov), ktorý ho pri prvom zavolaní rozkóduje na mieste. Zo súboru sa tak nedá prečítať ani kód dekodéra, ani jeho kľúč.
Súbor je dlhší asi o 110 bajtov – tu 399 namiesto 287.
Pamäť programu sa nezmenšila. Dekodér leží mimo neho, na adrese $0600 (ak tam program sám niečo nahráva, tak hneď za programom), a po štarte ho program môže pokojne prepísať.
Štart trvá o chvíľu dlhšie. Hra s 26 kilobajtmi sa dekóduje asi pol sekundy.
Nie je to ochrana. Kto program spustí v emulátore, vidí v jeho pamäti všetko už dekódované. Zakódovanie bráni len tomu, aby si texty niekto prečítal priamo zo súboru.
Bežné --scramble kóduje každý bajt pomocou bajtu pred ním. Je to rýchle a dekodér je krátky, no kto ten postup pozná, napíše si program, ktorý súbor rozkóduje bez spúšťania. Voľba --scramble-level vyberá úroveň zakódovania:
Úroveň
Ako kóduje
Dekodér
26 KB trvá
1
každý bajt XOR bajt pred ním (predvolená, to isté ako --scramble)
108 bajtov
0,50 s
2
každý bajt XOR číslo z 16-bitového generátora pseudonáhodných čísel (LFSR)
+12
asi 0,9 s
Bash
action26secret.act--scramble-level2
--scramble-level už znamená --scramble, oboje písať netreba. Efekty fungujú rovnako, napríklad --scramble-level 2 --scramble-fx bars.
Pri úrovni 2 čísla, ktorými sa bajty kódujú, vôbec nezávisia od programu a generátor beží bez prerušenia cez celý súbor – v súbore do 64 KB sa teda nikde neopakujú. Kto ich chce odstrániť, musí generátor napodobniť a poznať číslo, od ktorého začína – kľúč. Bez voľby --scramble-key si prekladač pri každom preklade vyberie nový náhodný kľúč, takže ten istý zdroják dá zakaždým iný súbor. Ak chceš, aby bol súbor pri každom preklade rovnaký (napríklad na porovnanie dvoch verzií), kľúč zadaj sám:
Kľúč je číslo od $0001 do $FFFF; nula nejde, generátor by z nej vyrábal len nuly. Pri úrovni 1 je kľúč jeden bajt od $01 do $FF, bez voľby platí $A7.
Kľúč ani tu nie je v súbore čitateľne, dekodér je zakódovaný rovnako ako pri úrovni 1. Čitateľný ostane len prvý stupeň a tabuľka, ktoré úseky pamäte sa majú dekódovať.
Ani úroveň 2 nie je ochrana: emulátor ukáže pamäť už dekódovanú a kto prvý stupeň pochopí, dostane sa ďalej. Len to dá podstatne viac práce.
Pol sekundy, počas ktorej sa na obrazovke nič nedeje, vyzerá ako zaseknutý počítač. Staré programy na Atari preto pri rozbaľovaní kreslili pruhy. --scramble-fx meno zakóduje súbor rovnako ako --scramble a pridá do dekodéra efekt:
Bash
action26secret.act--scramble-fxbars--run
Efekt uvidíš len v emulátore (--run) alebo na skutočnom Atari – simulátor (--sim) obrazovku nekreslí. Pri takom malom programe iba preblikne; poriadne ho vidno pri programe s desiatkami kilobajtov.
Meno
Čo je na obrazovke
Dekodér
26 KB trvá
none
nič – to isté ako --scramble
+0 bajtov
0,50 s
bars
farebné pásy cez celú obrazovku
+6
0,68 s
bars-border
farebné pásy len na okrajoch
+3
0,58 s
mono
čiernobiele pásy cez celú obrazovku
+8
0,72 s
mono-border
čiernobiele pásy na okrajoch
+5
0,64 s
rainbow
pravidelná dúha cez celú obrazovku
+6
0,68 s
rainbow-border
dúha na okrajoch
+3
0,58 s
slow
široké pomalé pásy cez celú obrazovku
+6
0,50 s
slow-border
široké pomalé pásy na okrajoch
+3
0,50 s
dots
bodky po celej obrazovke – znaky sa zmenia na zrnenie
+3
0,58 s
dots-bars
bodky a farebné pásy naraz
+9
0,76 s
blank
obrazovka zhasne, nič sa nekreslí
+20
0,36 s
bars-blank
obrazovka zhasne, farebné pásy cez celú plochu
+23
0,42 s
inc
obrazovka zhasne, biele čiarky na tmavočervenej ploche
+28
0,48 s
inc-border
biele čiarky na tmavočervených okrajoch
+8
0,66 s
Ako si vybrať:
Čo najrýchlejší štart:blank. Zhasnutá obrazovka neberie procesoru čas, preto je dekódovanie rýchlejšie než úplne bez efektu.
Efekt zadarmo:slow a slow-border. Farbu menia len raz za 256 bajtov, takže nič nespomalia.
Nech obrazovka ostane čitateľná: varianty -border kreslia len do okrajov; text v strede ostane, ako bol.
Ako za starých čias:bars alebo inc – ten kreslí to, čo rozbaľovač Super Packer.
Tri veci, ktoré je dobré vedieť:
„Celá obrazovka“ platí pre bežnú textovú obrazovku, na ktorej sa program nahráva. dots je vidno len v textových režimoch.
Farby aj znaky sa po dekódovaní vrátia samy, program nemusí nič upratovať.
Pri programe s dátami v skrytej pamäti (kapitola 38) beží dekodér po kúskoch počas celého nahrávania. Efekty so zhasnutou obrazovkou (blank, bars-blank, inc) vtedy blikajú.
Voľbu si program môže niesť v sebe, riadkom ;@compile --scramble-fx bars na začiatku zdrojáka (kapitola 33). Rovnako ;@compile --scramble-level 2 --scramble-key $3A7F.
zbalí výsledný súbor; Atari si ho počas nahrávania samo rozbalí
Disketová mechanika Atari je pomalá. Kratší súbor sa preto nahrá rýchlejšie a na disketu sa ich zmestí viac. Starí programátori na to mali programy ako Super Packer; v Action26 stačí voľba. Program pm-lanes.act z kapitoly 42:
Bash
action26pm-lanes.act--pack-xex--verbose
action26: packed 1 segments, loader at $0600 (180 bytes), buffer at $294D, file 2393 -> 1959 bytes
Súbor sa skrátil z 2393 bajtov na 1959. Spúšťa sa rovnako ako predtým (--run, z DOS-u, z diskety s autorunom) a program o zbalení nevie.
Každý kus programu zbalil (formátom ZX02, ktorý poznáš z PACK ZX02 v kapitole 39) a pridal krátky rozbaľovač so 180 bajtmi. DOS najprv nahrá rozbaľovač, potom zbalený kus a hneď ho zavolá; rozbaľovač kus rozbalí na jeho miesto. Až keď je všetko rozbalené, spustí sa tvoj program.
Pamäť programu sa nezmenšila. Rozbaľovač leží na adrese $0600 (ak tam program sám niečo nahráva, tak za programom) a zbalené dáta za programom. Oboje treba len počas nahrávania, po štarte ich program môže pokojne prepísať.
Funguje s hocijakým DOS-om, aj s dátami v skrytej pamäti (kapitola 38) – aj tie sa zbalia.
Malému programu nepomôže. Rozbaľovač má 180 bajtov, takže secret.act z predchádzajúcej časti by narástol z 287 na 455 bajtov. Oplatí sa to až pri programoch s niekoľkými kilobajtmi, hlavne s textami a obrázkami, ktoré sa dobre balia.
Voľbu si program môže niesť v sebe riadkom ;@compile --pack-xex (kapitola 33).
Teraz findstr nenájde nič. Prekladač najprv zbalí a potom zakóduje zbalené dáta; rozbaľovač ich pri nahrávaní najprv rozkóduje a potom rozbalí. Funguje to s oboma úrovňami aj s kľúčom (--scramble-level 2, --scramble-key), len efekty --scramble-fx so zbalením nejdú. Rozbaľovač narastie na 231 bajtov (s úrovňou 2 na 245).
Zakódujú sa všetky kusy programu, ktoré sa dajú zbaliť, aj keď sa zbalením neskrátia. Čitateľné ostanú len drobnosti: adresa štartu a nastavenia pod adresou $0400, napríklad farby.
upozorní na všetko, čo by pôvodný Action! odmietol
--quirks
napodobní aj známe chyby pôvodného prekladača
--wextra
ďalšie upozornenia – napríklad volanie s menším počtom argumentov
--werror
upozornenia sú chyby: program s varovaním sa nepreloží
--max-errors n
po koľkých chybách prestať (predvolene 20)
--verbose
vypíše, čo prekladač robí: veľkosť, adresy
--strict použi, keď má tvoj program bežať aj v pôvodnom Action! na skutočnom Atari.
--quirks použi, keď prekladáš starý program, ktorý sa spolieha na chyby originálu, a potrebuješ, aby sa správal presne ako kedysi. Vylučuje sa s --modern.
--wextra --werror je dobrá dvojica pre vlastné programy: prekladač je prísnejší a nedovolí varovania prehliadať.
-o mení meno výstupu, --listing ukáže preložený kód.
--sim je na logiku, --run na všetko, čo má byť vidieť a počuť.
-I pridáva priečinky pre INCLUDE, -D zavádza mená.
Predvolená optimalizácia -O2 je najlepšia; -O0 napodobňuje originál.
--scramble urobí súbor nečitateľným za cenu asi 110 bajtov a pol sekundy pri štarte; --scramble-fx k tomu pridá efekt na obrazovke a --scramble-level 2 silnejšie kódovanie s náhodným alebo zadaným kľúčom.
--pack-xex zbalí súbor, aby sa rýchlejšie nahral; oplatí sa pri programoch s niekoľkými kilobajtmi. S --scramble sa zbalené dáta aj zakódujú.
--strict stráži zlučiteľnosť s pôvodným Action!, --modern zapína rozšírenia.
--memory po preklade povie, koľko pamäte ešte ostáva a aký veľký je najväčší voľný kus; --memory-map ukáže každý kúsok po adresách, --reserve povie, čo si program zaberá za behu.
Program, ktorý potrebuje voľbu --modern alebo inú adresu, by si musel pamätať každý, kto ho prekladá. Lepšie je, keď si to program povie sám. action26 číta nastavenia z komentárov na začiatku zdrojáka.
Sú to komentáre – pôvodný Action! ich preskočí a program sa ním dá preložiť ďalej.
; Settings written in the source;;@strict ; warn about everything the original Action! refuses;@ORG $5000 ; put the program at address $5000PROCMain()
Print("This program starts at address ")
PrintCE(Main)
RETURN
;@compile berie voľby v rovnakom tvare ako príkazový riadok. Riadkov môže byť viac:
Action!
;@compile --modern -O1;@compile -I lib -D COUNT=7
Povolené sú len voľby, ktoré menia preklad: -I, -D, --set, --org, -O0/-O1/-O2, --max-errors, --initad, --scramble, --scramble-fx, --scramble-level, --scramble-key, --pack-xex, --case-sensitive, --quirks, --modern, --strict, --wextra, --werror.
Hodí sa to na všetko, čo má pre daný program platiť vždy. Hra, ktorej texty nemá nikto čítať zo súboru, si napríklad zakódovanie aj s efektom pýta sama (kapitola 32, časť Nečitateľný súbor):
Action!
;@compile --scramble-fx bars
Hra na diskete, ktorá sa má rýchlo nahrať a zároveň nemá prezradiť texty, si pýta zbalenie aj zakódovanie (kapitola 32, časť Zbalený a zakódovaný):
Action!
;@compile --pack-xex --scramble
Voľby, ktoré zapisujú súbory alebo niečo spúšťajú (-o, --listing, --atr, --run, --sim …), v zdrojáku nie sú dovolené. Stiahnutý cudzí program tak nemôže pri preklade prepísať súbor ani nič spustiť.
Cesta v -I sa berie od priečinka, kde zdroják leží – nie od miesta, odkiaľ prekladač spúšťaš.
Skutočné Atari nahráva programy z diskety. Emulátory a moderné náhrady disketových jednotiek používajú namiesto diskety obraz – jeden súbor s príponou .atr, v ktorom je celý obsah diskety. action26 vie s takými súbormi pracovať priamo: uložiť na ne program, vypísať obsah, kopírovať súbory tam a späť.
Kapitola nemá program v Action!. Sú v nej príkazy, ktoré si môžeš vyskúšať s programom hello-key.act z kapitoly 2.
Samotné Atari disketám nerozumie. Program, ktorý ho to naučí, sa volá DOS (Disk Operating System) a je na diskete. Po zapnutí si ho Atari z diskety nahrá – tomu sa hovorí bootovanie. Až potom existuje zariadenie D:.
Z toho plynie: disketa, z ktorej má Atari naštartovať, musí obsahovať DOS. DOS-ov je viac druhov (Atari DOS 2.5, MyDOS, SpartaDOS …); action26 pozná najbežnejšie. Obraz diskety s DOS-om si treba zaobstarať – sú voľne dostupné na stránkach o Atari.
Prekladač program preloží a uloží na disketu dos25.atr tak, aby sa po naštartovaní sám spustil. Na diskete s Atari DOS 2.5 to znamená súbor AUTORUN.SYS:
action26: stored AUTORUN.SYS on dos25.atr (DOS 2, single density, Atari DOS 2)
(Túto správu vypíše s voľbou --verbose.) S --run sa disketa hneď spustí v emulátore:
Bash
action26hello-key.act--atrdos25.atr--run
Toto je spôsob, ako spúšťať programy, ktoré pracujú so súbormi (kapitola 30).
Pracuj na kópii.--atr do obrazu diskety zapisuje. Pôvodný obraz s DOS-om si odlož a pre každý projekt si sprav kópiu.
Ak súbor .atr neexistuje, prekladač vytvorí novú prázdnu disketu a program na ňu uloží. Taká disketa však nemá DOS a Atari z nej nenaštartuje. Prekladač to povie:
action26: note: my.atr has no DOS, so the program does not start by itself; copy a DOS disk (DOS 2, MyDOS, WolfDOS, SpartaDOS, BW-DOS, LiteDOS) and use that with --atr to get a bootable disk
dos25.atr: DOS 2, single density (720 sectors of 128 bytes), Atari DOS 2 boots
DOS SYS 037
DUP SYS 042
RAMDISK COM 009
SETUP COM 070
COPY32 COM 056
DISKFIX COM 057
FILECOPY COM 025
AUTORUN SYS 004
8 file(s), 407 free sector(s)
Prvý riadok hovorí druh diskety a či sa z nej dá naštartovať. Číslo za menom súboru je jeho veľkosť v sektoroch – disketa je rozdelená na sektory po 128 bajtoch.
Textový súbor na Atari sa od textového súboru na PC líši koncom riadka. Na PC je to dvojica znakov (CR a LF), na Atari jeden znak s kódom 155 ($9B). Ostatné bežné znaky sú rovnaké.
Zdroják si action26 prečíta v oboch tvaroch. Prevod potrebuješ, keď má textový súbor čítať program na Atari, alebo keď chceš zdroják poslať niekomu, kto ho otvorí v pôvodnom Action!.
Z PC na Atari:
Bash
action26--to-atasciinotes.txtNOTES.ATA
Z Atari na PC:
Bash
action26--to-textNOTES.ATAnotes2.txt
Bez druhého mena dostane výsledok príponu .ACT, resp. .txt. Vstupný súbor sa nikdy neprepíše.
Jazyk Action! je z roku 1983 a niektoré veci, ktoré sú dnes bežné, v ňom chýbajú. action26 ich vie doplniť. Sú vypnuté, kým si o ne nepovieš – starý program sa tak nikdy nepokazí tým, že má napríklad premennú menom CASE.
Rozšírenia zapneš riadkom na začiatku zdrojáka:
Action!
;@modern
alebo voľbou --modern na príkazovom riadku. Program s rozšíreniami pôvodný Action! nepreloží. Ak má tvoj program bežať aj v ňom, túto a ďalšie kapitoly nepoužívaj.
Každé rozšírenie má v tejto kapitole vlastný krátky program. Všetky sa prekladajú rovnako – ;@modern si nesú v sebe:
DEFINE z kapitoly 17 nahrádza text a má pascu: DEFINE SIZE="5+5" a SIZE*2 dá 15. CONST je pomenovaná hodnota: prekladač ju vypočíta raz a ďalej s ňou narába ako s číslom.
;@modern; CONST: named values worked out by the compilerCONSTWIDTH=20, HEIGHT=3CONSTCELLS=WIDTH*HEIGHT; a constant may use earlier onesCONSTSIZE=5+5CONSTCHARFRAME='#PROCMain()
BYTEx, yFORy=1TOHEIGHTDOFORx=1TOWIDTHDOPut(FRAME)
ODPutE()
ODPrint("Cells: ")
PrintBE(CELLS)
Print("SIZE*2: ")
PrintBE(SIZE*2) ; 20 - with DEFINE it would be 15RETURN
CELLS je 60 už pri preklade – v programe sa nič nenásobí. SIZE*2 je 20, lebo SIZE je hodnota 10, nie text 5+5. Konštanta nezaberá pamäť a nedá sa do nej priradiť.
Stav semaforu, smer pohybu, druh nepriateľa – veci, ktoré majú niekoľko pevných možností. S číslami (0 = červená, 1 = zelená) sa ľahko pomýliš. ENUM dá možnostiam mená a prekladač stráži, aby sa nepomiešali s obyčajnými číslami.
;@modern; ENUM: a type of your own with named valuesTYPELight=ENUM [RED, GREEN, YELLOW]
LightFUNCNext(Lightnow)
IFnow=Light.REDTHENRETURN(Light.GREEN)
FIIFnow=Light.GREENTHENRETURN(Light.YELLOW)
FIRETURN(Light.RED)
PROCShow(Lightl)
CASElOFWHENLight.REDTHENPrintE("red - stop")
WHENLight.GREENTHENPrintE("green - go")
WHENLight.YELLOWTHENPrintE("yellow - wait")
ESACRETURNPROCMain()
Lightl=[Light.RED]
BYTEiFORi=1TO5DOShow(l)
l=Next(l)
ODPrint("The last value as a number: ")
PrintBE(BYTE(l))
RETURN
red - stop
green - go
yellow - wait
red - stop
green - go
The last value as a number: 2
Light sa používa ako každý typ: pre premennú, parameter aj výsledok funkcie. Prekladač nedovolí l=1 ani PrintB(l) – hodnota typu Light nie je číslo. Keď číslo naozaj potrebuješ, povieš to výslovne: BYTE(l). Opačne Light(2) spraví z čísla člen.
CASE výraz OFWHENhodnotaTHEN
príkazy
WHENhodnota1, hodnota2THEN; viac hodnôt
príkazy
WHENodTOdoTHEN; rozsah vrátane hraníc
príkazy
WHENodTOdoIFpodmienkaTHEN; rozsah a navyše podmienka
príkazy
ELSE
príkazy ; keď nesedelo ničESAC
Vykoná sa prvá vetva, ktorá sedí, a žiadna ďalšia. ELSE je nepovinné. ESAC (CASE odzadu) príkaz končí.
;@modern; CASE: choose one branch by a valuePROCDescribe(BYTEn)
PrintB(n)
Print(": ")
CASEnOFWHEN0THENPrintE("zero")
WHEN1TO9THENPrintE("one digit")
WHEN10, 100THENPrintE("ten or a hundred")
WHEN11TO99IFnMOD11=0THENPrintE("two digits, both the same")
WHEN11TO99THENPrintE("two digits")
ELSEPrintE("a big number")
ESACRETURNPROCMain()
Describe(0)
Describe(7)
Describe(10)
Describe(33)
Describe(42)
Describe(100)
Describe(200)
RETURN
0: zero
7: one digit
10: ten or a hundred
33: two digits, both the same
42: two digits
100: ten or a hundred
200: a big number
Číslo 33 sedí do rozsahu 11 TO 99 a spĺňa aj podmienku za IF (je deliteľné jedenástimi), takže sa vykoná prvá z dvoch vetiev. Číslo 42 do rozsahu sedí, ale podmienku nespĺňa – ide sa na ďalšiu vetvu. Podmienke pri WHEN sa hovorí stráž.
Prekladač stráži aj teba: keby sa tá istá hodnota vyskytla v dvoch vetvách bez stráže, druhá by sa nikdy nevykonala – a to je chyba prekladu (ACT234).
V pôvodnom Action! patrí porovnanie len do podmienky. S rozšíreniami je porovnanie aj hodnota – 1, keď platí, 0, keď neplatí. Hodnotou môže byť aj celý IF a CASE. A pretypovanie povie, v akom type sa má počítať.
;@modern; Comparisons, IF and CASE as values, and castsPROCMain()
CHARARRAYtext="one, two, three, four"BYTEa, b, bigger, commas, iCHARgradeCARDsuma=7b=12bigger=IFa>bTHENaELSEbFI; IF as a valuePrint("The bigger one: ")
PrintBE(bigger)
commas=0FORi=1TOtext(0)
DOcommas==+(text(i)=',) ; a comparison is 1 or 0ODPrint("Commas in the text: ")
PrintBE(commas)
grade=CASEbOF; CASE as a valueWHEN0TO4THEN 'CWHEN5TO9THEN 'BELSE 'AESACPrint("Grade: ")
Put(grade)
PutE()
a=200b=100sum=a+b; BYTE + BYTE overflowsPrint("200 + 100 as BYTE: ")
PrintCE(sum)
sum=CARD(a)+b; the cast makes it a CARD sumPrint("200 + 100 with CARD(a): ")
PrintCE(sum)
RETURN
The bigger one: 12
Commas in the text: 3
Grade: A
200 + 100 as BYTE: 44
200 + 100 with CARD(a): 300
Šachovnica, mapa hry, tabuľka – dáta, ktoré majú riadky a stĺpce. V pôvodnom Action! sa to robí jedným dlhým poľom a výpočtom indexu riadok*šírka+stĺpec. S rozšírením napíšeš dva indexy a výpočet spraví prekladač.
Dve vnorené slučky – vonkajšia po riadkoch, vnútorná po stĺpcoch – sú bežný spôsob, ako prejsť celú tabuľku. V pamäti ležia prvky riadok za riadkom: grid(r,c) je prvok číslo r*COLS+c.
Počiatočné hodnoty sa píšu ako jeden rad v tomto poradí:
Action!
BYTEARRAYglider(3,3)=[010001111]
Na rozdiel od jednorozmerných polí tu prekladač stráži aspoň to, čo vie: nesprávny počet indexov a index daný číslom mimo rozmeru sú chyby prekladu (ACT238). Index z premennej sa nekontroluje ani tu.
Keď pole odovzdáš rutine ako parameter, rutina dostane len adresu a vidí ho ako jednorozmerné.
Niektoré znaky sa do zdrojáka nedajú napísať z klávesnice PC: koniec riadka uprostred textu, inverzné písmo, pípnutie, pohyb kurzora. S rozšírením ich zapíšeš menom.
;@modern; Special characters written by namePROCMain()
Print("First line\{RETURN}Second line\{RETURN}")
Print("The letter with the code $41: \{$41}\{RETURN}")
IF 'A='\{$41} THENPrintE("'A and '\{$41} are the same character")
FIRETURN
Bash
action26m-escapes.act--sim
First line
Second line
The letter with the code $41: A
'A and 'A are the same character
Jeden Print vypíše dva riadky, lebo text obsahuje koniec riadka. Text s \{RETURN} vypisuj cez Print, nie PrintE: PrintE skončí pri prvom konci riadka, ktorý v texte nájde.
Inverzné písmo, pípnutie a pohyb kurzora uvidíš a počuješ len v emulátore – skús Print("\{CLEAR}\{INV: TITLE }\{BELL}").
Reťazec v Action! má najviac 255 znakov, lebo jeho dĺžka je v jednom bajte. Úvodný text hry alebo návod býva dlhší. PrintU vypisuje text, ktorý nemá dĺžkový bajt a končí dohodnutým znakom.
Druhý parameter je ukončovací znak – taký, ktorý sa v texte nevyskytuje. Keď je text napísaný priamo vo volaní, prekladač ukončovací znak na jeho koniec doplní sám. Tretí, nepovinný parameter obmedzí počet vypísaných znakov.
PrintUD(kanál, …) robí to isté na kanál (kapitola 30).
;@modern; PrintU: a text longer than 255 charactersPROCMain()
PrintU("Action! was written by Clinton Parker and published by Optimized Systems Software in 1983. It came on a cartridge with an editor, a compiler and a monitor. Programs in Action! run many times faster than programs in Atari BASIC, and they are far shorter than the same programs written in assembler.", '~)
PutE()
RETURN
Bash
action26m-longtext.act--sim
Action! was written by Clinton Parker and published by Optimized Systems Software in 1983. It came on a cartridge with an editor, a compiler and a monitor. Programs in Action! run many times faster than programs in Atari BASIC, and they are far shorter than the same programs written in assembler.
Text má 297 znakov – do obyčajného reťazca by sa nezmestil. PrintU ho vypisuje od začiatku, kým nenarazí na znak ~. Rovnako vypíše text, ktorý program načítal zo súboru do poľa, ak si na jeho koniec zapíše ukončovací znak.
37. Miesto v pamäti a assembler: ORG, ENDORG, ALIGN, ASM … ENDASM#
Rozšírenia action26 pre tých, ktorí chcú rozhodovať o tom, kde v pamäti veci ležia, a písať kúsky programu priamo v assembleri. Programy začínajú riadkom ;@modern (kapitola 35).
Kapitola nadväzuje na 24 (pamäť) a 25 (strojový kód).
Prekladač ukladá premenné tam, kde je program. Niekedy chceš inak:
Nultá stránka (adresy 0 až 255) je najrýchlejšia pamäť procesora 6502. Premenná v nej robí slučky rýchlejšími a ukazovateľ v nej prekladač použije priamo.
Hardvér Atari niektoré dáta chce na konkrétnych adresách.
Vlastná znaková sada musí začínať na adrese, ktorá je násobkom 1024. Pamäť pre pohyblivé objekty (hráčov a strely) na násobku 2048. ALIGN posunie nasledujúcu premennú na najbližšiu takú adresu.
;@modern; ORG and ALIGN: choosing where variables liveORG$CB; the zero page: the fastest memory there isBYTEfastCARDaddressENDORGBYTEnormal; back where the program isALIGN256; the next variable starts at a multiple of 256BYTEARRAYtable(16)
PROCMain()
PrintF("fast is at %H%E", @fast)
PrintF("address is at %H%E", @address)
PrintF("normal is at %H%E", @normal)
PrintF("table is at %H%E", table)
RETURN
Bash
action26m-org.act--sim
fast is at $00CB
address is at $00CC
normal is at $2000
table is at $2100
normal je za ENDORG, takže je znova pri programe – na jeho začiatku, $2000.
table by inak nasledovala hneď za normal ($2001). ALIGN 256 ju posunul na najbližší násobok 256, $2100. Preskočené bajty v súbore XEX nie sú.
ORG nie je to isté ako BYTE x=$CB z kapitoly 24. Tam si adresy každej premennej počítaš sám; v bloku ORG ich prekladač ukladá za sebou a stráži, aby sa neprekrývali.
Blok [ … ] z kapitoly 25 chce inštrukcie ako čísla. V bloku ASM sa píšu menami – tak, ako ich uvádzajú knihy o procesore 6502 – a dajú sa v ňom použiť mená premenných z programu.
;@modern; ASM: assembler instructions by name inside an Action! programBYTEcounterBYTEARRAYpage6(256)=$600PROCBump() ; add 1 to counterASMinccounterrtsENDASMPROCFillPage(BYTEvalue) ; fill the 256 bytes of page 6ASMldavalueldx#0loopsta$0600,xinxbnelooprtsENDASMPROCMain()
counter=5Bump()
Bump()
Print("counter: ")
PrintBE(counter)
FillPage(42)
Print("page6(0) and page6(255): ")
PrintB(page6(0))
Put(' )
PrintBE(page6(255))
RETURN
Procesor Atari vidí naraz 64 kilobajtov. Počítač má však pamäte viac, než program bežne vidí – na dvoch miestach:
1. RAM pod ROM. Na adresách $C000–$FFFF je operačný systém v pamäti ROM. Počítače XL a XE majú na tých istých adresách aj obyčajnú pamäť RAM, len je zakrytá. Je to asi 14 kilobajtov, ktoré bežný program nevidí.
2. Banky. Atari 130XE má 128 kilobajtov. Druhých 64 je rozdelených na štyri banky po 16 kilobajtov. V jednej chvíli je vidieť jedna z nich, a to v „okne“ na adresách $4000–$7FFF, namiesto bežnej pamäte, ktorá tam inak je. Rozšírené počítače majú bánk 16 aj 64.
Prepínať medzi tým ručne je práca s registrom PORTB, zakazovaním prerušení a rizikom, že si program odpojí pamäť pod vlastnými nohami. Rutiny action26 to robia za teba.
;@modern; Hidden memory: the banks of a 130XE and the RAM under the ROMPROCMain()
BYTEbanks, ibanks=XBanks()
Print("Banks of extended memory: ")
PrintBE(banks)
IFbanks=0THENPrintE("This program needs a 130XE.")
RETURNFIFORi=1TObanks; the same address in each bankDOXPoke(i, $4000, i*10)
ODPrint("Address $4000 in the banks: ")
FORi=1TObanksDOPrintB(XPeek(i, $4000))
Put(' )
ODPutE()
XPoke(0, $C000, 99) ; bank 0 is the ordinary memory, also under the ROMPrint("XPeek sees the RAM under the ROM: ")
PrintBE(XPeek(0, $C000))
RETURN
XBanks() zistí, koľko bánk počítač má. Vždy sa najprv opýtaj – program, ktorý siahne do banky, ktorá neexistuje, skončí chybou 101.
Slučka zapíše na tú istú adresu$4000 v každej banke inú hodnotu. Druhá slučka ich prečíta späť: sú štyri rôzne. To je dôkaz, že ide o štyri rôzne kusy pamäte.
XPoke(0, $C000, 99) zapíše do RAM pod operačným systémom. Obyčajný Poke($C000, 99) by nespravil nič (zápis do ROM) a Peek($C000) by vrátil bajt operačného systému.
Dlhé texty a obrázky nemusia zaberať miesto v programe. S ORG adresa BANK n ich prekladač pripraví tak, že sa pri nahrávaní programu uložia rovno do banky.
;@modern; A text loaded into a bank together with the programORG$4000BANK1CHARARRAYstory="Once upon a time there was an Atari with twice the memory of the others. The upper half was hidden, and only those who knew the right register could reach it.~"ENDORGPROCMain()
IFXBanks()=0THENPrintE("This program needs a 130XE.")
RETURNFIPrint("The text lives in bank ")
PrintBE(BankOf(story))
XPrint(BankOf(story), story, '~)
PutE()
RETURN
Bash
action26m-bankdata.act--sim--sim-mem130xe
The text lives in bank 1
Once upon a time there was an Atari with twice the memory of the others. The upper half was hidden, and only those who knew the right register could reach it.
Veľké dáta sa dajú dať do samostatného súboru, aby sa program pri vývoji nahrával rýchlo:
Bash
action26m-bankdata.act--data-only-ostory.dat
Bash
action26m-bankdata.act--code-only-ostory.xex
Na Atari sa najprv nahrá story.dat (uloží dáta do banky a vráti sa), potom story.xex. Program s --code-only pri štarte skontroluje, či sú dáta nahrané, a ak nie, povie to a skončí.
XPeek a XPoke pri každom volaní banku zapnú a vypnú. Keď s bankou pracuješ dlhšie, je rýchlejšie nechať ju v okne:
Action!
BYTEARRAYwindow(16384)=$4000; pole na adrese oknaXBank(2) ; v okne je banka 2window(100)=7; obyčajný prístup do poľaXBank(0) ; späť bežná pamäť
Jedno pravidlo: kým je v okne banka, nesmie v okne ležať nič z tvojho programu – ani kód, ani premenné. Program od $2000 sa do okna ($4000) dostane, až keď prerastie 8 kilobajtov. Prekladač na to upozorní varovaním ACT242.
Hra potrebuje obrázky, mapy úrovní a texty. Prepisovať ich do zdrojáka ako čísla v hranatých zátvorkách je otrava. A keď ich je veľa, do pamäte Atari sa nezmestia.
FILE vloží do programu obsah súboru tak, ako je.
PACK ho vloží zbalený (komprimovaný) – zaberie menej a program si ho za behu rozbalí.
Zbalené texty šetria miesto pri hrách s množstvom textu.
BYTEARRAYmeno=FILE"súbor"BYTEARRAYmeno=FILE"súbor" odkiaľ koľko
Prekladač súbor prečíta pri preklade a jeho bajty sa stanú počiatočnými hodnotami poľa. Nepovinné čísla vyberú len časť súboru: od ktorého bajtu a koľko bajtov.
Súbor sa hľadá ako pri INCLUDE – vedľa zdrojáka a v priečinkoch z voľby -I.
;@modern; FILE: the bytes of a file become part of the programBYTEARRAYmotto=FILE"motto.txt"PROCMain()
PrintU(motto, '~) ; the text in the file ends with ~PutE()
RETURN
Po preklade je text súčasťou programu – na Atari už súbor motto.txt netreba. Pole motto má toľko prvkov, koľko mal súbor bajtov. Vypisuje sa cez PrintU (kapitola 36), lebo to nie je reťazec s dĺžkovým bajtom.
Najčastejšie sa takto vkladajú obrázky: BYTE ARRAY picture=FILE "title.mic" a potom MoveBlock do pamäte obrazovky.
PACK pred zdrojom dát povie prekladaču, aby ich uložil zbalené. Unpack ich za behu rozbalí na adresu kam a vráti, koľko bajtov rozbalil. Cieľ musí mať miesto na celé rozbalené dáta.
Spôsob balenia vyberie prekladač sám – ten, s ktorým je celý program najmenší. Dá sa aj predpísať: PACK RLE … alebo PACK ZX02 ….
240 bajtov sa zbalilo do 23. Dáta s dlhými úsekmi rovnakých bajtov – a také sú obrázky aj mapy – sa balia veľmi dobre.
Kedy sa to oplatí. K zbaleným dátam sa do programu pribalí rozbaľovacia rutina (asi 140 až 470 bajtov podľa spôsobu balenia). Pri 240 bajtoch dát je teda program so PACK v skutočnosti väčší ako s obyčajným FILE. Pri obrázku cez celú obrazovku je to naopak: 7680 bajtov sa zbalí na niekoľko stoviek. Prekladač to pri automatickom výbere počíta – keď sa balenie neoplatí, uloží dáta nezbalené.
Textová hra má desiatky viet, v ktorých sa opakujú tie isté slová. Zbalené texty ukladajú najčastejšie dvojice znakov do spoločného slovníka a v textoch ich nahrádzajú jedným bajtom.
CHARARRAYmeno=PACK"text"PrintPacked(meno) ; vypíšePrintPackedE(meno) ; vypíše a ukončí riadokPrintPackedE("text") ; text priamo vo volaní sa zbalí tiežUnpackText(meno, reťazec) ; rozbalí do obyčajného reťazca
;@modern; Packed texts: the words that repeat are stored onceCHARARRAYhall=PACK"You are in the hall of an old house. There is a door to the north."CHARARRAYkitchen=PACK"You are in the kitchen of an old house. There is a door to the south."PROCMain()
CHARARRAYplain(100)
PrintPackedE(hall)
PrintPackedE(kitchen)
PrintPackedE("You are in the garden of an old house. There is a door to the west.")
UnpackText(hall, plain) ; into an ordinary stringPrint("The first text has ")
PrintB(plain(0))
PrintE(" characters.")
RETURN
Bash
action26m-texts.act--sim
You are in the hall of an old house. There is a door to the north.
You are in the kitchen of an old house. There is a door to the south.
You are in the garden of an old house. There is a door to the west.
The first text has 66 characters.
action26: PACK texts: 3 text(s), 205 -> 121 bytes with the dictionary of 40 pair(s)
Tri vety majú spolu 205 znakov a zaberú 121 bajtov vrátane slovníka. Čím viac textov a čím viac sa v nich slová opakujú, tým väčšia úspora.
Zbalený text nie je reťazec Action!: Print, SCompare ani indexovanie s ním nefungujú. Vypisuje sa rutinami PrintPacked…; keď ho potrebuješ ako reťazec, rozbaľ ho cez UnpackText.
Texty hry sa pohodlnejšie píšu do obyčajného textového súboru, jeden text na riadok. Zbalí ho nástroj:
Bash
action26--pack-textrooms.txtrooms.ptx
action26: rooms.txt -> rooms.ptx (3 text(s), 68 -> 60 bytes, 13 pair(s) in the dictionary)
V programe:
Action!
BYTEARRAYrooms=FILE"rooms.ptx"UsePackedTexts(rooms) ; odteraz platí slovník tohto súboruPrintPackedE(PackedText(rooms, 2)) ; text číslo 2 (číslujú sa od 0)
UsePackedTexts(0) prepne späť na slovník textov napísaných v programe.
Hra s celými stovkami textov ušetrí ešte viac, keď ich zbalí vo formáte 2:
Bash
action26--pack-text2rooms.txtrooms.pt2
Formát 2 robí dve veci inak:
Kód dostanú len znaky, ktoré v textoch naozaj sú. Ostatné kódy idú na dvojice – a čím viac dvojíc, tým kratšie texty.
Súbor si nepamätá miesto každého textu, len každého šestnásteho. Ostatné nájde tak, že preskočí najviac 15 textov pred hľadaným.
V programe sa používajú rutiny s dvojkou na konci:
Action!
BYTEARRAYrooms=FILE"rooms.pt2"UsePackedTexts2(rooms) ; odteraz platia texty tohto súboruPrintPackedE(PackedText2(rooms, 2)) ; text číslo 2
UsePackedTexts2(0) prepne späť na texty napísané v programe. UsePackedTexts2 vezme aj súbor z obyčajného --pack-text; pre ten ostáva PackedText.
Kedy sa to oplatí? Rutiny formátu 2 sú o asi 200 bajtov väčšie a tabuľka znakov tiež niečo stojí, takže pár krátkych viet (ako v rooms.txt hore) vyjde vo formáte 2 dokonca väčších. Pri textoch celej hry je to naopak – napríklad 814 textov hry Ataristův protiútok zaberie 24 814 bajtov namiesto 26 726, o 7 % menej.
Takto zbalený súbor rozbalí na Atari tá istá rutina Unpack, keď ho program načíta do pamäte.
Keď meno výstupu končí na .w8p, vznikne súbor vo formáte W8P – formát obrázkov z programu mic2w8p, používaný v niektorých hrách. Na Atari ho rozbalia rutiny UnpackW8P(súbor, kam, najviac) z pamäte a UnpackW8PD(kanál, kam, najviac) z otvoreného súboru.
Pohyblivé postavičky v hrách na Atari väčšinou nie sú nakreslené do obrázka. Kreslí ich zvlášť obvod GTIA navrch obrazovky – hráči (players) a strely (missiles). Atari ich má osem:
4 hráči (0–3): úzke pásy široké 8 bodov a vysoké cez celú obrazovku,
4 strely (4–7 v rutinách action26): rovnaké pásy široké len 2 body; strela má farbu „svojho“ hráča (strela 0 hráča 0 …).
Hráč sa hýbe bez toho, aby pokazil obrázok pod sebou, a počítač sám povie, či do niečoho narazil (kapitola 41). Tomu, čo sa takto kreslí, sa hovorí Player/Missile grafika, skrátene PMG.
V pôvodnom Action! sa PMG robí zápismi do registrov (PMBASE, SDMCTL, GRACTL, HPOSP0 …) a treba vedieť, kde a ako zarovnať pamäť – ukážka examples/pmg.act. Action26 má na to rutiny, ktoré sa volajú rovnako ako v Action! Tool Kite.
;@modern; A ship that flies across the screen: player 0BYTEARRAYship=[$18$3C$7E$FF$DB$FF$24$42]
PROCMain()
BYTEx, y=[120]
PrintE("A ship made of player 0")
PMGraphics(1) ; players on, one line per bytePMCreate(0, ship, 8, 1, 48, y) ; player 0: 8 rows, width 1, x=48PMColor(0, 1, 10) ; yellowPrint("Its shape lives at ")
PrintCE(PMAdr(0)+y)
FORx=48TO200DOPMWait() ; one step per frameIFx&16THENy==+1ELSEy==-1FI; up and down in steps of 16PMMove(0, x, y)
ODPrint("The ship stopped at x=")
PrintB(PMX(0))
Print(", y=")
PrintBE(PMY(0))
RETURN
počká, kým sa nakreslí ďalší obraz (50 alebo 60-krát za sekundu)
PMX(n), PMY(n)
funkcie – kde objekt je
PMAdr(n)
funkcia – adresa pamäte hráča n
Súradnice sú tie, ktoré pozná hardvér, nie body obrazovky:
Rozsah
Viditeľné
x
0–255
asi 48–200 (hráč šírky 1); 48 je ľavý okraj textu
y pri PMGraphics(1) a (3)
0–255
asi 32–223; riadok textu r začína na 32 + 8*r
y pri PMGraphics(2)
0–127
asi 16–111
Mimo viditeľnej časti je objekt jednoducho skrytý – tak sa dá aj „schovať“.
Prečo PMWait. Obraz sa kreslí 50-krát za sekundu (v Amerike 60). Bez čakania by slučka prebehla celú obrazovku skôr, než by sa stihla ukázať.
Pamäť. Tvary hráčov číta obrazový čip z pamäte, ktorá musí začínať na násobku 2 KB (pri PMGraphics(2) a (3) 1 KB). Prekladač ju vyhradí sám za koniec programu – PMAdr(0) ukáže, kde je. --memory-map ju vypíše ako PMG. Kto ju chce mať inde (napr. v banke, kapitola 42), povie to pred PMGraphics rutinou PMMemory(pole).
Koniec programu hráčov vypne sám – aj keď program skončí chybou alebo klávesom RESET. Inak by loď ostala svietiť na obrazovke DOS-u.
;@modern; A bird that flaps its wings and glides down: PMShape and mode 3BYTEARRAYbird=[$81$C3$E7$7E$3C$18$00$00; wings up$00$18$3C$7E$E7$C3$81$00] ; wings downPROCMain()
BYTEframePMGraphics(3) ; two lines per byte, y in linesPMCreate(0, bird, 8, 2, 100, 40) ; double widthPMColor(0, 15, 10) ; orangeFORframe=0TO119DOPMWait()
IF (frame&7)=0THEN; another picture every 8 framesPMShape(0, bird+(frame&8), 8)
FIPMVPos(0, 40+frame) ; one line down every frameODPrint("The bird landed on line ")
PrintBE(PMY(0))
RETURN
Dva obrázky v jednom poli.bird má 16 bajtov: prvých 8 sú krídla hore, ďalších 8 dole. bird+8 je adresa druhého obrázka. frame&8 je striedavo 0 a 8, takže PMShape(0, bird+(frame&8), 8) mení obrázok každých 8 snímok – vták máva.
PMShape vymení tvar na tom istom mieste; PMVPos posunie objekt len zvisle, PMHPos(n, x) len vodorovne. Runtime si pamätá tvar a polohu, takže zmaže len riadky, ktoré objekt opustil – to je rýchle.
Šírka 2 (PMCreate(…, 2, …) alebo PMWidth(0, 2)) roztiahne každý bod na dvojnásobok; šírka 4 na štvornásobok.
PMGraphics(3). Pri dvoch riadkoch na bajt by sa hráč hýbal zvisle po dvoch riadkoch. Režim 3 počíta y po riadkoch a nepárne y doladí registrom VDELAY – pohyb je plynulý a pamäť stále polovičná.
kto je vpredu: 1 hráči nad všetkým, 4 obrázok nad hráčmi; +16 štyri strely ako piaty hráč, +32 viacfarebné hráče
PMMemory(pole)
vlastné miesto pre pamäť hráčov
PMGraphics(0)
vypne hráčov a strely
Mená čísel. Súbor examples/modern/HARDWARE.ACT (INCLUDE) má pre ne mená: PM_SINGLE, PM_DOUBLE, PM_WIDE, PRI_PLAYFIELD …
Graphics nechá hráčov zapnutých. Obrazový režim sa dá zmeniť aj počas hry; hráči ostanú na mieste.
Program si hráčov kreslí aj sám. Do pamäte z PMAdr(n) sa dá zapisovať ako do poľa (BYTE POINTER). Objekt, ktorý nemá tvar z PMCreate, sa potom pri PMMove posúva tak, že sa celý pás pootočí (ako v Tool Kite) – pomalšie, ale funguje.
Hra potrebuje vedieť, či strela trafila, či loď narazila do steny alebo do nepriateľa. Atari to vie samo: obvod GTIA si pri kreslení každého obrazu zapisuje, ktorý hráč alebo strela sa prekryl s ktorým hráčom a s ktorou farbou obrázka. Program tieto zrážky (collisions) len prečíta.
Druhá možnosť je spočítať zrážku v programe z polôh a rozmerov objektov. Obe majú svoje výhody – tento program ukazuje obe naraz.
;@modern; A rock falls on a ship: a collision from the hardware and from PMOverlapBYTEARRAYship=[$18$3C$7E$FF$FF$DB$81$81],
rock=[$3C$7E$FF$FF$FF$FF$7E$3C]
PROCMain()
BYTEy, hw=[0], sw=[0]
PMGraphics(1)
PMCreate(0, ship, 8, 1, 120, 180) ; the ship at the bottomPMCreate(1, rock, 8, 1, 120, 100) ; the rock above itPMColor(0, 1, 12)
PMColor(1, 2, 6)
PMWait()
HitClr()
FORy=101TO190DOPMWait() ; the rock at y-1 is on the screen nowIFhw=0ANDPMHitPM(1)&1THEN; player 1 met player 0hw=y-1FIHitClr()
PMVPos(1, y) ; the rock one row lowerIFsw=0ANDPMOverlap(0, 1) THEN; the rectangles overlap at oncesw=yFIODPrint("PMOverlap: the rock hit the ship at y=")
PrintBE(sw)
Print("Hardware: the rock hit the ship at y=")
PrintBE(hw)
RETURN
PMOverlap: the rock hit the ship at y=173
Hardware: the rock hit the ship at y=0
Simulátor nemá obvod GTIA, preto hardvér v ňom zrážku nehlási (0). V emulátore (--run) vypíše program oba riadky s y=173: kameň v riadkoch 173–180 sa dotkne lode v riadku 180.
bity 0–3: s ktorými hráčmi sa objekt n zrazil (bit 0 = hráč 0, hodnota 1; bit 1 = hráč 1, hodnota 2 …)
PMHitPF(n)
bity 0–3: s ktorými farbami obrázka (playfield 0–3) sa objekt n zrazil
PMHit(n, c)
1 alebo 0: c 0–3 je hráč, 4–7 farba obrázka 0–3 (ako v Tool Kite)
HitClr()
všetky zrážky vynuluje
PMHitPM(1)&1 je teda „hráč 1 narazil do hráča 0“. Rovnako by platilo PMHitPM(0)&2 – zrážku hráčov hlási hardvér u oboch.
Dve pravidlá hardvérových zrážok:
Bity sa len pridávajú. Raz nastavený bit ostane, kým program nezavolá HitClr(). Bez neho by jeden náraz platil navždy.
Zrážka sa zistí až pri kreslení. Hneď po PMVPos registre ešte hovoria o starej polohe. Preto slučka robí vždy to isté: počkaj na obraz (PMWait) → prečítaj → HitClr → pohni. Program si preto pamätá y-1 – zrážku našiel obraz, v ktorom bol kameň ešte o riadok vyššie.
Zrážka z programu:PMOverlap(a, b) vráti 1, keď sa prekrývajú obdĺžniky dvoch objektov (poloha, šírka a počet riadkov tvaru, ktoré si runtime pamätá). Funguje hneď po pohybe, aj pre neviditeľný objekt a aj pre dve strely (hardvér zrážku strely so strelou nepozná). Je to však len obdĺžnik: prázdne rohy tvaru sa rátajú tiež. Hardvér naopak hlási len skutočne nakreslené body.
PMHitPF(n) hlási, do ktorej farby obrázka objekt narazil. Pozor na textový režim: písmená v GRAPHICS 0 sa hlásia ako farba 2 (hodnota 4), hoci ich farbu nastavuje SetColor(1, …):
Action!
IFPMHitPF(4)&4THEN; strela 0 (objekt 4) narazila do textuPMClear(4)
FI
Strely sú objekty 4–7. Tvar strely sú dva spodné bity každého bajtu ([1 1 1] – úzka, [3 3 3] – široká) a strela má farbu svojho hráča:
Štyria hráči sú pre hru málo. Hry na Atari preto ukazujú jedného hráča na viacerých miestach: obrazovka sa rozdelí na pásy a v každom má hráč inú polohu a farbu. Prepína ich krátky program, ktorý počítač spustí uprostred kreslenia obrazu – prerušenie display listu (DLI). Action26 ho má hotové: stačí povedať, kde pásy začínajú a čo v nich má byť.
Kapitola ukazuje aj dve menšie veci: hráčov v banke 130XE a hráča ako zvýraznenie riadku v menu.
;@modern; Three enemies made of one player: sprites in bandsBYTEARRAYenemy=[$3C$7E$DB$FF$FF$A5$81$C3]
PROCMain()
BYTEi, tGraphics(0)
PMGraphics(1)
FORi=0TO2DOPMSprite(8+i, 0, i+1) ; sprite 8+i is player 0 in band i+1PMBand(i+1, 4+6*i) ; bands from text rows 4, 10 and 16PMCreate(8+i, enemy, 8, 1, 50+20*i, 32+8*(5+6*i)) ; on rows 5, 11, 17ODPMColor(8, 4, 8) ; redPMColor(9, 12, 10) ; greenPMColor(10, 8, 12) ; bluePMBands(4) ; band 0 (the top) and bands 1-3FORt=1TO100DOPMWait()
FORi=0TO2DOPMHPos(8+i, PMX(8+i)+1) ; each one in its own bandODODFORi=0TO2DOPrint("Enemy ")
PrintB(i+1)
Print(" stopped at x=")
PrintBE(PMX(8+i))
ODRETURN
V emulátore idú zľava doprava traja nepriatelia – červený, zelený a modrý – každý v inom pruhu obrazovky, hoci sú všetci hráč 0. Simulátor nemá display list, takže pásy v ňom nie sú, ale program prebehne:
Bash
action26pm-lanes.act--sim
Enemy 1 stopped at x=150
Enemy 2 stopped at x=170
Enemy 3 stopped at x=190
objekt s (8–15) je sprite: kreslí sa do hráča n (0–3) a ukazuje sa v páse pás
PMBand(pás, riadok)
pás 1–7 začína riadkom obrazovky (v GRAPHICS 0 riadkom textu)
PMBands(počet)
zapne pásy 0 až počet-1; PMBands(0) ich vypne
Pás 0 je vrch obrazovky. Pásy 1–7 začínajú riadkom z PMBand; riadky musia s číslom pásu rásť.
Sprite je objekt ako každý iný: PMCreate, PMMove, PMShape, PMClear kreslia jeho tvar do pásu hráča (len jeho riadky), PMHPos a PMColor zmenia jeho polohu a farbu – ale len v jeho páse. Na to, kde sa ktorý riadok zobrazí, nemá vplyv nič iné: tvar spritu musí ležať v riadkoch jeho pásu.
Hráč bez spritu v páse si tam drží vlastnú polohu a farbu.
Zrážky hlási hardvér pre celého hráča – PMHitPM(8) je zrážka hráča 0 v ktoromkoľvek páse. Ktorý sprite to bol, povie PMOverlap. Šírka (PMWidth) tiež patrí celému hráčovi.
Obrazový čip číta tvary hráčov z pamäte rovnako ako obrazovku. Keď je pamäť hráčov v okne $4000–$7FFF, XAntic (kapitola 38) určí, či ju číta z bežnej pamäte alebo z banky:
Action!
BYTEARRAYpm(1024)=$4000; pamäť hráčov v oknePMMemory(pm)
XBank(1) PMGraphics(2) PMCreate(0, down, 8, 2, 60, 50) ; obrázok v banke 1XBank(0) PMGraphics(2) PMCreate(0, up, 8, 2, 60, 50) ; obrázok v bežnej pamäti
…
XAntic(1) ; ukáž banku 1XAntic(0) ; ukáž bežnú pamäť
Dva obrázky na tej istej adrese a prepínanie XAntic dajú animáciu, pri ktorej sa nekreslí ani bajt. Procesor a obrazový čip však nemôžu vidieť naraz dve rôzne banky – striedať sa dá bežná pamäť a jedna banka. Celý program je lekcia examples/modern/pmbank.act (potrebuje 130XE).
Hráč so šírkou 4 má 32 bodov – to je šírka ôsmich znakov textu. Dvaja vedľa seba dajú pruh cez 16 znakov, ktorý sa dá posúvať po riadkoch menu bez prekresľovania textu:
Action!
SetBlock(bar, 8, $FF) ; tvar: 8 plných riadkov = jeden riadok textuPMCreate(0, bar, 8, 4, 60, 32+8*riadok) ; stĺpec 3: x = 48 + 4*3PMCreate(1, bar, 8, 4, 92, 32+8*riadok)
PMColor(0, 9, 4) PMColor(1, 9, 4) ; tmavá farba
…
PMVPos(0, 32+8*riadok) PMVPos(1, 32+8*riadok)
Hráč je pred textom, ale písmená v ňom ostanú čitateľné: podľa opisu obvodu GTIA im v textovom režime nechá jas textu a dá im odtieň hráča. Preto má byť pruh tmavý. Celé menu s joystickom je lekcia examples/modern/cursor.act.
Rutiny hráčov zaberajú v programe od asi 500 bajtov (len hráči, bez striel) po asi 2 kilobajty (všetko vrátane spritov a pásov). Prekladač pribalí len to, čo program naozaj volá – napríklad kód pre strely len vtedy, keď program použije objekt 4–7, a kód pre pásy len s PMSprite, PMBand alebo PMBands. Program bez hráčov nemá z toho nič.
; komentár do konca riadkaDEFINEMAX="10"; mená pre texty a čísla (17)TYPEPoint=[BYTEx, y] ; typ záznamu (21)BYTEscore; globálne premenné (16)PROCHelper(BYTEn) ; procedúra (3, 14)BYTEi; lokálne premenné – pred prvým príkazom
…
RETURNBYTEFUNCTwice(BYTEn) ; funkcia (15)RETURN(n*2)
PROCMain() ; program začína v POSLEDNEJ rutine
…
RETURN
BYTEa, b; premennéBYTElives=[3] ; s počiatočnou hodnotouBYTEcolour=710; na adrese (24)BYTEARRAYt(10) ; poleBYTEARRAYdays=[312831] ; pole s hodnotamiCHARARRAYname="Atari"; reťazec: name(0) je dĺžka (19)CHARARRAYbuffer(40) ; miesto pre reťazecBYTEPOINTERp; ukazovateľ (20)Pointhere; záznamPointPOINTERpp; ukazovateľ na záznam
AND ARRAY BYTE CARD CHAR DEFINE DO ELSE ELSEIF EXIT FI FOR FUNC IF INCLUDE INT LSH
MOD MODULE OD OR POINTER PROC RETURN RSH SET STEP THEN TO TYPE UNTIL WHILE XOR
Menami nemajú byť ani rutiny a premenné knižnice (Print, Stick, color, device, EOF …) – vlastná premenná s takým menom ich zakryje. Veľké a malé písmená sa nerozlišujú.
CONSTMAX=10; konštantaTYPELight=ENUM [RED, GREEN] ; vymenovaný typ; hodnota Light.REDBYTEARRAYgrid(4,6) ; viacrozmerné poleCASExOF; výberWHEN1THEN …
WHEN2, 3THEN …
WHEN4TO9THEN …
WHEN10TO20IFpodmTHEN …
ELSE …
ESACy=(a>b) ; porovnanie ako 1/0y=IFa>bTHENaELSEbFI; IF ako hodnotay=CARD(a)+b; pretypovanie"text\{RETURN}"; špeciálne znakyORG$CB … ENDORG; deklarácie na adreseORG$4000BANK1 … ENDORG; dáta v bankeALIGN1024; zarovnanieASM … ENDASM; assemblerBYTEARRAYd=FILE"súbor"; súbor ako poleBYTEARRAYd=PACKFILE"súbor"; zbalenýCHARARRAYt=PACK"text"; zbalený text
Chyby sú dvojakého druhu: tie, ktoré nájde prekladač (program sa nepreloží), a tie, ktoré nastanú za behu (program sa preložil, ale niečo sa pokazilo).
Atari má vlastnú tabuľku znakov. Písmená, číslice a bežné znamienka sú na rovnakých kódoch ako v ASCII.
Kódy
Znaky
0–26
grafické znaky (čiary, rohy, kartové symboly)
27
ESC
28, 29, 30, 31
kurzor hore, dole, vľavo, vpravo
32
medzera
33–47
! " # $ % & ' ( ) * + , - . /
48–57
číslice 0–9
58–64
: ; < = > ? @
65–90
veľké písmená A–Z
91–95
[ \ ] ^ _
96
grafický znak (kosoštvorec)
97–122
malé písmená a–z
123, 124
grafický znak, |
125
vymazanie obrazovky
126
zmazanie znaku vľavo
127
tabulátor
155
koniec riadka ($9B)
253
pípnutie
128–255
tie isté znaky inverzne (kód + 128), okrem riadiacich
Riadiace znaky (28–31, 125–127, 253) sa pri výpise vykonajú – Put(125) vymaže obrazovku. Ak ich chceš vidieť ako znak, vypíš pred nimi ESC: Put(27) Put(125).
Príklady. V priečinku examples/ je takmer tisíc programov v Action!: hry, ukážky grafiky a zvuku, programy z časopisov. Čítať cudzie programy je najlepší spôsob, ako sa zlepšovať. Prehľad je v examples/README.md.
Lekcie rozšírení.examples/modern/ má 49 lekcií k rozšíreniam action26 – každá je program s podrobným popisom. Kapitoly 35 až 42 tejto knihy sú ich skrátením.
Pôvodný manuál.The ACTION! Reference Manual od Optimized Systems Software je predlohou tejto knihy. Je po anglicky a obsahuje aj časti o editore a monitore cartridge.
Knihy o Atari.Mapping the Atari (Ian Chadwick) opisuje každú adresu v pamäti počítača. De Re Atari vysvetľuje grafiku, zvuk a prerušenia do hĺbky. Obe sú voľne dostupné na internete.
Dokumentácia action26. Priečinok docs/ opisuje prekladač presne a úplne – jazyk (language.md), knižnicu (runtime.md) a rozdiely oproti pôvodnému Action! (differences.md). Je písaná pre tých, ktorí už jazyk poznajú.
Čo si napísať ako prvé. Hádanie čísla. Had, ktorý rastie. Kresliaci program ovládaný joystickom. Textová hra s tromi miestnosťami. Každý z nich použije väčšinu toho, čo je v tejto knihe.
Plán príručky v priečinku book/: jazyk Action! vysvetlený od úplných základov, príkaz po
príkaze, s prekladačom action26. Štýl a značky ako v plan.md. Stav je len
v nadpisoch:
Od 2026-10-10 je príručka v book\md\ (kapitoly, tento plán, examples\). Priečinok book\ je nástroj Doc26 (book\index.php), ktorý tie isté kapitoly ukazuje po svojom; témy
a syntaxe v book\themes\ a book\syntax\ sú spoločné. Cesty book/… v starších bodoch
plánu treba čítať ako book/md/….
[x] hotové,
[ ] čaká,
[-] nebude sa robiť (dôvod je v texte).
Čísla bodov sú B0 … B9, kapitoly majú vlastné čísla 01 … 39 a prílohy písmená A … E.
Stav: všetky body B0–B9 sú hotové (2026-10-03). Čo sa pri písaní ukázalo, je v časti Poznatky.
Pre koho: pre ľudí, ktorí nemajú skúsenosti s Atari ani s Action! a programujú málo alebo
vôbec.
Predloha: pôvodný manuál Action! (JAC\doc\action-manual.pdf v pôvodnom repozitári atari-action, pozri external\README.md),
ale bez popisu editora (a bez monitora cartridge – action26 ich nemá).
Postupne vysvetliť jednotlivé príkazy Action! tak, ako ich prekladá action26.
Ku každému príkazu úplný tutoriál (celý program, nie úryvok) a príkaz, ako ho preložiť.
Na koniec príkazy a možnosti action26 navyše: voľby prekladača, rozšírenia --modern,
RAM pod ROM, banky rozšírenej pamäte, kompresia dát.
Kde sa dalo ísť viacerými cestami, je tu zvolená cesta a dôvod. Dá sa zmeniť skôr, než sa
kapitoly napíšu.
Jazyk knihy je slovenčina. Programy (mená, texty na obrazovke, komentáre) sú po anglicky
ako vo zvyšku repozitára – Atari nemá slovenské znaky.
Jeden súbor na kapitolu (book/03-prvy-program.md), obsah je v book/README.md.
Kapitola je krátka: jeden príkaz alebo jedna téma.
Programy z knihy sú aj ako súbory v book/examples/ (hello.act …). Čitateľ ich nemusí
prepisovať a dajú sa strojovo overiť (bod B9).
Spúšťa sa najprv vo vstavanom simulátore (action26 program.act --sim): netreba nič
inštalovať a výstup sa objaví rovno v okne príkazového riadka. Emulátor atari800 (--run)
príde na rad pri grafike, zvuku a joysticku, kde simulátor nestačí.
Výstup v knihe je skutočný výstup programu, skopírovaný z behu, nie písaný z hlavy.
Poradie kapitol ide od použitia, nie od gramatiky. Manuál začína slovnou zásobou a typmi;
kniha začína programom, ktorý niečo vypíše, a typy príde vysvetliť, až keď ich treba.
Bez odkazov na vnútro prekladača. Kniha neposiela čitateľa do docs/ – tie sú pre
ľudí, ktorí prekladač poznajú. Výnimkou je príloha s odkazmi „kam ďalej“.
Rozdiely oproti originálnemu Action! sa spomenú len tam, kde by čitateľa prekvapili
(napr. program z časopisu, ktorý sa správa inak), krátkou poznámkou.
Z manuálu sa vynecháva: editor (časť II), monitor (časť III), voľby cartridge. Časť
„Run Time“ nahrádza kapitola o tom, že program z action26 beží bez cartridge.
Dohodnutý slovník pojmov, aby sa v celej knihe volali rovnako: prekladač, zdroják, rutina (procedúra alebo funkcia), premenná, pole, reťazec, ukazovateľ, záznam, knižnica, simulátor, emulátor.
Čo je Atari, čo je Action!, čo je action26. Čo je program, zdroják, prekladač, súbor XEX. Čo treba mať (action26.exe, textový editor, voliteľne emulátor). Ako knihu čítať.
02
02-prvy-program.md
Prvý program „Hello“. Kde ho napísať, ako uložiť, ako preložiť (action26 hello.act), spustiť v simulátore (--sim) a v emulátore (--run). Čo znamená chybové hlásenie prekladača a ako ho čítať.
obraz disku ATR: --atr, --atr-name, --atr-list, --atr-get, --atr-put, --atr-check; preklad z disku; --to-text, --to-atascii
35
35-modern-jazyk.md
CONST, TYPE … =ENUM, CASE … OF … WHEN … ESAC, porovnanie ako hodnota, IF a CASE ako hodnota, pretypovanie BYTE(x)
36
36-modern-data.md
viacrozmerné polia, špeciálne znaky \{…}, PrintU/PrintUD (text nad 255 znakov)
37
37-modern-pamat.md
ORG … ENDORG, ALIGN, ASM … ENDASM
38
38-skryta-pamat.md
RAM pod ROM a banky 130XE: XBanks, XPeek, XPoke, XMoveBlock, XSetBlock, XZero, XPrint, XRead, XWrite, XBank, XAntic, ORG … BANK n, BankOf, --data-only, --code-only, --sim-mem
slovníček pojmov a „kam ďalej“ (príklady v examples/, lekcie examples/modern/)
Overenie programov: skript tools\check-book.ps1 – každý program v book/examples/
sa musí preložiť; kde kapitola ukazuje výstup, musí sa zhodovať s behom v simulátore; program
vypísaný v kapitole musí byť zhodný so súborom.
tools\make-book.ps1 vyrobí z kapitol book\md\Action26.html: celú knihu v jednom súbore, so štýlmi
aj skriptom vnútri (netreba internet ani nič inštalovať). Súbor je vygenerovaný, v gite nie je.
(Pôvodný book\make-html.bat teraz patrí Doc26; skript sa spúšťa priamo.)
tools\make-book.ps1 – vlastný prevod Markdownu (nadpisy, odseky, bloky kódu, tabuľky,
zoznamy, citácie, čiary, tučné, kurzíva, kód v texte, odkazy). README.md je prvá sekcia,
ostatné súbory idú podľa mena, plan.md sa vynecháva.
Rám stránky, štýly a skript v tools\book\ (frame.html, book.css, book.js).
Odkazy medzi kapitolami (09-if.md) vedú dovnútra stránky; odkazy na programy
(examples/…) ostávajú odkazmi na súbory. Odkaz, ktorý nikam nevedie, je chyba a súbor sa
nezapíše.
Značky program: a output: dávajú programu hlavičku s menom súboru a výstupu vzhľad
obrazovky Atari.
V stránke: obsah vľavo so skupinami z README.md, hľadanie v celej knihe (bez ohľadu na
diakritiku), farby jazyka Action!, tlačidlo na skopírovanie programu, svetlý a tmavý vzhľad,
úprava pre úzke okno a pre tlač.
Zapojené do tools\test.ps1 -Full (prevod do dočasného súboru).
Verzia dokumentácie je v 01-uvod.md v riadku za značkou <!-- version -->:
„Verzia dokumentácie Action26 1.3.0.N“, teda File Version najnovšieho action26.exe
(bin\ alebo build\x64\Release\), nie číslo z gitu. Zapisuje ho tools\make-book.ps1
aj build.bat; Doc26 berie to isté číslo priamo z exe ("versionExe" v docs.json) do
pätičky aj do tohto riadku. Pri -Output (skúšobný prevod v testoch) sa kapitola nemení.
Export z book\out\ sa kopíruje aj do bin\ ("copyTo" v docs.json).
Témy. Namiesto prepínača svetlá/tmavá je v obsahu výber témy. Témy sú farebné schémy
Sublime Textu v book\themes\ (*.tmTheme, *.sublime-color-scheme); číta ich tools\book\themes.ps1 a do stránky sa dostanú len výsledné farby (asi 45 KB za 116 tém).
Slová programu sa farbia podľa mien z book\syntax\action.sublime-syntax
(entity.name.commands_cycle.action …), pre ktoré majú schémy vlastné pravidlá; zoznamy slov
sa berú z toho istého súboru. Schéma bez pravidiel pre Action! dostane všeobecné mená
(keyword.control …).
Nadpisy, tučné, kurzíva, kód, citácie, odrážky a hlavičky tabuliek sa farbia podľa mien
z book\syntax\Markdown.sublime-syntax (markup.heading.1.markdown …).
Farbu dáva pravidlo, ktoré sedí najlepšie, ako v editore: hlbší scope, potom dlhšie meno,
potom neskoršie pravidlo. Farby rámu stránky (obsah, čiary) sú zmiešané z pozadia a popredia.
Schéma, ktorá len dopĺňa inú (bez vlastného pozadia a popredia), sa vynechá a skript to vypíše.
Vynechá sa aj schéma, ktorá nemá pravidlo pre nič, čo stránka ukazuje (schéma len pre iný
jazyk, napr. amos, zxbasic) – celá stránka by bola jednou farbou.
Voľba sa pamätá v prehliadači (localStorage). Prehliadač, ktorý stránke úložisko nedovolí
(náhľad, ktorý súbor ukazuje ako adresu data:), si ju pamätá v mene okna – vydrží
znovunačítanie, nie zavretie karty. Pre taký prípad je voľba make-book.ps1 -Theme "meno":
stránka s touto témou začína, kým si čitateľ nevyberie inú.
„Kniha (podľa systému)“ je pôvodný vzhľad. Tlač je vždy svetlá.
Spracovanie tém trvá asi 10 sekúnd, preto sa výsledok drží v dočasnom súbore
(%TEMP%\action26-book-themes.txt) a číta sa znova len pri zmene témy alebo skriptu.
Pri zmene knihy: ak kapitola použije prvok Markdownu, ktorý prevod nepozná (vložené HTML,
obrázok s popisom, poznámka pod čiarou), treba ho doplniť do make-book.ps1 – inak sa zobrazí
ako obyčajný text.
Rozsah: 39 kapitol, 5 príloh, 52 programov v book/examples/ (plus motto.txt a frame.dat
pre kapitolu 39). Kapitoly 35 a 36 majú program pre každé rozšírenie zvlášť.
Doplnené 2026-10-17: kapitoly 40–42 o Player/Missile grafike (pm-ship.act, pm-bird.act, pm-hit.act, pm-lanes.act), spolu 42 kapitol a 57 programov; check-book.ps1 57/57, 46 výstupov zo simulátora. Programy 40–42 overené aj v atari800 (registre a pamäť, zrážka z hardvéru).
Doplnené 2026-10-28: kapitola 32 – silnejšie zakódovanie --scramble-level 2, kľúč --scramble-key, dvojstupňový dekodér a nové chybové hlásenia a ;@compile --scramble-level 2 --scramble-key $3A7F; kapitola 33 – --scramble-level a --scramble-key medzi voľbami pre ;@compile; kapitola 1 – skutočný výpis action26 --version (tri riadky). Čísla z --verbose (108 a 120 bajtov dekodéra, súbor 399 namiesto 287 bajtov) overené prekladom secret.act.
Overenie:
tools\check-book.ps1: všetkých 52 programov sa preloží, 52 výpisov programov v kapitolách sa
zhoduje so súbormi a 41 ukážok výstupu sa zhoduje s behom v simulátore. Skript je zapojený do tools\test.ps1 -Full.
Značky v kapitolách (<!-- program: … -->, <!-- output: … -->) sú HTML komentáre, v prehliadači
Markdownu ich nevidno.
Programy pre emulátor (grafika, zvuk, joystick, kocka) boli spustené v atari800 a obrazovka
prečítaná z pamäte: domček v režime 7 vrátane výplne Fill, textová obrazovka, kocka s Rand. files.act a operácie XIO (premenovanie, zamknutie, zmazanie, zoznam súborov) na disku DOS 2.5.
Tabuľky „Časté chyby“ uvádzajú hlásenia, ktoré prekladač naozaj vypísal; každé bolo vyskúšané.
Neoverené strojovo: interaktívne ukážky (input.act, if.act, do.act, until.act – výstup
s písaním používateľa je prepísaný z behu so vstupom zo súboru), zvuk (počuť sa nedá), pohyb
joystickom (overená len úvodná obrazovka), klávesy emulátora pre joystick.
Čo simulátor nevie (a kniha to hovorí): grafiku, zvuk, joystick, Rand (vracia stále to isté),
časovač na adrese 20 (slučka Wait v ňom nikdy neskončí).
Nájdené v simulátore: po XIO premenovaní súboru zlyhá jeho čítanie chybou 137 a zoznam
súborov (Open v režime 6) nevypíše nič. Na skutočnom DOS 2.5 v atari800 oboje funguje. Kapitola
30 preto posiela tieto operácie do emulátora.
Pasce jazyka, ktoré sa ukázali ako dôležité pre začiatočníka (každá má miesto v kapitole a
v prílohe C):
program začína v poslednej rutine; chýbajúci RETURN prepadne do ďalšej rutiny,
BYTE x=5 je adresa, nie hodnota,
BYTE+BYTE sa počíta v BYTE aj pri ukladaní do CARD (200+100=44),
FOR nepočíta nadol a BYTE počítadlo do 255 je nekonečná slučka,
premenná s menom knižničnej rutiny (stick) alebo typu (TYPE P, premenná p) ju zakryje –
veľké a malé písmená sa nerozlišujú; pointer je vyhradené slovo,
DEFINE SIZE="5+5" a SIZE*2 je 15,
lokálne premenné sú statické: počiatočná hodnota sa nastaví raz, rekurzia nefunguje,
reťazce sa neporovnávajú znakom = (porovnajú sa adresy),
1 LSH 8 v BYTE je 0.
Z manuálu vynechané: editor, monitor, voľby cartridge (podľa zadania). Časť o „Run Time“ je
nahradená vetou v kapitole 32, že action26 pribalí len použité rutiny.