A ZX Spectrum
Programozása
Tartalom
Előszó
Ez a könyv - címének megfelelően - a ZX Spectrum személyi számítógép használóihoz szól. Szándékunk az volt, hogy mindenki, aki kapcsolatba kerül a ZX Spectrummal, hasznosan tudja forgatni.
Az eltérő számítástechnikai ismeretek eltérő olvasási módot igényelnek. Azoknak, akik a számítástechnikát most kezdik tanulmányozni, az első három fejezetet ajánljuk figyelmébe. A BASIC programnyelvben már jártas, de a ZX Spectrummal most ismerkedők az 1.3 pont és a 2. fejezet elolvasása után már önállóan használhatják a számítógépet. Ha a ZX Spectrum nyelvét más BASIC-változatokkal akarják összevetni, szükségük lehet a 3. fejezet részletes áttanulmányozására is.
A ZX Spectrum BASIC használatában jártas olvasóknak a 4. - a gépi kódú programozással foglalkozó - fejezet elolvasását javasoljuk. A számítástechnikában, sőt a Z80 gépi kódú programozásában otthonos olvasóknak szintén hasznos lehet a könyv 4. fejezete, mert itt számos ROM rutin működését, használatát mutatjuk be. Megemlítjük még, hogy bár könyvünk a ZX Spectrum használatát írja le, a ZX81-et használók is eredményesen forgathatják a BASIC utasításokat leíró részt. Ekkor azonban figyelemmel kell lenniük arra, hogy a ZX81-en kevesebb utasítás van, és ezek egy része máshol található. A közös utasítások az INPUT kivételével hasonlóan működnek.
Kérjük a kedves olvasót, hogy ha a szerzők szándéka, a gondos lektorálás és szerkesztői munka ellenére hibát talál a könyvben, vagy egyéb észrevétele van, akkor jelezze a szerzőknek.
A szerzők
Budapest, 1985
1. A ZX Spectrum felépítése és használata
1.1 A gép felépítése
A ZX Spectrum személyi számítógép. A személyi jelző azonban csak a gép méreteire utal. A ZX Spectrum - legalábbis első megközelítésben - ugyanolyan részekből épül fel, mint a nagyobb méretű gépek.
Nézzük meg, milyen fő részekből áll egy számítógép, és mire szolgálnak az egyes részek)
Minden számítógépen megtaláljuk a tárolót vagy memóriát. A tároló célja, hogy a program végrehajtásának idejére tárolja azt a programot és azokat az adatokat, amelyekkel a számítógép dolgozik. (A számítógép csak olyan programokkal és adatokkal tud dolgozni, amelyek a tárolójában vannak.) Ezt a tárat teljes nevén operatív tárnak hívjuk.
A központi egységben (angol nevének rövidítése CPU) az alábbi részeket különböztethetjük meg:
A ki- és bemeneti egységek célja, hogy megvalósítsák a számítógép és a külvilág közötti információcserét. A bemeneti egységekkel adatokat tudunk bevinni a számítógépbe, a kimeneti egységekkel pedig adatokat vihetünk ki onnan. A számítógép működéséhez természetesen mindig mindkettő szükséges. A bemeneti egységen például utasítást adhatunk a számítógépnek, a kimeneti egységen pedig megkapjuk az eredményt
A felsorolt részegységek működéséhez már csak megfelelő áramforrás kell. Néhány alapfogalom azonban még további tisztázásra szorul. Ezért térjünk vissza kicsit a tárolóhoz és a kimeneti-bemeneti egységhez!
A tárak használatához tudnunk kell, hogy valamilyen mértékegységben kifejezve mekkora a befogadóképességük, kapacitásuk. (A mindennapi életben például tudjuk, hogy egy egyliteres üvegben a literben kifejezett folyadékmennyiségből éppen egy egységnyi fér el.) A tárolók tárolási kapacitását bájtban mérik. 1 bájt 8 bitből áll, 1 bit pedig egy kettes számrendszerbeli számot, 0-t vagy 1-et jelent. Rövid számolás után kiderül, hogy 1 bájton kettes számrendszerben 255 a legnagyobb ábrázolható szám. 1 bájton csak igen kevés információ ábrázolható, ezért a gyakorlatban ennek többszörösét, az 1 kbájtot használják egységként. A kbájt kilobájtot jelent és 1 kbájt 1024 bájttal egyenlő.
A számítógép operatív tárolóját a felhasználás szempontjából két részre osztjuk. A tároló egyik részében levő információkat tetszés szerint megváltoztathatjuk, a másik részben levő információkat csak felhasználhatjuk, de nem változtathatjuk meg. Az első szabadon használható memóriarész neve RAM, a másiké ROM. A ZX Spectrum gépeken a szabadon felhasználható tárterület nagysága 16 k, illetve 48 k, a ROM nagysága pedig 16 k.
A ROM-ról annyit kell tudnunk, hogy oda a számítógép gyártása során már bevitték az adatokat, és a normális működés során nem tudjuk eltávolítani őket. A ROM teszi lehetővé, hogy a ZX Spectrumot bekapcsolás után azonnal használni tudjuk, és a ROM-ban állandóan ott lévő program fogja értelmezni a megírt programokat.
A ZX Spectrum programjai, amelyeket a felhasználó ír majd, a RAM területére kerülnek. A RAM területén lévő adatok elvesznek, amikor a gépet kikapcsoljuk.
Ha csak operatív tároló volna, a programokat mindig újra kellene írni. Ez nem tenné lehetővé a hatékony munkát, ezért kialakították a háttértárolókat. Bizonyos háttértárak mágneses adathordozón - mágnesszalagon vagy mágneslemezen - tárolják az információkat. A háttértárakra megfelelő utasítással ki lehet vinni a számítógépből a programokat és az adatokat, illetve vissza lehet vinni őket. A háttértárak egyúttal kimeneti, bemeneti egységek is. A ZX Spectrum fő háttértárolója a magnetofon. Erre a célra minden jó minőségű, beépített erősítővel ellátott kazettás magnetofon megfelel.
Minden számítógéphez, így a ZX Spectrumhoz is számos adatkiviteli és adatbeviteli eszköz csatlakoztatható. A legfontosabb adatbeviteli eszköz maga az alapgépen lévő billentyűzet. A legfontosabb adatkiviteli eszköz pedig a televízió, melynek képernyőjén megjelenik a kívánt információ. A ZX Spectrumhoz, mint minden számítógéphez kiviteli egységként nyomtató is csatlakoztatható. Az eredetileg is ZX81-hez vagy ZX Spectrumhoz tervezett (a SINCLAIR által gyártott vagy a SEIKOSHA GP-50) nyomtató közvetlenül csatlakoztatható, az egyéb nyomtatók csak megfelelő illesztésen keresztül. Ugyanez igaz a mágneslemezre is.
1.2. A számítógép üzembe helyezése
Ahhoz, hogy Spectrumunkat használni tudjuk, a gépet össze kell állítani. Ezt először célszerű útmutatás alapján végezni, később majd nélküle is könnyen megy. A működőképes számítógépet a következő részegységekből kell összekapcsolni:
Az összeállítás lépései: Az áramátalakító kis dobozából 2 kábel nyúlik ki. Ezek közül az egyiket a hálózati csatlakozóba (konnektorba) kell dugnunk. Figyelem, ezt majd csak legutoljára végezzük! A másik kábel végén levő jackdugót a ZX Spectrum hátsó részének jobb oldalán levő 9VDC jelű csatlakozó hüvelybe kell dugni.
Ezek után már csak két kábelt kell bekötnünk. Az egyiknek mindkét végén 2 darab jackdugó van. Ez majd a magnetofonhoz kell. Az utolsó kábel az alapgép és a televízió közötti összeköttetéshez szükséges. A kábel egyik dugóját a ZX Spectrum hátán bal oldalon található TV jelű csatlakozóba kell bedugni, a kábel másik végét pedig a televízió 75 ohmos antennacsatlakozójába. Azokon a televíziókészülékeken, ahol több antennacsatlakozás is van, a 36-os UHF csatorna vételére alkalmas antenna csatlakozásába kell a ZX Spectrum megfelelő csatlakozóját dugni. Színes képet csak PAL rendszere adás vételére alkalmas tv-készüléken kaphatunk.
Ha kazettás magnetofont is akarunk használni, a magnetofonhoz csatlakozó kábelt a ZX Spectrum hátlapján lévő EAR, illetve MIC jelű hüvelyekbe kell dugni. (Az EAR a fülhallgató, a MIC a mikrofon angol nevének rövidítése.) A kábelpár másik végét a kazettás magnetofon megfelelő, hasonló jelű csatlakozó hüvelyeibe kell dugni. Szokjuk meg, hogy magnetofont és minden egyéb ki- és bemeneti egységet is csak áramtalanított géphez csatlakoztatunk. Ellenkező esetben a gép megsérülhet.
A fenti műveletsor elvégzése után a gépet áram alá helyezhetjük. Ekkor - ha a televízió előzőleg már a megfelelő csatornán állt - a bemelegedés után a képernyő legalsó sorában a
felirat jelenik meg. Ha a fenti üzenet nem látható, akkor a televíziót a megfelelő csatornára rá kell hangolni. A felirat megjelenése után számítógépünk munkára készen áll.
1.3. A billentyűzet és használata
A könyv szövegét ettől kezdve ajánlatos bekapcsolt számítógép mellett olvasni, hogy a leírtakat ki is lehessen próbálni. A billentyűk nyomogatásával ha nem erőltetjük - nem ronthatjuk el a gépet. Ha gyakorlás közben nagyon összekeveredünk, és a számítógép semmiképpen sem csinálja azt, amit szeretnénk, a 9VDC dugó kihúzásával, majd 3-4 másodperc eltelte utáni visszadugásával rendet teremthetünk. (Ennek persze az az ára, hogy a begépelt program és az adataink elvesznek.)
A billentyűzet elrendezése lényegében egy írógép billentyűzetére hasonlít, persze megfelelő eltérésekkel. Az írógéptől eltérően itt minden betűnek és számnak külön billentyű felel meg (például 1 = egy, I = i betű, o = o betű, 0 = nulla). Ismerkedjünk meg közelebbről is a billentyűk használatával) Nézzünk meg például néhány speciális célú billentyűt!
ENTER (jobb oldalon alulról a második, magyar jelentése: belép). Ez az egyik legfontosabb billentyű. Hatására a számítógép értelmezni kezdi a begépelt információt. Ez más szóval annyit jelent, hogy akárhogy is nyomkodjuk a billentyűket, amíg nem nyomjuk meg az ENTER-t, a számítógép nem értelmezi, amit bebillentyűztünk, hiába jelenik meg a televízió képernyőjén. Az ENTER megnyomásáig tehát a számítógép nem tudja, hogy a begépelt és a televízió képernyőjén is megjelenő információ neki szól. Ha az alapállapotban lévő gépnél (például bekapcsolás után azonnal) megnyomjuk az ENTER billentyűt, akkor a képernyő bal alsó sarkában egy négyzetben villogó K betli jelenik meg. Ennek neve kurzor (jelentése: mutató), használatára rövidesen visszatérünk.
BREAK/SPACE (jobb oldalon a legalsó, a BREAK jelentése: megszakítás, a SPACE jelentése: üres hely). A két felírásból sejthetjük, hogy ez a billentyű két különböző dologra való. Ha a billentyűt önmagában nyomjuk le, akkor az alsó állásnak megfelelően a SPACE hatása érvényesül. Ez annyit jelent, hogy a SPACE egyszeri lenyomásakor a kurzor egy szóközzel jobbra megy, azaz annyi üres hely lesz két beírt jel között, ahányszor a SPACE-t lenyomjuk. A billentyű másik funkciója a BREAK. Ez a gépben lévő és éppen működő program leállítására alkalmas. Akkor fogjuk majd használni, hogyha egy programot a befejeződése előtt le akarunk állítani. (Addig persze nem tudjuk kipróbálni, amíg nem tudunk programot írni.) A BREAK hatást úgy érhetjük el, hogy a BREAK/SPACE billentyűt a CAPS SHIFT billentyűvel egyszerre nyomjuk meg.
CAPS SHIFT (jelentése: nagybetűváltót. Nagyon sokféle feladatra használható billentyű. Fő jellemzője, hogy önmagában sohasem használjuk, mindig csak egy másik billentyűvel együtt. Célja tehát az, hogy más billentyűk működését megváltoztassa. Az ENTER billentyűn kívül bármely billentyűvel együtt megnyomható, hogy jelentését módosítsa.
Ha a CAPS SHIFT-et valamely betűt tartalmazó billentyűvel együtt nyomjuk meg, akkor az illető betű nagybetűként jelenik meg a képernyőn. Ez a hatás csak akkor érhető el, ha CAPS SHIFT nélkül ez a betű kisbetűként jelenne meg a képernyőn. Vannak ugyanis olyan helyzetek, amikor hiába nyomunk meg egy betűt tartalmazó billentyűt, nem a betű jelenik meg, hanem valami más, a billentyűn, illetve az alatta, esetleg felette lévő angol szó vagy rövidítés. Ennek okát hamarosan tisztázni fogjuk. Bekapcsolás után nyomjuk meg például az E betűt. A képernyőn a REM felirat és kurzorként az L betű jelenik meg. Ha most ismét lenyomjuk az E gombot, akkor a képernyő legalsó sorában a REM e jelenik meg. Ha az E betűt most a CAPS SHIFT-tel együtt nyomjuk meg, akkor az E is odakerül, és a legalsó sorban REM eE lesz látható. (Ha a billentyűket egy másodpercnél tovább tartjuk lenyomva, akkor ismétlődik a lenyomott érték.)
Ha a CAPS SHIFT-et a felső (számokat tartalmazó) sorokkal együtt használjuk, akkor érdekes és hasznos dolgokat csinálhatunk. A legfelső sorba a billentyűk fölé fehérrel azt írták fel, hogy mit is csinál a CAPS SHIFT hatására. Ha a 0-t (nullát) és a CAPS SHIFT-et egyszerre nyomjuk le, akkor a DELETE-nek megfelelően a törlés működik. Hatására a legutoljára begépelt betű vagy jel törlődik a képernyőről, a kurzor pedig ennek megfelelően balra lép vissza. Ha például az előbb begépelt REM eE esetén egyszerre nyomjuk meg a CAPS SHIFT-et és a 0-t, eltűnik az E és csak a REM e marad. A második együttes lenyomás után csak a REM marad, a harmadik után a villogó K betű lesz látható.
Ha a CAPS SHIFT-et a 9-es billentyűvel együtt nyomjuk le, akkor a GRAPHICS feliratnak megfelelően az ún. grafikus üzemmód lép érvénybe. Ennek legelső jele, hogy a villogó K betű kurzor villogó G kurzorrá alakul át. Ekkor az 1-7 számú billentyűk lenyomására a rajtuk lévő grafikus jel lesz látható a képernyőn. A grafikus üzemmódot nevének megfelelően rajzok, ábrák készítésére fogjuk majd használni. Igen fontos, hogy mindaddig a grafikus üzemmód marad érvényben, amíg a 9-es billentyűt meg nem nyomjuk (CAPS SHIFT-tel vagy önmagában). Törölni grafikus módban is a már megismert módon lehet. Ha a CAPS SHIFT-et a 8, 7, 6, 5 vagy 1 billentyűvel együtt nyomjuk meg, akkor úgynevezett szerkesztési funkciókat hajthatunk végre. Ennek részletes bemutatására a következő fejezetben kerül sor. A CAPS SHIFT és a 4-es billentyű együttes lenyomására az alap és a betű színe felcserélődik, és ez mindaddig tart, míg az eredeti állapotot a CAPS SHIFT és a 3-as billentyű segítségével vissza nem állítjuk. A CAPS SHIFT és a 2-es billentyű egyszeri lenyomásával a nagybetűs üzemmódot tehetjük állandóvá. Ez addig marad érvényben, amíg újra meg nem nyomjuk ezeket a billentyűket.
SYMBOL SHIFT (a legalsó sorban, jobbról a második, jelentése: szimbólumváltás).Ez a másik olyan billentyű, amelyet mindig. csak másik billentyűvel együtt használunk. Elsődleges szerepe, hogy a billentyűkön lévő piros jeleket teszi érvényessé. Ha például a már jól ismert E betűt és a SYMBOL SHIFT-et egyszerre nyomjuk meg, akkor a képernyőn a > =jel lesz látható. A SYMBOL SHIFT másik hatását csak ún. kiterjesztett üzemmódban láthatjuk. Mi is az a kiterjesztett mód? Ennek megértéséhez térjünk vissza a kurzor fogalmához!
A kurzor, mint már volt róla szó, magyarul mutatót jelent. Mindig két dolgot mutat. Az egyik, hogy amit éppen begépelünk, hová kerül az adott képernyősorban. A másik, hogy milyen jellegű adatot vár a számítógép. Ezt a villogó téglalapban lévő betű jelzi. A következő betűk fordulhatnak elő: K, G, E, L, C. Nézzük meg az egyes eseteket!
A K kurzor azt jelenti, hogy a számítógép valamilyen KULCSSZÓT vár. A kulcsszó azt jelenti, hogy a számítógép valamelyik billentyű lenyomására a billentyűn lévő fehér feliratot értelmezi. Amikor a megfelelő billentyűt lenyomtuk, a K kurzor L-re (esetleg C-re) változik. Az L és a C kurzor is azt jelzi, hogy a következő lenyomott billentyűt a számítógép a rajta lévő betűként fogadja el. Ha az L kurzor villog, akkor kisbetűként, ha a C kurzor villog, akkor kor nagybetűként. A G kurzort, amint arról már szóltunk, mi magunk állíthattuk elő és szüntethettük meg a CAPS SHIFT és a 9-es lenyomásával (a grafikus üzemmódot jelzi). Végül az E kurzor a kiterjesztett (angolul extended) üzemmódot jelzi. Ezt a CAPS SHIFT és a SYMBOL SHIFT együttes lenyomásával érhetjük el. Azért hívják kiterjesztett módnak, mert ilyenkor minden billentyű lenyomásakor új lehetőségeink is lesznek. Ebben a módban a billentyűkön lévő zöld színű jel lesz érvényben (például az E betűt lenyomva kiterjesztett üzemmódban a TAN jelenne meg).
Ha kiterjesztett üzemmódban egy billentyűt a SYMBOL SHIFT-tel együtt nyomunk le, akkor a billentyűn lévő piros jel lép érvénybe (például az E betűt lenyomva az ATN). Nézzük mindezt végig egy példán! Alapállapotban lévő gépen nyomjuk meg az ENTER billentyűt. Ekkor a K kurzor jelenik meg. Nyomjuk meg az E betűt: a REM felirat jelenik meg, utána az L kurzor. Ha most az E betűt nyomjuk meg, megjelenik az e betű, és megmarad az L kurzor. Ha együtt lenyomjuk a CAPS SHIFT-et és a 2-es billentyűt, akkor az L kurzor C-re vált át. Ha most nyomjuk le az E betűt, akkor E-t kapunk. Ha a SYMBOL SHIFT-et és az E-t nyomjuk le, akkor > = jelenik meg. Végül áttérve a kiterjesztett módba, villogó E kurzort látunk. Ha ekkor nyomjuk meg az E betűt, akkor a TAN feliratot kapjuk, és a kurzor visszavált C-re. újra kiterjesztett módba váltva, az E betűt a SYMBOL SHIFT tel együtt lenyomva, az ATN-t kapjuk. Az egész sor tehát:
REM eE>=TAN ATN
Megjegyezzük, hogy a géppel együtt szállított HORIZONS nevű kazetta - a PSION cég terméke - részletesen bemutatja a billentyűzet kezelését. Ezt a programot úgy kell betölteni a gépbe, hogy a megfelelően összeállított és bekapcsolt számítógépen a J billentyűt nyomjuk le. Ekkor a képernyőn a LOAD felirat jelenik meg. Ezután a SYMBOL SHIFT billentyűt a P betűvel együtt kétszer lenyomjuk. Ha a magnetofon lejátszáson áll, és a megfelelő kazetta a betöltendő programmal a helyén van, a begépelt parancsot az ENTER billentyű lenyomásával elküldhetjük. Programok kimentéséről és visszatöltéséről a könyv további fejezeteiben lesz szó.
ZX Spectrum számítógépünkön - a magnetofon vagy a Microdrive segítségével - előre megírt programokat használhatunk. Az előre megírt, megvásárolható programok a játékoktól kezdve a matematikai és műszaki feladatok megoldásain át az adatfeldolgozásig számos területet felölelnek. Akármilyen sok is a kész, megvásárolható program, minden felmerülő problémára nem vehetünk egyet. Ilyenkor valakinek - például a számítógép tulajdonosának vagy használójának - kell megírnia a szükséges programot. Ehhez nyújt segítséget ez a könyv is. Mielőtt részletesen foglalkoznánk a programozás szabályaival, néhány dolgot tisztáznunk kell.
Ezek közül az első, hogy milyen célra lehet és érdemes használni a ZX Spectrum számítógépet. Röviden azt mondhatjuk, hogy ZX Spectrumunkkal minden feladatot kényelmesen elvégezhetünk, kivéve, ha "nagyon sok" adatot használunk. A nagyon sok itt azt jelenti, hogy az adatok és az adatokat használó program mérete együttesen meghaladja a felhasználható operatív tároló - a RAM - méretét. Ha a program és az adatok egyszerre nem férnek el az operatív tárban, akkor vagy mágneslemezt használunk, vagy ha más tárolónk nincs, egyszerű kazettás magnetofont. Nagy tömegű adatok a ZX Spectrumon mágneslemez nélkül csak nehézkesen, lassan, viszonylag bonyolult programmal kezelhetők.
Azt is tisztáznunk kell, hogyan fogjunk hozzá egy feladat számítógépes megoldásához. Mindig gondoljuk végig alaposan a teljes feladatot! Keressünk pontos választ arra, milyen kiinduló adatokból milyen végeredményt kell kapnunk, és ehhez milyen műveleteket fogunk majd elvégezni. Ezeknek az igen lényeges kérdéseknek kellően részletes tárgyalása meghaladja e könyv kereteit, de az érdeklődők a programozás irodalmában részletes útmutatást kaphatnak.
Szólnunk kell röviden a programnyelvekről is. A számítógép programnyelve kommunikációs eszköz az ember és a számítógép között. Nagyon sokféle programnyelv létezik. További programok felhasználása nélkül a ZX Spectrumot BASIC programnyelven (kényelmesen) és gépi kódban (kevésbé kényelmesen) lehet programozni.
2.1. A ZX Spectrum BASIC programnyelvének jellemzői
A BASIC a ZX Spectrum alapvető programozási nyelve. A BASIC mozaikszó, magyar jelentése: alapvető. Ismerkedjünk meg a BASIC legfontosabb, általános jellemzőivel!
A BASIC magas színtű programnyelv. Ez azt jelenti, hogy magas szintű szolgáltatásokat nyújt. A BASIC-ben például - ellentétben a nem magas szintű programnyelvekkel - a matematikában szokásos négy alapműveletet igen egyszerűen el tudjuk majd végezni. Mint minden magas szintű nyelven, programjainkat BASIC-ben is az emberi nyelvhez közel álló nyelven fogjuk megírni. A program működését befolyásoló vezényszavak, az ún. kulcsszavak értelmes angol szavak vagy azok rövidítései. A számítógép természetesen nem tud angolul, de a tárolójában - a ROM-ban - állandóan ott lévő program, az ún. értelmező (interpreter) biztosítja majd, hogy a végrehajtás során a programban lévő kulcsszavak a gép számára érthető, ún. gépi kóddá alakuljanak át.
A BASIC általános célú programnyelv. Ennek megfelelően a legtöbb olyan feladat, amelyre a számítógépet használni érdemes, megoldható BASIC-ben. Azért kell kiemelni a BASIC általános jellegét, mert vannak ún. speciális céllal létrehozott programnyelvek is. Az ilyen speciális célú programnyelveken az adott speciális probléma viszonylag könnyen kezelhető, más feladatokat viszont nem, vagy csak igen nehezen lehet megoldani velük.
A BASIC legkellemesebb általános jellemzője, hogy viszonylag könnyen megtanulható, és ezért gyorsan terjed. Azok, akik már programoztak más programnyelven, igen könnyen megtanulhatják. De azok is elég könnyen elsajátíthatják, akik csak most ismerkednek a számítógép-programozás alapjaival. A kezdők figyelmét arra hívjuk fel, hogy a beszélt emberi nyelvekhez hasonlóan a számítógépes programnyelvet is csak megfelelő gyakorlással sajátíthatjuk el igazán.
A BASIC programnyelvnek eddig az előnyeit ismertettük, szólnunk kell azonban egy hátrányáról is: a BASIC - ellentétben a többi magas szintű programnyelvvel - nincs szabványosítva. Ebből következik, hogy ha a Spectrumon megírt BASIC nyelvű programunkat más típusú számítógépen akarjuk használni, akkor nem biztos, hogy azt programunk megváltoztatása nélkül megtehetjük. A könyv a ZX Spectrum BASIC programnyelvét ismerteti.
A BASIC programnyelv két nagy részre bontható: utasításokra és parancsokra. A működő BASIC program mindig utasításokat tartalmaz. A parancsok a megfelelő környezetet, az adminisztrációt biztosítják, és segítséget nyújtanak a programok megírásához, végrehajtásához. A ZX Spectrum BASIC-jének egyik sajátossága, hogy a parancsok és az utasítások élesen nem különülnek el egymástól, vagyis az utasításokat használhatjuk parancsként, a parancsokat pedig utasításként.
Jól tudjuk, hogy a beszélt nyelveknek meghatározott szabályaik vannak, ugyanígy a számítógépes programnyelveknek is. A programnyelvek szabályait két nagy csoportba osztjuk: vannak formai és logikai szabályok. Az élő nyelveket alapul véve a formai szabályok a nyelvtani szabályokhoz hasonlítanak (például a magyar nyelvben a múlt idő jele az egy vagy két t, így a ttttt már biztosan nyelvtani hiba). A programnyelvek logikai szabályait az élő nyelvekben meglévő logikai szabályokhoz hasonlíthatjuk (például tudjuk, hogy egy értelmes magyar mondatban alany, állítmány, tárgy, határozó stb. van - ez formai követelmény is -, de nem biztos, hogy ha formailag helyesen egy alanyt, egy állítmányt, egy tárgyat és egy határozót egymás mellé teszünk, akkor abból értelmes mondat sül ki).
A szabályok közül a formai szabályok az egyszerűbbek, mivel általánosan össze tudjuk foglalni őket. A logikai szabályok utasításonként eltérnek.
2.2. A ZX Spectrum BASIC programnyelvének formai szabályai
Minden utasítást és parancsot célszerű új sorba írni. A helyesen begépelt utasítást, vagy parancsot az ENTER billentyű lenyomásával lehet elküldeni (amint már tudjuk, akármi is van a képernyőn, a számítógép csak akkor vesz tudomást róla, ha elküldjük az ENTER-rel).
A ZX Spectrum BASIC-jében egy sorban több utasítást vagy parancsot is megadhatunk, de ekkor kettősponttal kell elválasztani őket (a Z betű és a SYMBOL SHIFT billentyűk együtt lenyomva).
Fontos tisztázni, hogy mit nevezünk egy sornak. A programírás szempontjából azt mondhatjuk, hogy egy programsor az ENTER billentyű két lenyomása között beírt jelek összessége. Ezt azért lényeges külön is kiemelni, mert előfordulhat, hogy a beírni kívánt utasítás egy képernyősornál nagyobb helyet foglal el. A képernyő egy sorában ugyanis csak 32 karakter fér el. (Karakter: a betűk, számok, írásjelek összefoglaló neve a számítástechnikában.) Tehát akárhány képernyősornyi is a bebillentyűzött programsor, a számítógép egy sornak tekinti egészen az ENTER billentyű lenyomásáig.
A programsoroknak sorszámmal kell kezdődniük. A sorszámoknak 1 és 9999 közötti pozitív egész számoknak kell lenniük, a határokat is beleértve.
Alapvető dolog, hogy a programsorok mindig növekvő utasítássorszám szerint, a beírás sorrendjétől függetlenül hajtódnak végre. A gyakorlatban ez a szabály annyit jelent, hogy a program végrehajtása a legkisebb sorszámú utasítással kezdődik, és - ha másként nem rendelkezünk a programban - növekvő sorszámú utasításokkal folytatódik egészen a legnagyobb sorszámig.
Ha több utasítást ugyanolyan sorszámmal küldünk el, a gép csak a legutolsót jegyzi meg (felülírás).
Ha csak üres sorszámot küldünk el - utasítás nélkül -, akkor ez az adott sorszámú programsor törlését jelenti.
Ezzel a három szabállyal tudunk egy programban javítani. A javítás - akármilyen bonyolultnak tűnik is - a három alapeset valamelyikére vezethető majd vissza: a törlésre, a beszúrásra, és a módosításra. A törlést már megvizsgáltuk. A beszúrás szintén igen egyszerű: lényege, hogy olyan új sorszámú utasítást írunk le, amilyen még nem volt. Ekkor az új sor - miután az ENTER billentyűvel elküldtük - a sorszámának megfelelő helyre kerül. Két sor közé természetesen csak akkor tudunk új sorokat beszúrni, ha sorszámuk nem egymás utáni két szám. A gyakorlatban a sorszámokat ötösével vagy tízesével, esetleg húszasával szoktuk növelni.
Az utolsó javítási lehetőség a módosítás. Módosításkor egy adott sorszámhoz tartozó utasítást részben vagy teljesen megváltoztatunk. A módosításra kétféle lehetőségünk is van: az egyik, hogy a sort újra leírjuk a régi sorszámmal, de a kívánt új tartalommal, a másik módosítási lehetőség pedig az EDIT billentyű használata (az 1 -es és a CAPS SHIFT egyszerre).
Az EDIT parancs hatására az adott sor a képernyő alsó, beírásra és javításra fenntartott részére kerül. Az így lehozott sorban a kurzort az 5-ös vagy a 8-as billentyű és-a CAPS SHIFT együttes lenyomásával tudjuk mozgatni. A javítást a kurzor által mutatott pozícióban lehet elvégezni. Az 5-ös és a CAPS SHIFT billentyű balra, a 8-as és a CAPS SHIFT billentyű pedig jobbra mozgatja a kurzort. A kijavított sor az ENTER hatására visszakerül a helyére. Természetesen, ha olyan sort viszünk le az EDIT paranccsal, amelyben nem akarunk javítani, akkor az ENTER hatására a sor változatlanul kerül vissza a helyére.
A legutoljára elküldött sornál a sorszám után egy > jel látható. Ez az ún. programkurzor, az aktuális sorszámmutató. Az EDIT parancs mindig a programkurzornak megfelelő sorszámú sor javítását teszi lehetővé. A programkurzort a 6-os vagy 7-es billentyűnek a CAPS SHIFT billentyűvel egyszerre való lenyomásával tudjuk változtatni (növelni vagy csökkenteni). A ZX Spectrum egyik nagy előnye, hogy ha formai hibát vétünk egy sorban, akkor az első formailag hibás karakter előtt egy villogó kérdőjel jelenik meg. Ameddig a hibát ki nem javítjuk, a gép nem fogadja el a rossz sort.
Általánosságban már szóltunk az utasításokról és a parancsokról. Mondtuk, hogy a működő programok mindig utasításokból állnak. Tudjuk azt is, hogy az utasítás megjelenhet parancsként, és ez fordítva is igaz. Most már, az utasítássorszámok ismeretében azt mondhatjuk, hogy a programok utasításai mindig sorszámmal kezdődnek. A parancsoknál soha nincs sorszám.
Az utasítások és a parancsok azonban nemcsak formailag különböznek egymástól. Működésűkben is lényeges eltérés van: a parancsokat a gép azonnal végrehajtja (miután ENTER-rel elküldtük őket). Az utasítások sohasem azonnal hajtódnak végre, hanem csak a megfelelő parancs elküldése után (és ezen belül is csak akkor, ha a program vezérlése az adott sorra ér).
2.3. Adatok a BASIC-ben
A számítógép programozásáról elég sokat megtudtunk már eddig is. A legfontosabb, hogy a programok utasításokból állnak, amelyek a BASIC-ben angol szavak vagy rövidítések. A programsorok elejére sorszámokat írunk. A konkrét utasítások tárgyalása előtt meg kell még néznünk, hogy a BASIC-ben milyen adatokat használhatunk.
Az adatokat három szempont szerint érdemes vizsgálni: időbeliségük, tartalmuk és összetettségük szerint.
Az adatok időbeliségéi tekintve azt mondhatjuk, hogy egy programon belül lehetnek állandók - elterjedt idegen szóval konstansok - vagy változók. Amint ez a névből is kiderül, a változók egy programon belül különböző értékeket is felvehetnek.
Az adatokat tartalom szerint osztályozva azt mondhatjuk, hogy egy adat vagy csak számokat, vagy számokat, betűket és egyéb jeleket is tartalmazhat. A csak számokat tartalmazó adatokat numerikus típusú adatoknak hívjuk. Az olyan adatokat, amelyekben számok, betűk ás mindenféle egyéb jelek is lehetnek, karakteres típusú adatoknak nevezzük.
Az adatok összetettségük szerint vagy egyszerű, vagy ún. összetett adatok, más néven tömbök lehetnek. A két adattípus közötti eltérést később részletesen tárgyaljuk.
Adatok:
Nézzük meg az állandók írásának szabályszerűségeit! A numerikus állandók csak számokat tartalmazhatnak, de a számok ábrázolásához még egyéb jelek is járulhatnak: a + vagy - jel, a . (tizedespont) és a kitevőt jelölő e vagy E betű. A bonyolult formai leírás helyett nézzük meg konkrét példákon a numerikus konstansok ábrázolási lehetőségeit!
A legegyszerűbb esetben csak pozitív egész számot ábrázolunk. Ilyenkor a számot kell leírni, előjellel vagy nélküle. Például:
13 +13 |
Negatív szám esetében kötelező kiírni előjelet:
-13 |
Törtszám esetén az egész rész mögé tizedespont kerül, és utána írjuk a törtrészt. (A BASIC-ben a tizedesvessző helyett tizedespont van.) Az egész részt le sem kell írnunk, ha 0. Például:
13.5 +13.5 -13.5 0.5 -0.5 .5 -5 |
A nagyon nagy vagy nagyon kicsi számokat kényelmesen ábrázolhatjuk normál alakban. Ilyenkor bármelyik már megismert ábrázolási módot használhatjuk, de utána írjuk, hogy 10-nek hányadik hatványával kell megszorozni a számot. Jelölése az e vagy E betű és az utána következő maximum kétjegyű előjeles vagy előjel nélküli egész szám. Ha az előjel pozitív, akkor az e vagy E előtt álló számot a 10 pozitív hatványával, ellenkező esetben pedig a negatív hatványával kell megszorozni. Például:
13.5e5 13.5E5 13.5e+5 13.5E+5 |
értéke minden esetben 1350000.
13.5e-5 13.5E-5 |
értéke pedig 0,000135.
A ZX Spectrumon ábrázolható legkisebb és legnagyobb pozitív, illetve negatív numerikus konstans értéke:
0.3E-38 | 1.7E+38 | -0.3E-38 | -1.7E+38 |
A karakterkonstansok az idézőjel kivételével tetszőleges karaktert tartalmazhatnak. Karakterkonstanson ugyanis két idézőjel (a P és a SYMBOL SHIFT billentyűk egyszerre) közötti jeleket értünk.
Az állandók után foglalkozzunk röviden a változókkal is! A változókról már tudjuk, hogy nevüknek megfelelően egy programon belül változtathatják értéküket. Így szükség lesz arra, hogy valahogyan hivatkozhassunk rájuk.
A változókra a változónév alapján tudunk hivatkozni. A változónév nem lehet tetszőleges, képzésénél bizonyos szabályokat be kell tartani. A numerikus változók neveire a következő szabályok vonatkoznak a ZX Spectrum BASIC-ben: A változónév első karaktere csak betű lehet, a második (és a továbbiak) tetszőleges betű vagy szám. A tömbök és a ciklusváltozók neve csak egy betűből állhat. A karakteres változókat a ZX Spectrum BASIC-ben egy betű és az utána következő dollárjel (a 4-es billentyű és a SYMBOL SHIFT együtt) jelzi. A változónevekben a kis- és nagybetűk tetszés szerint felcserélhetők. Tehát például az alma, ALMA, AlMa, aLmA stb. ugyanazt a változót jelenti.
2.4. A ZX Spectrum BASIC programnyelvének legfontosabb parancsai
A figyelmes olvasó ellentmondást fedezhet fel a cím és az eddig elmondottak között. Azt állítottuk ugyanis, hogy a ZX Spectrum parancsainak túlnyomó része utasításként is használható. Milyen alapon emelünk ki közülük néhányat? A válasz meglepően egyszerű: a gyakorlat alapján. Ugyanis az ebben a fejezetben tárgyalt parancsok közös jellemzője, hogy a gyakorlati felhasználás döntő, túlnyomó többségében parancsként használjuk őket.
A parancsok, amint tudjuk, a programozáshoz szükséges környezetet teremtik meg, és a számítógép az elküldés után azonnal megkísérli végrehajtani őket. Formailag csak a sorszám hiánya különbözteti meg a parancsokat az utasítástól. A legfontosabb parancsok az 1. táblázatban láthatók. Mindegyik parancs rendeltetését, működését elmagyarázzuk, de lesz közülük néhány, amelyre később még visszatérünk, finomítjuk működésének leírását.
Parancs | Helye |
Kurzor |
CLEAR CLS CONT LIST LLIST LOAD MERGE NEW RUN SAVE VERIFY |
X V C K V J T A R S R |
K K K K E K E + SYBOL SHIFT K K K E + SYBOL SHIFT |
A CLEAR parancs (magyar jelentése törölni) az X billentyűn található. Fő funkciója, hogy törli a gép memóriájában lévő összes BASIC változót, és így megváltoztatja a BASIC program számára rendelkezésre álló területet. Egyéb hatásai is vannak, ezeket főleg a gépi kódú programozáskor használjuk.
A CLS parancs (angol nevén clear the screen, magyar jelentése: töröld a képernyőt) a V billentyűn található. Hatására a képernyőn lévő kép eltűnik. A gépben lévő program azonban - ha van ilyen - változatlanul megmarad. Ha parancsként küldjük el, a képernyő legalsó sorában a 0 OK, 0:1 üzenet jelenik meg. Ez a parancs sikeres befejezését jelenti.
A CONT parancs (a continue rövidítése, magyar jelentése folytasd) a C billentyűn van. A megállított program működését tudjuk folytatni vele. A program működését vagy a BREAK billentyű, vagy a megfelelő utasítás begépelésével tudjuk megállítani. A CONT parancs nem hatásos, ha a program programhiba miatt állt meg.
A LIST parancs (magyar jelentése listázd) a K billentyűn található és a számítógépben lévő BASIC programot írja ki a képernyőre. A parancs sikeres végrehajtását a CLS-nél megismert üzenet jelzi. Előfordulhat, hogy a kilistázandó program hosszabb, mint ahány sor a képernyőre fér (22 sor fér rá). Ekkor az első 22 sort kilistázza a képernyőre a gép, majd a legalsó sorban a scroll? kérdés jelenik meg (a scroll jelentése kb. tekercs). Ha a kérdésre nem az N vagy nem a BREAK billentyűt nyomjuk meg válaszként, a listázás tovább folytatódik. Újabb 22 sor kiírása után természetesen megint megjelenik a scroll? kérdés.
A LIST után megadhatunk egy sorszámot is. Ekkor a listázás az adott sorszámú sortól kezdődik. Ha a LIST után negatív számot adunk meg, hibajelzést kapunk, 0 sorszám esetén pedig a legelső sortól listázza ki a programot a ZX Spectrum. Nem létező pozitív sorszám esetén a gép a következő létező sorszámtól kezdi a listázást.
Az LLIST parancs a V betűnél található E módban. Hatása hasonlít a LIST-ére, az eltérés csak annyi, hogy a listázás a nyomtatóra történik. Már most felhívjuk rá az olvasó figyelmét, hogy a nyomtató csak kikapcsolt géphez csatlakoztatható.
A LOAD parancs (jelentése betölteni) a J billentyűn található. Feladata a mágnesszalagon lévő program betöltése a tárba. A LOAD után két idézőjel között meg kell adni a program nevét. Ekkor a számítógép addig keres, míg a megadott nevű programot meg nem találja a szalagon. A megtalált programot betölti a tárba, és fölülírja az ott lévő programot. Ha a két idézőjel között nem adunk meg nevet, akkor a gép a szalagon az olvasófej előtt álló első teljes programot tölti be a tárba. Sikeres programbetöltés esetén a CLS parancsnál megismert üzenetet kapjuk. A LOAD parancs további lehetőségeiről a könyv további részeiben lesz szó.
A MERGE parancs (magyar jelentése összeolvasztani) a T billentyűn található E módban és a SYMBOL SHIFT-tel együtt. Hatása némileg hasonlít a LOAD-éhoz. A MERGE is behozza a mágnesszalagról az ott található programot, de míg a LOAD törli a korábbi memóriatartalmat, addig a MERGE csak összefésüli a szalagon lévő programot a tárban lévővel. Ha a szalagon és a memóriában lévő programban egyező sorszámú részek vannak, akkor a szalagon lévő sorszám az érvényes (ez fölülírja a memóriában lévő sorszámot). Sikeres végrehajtás esetén MERGE parancsnál is a CLS-nél és a LOAD-nál megismert üzenetet kapjuk.
A NEW parancs (magyar jelentése új) az A billentyűn található. Az egyik leggyakrabban használt parancs, melyet új program írása előtt célszerű kiadni. Hatására a BASIC program, valamint az adatok számára fenntartott memóriarész törlődik, és a számítógép készen áll az új program fogadására. NEW után a képernyőn a gép bekapcsolásakor megismert felirat jelenik meg. Új program írásakor azért hasznos a NEW parancs kiadása, mert így elkerülhetjük, hogy az előző programok maradványai véletlenül bekerüljenek új programunkba.
A RUN parancs (magyar jelentése fuss) az R billentyűn található és a leggyakrabban használt parancs. Hatására a tárban lévő program futni kezd, azaz a gép megpróbálja végrehajtani a programot. A BASIC értelmező ekkor alakít át minden programutasítást gépi kódúvá. A RUN utasítás törli a gép memóriájából az összes BASIC változót. A RUN után is meg lehet adni egy sorszámot, ekkor a programvégrehajtás csak az adott sortól kezdődik.
A RUN utasítás hatására a program által kiírtakon kívül egy
K SZ, S:U
alakú üzenetet is kapunk, ahol
A SAVE (magyar jelentése menteni) parancs az S billentyűn található. Segítségével a megírt programjainkat mágnesszalagra tudjuk kimenteni. A nevet a SAVE után idézőjelek között kell megadni. A névnek legalább egy és legfeljebb 10 karakter hosszúnak kell lennie.
A megfelelő név megadása után a
Start tape, then press any key.
üzenet jelenik meg. Ez szó szerint annyit jelent, hogy indítsd el a magnószalagot és nyomj le egy tetszőleges billentyűt. Vigyázni kell a helyes sorrendre, ugyanis a ZX Spectrum a billentyű lenyomásakor mindenképpen jelet küld a magnetofon felé, még ha az nincs is felvételre állítva. Sikeres befejezéskor a LOAD parancsnál megismert üzenetet kapjuk. A SAVE parancs fejlettebb változataival később foglalkozunk.
A VERIFY parancs (magyar jelentése ellenőrizd) az R betűnél van, és E módban a SYMBOL SHIFT-tel érhető el. Szerepe, hogy a SAVE-vel kimentett programot vagy adatokat ellenőrizze. Megvizsgálja, hogy a szalagra írt jelek pontosan megfelelnek-e a memóriában lévőnek. Egyezés esetén a már ismert OK üzenetet kapjuk. Ellenkező esetben az
R Tape loading error, 0:1
üzenet jelenik meg a képernyőn (szalagbetöltési hiba).
3. A ZX Spectrum programozása BASIC nyelven
Ebben a fejezetben a ZX Spectrum BASIC nyelvű programozásának szabályait mutatjuk be. Minden utasításnál ismertetjük a megfelelő szabályokat és példákon keresztül a használatukat is. Az utasítások tárgyalásánál nem ábécé sorrendben haladunk, hanem bizonyos fontossági sorrendben.
Az első néhány utasítás ismeretében már viszonylag bonyolultabb feladatokat is meg tudunk oldani. Felmerülhet a kérdés, miért van akkor annyi utasítás. Azért, mert a bonyolultabb problémák kényelmes megoldásához az első néhány utasítás nem elegendő. Ugyanakkor a sokféle utasítás az, amely a ZX Spectrum BASIC-ját igazán hatékony munkaeszközzé teszi.
A közölt mintapéldáknál két szempontot tartottunk szem előtt. Az első az volt, hogy minden mintapéldánál csak olyan utasításokat használjunk, amelyeket addig részletesen tárgyaltunk. Másik fontos szempontként arra figyeltünk, hogy sehol ne haladjuk meg a középiskolák szokásos tananyagát.
Helye: az E billentyű, a kurzor: K. A REM az angol remark (megjegyzés) szónak a rövidítése. Az utasítás pontosan ezt is csinálja. Hatása az, hogy nincs hatása. Ez úgy értendő, hogy akármi is áll a REM utasításban, semmit nem befolyásol a program végrehajtásakor. A REM után tetszőleges szöveget írhatunk, amely a program listázásakor láthatóvá válik.
Mi a célja a REM utasításnak, ha nincs hatással a program működésére? Az, hogy a programozót informálja bizonyos dolgokról. Ilyen lehet például a program célja, az egyes változóknak tulajdonított jelentés, az egész program működésének elve stb.
Felvetődhet a kérdés, miért van erre szükség, hiszen a program írója ezeket úgyis tudja, hiszen ő írja a programot. Amikor írja, bizonyára tudja is, de tegyük fel, hogy bizonyos idő (például 1-2 hónap, esetleg évek) múlva valami apró, javítanivaló akad a programban. Ilyenkor már ő sem mindig emlékszik rá. Az ún. öndokumentáló programoknak fontos része a működést magyarázó megjegyzés.
A REM utasításban tehát tetszőleges betű, szám, írásjel lehet. Alkalmazásával azonban vigyázzunk, mert abba az utasítássorba, ahol REM utasítás szerepel, más utasítást már nem írhatunk a REM után, mert az is megjegyzésnek minősül. Természetesen a REM utasítást is sorszám előzi meg, és az ENTER billentyűvel küldjük el.
A mintaprogram kipróbálásánál a sorszámmal jelzett sorok végén az ENTER billentyűt le kell nyomni. A 30-as sorszámú sorban a második REM az R és a CAPS SHIFT, az E és a CAPS SHIFT, valamint az M és a CAPS SHIFT billentyű együttes lenyomásával (tehát különálló betűnként) írható be. Ha a mintaprogramot végrehajtjuk (RUN és ENTER), akkor a
0 OK, 50 : 1
üzenetet kapjuk, ami azt jelenti, hogy az 50-es sorszámú sor 1. utasításánál jól, hibátlanul befejeződött a program.
10 REM elso mintaprogram
20 REM sok ertelme nincs,
30 REM bemutatja a REM utasitast
40 REM a rem (remark) magyarul
50 REM megjegyzest jelent
Helye: a P billentyű, a kurzor: K. Magyar jelentése: nyomtatni. Az utasítás lényegében ezt is csinálja, a televízió képernyőjére ír ki. Ez az egyik legfontosabb utasítás, minden értelmes programban legalább egyszer előfordul.
A PRINT után egy nyomtatási lista állhat. A nyomtatási listában kinyomtatandó adatok és nyomtatást vezérlő karakterek szerepelhetnek. A kinyomtatandó adatok a következők lehetnek: valamilyen állandó, valamilyen változó, valamilyen függvény, vagy az előzőekből képzett kifejezés. A nyomtatást vezérlő karakterek például: a vessző (az N billentyű és a SYMBOL SHIFT), vagy a pontosvessző (az O betű és a SYMBOL SHIFT).
A vessző és a pontosvessző a nyomtatott információ elhelyezkedését befolyásolja a következőképpen. Ha a nyomtatandó adatokat vesszővel választjuk el egymástól, akkor egy sorba legfeljebb 2 adatot nyomtathatunk ki: egyet az első oszlopba, egyet pedig a 17. karakterpozíciónál kezdődő oszlopba. Ha az első oszlopba nyomtatott adat hosszabb, mint 16 karakter, és a nyomtatási listában még van nyomtatandó elem, akkor az a következő sor első oszlopába kerül.
Ha egy nyomtatási listában vesszővel elválasztva csak numerikus adatokat szeretnénk kiíratni, akkor biztosan állíthatjuk, hogy minden harmadik listaelem új sorban fog kezdődni (numerikus érték kinyomtatva soha nem foglal el 16 karaktert). Mindez a második mintapéldán is látható:
10 REM masodik mintaprogram
20 REM pelda a PRINT utasitasra
30 PRINT "ez kisbetu"
40 PRINT "EZ NAGYBETU"
50 PRINT "ez is karakter:1"
60 PRINT "ez is","1","0.1","-1.5"
70 REM kovetkeznek a szamok:
80 PRINT "kovetkeznek a szamok:"
90 PRINT 1,0.1,-1.5,+1.5e2,1.5e+2,-1.5E-2,-1.5E2
100 PRINT 1.7e38
110 PRINT -1.7e38
120 PRINT 1.4e-39
130 PRINT 1.5e-39
A program a RUN parancs hatására az alábbiakat írja ki:
Ha az elválasztó karakter pontosvessző, akkor ún. tömör ábrázolásról van szó. Ilyenkor mindent szorosan egymás mellé ír a képernyőn a ZX Spectrum. A hatást ellenőrizhetjük, ha a második mintaprogram 60-as sorában a vesszőket pontosvesszőkre javítjuk ki. Amikor vessző és pontosvessző felváltva fordul elő, akkor hatásuk a fentiekből értelemszerűen következik, azaz mindig a megfelelő karakter érvényesül.
Nagyon lényeges, hogy minden PRINT utasítás új sor nyomtatását kezdi meg. Ez alól csak egyetlen kivétel van: ha az előző PRINT utasítás utolsó karaktere vessző vagy pontosvessző és az előzőleg kinyomtatott sorban még van hely. Az üres PRINT - amikor a PRINT utasítás után nem írunk semmit, hanem azonnal az ENTER billentyűt vagy az utasítás elválasztását jelentő kettőspontot nyomjuk le - üres sor kinyomtatását eredményezi. Előfordulhat, hogy a PRINT utasítással a képernyőre 22 sornál többet akarunk kiírni. Ekkor a LIST parancsnál már megismert scrolt? (tekercselni?) üzenet jelenik meg. Kezelése is hasonló tovább lehet engedni a nyomtatást vagy le lehet állítani.
A PRINT utasítás hatását az AT, TAB, FLASH stb. módosítók befolyásolhatják, erről a továbbiakban még lesz szó.
Helye: az L billentyű, a kurzor K. Magyar jelentése: legyen. Ez az egyik legfontosabb, az ún. értékadó utasítás Segítségével a változóknak új értéket adhatunk, azaz a változókat ténylegesen változtathatjuk, rendeltetésüknek megfelelően használhatjuk. A LET utasítás általános formája a következő:
sorszám LET változó = új érték
A LET kulcsszó után mindig egy és csak egy változónév állhat, amelyet egyenlőségjel (L billentyű és SYMBOL SHIFT), majd az új érték leírása követ. Kiolvasni úgy kell, hogy "a változó új értéke legyen egyenlő az egyenlőségjel után álló értékkel". Alapvető formai szabály, hogy az egyenlőségjel két oldalán azonos típusú kifejezésnek kell állnia. Így, ha a változó numerikus típusú, akkor az egyenlőségjel után álló, az új értéket leíró kifejezés is csak numerikus lehet. Ha a változó karakteres típusú, akkor az új érték is csak karakteres típusú lehet. Az új érték tehát vagy a változó típusának megfelelő állandó, vagy egy változó, vagy egy függvény, vagy egy kifejezés.
Az állandóról és a változóról már volt szó, de mi is az a kifejezés? A kifejezés fogalma hasonló a matematikában használthoz. Egy kifejezéshez úgy juthatunk, hogy állandókat vagy változókat megfelelő műveleti jellel kapcsolunk össze. Nézzük meg, hogyan jelöljük a műveleteket a BASIC programnyelvben!
Az összeadás és a kivonás jele megegyezik a matematikában megismerttel: + és - (K és J billentyűk SYMBOL SHIFT-tel). A szorzás jele a * (B billentyű és SYMBOL SHIFT). Az osztás jele a / (V billentyű és SYMBOL SHIFT). A kifejezésekben szerepelhet még a hatványozás művelete is, ennek jele: ^ (H billentyű és SYMBOL SHIFT). (Figyelem, ez a jel önmagában még csak a hatványozást jelöli ki, utána mindig le kell írni a hatványkitevőt is!) A kifejezésekben természetesen lehet tetszőleges függvény is.
Ezek után az új értékről mondottakat úgy módosíthatjuk, hogy az tetszőleges állandó, változó, függvény vagy ezekből a műveleti jelek segítségével képzett kifejezés lehet, ha típusa megegyezik a LET után álló változó típusával.
Ebből következik az a formai szabály, hogy műveleti jel nem állhat önmagában és kifejezés végén, sőt a plusz- és mínuszjel kivételével még kifejezés elején sem. A műveleti jelek a plusz és mínusz előjel kivételével mindig két érték - állandó, változó, függvény - között állnak. Megjegyezzük, hogy a karakter típusú változókra csak az összehasonlítási és az egyesítési (összeadási) műveleteknek van értelmük.
A LET használatához még el kell mondanunk, hogy milyen sorrendben végzi el a gép a műveleteket. Erre a prioritási szabály ad választ. A prioritás elsőbbséget jelent, a nagyobb prioritású műveleteknek elsőbbségük van a kisebb prioritásúakkal szemben. A nagyobb prioritású műveleteket előbb hajtja végre a számítógép, mint a kisebb prioritásúakat. A műveletek prioritása a 2. táblázatban látható. (A táblázatban felsorolt prioritási értékeket nem érdemes megjegyezni, legfeljebb a műveletek elhelyezkedését, egymáshoz viszonyított sorrendjét. A táblázat két első és utolsó négy műveletét a könyv további részeiben még tárgyaljuk.)
Művelet | Prioritás |
indexszámítás és részekre botás függvények hatványozás előjelképzés szorzás, osztás összeadás, kivonás relációs műveletek logikai NEM logikai ÉS logikai VAGY |
12 11 10 9 8 6 5 4 3 2 |
2. táblázat
Az eddig megismert műveletek közül a hatványozásnak van a legnagyobb, az összeadásnak és a kivonásnak a legkisebb prioritása. Az előjelképzésnek nagyobb prioritása van, mint a szorzásnak és az osztásnak, az osztásnak és a szorzásnak pedig nagyobb prioritása van, mint az összeadásnak és a kivonásnak. Mindez a gyakorlatra lefordítva azt jelenti, hogy ha egy összetett műveletben a 4 alapművelet fordul elő, akkor a szorzást és az osztást hamarabb végzi el a gép, mint az összeadást és a kivonást. Ezt figyelembe kell vennünk, amikor matematikai képleteket írunk át BASIC-be.
A prioritási sorrend zárójelezéssel megváltoztatható. A zárójelek használatáról (8-as és 9-es billentyű SYMBOL SHIFT-tel) azt kell tudnunk, hogy ahány nyitó zárójel van egy kifejezésben, annyi záró zárójelnek is kell lennie.
Felmerülhet a kérdés, mi a műveletek végrehajtási sorrendje, ha egy kifejezésben csupa egyenlő prioritású művelet szerepel. Ekkor az ún. balról jobbra szabály dönt. E szerint egyenlő prioritású műveletek esetén a számítógép a bal oldalon kezdi el a kifejezés kiértékelését, és így halad jobbra.
A LET utasításnál külön ki kell emelnünk, hogy az utasítás értékadást jelent és nem azonos a matematikai értelemben vett egyenlettel. Ez különösen azért fontos, mert a nem SINCLAIR BASIC-ben a LET kulcsszót ki sem kell írni, hanem elég az egyenlőségjel megadása is. Így az értékadás formailag az egyenlethez hasonlít.
A SINCLAIR BASIC másik érdekes tulajdonsága, hogy a LET utasítás jobb oldalán csak olyan változók szerepelhetnek, amelyek előzőleg már kaptak értéket. Az előző értékadás vagy egy előző LET utasítással, vagy egyéb BASIC utasítással (INPUT, READ, FOR) történhet. Ha ezt elmulasztjuk, akkor a
2 Variable not found
hibaüzenet jelenik meg és utána a megfelelő sorszám. A hibaüzenet magyar jelentése: a változó nem található.
A harmadik mintapéldában az értékadás néhány alapesete látható.
10 REM harmadik mintaprogram
20 REM pelda a LET utasitasra
30 LET a=1
40 LET a$="ha-"
50 LET b=a
60 LET b$=a$
70 LET c=a+b/2
80 LET d=(a+3*b^2)/(a-2*b^3)
90 LET c$=a$+b$
100 PRINT a,b,c,d,a$,b$,c$
A program a RUN parancs hatására az alábbiakat írja ki:
A 30-as sorban egy numerikus, a 40-es sorban pedig egy karakteres konstanstól kap értéket a megfelelő változó. Az 50-es és a 60-as sorban a b és a b$ változó az a és az a$ változó értékét veszi fel. A 70-es sorban egy egyszerűbb kifejezést látunk, melynek értéke a prioritási szabály miatt 1.5. A 80-as sorban a
képlet BASIC szerinti átírása szerepel. A 90-es sor a karakterláncok egyesítésére ad példát (ennek idegen neve konkatenáció).
Külön is megemlítjük az értékadás egyik érdekes, kezdők számára szokatlan, de a számítástechnikában sokat használt formáját. Egy BASIC programban szerepeljen a
190 LET i=i+1
utasítás! Mit is jelent ez? Azt, hogy akármi is volt az i változó értéke, a 190-es sorszámú utasítás végrehajtása után legyen eggyel nagyobb.
A negyedik mintapélda egy 5 egység sugarú kör kerületét és területét számítja ki az ismert képlet alapján.
10 REM negyedik mintaprogram
20 REM adott sugaru kor kerulete es terulete
30 LET r=5
40 LET k=2*r*PI
50 LET t=r*r*3.1415927
60 PRINT "a sugar=",r
70 PRINT "a kerulet=",k
90 PRINT "a terulet=",t
A program a RUN parancs hatására az alábbiakat írja ki:
a sugar= a kerulet= a terulet= |
5 31.415927 78.539818 |
A program 40-es sorában szereplő PI az M betűnél van E módban. Értéke - ahogy a következő sorban látható - 3,1415927. A program most csak az 5 egység sugarú kör kerületét és területét számítja ki. Más sugár esetén a 30-as sorba be kell írni a kívánt értéket.
FELADATOK
Helye: a G billentyű, a kurzor K. A GO TO jelentése: menj! Eddigi ismereteink alapján csak olyan programokat tudunk írni, melyek végrehajtása a legkisebb sorszámú utasításnál kezdődik, és amelynél a program a legnagyobb sorszámú utasításig minden utasítást végrehajt. Az ún. vezérlésátadó utasításokkal eltérhetünk ettől a sorrendtől. Ezek közül legelső a GO TO utasítás.
A GO TO utasítás formája:
sorszám GO TO új sorszám
az új sorszám helyébe valamilyen létező sorszámot kell írni.
A GO TO utasítást feltétlen vezérlésátadó utasításnak hívjuk, mert amikor a BASIC program a végrehajtás során a GO TO utasításra ér, majd minden esetben az új sorszámmal jelölt utasítással folytatódik a program. Például:
30 GO TO 100
A program a 30-as sor után a 100-as sorszámú utasítással folytatódik.
Meg kell vizsgálnunk az új sorszám megadásának lehetőségeit. A leggyakrabban előforduló esetre - amikor a sorszámot állandóként adjuk meg - már láttunk példát. Az új sorszámot azonban megadhatjuk tetszőleges változóként vagy kifejezésként is. Ilyenkor csak az a lényeg, hogy a változó vagy a kifejezés értéke létező sorszám legyen.
Ha a végeredmény nem létező sorszám, akkor két eset fordulhat elő. Ha a sorszám nem létezik, de nála nagyobb előfordul a programban, akkor a program ezzel a nagyobb sorszámú sorral folytatódik, ahogy ez az 5. mintapéldában is látszik.
10 REM otodik mintaprogram
20 REM pelda a GO TO utasitasra
30 GO TO 44
40 PRINT "ezt nem irja ki"
50 PRINT "ezt kiirja"
60 PRINT "vege"
Ha a GO TO utasításban olyan sorszámot adunk meg, amely nagyobb a programban előforduló legnagyobb sorszámnál, akkor a program 0 OK, ... üzenettel leáll. Ha az 5. mintaprogramban például azt írnánk, hogy
30 GO TO 700
és ezt futtatnánk, akkor a program
0 OK, 30:1
üzenettel állna le, és természetesen nem írna ki semmit.
A GO TO-val kapcsolatosan felmerülhet a kérdés, hogy a GO TO utasításban megadható-e magának a GO TO-nak a sorszáma? Formailag nem hibás az ilyen szerkezet, logikailag azonban igen. A BASIC ugyanis nem tudja, hogy mikor kell befejeznie az ilyen szerkezetet tartalmazó programokat. A soha véget nem érő programrészek neve: végtelen ciklus, (A végtelen ciklusban futó program a BREAK billentyűvel állítható meg.)
Az IF utasítás helye: az U billentyű, a THEN utasítás helye: a G billentyű SYMBOL SHIFT-tel, a kurzor: K, illetve L. Az IF jelentése ha, a THEN jelentése akkor. Az IF utasítással a programozó olyan feltételeket határozhat meg, amelyek megváltoztatják a program utasításainak végrehajtási sorrendjét.
Általános alakja:
sorszám IF feltétel THEN utasítás (utasítások)
Működése a következő: a BASIC először kiértékeli a feltételt. A feltétel - akármilyen bonyolult is - vagy igaz, vagy nem igaz, azaz hamis. Ha a feltétel igaz, akkor a program a THEN utáni utasítással vagy utasításokkal folytatódik. Ha a feltétel hamis, akkor a gép az IF utasítás sora utáni BASIC sort hajtja végre.
A feltételeket két csoportra oszthatjuk: vannak egyszerű és összetett feltételek. Az egyszerű feltételek az ún. relációk, amikor két értéket hasonlítunk össze, tehát egymáshoz viszonyítjuk őket. Összehasonlításra az egyenlő, nagyobb, kisebb, nagyobb vagy egyenlő, nem egyenlő, kisebb vagy egyenlő jeleket használjuk. (Ezek az L, T, R, E, W, Q billentyűkön érhetők el L kurzorral a SYMBOL SHIFT segítségével.)
Az összetett feltételeket egyszerű feltételekből állíthatjuk össze az ÉS, VAGY, NEM logikai műveletekkel. Az AND (magyarul és) az Y billentyűn, az OR (magyarul vagy) az U billentyűn, a NOT (magyarul nem) az S billentyűn érhető el a SYMBOL SHIFT-tel L kurzor mellett.
Ha két vagy több egyszerű feltételt AND segítségével összetett feltétellé - logikai kifejezéssé - kapcsolunk össze, az összetett kifejezés akkor és csak akkor lesz igaz, ha valamennyi részfeltétel igaz. Ha két vagy több egyszerű feltételt OR segítségével összetett feltétellé kapcsolunk össze, az összetett feltétel csak akkor hamis, ha valamennyi részfeltétel hamis. A NOT művelettel csak egy logikai kifejezést tudunk az ellenkezőjére váltani: hamisból igazzá, igazból hamissá alakítani. Megjegyezzük, hogy a 3 logikai művelettel és a relációkkal tetszőlegesen bonyolult logikai kifejezések építhetők fel.
Azt is meg kell néznünk, hogy milyen utasítást írhatunk a THEN utasítás után. A válasz kétféle lehet: először is igaz az, hogy a ZX SINCLAIR BASIC semmiféle korlátozást nem ír elő. Másrészt viszont vigyázni kell arra, hogy milyen utasítást írunk oda, ugyanis könnyen áttekinthetetlenné válik a program, és ekkor nehéz javítani. Az eddig tárgyak utasítások közül maga az IF utasítás az, amit lehet, de nem célszerű a THEN után írni. Az ilyen - ún. egymásba ágyazott (F utasítások - áttekinthetetlenné teszik a programot és nehezítik a hibák keresését Is. Végezetül megjegyezzük, hogy a SINCLAIR Spectrum BASIC-ben a THEN utasítás után mindig valamilyen utasításnak kell állnia (van ugyanis olyan BASIC-változat, ahol a THEN utasítás után egy utasítássorszám is elegendő).
A következő példában a 2-nek 1000-nél kisebb pozitív hatványait számoljuk ki. Érdemes megfigyelni az 50-es sorban lévő üres PRINT utasítást, amely egy üres sort ír ki, tehát soremelést jelent. A 70-es sorban lévő utasítást sokszor - szám szerint 10-szer - hajtja végre a program. A 60-as, 70-es és 80-as sorokban lévő szerkezetet ciklusnak hívjuk.
10 REM hatodik mintaprogram
20 REM pelda a GO TO es az IF utasitasra
30 REM 2 hatvanyai 1000 alatt
40 PRINT "KITEVO","2 HATVANYAI"
50 PRINT
60 LET kitevo=0
70 LET eredm=2^kitevo
80 IF eredm<=1000 THEN PRINT kitevo,eredm: LET kitevo=kitevo+1: GO TO 70
FELADATOK
3. | A 2. példát javítsuk ki úgy, hogy a program ellenőrizze, a beadott adatok háromszöget alkotnak-e! Ennek feltétele, hogy bármely két oldal összege nagyobb legyen a harmadiknál. Ha nincs ilyen háromszög - azaz az előbbi feltétel nem teljesül -, akkor a program írja ki a NINCS ILYEN HAROMSZOG szöveget és az oldalakat. A program minden esetben írja ki, hogy VEGE. |
4. | Írjunk általános BASIC programot az ax^2 + bx + c = 0 másodfokú egyenlet megoldásainak kiszámítására a = 1, b = -7, c = 12 értékek feltételezésével! Ha nincs valós megoldás (b^2 - 4ac = negatív), a program írja ki: NINCS VALOS MEGOLDAS. Ha csak egy megoldás van (b^2 - 4ac = 0), a program írja ki: CSAK EGY MEGOLDAS VAN, és számolja ki ezt az egy megoldást. Ha két megoldás van, akkor számolja ki a két megoldást. Ha az a = 0, írja ki: NEM MASODFOKU. A program befejeződésekor írja ki: VEGE. |
5. | Írjunk programot az ún. Fibonacci-sorozat első 20 tagjának kiszámítására! (A sorozat: 0, 1, 1, 2, 3, 5 stb., azaz minden tag az őt megelőző két tag összege.) |
6. | Írjunk programot a faktoriális kiszámítására! (Egy N egész szám faktoriálisa: 1*2*3*...*N.) Próbáljuk kiszámítani 5 faktoriálisát! |
3.6. A READ, a RESTORE és a DATA utasítás
A három utasítás működése szorosan összefügg egymással, ezért egyszerre ismertetjük őket. Három egymás melletti billentyűn (A, S, D) találhatók E módban (azaz a kurzor: E).
(A READ jelentése: olvasd, a RESTORE jelentése: helyreállítani, a DATA adatokat jelent.)
Az eddig megismert utasításaink közül csak a LET utasítással tudtunk egy változónak értéket adni. Ha olyan feladatokat oldottunk meg, ahol ugyanazt a számítást többféle bemenő adattal kellett elvégezni, akkor mindig belejavítottunk a programba, és ezután újra futtattuk. Az ilyen jellegű feladatokat a READ, RESTORE és DATA utasításokkal kényelmesebben megoldhatjuk. A három utasítás formális leírása:
sorszám DATA állandó(k) vesszővel elválasztva
sorszám READ változó(k) vesszővel elválasztva
sorszám RESORE (sorszám)
A DATA utasítással állandókat helyezhetünk el a program területén. Ez úgy történik, hogy a DATA kulcsszó után felsoroljuk az állandókat. Az állandók közé vesszőt kell tenni, a karakter típusú állandókat idézőjel közé írjuk.
A DATA utasítással elhelyezett állandókat a READ utasítással tudjuk kiolvasni. A READ után változók állnak, vesszővel elválasztva.
A programban a DATA és a READ utasítás egymáshoz viszonyított helyzete tetszőleges, azaz lehet előbb a DATA, utána a READ, de lehet fordítva, sőt összevissza is. A programban - akár elszórtan is - elhelyezkedő DATA utasítások állandóit ugyanis a BASIC sorra veszi.
A READ utasítás azonban csak akkor használható, ha a programban DATA is van. Biztosítanunk kell ugyanis, hogy a READ utasítások különféle változóihoz a DATA utasítások megfelelő adatai tartozzanak. A megfelelésnek egyrészt típus szerinti, másrészt pedig logikai, értelem szerinti megfelelésnek kell lennie.
A READ utasítás sorfolytonosan olvas, ami azt jelenti, hogy a DATA-ban tárolt adatok közül legelőször az elsőt, majd a másodikat és így tovább olvassuk ki. Az elmondottakat szemlélteti a következő programrészlet is:
1 DATA 1,2,"a"
2 READ x , y
3 DATA "b",-9,7
4 READ x$,y$
5 READ w, z
10 PRINT x,y,x$,y$,w,z
Az 1-es és 3-as sorban a DATA utasításokban helyeztük el az állandókat, amelyeket a 2-es, 4-es, 5-ös sorokban lévő READ utasításokkal olvasunk ki. Az első és utolsó két adat numerikus, a harmadik és negyedik adat karakteres. Ennek megfelelően az első READ utasításban 2 numerikus, a második READ utasításban 2 karakteres, a harmadikban pedig 2 numerikus változóba olvassuk be az állandókat. Ha a 6-os sorba egy újabb READ utasítást írnánk, akkor az
E Out of DATA, 6:1
üzenetet kapnánk. Ez annyit jelent, hogy elfogyott a DATA utasításokban tárolt adat.
Ilyenkor segít a RESTORE utasítás. Ennek hatására újra elölről tudjuk olvasni a DATA-ban tárolt adatokat (példánkban még 6-szor). Az előbbi programrészhez például hozzáírhatjuk a következő sorokat:
6 RESTORE
7 READ a,b,c$,d$,e,f
20 PRINT a,b,c$,d$,e,f
Így a tárolt 6 állandót újra kiolvashatjuk.
Az eddig elmondottakból az következik, hogy a DATA-ban tárolt adatokat nem tudjuk átugrani, visszalépni sem tudunk, csak a legelső elemre nyúlhatunk vissza. A RESTORE utasítást bármikor használhatjuk, nemcsak az összes adat kiolvasása után.
A ZX Spectrum BASIC-ben több DATA esetén megadható, hogy a RESTORE hatása melyik sortól érvényesüljön:
1 DATA 11,12,13
2 DATA 21,22,23
3 DATA 31,32,33
4 READ a1,a2,a3,a4,a5,a6,a7,a8,a9
5 RESTORE 3
6 READ b1,b2,b3
7 PRINT bl,b2,b3
Eredménye:
31 |
32 |
lesz.
A hetedik mintapéldában feltételeztük, hogy egy bizonyos héten minden nap adva van a napi középhőmérséklet Celsius-fokban. A példában kiírattuk a napokat és a hozzájuk tartozó hőmérsékletet, továbbá kiszámítottuk a heti átlaghőmérsékletet.
10 REM hetedik mintaprogram
20 REM pelda a DATA es a READ utasitasra
30 REM heti atlagos homerseklet
40 DATA "hetfo",25.4,"kedd",27.7
50 DATA "szerda",22.2,"csutortok",23.3
60 DATA "pentek'",24.4,"szombat"
70 DATA 18.8,"vasarnap",17.7
80 LET gyujto=0
90 LET i=1
100 PRINT "NAP","HOMERSEKLET (C)"
110 PRINT
120 READ n$,hom
130 PRINT n$,hom
140 LET gyujto=gyujto+hom
130 LET i=i+1
160 IF i<=7 THEN GO TO 120
170 PRINT : PRINT "ATLAGOS",gyujto/7
NAP hetfo ATLAGOS |
HOMERSEKLET (C) 25.4 22.785714 |
A DATA - READ - RESTORE utasításról eddig elmondottak a legtöbb BASIC változatban megtalálhatóak (a RESTORE sorszám alaktól eltekintve). A ZX Spectrum BASIC érdekessége, hogy a DATA-ban változók is megadhatók. Ilyenkor a DATA-ba változóneveket kell írni, és a változóknak a felhasználásig - a READ utasítás előtt - értéket kell kapniuk. Ezt a következő programrészlet szemlélteti:
10 LET n=5
20 DATA n,-1,-2,-3,-4,-5,-6,-7
Itt a 20-as sorszámú DATA utasításban az n egy olyan változó, melynek konkrét értéke 5.
Helye: az I billentyű, a kurzor: K. Jelentése: beolvasni. Igen fontos utasítás. Jelentőségét taglalva elég arra utalnunk, hogy eddig csak állandó bemenő adatokkal tudtuk végrehajtani a programjainkat. Az INPUT utasítás segítségével a programoknak különböző adatokat tudunk megadni, és ez lényegesen eltér az eddig megismert adatmegadási lehetőségektől: a LET, a READ és a DATA utasításoktól. Eddig ugyanis csak úgy tudtuk megváltoztatni a programok bemenő, kiinduló adatait, hogy belejavítottunk a programba és RUN paranccsal újrafuttattuk. Az INPUT utasítás segítségével végrehajtás közben tudunk bemenő adatokat adni a programnak.
Az INPUT utasítás legegyszerűbb formája:
sorszám INPUT változók listája
A változók listájában azokat a változókat kell felsorolni, amelyeknek a program futása során majd a billentyűzetről akarunk értéket adni. A változók listájában tetszőleges numerikus vagy karakteres típusú, egyszerű vagy összetett változó lehet meghatározatlan sorrendben. A felsorolt változókat vessző vagy pontosvessző választja el egymástól.
A program végrehajtása során, amikor a vezérlés az INPUT utasításra kerül, a képernyő alsó, adatbeviteli sorában egy villogó L - nagybetűs üzemmód esetén C - kurzor jelenik meg. Ez jelzi, hogy a program adatbevitelre vár. Ekkor üthetjük be a billentyűzeten az INPUT-ban felsorolt változók típusának megfelelő adatokat. Minden változó bebillentyűzése után meg kell nyomni az ENTER-t. Numerikus változóba természetesen csak numerikus jellegű adatok olvashatók be. Karakteres változóba az idézőjelen kívül mindenféle adatot beolvashatunk. A numerikus adatok bebillentyűzésénél a konstansoknál leírt összes formát használhatjuk.
A következő mintapéldában az INPUT utasítás használatát mutatjuk be. A program azt szemlélteti, hogy az INPUT utasítás csak az adatok típusát - numerikus vagy karakteres - ellenőrzi, a tartalmát nem. Ez mindig a program készítőjének a feladata.
Ha numerikus típusú változó bevitele esetén betűvel kezdődő adatot írunk be, akkor a program 2-es hibaüzenettel leáll. Ez azért történik így, mert az értelmező úgy tekinti az ilyen beírást, mintha újra egy már a gépben lévő változó értékét kívánnánk megadni.
10 REM nyolcadik mintaprogram
20 REM pelda az: INPUT -ra (adatellenorzes)
30 PRINT "Jo napot! En a ZX Spectrum vagyok"
40 PRINT
50 PRINT "Ont hogy hívjak, hany eves?"
60 INPUT n$,ev1
70 PRINT "Hany eve foglalkozik BASIC-kel?"
80 INPUT ev2
90 IF ev1<=ev2 OR ev1<=0 OR ev1<=6 OR ev1>100 THEN PRINT " Ejnye, kedves ";n$,, "On be akar csapni": GO TO 50
100 IF ev1<=18 THEN PRINT "Kedves ";n$;"!",,"Sok oromod lesz meg a BASIC programozasban!"
110 IF ev1>18 AND ev1<=30 THEN PRINT "Kedves ";n$;"!",,"Onbol meg jo programozo lehet!"
120 IF ev1>30 THEN PRINT "Kedves ";n$;"!",,"Meglatja, nem is olyan nehez dolog ez."
Programjainkat mindig úgy kell megírni, hogy a végrehajtáskor egyértelmű legyen, mikor milyen adatot vár a program. A mintaprogramban erre valók az INPUT utasítás előtti PRINT-ek. Annyira természetes, hogy a programozó minden INPUT utasításnál felvilágosítást akar adni a várt adatokról a program használójának, hogy ezt a lehetőséget az INPUT utasításba is beépítették. Az INPUT változói előtt idézőjelben tetszőleges szöveg is megadható. Az idézőjeles szöveget vessző vagy pontosvessző választja el a változóktól. Formálisan:
sorszám INPUT "tetszőleges szöveg" vagy változók listája
Az előző program 50-es, 60-as, 70-es, 80-as sorát így is írhattuk volna:
50 INPUT "ont hogy hívjak, hany eves",n$,ev1
60 INPUT "hany eve foglalkozik a BASIC-kel";ev2
vagy még egyszerűbben:
50 INPUT "ont hogy hívjak? ";n$,"hany eves? ";ev1,,"hany eve foglalkozik a BASIC-kel ";ev2
Az INPUT utasításról eddig elmondottak a legtöbb BASIC-változatban megtalálhatók, van azonban ennek az INPUT-nak néhány olyan tulajdonsága, ami más BASIC-változatokban viszonylag ritka. Az egyik érdekes lehetőség, hogy az INPUT utasításban kiírathatunk változókat is. Ekkor a kiírandó változókat zárójelbe kell tenni. Ez látható a következő mintapélda 80-as sorában.
10 REM kilencedik mintaprogram
20 REM pelda az INPUT utasitasra
30 REM osztalyatlag szamitasa
40 PRINT "A program a tanulok atlagabol osztalyatlagot szamit"
50 PRINT "Adatbevitel vege: 0 vagy negativ szam."
60 LET a=0: LET i=1
70 INPUT "KEREM AZ OSZTALY JELET ";j$
80 INPUT "Kerem az ";(i);". tanulo atlagat! ";j
90 IF j<=0 THEN GO TO 120
100 IF j>5 THEN PRINT "Hibas adat, kerem ujra! ": GO TO 80
110 LET a=a+j: LET i=i+1: GO TO 80
120 IF a<>0 THEN PRINT "OSZTALY: ";j$;" ATLAG: ";a/(i-1)
130 INPUT "Kell meg szamolni? (i/n)",j$
140 IF j$="i" THEN GO TO 60
A mintapéldában azt feltételeztük, hogy egy iskola tetszőleges számú osztályában az osztályátlagot kell kiszámolni, ha ismert az egyes tanulók átlaga.
Azt mondottuk, hogy a karakteres változókba nem olvashatók be idézőjelek. Ez igaz is, ha csak az eddig ismertetett lehetőségeink lennének. Ha viszont az INPUT utasítást kiegészítjük a LINE utasítással (3-as billentyű, E módban, SYMBOL SHIFT-tel), akkor már tetszőleges jeleket - az idézőjelet is beleértve - be tudunk olvasni.
FELADATOK
7. | Írjuk át a másodfokú egyenletet megoldó programot úgy, hogy tetszőlegest bemenő adatokkal tetszőleges számú egyenletet tudjunk megoldani! |
FOR (helye: az F billentyű, a kurzor: K),
TO (helye: az F billentyű és vele együtt a SYMBOL SHIFT, a kurzor: L vagy C),
STEP (helye: a D billentyű és a SYMBOL SHIFT, a kurzor: L vagy C),
NEXT (helye: az N billentyű, a kurzor: K).
A FOR jelentése: számára, a TO jelentése: -ig, valameddig, a STEP jelentése: lépés, a NEXT jelentése: következő.
Ezek az utasítások ugyanahhoz a fogalomhoz, a ciklushoz kapcsolódnak. Eddig is volt már szó ciklusokról, sőt példát is láttunk rájuk anélkül, hogy a nevükön neveztük volna. A ciklus a mindennapi életben és a számítástechnikában is valamilyen ismétlődő jelenséggel kapcsolatos. Ha egy számítástechnikai feladatban olyan részek vannak, amelyeket sokszor kell ugyanúgy vagy hasonlóan megismételni, akkor az adott részekre ciklust írunk (vagy egy másik elfogadott elnevezéssel, ciklust szervezünk).
A számítástechnika irodalma igen részletesen foglalkozik a ciklusokkal. A ciklusok vizsgálatánál legalább két alapkérdést tisztázni keli. Az egyik, hogy tudjuk-e már a ciklusba lépéskor, hányszor kell majd a ciklust végrehajtani? A másik alapkérdés, hogy mikor dől el: szükséges-e még továbbra is végrehajtani a ciklust, vagy sem. Erre a ciklusba lépés előtt vagy a ciklus végrehajtása során kapunk választ.
Úgy gondoljuk, nem igényel bővebb magyarázatot az sem, hogy eddigi ismereteinkkel - a GO TO és az IF utasításokkal - már tetszőleges ciklusokat tudunk írni. (A kétféle ciklusra példa a hatodik és hetedik mintaprogram: a hatodik mintapéldában nem tudtuk előre, hányszor kell végrehajtani a ciklust, a hetedikben tudtuk.)
A ZX Spectrum BASIC-ben az olyan ciklusok megírására, amelyeknél előre tudjuk, hányszor kell végrehajtani, külön utasítás van. Mielőtt a konkrét utasításra térnénk, vizsgáljuk meg, milyen jellemzői lesznek az ilyen ciklusnak. Mindenekelőtt kell majd egy numerikus típusú változó, amelynek segítségével azt számoljuk, hogy hányszor hajtottuk végre a ciklust. Ennek a ciklusváltozónak lesz egy kezdőértéke (ez a ciklusváltozó értéke a legelső ciklus végrehajtása előtt) és egy végértéke (ez a ciklusváltozó értéke a ciklus legutolsó végrehajtása során). Ismernünk kell azt is, hogy a kezdőértéktől hogyan jutunk el a végértékhez. A ciklus kezdetét egy összetett, 2 vagy 3 kulcsszóból álló utasítás jelzi:
sorszám FOR ciklusváltozó = kezdőérték TO végérték
vagy
sorszám FOR ciklusváltozó = kezdőérték TO végérték STEP lépés
A FOR jelentése az volt, hogy számára, amit így kell érteni: a ciklusváltozó számára az egyenlőségjel utáni érték legyen a kezdőérték. A TO jelentéséről azt mondtuk, -ig, ennek megfelelően az utána álló kifejezés a ciklusváltozó végértékét jelenti, azt az értéket, ameddig a ciklusváltozónak el kell jutnia. A STEP jelentése: lépés, azt jelzi, hogy a ciklusváltozó kezdőértékétől milyen lépésekben kell eljutni a végértékhez. A ciklus első sorát, amelyben a FOR utasítás áll, szokás ciklusfejnek is nevezni.
A ciklus lényege a ciklusfej után következik. Itt olyan utasítás vagy utasítások következnek, amelyeket többször végre kell hajtani. Ezek tetszőleges BASIC utasítások lehetnek. A ciklus végét egy speciális utasítás jelzi:
sorszám NEXT ciklusváltozó
A NEXT jelentése: következő, vagyis a ciklusváltozó akkor veszi fel a következő értékét, amikor a vezérlés a NEXT utasításra ér. A NEXT után ugyanazt a ciklusváltozót kell írni, mint a FOR után.
A FOR és a NEXT kőzött lévő utasítást vagy utasításokat a ciklus magjának nevezzük.
A ciklus használatához néhány szabályt még meg kell ismerni. A ciklusváltozó csak egy-egy betűből álló numerikus típusú változó lehet. A ciklusváltozó kezdőértéke, végértéke, lépésköze numerikus állandó, változó, függvény vagy kifejezés lehet. A lépésköz értéke lehet negatív szám, sőt törtszám is. Kiírása nem kötelező, ekkor a lépésköz fettételezett értéke +1.
Amint már említettük, a ciklusváltozó az új értékét a NEXT utasítás végrehajtásakor veszi fel. Ekkor a ciklusváltozó pillanatnyi értéke a lépésköz értékével nő (illetve csökken, ha a lépésköz negatív). A végrehajtási feltétel vizsgálata - azaz, hogy a ciklusváltozó elérte-e a végértéket - a ciklus végrehajtása előtt megy végbe. Ebből következik, hogy a ciklus végrehajtása után, azaz a ciklusból való kilépéskor a ciklusváltozó értéke nem a végértékkel lesz egyenlő, hanem annál nagyobb (illetve ha a lépésköz negatív volt, akkor kisebb) lesz.
Ha a FOR utasításba olyan feltételt írunk, amely soha nem teljesül, akkor a ciklus egyszer sem fut, mivel a végrehajtási feltétel a ciklusba lépés előtt értékelődik ki.
Fontos szabály, hogy a ciklusmagba nem szabad beugrani, azaz GO TO utasítással - vagy egyéb utasítással - a FOR ás NEXT közötti sorszámokra ugrani. Ekkor ugyanis a számítógép nem tudja beállítani a ciklus kezdő feltételeit. Ha ilyet csinálunk, akkor vagy az
1 NEXT without FOR,...
vagy a
2 Variable not found, ...
üzenetet kapjuk. Az 1 jele üzenet azt jelenti, hogy a NEXT-nek nincs párja, nincs hozzá tartozó FOR. Ezt olyankor kapjuk, amikor van már olyan nevű változó, mint amit a NEXT után irtunk, de az nem a ciklusváltozó. A 2 jelű hibaüzenet azt jelenti, hogy egyáltalán nincs olyan változó, mint amit a NEXT után írtunk.
A ciklusból általában kiugrani sem szabad, de lehet, mert ezt a BASIC nem tudja ellenőrizni. Ajánlatos megszokni, hogy a ciklust csak a NEXT utasításnál hagyjuk el.
A cikluson belül a ciklusváltozót nem szabad megváltoztatni, de számolni lehet vele.
A tizedik mintaprogram a ciklusszervezést, a FOR-NEXT utasítás használatát mutatja be a kamatos kamat kiszámításával.
10 REM tizedik mintaprogram
20 REM pelda a FOR-NEXT utasitasra
30 REM kamatos kamat tablazasa
40 INPUT "Kerem az alap, a kamatlab es az evek erteket",a,k,e
50 PRINT "EV","KAMATOS KAMAT"
60 FOR i=1 TO e
70 LET a=a+a*k/100
80 PRINT i,a
90 NEXT i
Azt állítottuk, hogy a cikluson belül tetszőleges BASIC utasítás állhat. Felmerül a kérdés, hogy a FOR-NEXT utasításpáron belül állhat-e újabb FOR utasítás? Készíthetünk-e ún. egymásbaágyazott ciklusokat? A válasz: igen, de egy szabályt be kell tartani. Ha egy ciklus egy másik ciklust tartalmaz, azt csak teljes egészében tartalmazhatja. A gyakorlatban ehhez a szabályhoz elég annyit megjegyeznünk, hogy az először kezdett ciklust kell legutolja befejezni, a másodikként kezdett lesz az utolsó előtti stb.
Végezetül még megjegyezzük, hogy ha a FOR-NEXT használatával kapcsolatos szabályokat betartjuk, akkor nem írhatunk végtelen ciklusokat (kivétel, ha a ZX Spectrum BASIC-ben a STEP után növekményként 0-t adunk meg). |
FELADATOK
8. | Írjuk át a faktoriálist számító programot FOR-NEXT utasítással! A program tetszőleges egész számra működ jön 1-33 között. |
9. | Írjunk programot a 3 és 3000 közötti 3-mal osztható számok összegének ki számítására! (Ne a számtani sorozat összegképletét használjuk!) |
10. | Írjuk át a Fibonacci-féle sorozatot számoló programunkat FOR-NEXT utasítással! |
11. | Írjunk olyan programot, amely az összes csak páratlan számjegyet tartalmazó 3 jegyű számot előállítja! |
12. | Tudjuk, hogy 1 mérföld 1609,33 méterrel egyenlő. Készítsünk táblázatot tízes lépésközzel 10 és 90 között, mellyel mérföldből km-t, illetve km-ből mérföldet tudunk számítani! |
3.9. A DIM utasítás és a tömbök
Helye: a D billentyű, a kurzor: K. Az angol dimension - kiterjedés, terjedelem - rövidítése.
Mielőtt az utasítás használatáról, szabályairól szólnánk, meg kell ismerkednünk néhány fogalommal. Az adattípusok tárgyalásánál nem magyaráztuk el az összetett adatokat. Most, hogy már van némi számítástechnikai ismeretünk, pótoljuk a hiányt.
Gyakori feladat, hogy több, valamilyen szempontból összetartozó adatot kell kezelnünk. Ilyenkor szükségünk lehet egy-egy adatra külön is, de egyszerre az egész adatmennyiségre is. Gondoljunk például egy olyan egyszerű feladatra, mint egy iskolai osztály tanulmányi átlagának kiszámítása tanulónként, tantárgyanként. Az ilyen és hasonló jellegű feladatokat az egyszerű változók segítségével nem, vagy csak igen nehézkesen lehet megoldani, míg tömbök, vagyis az összetett változók segítségével viszonylag könnyű.
Mi is az a tömb? Egy jellemzőjét már megismertük: az összetett változók közé tartozik. További lényeges tulajdonságai is ebből következnek: több, hasonló típusú - numerikus vagy karakteres - adatra egyetlen névvel, a tömbnévvel tudunk majd hivatkozni. Ha a több adatból valamelyik konkrét adatot akarjuk kiválasztani, arra is van lehetőség, de ekkor valahogy tudatnunk kell a számítógéppel, hogy a sok adat közül melyikre gondolunk.
A DIM utasítás fő célja, hogy a tömbök számára helyet foglaljunk le: meghatározhatjuk a tömb nevét, típusát, a benne tárolt adatok számát, elhelyezkedését. A DIM utasítás általános formája:
sorszám DIM tömbnév (elemek száma)
A sorszám és a kulcsszó már ismert. A tömbnév helyén a tömb nevét kell megadni, amely a ZX Spectrum BASIC-ben csak egyetlen betű lehet. A karakteres típusú tömbök neve után $ jelet kell ími. A tömbnév után zárójelek között meg kell adni a tömb elemeinek számát és azt, hogy ezek az elemek hogyan helyezkednek el. Például a
10 DIM a(20)
20 DIM a$(20)
utasítások azt jelzik, hogy a 10-es sorszámú DIM utasítással lefoglaltunk egy numerikus tömböt, melynek neve: a, és amely 20 elemet tartalmaz. A 20-as sorszámú utasításban egy 20 elemű karakteres tömböt jelöltünk ki, melynek minden elemében 1 karaktert tárolhatunk. A
30 DIM b(5,4)
40 DIM b$(5,4)
50 DIM c(4,5)
60 DIM c$(4,5)
utasításokkal szintén 20 elemű tömböket jelöltünk ki, de az elemek elhelyezkedése más, mint az a jelű tömböknél. Az a jelű tömbre azt mondjuk: egydimenziós. Úgy képzelhetjük el, hogy a 20 elem egymás után, sorban helyezkedik el. A b ás c jelű tömbökre azt mondjuk: kétdimenziósak. A b és b$ nevű tömböket olyan táblázatként kell elképzelnünk, melynek 5 sora és 4 oszlopa van. Ezzel szemben a c és c$ nevű tömbök olyan kétdimenziós tömbök, melyeknek 4 soruk és 5 oszlopuk van.
A példákból levonhatjuk az általános tanulságot: a tömbnév után zárójelben a tömb határait kell megadni, több dimenziós tömb esetén az egyes irányok határait vesszővel kell elválasztani egymástól.
A ZX Spectrum BASIC-ben tetszőleges dimenziószámú tömböket használhatunk, de a 3-nál nagyobb dimenziószámú tömb elemeinek elhelyezkedését nehezen tudjuk elképzelni. A gyakorlati feladatokhoz rendszerint elegendőek a kétdimenziós tömbök.
A ZX Spectrum BASIC-ben a DIM utasításban nemcsak állandók szerepelhetnek, hanem változók, sőt kifejezések is. A változónak természetesen megfelelő értékkel kell rendelkeznie illetve a kifejezésnek kiértékelhetőnek kell lennie -, mire a vezérlés a DIM utasításra ér.
Akármilyen formában - állandó, változó, kifejezés - adjuk is meg a tömb határait, a ZX Spectrum kerekíti a törtszámokat. A tömb határainak felső értéke nincs, ezt a tárméret és a program mérete határozza meg.
Lényeges és a legtöbb BASIC-változattól eltér a ZX Spectrum két tulajdonsága: az egyik, hogy a karakteres tömb egy elemében csak egyetlen karaktert tárolhatunk. A másik: a DIM utasításnak a tömb felhasználása előtt kell lennie.
De hogyan is használjuk a tömböket? Lényegében ugyanúgy, mint minden más változót, de - az indexek segítségével - mindig ki kell jelölnünk, hogy melyik tömbelemről van szó. Az index a megfelelő utasításban a tömbnév után zárójelben lévő állandó, változó vagy kifejezés, amelynek segítségével megmondjuk, hogy az adott műveletben a tömb melyik eleme vesz részt. Például a
10 DIM a(20)
20 PRINT a(1)
30 PRINT a(20)
utasítások az a tömb első és utolsó elemét fogják kiírni. Ha kiegészítjük a programrészletet,
40 LET a(1)=100
50 LET a(20)=-99
60 PRINT a(1),a(20)
akkor a 60-as utasítás kiírja a tömb első és utolsó elemét, melyeknek előzőleg 100 és -99 értéket adtunk. Az előbbiekből az is világosan kiderül, hogy ha egy tömb minden elemével akarunk valamilyen műveletet végezni, akkor azt a műveletet általában egy cikluson belül kell majd elvégeznünk.
A következő mintaprogrammal egy statisztikai jellegű kimutatást készítettünk. Feltételeztünk egy munkahelyet 8 dolgozóval. A program beolvassa a 8 dolgozó nevét és fizetését, kiszámítja a dolgozók átlagos fizetését, valamint azt, hogy az egyes dolgozók fizetése az átlagfizetés hány százaléka.
10 REM tizenkettedik mintaprogram
20 REM pelda a DIM utasitasra
30 REM fizetesi statisztika
40 DIM f(8)
50 DIM n$(8,15)
60 DIM s(9)
70 LET gyujto=0
80 FOR i=1 TO 8
90 INPUT "Kerem az ";(i);". nevet es fizetest",v$,f(i)
100 LET gyujto=gyujto+f(i)
110 LET n$(i)=v$
120 NEXT i
130 LET atlag=gyujto/8
140 FOR i=1 TO 8
150 LET s(i)=f(i)*100/atlag
160 PRINT n$(i),f(i);" ";s(i)
170 NEXT i
Kiss Endre Nagy Bela Kis Kati Nagy Andi Kovacs Istvan Ret Sandor Ot Odon Grof Klara |
10000 20000 30000 40000 50000 60000 70000 80000 |
22.222222 44.444444 66.666667 88.888889 111.11111 133.33333 155.55556 177.77778 |
Felhívjuk a figyelmet az 50-es, 90-es, 110-es, 160-as sorszámú sorokra, ahol a karakteres tömbök használatára adtunk példát. Az 50-es sorszámú utasításban 8 névnek foglaltunk le helyet, minden név 15 karakter hosszúságú lehet. A 90-es sorban olvassuk be a neveket és a fizetéseket. A neveket egy külön változóba, a v$-ba olvassuk be. A 110-es sorban az n$ tömb egy sorába visszük be a neveket. Az eredményt a 160-as sorban íratjuk ki.
A mintapélda 110-es és 160-as sorában a ZX Spectrum karakteres tömbjeinek egy érdekes tulajdonságára is példát látunk. Egy karakteres tömb minden elemében egyetlen karaktert tárolhatunk. Ha azonban az utolsó indexet - jelen esetben a másodikat - elhagyjuk, akkor egyszerre egynél több adatra is tudunk hivatkozni. Az elhagyott index mutatja meg, hogy mennyi ez az adat. A példában a DIM utasításban 15 volt a második index, ezért ha elhagyjuk, egyszerre 15 adatra tudunk majd hivatkozni, ami megfelel a 15 karakter hosszú neveknek.
A karakteres tömböknek ez a sajátossága általában is igaz. Nézzük meg az alábbi háromsoros programot:
10 DIM a$(5)
20 INPUT a$
30 PRINT a$
Ezt a programot akárhányszor futtathatjuk, mindig csak az első 5 karaktert fogadja el és írja ki.
Az előbbi mintaprogramot kétdimenziós tömbök segítségével valamivel egyszerűbben is meg lehet írni:
10 REM tizenharmadik mintaprogram
20 REM pelda a DIM utasitasra
30 REM fizetesi statisztika
40 INPUT "Hany dolgozo van? ";n,"A leghosszabb nev hany betu? ";h
50 DIM f(n,2)
60 DIM n$(n,h)
70 LET gyujto=0
80 FOR i=1 TO n
90 INPUT "Kerem az ";(i);". nevet es fizetest",n$(i),f(i,1)
100 LET gyujto=gyujto+f(i,1)
110 NEXT i
120 LET atlag=gyujto/n
130 FOR i=1 TO n
140 LET f(i,2)=f(i,1)*100/atlag
150 PRINT n$(i),f(i,1);" ";f(i,2)
160 PRINT
170 NEXT i
Megemlítjük, hogy néhány más BASIC-változattal ellentétben a ZX Spectrumban egy DIM utasítással csak egy tömb adatainak foglalhatunk helyet. Természetesen hibaüzenetet kapunk, ha egy tömb nem létező elemeire hivatkozunk (negatív vagy nullánál kisebb elemszám, a tömb elemszámánál nagyobb elemre hivatkozás, a dimenziószám nem egyezik).
FELADATOK
13. | Hozzunk létre egy egydimenziós numerikus tömböt és töltsük fel adatokkal! Írassuk ki először az elején kezdve a tömb első, második stb. elemét, majd visszafelé először a 10. elemet, majd a kilencediket stb.! |
14. | Hozzunk létre 2 egydimenziós numerikus tömböt! Az egyik tömbbe olvassuk be a termékek egységárait, a másikba a termékekből eladott mennyiséget! (Íjuk ki a két tömböt és az összes árbevételt! |
15. | Írjunk programot, amely egy 10 elemű egydimenziós numerikus tömb elemei közül kiválasztja a legnagyobbat) |
16. | Írjunk programot, amely egy 10 elemű egydimenziós numerikus tömb elemeit növekvő sorrendbe rendezi! |
17. | Egy 4 sorból és 3 oszlopból álló kétdimenziós, numerikus tömb minden sorának minden elemébe írjuk be, hogy hányadik sorban van! (Tehát az első sor minden elemébe 1-et, a második sor minden elemébe 2-t stb.) írassuk ki a tömböt! |
18. | Egy 4 sorból és 3 oszlopból álló 2 dimenziós numerikus tömb minden oszlopának minden elemébe írjuk be, hogy hányadik oszlopban van! (Tehát az első oszlopba 1-et, a második oszlopba 2-t stb.) Írassuk ki a tömböt! |
19. | Írjunk programot, amely egy legfeljebb 50 nevet tartalmazó karakter típusú tömb elemeit névsorba rendezi! Egy név hossza legfeljebb 20 karakter lehet. |
Helye: az A billentyű SYMBOL SHIFT-tel, a kurzor K. Jelentése: állj. Ez a legegyszerűbb BASIC utasítás. Hatására a program leáll, méghozzá a
9 STOP statement, sor: utasítássorszám
alakú üzenettel, ahol a sor annak a sornak a sorszáma, ahol a STOP utasítás volt, a kettőspont után álló szám pedig megmondja, hogy a STOP utasítás hányadik utasítás volt az adott sorban.
A STOP utasítás bárhol elhelyezhető a programban. A STOP hatására leálló programot CONT paranccsal lehet folytatni. A STOP utasítást jól fel lehet használni programhibák kiderítésére. A nem jól működő programba ideiglenes jelleggel tetszőleges helyekre STOP utasításokat írhatunk. Amikor azután egy ilyen STOP utasításon leáll a program, akkor a PRINT parancs segítségével- PRINT utasítássorszám nélkül - tájékozódhatunk arról, meddig is jutott el a programunk. Ha azután úgy döntünk, hogy bizonyos STOP utasítások már feleslegessé váltak, akkor természetesen kitörölhetjük őket a programból.
A STOP utasítást INPUT-ra válaszként megadva a program H üzenettel leáll. A STOP utasítást karaktert váró INPUT utasításban az első idézőjel kitörlése után kell megadni.
3.11. A GO SUB és a RETURN utasítások
A GO SUB utasítás helye: a H,
a RETURN utasítás helye: az Y billentyű, a kurzor mindkét utasításnál: K. A GO SUB utasítás az alprogramok - idegen szóval szubrutinok - végrehajtására ad lehetőséget.
Mi is az az alprogram? Tágabb értelemben véve önálló programot vagy programrészt jelent. A ZX Spectrum BASIC-ben azonban csak ún. belső szubrutint lehet írni. A belső szubrutin fő jellemzője, hogy része a programnak, és az eddig megismert szabályok vonatkoznak rá.
Mi az előnye, értelme az alprogramok használatának? Mindenekelőtt az a legfontosabb, hogy egy alprogrammal áttekinthetőbb programokat tudunk írni. Mód nyílik arra, hogy a feladatokat részekre bontsuk és az egyes problémákat külön oldjuk meg. Az alprogramba a GO SUB utasítással tudunk belépni, melynek formája:
sorszám GO SUB az alprogram sorszáma
ahol az alprogram sorszáma annak a legelső utasításnak a sorszáma, amelyet az alprogramból végre kell hajtani. Ezt a sorszámot nemcsak állandóként, hanem változóként vagy kifejezésként is megadhatjuk, ahogyan ezt a GO TO utasításnál már láttuk.
Az alprogramból a főprogramba egy külön utasítással tudunk visszatérni, mindig a GO SUB utáni utasításra. A visszatérési utasítás alakja:
sorszám RETURN
A RETURN után azért nem kell soha semmit sem írni, mert a gép tudja, hogy hová kell visszatérnie. A GO SUB végrehajtásakor ugyanis a processzor egy speciális memóriarészben - az ún. GO SUB stackben - tárolja a következő utasítás címét.
A GO SUB-ra és a RETURN-re egyetlen szabály vonatkozik. Egy programban a végrehajtott GO SUB és RETURN utasítások számának meg kell egyeznie. Ezt szemlélteti a mintapélda is.
10 REM tizennegyedik mintaprogram
20 REM pelda a GO SUB -ra es a RETURN -re
30 REM sok ertelme nincs
40 PRINT "kezdet"
50 GO SUB 100
60 PRINT "vissza 1"
70 GO SUB 100
80 PRINT "vissza 2"
90 STOP
100 REM itt kezdodik az alprogram
110 PRINT "itt az alprogram"
120 RETURN
kezdet 9 STOP statement, 90:1 |
A mintapéldában két GO SUB utasítás van, de csak egy RETURN. A program mégis jól működik, mert a 90-es sorban a STOP utasítás hatására leáll. Ha a 90-es sort kitörölnénk, akkor a
7 RETURN without GOSUB, 120:1
hibaüzenetet kapnánk, mert a program harmadszor is ráfutna a RETURN-re, aminek logikailag nincs párja (az üzenet is ezt jelzi). Az elmondottakból az is következik, hogy az alprogramokat célszerű a program végére összegyűjteni és a legelső alprogram elé egy STOP utasítást tenni. Az alprogramban tetszőleges utasítás lehet, beleértve újabb alprogram hívását is, ha a GO SUB-ok és a RETURN-ök száma a már említett módon végrehajtáskor megegyezik.
Egy alprogram - a ZX Spectrum BASIC-ben - önmagát is hívhatja, amit rekurziónak nevezünk. Kezdők számára azonban ezt nem javasoljuk.
A következő, összetettebb mintapélda kettős célt szolgál. Egyrészt a GO SUB utasítás használatát világítja meg. Másfelől bemutatja, hogy egy viszonylag összetettebb, a gyakorlati életben is előforduló, bonyolult feladatokhoz közelálló probléma megoldásánál hogyan lehet eljárni. Ismertetni fogjuk a feladatot, a megoldását, sőt a végén a megoldás hiányosságait is.
A feladat a következő: egy tetszőleges iskola - általános iskola stb. - tanulóinak tanulmányi átlagát kell kiszámolni. Ehhez a következő bemenő adatokat ismerjük: a tantárgyak az egyes osztályokban, a tanulók neve és osztályzata az egyes tantárgyakból. Az elkészítendő kimutatás: az egyes tanulók tanulmányi átlaga, az egyes osztályokban az egyes tantárgyakból elért átlag, az osztályátlag és az iskola átlaga.
Az első probléma magának a kitűzött feladatnak a megértése lehet. Itt - úgy véljük - ez nem okoz nehézséget, hiszen iskolába mindenki járt egyszer, s emlékszünk rá, hogy például év végén minden tanuló minden tantárgyból osztályzatot kapott, és ebből számítottuk ki az átlagos tanulmányi eredményt. Ha - mint jelen esetben is - kíváncsiak vagyunk arra, hogy egy osztály milyen átlagos eredményeket ért el az egyes tantárgyakból, akkor ezeket az eredményeket tárolnunk kell, legalább az átlag kiszámításáig. Ha osztályátlagot, sőt iskolaátlagot is akarunk számítani, akkor nyilván gyűjtenünk kell majd valahol az osztályzatokat erre a célra, sőt a tanulók számát is. Nézzük meg most már magát a programot is!
10 REM tizenotodik mintaprogram
20 REM pelda a GO SUB hasznalatara
30 REM iskolai statisztika
40 PRINT "Ez a program a tanulok ev vegi osztalyzataibol kiszamolja egy-egy tanulo atlagat, a tantar- gyankenti atlagot, az osztaly- atlagot es az iskola atlagat."
60 DIM i(2)
70 INPUT "Kerem az osztaly jelet ";j$,"letszamat ",l,"a tantargyak szamat ";t
80 GO SUB 1000
90 GO SUB 2000
100 GO SUB 3000
110 INPUT "Van meg osztaly, amelynek atlagot kell szamolni? (i/n)",v$
120 IF v$="i" OR v$="I" THEN GO TO 70
130 CLS
140 PRINT "AZ OSSZES TANULO SZAMA: ",i(2)
150 PRINT "AZ OSSZES TANULO ATLAGA: ",i(1)/i (2)
999 STOP
1000 REM ***** elokeszítes uj osztaly eseten
1010 DIM j(l,t): REM osztalyzatok tanulonkent
1020 DIM n$(l,20): REM maximum 20 karakteres nevek
1030 DIM t$(t,10): REM tantargynevek
1040 PRINT "Kerem a tantargyak nevet!"
1050 FOR i=1 TO t
1060 INPUT (i);". tantargy neve:";t$(i)
1070 NEXT i
1080 LET osztalyatlag=0
1090 RETURN
2000 REM ***** osztalyzatok tanulonkent es tanulonkenti atlag
2010 FOR i=1 TO l
2020 LET tanulo atlaga=0
2030 INPUT "Az ";(i);". tanulo neve:",n$(i)
2040 FOR j=1 TO t
2050 INPUT (n$(i));" osztalyzata ",(t$(j));" ";j(i,j)
2060 IF NOT (j(i,j)=1 OR j(i,j)=2 OR j(i,j)=3 OR j(i,j)=4 OR j(i,j)=5) THEN GO TO 2050
2070 LET tanulo atlaga=tanulo atlaga+j(i,j)
2080 NEXT j
2090 LET tanulo atlaga=tanulo atlaga/t
2100 PRINT n$(i)," atlaga: ";tanulo atlaga
2110 LET i(1)=i(1)+tanulo atlaga
2120 LET i(2)=i(2)+1
2130 INPUT "Mehet tovabb? (i/n)",v$
2140 IF NOT (v$="i" OR v$="I") THEN GO TO 2130
2150 CLS
2160 LET osztalyatlag=osztalyatlag+tanulo atlaga
2170 NEXT i
2180 RETURN
3000 REM *****tantargyankenti atlag szamitasa
3010 CLS
3020 PRINT "Az ";j$;" osztaly atlaga tantargyankent"
3030 PRINT
3040 PRINT "TANTARGY","ATLAG"
3050 LET sorszam=3
3060 FOR j=1 TO t
3070 LET tantargyatlag=0
3080 FOR i=1 TO l
3090 LET tantargyatlag=tantargyatlag+j(i,j)
3100 NEXT i
3110 LET tantargyatlag=tantargyatlag/l
3120 PRINT
3130 PRINT t$(j),tantargyatlag
3140 LET sorszam=sorszam+2
3150 IF sorszam>20 THEN GO SUB 3500
3160 NEXT j
3170 PRINT : PRINT
3180 PRINT "AZ OSZTALYATLAG: ";osztalyatlag/l
3190 RETURN
3500 REM *****uj kepernyo
3510 INPUT "Mehet tovabb? (i/n)",v$
3520 IF NOT (v$="i" OR v$="I") THEN GO TO 3160
3530 CLS
3540 PRINT "TANTARGY","ATLAG"
3550 PRINT
3560 LET sorszam=2
3570 RETURN
Látható, hogy bár az egész program viszonylag hosszabb, a vezérlőrész rövid, még 20 utasítás sincs benne.
A 40-es sorszámú PRINT utasítással mindössze a program célját közöljük a felhasználóval. Amikor nem maga a program írója a felhasználó, jól jöhet a rövid információ a program működéséről. Természetesen nem szabad megfeledkeznünk arról, hogy a ZX Spectrum egy sorba mindössze 32 karaktert tud kiírni. Ha ezt figyelmen kívül hagyjuk, akkor a gép automatikusan 32 karakterenként tördelni fogja a kinyomtatandó szöveget, többnyire nem a helyesírás szabályainak megfelelően. Ezen többféleképpen is lehet segíteni, mi a legegyszerűbb megoldást választottuk: üres karakterek beiktatását (SPACE billentyű). Az "év végi" után 3, a "tanuló átlagát" előtt 4, az "iskola átlagát" előtt 2 üres hely van. Az ilyen hosszú sorok hátránya, hogy a javításuk lassúbb.
A 60-as sorban az i jelű egydimenziós tömbben az iskolai átlaghoz szükséges adatokat fogjuk gyűjteni: a tömb első elemében az egyes tanulók átlagait összegezzük majd, a második elemben pedig a tanulók számát számoljuk.
A 70-es sorszámú INPUT utasítással 3 adatot olvasunk be: a j$ nevű karakteres típusú változóba az osztály jelét (például 1/a, 3/c stb.). Ez csak adminisztratív célokra szolgál, az egyes osztályokat azonosítja. Az l jelű numerikus változó az osztálylétszámot, a t jelű pedig az osztályban tanított tantárgyak számát jelenti.
A 80-as, 90-es, 100-as sorszámú utasítások egy-egy alprogramot hívnak. Ezek az alprogramok végzik a tényleges adatbeolvasást és a számítást egy-egy osztályban. Miután a program a 3 alprogram végrehajtása után kiszámolta egy osztály eredményeit, a vezérlés a 110-es sorszámú INPUT utasításhoz tér vissza. Ha a "Van még osztály, amelynek átlagot kell számolni?" kérdésre az igent rövidítő i betűvel válaszolunk, akkor a program a 70-es sorban folytatja működését, és új osztály adatait kéri. Látható - amint a FOR utasításnál részletesen is szó volt róla -, hogy így akárhány osztály adatait kiszámíthatjuk, nem kell előre tudnunk, hány osztály lesz. Ha nincs több kiszámolandó részadat, akkor a CLS utasítás - 130-as sor - segítségével töröljük a képernyő tartalmát, és kiíratjuk az i tömb két elemét. Az átlaghoz az első tömbelem tartalmát osztani kell a második tömbelem tartalmával (150-es sor).
Az első alprogram az 1000-es sorszámú sorral kezdődik. Ez az alprogram - amint a kezdő megjegyzés is mutatja - az új osztálynál szükséges teendőket végzi el. Ezek közül a legelső a jegyek számára egy j nevű kétdimenziós tömb lefoglalása. Erről a tömbről azt tudjuk, hogy sorainak száma megegyezik az l osztálylétszámmal, oszlopainak száma pedig a tantárgyak számával (t). Mivel minden osztályban eltérhet a létszám és a tantárgyszám is, így az volt a legegyszerűbb, hogy a tömb határait az / és t változókkal határozzuk meg. Választhattuk volna azt a megoldást is, hogy az 1010-es sorban a tömbök határainak az előforduló legnagyobb értékeket vesszük fel. Ez azonban a rugalmasságot csökkentené. Egyes BASICváltozatokban nem lehet így - változóként - megadni a tömb határait, ott csak előre rögzített méretű tömbökkel lehet dolgozni.
Az n$ tömböt a tanulók neveinek, a t$ tömböt pedig a tantárgyak neveinek foglaltuk le. Az 1040-1070-es sorokban olvassuk be az adott osztályban tanított tantárgyak nevét. Ezt azért nem lehetett állandóként felvenni, mert - ahogy ez közismert - a középiskolákban a párhuzamos osztályok általában eltérő tantárgyakat tanulnak. Lényeges az osztályátlag nevű változó nullázása is, mert ennek hiányában csak a legelső osztálynál kapnánk helyes eredményt, a többi osztály eredményét ehhez adná hozzá a program.
A 2000-es sorszámmal kezdődő alprogramban egy tanuló adatait olvassuk be és számoljuk ki. A tanuló neve után beolvastatjuk az egyes tantárgyakból kapott osztályzatait.
A 2060-as sorban ellenőrizzük az adatokat, hogy csak az érvényes jegyeket lehessen beolvastatni. Ez igen fontos, hiszen sok adat beolvasásánál könnyen eltéveszthetjük az adatbevitelt, melléüthetünk. A program írásakor amennyire lehet mindig fel kell készülnünk a hibalehetőségekre, hiszen tökéletes védelem rendszerint nincs. Ebben az alprogramban történik az i tömb elemeinek gyűjtése is.
Szólnunk kell még a látszólag felesleges 2130-2140 sorszámú utasításokról is. A program ezek nélkül is működne, de így kényelmesebb a használata. Így ugyanis egy tanuló adatai után a program nem azonnal kéri a következő tanuló adatait, hanem csak akkor, ha a program felhasználója felkészült rá (például ha a tanár az előző tanuló átlagát beírta a naplóba stb.).
A 3000-es sorszámú sorral kezdődő alprogram a tantárgyankénti átlagot számolja ki a j tömb megfelelő összegezésével. (A j tömb minden oszlopán belül minden sorát összegezni kell.)
Érdekesség még a belső alprogram a 3500-as sortól kezdve. Ide csak akkor kerül a vezérlés, ha a képernyőre kiírt sorok száma nagyobb 20-nál (az üres sorokat is beleértve).
Mi az előnye a programnak? Viszonylag rugalmas, kényelmesen használható. Felhívjuk a figyelmet az ún. emlékeztető változónevek használatára. Szándékosan két szélsőséges példát mutattunk be. Az egyik az / és a t változó a létszámhoz és a tantárgyszámhoz. Ezek az egybetűs nevek bizony csak kismértékben emlékeztetnek. A karakter- és tömbneveknél azonban a ZX Spectrum BASIC-ben mást nem használhatunk. Így lett a programban a jegyeket gyűjtő tömb neve j. Az osztályzat rövidítését az o betűt azért kerültük, mert könnyen összetéveszthetjük a nullával. A beszélő változónevek másik véglete az osztályátlag, a tantárgyátlag és a tanulók átlaga nevű változók. Ezek ugyan pontosan megmondják, mire szolgálnak, de túl hosszúak, könnyen el lehet hibázni az írásukat. A programban a helyes középutat a sorszám nevű változó képviseli.
Programunk természetesen nem tökéletes. Nem akartuk jobban bonyolítani, de utalunk rá, hogy ha például valaki testnevelésből fel van mentve, akkor a program rosszul működik. Javasoljuk, az olvasó gondolkodjon el a megoldáson. Mi még visszatérünk rá. További szépséghibája a programnak, hogy nagyon sok tizedest ír ki. Ennek rendbetételéről is lesz szó, Az adatvédelem sincs tökéletesen megoldva.
FELADATOK
20. | Írjuk át a másodfokú egyenletet megoldó programot alprogramok segítségével! |
21. | A faktoriálist előállító programot alprogramként használva írjunk programot az sor összegének kiszámítására! (A nevezőben a felkiáltójellel jelzett számok a, faktoriálist jelölik.) Számoljuk ki a sor értékét, ha x = 0,52358! |
3.12. A szélesebb körű képernyőhasználat
Megismerkedtünk már a PRINT utasítással, melynek segítségével információkat írhattunk ki a képernyőre. A ZX Spectrumot többek között az igen fejlett képernyőkezelés teszi kiváló munkaeszközzé.
A következő pontokban (3.12.1-3.12.6) leírt utasításokban az a közös, hogy valamennyien a képernyő használatával függnek össze. Az eddig tárgyalt utasítások valamilyen formában más BASIC-változatokban is megtalálhatók, míg itt a legtöbb utasítás - ilyen formábán legalábbis - csak a ZX Spectrumon használható. Azonban azoknak is javasoljuk e részek átolvasását, akiknek a könyv olvasásakor nincs szándékuk vagy - például színes tv híján lehetőségük - az összes leírt lehetőséget kihasználni, mert így megismerhetik, mire is képes a ZX Spectrum.
3.12.1. Az AT módosító használata
Helye: az I billentyű SYMBOL SHIFT-tel, a kurzor: L vagy C. Magyar jelentése kb.: -nál, -nél. Azért hívjuk módosítónak, mert nem igazi, önálló utasítás, de nem is igazi függvény. Önállóan nem állhat, csak a PRINT és az INPUT utasításban. Hatását, működését a PRINT utasítással együtt mutatjuk be, mert használata is leggyakrabban ehhez kapcsolódik. Általános formája:
sorszám PRINT AT sor, oszlop; kinyomtatandó elem
ahol az AT után álló sorszám azt jelenti, hogy a kinyomtatandó elem a képernyő hányadik sorába kerüljön, az oszlop pedig, hogy e soron belül hányadik oszlopba. Ha a sorszám 22, akkor az
5 Out of screen, ...
jelű hibaüzenetet kapjuk, jelentése: kimentünk a képernyőről. A képernyőn ugyanis csak 22 sorba tudunk írni, de ezeket nullától 21-ig sorszámozzuk. Ha a sorszám értéke 23 vagy ennél nagyobb, akkor a
B Integer out of range, ...
üzenetet kapjuk, melynek szó szerinti jelentése: a szám a megengedett értékhatáron kívül esik. Oka megegyezik az előbb leírt üzenettel. Az oszlopszámnál 32 és ennél nagyobb számoknál kapjuk az előbb tárgyalt B jelű hibaüzenetet, hiszen egy sorba csak 32 karaktert tudunk írni 0-31-ig számozva.
Érdekesség, hogy a gép az adott intervallumban negatív számokat is elfogad, és ezeket pozitívként értelmezi (azaz a PRINT AT 1,1 és a PRINT AT -1,-1 is ugyanoda fog nyomtatni, a képernyő második sorának második oszlopába). Ahogy ez várható, a sor és oszlop helyére nemcsak állandó értékeket írhatunk, hanem változókat, függvényeket, sőt kifejezéseket is.
Fontos még megjegyezni, hogy az oszlop és a kinyomtatandó érték közé pontosvesszőt illik írni. Azért csak illik, mert a ZX Spectrum megengedi a vesszőt is, de akkor számolni kell egyéb, nem kívánatos mellékhatásokkal. A mellékhatások lényege - amint a PRINT-nél már leírtuk -, hogy vessző esetén egy sorba csak 2 elemet lehet kiírni, egyet a legelső, egyet a 17. oszlopba.
A következő négy utasítás a legfelső és a legalsó sorba ír ki egy sornyi csillagot:
10 FOR i=0 TO 31
20 PRINT AT 0,i;"*"
30 PRINT AT 21,i;"*"
40 NEXT i
Ha most ehhez hozzáírjuk az
50 PRINT AT 0,0;"a"
utasítást, akkor azt látjuk, hogy a képernyő bal felső sarkában a csillagot az a betű, felülírta, minden üzenet, figyelmeztetés nélkül.
Egy PRINT utasításban természetesen több AT is lehet. Ezt szemlélteti az alábbi három utasítás, amelyekkel a képernyő két oldalára I betűket rajzoltatunk:
60 FOR j=0 TO 21
70 PRINT AT j,0;"I";AT j,31;"I"
80 NEXT j
Az alábbi két utasítással a képernyő közepére egy csillagot és egy !-et írunk.
90 PRINT AT 11,16;"*"
100 PRINT AT 11,17;"!"
Futtassuk a 90-100-as sort, majd írjuk hozzá, hogy:
110 PRINT AT 11,16;"UJ"
Ha most futtatjuk ezt a néhány soros programot, akkor a képernyő közepén csak az UJ felírat látszik majd, mert az utolsó sor felülírta az előzőeket. A
120 PRINT AT 12,5;-1.12345
130 PRINT AT 12,6;1.99
utasítások hatására a képernyőn a
-1.99345
szám látható majd, ami nem azonos a 130-as sorba írt számmal. Nagyon kell tehát vigyázni, mert a PRINT AT a képernyőnek csak azt a kis részét írja felül, ahová a kinyomtatandó információt elhelyezi.
Tizenhatodik mintapéldánk a PRINT AT használatát mutatja be egy egyenes megrajzolásával.
10 REM tizenhatodik mintaprogram
20 REM pelda a PRINT AT -re
30 REM egyenes rajzolasa
40 INPUT "y=m*x+b m=";m,"b=";b,"toltokarakter=";t$
50 FOR x=0 TO 21
60 IF m*x+b<0 OR m*x+b>31 THEN GO TO 80
70 PRINT AT x,m*x+b;t$
80 NEXT x
A PRINT utasításban az AT előtt és után természetesen állhatnak még egyéb dolgok is vesszővel vagy pontosvesszővel elválasztva, ahogy azt az eddigiekből megismertük.
Ha INPUT-nál használjuk az AT-t, akkor két lehetőségünk van. Ha egy INPUT utasításban csak egy AT van, akkor 0 sorszám esetén az alulról számított második sorba ír ki az INPUT, az összes többi esetben pedig a legalsó sorba:
1 INPUT AT 0,0;"23. (alulrol 2.)";a$
2 INPUT AT 1,0;"24. (legalso)";b$
3 INPUT AT 2,0;"ez is";c$
4 INPUT AT 3,0;"ez is";d$
Ha ezt a négy sort kipróbáljuk, akkor láthatjuk, hogy az 1-es sorszámú kiírás máshova kerül - egy sorral feljebb -, mint a 2-3-4-es sorszámú.
Amikor egy INPUT utasításon belül több AT van, akkor az AT jól működik. Ez annyit jelent, hogy INPUT esetén is a legnagyobb sorszámú sor a legalsó. Az INPUT AT ilyenkor úgy mozgatja a kiírt sorokat, hogy mindig a legalsó sor legyen a legnagyobb sorszámú.
20 INPUT AT 0,0;"0.sor 0.oszlop";a$;
AT 1,0;"1.sor 0.oszlop";b$;
AT 2,0;"2.sor 0.oszlop";c$;
AT 3,0;"3.sor 0.oszlop";d$;
AT 4,0;"4.sor 0.oszlop";e$
Ez az egy utasítás öt sorba fogja kiírni a megfelelő szövegeket, legalul lesz a "4. sor, 0. oszlop" kiírás.
A következő INPUT utasítás viszont csak a két legalsó sorba fog írni, mert a 3., 4., 5. AT felülírja az első kettőt, ahogy a PRINT AT-nél láttuk.
30 INPUT AT 0,0;"0.sor 0.oszlop";a$;
AT 1,0;"1.sor 0.oszlop";b$;
AT 0,0;"ez is 0.sor";c$;
AT 1,0;"ez is 1.sor";d$;
AT 0,0;"ez is 0.sor";e$
Ha az INPUT és a PRINT találkozik a képernyőn, és mindkettőben AT is szerepel, akkor mindig az utolsó hatása érvényesül. Azaz az utolsó utasítás felülírja az előzőeket, akár PRINT, akár INPUT volt.
Végül megjegyezzük, hogy ha az AT-nél az oszlopok vagy a sorok számánál törtértéket adunk meg, a ZX Spectrum kerekít.
Helye: a P billentyű, a kurzor: E. A táblázást jelentő angol tabulate rövidítése. A függvények közé szokták sorolni, de valójában nem igazi függvény. Hatása, hogy egy adott sorban beállítja a kiíratási pozíciót. Önmagában sosem fordul elő, mindig csak a PRINT, esetleg INPUT utasításban. Formális leírása:
sorszám PRINT TAB oszlopszám; nyomtatandó érték
Az első és egyben legjelentősebb eltérés az AT-hez képest, hogy a TAB-nál mindig csak az oszlopszámot kell megadni. Tudjuk, hogy a képernyő egy sorában 32 oszlop van. Mivel az oszlopokat 0-31-ig sorszámozzuk, a TAB után is csak ezeket az értékeket adhatjuk meg. Negatív oszlopszámnál a már jól ismert
B Integer out of range,...
hibaüzenetet kapjuk. Ha az oszlopszám meghaladja a 31-et, akkor a kiírás majd a kinyomtatott adat után álló vezérlőkaraktertől (vessző vagy pontosvessző) függ. Természetesen az oszlopszámot is leírhatja állandó, változó vagy összetett kifejezés. Egyetlen logikus szabályt kell megjegyeznünk. Ha egy sor egy bizonyos oszlopába kiírtunk már valamit, akkor a TAB-bal nem tudunk visszalépni. Ennek megfelelően például a
PRINT TAB 3;"3";TAB 10;"x";TAB 9;"9"
parancsot elküldve azt tapasztaljuk, hogy az első és második TAB-nak megfelelően a 3. oszlopba 3, a 10. oszlopba x kerül, de a 9 már a következő sor 9. oszlopába íródik. Ugyanezt az eredményt kapjuk a
PRINT TAB 3;"3";TAB 10;"x";TAB 41;"9"
parancs elküldésekor. Ugyanis az első sorban 0-31 oszlop van, a második sor legelső oszlopa a 32. és 32+9=41. Próbáljuk ki a következő kis programot!
10 INPUT a$
20 FOR i=1 TO 50
30 PRINT TAB i;a$;
40 NEXT i
Ha ezt a programot bármilyen egykarakteres bemenő adattal futtatjuk, mindig két sort fog kiírni a képernyőre, a második sorban csak 19 jel lesz. Ha viszont bemenő adatként két vagy több karaktert adunk, érdekes jelenséget tapasztalunk: átlósan írja ki a jelet, és ki sem fér majd egy képernyőre. Mi lehet az oka? Gondoljuk végig mi is történt! Az i=1 esetben a legelső sorba két vagy több karaktert ír ki. Ez elfoglalta az első és második oszlopot. Így ha i=2 volt, akkor a második PRINT utasításnak megfelelő karakter csak a második sorban lévő második oszlopba kerülhet. Hasonló lesz a helyzet az i=3 és a többi esetben is: a második sor második oszlopában elkezdett kiírás elfoglalja a harmadik oszlopot is, ezért az i=3 esetén a nyomtatás már a következő sorban történik stb.
Ha a fenti kis program 30-as sorában a legutolsó pontosvesszőt elhagyjuk vagy vesszőre cseréljük ki, akkor ugyanazt az eredményt kapjuk, mint pontosvessző esetén, de két- vagy több karakteres INPUT-nál. Oka a PRINT utasításnál leírtakkal magyarázható. Ha a 30-as sor végére nem írunk vesszőt, akkor az 50-szer végrehajtott PRINT mindig külön sorba fog kiírni. Ha a legutolsó karakter vessző, akkor viszont azért kapunk átlós kiírást, mert vesszős elválasztásnál - ahogy azt az egyszerű PRINT-nél láttuk - nem tudunk két egymás melletti oszlopba írni.
A következő program a TAB használatát mutatja be.
10 REM tizenhetedik mintaprogram
20 REM pelda a FRINT TAB-ra
30 PRINT TAB 3;"EZ A PROGRAM EGYENEST RAJZOL"
40 FOR I=3 TO 30
50 PRINT TAB I;"=";
60 NEXT I
70 PRINT
80 PRINT "FUGGETLEN VALTOZO:FUGGOLEGESEN"
90 PRINT TAB 18;"20 EGYSEG"
100 PRINT "FUGGO VALTOZO:";
110 PRINT TAB 18;"VIZSZINTESEN"
120 PRINT TAB 18;"30 EGYSEG"
130 PRINT TAB 18;"MINDKETTO CSAK",TAB 18;"POZITIV LEHET"
140 INPUT TAB 5;"Kerem az egyenes adatait:","m= ";m;" b=";b;" toltokarakter=";t$
150 CLS
160 FOR I=1 TO 29
170 PRINT TAB I;"-";
180 NEXT I
190 PRINT ">Y"
200 FOR X=1 TO 20
210 IF M*X+B>31 OR M*X+B<0 THEN GO TO 240
220 IF M*X+B=0 THEN PRINT T$: GO TO 240
230 PRINT "I";TAB M*X+B;T$
240 NEXT X
250 PRINT "X"
FELADATOK
22. | Írjunk programot az y=x^2 függvény néhány pontjának kirajzolására! Javasoljuk az eltérő léptékek használatát, de ezt a program jelezze. |
23. | Írjunk programot, amely grafikont rajzol! Mintaadatként felhasználható például az érdemjegyek megoszlása egy iskolai osztályban. |
3.12.3. A ZX Spectrum színkezelése
A ZX Spectrum egyik legfontosabb eltérése kisebb testvérétől - a ZX 81-től - a színes képernyőkezelés lehetősége. Itt hívjuk fel újra a figyelmet, hogy csak megfelelő - PAL rendszerű - színes tv használatával érjük el az itt leírt színhatásokat. Fekete-fehér tv-készülékeken a színek a fehér-fekete és a szürke különféle árnyalataiban látszanak.
A ZX Spectrumon 8-féle szín van, ezeket számokkal jelöljük, 0-tól 7-ig. Az egyes színeknek megfelelő színkódok a 3. táblázatban láthatók.
Szín | kódja - helye |
Fekete Kék Piros Bíborvörös Zöld Halványkék Sárga Fehér |
0 1 2 3 4 5 6 7 |
3. táblázat
A táblázatban csak két oszlop van, mert az egyszerűség kedvéért minden szám (0-7-ig) egyben a megfelelő színkódot is jelenti. Ha a színkód meghaladja a lehetséges értékeket, akkor a
K lnvalid colour,...
ha a színkód negatív, akkor pedig a
B Integer out of range,...
üzenetet kapjuk. Az első üzenet jelentése: hibás szín, a másodiké: az egész szám nincs a megengedett tartományban. Gondoljuk végig, mit is színezhetünk a képernyőn? Mindössze három dolgot: a keretet, az alapszínt és a kiírt betűket. Ezzel azonban nagyon sokféle színhatást lehet elérni, főleg a később megtárgyalandó módosító hatások segítségével. Nézzük végig először a 3 legfontosabb jellemzőt!
A keret színezése a BORDER utasítással lehetséges. Helye: a B billentyű, a kurzor: K. Magyar jelentése: határ, szegély. Hatását az alábbi néhány sor szemlélteti:
10 FOR i=0 TO 7
20 BORDER i
30 INPUT "tovabb?";m$
40 NEXT i
A 30-as sor csak a késleltetés miatt szerepel a programban. Hiányában ugyanis olyan gyorsan változnának a színek, hogy nem tudnánk követni őket. Megjegyezzük, hogy ha a 10-es sort kijavítjuk:
10 FOR i=7 TO 0 STEP -1
akkor a program befejeződése után is fekete keretes marad a képernyő.
A képernyő alapszínét a PAPER utasítással állíthatjuk be. Helye: a C billentyű SYMBOL SHIFT-tel, a kurzor: E. Magyar jelentése: papír. Hatását az alábbi néhány soros programmal próbálhatjuk ki:
10 INPUT i
20 PAPER i
30 PRINT "az alap szinkodja: ";i
A programot próbáljuk ki néhányszor, és utána megállapíthatjuk az alábbi szabályszerűségeket: Ha alaphelyzetből futtatjuk a programot - amikor az alap fehér színű - a megfelelő szám, például a 6 bebillentyűzése után a program kiírja:
szöveget úgy, hogy a kiírt szöveg sárga alapon látható, de a képernyő többi része fehér marad. Ha a programot kilistázzuk, akkor már az egész listázás sárga alapon történik. Ha listázáskor megtelik a képernyő vagy egy utasítást beírunk, vagy törlünk, vagy csak egyszerűen megnyomjuk az ENTER billentyűt, akkor az egész képernyő - a keretet kivéve - sárga lesz, és újabb PAPER utasítás vagy parancs kiadásáig úgy is marad.
Nézzük meg a következő néhány sor hatását!
10 INPUT i
20 PRINT PAPER i;"papir ";
30 PRINT "valtozatlan"
Az előző sorokhoz képest az a fő változás, hogy a PAPER utasítást a PRINT-be írtuk. A PRINT és a PAPER kulcsszavak közé nem kötelező valamit írnunk. A vessző vagy pontosvessző hatása pontosan ugyanaz, mintha a PRINT listában az első kinyomtatandó információ előtt vesszőt vagy pontosvesszőt írnánk. Mi a hatása a PRINT-tel egybeírt PAPER utasításnak? Ugyanaz, mint egyébként, de azzal a lényeges eltéréssel, hogy csak arra az egy adott PRINT utasításra vonatkozik a hatás. Amint látható - ha kipróbáljuk a programot - a 30-as sorban visszaáll az alapszín.. Ez az ideiglenes hatás még néhány további képernyőkezelő utasításra is jellemző lesz. A PAPER utasítást természetesen az INPUT-ban is használhatjuk.
10 INPUT PAPER 6;"kenem a szinkodot";i
20 IF i=6 THEN PRINT PAPER i;"Egyszinu"
30 IF i<>6 THEN PRINT PAPER i;"Mas szinu"
A program végrehajtásakor a "Kerem a szinkodot" kiírás mindig sárga alapon fog látszani, akárcsak az "Egyszinu" kiírás. A "Mas szinu" kiírás pedig a beolvasott színkódnak megfelelően látszik majd.
A kiírás színét az INK utasítással lehet változtatni. Az INK utasítás helye: az X billentyű SYMBOL SHIFT-tel, a kurzor: E. Az INK magyarul tintát jelent. A következő néhány sor az INK hatását mutatja be:
10 INPUT s
20 INK s
30 PRINT "a szin kodja: ";s
Itt is igaz, hogy ha külön utasításba írjuk az INK-et, akkor hatása a program befejeződése után is érvényes lesz (a következő NEW parancsig vagy az újabb INK utasításig). A PAPER-hez hasonlóan ezt is beírhatjuk a PRINT vagy az INPUT utasításba, így hatása csak ideiglenes lesz. Az INK utasítás hibaüzenetei megegyeznek a PAPER és a BORDER utasítás hibaüzeneteivel.
A következő képernyőkezelő utasítás a kiírás fényességét szabályozza. Hatására a kiírt szöveg, információ a szokottnál fényesebben világit. Az utasítás neve - a fényesség angol nevének megfelelően - BRIGHT. A B billentyűn érhető el SYMBOL SHIFT-tel, a kurzor: E. Ha a normálisnál fényesebb kiírást akarunk, akkor a BRIGHT után 1-et kell írnunk, ha az eredeti fényességre akarunk visszaállni, akkor 0-t. A BRIGHT állhat önállóan és PRINT vagy INPUT utasításban is, de ekkor csak ideiglenes a hatása. Működését a
10 PRINT "ez nem fenyes" 20 PRINT BRIGHT 1;"ez fenyes" |
programocskával próbálhatjuk ki.
A következő érdekes utasítás a FLASH. Jelentésének - villogás - megfelelően a kiírt információt lehet villogtatni vele. Helye: a V billentyű SYMBOL SHIFT-tel, a kurzor: E.
Ugyanúgy 1 hatására lép működésbe, és 0 kapcsolja ki, mint a BRIGHT utasítást. Önálló utasításként vagy parancsként használva az egész képernyő villogni kezd. A villogás lényege, hogy a PAPER és az INK színe változik. A villogás igen fárasztó a szemnek, ezért nem árt, ha tudjuk, hogy a FLASH 0 parancs hatására még nem szűnik meg azonnal a villogás. A FLASH 0 parancs után legegyszerűbb még egyszer megnyomni az ENTER billentyűt. Ekkor azonnal megszűnik a villogás.
10 INK 1 20 PRINT FLASH 1;"ez villog" |
A FLASH utasítás nagyon jói használható, ha a képernyőn valamilyen fontos információt ki akarunk emelni.
A PAPER, INK, BRIGHT és FLASH utasításokban kódként 8-ast is meg lehet adni, hatására az előző állapot marad érvényben. Az INK és PAPER utasításokban 9-et is meg lehet adni, hatására az új szín az előzőleg beállított szín kontrasztja lesz (ha az előző kód 0, 1, 2 vagy 3 volt, akkor fehér, a többi esetben fekete).
Helye: az N billentyű SYMBOL SHIFT-tel, a kurzor: E. Az OVER jelentése: át, keresztül. Önállóan nem használjuk, csak PRINT vagy INPUT utasításban. Ha az eddig megismert eszközökkel egy képernyőpozícióban kiírtunk már egy karaktert, nem tudtunk változtatni rajta. Esetleg az AT segítségével átírhattuk az egészet.
Az OVER utasítás módot ad rá, hogy egy már kiírt karakterbe beleírjunk vagy belejavítsunk. Az OVER működésére nézzük meg az alábbi két utasítást!
10 PRINT AT 1,1;"aaaaa"
20 PRINT AT 1,2; OVER 1;" ' "
A 10-es sor nem szorul magyarázatra. A 20-as sorban az idézőjelek között lévő jel egy ékezet (helye a 7-es billentyűn van SYMBOL SHIFT-tel). A két programsor végrehajtása után a második a betűből á lesz. Így is lehet tehát ékezetes betűket írni.
Javítsuk ki a 20-as sorban idézőjelek között lévő " ' "-t mínuszjelre! Érdekes dolgot tapasztalunk: az a betű közepén fehér csík keletkezett. Mi ennek a magyarázata? Amikor egy karaktert írunk ki a képernyőre, akkor ez mindig 8x8 pontból áll össze. A 64 pont mindegyike kétféle színű lehet: vagy papír színű, vagy tinta színű, azaz vagy a PAPER utasításban, vagy az INK utasításban megadott színnel egyezik meg. Az eredeti és az OVER utasításban szereplő karakterek 8 sorban 8 pontból állnak. Ha mindkét pontban - az eredetileg képernyőn lévőben és az OVER utasításban odaírandóban is - azonos szín van, mindkettőben PAPER vagy mindkettőben INK, akkor az eredmény PAPER színű lesz. Ha PAPER szín találkozik INK színnel, akkor az eredmény INK színű lesz. A
10 PRINT AT 1,1;"aaaaa"
20 PRINT AT 1,2; OVER 1;"a"
soroknak például az a hatásuk, hogy a második a betű nem látszik, mert két teljesen azonos karakter találkozott, s ekkor az eredmény színe megegyezik a PAPER színével.
Az OVER utasításnál nemcsak az AT segítségével lehet visszalépni, hanem a kinyomtatást vezérlő karakterek segítségével is. Ehhez a CHR$ függvényt lehet majd felhasználni (lásd 3.19.1).
Helye: az M billentyű SYMBOL SHIFT-tel, a kurzor: E. Az utasítás jelentésének megfelelően inverz, azaz fordított képet állít elő. Ez annyit jelent, hogy az INVERSE hatására az alapszín megegyezik az INK utasítás által meghatározott színnel, a kiírás színe pedig a PAPER utasításban megadott szín lesz. Az INVERSE utasítást a 0 és 1 számokkal lehet vezérelni. Az 1 a bekapcsolást, a 0 a kikapcsolást jelenti. Állhat önálló utasításként, PRINT vagy INPUT utasításban és természetesen parancsként is.
Az eddig megismert utasítások közül a PRINT AT és a PRINT TAB utasítással viszonylag jól tudunk rajzolni is. Kényelmetlen viszont, hogy ezekkel az utasításokkal összesen 32x22 = 704 karaktert tudunk kiírni a képernyőre.
Az OVER utasításnál láttuk, hogy egy karakter lényegében egy 8x8-as hálózat bizonyos pontjain helyezkedik el. A most tárgyalandó utasítások közös jellemzője, hogy nagy felbontású grafikai lehetőségeket nyújtanak. Ennek az lesz a lényege, hogy az egy karaktert alkotó egyes pontokba is írhatunk jeleket. Ezek a jelek végső soron csak pontok lehetnek ugyan - melyek színét az INK utasítás határozza meg -, de ez nem probléma, hiszen a pontokból minden megrajzolható. Az eddigiekből az is következik, hogy nem 22 sorban és 32 oszlopban dolgozhatunk, hanem 32x8 = 256 oszlopban és 22x8 = 176 sorban. Vigyázat, a számozásuk 0-tól 255-ig és 0-tól 175-ig terjed majd!
A legelső rajzolóutasítás a PLOT. A PLOT utasítás helye: a Q billentyű, a kurzor: K. A PLOT jelentése kb.: ábrázol. Formája:
sorszám PLOT vízszintes koordináta, függőleges koordináta
A vízszintes koordináta értéke a pont vízszintes, a függőleges pedig a függőleges helyzetét határozza meg. A vízszintes koordináta értéke 0-255, a függőlegesé 0-175 között lehet. Negatív és törtszámok is megengedettek az adott tartományban. A negatív szám hatása megegyezik a pozitív száméval. Törtszám esetén kerekítünk. Ha nem az adott tartományba eső számot adjuk meg, akkor
B Integer out of range,...
hibaüzenetet kapunk. A koordinátákat állandó, változó vagy kifejezés formájában adhatjuk meg. A
10 PLOT 128,88
utasítás a képernyő közepére ír egy pontot. Jobban látható a PLOT hatása az alábbi utasítások kipróbálásával:
10 FOR i=0 TO 175
20 PLOT i,i
30 NEXT i
Az utasítás hatására a képernyő bal alsó sarkából kiinduló 45 fokos dőlésszögű egyenest kapunk. A következő három utasítás egy parabolát rajzol:
10 FOR i=0 TO 255
20 PLOT i,i^0.5
30 NEXT i
Az így kapott parabola bizony elég csúnya, lépcsős. Szebbé tehetjük a rajzot, ha a függőleges koordináták tízszeresét vesszük:
10 FOR i=0 TO 255
20 PLOT i,10*i^0.5
30 NEXT i
A DRAW grafikus utasítással - amint a neve is mondja - rajzolni lehet majd. Helye: a W billentyű, a kurzor: K.
A DRAW utasítással két pont közé egyenest vagy körívet lehet rajzolni. A DRAW utasításban csak egy pont koordinátáit kell leírnunk, ugyanis a ZX Spectrum BASIC a másik pontnak az előző PLOT pozícióban lévő pontot tekinti. Az előző PLOT pozíció a legutolsó PLOT utasítás által meghatározott pozíció. A PLOT pozíciót valamennyi e pontban szereplő utasítás beállítja, így maga a DRAW is. A DRAW utasítás első formája:
sorszám DRAW vízszintes koordinátanövekmény, függőleges koordinátanövekmény
Látható, hogy nem magát a vízszintes és függőleges koordinátát kell megadni, hanem az előző PLOT pozícióhoz viszonyított helyzetet. Ezért a DRAW utasításban igen gyakori a negatív érték is.
Ha nem volt előző PLOT pozíció, akkor az előző koordináták értéke 0,0. Ilyenkor a DRAW-ban nem írhatunk negatív értékeket, mert akkor a már ismert B hibaüzenetet kapjuk. Akkor mondjuk, hogy nem volt előző PLOT pozíció, ha a programban a DRAW utasítás kiadásáig nincs egy sem e pont utasításaiból, illetve ha a DRAW előtt CLS vagy CLEAR utasítást hajtottunk végre. Ennek megfelelően az előbb ciklussal rajzolt egyenest egyetlen utasítással is előállíthatjuk:
1 DRAW 175,175
Ha ezt a sort kiegészítjük a
2 DRAW 0,-175
utasítással, akkor a 175,175 és a 175,0 pontok között függőleges egyenest kapunk. A
3 DRAW -175,0
utasítással egy egyenlő szárú derékszögű háromszög harmadik oldalát rajzoltuk meg.
A DRAW utasítás második formája:
sorszám DRAW vízszintes növekmény, függőleges növekmény, középponti szög
A középponti szög a rajzolandó körív középponti szöge radiánban. Ha ez az érték pozitív, akkor a körív a két pont közé képzelt egyenestől jobbra esik, ha negatív, akkor balra. Ha a teljes körnek megfelelő értéket írunk a DRAW után, akkor egyenest kapunk. A DRAW-val tehát nem tudunk teljes kört rajzolni, csak körívet. A kör rajzolásához külön utasítás kell a CIRCLE.
A CIRCLE utasítás helye: a H billentyű SYMBOL SHIFT-tel, a kurzor: E. A CIRCLE jelentése: kör. A CIRCLE utasítás formája:
sorszám CIRCLE középpont vízszintesen, középpont függőlegesen, sugár
Valamennyi most tárgyalt utasításban használhatjuk az eddig megismert színkezelő utasításokat is (PAPER, INK, FLASH, INVERSE, OVER, BRIGHT). A színkezelő utasításokat a kulcsszó és a koordináták közé kell írni, és vesszővel vagy pontosvesszővel kell elválasztani őket a koordinátáktól. Megjegyezzük még, hogy az egy karakternek megfelelő 8x8-as mezőben összesen kétféle szín lehet: egy a PAPER-rel és egy az INK-kel meghatározott szín. Ezért ha PLOT, DRAW vagy CIRCLE utasításban szint használunk, mindig a legutolsó szín lesz a maradandó. Futtassuk például a következő programot úgy, hogy a sárga színt jelentő 6-ot adjuk be színkódnak - ez fekete-fehér tv-n is jól látszik:
10 INPUT i
20 DRAW INK 1,100,100
30 DRAW 0,-100
A 0,0 - 100,100 pontok közötti egyenes sárga lesz, kivéve a legfelső 8 pontot. Ezek a 30-as sor hatására feketék lesznek, miután a program a 30-as sort is végrehajtotta. Meggyőződhetünk erről a
25 STOP
utasítás beiktatásával, ha a
9 STOP statement, 25:1
üzenet után a CONT paranccsal folytatjuk a programot.
Az egyes pontok színének lekérdezésére megfelelő függvények állnak rendelkezésre. A 18. programmal egy négyzetbe egy kört rajzoltunk mindhárom utasítás felhasználásával:
10 REM tizennyolcadik mintaprogram
20 REM PLOT, DRAW, CIRCLE
30 LET k1=0
40 LET k2=0
50 PLOT k1,k2
60 DRAW 0,k2+48
70 DRAW k1+48,0
80 DRAW 0,k2-48
90 DRAW -48,0
100 CIRCLE k1+24,k2+24,24
Helye: az M billentyű, a kurzor: K. Jelentése: szünet, és a hatása is ez. Eddigi utasításaink közös jellemzője az volt, hogy végrehajtásuk után a vezérlés azonnal egy másik utasításra adódott át. A PAUSE utasítás hatására a program végrehajtása bizonyos időre abbamarad, a ZX Spectrum bizonyos ideig nem foglalkozik a programunkkal. A PAUSE utasítás formája:
sorszám PAUSE idő
Az idő helyén a szünet idejét kell megadni 1/50-ed másodpercben. A megadott idő értéke 0 és 65535 között lehet. Ha 0-t adunk meg, akkor a gép végtelen hosszú ideig vár. A várakozást bármelyik billentyű lenyomásával befejezhetjük. Negatív szám esetén a B hibaüzenetet kapjuk. Mivel a PAUSE utasításban 1/50-ed másodperc egységben kell megadni az időt, a megadott számot 50-nel elosztva megkaphatjuk a várakozási időt.
Ha a következő programot kipróbáljuk és jól működő órával ellenőrizzük, akkor a hálózati frekvencia esetleges ingadozásai miatt eltérést is tapasztalhatunk.
10 INPUT i
20 PAUSE i
30 PRINT i/50;" masadperc volt"
A PAUSE utasítást nagyon gyakran használjuk, ha a programban valamilyen okból mérni kell az eltelt időt (játékprogramokban, rajzolóprogramokban, párbeszédes programokban).
A következő programmal az előző példa négyzetét és a benne lévő kört mozgatjuk. A program lényege: az ábrát leíró rajzolóutasítások egy ciklus belsejében vannak. A mozgás sebességét a 180-as sorban lévő PAUSE utasítással lehet szabályozni.
10 REM tizenkilencedik mintaprogram
20 REM kep mozgatasa
30 INPUT "Hogyan mozogjon?",TAB 1; FLASH 1;"L"; FLASH 0;"assan?",TAB 1 ; FLASH 1;"G"; FLASH 0;"yorsabban";TAB 1; FLASH 1;"N"; FLASH 0;"agyon gyorsan";s$
40 IF NOT (s$="L" OR s$="l" OR s$="G" OR s$="g" OR s$="N" OR s$="n") THEN GO TO 30
50 IF s$="L" OR s$="l" THEN LET s=50
60 IF s$="G" OR s$="g" THEN LET s=5
80 LET k2=0
90 FOR i=0 TO 200
100 LET k1=i
110 PLOT k1,k2
120 DRAW 0,k2+48
130 DRAW 48,0
140 DRAW 0,k2-48
150 DRAW -48,0
160 CIRCLE k1+24,k2+24,24
170 IF s$="N" OR s$="n" THEN GO TO 190
180 PAUSE s
190 IF i<200 THEN CLS
200 NEXT i
3.14. Hanghatások, a BEEP utasítás
A BEEP utasítás helye: a Z billentyű SYMBOL SHIFT-tel, a kurzor: E. Hatására a ZX Spectrum beépített hangszórójával hangok állíthatók elő. Formája:
sorszám BEEP időtartam, hangmagasság
Az időtartam és a hangmagasság helyére tetszőleges számkifejezés írható. Az időtartam azt mondja meg, hogy milyen hosszan szóljon a megszólaló hang. Az idő hosszúságát másodpercben kell megadni. Ha negatív vagy 10,4999-nél hosszabb időtartamot adunk meg, akkor a B hibaüzenetet kapjuk. A hangmagasság helyén értelemszerűen a kívánt zenei hang magasságát kell megadni félhangonként. A 0 felel meg a normál C, a 2 a normál B, a 4 a normál E hangnak, és így tovább. Ha egy oktávval magasabb vagy alacsonyabb hangot akarunk előállítani, akkor 12-t kell adni az értékhez, vagy ugyanennyit le kell vonni belőle. Ennek megfelelően a felső C értéke 12, az alsó C értéke -12.
10 REM huszadik mintaprogram
20 REM pelda a BEEP utasitasra
30 REM J. S. Bach Parasztkantata /reszlet/
40 LET a=.2
50 GO SUB 100
60 PAUSE 10
70 GO SUB 100
80 STOP
100 BEEP a,0: BEEP a,2: BEEP 2*a,4: BEEP 2*a,4: BEEP 2*a,4: BEEP a,5: BEEP a,4: BEEP 2*a,2: BEEP 2*a,2: BEEP 2*a,2: BEEP 2*a,4: BEEP 2*a,5: BEEP a,4: BEEP a,2: BEEP 2*a,4: BEEP a,2: BEEP a,0: BEEP 3*a,0
110 RETURN
Az. IN helye az I billentyű, az OUT helye az O billentyű, mindkettő SYMBOL SHIFT-tel, a kurzor mindkét esetben: E. Valójában csak az OUT utasítás, az IN függvény, de mivel működésüket tekintve hasonlóak, egyszerre foglalkozunk velük.
A számítógép felépítésének tárgyalásánál láttuk, hogy a számítási és vezérlési feladatot ellátó mikroprocesszorhoz mindenféle adatbeviteli és adatkiviteli - angol nevén input és output - perifériák járulnak. Az OUT utasítással bármelyik kimeneti perifériára egyetlen bájtnyi információt tudunk kivinni, amelynek értelmezése a perifériától függ. Az IN függvénnyel a megfelelő bemeneti perifériáról egyetlen bájtnyi információt tudunk beolvasni.
Az OUT utasítás formája:
sorszám OUT cím, érték
ahol a cím helyére a periféria címét, az érték helyére az egy bájtnyi információt kell írni. Az egy bájtnyi információ 0 és 255 közötti érték lehet. Az IN függvény formája:
sorszám változó = IN cím
ahol a cím annak a perifériának a címe, ahonnan valamit be akarunk olvasni.
A cím értéke mindkét esetben 0 és 65535 között lehet. Ha az érték nem az adott tartományba esik, vagy az OUT utasítással 255-nél nagyobb értéket akarunk kiküldeni, akkor a B hibaüzenetet kapjuk.
Az OUT utasítás hatását megfigyelhetjük például a következő két utasítás kipróbálásával:
10 INPUT a
20 OUT 0,a
Ezt futtatva és a beolvasott értéket 0-7 között változtatva azt tapasztalhatjuk, hogy a képernyő keretének színe megváltozik (a BORDER utasításhoz hasonlóan). Az IN használatára az alábbi rövid példát mutatjuk be:
10 LET a=IN 65022
20 IF a=255 THEN GO TO 10
30 PRINT a
A 65022 az A-S-D-F-G billentyűk fizikai címe. Ha az A-S-D-F-G billentyűk bármelyikét megnyomjuk, akkor a 255-2^n képletnek megfelelő számot kapjuk, ahol n értéke a fenti sorrendnek megfelelően 0,1,2,3,4 lehet.
A PEEK és a POKE helye is az O billentyű, a kurzor a POKE-nál: K, a PEEK-nél: E. A PEEK jelentése kb.: kukucskálni, a POKE jelentése kb.: döfni, lökdösni. Itt is el kell mondanunk, hogy a PEEK függvény, de mivel hatása összefügg a POKE-kal, vele együtt tárgyaljuk. A POKE utasítás segítségével a RAM memória tetszőleges létező helyére 1 bájtnyi információt írhatunk, a PEEK függvénnyel pedig kiolvashatjuk ezt az informálót.
A POKE utasítás formája:
sorszám POKE cím, tartalom
A PEEK függvény formája:
sorszám változó = PEEK cím
A POKE utasításnak a gépi kódú programozásban lesz majd szerepe. A PEEK függvény segítségével megismerkedhetünk például a számítógép memóriájának felépítésével. A POKE utasítással kapcsolatosan emlékeztetnünk kell arra, hogy számítógépünknek kétféle memóriája van: ROM és RAM. Azt is tudjuk már, hogy a ROM memória tartalmát nem tudjuk megváltoztatni. Ezért, ha a POKE utasításban olyan memóriacím szerepel, amely még a ROM-hoz tartozik, a POKE hatástalan. (A ROM mérete 16k.) Próbáljuk ki az alábbi utasításokat:
10 INPUT "kerem a címet ";i
20 PRINT PEEK i
30 POKE i ,13
40 PRINT PEEK i
Ha címként 0 és 16383 közötti értékeket adunk meg, akkor a program mindkét esetben ugyanazt az értéket fogja kiírni. Ez az adott címen lévő bájt tartalma lesz. 16384 ás 32767, illetve 48k-s Spectrum esetén 16384 és 65535 közötti címet megadva a fenti kis programnál azt tapasztaljuk, hogy a program először kiírja az adott cím eredeti tartalmát, majd a 13-at, amit a POKE utasítással írtunk oda.
A teljesség kedvéért még hozzá kell tennünk, hogy a ZX Spectrum a RAM egy bizonyos részét is felhasználja saját, belső adminisztrációjához. Ezen a memóriaterületen bizonyos bájtokat megváltoztathatunk anélkül, hogy abból baj származna, viszont bizonyos bájtok megváltoztatásakor érdekes, gyakran nem várt következményeket tapasztalhatunk. Például az
1 POKE 23609,255
utasítást írva bármely program elejére, minden egyes billentyű lenyomásakor sípoló hangot hallunk.
FELADAT
24. | Írjon programot, amely kirajzolja a képernyőre a magyar zászlót! |
A BASIC programnyelvben a parancsok és az utasítások mellett a függvények teszik lehetővé a kényelmes programozást. A függvényeket felhasználni - szakszóval aktivizálni - a függvénynévnek megfelelő billentyű vagy billentyűk lenyomásával tudjuk. A függvényekkel kapcsolatosan három fogalmat kell megkülönböztetnünk:
A ZX Spectrum BASIC-ben a függvénynév után a független változót nem kötelező zárójelek közé tenni, ez alól csak néhány függvény lesz kivétel. Igen fontos és logikus formai szabály, hogy függvénynév önmagában nem állhat.
A függvények csoportosítása:
A beépített függvények a működésükre vonatkozó szabályok betartásával bármikor használhatók, hiszen a ROM-ban vannak. A felhasználói függvényeket használat előtt a felhasználónak le kell írnia (szakszóval meg kell határoznia a függvényt). Ennek pontos módját a beépített függvények tárgyalása után részletesen is ismertetjük. A beépített és a felhasználói függvények is lehetnek numerikusak vagy karakteresek. A numerikus függvénynek a független változója és a függvényértéke is numerikus. A karakteres típusú függvényeknél vagy a független változó, vagy a függvény visszaadott értéke, vagy mindkettő karakteres típusú. A logikai függvények közé az IF utasításnál tárgyalt logikai műveleteket megvalósító utasításokat soroljuk, mivel ezeket függvényként is lehet használni. Egyéb csoportba kerültek az egyéb, speciális függvények, melyek egyik fenti csoportba sem tartoznak.
A numerikus függvényekről annyit már tudunk, hogy mind a független, mind a visszaadott érték csak numerikus lehet. További közös tulajdonságuk, hogy használatuknál a matematika szabályait kell betartanunk. Nézzük meg őket részletesen!
Az ABS függvény helye a G billentyű, a kurzor: E. Hatására a független változó abszolút értékét kapjuk vissza.
10 INPUT i
20 PRINT ABS i
A BIN függvény helye: a B billentyű, a kurzor: E. Nem igazi függvény, mert a független változót csak állandóként lehet megadni. Hatása: a független változóként megadott nullákat és egyeseket kettes számrendszerbeli számokként értelmezi és átalakítja 10-es számrendszerbe.
A következő néhány sor futtatása után az 1, a 3 és a 7 jelenik meg a képernyőn.
10 PRINT BIN 1
20 PRINT BIN 11
30 PRINT BIN 111
3.18.3. Az EXP és az LN függvény
Az EXP függvény helye: az X, az LN függvény helye: a Z billentyű, a kurzor mindkét esetben: E. A két függvény egymás inverze.
Az EXP függvény az e természetes szám hatványát számítja ki, az LN pedig az e alapú logaritmust, ahol e = 2,7182818. Az LN függvény független változójaként természetesen nem adhatunk meg negatív számot és 0-t sem. Az ismert képlet alapján könnyen számolhatunk a 10-es alapú logaritmus szerint is. Például a
PRINT LN 100/LN 10
parancs eredménye: 2.
A SIN függvény helye: a Q, a COS függvény helye: a W, a TAN függvény helye: az E billentyű, a kurzor mindhárom esetben: E. A szögfüggvényekről annyit kell tudni, hogy a szöget radiánban kell megadni. A radiánba való átszámításhoz a PI függvény használható, helye: az M billentyű, a kurzor: E. A PI függvény értéke: 3,1415927. A szögfüggvények gyakorlati hasznát a következő példán láthatjuk:
10 REM huszonegyedik mintaprogram
20 REM pelda a szogfuggvenyekre
30 INPUT "Kerem a szoget (fok) ";f;" (perc) ";p
40 LET r=(f+p/60)*PI/180
50 CLS
60 PRINT "A szog: ";f;" fok ";p;" perc."
70 PRINT "Ez ";r;" radian."
80 PRINT "A szog sinusa=";SIN r;",","a szog cosinusa=";COS r;","
90 IF SIN r=1 THEN PRINT "a szog tangense=vegtelen,","a szog cotangense=0": GO TO 120
100 IF SIN r=0 THEN PRINT "a szog tangense=0,","a szog cotangense=vegtelen": GO TO 120
110 PRINT "a szag tangense=";TAN r;",","a szog cotangense=";1/TAN r;"."
120 INPUT "Kell meg szamolni? (i/n)";v;
130 IF v$="i" THEN GO TO 30
3.18.5. Az inverz szögfüggvények
Az ASN függvény helye: a Q, az ACS függvény helye: a W, az ATN függvény helye: az E billentyű SYMBOL SHIFT-tel, a kurzor: E. Ezeknek a függvényeknek a felhasználásával megtudhatjuk, hogy adott szinusz, koszinusz, tangens értékek milyen szögekhez tartoznak.
10 REM huszonkettedik mintaprogram
20 REM pelda a szogfuggvenyek visszakeresesere
30 INPUT "Kerem a visszakeresendo erteket ",v,,"es a jelet (SN CS TN CT) ";j$
40 CLS
50 IF NOT (j$="SN" OR j$="sn" OR j$="CS" OR j$="cs" OR j$="TN" OR j$="tn" OR j$="CT" OR j$="ct") THEN PRINT FLASH 1;"ROSSZ JEL": GO TO 30
60 IF j$="SN" OR j$="sn" THEN LET s=ASN v
70 IF j$="CS" OR j$="cs" THEN LET s=ACS v
80 IF j$="TN" OR j$="tn" THEN LET s=ATN v
90 IF (j$="CT" OR j$="ct") AND v<>0 THEN LET s=ATN (1/v)
100 IF (j$="CT" OR j$="ct") AND v=0 THEN LET s=PI/2
110 PRINT "A szog= ";s;" radian,",s*180/PI;" fok"
120 INPUT "Kell meg szamolni? (i/n)";v$
130 IF v$="i" THEN GO TO 30
Helye: az F billentyű, a kurzor: E. Az SGN függvény a matematikából ismert előjelfüggvényt valósítja meg. Ha a független változó pozitív, akkor a függvény értéke +1, ha a független változó negatív, akkor a függvény értéke -1. Ha a független változó 0, akkor a függvény értéke is 0.
Az SGN függvényt próbáljuk ki a következő két sorral:
10 INPUT i
20 PRINT i,SGN i
Helye: a H billentyű" a kurzor: E. A független változó négyzetgyökét számolja ki, tehát a független változó nem lehet negatív.
Helye: az R billentyű, a kurzor: E. Az INT függvény a független változó egész értékét állítja elő. Az egész érték nem kerekítést jelent, hanem azt a legnagyobb egész számot, amily még kisebb a független változónál. A függvény hatását az alábbi kis program szemlélteti:
10 FOR i=1.9 TO -1.9 STEP -0.4
20 PRINT i,INT i
30 NEXT i
A program futása után az alábbi két oszlopot kapjuk:
1.9 1.5 1.1 0.7 0.3 -0.1 -0.5 -0.9 -1.3 -1.7 |
1 1 1 0 0 -1 -1 -1 -2 -2 |
Az első oszlopban az i változó értékei láthatók, a második oszlopban az ezekből képzett egész értékek.
3.18.9. Az RND függvény és a RANDOMIZE utasítás
Az RND függvény helye: a T billentyű, a kurzor: E; a RANDOMIZE-utasítás helye: a T billentyű, a kurzor: K. Az RND függvény segítségével véletlenszámokat állíthatunk elő a 0 és 1 közötti tartományban. A véletlenszám 1 értéket sohasem vehet fel, 0-t viszont igen. Az így előállított véletlenszámokat ún. álvéletlenszámoknak hívjuk. Ez annyit jelent, hogy a számok csak látszólag véletlenszámok, a számítógép meghatározott eljárás - algoritmus - alapján állítja elő őket. (A valóságban a gép 65536-féle különböző 0 és 1 közötti számot állit elő adott sorrendben, a véletlenszámok ebben a sorozatban egymás után álló számok.)
Futtassuk néhányszor a
10 FOR i=1 TO 5
20 PRINT RND
30 NEXT i
programot. Azt látjuk, hogy minden alkalommal más-más 5 számot kapunk.
A véletlenszámokat tartalmazó programok "belövését", azaz jól működő állapotba hozását gátolhatják maguk a véletlenszámok is. Hasznos lehet, ha ilyenkor a véletlenszámok minden futásnál ugyanazok, azaz csak egy futáson belül véletlenek. Erre való a RANDOMIZE utasítás. (A billentyűn RAND-nak van rövidítve.) A RANDOMIZE utasítás után megadható egy pozitív 1 és 65535 közé eső szám. A gép ezt a számot a véletlenszámot előállító eljárás kezdőértéknek tekinti, és az előbb említett sorozat adott elemétől kezdi előállítani a számokat. Ha az előbbi 3 sor elé beírjuk az
5 RANDOMIZE 30
utasítást, akkor akárhányszor is futtatjuk a programot, mindig az alábbi 5 számot kapjuk:
.035461426
0.66070557
0.55329895
0.4979248
0.34492493
Ha a RANDOMIZE után 0-t írnánk vagy nem írnánk semmit, akkor a ZX Spectrum a bekapcsolás óta, illetve a PAUSE utasítás használata óta eltelt idő szerint állítaná be a kezdőértéket.
A véletlenszámokat a statisztikában, a szimulációban és a játékprogramokban használják igen gyakran. A gyakorlati felhasználásban rendszerint nem 0 és 1 közötti véletlenszámokra van szükség, hanem más határok közé esőkre. Ilyenkor egyszerűbb matematikai átalakításokat végezni. A huszonharmadik programban a véletlenszámok segítségével lottószámokat állítunk elő. Ezeknek a számoknak 1 és 90 közötti egész számoknak kell lenniük, és az 5 szám között nem lehetnek egyformák.
A véletlenszámok előállítását a 70-es sorszámú utasítás végzi. A program többi része növekvő sorrendbe rendezi, majd kiírja a számokat.
10 REM huszonharmadik mintaprogram
20 REM pelda a veletlenszamokra
30 REM LOTTO szamok eloallitasa
40 RANDOMIZE
50 DIM l(5)
60 FOR i=1 TO 5
70 LET l(i)=1+INT (90*RND)
80 IF i=1 THEN GO TO 120
90 FOR j=1 TO i-1
100 IF l(j)=l(i) THEN GO TO 70
110 NEXT j
120 NEXT i
130 PRINT "A LOTTO-SZAMOK"
140 FOR i=1 TO 4
150 FOR j=i+1 TO 5
160 IF l(i)<l(j) THEN GO TO 200
170 LET w=l(i)
180 LET l(i)=l(j)
190 LET l(j)=w
200 NEXT j
210 PRINT l(i)
220 NEXT i
230 PRINT l(5)
Helye: a 8-as billentyű SYMBOL SHIFT-tel, a kurzor: E. Használatához fel kell idéznünk a PLOT, a DRAW és a CIRCLE utasítások közös lényegét: a képernyő egy elemi pontját színezik be. Más szóval kifejezve, az említett utasítások hatására a képernyő bizonyos elemi pontjainak színe beáll a tinta színével megegyező, azaz az INK utasításban megadott színűre.
A POINT függvénnyel azt lehet megtudni, hogy egy adott elemi pont papír színű-e vagy tinta színű-e. Ha a POINT függvényben megadott elemi pont színe megegyezik az INK utasításban adottal, akkor a függvény értéke 1, különben 0. Az elemi pontok számának megfelelően a POINT függvényben egy vízszintes és egy függőleges koordinátát kell megadni. A függőleges koordinátának 0-175, a vízszintesnek 0-255 közé kell esnie. A POINT függvénynél a független változókat zárójel közé kell tenni.
A POINT függvény használatát a következő programmal mutatjuk be. A program első része - a 90-es sorszámú utasításig - a képernyő alját színezi be, a 120-as sorszámú utasítás az egyes elemi pontok színét kérdezi le és írja ki.
10 REM huszonnegyedik mintaprogram
20 REM pelda a POINT fuggvenyre
30 FOR i=0 TO 255
40 LET szin=INT (i/7)
50 IF szin>7 THEN LET szin=INT (szin/7): GO TO 50
60 FOR j=0 TO 8
70 INK szin: PLOT i,j
80 NEXT j
90 NEXT i
100 FOR j=0 TO 16
110 FOR i=0 TO 255
120 PRINT AT 0,1; INK 0;"Koordinatak: x=";i;" y=";j;" POINT=";POINT (i,j);" "
130 NEXT i
140 NEXT j
150 INK 0
Helye: az L billentyű SYMBOL SHIFT-tel, a kurzor: E. A POINT függvény segítségével megtudtuk egy elemi pontról, hogy tinta vagy papír színű-e. Az ATTR függvény felhasználásával azt is meg tudjuk mondani, hogy a 32 oszlopból és 24 sorból álló képernyő egy adott pontján milyen az alapszín és a tinta színe, villog-e az adott pont és fényes-e. Ezeket a jellemzőket a PAPER, az INK, a FLASH és a BRIGHT utasításokkal lehet beállítani.
A képernyő egy pontjára vonatkozó fenti jellemzőket a ZX Spectrum az ún. attributum-bájtban tárolja. Az ATTR függvény ennek a bájtnak a decimális értékét adja vissza. Az ATTR függvényben az első helyen álló független változónak 0 és 23 közé, a második helyen állónak pedig 0 és 31 közé kell esnie. A független változókat zárójelek közé kell tenni. Az attributum-bájt felépítése a harmadik ábrán látható.
Bit | Mit jelez |
0,1,2 3,4,5 6 7 |
A tinta színe A papír színe A fényesség jele A villogás jele |
3. ábra
A 8 bit mindegyike vagy 0-t, vagy 1-et tartalmazhat. A 3 legkisebb helyértékű bit a tintának az INK utasításban meghatározott színét mondja meg. A 3 biten 0-7-ig ábrázolhatjuk a számokat, s ez pont megfelel a színkódoknak. Elsőként nézzük meg a következő rövid kis programot!
10 FOR i=0 TO 7
20 PRINT AT i,i; PAPER 0; INK i;"ez szines";
30 PRINT " a szinkod=";ATTR (i,i)
40 NEXT i
A program végrehajtásakor azt tapasztaljuk, hogy a program - a 20-as sorszámú utasítás hatására - a képernyő felső 8 sorában fekete alapon kiírja az "ez szines" szöveget különféle színekkel. A 30-as sorban lévő ATTR a színkódot írja ki. A 20-as sorszámú PRINT utasításban a papír színét azért kellett feketére állítani, mert így a nagyobb helyértékű bitek 0 értékűek lesznek és nem zavarják a számítást.
Ha csak a papír színezésének módját akarjuk tanulmányozni, akkor az előbbi rövid kis program 20-as sorszámú sorában cseréljük fel a PAPER és az INK utasításokat!
20 PRINT AT i,i; INK 0; PAPER i;"ez szines";
Ha most futtatjuk a programot, azt látjuk, hogy a változó alapszínű képernyőn mindig fekete színnel jelenik meg az "ez szines" felirat. A színkód meglepő módon nem a várt 0-7 közé, hanem 0-56 közé esik. Semmi más nem történt, csak az, hogy a 0-7-nek megfelelő bitkombinációk a magasabb helyértéket jelentó 4.-5.-6. biten jelentek meg. Ez pedig 2^3 = 8 értékű eltolást jelent. A színkód a megszokott formájában jelenik meg, ha a programba beírjuk a következő utasítást:
35 PRINT AT i,30;ATTR (i,i)/8
A színkód eltolásához hasonlóan a villogást jelző bit 128-cal, a fényességet jelző bit pedig 64-gye1 növeli meg az eredményt.
A következő program első részében a képernyő első 10 sorában véletlenszerűen beállítjuk a jellemzőket, és ezeket a program második részében kiíratjuk.
10 REM huszonotodik mintaprogram
20 REM pelda az ATTR fuggvenyre
30 DIM s$(8,6)
40 DATA "fekete","kek","piros","bibor","zold","cian","sarga","feher"
50 FOR i=1 TO 8
60 READ s$(i)
70 NEXT i
80 FOR r=0 TO 9
90 FOR c=0 TO 31
100 LET papir=INT (8*RND)
110 LET tinta=INT (8*RND)
120 LET feny=INT (2*RND)
130 LET villog=INT (2*RND)
140 PRINT AT r,c; PAPER papir; INK tinta; BRIGHT feny; FLASH villog;"+"
150 NEXT c
160 NEXT r
170 FOR r=0 TO 9
180 FOR C=0 TO 31
190 LET kod=ATTR (r,c)
200 PRINT AT 11,2;"sor=";r;" oszlop=";c;" "
210 PRINT "A pont jellemzoi"
220 IF kod<128 THEN PRINT " ","nem villog": GO TO 250
230 PRINT " ","villog "
240 LET kod=kod-128
250 IF kod<64 THEN PRINT " ","nem fenyes": GO TO 280
260 PRINT " ","fenyes "
270 LET kod=kod-64
280 PRINT " ","a papir szine: ";
290 LET szin=0
300 FOR i=2 TO 0 STEP -1
310 LET szin=szin+(INT (kod/2^(i+3))*2^i)
320 IF kod>=2^(i+3) THEN LET kod=kod-2^(i+3)
330 NEXT i
340 PRINT ,s$(szin+1)
350 PRINT " ","a tinta szine:",,s$(kod+1)
360 NEXT c
370 NEXT r
FELADATOK
25. | Írjon programot, mely adott számról megállapítja, páros-e vagy páratlan! |
26. | Írjon programot, mely adott forintösszeget felvált a lehető legkevesebb számú bankjegyre és pénzérmére! |
27. | Írjon programot a fej vagy írás játék szimulálására! Próbálja ki, hogy 10, 100, 1000, 10000 dobásnál hány fejet és hány írást kapunk! Írassa ki az eredményt százalékosan is! |
A beépített karakteres függvények általános jellemzője, hogy vagy a független változó, vagy a függvény értéke, vagy mindkettő karakteres típusú. Formai szabályként megjegyezhetjük, hogy azoknál a karakteres függvényeknél, ahol a függvény értéke karakteres típusú, a függvénynév utolsó betűje $ (dollár) jel.
3.19.1. A CODE és a CHR$ függvény
A CHR$ helye: az U, a CODE helye: az I billentyű, a kurzor mindkét függvénynél: E.
A ZX Spectrum alapvetően ASCII kódban dolgozik. Ez azt jelenti, hogy a karakterek, jelek belső ábrázolása az ún. ASCII kódrendszer szerint történik. A ZX Spectrum azonban némi bővítést is tartalmaz az eredeti ASCII kódhoz képest.
A CHR$ függvény megmondja, hogy bármely 0 és 255 közé eső számnak milyen karakter felel meg a ZX Spectrumon. A CODE függvény független változója egy karakter, és a függvény az adott karakter ASCII kódját adja vissza. Egy karakternél hosszabb független változó esetén a CODE függvény csak a legelső karaktert vizsgálja meg. Megjegyezzük, hogy a CHR$ függvénynek 32-nél kisebb értékeket adva a függvény egy kérdőjelet adhat vissza eredményként. Ennek az az oka, hogy a 32-nél kisebb kódhoz tartozó jelek az ún. vezérlőjelek, amelyek közül nem mindegyik nyomtatható ki.
A CODE függvényt például az alábbi néhány utasítással próbálhatjuk ki:
10 INPUT a$
20 PRINT a$;" kodja=";CODE a$
Kis a betű esetén 97, A esetén 65 lesz az eredmény. Ehhez hasonlóan a CHR$-t is kipróbálhatjuk:
10 INPUT a
20 PRINT a," karakter=";CHR$ a
Ha most 98-at adunk be, akkor b-t, 66 esetén pedig B-t kapunk eredményként.
Helye: az N billentyű, a kurzor: E. Nagyon fontos és hasznos függvény. Nincs független változója. Hatására a ZX Spectrum egyetlen karaktert olvas be a billentyűzetről.
Mi az eltérés az INPUT és az INKEY$ függvény között? Az INKEY$ mindig csak egyetlen karaktert olvas be, azt viszont azonnal, nem kell megnyomni az ENTER billentyűt sem. Ha nem nyomunk meg egy billentyűt sem, akkor a függvény értéke üres karakter lesz.
10 REM huszonhatodik mintaprogram
20 REM pelda az INKEY$ fuggvenyre
30 PRINT "Igy kell hasznalni az INKEY$-t"
40 PRINT "Ertheto? (i/n)"
50 IF NOT (INKEY$="i" OR INKEY$="n" OR INKEY$="I" OR INKEY$= "N") THEN GO TO 50
60 IF INKEY$="i" OR INKEY$="I" THEN PRINT "akkor jo"
70 IF INKEY$="n" OR INKEY$="N" THEN PRINT "pedig egyszeru"
Helye: a K billentyű, a kurzor: E. A LEN az angol length - hosszúság - szónak a rövidítése. Jelentésének megfelelően hatása a következő: a független változóként megadott karaktersorozat hosszát adja vissza.
10 INPUT "Kerek egy nevet ";n$
20 PRINT n$,"hossza=";LEN n$
Helye: a K billentyű SYMBOL SHIFT-tel, a kurzor: E. A screen jelentése: képernyő. A SCREEN$ függvény a megadott képernyőpozíción lévő karaktert adja vissza. A független változókat zárójelbe kell tenni, és a szokásos módon az első független változónak 0-23, a másodiknak pedig 0-31 közé kell esnie.
10 INPUT "Hova x=";x;" y=':;y;" jel=";m$
20 IF x>31 OR y>23 TNEN GO TO 10
30 PRINT AT x,y;m$
40 PRINT AT 0,0;SCREEN$ (x,y)
Helye: az Y billentyű, a kurzor: E. Az STR a karakterláncot jelentő angol string szó rövidítése. Az STR$ függvény a független változóként megadott numerikus értéket karakterré alakítja. Jelentősége, hogy segítségével eltérő - karakteres és numerikus - típusok között tudunk műveleteket végezni.
10 LET a=5
20 LET b=4
30 PRINT a+b
40 PRINT STR$ (a+b)
50 PRINT STR$ a+STR$ b
A program eredménye:
9
9
54
Az első és a második 9-es csak formailag azonos, az első numerikus, a második karakteres típusú.
3.19.6. A VAL és a VAL$ függvény
A VAL függvény helye: a J billentyű, a VAL$ függvény helye: a J billentyű SYMBOL SHIFT-tel, a kurzor: mindkét esetben E.
A VAL az értéket jelentő angol value szó rövidítése. A VAL függvény a független változójaként megadott karakterláncot (stringet), számmá alakítja. A karakterláncnak karakter formájú számot vagy numerikusan helyes kifejezést kell tartalmaznia. A VAL függvény lehetővé teszi, hogy karaktereket numerikus értékké alakítsunk.
Ha a karakterlánc numerikus értéket tartalmaz, akkor C hibaüzenetet kapunk.
10 LET a$="5"
20 LET b$="4"
30 PRINT a$+b$
40 PRINT VAL (a$+b$)
50 PRINT VAL a$+VAL b$
Eredménye:
54
54
9
A VAL függvény tehát az STR$ függvény inverze.
A VAL$ függvény bemenő adata egy tetszőleges karakterlánc, és a függvény azt adja vissza, de a határoló idézőjel nélkül.
A VAL$ működésének megértéséhez szólnunk kell arról, hogyan is történik a VAL, illetve a VAL$ függvények kiértékelése. A VAL függvény kiértékeli a karakteres kifejezést, majd az idézőjelek eltávolítása után a karakteres kifejezést numerikussá próbálja átalakítani. A VAL$ függvény is kiértékeli a karakteres kifejezést, és eltávolítja a határoló idézőjeleket, de a karaktereket, amelyek így megmaradnak, változatlanul hagyja. Ezért a VAL$ független változóját dupla idézőjelek közé kell tenni. (A dupla idézőjel jelen esetben 3-3 idézőjelet jelent, ugyanis idézőjeleket kell idézőjelek közé írnunk.)
10 LET a$=VAL$ """-13.456"""
20 PRINT a$
30 LET b$="-34"
40 LET c$=VAL$ "b$"
50 PRINT c$
60 LET d$=VAL$ """""""3.5"""""""
70 PRINT d$
Eredménye:
-13.456
-34
"3.5"
A FOR-NEXT utasításnál megismert TO a ZX Spectrumon függvényként is használható. Így használva karakterek levágására - szeletelésére - vagy karakterek beszúrására használható.
A TO függvény formája mindkét esetben:
karakterlánc - kifejezés (kezdet TO vég)
A kezdet és a vég a levágás, illetve a beszúrás elejének ás végének kezdőpozícióját jelzi.
Nézzük először a karakterek levágását! Ha nem adunk meg kezdetet, akkor a TO a legelső karaktertől vágja le a karaktereket. Ha nem adunk meg végső pozíciót, akkor a TO végig levágja a szeletelendő karaktersorozatot. Például:
10 LET a$="nem is nehez"
20 LET b$=a$(1 TO 3)
30 PRINT a$,b$
40 LET c$=a$( TO 6)
50 PRINT a$,c$
60 LET d$=a$(5 TO )
70 PRINT a$,d$
A futás eredménye:
nem is nehez
nem is nehez
nem is neheznem
nem is
is nehez
A TO függvényt arra is használhatjuk, hogy adott karaktersorozat bizonyos helyére másik karaktersorozatot illesszünk.
10 LET a$="ez igy nehez"
20 LET b$="nem"
30 PRINT a$,b$
40 LET a$(4 TO 6)=b$
50 PRINT a$
A program végrehajtása után a kiírás:
ez igy nehez ez nem nehez |
nem |
A logikai műveletekkel - ÉS, VAGY, NEM; angolul AND, OR, NOT -az IF utasításnál már megismerkedtünk. Most arról lesz szó, hogyan használhatjuk őket függvényként.
Az AND függvény értéke kétféle lehet; ha a második változó nem 0, akkor a függvény eredménye az első változó, ha a második változó 0, akkor a függvény eredménye is 0.
10 FOR a=8 TO 9
20 FOR b=0 TO 3 STEP 2
30 PRINT "a=";a;" b=";b;", a AND b=";a AND b
40 NEXT b
50 NEXT a
Az eredmény:
Az eredmény hasonló akkor is, ha az első változó karakteres típusú:
10 LET a$="string"
20 FOR b=0 TO 3 STEP 2
30 PRINT "a$=";a$;" b=";b;", a$ AND b=";a$ AND b
40 NEXT b
Eredménye:
a$=string b=0, a$=string b=2 |
a$ AND b= a$ AND b=string |
Azaz, ha b=0, akkor az a$ AND b függvény eredménye üres karakter.
Az AND függvény nem azonos az AND logikai művelettel. Amint tudjuk, az AND logikai művelet értéke akkor igaz, ha mindkét részfeltétel igaz. Ezt szemlélteti az alábbi kis program:
10 FOR a=3 TO 4
20 FOR b=2 TO 4 STEP 2
30 IF a=4 THEN PRINT 1;" ";
40 IF a<>4 THEN PRINT 0;" ";
50 IF b=4 THEN PRINT 1;" ";
60 IF b<>4 THEN PRINT 0;" ";
70 IF a=4 AND b=4 THEN PRINT 1: GO TO 90
80 PRINT 0
90 NEXT b
100 NEXT a
A program eredménye:
0 0 0
0 1 0
1 0 0
1 1 1
A kiírásban a 0 azt jelenti, hogy a feltétel hamis, az 1 pedig, hogy a feltétel igaz. Az első oszlopban az első feltétel, a második oszlopban a második feltétel értéke látható, míg a harmadik oszlopban a logikai AND művelettel összekapcsolt két érték eredménye. A fenti program eredményét a kétváltozós logikai ÉS művelet igazságtáblázatának is szokták nevezni.
Az OR függvény eredménye 1, ha a második változó nem 0, ha 0, akkor az eredmény az első változóval egyezik meg.
10 FOR a=3 TO 4
20 FOR b=0 TO 2 STEP 2
30 PRINT "a=";a;" b=";b;", a OR b=";a OR b
40 NEXT b
50 NEXT a
Eredménye:
a=3 b=0, a=3 B=2, a=4 b=0, a=4 b=2, |
a OR b=3 a OR b=1 a OR b=4 a OR b=1 |
Most is elmondhatjuk, hogy az OR függvény nem azonos az OR logikai művelettel. Ha az AND-nél leírt program 70-es sorát megváltoztatjuk és az AND-et OR-ra cseréljük ki:
10 FOR a=3 TO 4
20 FOR b=2 TO 4 STEP 2
30 IF a=4 THEN PRINT 1;" ";
40 IF a<>4 THEN PRINT 0;" ";
50 IF b=4 THEN PRINT 1;" ";
60 IF b<>4 THEN PRINT 0;" ";
70 IF a=4 OR b=4 THEN PRINT 1: GO TO 90
80 PRINT 0
90 NEXT b
100 NEXT a
akkor az alábbi eredményt kapjuk:
0 0 0
0 1 1
1 0 1
1 1 1
Ez a kétváltozós logikai VAGY művelet igazságtáblázata.
A NOT függvény értéke 0, ha a NOT után álló változó értéke nem 0. Ha a NOT után álló változó értéke 0, a NOT függvény értéke 1.
10 FOR a=0 TO 6 STEP 6
20 PRINT "a=";a;", NOT a=";NOT a
30 NEXT a
Eredménye:
a=0,
a=6,NOT a=1
NOT a=0
A NOT függvény és a NOT művelet sem azonos:
10 FOR a=3 TO 4
20 IF a=4 THEN PRINT 1;" ";
30 IF a<>4 THEN PRINT 0;" ";
40 IF NOT a=4 THEN PRINT 1: GO TO 60
50 PRINT 0
60 NEXT a
Eredménye:
0 1
1 0
Az egyéb beépített függvények közé sorolt függvényeket röviden úgy lehetne jellemezni, hogy nem tartoznak egyik eddig részletezett csoportba sem. Az ide tartozó függvények közül az IN, a PEEK és a TAB függvényekről már volt szó. Egy függvény maradt csak ki ebből a csoportból: az USR. Helye: az L billentyű, a kurzor: E. Az USR a felhasználó jelentésű angol user szó rövidítése. Az USR függvény egy felhasználói függvényt hív és kétféle célra használható: vagy egy gépi kódú alprogram hívását jelenti, vagy egy felhasználó által meghatározott grafikus jel első bájtjának címét adja meg. Részletesen mindkét esetről később lesz szó. Azt azonban már most tisztázhatjuk, hogy gépi kódú program hívása esetén az USR független változója a gépi kódú program címe:
10 PRINT USR 32500
A megfelelő programot előzőleg természetesen el kell helyezni a 32500-as címen. A felhasználó által meghatározott grafikus jel létrehozásakor a kiválasztott betűt kell megadni az USR függvény független változójaként.
3.22. A felhasználó által meghatározható függvények
A ZX Spectrum egyik erőssége a felhasználói függvények alkalmazásának lehetősége, rugalmassága. Ez a lehetőség - bonyolultabb programok esetén - igen nagy segítséget jelent a programozónak. Az alapelvnek megfelelően a felhasználó előbb bizonyos szabályok szerint meghatároz egy függvényt, később csak hivatkozik majd rá.
A függvények meghatározására - definiálására - a DEF FN utasítás való. Helye: az 1-es billentyű SYMBOL SHIFT-tel, a kurzor: E. A függvényleírás formai szabálya:
sorszám DEF FN betű (változók) = függvény
A betű helyére a felhasználói függvény egybetűs nevét kell írni. Összesen tehát 26 felhasználói függvény lehet. Az egybetűs függvénynevet a független változók zárójelek közötti felsorolása követi. A független változók felsorolása után egyenlőségjel következik, majd a függvény leírása. Tetszőleges függvényeket írhatunk le, és az eddig megismert beépített függvényeket is felhasználhatjuk.
A változókat formális paramétereknek hívjuk. A függvény a formális paraméterek valamilyen függvénykapcsolatát írja le. A
10 DEF FN a(c)=(c*c*c*c-1)
utasítás például azt írja le, hogy a független változó negyedik hatványából egyet le kell vonni. Az így meghatározott függvényt az FN függvénnyel tudjuk aktivizálni, azaz felhasználni. Az FN helye: a 2-es billentyű SYMBOL SHIFT tel, a kurzor: E. Az FN után a függvény egybetűs nevét kell írni. A függvény aktivizálásakor ugyanannyi paramétert kell írnunk, mint a függvény meghatározásakor. Ellenkező esetben a
Q Parameter error, ...
hibát kapjuk, aminek magyar jelentése: paraméterhiba.
Az FN utasításban leírt paramétereket aktuális paramétereknek hívjuk. A függvény minden hívásakor más és más aktuális paraméterrel hívhatjuk újra a függvényt. Az előbb meghatározott a jelű függvényt hívhatjuk például a következőképpen:
10 DEF FN a(c)=(c*c*c*c-1)
100 LET z=2
110 PRINT FN a(z)
220 PRINT FN a(3)
300 LET a=4
310 PRINT FN a(a)
Itt c a formális paraméter, z, 3, a az aktuális paraméterek.
A ZX Spectrumon többváltozós függvényeket is meghatározhatunk. A független változók száma 2x26 lehet, tehát 26 numerikus és 26 karakteres független változót használhatunk. A felhasználó által meghatározott függvényeket egymásba is ágyazhatjuk:
10 DEF FN a(t)=t*t
20 DEF FN b(y)=FN a(y)*FN a(y)
30 DEF FN c(z)=FN b(z)*FN b(z)
40 LET a=2
50 PRINT a,FN a(a),FN b(a),FN c(a)
Eredménye:
2 16 |
4 256 |
A következő program a DEF FN és az FN használatát mutatja be:
10 REM huszonhetedik mintaprogram
20 REM pelda a DEF FN-re es az FN-re
30 REM masodfoku egyenlet megoldasa
40 DEF FN a(a,b,c)=b*b-4*a*c
50 DEF FN b(a,b,c)=(-b+SQR FN a(a,b,c))/(2*a)
60 DEF FN c(a,b,c)=(-b-SQR FN a(a,b,c))/(2*a)
70 DEF FN d(a,b)=-b/(2*a)
80 INPUT "Kerem a masodfoku egyenlet egyutthatoit!","masodfoku tag=";a2,"elsofoku tag=";a1 ,,"allando=";a0
90 CLS
100 IF a2=0 THEN PRINT AT 4,0;"nem masodfoku" : GO TO 160
110 LET d=SGN FN a(a2,a1,a0)
120 PRINT AT 2,0;"masodfoku tag=";a2;" elsofoku tag=";a1;" allando=" ;a0
130 IF d=-1 THEN PRINT AT 4,0;"nincs valos megoldas": GO TO 160
140 IF d=0 THEN PRINT AT 4,0;"a ket megoldas egybeesik ";FN d(a2,a1): GO TO 160
150 PRINT AT 4,0;"x1=";FN b(a2,a1,a0);" x2=";FN c(a2,a1,a0)
160 PRINT "Kell meg szamolni? (i/n)"
170 IF NOT (INKEY$="i" OR INKEY$="n") THEN GO TO 170
180 IF INKEY$="i" THEN GO TO 80
FELADAT
28. | A felhasználói függvények segítségével írjon programot, amely kiszámítja az és függvények értékét tetszőleges helyen! |
3.23. A felhasználói karakterek
A ZX Spectrum egyik érdekes sajátossága, hogy a billentyűkön lévő karaktereken kívül tetszőleges jeleket, karaktereket is használhatunk. Mindössze két körülményt kell figyelembe venni: az egyik, hogy egyszerre legfeljebb 21 ilyen karaktert használhatunk. A másik - magától értendő tény -, hogy a különleges jeleket nekünk kell elmagyarázni a gépnek. Ehhez a következőket kell tudni:
Minden karakter 8x8 pontból áll. A 64 pont mindegyike vagy papír, vagy tinta színű lehet. A kívánt karaktert a következő módon állítjuk elő: első lépésként megtervezzük a betűt. Ezt egy kockás papír 8x8-as területén célszerű elvégezni. A 64 kocka közül bármelyik vagy üres marad, vagy bejelöljük. Ezután a karakternek nevet választunk. A név A-tól U-ig terjedhet. Utána a képet számmá alakítjuk, és az így kapott számokat a POKE utasítás segítségével elhelyezzük a memóriában.
A képet soronként alakítjuk számmá. Minden sorban az üres kockák helyére 0-át, a bejelölt kockák helyére 1-et írunk. Így soronként egy nullákból és egyesekből álló számot kapunk, amely egy 8 bitből álló 2-es számrendszerbeli szám. Ennek a számnak a 10-es számrendszerbeli megfelelőjét kell majd a POKE utasítással a memória megfelelő helyére beírni. A bevitelhez azt kell tudnunk, hogy a 8 sor 8 egymás utáni bájtot foglal le, melyek közül az első bájt címét az USR "karakternév" segítségével kapjuk meg.
Az előállított karaktereket a következő módon tudjuk majd megjeleníteni: a megfelelő PRINT utasításban grafikus üzemmódban idézőjelek között a karakter nevét írjuk le.
Nézzük meg mindezt egy példán! Írassuk ki a számítógéppel az Á és az É betűket. Első lépésként rajzoljuk le kockás papírra a betűket! Célszerű alul egy sornyi és két oldalt egy-egy üres oszlopnyi üres helyet hagyni, hogy a két betű szépen illeszkedjék a többi betűhöz. A két betű rajza a 4. ábrán látható:
|
|
A program a következő:
10 REM huszonnyolcadik mintaprogram
20 REM pelda a felhasznaloi karakterekre
30 DIM z(8)
40 LET z(1)=BIN 00001000
50 LET z(2)=BIN 00001000
60 LET z(3)=BIN 00111100
70 LET z(4)=BIN 01000010
80 LET z(5)=BIN 01111110
90 LET z(6)=BIN 01000010
100 LET z(7)=BIN 01000010
110 LET z(8)=BIN 00000000
120 FOR i=0 TO 7
130 POKE USR "A"+i,z (i+1)
140 NEXT i
150 PRINT "Á"
160 LET z(1)=8
170 LET z(2)=8
180 LET z(3)=64+32+16+8+4+2
190 LET z(4)=64
200 LET z(5)=64+32+16+8+4
210 LET z(6)=64
220 LET z(7)=64+32+16+8+4+2
230 LET z(8)=0
240 FOR i=0 TO 7
250 POKE USR "E"+i,z (i+1)
260 NEXT i
270 PRINT "É"
280 PRINT "SZÁMITOGÉP"
A program 30-as sorában egy 8 elemű tömbnek foglaltunk le helyet. Ez a további munka egyszerűsítéséhez kellett. A program 40-110-es soraiban az Á betű minden pontjának 1, az üres helyeknek 0 felel meg. Az egyes értékeket a BIN függvény segítségével egyszerűen átszámíthatjuk 10-es számrendszerbe.
A 130-as sorszámú utasításban a tömb egyes elemeiből a memória külön területére visszük át az értékeket. A létrehozandó új karaktert A-val jelöltük, és az USR függvénybe is ezt írtuk. A 8 érték beírása után a 150-es sorban már kiírathatjuk az új betűt. Figyelem, a 150-es sorban az idézőjelek közötti A betűnél először grafikus üzemmódba tértünk át -CAPS SHIFT+9 - utána A betűt nyomtunk, majd visszatértünk a grafikus üzemmódból: CAPS SHIFT+9!
A 160-230-as sorszámú sorokban É betűt írtunk le. Itt az előzőekhez képest annyi az eltérés, hogy kiszámoltuk a decimális értékeket.
Érdekességként jegyezzük meg, hogy a NEW parancs hatására kitörlődik a program, de a fent leírt módon meghatározott karaktereket megjegyzi a gép, tehát egy következő programban felhasználhatók. Ha a géppel el akarjuk felejtetni a létrehozott karaktert, akkor ezt -a gép kikapcsolásán kívül -a PRINT USR 0 paranccsal tehetjük meg.
A függvények megismerése után visszatérhetünk a 3.11 pontban közölt 15. programhoz. Ott a megoldás után közöltük a program fő hibáit is:
10 REM tizenotodik mintaprogram (javitott valtozat)
20 REM pelda a GO SUB hasznalatara
30 REM iskolai statisztika
40 PRINT "Ez a program a tanulok ev vegi osztalyzataibol kiszamolja egy-egy tanulo atlagat, a tantar- gyankenti atlagot, az osztaly- atlagot es az iskola atlagat."
60 DIM i(2)
70 INPUT "Kerem az osztaly jelet ";j$,"letszamat ",l,"a tantargyak szamat ";t
75 LET l=ABS (INT (1)): LET t=ABS (INT (t)): If l=0 OR t=0 THEN PRINT "ROSSZ ADAT": GO TO 70
80 GO SUB 1000
90 GO SUB 2000
100 GO SUB 3000
110 INPUT "Van meg osztaly, amelynek atlagot kell szamolni? (i/n)",v$
120 IF v$="i" OR v$="I" THEN GO TO 70
130 CLS
140 PRINT "AZ OSSZES TANULO SZAMA: ",i(2)
145 LET vegso=i(1)/i(2): LET pon=vegso: GO SUB 4000: LET vegso=ker
150 PRINT "AZ OSSZES TANULO ATLAGA:",vegso
999 STOP
1000 REM *****elokeszites uj osztaly eseten
1010 DIM j(l,t): REM osztalyzatok tanulonkent
1020 DIM n$(l,20): REM maximum 20 karakteres nevek
1030 DIM t$(t,10): REM tantargynevek
1040 PRINT "Keret a tantargyak nevet!"
1050 FOR i=1 TO t
1060 INPUT (i);". tantargy neve: ";t$(i)
1070 NEXT i
1080 LET osztalyatlag=0
1081 LET tl=0: LET tt=0
1082 REM tl=tenyleges letszam tantargyankent, tt=tenyleges tantargyszam tanulonkent
1083 DIM f$(l,t)
1084 FOR i=i TO l: FOR j=1 TO t: LET f$(i,j)="0": NEXT j: NEXT i
1090 RETURN
2000 REM *****osztalyzatok tanulonkent es tanulonkenti atlag
2010 FOR i=1 TO l
2020 LET tanulo atlaga=0
2030 INPUT "Az ";(i);". tanulo neve:",n$(i)
2035 CLS : PRINT AT 0,0;"Kerem az osztalyzatokat!": PRINT AT 1,0;"Nev: ";n$(i): PRINT AT 2,0;"Az 5 osztalyzaton kivul minden jel felmentesnek minosul"
2040 FOR j=1 TO t
2050 INPUT (n$(i));" osztalyzata ",(t$(j));" ";m$
2060 IF m$>"0" AND m$<"6" THEN LET j(i,j)=VAL m$: LET tt=tt+1: LET f$(i,j)="1"
2070 LET tanulo atlaga=tanulo atlaga+j(i,j)
2080 NEXT j
2085 IF tt=0 THEN PRINT FLASH 1;"NEM ERTEKELHETO, SEMMIBOL SINCS JEGY!": GO TO 2130
2090 LET tanulo atlaga=tanulo atlaga/tt
2095 LET tt=0: LET pon=tanulo atlaga: GO SUB 4000: LET tanulo atlaga=ker
2100 PRINT n$(i)," atlaga: ";tanulo atlaga
2110 LET i(1)=i(1)+tanulo atlaga
2120 LET i(2)=i(2)+1
2130 INPUT "Mehet tovabb? (i/n)",v$
2140 IF NOT (v$="i" OR v$="I") THEN GO TO 2130
2150 CLS
2160 LET osztalyatlag=osztalyatlag+tanulo atlaga
2170 NEXT i
2180 RETURN
3000 REM *****tantargyankenti atlag szamitasa
3010 CLS
3020 PRINT "Az ";j$;" osztaly atlaga tantargyankent"
3030 PRINT
3040 PRINT "TANTARGY","ATLAG"
3050 LET sorszam=3
3060 FOR j=1 TO t
3070 LET tantargyatlag=0
3075 LET tl=0
3080 FOR i=1 TO 1
3090 LET tantargyatlag=tantargyatlag+j(i,j)
3095 LET tl=tl+VAL f$(i,j)
3100 NEXT i
3105 IF tl=0 THEN PRINT FLASH 1;"EGYETLEN ERTEKELHETO SINCS": PRINT "A PROGRAM LEALL": STOP
3110 LET tantargyatlag=tantargyatlag/t1
3120 PRINT
3125 LET pon=tantargyatlag: GO SUB 4000: LET tantargyatlag=ker
3130 PRINT t$(j),tantargyatlag
3140 LET sorszam=sorszam+2
3150 IF sorszam>20 THEN GO SUB 3500
3160 NEXT j
3170 PRINT : PRINT
3175 LET oatl=osztalyatlag/1: LET pon=oatl: GO SUB 4000: LET oatl=ker
3180 PRINT "AZ OSZTALYATLAG: ";oatl
3190 RETURN
3500 REM *****uj kepernyo
3510 INPUT "Mehet tovabb? (i/n)",v$
3520 IF NOT (v$="i" OR v$="I") THEN GO TO 3160
3530 CLS
3340 PRINT "TANTARGY',"ATLAG"
3550 PRINT
3560 LET sorszam=2
3570 RETURN
4000 REM kerekito szubrutin
4010 REM pon=pontos, ker=kerekitett ertek (2 tizedesre)
4020 LET ker=pon+0.005
4030 LET ker=(INT (ker*100))/100
4040 RETURN
A 4000-4040-ig tartó új szubrutin a kerekítést végzi, két tizedesre. A kerekítés bemenő adata a pon nevű változó, amely a pontos adatot tartalmazza. A 75-ös sorban a javítással elértük, hogy a programnak nem lehet rossz határokat megadni. A 145-ös sorban a kerekítés miatt kellett javítani. Az 1081-1084-es sorban a fakultatív tantárgyak és a felmentések kezelésére vettünk fel új változókat. A 2035-2095-ös sorban a beadott adatokat ellenőriztük tanulónként, és a felmentéseket, illetve a fakultációkat adminisztráltuk. A 2085-ös utasítás kiszűri, ha egy tanulónak semmiből sincs értékelhető jegye, de a program folytatódik. Ezzel szemben a 3105-ös sorban az új vizsgálat kiszűri, ha egy tantárgyból senkinek sincs osztályzata egy osztályon belül. Ekkor feltételezhetően végzetes hiba történt, ezért a program leáll. A programot tovább lehetne bővíteni a magyar magánhangzók használatával.
3.24. A SAVE ás a LOAD további lehetőségei
A SAVE ás a LOAD utasítások működését már ismertettük, most néhány olyan lehetőséget sorolunk fel, amelyek alkalmazásával a ZX Spectrum igazán komoly munkaeszközzé válik.
3.24.1. Az automatikus programindítás
A SAVE utasítást LINE kulcsszóval bővítve elérhetjük, hogy a program a betöltés után azonnal induljon. Ha egy programot például a
SAVE "akarmi" LINE 10
paranccsal kimentünk, a program a visszatöltés után automatikusan indul. Azaz a
LOAD "akarmi"
parancs hatására a program nemcsak betöltődik a tárba, hanem a 10-es sorszámú utasítástól kezdve megkezdődik a végrehajtása is.
3.24.2. Az adattömbök használata
A SAVE utasítást DATA kulcsszóval bővítve lehetőségünk nyílik adattömbök kimentésére vagy visszatöltésére. A
SAVE "numtomb" DATA a()
paranccsal például az a neve numerikus tömböt menthetjük ki, a
SAVE "kartomb" DATA a$()
paranccsal pedig az a$ nevű karakteres tömböt. A tömbök a
LOAD "numtomb" DATA a()
és a
LOAD "kartomb" DATA a$()
paranccsal tölthetők vissza.
Mind a SAVE, mind a LOAD esetében kötelező a zárójelpár használata. Egy gyakorlati jó tanács: A tömbök LOAD paranccsal való visszatöltése után a programot ne RUN-nal indítsuk, hanem GO TO-val, mert a RUN törli a tömbök tartalmát. Az így kimentett tömböket a MERGE paranccsal nem lehet betölteni.
3.24.3. A képtartalom kimentése
A képernyőn lévő képet a SAVE után írt SCREEN$ kulcsszóval lehet kimenteni és a LOAD-dal lehet visszatölteni. A
SAVE "kep" SCREEN$
például kimenti, a
LOAD "kep" SCREEN$
visszatölti a képet.
3.24.4. A gépi kódú programok kimentése
A gépi kódú programokat úgy tudjuk kimenteni, hogy a SAVE utasítás után a következőket írjuk: A CODE kulcsszót, a gépi kódú program címét, valamint a program hosszát bájtokban. A
SAVE "gepi kod" CODE 32500,100
például a 32500-as címen kezdődő 100 bájt hosszúságú tártartalmat menti ki, amelyet a
LOAD "gepi kod" CODE
vagy a
LOAD "gepi kod" CODE 32500,100
paranccsal lehet visszatölteni. Mindkét LOAD behozza a gépi kódú programot, de a második ellenőrzi is, hogy tényleg a megadott hosszúságú-e. A felhasználó által irt grafikai jeleket a
SAVE "betuk" CODE USR "a",21*8
paranccsal lehet kimenteni, amelyet a
LOAD "betuk" CODE USR "a"
paranccsal tölthetünk vissza. Az utóbbi két parancs az összes - 21 db - felhasználói karaktert kimenti, illetve visszatölti.
A ZX Spectrumhoz számos nyomtató kapcsolható. A legegyszerűbb a SINCLAIR által gyártott nyomtató használata. Ennek legfőbb hátránya a kis sebesség és a drága papír, de előnye, hogy egyszerűen kezelhető.
A nyomtatót a gép kikapcsolt állapotában kell a számítógép hátán, jobb oldalon lévő csatlakozóba kötni. A nyomtató három paranccsal működtethető:
Az LPRINT és az LLIST utasítások helye: a C és a V billentyű, a kurzor mindkét esetben: E. A két utasítás a PRINT és a LIST utasításokhoz teljesen hasonlóan működik, de természetesen a nyomtatóra ír ki. Az LPRINT-nél annyi az eltérés, hogy az AT csak oszlopszámot szabályoz, sorszámot nem, és a színkezelő utasítások sem működnek.
A COPY utasítás helye: a Z billentyű, Jelentése másolni. Ennek megfelelően a képernyő tartalmát a nyomtatóra másolja át.
3.26. Néhány érdekes lehetőség
Eddig azzal foglalkoztunk, amit a ZX Spectrum BASIC nyelvű programozásáról tudni kell. Már csak a microdrive használata maradt hátra. A hazai felhasználók között a microdrive még nem nagyon terjedt el, ezért ismertetése előtt néhány olyan módszert, eljárást mutatunk be, amelyet minden ZX Spectrum tulajdonos könnyen kipróbálhat.
A nyomtatási feltételeket - ha a kinyomtatandó információ karakteres jellegű -beépíthetjük magába a PRINT utasításba is:
10 INPUT i
20 LET a$="kutya"
30 LET b$="cica"
40 PRINT (a$ AND j>0)+(b$ AND j<=0)
Ha a fenti rövid programot kipróbáljuk, akkor pozitív bemenő adat esetén - mivel az első feltétel igaz - az a$ értéke, a "kutya" nyomtatódik ki, míg 0 és negatív számok esetén a b$ értékét írja ki a program. Numerikus értékek esetén a felírás nem üzembiztos, ezért numerikus változóknál célszerű az STR$ függvényt használni.
A GO TO utasításnál elmondtuk, hogy a GO TO utáni sorszám változóként is megadható. Például az
1000 GO TO i
utasítás teljesen szabályos, ha i megfelelő értékkel rendelkezik. Ennek továbbfejlesztéseként írhatunk olyan GO TO utasítást, melynek elágazásait a billentyűzetről vezéreljük. Erre mutat példát az alábbi - önmagában is használható - programrészlet:
1000 LET a$=INKEY$: GO TO 1000+100*(a$="1")+200*(a$="2")+300*(a$="3")+999*(a$=" ")
1100 PRINT "az 1-es lett megnyomva"
1199 STOP
1200 PRINT "a 2-es lett megnyomva"
1299 STOP
1300 PRINT "a 3-as lett megnyomva"
1399 STOP
1999 PRINT "a ""SPACE"" lett megnyomva"
Ha az 1-es, 2-es, 3-as, vagy SPACE billentyűkön kívül egyéb billentyűt nyomunk meg, a program mozdulatlan, mert az 1000-es sorszámú utasítás ilyenkor egy 1000 GO TO 1000 utasításnak felel meg. Ha valamelyik fenti kiválasztott karaktert nyomjuk meg, akkor az INKEY$ által generált logikai érték igaz, azaz 1 lesz, és így a zárójel előtt álló konstanst ezzel kell szorozni. Ha a feltétel hamis, akkor 0-val kell szorozni a konstanst.
A GO TO-ba egyéb feltételeket is be lehet építeni:
999 INPUT x,y,Z
1000 GO TO 1100*(x=0 AND y=1 OR z=2)+1200*(x<>0 OR y<>1 OR z<>2)
1100 PRINT 1100
1111 STOP
1200 PRINT 1200
A fenti - nem túl érdekes, de szemléltető - példából az a következtetés vonható le, hogy a GO TO utasításba tetszőlegesen bonyolult logikai kifejezéseket is beírhatunk. A logikai kifejezések kiértékelésük után 0-t vagy 1-et adnak eredményül. Az igaz feltételnek megfelelő 1-et tetszőleges aritmetikai kifejezésekbe építhetjük be. Vigyázni kell azonban a feltételek írásánál. Ha olyan fettételt írunk, amely egyszerre egynél több tagnál is teljesül, akkor esetleg nem kívánt módon működik majd a program. Ha viszont olyan feltételeket írunk, amelyek sohasem teljesülnek, akkor végtelen ciklust kaphatunk. Nézzük a következő programot!
10 LET x=3
20 LET y=4
30 LET z=2
40 GO TO (1000*(x=0 OR z=2)+1200*(y=0 OR z=2))
1100 PRINT 1100: STOP
1200 PRINT 1200: STOP
Ez a program így a
0 O K, 40:1
üzenettel fog leállni. Ha viszont kijavítjuk a 30-as sorszámú sort:
10 LET x=3
20 LET y=4
30 LET z=-2
40 GO TO (1000*(x=0 OR z=2)+1200*(y=0 OR z=2))
1100 PRINT 1100: STOP
1200 PRINT 1200: STOP
akkor végtelen ciklust kapunk.
A GO TO érdekességei közül végül bemutatjuk, hogy a GO TO utasítás a DATA-READ utasításpárral is kombinálható:
10 DATA "x=0 AND y=1 OR z=2",1100,"x<>0 OR z=2",1200
800 PRINT 800
900 INPUT "x= ";x;", y= ";y;", z= ";z
910 PRINT 910
920 FOR i=1 TO 2
930 READ a$,n
940 GO TO VAL a$*n
930 NEXT i
1000 PRINT 1000: STOP
1100 PRINT 1100: STOP
1200 PRINT 1200: STOP
A programot futtatva két eset lehetséges: vagy az első feltétel teljesül, vagy a második, a beolvasott adattól függően. Ha az első feltétel teljesül, akkor a program a következőt írja ki:
800
910
1100
Ha az első feltétel nem teljesül, a program újabb adatokat kér, noha a vezérlést nem küldjük vissza az INPUT-ra. Ekkor
800
910
800
910
1200
lesz a sorrend, és a 800-as, 910-es kiírások között minden esetben adatokat vár a program.
3.26.3. A képernyő érdekességei
Amint ez már ismert, 0-tól 21-ig, azaz 22 sorba tudunk kiírni a képernyőre. A legalsó 2 sort a számítógép magának tartja fenn. Némi ügyeskedéssel azonban oda is írhatunk. Azt kell tudnunk hozzá, hogy a ZX Spectrum a perifériákat a csatornarendszeren (16 db 0-tól 15-ig számozott csatorna) keresztül éri el. A programban ezekre a - végső soron az elektronikus kapcsolatot megvalósító - csatornákra az ún. kettőskereszt (#) - angolul hashmark - segítségével hivatkozhatunk. A kettőskereszt helye: a 3-as billentyű SYMBOL SHIFT-tel.
Nézzük például az alábbi programot:
10 FOR i=0 TO 3
20 PRINT #i ,i
30 NEXT i
40 PAUSE 0
A program eredménye:
illetve a nyomtatón - ha van - a 3-as is megjelenik. A 0 és az 1 a képernyő alsó két sorában, a 2 a képernyő felső sorában jelenik meg. A 0 és az 1 a képernyő alsó két sorának csatornáját jelenti, a 2-es a képernyő, a 3-as a nyomtató csatornája. A PAUSE 0 azért kell, hogy a program ne fejeződjön be, mert akkor a befejező üzenet törli az eredményt.
A következő rövid program a képernyő alsó 22 sorába ír:
10 FOR i=0 TO 21
20 PRINT #1;AT i,i;i
30 NEXT i
40 PAUSE 0
A csatornák felhasználásával írhatunk olyan programot is, amely nem a felső vagy alsó 22 sorba ír ki, hanem mind az alsó, mind a felső részre:
10 FOR i=0 TO 23
20 IF i<22 THEN PRINT i
30 IF i>22 THEN PRINT #0;AT i-22,0;i
40 NEXT i
50 PAUSE 0
A következő rövid program a beadott betűktől függően alulról vagy felülről ír 22 sort. A beadott betűk csak az s vagy a k lehetnek. A k betű hatására alulról, az s betű hatására felülről kezd írni a ZX Spectrum. Más betűk hatására az
F lnvalid file name
üzenetet kapjuk, amelynek magyar jelentése: hibás adatállománynév.
A hiba magyarázata: a képernyőhöz a 2-es csatorna tartozik. Ehhez csak két adatállomány tartozhat: a képernyő, angolul screen, röviden s és a billentyűzet, angolul keyboard, röviden k. Nyilvánvaló, hogy ha valamit ki akarunk írni a képernyőre, akkor felül kezdjük, és így haladunk lefelé. A számítógépnek szóló információkat pedig alul kezdjük, és így haladunk felfelé. Az állományokat - amint erről a microdrive-nál szó lesz - az OPEN utasítással meg kell nyitni (4-es billentyű).
A program tehát a következő:
10 LET a$=INKEY$
20 IF a$="" THEN GO TO 10
30 OPEN #2,a$
40 FOR i=0 TO 21
50 PRINT AT i,i;i
60 NEXT i
70 PAUSE 0
A következő program is az alsó sorba ír:
10 INPUT i
20 OPEN #i,"k"
30 PRINT #i,AT i,i;"alulra"
40 PAUSE 0
A programban i 0 és 15 közötti tetszőleges egész szám lehet.
A microdrive és a hozzá tartozó Interface 1 a ZX Spectrumot olyan munkaeszközzé teszi, amely méreteit meghazudtoló feladatok megoldására is alkalmas. Mi is az a microdrive és az Interface 1?
A microdrive lényegében egy kis méretű magnetofon, amely az adatrögzítés igen fontos és hatékony eszköze. Beléhelyezhető kazettáján 70-90 kilobájtnyi adat tárolható. Fizikai megvalósítását tekintve a microdrive-ban végtelenített mágnesszalag forog nagy sebességgel. A microdrive-on programok, adatok tárolhatók és onnan néhány másodperc alatt visszanyerhetők.
Az Interface 1 a microdrive vezérlőegységét tartalmazza, de ugyanakkor módot ad arra is, hogy segítségével az ZX Spectrumot ún. helyi hálózatba kapcsoljuk. A helyi hálózat egyszerre legfeljebb 64 állomásból állhat. Az állomások bármelyike ZX Spectrum és Interface 1 vagy SINCLAIR QL lehet. Az Interface 1-ben lévő RS 232-es Interface - csatlakozó - lehetővé teszi más, eredetileg nem a ZX Spectrumhoz készük számítástechnikai eszköz csatlakoztatását a ZX Spectrumhoz.
Az Interface 1-et úgy kell összekapcsolni a ZX Spectrummal, hogy az áramforrásból kihúzott, más perifériáktól - tv, magnetofon, stb. - megszabadított alapgépen az alaplap hátsó részének jobb és bal oldalán lévő egy-egy csavart kicsavarjuk. Ezután az Interface 1 beilleszthető, majd a két csavar visszacsavarható. Az első microdrive-ot a dobozban lévő kábellel a ZX Interface 1 bal oldalán lévő csatlakozóhoz kapcsoljuk. Több microdrive használata esetén a microdrive-okat értelemszerűen egymáshoz kell kapcsolni.
A következőkben néhány alapfogalmat ismertetünk. Előrebocsátjuk, hogy - az eddigiekhez hasonlóan - a microdrive használata is csak gyakorlással sajátítható el.
Adatállomány (fájl): logikailag összetartozó adatokat jelent. A ZX Spectrum microdrive csak ún. soros szervezésű adatállományokat használ. Ezek általános jellemzője, hogy minden külön adatot csak úgy érünk el, ha az előtte lévőket már elértük (hasonlóan a magnetofonon tárolt adatokhoz).
A puffer ideiglenes adattárolót jelent. Célja az adatátvitel gyorsítása. A számítógép memóriájából a microdrive-ra, illetve fordítva mindig a puffer méretének megfelelő adatmennyiséget vihetünk át. A microdrive puffere 512 bájt.
Katalógus: egy-egy microdrive kazetta tartalomjegyzéke, amely a kazettán lévő állományok, adatok nevét tartalmazza.
Csatornák: az adatok átvitele a számítógép központi egysége és a perifériák között a csatornák segítségével történik. A ZX Spectrum kétféle csatornát használ:
A ZX Spectrumhoz 16 logikai és 7 fizikai csatorna tartozik. A logikai csatornákat 0-tól 15-ig sorszámozzuk és # jellel jelöljük. A #0-#3 csatornák már alapértelmezésként meghatározott fizikai csatornákhoz vannak rendelve. Ez a 4. táblázatban látható. A fizikai csatornákat az 5. táblázat sorolja fel.
Az adatokat kiíró és beolvasó utasításoknál - PRINT, INPUT, INKEY$ - microdrive, illetve Interface 1 használata esetén mindig jelezni kell a megfelelő logikai csatornát.
4. Táblázat:
Logikai csatorna | Jel | Fizikai eszköz | Irány |
#0 #1 #2 #3 |
K K S P |
A tv alsó két sora és a billentyűzet A tv alsó két sora Billentyűzet és a tv felső 22 sora Nyomtató |
Kiírás Bevitel Kiírás Bevitel Kiírás Kiírás |
5 Táblázat:
A fizikai csatornák |
|
Jel | Leírás |
K S P T B N M |
Billentyűzet (keyboard) Képernyő (screen) Nyomtató RS 232 Interface (text) RS 232 Interface (binary) Hálózat (network) Microdrive |
Állományok nyitása, zárása. Az állományokat használat előtt az OPEN utasítással meg kell nyitni. Ekkor megy végbe az állomány nevének, létezésének ellenőrzése, valamint a fizikai és logikai csatornák összekapcsolása. Az állomány lezárása: a maradék adat átvitele és a kapcsolat megszüntetése. Nem megfelelően lezárt állományt többé nem tudunk elérni.
Formázás: Az új kazettát a legelső használat előtt a megfelelő paranccsal - FORMAT- alkalmassá kell tenni az adatok fogadására. Ha adatot tartalmazó kazettát formázunk, akkor az addig rajta tárolt összes adat, program elvész. Itt hívjuk fel a figyelmet, hogy a kazettát nem szabad kivenni a microdrive-ból, ha a lámpa világít, mert a kazetta fizikailag károsodhat!
3.27.2. A microdrive használatához szükséges új parancsok
Parancs | Jelentés |
CAT y | Az y jelű microdrive tartalomjegyzékét adja meg. Az állományok nevén kívül a kazetta nevét és a kazettán lévő szabad kilobájtok számát is kiírja. Az y 1 és 8 közötti szám lehet. |
CAT # z;y | Ugyanaz, mint a CAT, de a kazetta nevét, a tartalom jegyzéket és a szabad kilobájtok számát a z logikai csatornára küldi. |
CLOSE # z | Lezár egy logikai csatornát. |
ERASE "m";y;"nev" | Az y jelű microdrive-ban lévő kazettáról törli a "nev" jelű állományt. |
FORMAT "m";y;"nev" | Az y jelű microdrive-ban lévő kazettát formázza. A kazetta neve az idézőjelek között megadott név lesz. Maximálisan 10 karakteres név adható meg. |
FORMAT "n";x | Az adott ZX Spectrumot x számmal beállítja a hálózatba. Az x 1 és 64 közötti szám lehet (különleges esetben 0 is). |
FORMAT "t";x FORMAT "b";x |
Az RS 232 beállítása x szabványos átviteli sebességre (t = szövegátvitel, b = bináris átvitel). |
INKEY$ # z | Ugyanaz, mint a normál INKEY$, de csak hálózat vagy RS 232 Interface esetén használható. |
INPUT # z; változó | Ugyanaz, mint a normál INPUT, de előzőleg a z logikai csatornát meg kell nyitni. |
LOAD * fizikai csatorna | Ugyanaz, mint a normál LOAD, de csak "b", "n", "m" csatorna használható. |
MERGE * fizikai csatorna | Ugyanaz, mint a normál MERGE, de microdrive-ra (csak "b", ,'n", "m" csatorna használható). |
MOVE honnan TO hova | Adatokat mozgat át a logikai és a fizikai csatornák között. |
OPEN # stream, csatorna | A streamet a megadott csatornához rendeli. |
PRINT # logikai csatorna | Kiírás a logikai csatornára. |
SAVE * fizikai csatorna | Ugyanaz, mint a normál SAVE, de microdrive-ra vagy hálózatra. |
VERIFY * fizikai csatorna | Ugyanaz, mint a normál VERIFY, de microdrive-ra. |
4. A ZX Spectrum gépi kódú programozása
Mindenekelőtt a fejezet címét szeretnénk pontosabbá tenni, illetve megmagyarázni. Ehhez bizonyos számítástechnikai, főleg hardver fogalmakat kell tisztáznunk, átismételnünk. (A számítástechnikában hardvernek nevezzük a dolgok megvalósításához szükséges valamennyi elektronikát.) Felmerülhet az olvasóban: mi szükség van erre, hiszen "az is tudhat autót vezetni, akinek fogalma sincs arról, hogy mi történik a motorban, amikor beletapos a gázpedálba". Ez kétségkívül igaz, csakhogy a számítógép az autónál jóval bonyolultabb eszköz, s az önálló, gépi kódú programozáshoz néhány egyszerűbb fogalom ismerete - véleményünk szerint - elengedhetetlen.
Minden elektronikus számítógép működését egy központi vezérlőegység (CPU) szabályozza és ellenőrzi. Ez a ZX Spectrumnál egy Z80A típusú mikroprocesszor, amelynek a gépi kódú programozásban meghatározó szerepe van.
Mit is jelent gépi kódban programozni? Körülbelül azt, hogy a processzorral közlünk egy alkalmas sorrendű számkombinációt, melynek hatására a kívánt folyamat lejátszódik. Mivel ezeket a számokat a memóriarekeszek tartalmazzák, értékük 0 és 255 között változhat.
A következő vázlatos ábra egy számítógép, esetünkben a ZX Spectrum felépítésének egy elvi részletét mutatja.
5. ábra
Az egyes számítógépi folyamatok során különös jelentőségű az adatok mozgatása. Természetesen ezt a feladatot is a CPU végzi. Megcímezi a kívánt memóriarekeszt, beolvassa belőle az adatot, újabb címzés, majd az adatot kiviszi az új címre.
A Z80 processzor 2 bájt hosszúságú címeket tud képezni, tehát 0-tól 65535-ig (= 2^16 -1), azaz összesen 65536-ot. Az iménti leírásból az is kitűnik, hogy az adatátvitel nem közvetlenül a memóriarekeszek között, hanem a processzoron keresztül zajlik. Ehhez azonban nyilvánvalóan az kell, hogy a processzornak legyenek saját belső memóriarekeszei. Ezek az ún. regiszterek. A következő ábra a regiszterek elvi vázlatát mutatja be. A zárójelben lévő szám megadja, hogy az adott regiszter hány bit hosszúságú.
|
|
||||||||||||||||
|
6. ábra
A gép BASIC nyelvű programozásakor nem történik egyéb, mint hogy a gép a ROM segítségével értelmezi a BASIC program egyes sorait, azaz a megfelelő - ROM-ban található - gépi kódú részprogramokat, az ún. rutinokat aktivizálja, lefuttatja. Mindezekből talán látszik, hogy a processzor a gépi kódú programot érti meg, tehát minden más nyelven megírt programot előbb értelmeznie kell.
Még két kérdésre szeretnénk kitérni. A fejezet címében egy konkrét géptípus gépi kódú programozásáról beszéltünk, viszont az eddig elmondottak art sugallják, hogy a gépi kódú programozás kódrendszere kizárólag a processzor típusától függ. Ez igaz is, ha csak a gépi kódú programozás utasításkészletére gondolunk. Ha azonban figyelembe vesszük, hogy a programozás semmilyen formában sem lehet öncélú, akkor már tekintettel kell lennünk az adott géptípusra is. A tv-kép memóriabeli elhelyezkedése stb. már az adott gép felépítésétől függ.
A második kérdés a gépi kódú program tömörebb, áttekinthetőbb jelölésmódjára vonatkozik. Ez az ún. assembly nyelv. Az assembly nyelv és a gépi kód közé persze több okból sem lehet egyenlőségjelet tenni. Az assembly nyelv általában több utasítást tartalmaz, mint az egyszerű gépi kód. Ezek az utasítások a programelhelyezés megszervezésére, az adatmezők kijelölésére stb. vonatkoznak. Másrészt - és ez a fontosabb - a gép közvetlenül nem érti meg még ezt a nyelvet sem. Megfelelő, viszonylag egyszerű fordítóprogram (assembler) segítségével azonban igen kényelmes a használata.
Az assembly nyelv jelölése annyira világos és áttekinthető, hogy a programokat a továbbiakban ebben a jelölésrendszerben írjuk, és csak mellékesen utalunk a 10-es (decimális), illetve 16-os (hexadecimális) számrendszerű gépi kódú jelölésre.
4.3. A Z80 mikroprocesszor regiszterei
A 6. ábrán láttuk, hogy a Z80 mikroprocesszornak 22 regisztere van. Ebből azonban csak 14 aktív, ugyanis a vesszős regiszterek - A', B', C, D', E', H', L' és F - lényegében csak arra valók, hogy a megfelelő aktív regiszterek tartalmát szükség esetén -alkalmas utasítások hatására - tárolják. Pontosabban szólva: az alkalmas utasítások hatására a megfelelő regiszterpárok tartalma felcserélődik. Ezek a felcserélési utasítások, valamint mindazok, amelyek a 16 bites műveletekkel kapcsolatosak, párban kezelik a regisztereket. Ezek a párok a következők:
BC |
|
||||||||||||||||||||||||||||||||
DE |
|
||||||||||||||||||||||||||||||||
HL |
|
||||||||||||||||||||||||||||||||
AF |
|
A továbbiakban röviden taglaljuk az egyes regiszterek szerepét.
Általános célú regiszterek
Ehhez a csoporthoz az A, B, C, D, E, H és L regiszterek tartoznak. Szerepük az utasításkészlet következtében nem egyenértékű. Így a legtöbb 8 bites aritmetikai és valamennyi logikai művelet eredménye az A regiszterbe kerül, a kétbájtos aritmetikai műveletek zöme pedig a HL regiszterpárral kapcsolatos.
Az F regiszternek egészen különös tulajdonsága van. Az a szerepe, hogy a műveletek során kialakult eredmény jellegét valamilyen formában jelezze (innen az elnevezése: flag = jelzőbit). Ez úgy történik, hogy az F regiszter egyik bitje az eredmény alakulásától függően 0 vagy 1 lesz. A legfontosabb bitek a következők:
Az F regiszter további három bitje adhat még hasznos információt. A maradék két bit, a 3. és az 5. értéke határozatlan. A még hasznos információt adók a következők:
A túlcsordulás fogalmát - e vonatkozásban - érdemes tisztáznunk.
Arról van szó ugyanis, hogy egy 8 bites szám tekinthető előjeles számnak a következő értelemben:
azaz pl.
10011011=27-128=-101
A túlcsordulási jelzőbit akkor vált 1-re, ha valamelyik művelet kivezet a [-128, -1] vagy a [0,127] tartományból. Például:
01101101 |
109 |
+ 01010101 |
+ 85 |
11000010 |
194 |
194> 127, tehát V = 1 lesz, és a szám ebben az értelemben
66 - 128 = -62
Speciális célú regiszterek
Ezek a 16 bites PC, SP, IX és IY, valamint a 8 bites I és R regiszterek.
A PC (programszámláló) regiszter azt a memóriacímet tartalmazza, ahol a következő végrehajtandó utasítás első bájtja található. A Z80 utasításai 1,2,3 vagy 4 bájt hosszúságúak. A PC regiszter mindig az adott lánc első bájtjára mutat. A program végrehajtása során a CPU mindig automatikusan növeli a PC tartalmát.
A mikroprocesszorokat, így a Z80-at is úgy alkották meg, hogy képesek legyenek csaknem valamennyi regiszterük tartalmát a külső RAM meghatározott részére közvetlenül kimenteni, illetve onnan beolvasni. (Ez a memóriarész a verem, angolul stack.) A kimentés a RAM bizonyos címétől kezdődően a csökkenő címek felé halad, a beolvasás pedig mindig a növekvő címek irányában. Ezekben a műveletekben kizárólag 16 bites regiszterpárok vesznek részt. Tehát, ha a kimentési sorrend 1, 2, 3 volt, akkor a beolvasási sorrend 3, 2, 1 lesz. Az SP regiszter azt a legalacsonyabb RAM címet tartalmazza, ahol ilyen kimentett érték van.
Az IX és az IY ún. indexregiszterek. Ezek a regiszterek lehetővé teszik a memória indexes, azaz közvetett címzését. Az indexregiszter tartalma + egy 8 bit hosszúságú szám együttesen adja a művelet szempontjából értékes adatot tartalmazó memóriacímet. Rendkívül hatékony lehetőség!
Az I regiszter az ún. megszakítási vektor regisztere. Később - az utasítások kapcsán - bővebben tárgyaljuk a szerepét.
Az R regiszter az ún. memóriafrissítő regiszter. Ez egy egyszerű számláló, melynek tartalma minden utasítás vagy minden adatbájt beolvasása után 1-gyel nő, tehát ismételten 0-255 közötti értéket tárol. Ez az érték kikerül a címsínre és egy látszat memóriakiolvasás történik. Erre a látszólagos beolvasásra, frissítésre azért van szükség, mert a dinamikus félvezető memória - valódi beolvasás hiányában - rövid időn belül elfelejtené a tartalmát. Programozás szempontjából ennek a regiszternek nem sok szerepe van.
4.4. A Z80 mikroprocesszor utasításkészlete
A következőkben vázlatos áttekintést adunk a Z80 mikroprocesszor utasításkészletéről. Nem térünk ki valamennyi utasításra, de ahol csak lehet, taglaljuk az utasítás végrehajtásának minden lényeges következményét. Az utasításokat csoportosítva tárgyaljuk. A csoportosítás - természeténél fogva - bizonyos önkényességet tartalmaz, de így talán áttekinthetőbb lesz.
Mielőtt rátérnénk az egyes utasításcsoportok részletes ismertetésére, egy érdekességre utalunk. A Z80 utasításai bizonyos matematikailag is megfogalmazható struktúráltságot mutatnak. Ilyen például az is, hogy egyes azonos típusú utasítások számkódjainak különbsége maradék nélkül osztható 8-cal. Ez a szerkezeti felépítés azonban a tényleges programírás szempontjából kevésbé jelentős, inkább csak az utasítástáblázatban való keresésekor segít.
Az egyes utasításcsoportok bemutatásának formája a következő: Néhány általános bevezető sor után utasítási példákkal szemléltetjük az adott csoportot. A példa mindig a konkrét utasítás formai leírásával kezdődik a következő sorrend szerint: assembly írásmód, decimális kód, hexadecimális kód. Ezután röviden elmondjuk, hogy mi történik az utasítás hatására. Mivel az egyes utasítások leírásához több kódra is szükség lehet, vesszővel választjuk el őket.
4.4.1. Az egyszerű betöltési utasítások
Ezek a 8, illetve 16 bites műveletek - természetüknél fogva - két 8 bites utasítástól eltekintve nem változtatják meg a jelzőbiteket. A címzés lehet közvetlen vagy közvetett. Összesen mintegy 144 ilyen típusú utasítás van. A legfontosabbak a következők:
LD A,27 |
62,27 |
3E,1B |
Az utasítás hatására az A regiszterbe 27 kerül.
LD H,139 |
38,139 |
26,8B |
Az utasítás hatására a H regiszterbe 139 kerül.
LD B,L |
69 |
45 |
Az utasítás hatására a B regiszterbe betöltődik az L regiszter tartalma. Az L regiszter tartalma természetesen nem változik.
LD A,(29318) |
58,134,114 |
3A,86,72 |
Az utasítás hatására az A regiszterbe betöltődik a 29318-as címen lévő memóriarekesz
tartalma.
Az utasítás megértése a kezdő olvasónak esetleg gondot okozhat, ezért a gépi kódú címleírást, illetve a processzorcímzés szerkesztését részletesebben tárgyaljuk.
A gépi kódú címzés és a regiszterek
A gépi kódban a legnagyobb szám 255 lehet, a processzor által előállított cím viszont maximum 65535 is lehet. E látszólagos ellentmondásnak az a feloldása, hogy címként mindig két egymást követő kódot használunk. A címkódok sorrendje lényeges, ugyanis az első kód a cím értéknagysága szempontjából kevésbé meghatározó, mint a második. Így, ha a címkódok sorrendje: p,Q, akkor a tényleges cím az
n = 256*q + p
összefüggés alapján számolható ki.
A fenti összefüggésből nyilvánvaló, hogy ha elemeire bontunk egy címet, akkor a
q = INT (n/256)
és a
p = n - 256*INT (n/256)
képletet használhatjuk.
Ha a processzor regiszterpárjainak tartalmát címként értelmezzük, akkor az eljárás a fentiekhez hasonló. Megjegyezzük, hogy ha a tartalom csupán szám jellegű, akkor értelmezése ugyanilyen, de figyelembe kell venni, milyen a jelölési rendszer. Az összekapcsolható regiszterek (például a BC, DE, stb.) esetén ugyanis a jelölési konvenciók következtében az elöl álló regiszter tartalmazza a meghatározó értéket. Például:
n =256*(D) + (E)
E kis kitérő után nézzük újra a betöltési utasításokat!
LD C,(HL) |
78 |
4E |
Az utasítás hatására a HL regiszterpár által meghatározott címen lévő tartalom betöltődik a C regiszterbe. Az ilyen típusú címzést közvetett (indirekt) címzésnek hívjuk.
LD (IY+32),E |
253,115,32 |
FD,73,20 |
Az utasítás hatására az E regiszter tartalma betöltődik az IY regiszter által megadott számnál 32-vel nagyobb értékű címre. 32 helyett - szükség esetén - bármely 0 és 255 közötti szám választható. (A +0-t ki sem kell írni.)
LD BC,1000 |
1,232,3 |
01,E8,03 |
Az utasítás hatására a BC regiszterpárba 1000 íródik be, azaz B-be 3, C-be 232.
LD HL,(40000) |
42,64,156 |
2A,40,9C |
Az utasítás hatására a 40000-es cím tartalma L-be, a 40001-es cím tartalma pedig H-ba íródik be.
LD SP,HL |
249 |
F9 |
Az utasítás hatására a HL regiszterpár tartalma betöltődik az SP regiszterbe.
LD (40000),IX |
221,34,64,156 |
DD,22,40,9C |
Az utasítás hatására a 40000-es címre betöltődik a 16 bites IX regiszter alsó nyolc (kevésbé meghatározó) bitje, míg a 40001-es címre az IX felső nyolc bitje.
PUSH DE |
213 |
D5 |
Az utasítás hatására a DE regiszterpár tartalma kimentődik a RAM verem- (stack) területére, vagyis az E regiszter tartalma betöltődik az SP regiszterbeli címnél kettővel kisebbre, a D regiszter tartalma az SP regiszterbeli címnél eggyel kisebbre, és az SP regiszter tartalma kettővel csökken.
POP DE |
209 |
D1 |
Az utasítás hatására az SP regiszter által meghatározott cím tartalma betöltődik az E regiszterbe, az eggyel magasabb cím tartalma pedig a D regiszterbe, végül az SP értéke kettővel nő.
4.4.2. A blokkbetöltési és az átviteli utasítások
Négy ilyen utasítás van, amelyek közül kettő addig ismétlődik, amíg bizonyos feltétel nem teljesül. Ezek az utasítások az előjelet, a nullát és az átviteli jelzőbiteket nem érintik, az N és H jelzőbitek pedig 0-ra állítódnak be.
LDI |
237,160 |
ED,A0 |
Az utasítás hatására a HL regiszterpárban megadott címen lévő tartalom betöltődik a DE regiszterpárban megadott címre. A DE és a HL regiszterpár tartalma eggyel nő, a BC regiszterpár tartalma eggyel csökken. Ha a BC regiszterpár tartalma 1, akkor a P/V jelzőbit értéke éppen 0, különben 1.
LDIR |
237,176 |
ED,B0 |
Ugyanaz, mint az LDI, de a lépések automatikusan addig ismétlődnek, amíg a (BC) = 0 feltétel nem teljesül. A P/V jelzőbit értéke 0!
LDD |
237,168 |
ED,A0 |
Ugyanaz, mint az LDI, de a DE és a HL regiszterpárok tartalma csökken.
LDDR |
237,184 |
ED,B8 |
Ugyanaz, mint az LDD, de a lépések automatikusan addig ismétlődnek, amíg a (BC) = 0 feltétel nem teljesül. A P/V jelzőbit értéke 0!
4.4.3. A felcserélési utasítások
Ezek az utasítások bizonyos regiszterek, illetve regisztercsoportok tartalmát cserélik fel. A jelzőbitekre nincs hatásuk. A csoporthoz összesen hat utasítás tartozik.
EX DE,HL |
235 |
EB |
Az utasítás hatására a DE regiszterpár tartalma felcserélődik a HL regiszterpáréval.
EXX |
217 |
D9 |
Az utasítás hatására a BC, a DE és a HL regiszterpárok értékei felcserélődnek a megfelelő BC', DE', valamint HL' regiszterpárokéival. Mondhatnánk persze azt is, hogy az utasítás következtében a vesszős, nem aktív regiszterek aktivizálódnak (saját tartalommal), vesszőtlenné válnak, ugyanakkor az eddig aktívregiszterek vesszős (tartalék) állományba kerülnek (saját korábbi tartalommal). A hardver szempontjából nyilván nem ugyanaz a két dolog, de programozási oldalról e két megfogalmazás - végül is - ugyanazt jelenti.
EX AF,AF' |
8 |
08 |
Ugyanaz, mint az EXX, de az AF és az AF' regiszterpárok között.
EX (SP),HL |
227 |
E3 |
Az utasítás hatására felcserélődik a HL regiszterpár és az SP regiszterrel megadott cím (2 bájt) tartalma. Az alacsonyabb bájt tartalma L-lel, a magasabb bájt tartalma pedig H-val vált.
EX (SP),IX |
221,227 |
DD,E3 |
Ugyanaz, mint az előző, de a HL helyett IX szerepel.
EX (SP),IY |
253,227 |
FD,E3 |
A HL helyett IY is szerepelhet.
4.4.4. Az aritmetikai és a logikai műveletek
Ebbe a csoportba 140 darab, jellegét tekintve meglehetősen eltérő utasítás tartozik. Éppen ezért - a jobb áttekinthetőség kedvéért - további csoportfelbontást hajtunk végre.
16 bites regiszternövelő, illetve -csökkentő utasítások
Ebbe a csoportba 12 utasítás tartozik, amelyek a BC, a DE és a HL regiszterpárokra, valamint az SP, az IX és az IY regiszterekre vonatkoznak. Ezek az utasítások nem érintik a jelzőbiteket!
INC DE |
19 |
13 |
Az utasítás hatására a DE regiszterpár tartalma 1-gyel nő.
DEC SP |
59 |
3B |
Az utasítás hatására az SP regiszter tartalma 1-gyel csökken.
16 bites összeadási és kivonási utasítások
Ez a csoport 20 műveletet tartalmaz, amelyek közül 12 egyszerű összeadásra, 4 átviteles összeadásra, 4 pedig átviteles kivonásra vonatkozik. E részcsoportra általánosságban igaz, hogy a H jelzőbit értéke nincs meghatározva, az N pedig 0, ha összeadásról, 1, ha kivonásról van szó. Az egyszerű összeadási utasítások az S, a Z és a P/V jelzőbiteket nem érintik, a C értéke pedig az eredménytől függ.
ADD HL, BC |
9 |
09 |
Az utasítás hatására a BC és a HL regiszterpárok tartalma összeadódik, az eredmény a HL-ben jelenik meg.
ADD IX,IX |
221,41 |
DD,29 |
Az utasítás hatására az IX regisztertartalma megduplázódik.
ADD IY,BC |
253,9 |
FD,9 |
Az utasítás hatására az IY regiszter és a BC regiszterpár tartalma összeadódik, és az eredmény az IY-ban jelenik meg.
Az átviteles összeadás és kivonás esetén mindig a HL regiszterpár a főszereplő. Ugyanis minden esetben a HL regiszterpár tartalmához adjuk hozzá (vagy vonjuk le belőle) valamelyik másik regiszterpár vagy az SP regiszter tartalmát. Ezek az utasítások még annyiban is különböznek az egyszerű összeadástól, hogy az átviteli jelzőbit tartalma is hozzáadódik a HL regiszterpár értékéhez (illetve kivonódik belőle). Az S, a Z és a P/V (most V) jelzőbitek értékei is az eredménytől függnek.
ADC HL,DE |
237,90 |
ED,5A |
Az utasítás hatására a HL regiszterpár értéke DE-vel és a C jelzőbittel nő.
SBC HL,HL |
237,98 |
ED,62 |
Az utasítás hatására HL-ben 0 vagy 65535 lesz aszerint, hogy a C jelzőbit 0 vagy 1 volt. 16 bites logikai utasítás nem lévén, áttekintettük valamennyi 16 bites műveletet.
Növelő és csökkentő utasítások
20 ilyen utasítás van. Ezek az utasítások nem csupán a regiszterek tartalmát növelik vagy csökkentik 1-gyel, hanem a HL, az IX és az IY által meghatározott címen lévő rekeszekre is vonatkoznak. Hatásuk az átviteli jelzőbit kivételével valamennyi jelzőbitet érinti. P/V esetén a V van értelmezve., N pedig 0 vagy 1 aszerint, hogy növelés vagy csökkentés történik.
INC (IX+44) |
221,52,44 |
DD,34,2C |
Az utasítás hatására az IX regiszterben megadott számnál 44-gyel nagyobb címen lévő memóriarekesz tartalma 1-gyel nő.
DEC B |
5 |
05 |
Az utasítás hatására a B regiszter tartalma 1-gyel csökken.
8 bites összeadási és kivonási utasítások
44 ilyen utasítás van, mégpedig 11 egyszerű összeadási, 11 egyszerű kivonási, 11 átviteles összeadási és 11 átviteles kivonási. Valamennyi műveletnél az A regiszter az első operandus, ehhez adunk hozzá, illetve ebből vonunk ki, az eredmény is A-ban jelenik meg. Az átviteles összeadásnál és kivonásnál az átviteli jelzőbit is hozzáadódik, illetve levonódik A tartalmából. A műveletek eredménye valamennyi jelzőbitet befolyásolja. P/V jelzőbit esetén a V-t értelmezzük, N értelemszerűen alakul.
ADD A,B |
128 |
80 |
Az utasítás hatására az A regiszter tartalmához hozzáadódik a B regiszter tartalma.
SUB A,(HL) |
150 |
96 |
Az utasítás hatására az A regiszter tartalmából levonódik a HL regiszterpár által meghatározott címen lévő memóriarekesz tartalma.
ADC A,41 |
206,41 |
CE,29 |
Az utasítás hatására az A regiszter tartalmához hozzáadódik 41 és az átviteli flag értéke
SBC A,D |
154 |
9A |
Az utasítás hatására az A regiszter tartalmából levonódik a D regiszter tartalma és az átviteli flag értéke.
8 bites logikai műveletek
33 ilyen utasítás van. Három nagyobb csoportba sorolhatók: ÉS (AND), VAGY (OR), valamint kizáró VAGY (XOR) műveletek. A műveletek bitenként hajtódnak végre a következő séma szerint:
|
|
|
Ennek megfelelően például:
|
|
||||||||||||||||||
|
A logikai műveleteket mindig az A regiszter tartalmával, valamint az A,B,C,D,E,H,L regiszterekkel, a HL,IX és IY által meghatározott címen lévő memóriarekesz tartalmával vagy pedig egy 8 bites számmal végezzük el. Az eredmény mindig az A regiszterben jelenik meg. A logikai műveletek hatása valamennyi jelzőbitet érinti. A C és N jelzőbit mindig 0, a H mindig 1 lesz.
A P/V jelzőbitnél a P van értelmezve.
AND (HL) |
166 |
A6 |
Az utasítás hatására az A regiszter tartalma és a HL regiszterpárban megadott címen lévő memóriarekesz tartalma között végrehajtódik a logikai ÉS utasítás. Az eredmény az A-ban jelenik meg.
OR 18 |
246,18 |
F6,12 |
Az utasítás hatására az A regiszter tartalma és a 18-as szám között végrehajtódik a logikai VAGY művelet, az eredmény az A-ba kerül.
XOR A |
175 |
AF |
Az utasítás hatására az A regiszter tartalma kizáró VAGY kapcsolatba kerül saját magával, és az eredmény A-ban jelenik meg. Ez konkrétan azt jelenti, hogy A tartalma 0 lesz.
Összehasonlító utasítások
11 Ilyen utasítás van. Az utasítások hatására az A regiszter tartalma összehasonlítódik valamely más regiszter vagy memóriarekesz tartalmával, illetve egy konkrét számmal. Az összehasonlítás következtében a jelzőbitek megváltozhatnak, de az egyes regiszterek tartalma változatlan marad. Mivel az összehasonlítás - ebben a vonatkozásban - lényegében kivonás, az N jelzőbit értéke 1 lesz, az összes többit az eredmény alakulása befolyásolja. P/V-nél a V van értelmezve.
CP B |
184 |
B8 |
Az utasítás hatására összehasonlítódik az A és a B regiszter tartalma.
4.4.5. A kereső-összehasonlító utasítások
4 ilyen utasítás van, amelyek közül kettő automatikusan ismétlődik. A műveletek hatására a C jelzőbit nem változik, az N 1 lesz, a többit az eredmény alakulása befolyásolja. A Z és a P/V jelzőbitek szerepe kitüntetett. Az összehasonlítások az A regiszter és a HL regiszterpár által meghatározott című memóriarekesz között történnek, miközben a HL és a BC regiszterpárok tartalma egyesével változik (a BC-é mindig csökken). Ennek megfelelően két kitüntetett állapot van:
Az 1.-t a Z, a 2.-t a P/V jelzőbit 1 volta jelzi.
CPI |
237,161 |
ED,A1 |
Az utasítás hatására összehasonlítódik az A regiszter, valamint a HL regiszterpár által meghatározott címen lévő memóriarekesz tartalma, a HL értéke 1-gyel nő, a BC értéke pedig 1-gyel csökken.
CPIR |
237,177 |
ED,B1 |
Ugyanaz, mint a CPI, de addig ismétlődik, amíg az A =(HL) vagy a BC = 0 feltétel nem teljesül.
CPD |
237,169 |
ED,A9 |
Hasonló a CPI-hez, de azzal a különbséggel, hogy a HL tartalma nem nő, hanem csökken.
CPDR |
237,185 |
ED,B9 |
Ugyanaz, mint a CPD, de addig ismétlődik, amíg az A = (HL) vagy a BC = 0 feltétel nem teljesül.
4.4.6. A forgatási és az eltolási (shift) utasítások
Ez a csoport összesen 76 utasítást tartalmaz. Az utasítások közül négy csupán az A regisztert, kettő az A regiszter és a HL regiszterpár által megadott címen lévő memóriarekesz kapcsolatát érinti. Az összes többi (lényegében hét különböző utasítás) valamennyi regiszterre, az indexregiszterek, valamint a HL által megadott címen lévő memóriarekeszekre hat:
4 + 2 + 6 * (A, B, C, D, E, H, L, (IX), (IY), (HL)) = 76
Minden magyarázkodás helyett néhány egyszerű rajzzal jobban lehet szemléltetni a lényeget. Vezessük be ehhez a következő egyszerű jelölést: s jelentse a fenti 7-es szorzó mellett álló bármelyik regisztert, illetve memóriacímet! (E jelölést a későbbiekben is használjuk.) Az utasítások tehát a következők (lásd 7. ábra).
7. ábra
Nincs tévedés! Az RLCA nem egészen ugyanazt jelenti, mint az RLC A utasítás, ugyanis a jelzőbitekre gyakorolt hatásuk más. Valamennyi utasítás kinullázza a H és az N jelzőbiteket, a C jelzőbit értékét pedig az RLD, valamint az RRD kivételével alkalmasan beállítja. Az RLCA, RLA, RRCA és RRA utasításoknak más egyéb hatásuk már nincs is. Az összes többi utasítás viszont befolyásolja valamennyi nem említett jelzőbitet (P/V-nél a P van értelmezve).
RRA |
31 |
1F |
RR A |
203,31 |
CB,1F |
RRD |
237,103 |
ED,67 |
Ezek az utasítások az s (lásd előbbi) bármelyik (0-7) bitjére vonatkozhatnak. Az utasítások három nagyobb csoportra oszthatók. Az első csoporthoz tartozó utasítások hatására az adott bit negáltja (tehát ha a bit 0 volt, akkor 1, ha 1 volt, akkor 0) beíródik a Z jelzőbitbe. A C jelzőbit nem változik, az N 0, a H 1 lesz. A P/V és az S értéke határozatlan. A másik két csoporthoz tartozó utasítások az s adott bitjét 0-ra vagy 1-re állítják, a jelzőbiteket pedig nem befolyásolják.
BIT 4,B |
203,96 |
CB,60 |
Az utasítás hatására a Z-be beíródik a B regiszter negyedik bitjének negáltja.
SET 7,(HL) |
203,254 |
CB,FE |
Az utasítás hatására a HL címen lévő memóriarekesz hetedik bitje 1 lesz.
RES 0,(IY+128) |
203,254 |
CB,FE |
Az utasítás hatására az IY-beli számnál 128-cal nagyobb értékű címen lévő memóriarekesz nulladik bitje 0 lesz.
A számítógép alaphelyzetben az utasításokat a memóriabeli elhelyezkedés sorrendjében, a nagyobb cím felé haladva hajtja végre. Ha ettől valamilyen oknál fogva el akarunk térni, akkor az ugróutasításokat alkalmazzuk (vezérlésátadás). A vezérlésátadás
történhet.
Az ugráshoz szükséges feltételek teljesülését az F regiszter alkalmas bitjének állapota határozza meg. Ha a feltétel nem teljesül, akkor az ugrás nem valósul meg, és a program közvetlenül a végre nem hajtandó ugróutasítás után folytatódik. Feltétel nélküli utasításnál a vezérlés természetesen átadódik a kívánt helyre.
Címre ugrás esetén a címzés lehet közvetlen vagy közvetett. Az utóbbi azt jelenti, hogy a HL, az IX vagy az lY regiszter által meghatározott címre ugrunk. A relatív címre ugrás azt jelenti, hogy az ugróutasítás helyétől adott távolságban lévő címre adódik át a vezérlés. Bár ez a címzési mód nagyon logikus, nem biztos, hogy azonnal érthető, ezért egy kicsit részletesebben is foglalkozunk vele.
Tekintsük tehát a memóriának egy olyan részterületét, ahol egy ilyen relatív ugróutasítás van (8. ábra).
Az ugróutasítások a jelzőbiteket nem érintik. 8. ábra |
JP PO,32768 |
226,0,128 |
E2,00,80 |
Az utasítás hatására a 32768-as címre adódik át a vezérlés, ha a P/V jelzőbit 0.
JP (HL) |
223 |
E9 |
Az utasítás hatására a vezérlés a HL-ben lévő címre adódik át.
JR NZ,30 |
32,30 |
20,1E |
Az utasítás hatására az utasítás címéhez képest 32-vel előreugrunk, ha a Z jelzőbit 0.
DJNZ 210 |
16,210 |
10,D2 |
Az utasítás hatására a B regiszter tartalma 1-gyel csökken, és ha elérte a 0-t, több visszaugrás 44-gyel nem következik be, hanem folytatódik a program. Így például ha B tartalma kezdetben 18 volt, akkor 18-szor ismétlődik meg ez a ciklus (feltéve, hogy a ciklusban a B regiszter tartalma nem változott).
4.4.9. A szubrutinkezelő utasítások
A gépi kódú programoknak is lényeges fogása a szubrutinok használata. A dolog lényege a megvalósítás szempontjából néhány vonatkozásban eltér a BASIC nyelvben tanultaktól. Az eltéréseket később taglaljuk. Az egyszerű szubrutinhívások és a visszatérések a szubrutinból valamilyen feltétel teljesüléséhez köthetők. A feltételvizsgálatok a zérus-, az átviteli, a paritás- és az előjel jelzőbithez kapcsolódnak. Ezek az utasítások a jelzőbiteket nem változtatják meg.
CALL 16384 |
205,00,64 |
CD,00,40 |
Az utasítás hatására a 16384-es címtől kezdődő programrész szubrutinként hajtódik végre.
RET PE |
232 |
E8 |
Az utasítás hatására a szubrutin végrehajtása akkor fejeződik be, ha a P jelzőbit értéke 1 lesz. A program ekkor visszatér a szubrutin hívásának helyére.
4.4.10. A be- és kimeneti utasítások
Ezeket az utasításokat csak igen röviden tárgyaljuk. Szerepük elsősorban a számítógéphez, pontosabban a mikroprocesszorhoz kapcsolt egyéb berendezések és a mikroprocesszor közötti adatcserében van. Az egyszerűbb, gyakorlati programozás szempontjából e csoport két utasításának van nagyobb jelentősége:
IN A,(254) |
219,254 |
DB,FE |
és
OUT (254),A |
211,254 |
D3,FE |
A fenti utasításokban 254 helyett természetesen bármilyen más 0 és 255 közé eső számot írhatunk. A parancsok hatására a számmal megjelölt csatlakozókapu (port), illetve az A regiszter között adatátvitel történik. IN esetén az adat A-ba kerül, OUT esetén a csatlakozókapura. A címsín értéke mindkettőnél:
256*(A)+N
ahol N 0 és 255 közé eső szám.
Ez a két utasítás a jelzőbiteket nem befolyásolja, de az ehhez a csoporthoz tartozó utasítások többnyire hatást gyakorolnak rájuk.
4.4.11. A megszakítást (interrupt) kezelő utasítások
Ezek az utasítások egy adott program futása közben a kívülről (tehát nem a processzortól) érkező jeleket kezelik.
A megszakításnak alapvetően két típusa létezik:
A le nem tiltható megszakítást eredményező jelek általában külső eszköztől származnak. A gyakorlati programozás szempontjából ez a megszakítás kisebb jelentőségű.
A letiltható megszakítás kezelése azonban nagyon hasznosnak bizonyulhat, mert ilyen jelet maga a Spectrum elektronikája is létrehoz mikroprocesszora számára minden 20. ms-ban. Ilyenkor megy végbe a belső óra léptetése (ez a 23672-23674-es címeken található FRAMES nevű rendszerváltozó tartalmának növekedéséből figyelhető meg), valamint a billentyűzet ellenőrzése.
A letiltható megszakításnak három módja van: 0-s, 1-es és 2-es. A vezérlés minden meg szakításnál az 56-os ROM címre ugrik, ahol megtörténik a szükséges rutinok lefuttatása.
A Spectrum 0-s módban csak ténylegesen külső eszköztől érkező megszakítást fogad el. 1-es módban (bekapcsolás után automatikusan ez alakul ki) a fent már említett folyamatok játszódnak le. A gyakorlati programozó szempontjából a 2-es mód a legérdekesebb. Ekkor ugyanis a következő folyamat játszódik le: a megszakítási jelre a processzor megnézi, hogy milyen érték van a
q = 256*(I) + hardverszám
címen (a hardverszám a megszakítást adó eszköz által generált érték - a Spectrum saját megszakítása esetén ez az érték 255 -, az (I) pedig az I regiszterben őrzött érték), elugrik a q, valamint a q+1 címeken talált értékek által megadott
(q)+256*(q+1)
címre, és onnan folytatja a program végrehajtását.
Ha például az I regiszter tartalma 140, akkor saját megszakítás esetén
q = 256*140+255 = 36095
a kritikus cím. Tegyük fel, hogy a 36095-ös cím tartalma 110, a 36096-osé pedig 200. Ekkor az ugrási cím:
110+(256*200) = 51310
A program további végrehajtása tehát ettől a címtől indul.
A 16 k-s Spectrum tulajdonosainak életét kissé megkeserítheti az a korlátozás, hogy az I regiszterbe, amely bekapcsolás után 63-at tartalmaz, a képernyő megzavarása nélkül 64 ás 127 közötti számok nem tölthetők be. Így a címadás szempontjából a 16 k-s Spectrum teljes RAM tartománya tilos terület. Ezt a problémát úgy lehet megkerülni, hogy a megszakítással ROM memóriarészt jelölünk ki, ahonnan már megfelelő cím vehető.
A megszakítással kapcsolatos utasítások a jelzőbiteket nem érintik.
EI |
251 |
FB |
Az utasítás lehetővé teszi a megszakítást.
DI |
243 |
F3 |
Az utasítás letiltja a megszakítójel fogadását.
IM 0 |
237,70 |
ED,46 |
utasítás a processzort a 0-s megszakítási módba helyezi.
IM 1 |
237,86 |
ED,56 |
Az utasítás a processzort az 1-es megszakítási módba helyezi.
Ebbe a csoportba sorolhatók még az
RST p
alakú utasítások is, ahol p 0, 8, 16, 24, 32, 40, 48 vagy 56 lehet. Ezek az utasítások a számítógép valamelyik funkcióját aktivizálják. Ilyen fontos funkció például az inicializálás (a bekapcsolás utáni állapot elérése), amely a p = 0-hoz tartozik, valamint a billentyűzet és a belső óra kezelése, amelynél a p értéke 56.
Az eddigi felsorolásokból kimaradt hét utasítás, amelyeknek különféle - elsősorban a processzorra vonatkozó - hatásuk van.
NOP |
0 |
00 |
Ez az ún. üres utasítás. Hatására nem történik semmi.
HALT |
118 |
76 |
Az utasítás hatására a processzor egy belső periódus idejére megáll. A jelzőbitek nem változnak meg.
SCF |
55 |
37 |
Az utasítás hatására a C jelzőbit 1, az N és a H 0 lesz.
IM2 |
237,94 |
ED,5E |
Az utasítás a processzort a 2-es megszakítási módba helyezi.
RETI |
237,77 |
ED,4D |
Az utasítás hatására a gép a megszakítással kezdett program végrehajtását befejezi, és visszatér abba a programrészbe, ahonnan kiugrott.
RETN |
237,69 |
ED,45 |
Ugyanaz, mint a RETI, de a gép a le nem tiltható megszakításból tér vissza.
CCF |
63 |
3F |
Az utasítás hatására a C jelzőbit komplementálódik (ha 1 volt 0 lesz, ha 0 volt, akkor 1), az N jelzőbit 0 lesz, a H jelzőbit határozatlan, az összes többi változatlan marad.
CPL |
47 |
2F |
Az utasítás hatására az A-ba bitenként vett komplementre kerül. Az N és a H jelzőbit értéke 1 lesz, a többi változatian marad.
NEG |
237,68 |
ED,44 |
Az utasítás hatására A-ba (0-A) kerül. A parancs valamennyi jelzőbitet érinti, N-be 1 kerül, P/V-nél V-t értelmezzük.
DAA |
39 |
27 |
Az utasítás hatására az A regiszter BCD-korrekciót szenved. N kivételével valamennyi jelzőbit megváltozhat, P/V-nél P van értelmezve.
Ez utóbbi utasítás jobb megértéséhez néhány fogalmat tisztáznunk kell. Mindenekelőtt azt, hogy mit is jelent a BCD. Angol eredete betűszó (Binary Coded Decimal), jelentése binárisan kódolt tízes alapú szám. Eszerint 4 biten (amely egyébként 2^4, azaz 16 különböző értéke szám leírására elegendő) csak 10 számot rögzítünk: 0-tól 9-ig. Például a 9 = 1001, az 5 = 0101 stb. Természetesen bőven akad olyan bináris szám, amelynek nincs valódi BCD-beli megfelelője. Például mennyi az 1100? Az utóbbi körülmény oda vezet, hogy az eredetileg szabályos BCD kódú számok között végzett műveletek során olyan eredményre jutunk, amelynek nincs megfelelő BCD kódja.
A Z80 egy 8 bites regiszterében tárolt szám - bizonyos körülmények között - két helyértékes BCD-számnak tekinthető. Mindebből viszont arra következtethetünk, hogy az ilyen számok között végzett műveletekkel néha baj lehet. Például:
Bináris |
Decimális |
BCD |
|||||||||
|
|
|
Az eredmény binárisan és decimálisan helyes, de BCD-ben nem! A végeredményül kapott bináris számnak nincs BCD-megfelelője! Ha azonban a bináris végeredményhez hozzáadunk 6-ot (0110), akkor helyes BCD-eredményre jutunk:
01111011 |
|
0110 |
|
10000001 |
81 |
Vigyázati A 0110 szám nem ún. "zűrfaktor" (olyan szám, amelyet a mindenkori végeredményhez adva megkapjuk a helyes végeredményt), hanem olyan szám, amelyet minden esetben hozzá kell adni a bináris végeredményhez, ha az meghaladja a 9-et.
8 bites regiszterekben gondolkodva ez a korrekciós szám 60, illetve 66 is lehet az eredmény alakulásától függően:
Bináris |
Decimális |
BCD |
|||||||||
|
|
|
Ebben az esetben a szükséges korrekció 60, tehát:
10100101 |
||
01100000 |
||
00000101 |
(C=1!) |
5 (+100!) |
Ezt a példákban bemutatott korrekciót végzi el a DAA utasítás.
4.4.13. Az assembler utasítások
Az itt sorra kerülő fogalmak nem tartoznak szorosan a gépi kódú programozáshoz, de számos assembler fordító ismeri ezeket az utasításokat, lehetőségeket. Használatuk nagyban megkönnyíti a programírást.
Címke. Nem utasítás, hanem lehetőség. Használata bármely programsor egyszerű azonosítását teszi lehetővé. Általában betűvel kezdődő, korlátozott hosszúságú karakterkombináció. Segítségével például elkerülhető a relatív ugrások távolságának - kellemesnek egyáltalán nem mondható - meghatározása. Használatát a következő egyszerű példával szemléltetjük
C020 0640 C022 1EFF C024 211806 C027 19 C028 38FD C02A 10F8 C02C C9 |
1 2 3 START 4 JUMP 5 6 7 |
LD B,64 LD E,65535 LD HL,1560 ADD HL,DE JR C,JUMP DJNZ START RET |
Mi is történik, amikor a fenti kis késleltető szubrutin fut? A betöltési utasítások végrehajtása után a HL tartalmához hozzáadódik a DE. A HL-ben 1559 lesz, és a C jelzőbit 1-re vált. Ekkor a JRC, JUMP utasítás következtében visszaugrunk az összeadáshoz. (Címkehasználatnál nem kell kiszámítanunk a relatív ugrás távolságát, mint a közvetlen gépi kódú felírásnál.) Ez a visszaugrálgatás utoljára akkor következik be, amikor a HL-be 0 kerül, mert a kővetkező összeadás nem billenti 1-re a C-t, a program tehát folytatódik. A következő utasítás 1-gyel csökkenti a B-t, és visszaugrunk a program elejére, ha B<>0. HL-be újra beíródik a kezdőérték, és a folyamat megismétlődik. Ez a külső hurok addig "ketyeg", amíg a B végre 0 nem lesz. Ekkor továbblépünk, és a RET utasítás hatására a program visszatér a hívás helyére.
ORG. Ez már parancs. Teljes alakja például: ORG 40000. Arra való, hogy az assembly nyelven megírt programot az ORG-ban megadott címtől kezdve helyezze e/ a fordítóprogram. Lényegében ekkor kapnak értéket a címkék. Maga a kifejezés az angol origin (kezdet) szó rövidítése.
EQU. Olyan utasítás, amellyel a címkének értéket adhatunk. A kifejezés az angol equate (egyenlővé tesz) szóból származik. Használatával például lehetővé válik, hogy egy adott címke konstansként szerepeljen a programban. Ezeket az utasításokat általában a program elején helyezzük el.
DEFL. Olyan utasítás, amellyel a címkének értéket adhatunk. Az EQU utasítással ellentétben a címke minden új meghatározása az előző érték elvesztését vonja maga után (a program során akár többször is).
END. Olyan utasítás, amely a fordítóprogramnak a fordítandó rész végét jelzi.
DEFB. Olyan utasítás, amely egyetlen adatbájtot határoz meg, így értékének 0 és 255 közé kell kerülnie.
DEFW. Olyan utasítás, amely egy kettős adatbájt (szó) meghatározására való. Értéke ennek megfelelően 0 és 65535 közé esik. A memóriában a kettős adatbájt a 280-as processzor kívánalmainak megfelelően helyezkedik el, tehát előbb a kevésbé meghatározó (I), utána a meghatározó (h) bájt, amelyekkel a kívánt érték az
I+(256*h)
összefüggés alapján határozható meg.
DEFM. Olyan utasítás, amellyel - általában korlátozott hosszúságú - karakterlánc (szöveg) határozható meg. A definiálandó szöveg az utasítás után általában idézőjelben szerepel. A memóriába természetesen az egyes karaktereknek megfelelő kód kerül.
DEFS. Olyan utasítás, amellyel adott számú üres (0) értékű adatbájt határozható meg. Általában megfelelő méretű adattároló-tartomány lefoglalására használják.
Léteznek olyan assembler fordítók is, amelyek a feltételes utasításokat is ismerik, sőt ún. makrókat is meg lehet bennük határozni. A feltételes utasítás azt jelenti, hogy az adott rész gépi kódra fordítása csak bizonyos feltétel teljesülése esetén valósul meg. A makró lényegében egy megfelelő címkével ellátott programírási szubrutin, amelyre a címkéje segítségével mint assembler parancsra lehet hivatkozni. Ilyenkor a címke helyére a teljes szubrutin lefordítódik.
Eddig áttekintettük a gépi kódú utasításokat. Oldjunk meg néhány feladatot, hogy némi jártasságot szerezzünk a programírásban! A megoldások természetesen csak az adott feladatok lehetséges megoldásai, hiszen csaknem valamennyi probléma sokfelől megközelíthető. A feladatokat assembly nyelven oldjuk meg, hat karakternél hosszabb azonosítót ne használjunk!
1. Írjunk programot, amely megszámolja, hogy az A regiszterben hány 1-es bit van! A végeredményt a C regiszterben tároljuk!
7530 7530 0E00 7532 0608 7534 1F 7535 3001 7537 0C 7538 10FA 7536 C9 |
1 2 3 4 5 6 L1 7 8 9 10 11 L2 12 13 |
ORG 30000 LD C,0 LD B,8 RRA JR NC, L2 INC C DJNZ L1 RET |
; 1. feladat megoldása ; Végeredmény majd a 'C' ; regiszterben ; 1 bájt=8 bit. ; A C jelzőbitben a ; következő bit, ; ugrás előre ha ez 0, ; ha nem, akkor 'C' 1-gyel ; nő ; Ugrás vissza, amíg a 8 ; bitet át nem mozgattuk, ; ekkor vége |
Mint látható, a magyarázatokat, megjegyzéseket pontosvesszővel választottuk el a tényleges programtól. Nagyon sok assembler fordító megengedi ezt a lehetőséget. A fordítás során a pontosvesszőtől kezdődő részt figyelmen kívül hagyja.
2. írjunk programot, amely megszámolja, hogy a 30000-től 31999-ig terjedő memóriarészen hány A karakternek megfelelő ASCII kód van! A címeket a DE és a HL regiszterpárok tartalmazzák, a HL-ben legyen a nagyobb cím!
7530 7530 225075 7533 EB 7534 225275 7537 EB 7538 A7 7539 ED52 753B E5 753C C1 753D 03 753E 2A5275 7541 110000 7544 3E41 7546 EDA1 7548 2001 754A 13 754B 78 754C B1 754D 20F5 754F C9 7550 7552 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 L1 20 21 22 23 24 25 26 27 28 L2 29 30 31 32 33 34 S1 35 S2 |
ORG 30000 LD (S1),HL EX DE,HL LD (S2),HL EX DE,HL AND A SBC HL,DE PUSH HL POP BC INC BC LD HL,(S2) LD DE,0 LD A,65 CPI JR NZ,L2 INC DE LD A,B OR C JR NZ,L1 RET DEFS 2 DEFS 2 |
; 2. feladat megoldása ; Tároljuk a magasabb ; címet ; Tároljuk az alacso- ; nyabbikat is. ; Visszaállítjuk az ; eredeti helyzetet és ; töröljük a C ; jelzőbitet. ; Előállítjuk és ; a BC-be helyezzük a ; vizsgálandó hosszat. ; DE tartalmazza majd a ; darabszámot. ; 'A' regiszterben "A" ; ASCII kódja. ; összehasonlítjuk a ; HL-beli cím tartalmát ; 'A'-val. ; Ugrás előre, ha nem ; egyeznek, ; ha igen, akkor DE ; 1-gyel nő. ; A folyamat végére ; értünk-e? ; Ha nem, akkor ugrás ; vissza, ha igen, akkor vége! |
3. Egészítsük ki az előző programot úgy, hogy minden megtalált A karakter helyébe a B karakternek megfelelő ASCII kódot tegye!
7530 7530 225075 7533 EB 7534 225275 7537 EB 7538 A7 7539 ED52 753B E5 753C C1 753D 03 753E 2A5275 7541 110000 7544 3E41 7546 EDA1 7548 2001 754A 13 754B 78 754C 34 754D 23 754E 78 754F B1 7550 20F2 7552 C9 7553 7555 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 L1 20 21 22 23 24 25 26 27 28 29 30 31 32 33 L2 34 35 36 37 38 39 S1 40 S2 |
ORG 30000 LD (S1),HL EX DE,HL LD (S2),HL EX DE,HL AND A SBC HL,DE PUSH HL POP BC INC BC LD HL,(S2) LD DE,0 LD A,65 CPI JR NZ,L2 INC DE DEC HL INC (HL) INC HL LD A,B OR C JR NZ,L1 RET DEFS 2 DEFS 2 |
; 3. feladat megoldása ; Tároljuk a magasabb ; címet ; Tároljuk az alacso- ; nyabbikat is. ; Visszaállítjuk az ; eredeti helyzetet és ; töröljük a C ; jelzőbitet. ; Előállítjuk és ; a BC-be helyezzük a ; vizsgálandó hosszat. ; DE tartalmazza majd a ; darabszámot. ; 'A' regiszterben "A" ; ASCII kódja. ; összehasonlítjuk a ; HL-beli cím tartalmát ; 'A'-val. ; Ugrás előre, ha nem ; egyeznek, ; ha igen, akkor DE ; 1-gyel nő. ; 1-gyel túlszaladtunk ; már a kritikus ponton ; Beállítjuk a kívánt ; kódot. ; Visszaállítjuk HL-t. ; A folyamat végére ; értünk-e? ; Ha nem, akkor ugrás ; vissza, ha igen, ; akkor vége! |
4. Írjunk programot, amely bármely két egy bájtos számot összeszoroz! A két szám legyen a B és a C regiszterben! A megoldás áttekinthetősége kedvéért végezzünk el egy ilyen szorzást kézzel a kettes számrendszerben! A két szám legyen például 63 és 27.
63 = 00111111
27 = 00011011
00111111 |
* 00011011 |
00111111 00111111 00111111 00111111 |
|
011010100101 |
Látható, hogy a szorzás egyszerűen elvégezhető, ha az első számot balra tologatjuk, majd összeadunk.
7530 7530 210000 7533 1600 7535 58 7536 0608 7538 CB39 753A 3001 753C 19 753D CB22 753F CB23 7541 3002 7543 CBC2 7545 10F6 7547 C9 |
1 2 3 4 5 6 7 8 9 10 11 12 13 L1 14 15 16 17 18 19 L2 20 21 |
ORG 30000 LD HL,0 LD D,0 LD E,B LD B,8 SRL C JR NC,L1 ADD HL,DE SLA D SLA E JR NC,L2 SET 0,D DJNZ L1 RET |
; 4. feladat megoldása ; HL-ben lesz a ; végeredmény. ; DE lesz az alkalmi ; összeadó. ; 8 bites a szám. ; össze kell-e adni? ; Ha nem, ugrás előre, ; ha igen, ; akkor tegyük! ; DE balra mozog, ; de vigyázat(!), a ; mozgás során ; 'E' 7. bitje , 'D' 0. bitje lesz. ; Ha nincs meg mind a ; 8 tolás, akkor vissza, ; egyébként vége! |
5. Írjunk programot, amely bármely két egybájtos szám hányadosát képezi és a maradékot is rögzíti! Az osztandó legyen a B regiszterben, az osztó pedig a C-ben!
Az osztásnál csak azt kell szem előtt tartani, hogy nem más, mint ismételt kivonás.
7530 7530 79 7531 FE00 7533 28FE 7535 78 7536 1600 7538 91 7539 3803 753B 14 753C 18FA 753E 81 753F C9 |
1 2 3 4 5 6 7 8 9 10 11 12 L1 13 14 15 16 17 18 19 L2 20 21 |
ORG 30000 LS A,C CP 0 JR Z,BAJ LD A,B LD D,0 SUB C JR C,L2 INC D JR L1 ADD A,C RET |
; 5. feladat megoldása ; Kizárjuk a 0-val ; történő osztást. ; A "BAJ" címkétől ; kezdődően helyezendő ; el a hibakezelési ; rutin!!! ; 'D'-ben lesz a ; hányados. ; Ha az osztás végére ; értünk, akkor ugrás ; előre, ; ha nem, akkor 'D' ; 1-gyel nő. ; Ugrás vissza. ; Visszaállítjuk a ; maradékot. ; Vége! |
A program első három sora igen fontos rész, hiszen az értékeket nem láthatjuk előre, és a zavaró számok ellen védekezni kell. Az első három sor nélkül (C) = 0 esetén a gép végtelen ciklusba esne.
A példák jól szemléltetik, hogy a gépi kódú programozás nem sokkal bonyolultabb, mint a BASIC nyelvű. Három tanácsot azért adunk az önálló gépi kódú programozáshoz:
4.5. A ROM rutinok, a RAM és a perifériák
A Spectrumhoz mellékelt gépkönyvből sokat megtudhatunk. Mi csak az ottani ismereteken túlmutató, elsősorban programozási szempontból hasznos információkat kívánunk nyújtani. A tárgyalás során számos gépi kódú rutint mutatunk be. Ezeket az USR függvénnyel lehet a BASIC-ből indítani, alapvetően háromféle módon:
Mindhárom esetben az xxxx címtől kezdődő rutin aktivizálódik, de a visszatérés más lesz. Az elsőnél a 23670-es és a 23671-es címeken található rendszerváltozóba beíródik a C, illetve a B regiszterek tartalma, a másodiknál a képernyőn megjelenik a BC tartalma (C) + 256*(B) formában, a harmadiknál az A változó felveszi az iménti értéket.
A következő nagyon fontos kérdés: hol helyezzük el gépi kódban megírt programjainkat? Egészen enyhe túlzással azt mondhatnánk, hogy a RAM területén bárhol. Mégis - elsősorban a kezdőknek, a bonyodalmak elkerülése végett - azt tanácsoljuk, hogy a következő három lehetőség közül válasszanak:
A nyomtató puffer a 23296-os címtől kezdődő 256 bájt hosszúságú terület. Nagyon kényelmesen használható, semmiről sem kell külön gondoskodni. Hátránya viszont az erősen korlátozott hossza, továbbá, hogy a ZX nyomtató használata esetén felülíródhat.
A második lehetőség előnye, hogy itt már hosszabb programok is elhelyezhetők, valamint hogy magnetofonon való rögzítéskor a BASIC-kel együtt felvevődik. Hátránya viszont a pontos címmeghatározás nehézkessége.
Ha a BASIC programot egy REM utasítással kezdjük, címmeghatározási gondjaink jelentősen csökkennek. Legyen az első BASIC sor a következő:
10 REM ..........
A REM mögött legalább annyi karaktert kell elhelyeznünk, ahány bájtból áll a gépi kódú program. A sorszám közömbös, nem az a lényeg, hogy 10 legyen, hanem az, hogy ez legyen az első sor. Ezek után a REM mögötti első pozíció címét a
PEEK 23635 + 256*PEEK 23636 + 5
összefüggés adja. A 23635-ös és a 23636-os címen a PROG nevű rendszerváltozó található, amely a BASIC tartomány kezdőcímét adja meg.
Ha a Spectrumhoz nem kapcsolódik Interface 1 (microdrive), helyzetünk még egyszerűbb, mert a fenti kifejezés értéke ekkor általában 23760.
Bármely REM-mel kezdődő sor REM mögötti első karakterének címét úgy tudjuk meghatározni, hogy közvetlenül a sor elé - megfelelő sorszámmal ellátva - begépeljük az
xx PRINT PEEK 23637 + 256*PEEK 23638 - 47: STOP
sort. Ezt indítva (RUN xx), a képernyőn megjelenik a cím. Az újonnan beírt sort törölve már minden rendben van.
Ezt a műveletet azért lehet végrehajtani, mert a 23637-es és a 23638-as címen lévő NXTLIN nevű rendszerváltozó a program futása során a mindenkori következő BASIC sor memóriabeli címét tartalmazza. Ennek megfelelően, ha alkalmas sorszámmal ellátva bármely sor mögé begépeljük az
xx PRINT PEEK 23637 + 256*PEEK 23638 - 23810: STOP
sort, majd elindítjuk, a képernyőn megjelenik az addigi BASIC program hossza (fenti sorunkat természetesen nem beleértve).
Ha a készülékhez microdrive is kapcsolódik, akkor a fenti kifejezésben 23810 helyett
PEEK 23635 + 256*PEEK 23636 + 55
szerepel.
A harmadik lehetőség sok szempontból a legjobb. Mindössze a RAMTOP megfelelő beállításáról kell gondoskodni. Ezt az egyszerű CLEAR nnnn paranccsal oldhatjuk meg. Emlékeztetünk rá, hogy ilyenkor a változóterület törlődik. Ezt sajnos egyszerű módon nem lehet elkerülni. Ha valaki mégis azt gondolná, hogy ez lehetséges - hiszen a 23730-as és a 23731-es címen van a RAMTOP nevű rendszerváltozó, és alkalmas POKE utasítással a benne lévő érték átírható -, ki kell ábrándítanunk, mert a RAMTOP ilyenkor ténylegesen még nem helyeződik át, csak egy NEW parancs után. Ott vagyunk, ahol a part szakad...
Megfelelő assembler fordító híján gépi kódú rutinjainkat a BASIC segítségével gyárthatjuk. Vagy úgy, hogy a kódokat DATA-ban helyezzük el, vagy pedig úgy, hogy INPUT-on keresztül visszük be. (Lehetséges volna - bizonyos korlátozással - karakterváltozóba vagy közvetlenül egy REM mögé is írni, de ezeket az utakat igen körülményes voltuk miatt nem javasoljuk.)
A decimális kódokat POKE utasítással közvetlenül a megfelelő címre küldhetjük. Hexadecimális kódok használata esetén alkalmas átalakító programot kell írnunk.
Az alábbiakban egy egyszerű átkódoló programot mutatunk be. Feltételezzük, hogy a hexadecimális kód már megfelelő formátumú, azaz két karakter hosszúságú, és a számokon kívül csak az A,B,C,D,E, valamint az F karaktereket tartalmazza. (Egyebekben ezt az ellenőrzést el kell végezni!) Az átalakító rutinba való belépéskor a hexadecimális kódot az a$ tartalmazza, kilépéskor a megfelelő decimálisat az a változó.
100 LET a$(1) = CHR$ (CODE a$(1) -7*(CODE a$(1)> 57))
200 LET a$(2) = CHR$ (CODE a$(2) - 7*(CODE a$(2) > 57))
300 LET a = 16*CODE a$(1) + CODE a$(2) - 816
Ha az a, b, c, d, e és f karaktereket használjuk, akkor a fenti programban a 7-es szorzó helyett 39-es szorzót kell alkalmaznunk.
A bevezetés lezárásaként a Spectrumon való gépi kódú rutinok futtatásával kapcsolatban szeretnénk felhívni a figyelmet néhány nagyon fontos körülményre. BASIC program futásakor az IY indexregiszter 23610-et, az I regiszter pedig 63-at tartalmaz, és 1-es megszakítási módban a megszakítás nincs letiltva. Éppen ezért, ha ezeket a tényezőket - saját speciális céljaink miatt - átállítottuk, a BASIC-be való visszatérés előtt feltétlenül vissza kell állítani!
Végül megjegyezzük, hogy a ROM-ban nincs microdrive-val foglalkozó rutin.
Mint ismeretes, a képernyővel kapcsolatos RAM terület a 16384-es címtől a 23295-ös címig terjed. Ebből az első, 6144 bájt hosszúságú rész (16384-től 22527-ig) a megjelenő rajzolatot tartalmazza, míg a második, 768 bájt hosszúságú (22528-tól 23295-ig) a színt és a villogási állapotot. A képernyő 32*24 = 768 (egyszerűbb esetben 32x22) karaktermezőre bomlik. Minden karaktermezőhöz 8 bájt tartozik. Egy karaktermező tehát 8x8 bitből áll. Egy karaktermezőben azok a pontok (angolul: pixel) tinta színűek, amelyekhez 1-es értékű bitek tartoznak. Így például, ha 8 bájt tartalma 1,2,4,8,16,32,64 és 128, akkor egy 45 fokos egyenes szakaszt kapunk:
X | |||||||
X | |||||||
X | |||||||
X | |||||||
X | |||||||
X | |||||||
X | |||||||
X |
A képernyő színállapotát meghatározó ún. attributum és a karakterpozíciók között nagyon egyszerű összefüggés állítható fel. A szokásos jelölés esetén (a képernyő bal felső karakterének pozícióját a (0,0) számpár, jobb alsó karakterének pozícióját pedig a (23,31) számpár jellemzi) a memóriacím és a karakterpozíció közötti összefüggés a következő:
cím = 22528 + 32*i + j
ahol i a sorszám, j pedig az oszlopszám.
Távolról sem ilyen egyszerű az összefüggés a rajzolatot tartalmazó rész esetében. Először is: ebben a vonatkozásban a képernyő három 8 karakter magasságú sávra bontható. Az egyes sávok tehát egy-egy 2048 bájt hosszúságú memóriarészen, egy-egy blokkban találhatók. A blokkok a címzés szempontjából hasonlóan viselkednek. Az egyes blokkok kezdőcímei:
16384 | 0 - 7 sor |
18432 | 8 - 15 sor |
20480 | 16 - 23 sor |
Egy blokkban 8*32 = 256 karakterpozíció van. A memóriában egymás után következő címek az egymás után következő karakterek azonos sorának felelnek meg, feltéve, hogy elölről kezdtük a számolást. (Emlékeztetőül: 1 karakter 8 sorból - bájt -, egy sor 8 pontból - bit - áil. Így tehát ugyanahhoz a karakterhez a 256 címnyi távolságra lévő memóriacím tartozik.)
Példaképpen határozzuk meg a 13-as sor 13-as karakterének memóriacímeit. A 13-as sor a .középső blokkban található, tehát felső sorának címe:
cím = 18432 + 32*(13 - 8) + 13 = 18605
Következő sorának címe 256-tal nagyobb, tehát 18861 stb.
Ezt a meglehetősen körülményes számolást egy egyszerű gépi kódú rutinnal el lehet végeztetni. Ezt a rutint közvetlenül a megfelelő BASIC programban helyezzük el. A gépi kódú programba való belépéskor az A regiszterbe betöltjük a karaktert alkotó sorok számát (0-7, a felső a 0), a B regiszterbe a sorszámot (0-23), a C regiszterbe pedig az oszlopszámot (0-31). Visszatéréskor a BC regiszterpár tartalmazza majd a megfelelő memóriacímet.
7530 7530 3E00 7532 0600 7534 0E00 7536 F5 7537 78 7538 E618 753A C640 753C 67 753D F1 753E 84 753F 67 7540 78 7541 E607 7543 0F 7544 0F 7545 0F 7546 81 7547 6F 7548 E5 7549 C1 754A C9 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
ORG 30000 LD A,0 LD B,0 LD C,0 PUSH AF LD A,B AND 24 AND A,64 LD H,A POP AF ADD A,H LD H,A LD A,B AND 7 RRCA RRCA RRCA ADD A,C LD L,A PUSH HL POP BC RET |
; A képernyő RAM címeit ; meghatározó rutin. ; Belépési paraméterek: ; 'A'-ba larakteren belüli ; sorszám (Ks: 0-7; ; a felső a "0"), ; 'B'-be a sorszám ; (S: 0-23), ; 'C' be az oszlopszám ; (O: 0-31)- ; Ks! ; B! ; O! ; Kimentjük 'A'-t. ; 'A'-ban van a sorszám. ; Sávkiválasztás. ; Képernyőkezdet ; most már a 'H'-ban. ; Karakterkorrekció. ; Blokkon belüli ; sorszám. ; szorzás 32-vel. ; Az oszlopszám ; betöltve. ; Eredmény a BC-ben. ; Vége! |
A gépi kódú rész összesen 27 bájtból áll, ezért a BASIC program első sorában a REM mögött legalább 27 karakternyi helyet kell fenntartani.
10 REM Ide legalabb 27 karakternyi hely kell!
20 DATA 62,0,6,0,14,0,245,120,230,24,198,64,103,241,132,103, 120,230,7,15,15,15,129,111,229,193,201
30 LET l=PEEK 23635+256*PEEK 23636+5
40 FOR i=1 TO l+26: READ a: POKE i,a: NEXT i
50 LET CONT=7: LET H=0: INPUT "Karaktersor ";a
60 LET g=a: GO SUB 180: IF H=1 THEN GO TO 50
70 LET CONT=23: LET H=0: INPUT "Sor ";s
80 LET g=s: GO SUB 180: IF H=1 THEN GO TO 70
90 LET CONT=31: LET H=0: INPUT "Oszlop ";o
100 LET g=o: GO SUB 180: IF H=1 THEN GO TO 90
110 POKE l+1,a: POKE l+3,s: POKE l+5,o
120 PRINT "Karaktersor: ";a
130 PRINT "Sor: ";s
140 PRINT "Oszlop: ";o
150 PRINT "Memoriacim: ";USR 1
160 PAUSE 0
170 CLS : GO TO 50
180 IF g<>INT g OR g<0 OR g>CONT THEN LET H=1
190 RETURN
A képernyőcímet kereső rutin - a továbbiakban nevezzük KCK rutinnak -, nagyon hasznosnak bizonyulhat számos más program szubrutinjaként.
Inverz képernyő
A feladat, s megoldása nyilván egyszerű, az eredmény pedig szó szerint látványos. Fogalmazzuk meg a célt a gép nyelvén: a képernyő memóriaterületén minden 1-es bit helyett 0 és minden 0 helyett 1-es legyen! Ezek után minden kézenfekvő:
7530 7530 210040 7533 010018 7536 7E 7537 2F 7538 77 7539 23 753A 0B 753B 78 753C B1 753D 20F7 753F C9 |
1 2 3 4 5 6 L1 7 8 9 10 11 12 13 14 15 16 17 18 |
ORG 30000 LD HL,16384 LD BC,6144 LD A,(HL) CPL LD (HL),A INC HL DEC BC LD A,B OR C JR NZ,L1 RET |
; Inverz képernyő ; HL-ben a képernyő- ; kezdőcím ; BC-ben a hossz. ; 'A'-ban a ; címtartalom ; Invertáljuk és ; visszatöltjük ; A következő címre ; lépünk. ; A képernyő végére ; értünk-e? ; Ha nem, ugrás ; vissza, ha igen; ; akkor vége! |
Ha csak a képernyő bizonyos részét kívánjuk invertálni, a KCK rutin hasznosítani lehet.
A képernyő törlése
Ez a feladat is többféle módon oldható meg. A legegyszerűbb talán - s ilyenkor az eredeti papír- és tintaszín visszaváltásáról sem kell külön gondoskodni -, ha alkalmas módon meghívjuk a megfelelő ROM rutint. Ez a rutin a 3435-ös (0D6BH) címen található. A képernyő törlésére számos más - a fentinél látványosabb - lehetőség is van. Egy ilyet mutat be a következő program.
7530 7530 1608 7532 210040 7535 010018 7538 180E 753A CBA6 753C CB96 753E CBAE 7540 CB8E 7542 CBB6 7544 CB86 7546 CB9E 7548 CBBE 754A 23 754B 0B 754C 78 754D B1 754E 20E8 7550 213975 7553 35 7554 35 7555 15 7556 20DA 7558 213975 755B 360E 755D C9 |
1 2 3 4 5 L1 6 7 8 L2 9 10 11 12 13 14 15 16 17 18 L3 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
ORG 30000 LD D,8 LD HL,16384 LD BC,6144 JR L3 RES 4,(HL) RES 2,(HL) RES 5,(HL) RES 1,(HL) RES 6,(HL) RES 0,(HL) RES 3,(HL) RES 7,(HL) INC HL DEC BC LD A,B OR C JR NZ,L2 LD HL,L2+1 DEC (HL) DEC (HL) DEC D JR NZ,L1 LD HL,L2+1 LD (HL),14 RET |
; Képernyőtörlés ; Egy pozíció 8 ; bitből áll. ; HL-ben a ; képernyő-kezdőcím ; BC-ben a hossz. ; Ugrás előre, hogy a ; megfelelő bit ; törlődjék. ; A következő címre ; lépünk. ; A hátramaradó hossz ; 1-gyel csökken. ; A kérenyő végére ; értünk-e? ; Ha nem, ugrás ; vissza, ha igen, ; akkor az előreugrás ; mértékét alkalmasan ; csökkentjük, és így ; újabb bit törlődik. ; Töröljük-e az összes ; bitet? ; Ha nem, ugrás az ; elejére, ha igen, ; akkor visszaállítjuk ; a kezdő ugrást és ; vége! |
A képernyő bizonyos részének törléséhez a KCK rutin hasznos lehet, de ha megelégszünk csak a képernyő alsó részének törlésével (a törlés a felső tíz sort általában nem érinti), akkor elegendő a 3652-es (0E44) ROM rutin alkalmas meghívása is.
A 3435-ös valamint a 3652-es címen lévő utasítások BASIC-ből is meghívhatók!
A képernyő mozgatása
A ROM maga is tartalmaz néhány ilyen rutint. Ezek azonban általános grafikai szempontokból már biztosan nem kielégítőek, de egyszerűbb célokra, főleg karakteres (alfanumerikus) kiíratásokra nagyon jól hasznosíthatók. A következő rutinok - mivel nem igényelnek külön bemenő adatokat - BASIC-ből is meghívhatók:
Ezek a rutinok nem gondoskodnak a nyomtatási pozíció átállításáról, sőt még a 3652-es címen lévő félképernyő-törlő rutin sem, következésképpen egy újabb PRINT parancsnál a gyanútlan programozót meglepetés éri: a képernyő alján megjelenik a "scroll?" kérdés. Ezen a bajon még az sem segít igazán, ha az újabb PRINT utasítás elé automatikus soremelést biztosító POKE 23692,x (x egynél nagyobb egész szám) utasítást írunk, ugyanis ekkor meg az automatikus soremelés következtében üres sor is kerül a képernyőre.
A megoldás tehát csak a nyomtatási pozíció AT utasítással való beállítása lehet. Például: a RANDOMIZE USR 3652 utasítás után PRINT AT 10,... utasítást írunk, vagy a RANDOMIZE USR 3582 egyszeres alkalmazása után PRINT AT 21,... utasítást stb., és máris folytonos a kiíratás. Megjegyezzük, hogy a RANDOMIZE USR 3330 után nincs más orvosság, mint a CLS parancs, mert különben a képernyő "megbolondul".
A fenti rutinok tehát végeredményben - megfelelő körültekintés esetén - jól használhatóak. Más hasonló jellegű képernyőt mozgató rutin a ROM-ban nincs, írjunk tehát! Erre példa a következő program, amely a képernyőpontokat egyesével balra mozgatja.
Ez az oldalra tolás még gyorsabbá tehető, ha közben letiltjuk a megszakítást, azaz a programot a DI utasítással (kódja 243) kezdjük, majd utolsó előtti utasításnak a RET elé beírjuk az EI-t (kódja 251).
Hasonló módon lehet megvalósítani bármilyen irányú mozgatást, de vigyázzunk, az attributumot csak karakterenként lehet kezelni.
7530 7530 21FF57 7533 010018 7536 37 7537 3F 7538 0620 753A CB16 753C 2B 753D 1B 753E 10FA 7540 7A 7541 B3 7542 20F2 7544 C9 |
1 2 3 4 5 6 7 8 L1 9 10 11 12 L2 13 14 15 16 17 18 19 20 21 22 23 |
ORG 30000 LD HL,22527 LD BC,6144 SCF CCF LD B,32 RL (HL) DEC HL DEC DE DJNZ L2 LD A,D OR E JR NZ,L1 RET |
; A képernyőt képpontonként ; egyesével balra ; mozgató rutin. ; HL-ben a képernyő ; utolsó címe. ; BC-ben a hossz. ; Balra toláskor a kép ; jobb szélére mindíg ; papírszín kerül. ; 1 sor = 32 karakter. ; Balra mozog a sor, ; miközben a megfelelő ; számlálók lépésenként ; csökkennek. ; Ha még nem értünk a ; sor végére, akkor ; vissza. ; A képernyő elejére ; értünk-e? ; Ha nem, akkor új sor ; nyitás, ha igen, ; akkor vége! |
A szín beállítása
Mindenekelőtt emlékeztetnünk kell arra, hogy a Spectrumon a színbeállítás (papír, tinta, fényesség, villogás) alapvetően kétféle lehet:
- állandó vagy
- időszakos.
Az utóbbi azt jelenti, hogy a színparancs csak egy adott utasítás vagy egy rövidebb utasításcsoport erejéig van érvényben. Kezelésére majd később visszatérünk. Számunkra sokkal fontosabb most az állandó színparancs megvalósítása.
A processzor a perifériákat - ezekhez nemcsak a külső eszközök, hanem a billentyűzet, a képernyő stb. is hozzátartozik - az ún. csatornákon keresztül éri el. így például, ha a képernyőt valamilyen módon meg akarjuk változtatni, meg kell nyitnunk a megfelelő csatornát. Ez természetesen akkor a legegyszerűbb, ha aktivizáljuk a megfelelő ROM rutint. Ekkor az A regiszterbe be kell tölteni a kívánt perifériára vonatkozó kódot, és meg kell hívni azt a ROM rutint, amely az 5633-as (1601H) címen található. Az A-ba töltendő értékek:
3 | - nyomtató, |
2 | - képernyő, |
1 | - billentyűzet (a képernyő alja), |
0 | - billentyűzet |
255 | - munkaterület, |
254 | - képernyő, |
253 | - billentyűzet (a képernyő alja), |
stb. |
A közvetlen színbeállításnál a 23624-es és a 23693-es címeken található rendszerváltozók igen jól felhasználhatók. Az előbbi a keret (border), az utóbbi a képernyő többi részére (attributum) vonatkozó színadatokat tartalmazza.
A következő egyszerű rutin elvégzi a színbeállítást. Belépéskor az A regiszter tartalmazza a kívánt színkódot. Elvárjuk továbbá, hogy a keret a tintával megegyező színű legyen.
7530 7530 F5 7531 328D5C 7534 3E02 7536 CD0116 7539 CD6B0D 753C F1 753D FE08 753F 3004 7541 CD9B22 7544 C9 7545 D608 7547 18F4 |
1 2 3 4 5 6 7 8 9 10 11 12 13 L2 14 15 16 17 18 L1 19 20 |
ORG 30000 PUSH AF LD (23693),A LD A,2 CALL 5633 CALL 3435 POP AF CP 8 JR NC,L1 CALL 8859 RET SUB 8 JR L2 |
; Színbeállító rutin 1 ; Kimentjük 'A'-t, és ; betöltjük ; 'ATTR P'-be. ; Megnyitjuk a ; képernyőt. ; A ROM-beli törlőrutin ; beállítja az ; attributumot. ; Visszahozzuk 'A'-t ; és ellenőrizzük, ; hogy kisebb-e 8-nál. ; Ha nem, ugrás előre, ; ha igen, akkor ; beállítjuka Border-t, ; és vége! ; 8-cal csökkentjük ; 'A'-t. ; Vissza a vizsgálathoz |
A 8859-es címen található rutin beállítja a keret színét, de fontos, hogy belépéskor az A-ban ne legyen 7-nél nagyobb szám. Az érték közvetlen betöltése a BORDCR (23624) rendszerváltozóba még hatástalan, másrészt "nem az igazi". Próbáljuk meg a következőt: POKE 23624,0 (fekete szín), majd 2 * ENTER. Lesz meglepetés! Azt "látjuk", hogy nem látunk semmit, hiába írunk le parancsot. A parancs természetesen ott van fekete papíron fekete tintával, tehát végrehajtódik.
Ha a keretet a papírral egyező színűre kívánjuk hozni, akkor a programot a következőképpen kell módosítanunk:
7530 7530 F5 7531 328D5C 7534 3E02 7536 CD0116 7539 CD6B0D 753C F1 753D e638 753F 1F 7540 1F 7541 1F 7542 CD9B22 7545 3EFE 7547 CD0116 754A CD6B0D 754D C9 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
ORG 30000 PUSH AF LD (23693),A LD A,2 CALL 5633 CALL 3435 POP AF AND 56 RRA RRA RRA CALL 8859 LD A,254 CALL 5633 CALL 3435 RET |
; Színbeállító rutin 2 ; Kimentjük 'A'-t, és ; betöltjük ; 'ATTR P'-be. ; Megnyitjuk a ; képernyőt. ; A ROM-beli törlőrutin ; beállítja az ; attributumot. ; Visszahozzuk 'A'-t. ; 'A'-ban csak a papír ; színkód marad meg, ; melyet 8-cal osztunk. ; Beállítjuk a Bordert, ; megnyitjuk a ; képernyő alját és ; meghívjuk a törlőrutint. |
A képernyő alján esetleg megjelenő két karakter széles csík a 17-es, 18-as, 19-es sorokban Tévő utasításokkal tüntethető el.
A téma lezárásaként néhány eddig még fel nem sorolt idevágó ROM rutint ismertetünk, végül bemutatunk egy rövid, de igen érdekes programot.
A képpontcím rutin a 8874-es (22AAH) címen található. Meghívása előtt gondoskodni kell arról, hogy a pont koordinátái a BC regiszterpárba kerüljenek, azaz a B tartalmazza a rövidebb oldal koordinátáját (0 <= B <= 175), a C pedig a hosszabbét (0 <= C <= 255). Visszatéréskor HL tartalmazza majd a megfelelő memóriacímet, A pedig azt, hogy ezen a címen hányadik bit a szóban forgó. Ezt a rutint egy pont megjelenítésekor is használhatjuk, de ilyenkor egyszerűbb, ha az ún. plot rutint aktivizáljuk.
A plot rutin a 8933-as (22E5H) címen található. Meghívásakor ugyanúgy kell eljárni, mint az előző esetnél. A képpont koordinátáit - az ott már említett módon - a BC regiszterpárban kell elhelyezni.
Természetesen van több lehetőség a képernyőn lévő pont eltüntetésére is. A drasztikus eljárásokon kívül általában két dolgot tehetünk. A plot rutin meghívása előtt a
SET 0,(IY+87)
utasítást adjuk, amelynek hatása megegyezik a BASIC-beli OVER 1 utasításéval, azaz ettől fogva minden kiírt pont invertálja a képernyőn találhatót. A másik lehetőség, hogy a
SET 2,(IY+87)
utasítást adjuk, amelynek hatása viszont a BASIC-beli INVERSE 1 utasításéval egyezik meg, azaz ettől fogva minden kiírt pont papír színű lesz.
A fenti hatások természetesen bármikor megszüntethetők a megfelelő RES utasítással.
Végül pedig az ígért program, de minden magyarázat nélkül, csak egy rövid használati utasítással: a rutint az elejéről kell indítani. A C, L és D regiszterekbe más értékek is betölthetők.
7530 7530 0E07 7532 2E02 7534 16FF 7536 1EFF 7538 45 7539 10FE 753B D3FE 753D 81 753E 1D 753F 20F7 7541 15 7542 20F2 7544 C9 |
1 2 3 4 5 6 L1 7 L2 8 L3 9 10 11 12 13 14 15 |
ORG 30000 LD C,7 LD L,2 LD D,255 LD E,255 LD B,L DJNZ L3 OUT (254),A ADD A,C DEC E JR NZ,L2 DEC D JR NZ,L1 RET |
; Meglepetés |
4.5.2. A karakterek megjelenítése
Ez a feladat is, mint szinte valamennyi, igen sokféleképpen oldható meg. Legegyszerűbbnek azonban a megfelelő ROM rutinok felhasználása látszik, ezért ezzel foglalkozunk.
Mint azt már az előző pontban is láttuk, mindenekelőtt meg kell nyitnunk a megfelelő csatornát; ha szükséges, törölni kell a képernyőt, s be kell állítani az állandó színeket. Vigyázat! Törlés után újra meg kell nyitni a csatornát! Általában igaz, hogy ha például a képernyőn kívül más csatornán át is dolgozunk, akkor újabb karakter kivitelekor újra meg kell nyitni ezt a csatornát.
Egyetlen vagy kevés számú karakter nyomtatásához (képernyő!) nagyon jól használható az RST 16-os rutin, amellyel valamennyi kívánt színállapot, helyzet stb. beállítható. A következő programvázlat valamennyi lehetőség kezelését bemutatja:
7530 7530 3E02 7532 CD0116 7535 CD6B0D 7538 3E02 753A CD0116 753D 3E10 753F D7 7540 3E00 7542 D7 7543 3E11 7545 D7 7546 3E07 7548 D7 7548 3E12 754A D7 754B 3E01 754D D7 754E 3E13 7550 D7 7551 3E01 7553 D7 7554 3E14 7556 D7 7557 3E01 7559 D7 755A 3E15 755C D7 755D 3E01 755F D7 7560 3E16 7562 D7 7563 3E00 7565 D7 7566 3E00 7568 D7 7569 3E2A 756B D7 756C C9 756D FDCB57D6 7571 FDCB5796 7575 FDCB57C6 7579 FDCB5786 757D 0618 757F 0E21 7581 CDD90D 7584 118E75 7587 011600 758A CD3C20 758D C9 758E 457A7420 75A4 00 75A5 7D 75A6 C630 75A8 D7 75A9 C9 75AA CD2B2D 75AD CDE32D 75B0 C9 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 KEZD 105 VEG 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
ORG 30000 ; ******************* LD A,2 CALL 5633 CALL 3435 ; ******************* LD A,2 CALL 5633 ; ******************* LD A,16 RST 16 LD A,0 RST 16 ; ******************* LD A,17 RST 16 LD A,7 RST 16 ; ******************* LD A,18 RST 16 LD A,1 RST 16 ; ******************* LD A,19 RST 16 LD A,1 RST 16 ; ******************* LD A,20 RST 16 LD A,1 RST 16 ; ******************* LD A,21 RST 16 LD A,1 RST 16 ; ******************* LD A,22 RST 16 LD A,0 RST 16 LD A,0 RST 16 ; ******************* LD A,42 RST 16 RET ; ******************* SET 2,(IY+87) RES 2,(IY+87) ; ******************* SET 0,(IY+87) RES 0,(IY+87) ; ******************* LD B,24 LD C,33 CALL 3545 ; ******************* LD DE,KEZD LD BC,VEG-KEZD CALL 8252 RET DEFM "Ezt a sort iratjuk ki! DEFB 0 ; ******************* LD A,L ADD A,48 RST 16 RET ; ******************* CALL 11563 CALL 11747 RET ; ******************* ; ******************* |
; Kiiratási rutinol. ;I. Törlés indítás ; A képernyő felső ; részének megnyitása. ; ROM-beli törlőrutin ; meghívása ;II. Sima indítás. ;a. Tintaszín ; beállítása. ; Tintakód hívása. ; Itt 0-tól 7-ig, a ; színnek megfelelően ; akármi szerepelheu ;b. Papírszín ; beállítása. ; papírkód hívása. ; Itt 0-tól 7-ig, a ; színnek megfelelően ; akármi szerepelhet. ;c. Villogás be-(ki-) ; kapcsolása. ; 'FLASH' kód hívása. ; Kikapcsoláskor ; 'A'-ba 0-t töltünk. ;d. Fényesség be-(ki-) ; kapcsolása. ; Meghívjuk a 'BRIGHT' ; kódját. ; Kikapcsoláskor ; 'A'-ba 0-t töltünk. ;e. Inverz kiiratás ; be-(ki-) kapcsolása. ; Meghívjuk az inverz ; állapot kódját. ; Kikapcsoláskor ; 'A'-ba 0-t töltünk. ;f. Áthatás ('OVER') ; be-(ki-) kapcsolása. ; 'OVER' kód hívása, ; Kikapcsoláskor ; 'A'-ba 0-t töltünk. ;g. Pozícionálás ; 'AT' kód hívása. ; Itt a sorpozíciónak ; megfelelő 0 és 21 ; közé eső szám ; szerepelhet. ; Itt az oszlop- ; pozíciónak megfelelő ; 0 és 31 közé eső ; szám szerepelhet ;h. Kiiratás. ; Itt akármelyik ASCII ; vagy grafikus ; karakterhez rendelt ; kód szerepelhet. ; Vége! ;e'. ; Inverz állapot be-, ; illetve ; kikapcsolása ; lehetséges ;f'. ; 'OVER' állapot be-, ; illetve ; kikapcsolása ; lehetséges. ;g'. ; Ide 24-(sorszám) ; írandó! ; Ide 33-(szlopszám) ; írandó! ;h'. Hosszabb szöveg ; kiiratása ; Ide a kezdőcím ; írandó! ; Ide a hossz írandó ; Az alkalmas ROM ; rutin címe. ; Vége a szubrutinnak! ;h''. 'L'-ben lévő ; egyetlen számjegy ; kiíratása. ; A számot betöltjük ; 'A'-ba. ; Előállítjuk ASCII ; kódját és ; megjelenítjük. ; Vége! ;h'''. BC-ben lévő ; tetszőleges szám ; kiíratása. ; BC-ből a ; lebegőpontos ; verembe töltjük. ; Lebegőpontos kiírás. ; Vége! |
Az I-es indításra akkor van szükség, ha az egész képernyőt törölni akarjuk. Ha nem, akkor elég a II-es, sőt ha előzetesen a képernyő csatornája volt nyitva, akkor még az is elhagyható. Az a., b., c., d., e. és f. részeket csak akkor kell beírni a konkrét programba, ha az előzetes állapothoz képest változtatni akarunk. A g. rész elhagyható, ha a következő karakterpozícióba akarunk nyomtatni.
Az inverz és az over állapotok - tehát az e. és az f. rész - vezérlésére a korábbról már ismert, valamivel rövidebb e'. és f'. szakaszban leírt utasítások is használhatók.
A képernyő alsó két sorába nyomtatáshoz a megnyitásban (II) az A regiszterbe 0-t vagy 1-et töltsünk, s ugyanakkor a g. blokkban a pozíció 0 vagy 1 legyen.
A g. pozícionáló rutin helyett használhatjuk a g'.-t is. E rutin használata még azzal az előnnyel is jár, hogy a képernyő alsó részét nem kell külön megnyitni, tehát a sorok száma most 0-tól 23-ig terjed!
A fenti rutin az ASCII kódnak megfelelő karaktereket jeleníti meg. Ez az állítás csak annyiban igaz, hogy a gépbe beépített karakterkészlet jelenik meg, s a Spectrum elsősorban az ASCII kódot használja az alaphelyzethez. Ennek megfelelően, ha az A regiszterbe 32 és 127 közé eső számot töltünk, akkor a számnak megfelelő ASCII karakter, ha 128 és 143 közé eső számot, akkor a beépített grafikus jelek, ha 144 és 164 közé eső számot, akkor a felhasználó által meghatározott grafikus jelek, és ha 164-nél nagyobb számot, akkor az egy karakterpozíciónál hosszabb kulcsszavak, jelek nyomtatása történik.
A gép ez utóbbi csoport karaktereit is a saját karakterkészletéből veszi. A karakterkészlet a ROM-ban található a 15616-os címtől (3D00H) kezdődően 16383-ig (3FFFH), tehát 768 bájt hosszan. A kezdőcímre a 23606-os és a 23607-es címen lévő rendszerváltozó mutat. Pontosabban szólva nem ide, hanem egy 256 bájttal alacsonyabb címre, mert bekapcsolás után a 23607-es címen nem 61, hanem 60 található (23606-ban 0 van!).
Így, ha megváltoztatjuk a karaktercím-mutató rendszerváltozót, már nem is az ASCII kódban vagyunk. Mint ismeretes, egy karakter 8 bájton tárolható, így ha a 23606-ba mondjuk 8-at viszünk, akkor éppen egy karakterrel toltuk el a kódtáblát. Ekkor például az A betű helyett a B betű jelenik meg stb. Az ilyen - és különösen a nem teljes karakterrel való - félrecímzésnek csak annyiban van létjogosultsága, hogy avatatlan szemek előtt a programlista teljes káosz lesz.
A címbeállítás lehetőségének hasznossága inkább abban nyilvánul meg, hogy saját egyéni ízlésűnknek megfelelő betű- és karakterformákat határozhatunk meg és mindezt ASCII kódban. Nem kell tehát mást tennünk, mint a memóriába (RAM) beírni a 768 bájt hosszú saját karakterkészletet és a rendszerváltozóval megcímezni (vigyázat! 256 bájttal alacsonyabban). Az átcímzések nem érintik a grafikai jeleket.
Ha a képernyőre egyszerre több karaktert akarunk egymás mellé (egymás után) kivinni, akkor az előző programvázlat h. blokkját kell többször egymás után aktivizálni. Néhány (maximum 3-4) karakterig ez jó is, de hosszabb szövegnél - bár természetesen lehetséges - már nehézkes. Sokkal jobb megoldás, ha a többszörös hívogatásra ciklust szervezünk. Persze gondoskodni kell a ciklus lezárásáról is. Szerencsére ezt a nem túlságosan nehéz problémát sem kell megoldanunk, mivel a ROM-ban található rá alkalmas rutin. Így hosszabb szöveg kiírására a h. helyett az előző programvázlat h'. szövegkiírási részét használhatjuk.
A számok megjelenítése sem okozhat gondot. Amíg a szám egykarakteres egész, eddigi ismereteink alapján a szokásos módon minden további nélkül megjeleníthető. Tegyük fel, hogy a megfelelő előkészítést - a képernyőnyitást stb. - már elvégeztük, és a kérdéses 0 és 9 közé eső szám az L regiszterben van. Ekkor az előző programvázlat h'. részét használhatjuk (48 hozzáadásával a szám ASCII kódját állítottuk elő).
Több helyértékes szám esetén az egyik járható út a helyértéklebontó rutin. A rutin - mivel az egy regiszterpárban tárolható legnagyobb szám 65535 - nem csinál mást, mint hogy az öt helyértékes szám egyes helyértékein lévő számokat a RAM meghatározott, mondjuk egymás utáni öt címén tárolja. Ezután a programvázlat h. blokkjára alkalmas ciklust szervezve célt érünk.
Ennél azonban sokkal egyszerűbben is megoldható a probléma. Ha biztosan tudjuk, hogy az ábrázolandó szám nem nagyobb 9999-nél (nagyon fontos!), akkor a számot a BC regiszterpárba töltve és a 6683-as (1A1BH) rutint meghívva a várt szám megjelenik. Ha ismerjük a szám memóriabeli címét, akkor ezt a címet a HL regiszterpárba tölthetjük, majd meghívjuk a 6696-os (1A28H) címen található ROM rutint, s az eredmény nem marad el.
Ha a megjeleníteni kívánt szám 9999-nél nagyobb, akkor is van - bár az előzőnél valamivel bonyolultabb, de a helyértéklebontó rutinnál még mindig sokkal egyszerűbb - eljárás. A megfelelő pozicionálás után a számot a BC regiszterpárba töltjük (lásd az előző program H'''. szakaszát). A 11563-as (2D2BH) címen található ROM rutin a BC regiszterpár tartalmát a lebegőpontos verembe tölti (természetesen lebegőpontos módon). A 11747-es (2DE3H) címen található ROM rutin pedig a lebegőpontos verem tetejének tartalmát jeleníti meg. A lebegőpontos számokról, egyáltalán a Spectrum számábrázolásáról később még szólunk.
A nyomtatóval kapcsolatban lényegében minden igaz, amit a képernyőről már elmondtunk, természetesen az eszköz jellegének figyelembevételével. Tehát nincs keret, nincsenek külön színek, a papír nem villog, és olyan fényes, amilyen, változtatni nem lehet. Egyedül az inverz karakter jöhet szóba, de ezt lehetőleg ne használjuk.
Ezek után: a csatorna megnyitásakor az A regiszterbe 3-at töltünk, a pozícionáláskor a 3545-ös (0DD9H) rutint használjuk és a C regiszterbe a megfelelő oszlopszámot töltjük. A B regiszterbe semmit sem kell írnunk, hiszen a sor pozíciója érdektelen. Ha sort akarunk emelni, nyomtassunk üres helyet (32-es kód)!
A hangszóró mint periféria az OUT (254),A utasítással érhető el. Ennek ismeretében semmilyen különösebb akadálya sincs olyan saját rutin megírásának, amely zenél. Egyszerűbb azonban, ha meghívjuk a 949-es (03B5H) címen található ún. beeper ROM rutint. Ez a rutin azután mindenről gondoskodik. A rutin meghívásakor a DE és a HL regiszterpárok tartalma szerint alakul a hang, mégpedig:
DE = INT (f*t)
és
HL = INT (3500000/f - 30,125),
ahol t a hanghatás időtartama, f pedig a frekvenciája.
A pontos hangmagasság előállítása érdekében figyelembe kell venni az alábbi táblázatot:
Hang | Frekvencia |
C Cisz D Disz E F Fisz G Gisz A Aisz H |
261,63 277,18 293,66 311,13 329,63 349,23 369,99 392,00 415,30 440,00 466,16 493,88 |
A beeper rutin letiltja a megszakítást, de egyebekben nemigen köti meg a kezünket. Ennek szemléltetésére tekintsük a következő - a rendőrautó szirénájának hangját utánzó - példát:
7530 7530 3E28 7532 F5 7533 216401 7536 110200 7539 0678 753B E5 753C D5 753D C5 753E CDB503 7541 C1 7542 D1 7543 E1 7544 2B 7545 2B 7546 10F3 7548 0650 754A E5 754B D5 754C C5 754D CDB503 7550 C1 7551 D1 7552 E1 7553 23 7554 23 7555 10F3 7557 F1 7558 3D 7559 20D7 755B C9 |
1 2 3 4 L1 5 6 7 8 L2 9 10 11 12 13 14 15 16 17 18 19 20 21 L3 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
ORG 30000 LD A,40 PUSH AF LD HL,356 LD DE,2 LD B,120 PUSH HL PUSH DE PUSH BC CALL 949 POP BC POP DE POP HL DEC HL DEC HL DJNZ L2 LD B,80 PUSH HL PUSH DE PUSH BC CALL 949 POP BC POP DE POP HL INC HL INC HL DJNZ L3 POP AF DEC A JR NZ,L1 RET |
; Sziréna ; Ismétlések száma ; Kimentjük 'A'-t. ; Kezdőérték ; a felfelé ; glisszandóhoz. ; Valamennyit ; kimentjük. ; A beeper rutin. ; Értékek vissza. ; Frekvencianövelés. ; A fel-glisszandó ; hurok vége. ; A le-glisszandó ; lépésszáma ; Értékek kimentése. ; A beeper rutin. ; Értékek vissza. ; Frekvencia- ; csökkentés. ; A le-glisszandó ; hurok vége. ; Ismétlésvizsgálat Vége! |
A billentyűzet a gép legfontosabb perifériájának tekinthető, hiszen a parancsokat ezen keresztül tudjuk eljuttatni a processzorhoz.
Mint már említettük, a gép 20 ms-onként ellenőrzi a billentyűzet állapotát. (Emiatt lehet például a BREAK utasítással a BASIC program futását megállítani.) Éppen ezért, ha letiltjuk a megszakítást, és ugyanakkor szükségünk van a billentyűzet használatára is, akkor erről külön kell gondoskodnunk.
A billentyűzetet mint perifériát a 254-es vonalon (porton) lehet elérni. Ugyanezen a vonalon van például a hangszóró is, de ez nem okozhat zavart, hiszen a billentyűzet és a processzor között más az adatáramlás iránya. Tehát, ha a 254-es vonalról olvassuk be az adatokat - a magnetofon ilyenkor természetesen nem működik, bár ezen a vonalon van -, akkor a billentyűzet állapotáról kapunk információt. Ezt az információt több úton is megszerezhetjük.
A billentyűzet kezeléséhez több rendszerváltozó tartozik. Ezek közül számunkra a 23560-as címen található LAST K nevű a legfontosabb. Ez tartalmazza ugyanis a legutoljára lenyomott billentyű, illetve a billentyűkombináció ASCII kódját. Így ez a változó számos esetben kitűnően hasznosítható a céljainkra. Nem szabad azonban elfeledkeznünk arról, hogy ebben a rendszerváltozóban mindaddig nem változik meg az érték, amíg nem nyomunk le újabb billentyűt. Ez a körülmény magában foglalja, hogy ugyanannak a billentyűnek többszöri egymás utáni lenyomása sem hoz változást.
A fenti ismeretek birtokában írjunk programot, amely a q, a, m és n billentyűkre reagálva mást-mást csinál, de úgy, hogy a többi billentyű hatástalan legyen! Tegyük fel, hogy az aktív billentyűkkel kapcsolatos programrészek a C1, C2, C3 és C4 címeken találhatók.
7530 7530 3A085C 7533 FE71 7535 28FE 7537 FE61 7539 28FE 753B FE6D 753D 2806 753F FE6E 7541 28FE 7543 18EB |
1 2 3 4 5 6 7 L1 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
ORG 3000 LD A,(23560) CP 113 JR Z,C1 CP 97 JR Z,C2 CP 109 JR Z,C3 CP 110 JR Z,C4 JR L1 |
; Billenzyűzet figyelő ; rutin-1. ; Figyelt billentyűk: ; q, a, m és n ; A főhurok ; A 'LAST K' ; rendszerváltozóban ; található értéket ; betöltjük 'A'-ba. ; "q" ? ; Ha igen, ugrás ; a C1 címre. ; "a" ? ; Ha igen, ugrás ; a C2 címre. ; "m" ? ; Ha igen, ugrás ; a C3 címre. ; "n" ? ; Ha igen, ugrás ; a C4 címre. ; Visszaugrás a ; hurok elejére. |
25 26 27 28 29 30 31 32 |
; ****************************** ; Az egyes címeken (C1, C2, stb.) lévő ; rutinokat nem szemléltetjük, mivel azok ; most érdektelenek. Csupán egy, mondjuk a ; C3-as, töredékes vázlatát közöljük. ; A szubrutin - jobb híján - üres ; utasítással kezdjük ; ****************************** |
||
7545 00 7546 18E8 |
33 C3 34 35 36 37 |
NOP ; ... JR L1 |
Ide jönnek a szubrutin ; közbülső részei. ; Visszatérés ; a főhurokba! |
A programvázlat működését egyszerűen meg lehet érteni: az A regiszterbe betöltjük az utolsó lenyomott billentyű kódját. Ha ez éppen megegyezik a kívánt betűvel, akkor a CP utasítás hatására a Z jelzőbit bebillen, 1 lesz, és létrejön a megfelelő címre való ugrás. Ha nem, akkor a folyamat elölről indul. Miután a LAST K változó mindaddig megtartja értékét, amíg új billentyűt nem nyomunk le, gondoskodni kell arról, hogy értéke megváltozzék, ha egy ugrás megvalósult. Ezt egyszerűen úgy lehet megoldani, hogy a C1 stb. címeken Lévő rutinok végén egy 23560-ba valamilyen, a fentiektől eltérő értéket betöltő kis rutint helyezünk el.
Elegánsabb a megoldás, ha a billentyű lenyomására váró, ROM-ban lévő rutint aktivizáljuk. Tehát:
7530 7530 3A085C 7533 FE71 7535 28FE 7537 FE61 7539 28FE 753B FE6D 753D 2806 753F FE6E 7541 28FE 7543 18EB |
1 2 3 4 5 6 7 L1 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
|
; Billenzyűzet figyelő ; rutin-2. ; Figyelt billentyűk: ; q, a, m és n ; A főhurok ; A 'LAST K' ; rendszerváltozóban ; található értéket ; betöltjük 'A'-ba. ; "q" ? ; Ha igen, ugrás ; a C1 címre. ; "a" ? ; Ha igen, ugrás ; a C2 címre. ; "m" ? ; Ha igen, ugrás ; a C3 címre. ; "n" ? ; Ha igen, ugrás ; a C4 címre. ; Visszaugrás a ; hurok elejére. |
25 26 27 28 29 30 31 32 |
; ****************************** ; Az egyes címeken (C1, C2, stb.) lévő ; rutinokat nem szemléltetjük, mivel azok ; most érdektelenek. Csupán egy, mondjuk a ; C3-as, töredékes vázlatát közöljük. ; A szubrutin - jobb híján - üres ; utasítással kezdjük ; ****************************** |
||
7545 00 7546 1800 7548 3EFD 754A CD0116 754D FDCB02EE 7551 CDD415 7554 C33075 |
33 C3 34 35 36 37 38 39 L2 40 41 42 43 44 |
NOP ; ... JR L2 LD A,253 CALL 5633 SET 5,(IY+2) CALL 5588 JP L1 |
Ide jönnek a szubrutin ; közbülső részei. ; Ugrás a billentyű- ; lenyomást figyelő ; rutinra. ; A megfelelő ; csatorna megnyitása. ; Billentyűfigyelés. ; Visszatérés ; a főhurokba! |
Az 5588-as (15D4H) címen lévő rutin a SET 5, (IY+2) utasítás után nem adja át a vezérlést, míg valamilyen billentyűt le nem nyomtunk. (A shift billentyűk önálló lenyomása nem számít.) Fontos azonban, hogy előtte megnyissuk a billentyűzet csatornáját.
A másik - talán még egyszerűbb - lehetőség, hogy a LAST K betöltése előtt megvizsgáljuk az (IY+1) címen lévő adat 5. bitjét. Ugyanis: ha ez a bit 1, akkor már lenyomtunk egy billentyűt, ha 0, akkor nem. Programunkat tehát javítsuk ki a következő módon:
7530 7530 FDCB016E 7534 28FA 7536 3A085C 7539 FDCB01AE 753D FE71 753F 28FE 7541 FE61 7543 28FE 7545 FE6D 7547 2806 7549 FE6E 754B 28FE 754D 18E1 |
1 2 3 4 5 6 7 L1 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
ORG 3000 BIT 5,(IY+1) JR Z,L1 LD A,(23560) RES 5,(IY+1) CP 113 JR Z,C1 CP 97 JR Z,C2 CP 109 JR Z,C3 CP 110 JR Z,C4 JR L1 |
; Billenzyűzet figyelő ; rutin-3. ; Figyelt billentyűk: ; q, a, m és n ; A főhurok ; Történt-e billentyű ; lenyomás? ; Ha nem, ugrás vissza ; A 'LAST K' ; rendszerváltozóban ; található értéket ; betöltjük 'A'-ba. ; Töröljük a lenyomást ; jelző bitet. ; "q" ? ; Ha igen, ugrás ; a C1 címre. ; "a" ? ; Ha igen, ugrás ; a C2 címre. ; "m" ? ; Ha igen, ugrás ; a C3 címre. ; "n" ? ; Ha igen, ugrás ; a C4 címre. ; Visszaugrás a ; hurok elejére. |
30 31 32 33 34 35 36 37 |
; ****************************** ; Az egyes címeken (C1, C2, stb.) lévő ; rutinokat nem szemléltetjük, mivel azok ; most érdektelenek. Csupán egy, mondjuk a ; C3-as, töredékes vázlatát közöljük. ; A szubrutin - jobb híján - üres ; utasítással kezdjük ; ****************************** |
||
754F 00 7550 18DE |
38 C3 39 40 41 42 |
NOP ; ... JR L1 |
Ide jönnek a szubrutin ; közbülső részei. ; Visszatérés ; a főhurok-ba! |
Ugyancsak nagyon kényelmesen lehet használni a 4264-es (10A8H) címen lévő ROM rutint is. Hatására rögtön az A regiszterbe kerül a billentyűkód.
A 23552-es és a 23559-es címek közötti rendszerváltozók közül a 23556-os és a 23559-es érdemel külön említést. A 23559-es a LAST K-hoz szinte mindenben hasonlóan viselkedik. A 231556-osnak, bár csak a nagybetűk és a számok kódját tartalmazza (valamint ENTER esetén 13-at, a két shift billentyű egyidejű lenyomása esetén pedig 14-et), megvan az a nagyon hasznos tulajdonsága, hogy a billentyűk lenyomása nélküli állapotban azonnal felveszi a 255-ös értéket. Használata esetén tehát nem kell külön gondoskodni az inicializálásról.
Van még négy, a billentyűzettel kapcsolatos rendszerváltozó:
Cím | Név | Kezdőérték |
23561 23562 23608 23609 |
REPDEL REPPER RASP PIP |
35 5 64 0 |
Szerepük nem a programokban, hanem a programozáskor nyilvánul meg. A REPDEL értéke megszabja, mennyi időt vár a gép, amíg a folyamatosan nyomott billentyű ismétléses állapotot nem idéz elő (kb. 0,7s). A REPPER az ismétlődési időt adja (kb. 0,1s). Vigyázat, ha a tartalmát 0-ra állítjuk, nem gyors, hanem éppen a leglassúbb lesz! A RASP a figyelmeztető zúgás hosszát adja, a PIP pedig a billentyű lenyomásakor elhangzó jelhangét.
Az eddig felsorolt lehetőségek, programok csak a gép alapállapotában, tehát 1-es megszakítási módban dolgoznak. Ha nem ez a helyzet, akkor a billentyűzetfigyelő rutinokat külön kell aktivizálni, vagy mindenről magunknak kell gondoskodni. A ROM rutinok felhasználására a következők a lehetőségeink:
Bár ezek a ROM rutinok nagyon jók, mégis sokkal előnyösebb, ha olyankor, amikor egyéni célt kívánunk megvalósítani, saját billentyűzetfigyelő és dekódoló rutint írunk. Nézzük például a következő egyszerű figyelő-dekódoló rutint:
7530 7530 F3 7531 3EFE 7533 DBFE 7535 1F 7536 38F9 7538 FB 7539 C9 |
1 2 3 4 5 6 7 L1 8 9 10 11 12 13 14 15 |
ORG 30000 DI LD A,254 IN A,(254) RRA JR C,L1 EI RET |
; Billentyűzet figyelő ; rutin-4 ; Figyelt billentyű: ; CAPS SHIFT ; Megszakítás letiltás ; CAPS SHIFT figyelés. ; Visszaugrás, ha nem ; a "CAPS SHIFT" a ; megnyomott billentyű ; A megszakítás ; engedélyezése. ; Vége! |
Ez a kis rutin nagyon tanulságos, és még hasznos is lehet. Először is bemutatja, hogy letiltott megszakítás esetén miként lehet hozzáférni a billentyűzethez, valamint igen egyszerű és gyors billentyűzet szerinti elágazást tesz lehetővé.
Az alábbi felsorolás bemutatja, hogy BASIC-ből való meghívásnál melyik billentyű jelent kizárólagos visszatérést.
x |
billentyű |
127 191 223 239 247 251 253 254 |
SPACE ENTER P 0 1 Q A CAPS SHIFT |
Minden más x értékre (a 255-öt kivéve), legalább két billentyűvel lehet visszatérni (255-re egyáltalán nincs visszaút). Így nyolc irányba lehet elágazni:
7530 7530 3E7F 7532 DBFE 7534 1F 7535 D23575 7538 3EBF 753A DBFE 753C 1F 753D D23D75 7540 3EDF 7542 DBFE 7544 IF 7545 D27275 7548 3EEF 754A DBFE 754C 1F 754D D24D75 7550 3EF7 7552 DBFE 7554 1F 7555 D25575 7558 3EFB 755A DBFE 755C 1F 755D D25D75 7560 3EFD 7562 DBFE 7564 1F 7565 D26575 7568 3EFE 756A DBFE 756C 1F 756D D26D75 7570 18BE |
1 2 3 4 5 6 7 8 L1 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
ORG 30000 LD A,127 IN A,(254) RRA JP NC,C1 ; ******************* LD A,191 IN A,(254) RRA JP NC,C2 ; ******************* LD A,223 IN A,(254) RRA JP NC,C3 ; ******************* LD A,239 IN A,(254) RRA JP NC,C4 ; ******************* LD A,247 IN A,(254) RRA JP NC,C5 ; ******************* LD A,251 IN A,(254) RRA JP NC,C6 ; ******************* LD A,253 IN A,(254) RRA JP NC,C7 ; ******************* LD A,254 IN A,(254) RRA JP NC,C8 JR L1 |
; Billentyűzetfigyel ; rutin-5 ; Figyelt billentyűk: ; SAPCE, ENTER, P, 0, ; 1, Q, A, CAPS SHIFT ; A főhurok ; "SPACE" figyelése. ; Ugrás a kívánt címre ; a megfelelő billentyű- ; lenyomása esetén ; "ENTER" figyelése ; Ugrás a kívánt címre ; a megfelelő billentyű- ; lenyomása esetén ; "P" figyelése. ; Ugrás a kívánt címre ; a megfelelő billentyű- ; lenyomása esetén ; "0" figyelése. ; Ugrás a kívánt címre ; a megfelelő billentyű- ; lenyomása esetén ; "1" figyelése. ; Ugrás a kívánt címre ; a megfelelő billentyű- ; lenyomása esetén ; "Q" figyelése. ; Ugrás a kívánt címre ; a megfelelő billentyű- ; lenyomása esetén ; "A" figyelése. ; Ugrás a kívánt címre ; a megfelelő billentyű- ; lenyomása esetén ; "CAPS SHIFT" figyelése. ; Ugrás a kívánt címre ; a megfelelő billentyű- ; lenyomása esetén ; Visszatérés ; a főhurokba! |
65 |
; ****************************** ; Az egyes címeken (C1, C2, stb.) lévő ; rutinokat nem szemléltetjük, mivel azok ; most érdektelenek. Csupán egy, mondjuk a ; C3-as, töredékes vázlatát közöljük. ; A szubrutin - jobb híján - üres ; utasítással kezdjük ; ****************************** |
||
7572 00 7573 18BB |
73 C3 74 75 76 77 |
NOP ; ... JR L1 |
Ide jönnek a szubrutin ; közbölső részei. ; Visszatérés ; a főhurokba! |
A fenti blokkok egy adott billentyű lenyomását vizsgálják. Ha az alkalmas billentyűt nyomjuk meg, akkor a megfelelő blokkban lévő utasítások hatására a C jelzőbit 0 lesz, és a feltétel teljesülése folytán megtörténik az ugrás.
A billentyűzet állapotának vizsgálatát jobban meg lehet érteni, ha megnézzük a billentyűzetet bemutató vázlatos ábrát (10. ábra): Az ábrán a billentyűket nyolc fél sorba soroltuk, és ezeket 0-tól 7-ig beszámoztuk. A 2-es fél sor például a Q, a W, az E, az R és a T billentyűt foglalja magában.
3 |
4 |
2 |
5 |
1 |
6 |
0 |
7 |
Gondolatban a billentyűket is beszámozzuk kintről befelé haladva, 0-val kezdve. Így például az 5-ös fél sor billentyűinek számai:
P=0, O=1, 1=2, U=3, Y=4.
A fél sorokhoz rendelt számok megadják, hogy a vizsgálatot végző
LD A,x
IN A,(254)
rutinban az x szám hányadik bitjét kell 0-nak választani. Így például ha a 4-es számú fél sort ellenőrizzük, akkor az x negyedik bitje lesz 0, a többi 1, tehát:
x=11101111,
azaz
x=255-16=239.
Ez persze kombinációban is megy. Ha például az x 0. és 7. bitjét nullázzuk ki, akkor az alsó sor a vizsgálat tárgya, és
x=255-(128+1)=126.
Ezzel magyarázható, hogy x = 255 esetén sehonnan sincs beolvasás, x = 0 esetén pedig mindenhonnan.
Ha a vonalról olvastunk be, az A regiszterbe kerülő értéket a billentyű fél soron belüli sorszámából határozhatjuk meg, ugyanis éppen a sorszámnak megfelelő bit lesz 0, a többi pedig 1. Így például, ha a 3-as számú fél sorról olvasunk be, és a megnyomott billentyű 4-es feliratú - amelynek fél soron belüli sorszáma 3 -, akkor az A regiszterbe
x = 255 - 8 = 247
kerül.
Magától értetődik, hogy a nem vizsgált területről érkező billentyűnyomás hatástalan, tehát az A-ban ekkor 255 lesz. Több megfelelő (a vizsgált területről származó) billentyű egyidejű lenyomása a sorszámnak megfelelő bit nullázását jelenti.
Befejezésül bemutatunk egy elsősorban játékra alkalmas, speciális billentyűzetfigyelő és dekódoló rutint. Nyolc irányban mozoghatunk vele, és lőhetünk is. A mozgás-billentyű kapcsolatot a 11. ábra szemlélteti.
A program a következő:
7530 7530 0E00 7532 3EE7 7534 DBFE 7536 2F 7537 E61F 7539 2804 753B CBD9 753D 180B 753F 3EBD 7541 DBFE 7543 2F 7544 E61F 7546 2802 7548 CBC9 754A 3EDF 754C DBFE 754E 2F 754F E61F 7551 2804 7553 CBC1 7555 180B 7557 3EFB 7559 DBFE 755B 2F 755C E61F 755E 2802 7560 CBD1 7562 3E7E 7564 DBFE 7566 2F 7567 E61F 7569 C8 756A CBE1 756C C9 |
1 2 3 4 5 6 FE 7 8 9 10 11 12 13 LE 14 15 16 17 18 19 JO 20 21 22 23 24 25 26 27 BA 28 29 30 31 32 33 34 TU 35 36 37 38 39 40 |
ORG 30000 LD C,0 LD A,231 IN A,(254) CPL AND 31 JR Z,LE SET 3,C JR JO LD A,189 IN A,(254) CPL AND 31 JR Z,JO SET 1,C LD A,233 IN A,(254) CPL AND 31 JR Z,BA SET 0,C JR TU LD A,251 IN A,(254) CPL AND 31 JR Z,TU SET 2,C LD A,126 IN A,(254) CPL AND 31 RET Z SET 4,C RET |
; Billentyűzet figyelő ; rutin-6 ; Információs regiszter ; kiürítése. ; Felső sor vizsgálata ; 3. sor vizsgálata ; 2. sor jobb oldalának ; vizsgálata. ; 2. sor bal oldalának ; vizsgálata. ; Alsó sor vizsgálata ; RET |
Fel |
|
Balra |
Jobbra |
Le |
|
Tűz! |
A C regiszter tartalma
A rutinból való visszatérés után C-ben az ábrán vázolt értékek lesznek. Ha nem volt billentyűnyomás, akkor C-ben természetesen 0 van. A fel és jobbra irányoknak prioritásuk van a le, illetve balra irányokkal szemben.
Ahhoz, hogy minden tekintetben hatékony programot tudjunk írni, elevenítsük fel - persze kissé kibővítve - az eredeti Spectrum gépkönyvből szerzett ismereteinket.
A Spectrum a számokat mindig öt bájt hosszan ábrázolja, de alapvetően kétféle formában:
Egy x szám egész típusú, ha egész szám és igaz rá a
-65535 <= x <= 65535
egyenlőtlenséglánc.
Az ilyen számok tárolásakor az első és az ötödik bájt zérus. A második bájt 0 vagy 255 aszerint, hogy a szám pozitív-e vagy negatív. Pozitív számok esetén:
a 3. bájt =x -256 * INT (x/256),
a 4. bájt = INT (x/256).
Negatív számok esetén:
a 3. bájt = 65536 - x - 256 * INT (65536 - x / 256),
a 4. bájt = INT (65536 - x / 256).
Ez azért is kedvező, mert a számtárolás logikája a Z80-as processzor logikájának megfelelő, tehát ilyen számokkal a gép sokkal gyorsabban tud számolni.
Minden más szám lebegőpontos. Ezek a számok a kettes számrendszerbeli mantissza-karakterisztika írásmódot követik, tehát
x=m*2^k
alakban tárolódnak.
Az első bájt az exponens karakterisztika, mégpedig úgy, hogy ha a szám egynél kisebb, akkor az első bájtban legfeljebb 128 lehet. Pontosítva: ha x kifejezésében k = -1, akkor az első bájt tartalma pontosan 128. Amennyire ettől a konkrét szám k-ja eltér, annyival változik a 128.
Például x = 0,124 esetén, mivel
2^-4 < x < 2 ^-3,
az első bájt tartalma 128 - ( - (-4) - 1) = 125 lesz.
x = 2,12 esetén
2^2 > x > 2^1
miatt az első bájt tartalma 128 - (- 1 - 1) = 130 lesz.
A következő 4 bájton a szám kettes számrendszerbeli alakja jelenik meg természetesen az első értékes egyestől. Azaz nem pontosan így, mert az előjel-információt is a második bájt tartalmazza. A ROM létrehozói ugyanis igen szellemesen kiaknázták azt, hogy egy kettes számrendszerbeli szám mindig egyessel kezdődik. (A szám elé írt nulláknak nincs tartalmuk!) Tehát ha ez az egyes - amiről tudjuk, hogy ott kell lennie a szám elején - mégis hiányzik, akkor ez nem a hiányt, esetleg valaminek a hibáját jelenti, hanem azt, hogy a szám pozitív. Ha az egyes mégis ott van, akkor a szám negatív.
Például: x = 5,8 esetén, mivel
2^3 > x > 2^2
az első bájt 128 - (- 2 - 1) = 131 lesz.
A második pedig, mivel a szám pozitív,
001110012 = 5710
lesz. Az összes többi bájt megegyezik és 153 lesz. Tehát az 5,8 a gépben 131, 57, 153, 153, 153 alakban jelenik meg.
A RAM-ban minden egyes BASIC-sor a következőképpen jelenik meg (12. ábra):
12. ábra
Az első két bájton a sorszám helyezkedik el, de - és ez nagyon fontos - nem az eddigi logikának megfelelő kevésbé meghatározó-meghatározó sorrendben, hanem éppen fordítva. A következő két bájt - ez már a szokásos logikának megtelelő sorrendben - a sor hosszát adja meg, beleértve a sort lezáró 13-as kódú ENTER-t is. A hosszúságot megadó bájtok és az ENTER közé az adott utasításnak, szimbólumnak megfelelő kód kerül.
Ha a sorban tényleges szám is van (az L22 azonosító, nem számi), akkor a számjegykarakterek kódjai után egy 6 bájt hosszúságú blokk kerül. A blokk első bájtja 14-et tartalmaz, jelezve, hogy az utána következő 5 bájt - a már ismert formában - egyetlen számot takar.
Ennek megfelelően egy BASIC-sor hossza viszonylag könnyen meghatározható:
hosszúság = 5 + a karakterek száma + 6 * (a számok száma),
ahol 5 a sorszám, a hossz és az ENTER együttvéve.
A memóriabeli BASIC tartomány teljes hosszát vagy a már korábban említett módon, a NXTLIN rendszerváltozó segítségével határozhatjuk meg, vagy pedig a
PEEK 23627 - PEEK 23635 + 256 * (PEEK 23628 - PEEK 23636)
utasításokkal.
A 23635-ös és a 23636-os címen lévő PROG rendszerváltozót már ismerjük. A 23627-es és a 23628-as címen lévő VARS nevű rendszerváltozó a BASIC-változók megadására kijelölt terület kezdőcímét tartalmazza.
Ebben a részben felsorolásszerűen a BASIC-változók változótartományon belüli elhelyezkedéséről és a kódokról lesz szó.
Az egyszerű változó (egy betű) hossza: 6 bájt (az azonosító + 5 bájt a számnak), azonosító kódja: 97 - 122 (a-tól z-ig). (Ezt a továbbiakban betűkódnak nevezzük.)
Az összetett változó betűvel kezdődő, betűből és számokból álló kombináció. Hossza az azonosító hossza + 5 bájt.
Az első karakter = azonosító kódja: betűkód + 64 (161 - 186), a belső karakterek = betű- vagy számkódok, az utolsó karakter = azonosító kódja: betű- vagy számkód + 128 (225 - 250) vagy (176 - 185).
A karakterváltozó hossza: 3 bájt + a karakterek száma, azonosító kódja: betűkód - 32 (65-90).
Szerkezete:
1. bájt = 2. bájt = 3. bájt |
azonosító hosszúság |
. . . |
karakterek |
A számtömb hossza: 4 + 2 * (a dimenziók száma) + 5 * (a számok száma), azonosító kódja: betűkód + 32 (129 - 154).
Szerkezete:
1. bájt = 2. bájt = 3. bájt 4. bájt = |
azonosító hosszúság a dimenziók száma |
5, 6, 7, 8 bájt = |
egy dimenzión belüli darabszám |
. . . |
számok |
A karaktertömb hossza: 4 + 2 * (dimenziószám) + karakterszám, azonosító kódja: betűkód + 96 (193 - 218).
Szerkezete: értelemszerűen ugyanaz, mint a számtömbé.
A ciklusváltozó hossza: 19 bájt, azonosító kódja: betűkód + 128 (225 - 240). Szerkezete:
1. bájt = | azonosító |
2, 3, 4, 5, 6. bájt = |
érték |
7, 8, 9, 10, 11. bájt = |
határérték |
12, 13, 14, 15, 16. bájt = |
lépésköz |
17, 18. bájt = |
az utasítás sorszáma |
19. bájt = | a soron belüli utasítások száma |
Eddig is szóltunk már néhány rendszerváltozóról. Ebben a részben a teljesség igénye nélkül kiegészítjük a felsorolást. Célunk, hogy az olvasót olyan ismeretekhez juttassuk, amelyekkel a Spectrum lehetőségeit az egyszerű BASIC nyelvű, illetve a gépi kódú programozáson kívül is ki tudja használni.
A kurzor üzemmódjának váltása
A program futása közben is lehetőség van a kurzor üzemmódjának váltására. Ennek elsősorban akkor van jelentősége, ha a programban INPUT A$ vagy hasonló parancs van. Ilyenkor nem kell a felhasználóra bízni, hogy átkapcsoljon, hanem az INPUT-ot tartalmazó sorra való lépés előtt szerepeltetni kell a
POKE 23658,8
utasítást. A kurzor a
POKE 23658,0
utasítással állítható vissza.
Ha grafikus karaktereket akarunk bevinni, akkor a
POKE 23617,2
parancs kiadására van szűkség. A kurzor a
POKE 23617,0
utasítással állítható vissza.
A 23617-es címen lévő MODE nevű rendszerváltozóval egészen különleges hatásokat lehet elérni. Ezek közül táblázat formájában felsorolunk néhányat:
Érték | Hatás | Megjegyzés |
30 32 34 36 160 162 164 238 |
grafikai jelek | |
236 | kérdőjel | |
142 | fontjel | |
240 | dollárjel | |
101 | (nincs villogás, a két idézőjel egymás főlőtt lesz) | |
106 | INPUT LINE A$ esetén (nincs villogás, a képernyő alja üres) |
A különleges ugróutasítás
A 23618-as és a 23619-es címen lévő NEWPPC, valamint a 23620-as címen lévő NSPPC rendszerváltozó együtt igen különleges ugrást tesz lehetővé. Nemcsak a sor elejére ugorhatunk, mint a GO TO vagy a GO SUB parancsokkal, hanem a sorban akárhányadik utasításra. Írjuk ugyanis valamelyik sorba a következőket:
POKE 23618,s-256*INT (s/256): POKE 23619,INT (s/256): POKE 23620,u
Az s-nek és az u-nak előzetesen értéket adva, futás közben a program erre a sorra érve elugrik az s-edik sor u-adik utasítására. Ha ezt a sort GO SUB-bal hívtuk meg, akkor a hívás természetesen szubrutin jellegű.
A belső óra
A 23672-es, a 23673-as és a 23674-es címeken található FRAMES nevű rendszerváltozó időmérésre alkalmas, ugyanis ha a megszakítás nincs letiltva, e változó értéke minden 20. ms-ban, azaz másodpercenként 50-szer eggyel nő. A számlálás a bekapcsolás pillanatától, zérus értékről kezdődik. Megfelelő POKE utasításokkal az óra természetesen tetszőleges kezdőértékre is beállítható. Az eltelt idő másodpercekben a következő:
(PEEK 23672 + 256 * PEEK 23673 + 65536 * PEEK 23674)/50
A programvédelem
A Spectrumon a programvédelemnek igen széles skálája valósítható meg. Kezdve a legélesebbel - hogy bármely avatatlan személy számára felhasználhatatlanná, sőt betölthetetlenné tudjuk tenni programunkat - az egészen enyhéig, a listázhatóság megakadályozásáig. Most azonban csak két programvédelmi lehetőséggel foglalkozunk:
A listázás megakadályozásának egyik Iegegyszerűbb és emiatt talán a legkevésbé hatékony módja a színkódok használata. A módszer lényege a következő: Mielőtt a megírt BASIC-sort az ENTER utasítással a helyére küldenénk, állítsuk a kurzort közvetlenül a sorszám után! Ezután állítsuk a gépet E módba, és nyomjunk meg egy színbillentyűt (0-7)! A gépet ismét E módba állítva nyomjuk le ismét ugyanezt a színbillentyűt, és közben tartsuk lenyomva a CAPS SHIFT billentyűt!
Ha az első 4-5 sort ilyen módon "megfejeljük", és ezt a "játékot" 2-3 soronként megismételjük, akkor a listázáskor nagy valószínűséggel csak az első sorszám fog látszani. De a legrosszabb esetben is - természetesen nem a sima LIST-re, hanem mondjuk a LIST 684-re gondolunk - csak egy-két sor látszik majd.
Lényegesen rafináltabb módszer, ha a program elején a POKE utasítással a 23607-es címre az eredeti 60 helyett egy nagy számot, mondjuk 250-et juttatunk be. A baj csak az, hogyha a képernyőre normál, tehát nem grafikus karaktereket akarunk kivinni, akkor a 60-at átmenetileg vissza kell írnunk.
A legravaszabb, és más módszerekkel kombinálva csaknem felderíthetetlen állapotokat létrehozó eljárás a következő:
Írjuk meg az alábbi - magas szintű programozói fogásokkal teletűzdelt, és ezért mások tekintetétől feltétlenül védendő - programot!
10 PRINT "kutya"
20 PRINT "macska"
30 GO TO 10
Ki is lehet próbálni, működik-e? Nos, ha igen, és BREAK utasítással megállítottuk, akkor tegyük a következőt:
POKE 23755,100
és ENTER.
Csiribi-csiribá, volt program - nincs program. Nincs az a kézenfekvő BASIC utasítás, amely megmutatná, hogy BASIC program van a gépben. Pedig ott van, hiszen ha kiadjuk a
POKE 23755,0
és ENTER
utasítást, megtörténik a "visszavarázsolás", de most nem ez a cél. Tehát maradjunk az elrejtett állapotnál azzal a szomorú tapasztalattal, hogy a RUN parancs hatástalan. Gépeljük be a következő "akármit":
RUN 25610
majd ENTER, és csodák csodája, fut a program, azaz nem egészen, mert csak egy "kutya" és egy "macska" lesz a képernyőn. Ha azonban a 30. sort előzetesen GO TO 25610 paranccsal (!) küldtük volna be, akkor most szépen működne a program.
A programrejtés ezzel persze még egyáltalán nincs megoldva, hiszen a program ebben a rejtett formájában - bár működőképes - a GO TO utasítás körül mindenképpen hibás a sorszámok összevisszasága miatt. Ha mondjuk SAVE "kutya" LINE 25610 utasítást adnánk, az autostart érdekében ezt is elfogadná a gép és akkor is csak ott lennénk, ahol a part szakad, mert 9999-es cím felett az autostartos felvétel sima felvételként működik.
A dolgok magyarázatához még annyit, hogy a 25610-es cím az eredeti 10 és a bevitt 100 * 256 hatására alakult ki. Az autostartos felvétel és a GO TO használata mégis megoldható. Ennek felderítését az olvasóra bízzuk.
A programba való bepillantás megakadályozására két lehetőségünk van. Mindkettőhöz az szükséges, hogy az egyébként hibátlanul működő program autostarttal induljon. Erre a címre azután elhelyezhetjük a védelmet biztosító utasításainkat.
Az egyik lehetőség a 23659-es címen található DF SZ nevű rendszerváltozó átállítása. Ugyanis ez a rendszerváltozó tartalmazza a képernyő alsó részében található sorok számát. Ha tehát ide a POKE 23659,0 utasítással zérust írunk be, megszüntetjük a képernyő alsó részét.
Ebből következik, hogy a CAPS SHIFT + BREAK utasítást a gép nem tudja végrehajtani, következésképpen "elszáll", és a program megállíthatatlanná válik. A 24 soros nyomtatásra van lehetőség, de az INPUT utasítás természetesen nem használható, és ugyancsak baj lesz, ha a "scroll?" felírásnak egyébként meg kellene jelennie.
Mindezek a korlátozások nem jelentkeznek, ha az induló sorba a következőket írjuk:
LET q = PEEK 23613 + 256 * PEEK 23614: POKE q,0: POKE q + 1,0
A 23613-as és a 23614-es címen lévő ERR SP nevű rendszerváltozó azt a veremcímet tartalmazza, amelyen a hiba utáni visszatérés címe van. Ez a fenti sor hatására a ROM-beli 0 cím, azaz a bekapcsolási rutin lesz.
Ezek a védelmek akkor tehetők teljessé, ha megakadályozzuk a MERGE rutin működését, tehát ne lehessen megállítva betölteni. Erre több lehetőség kínálkozik:
Programunk utolsó két sorát a következőképpen alakíthatjuk:
SAVE "NÉV" CODE 23552, HOSSZ
GO TO NNNN vagy
RUN
A "HOSSZ" meghatározható kézi számítással, de szebb, ha helyette
PEEK 23641 + 256 * PEEK 23642 - 23552
áll. A 23641-es és a 23642-es címen az E LINE neve rendszerváltozó van, amely az éppen begépelésre kerülő sor memóriabeli címét adja, amely éppen a BASIC-változók memóriabeli címe mögött kezdődik. A program CODE-os betöltése lesz, tehát nem lesz MERGE, ugyanakkor a betöltés után azonnal indul.
Programunk utolsó sorába a következőt is írhatjuk:
xx REM
A már ismert módon keressük meg a sor memóriabeli címét, azt, ahol a sorszám meghatározó bájtja van. Legyen ez mondjuk n. Ebben az esetben az (n + 2)-es címen van e sor hosszának kevésbé meghatározó bájtja, amely most kettő. Tegyük tehát a következőt: POKE n + 2,0 és ENTER, majd autostartos módon rögzítsük programunkat a hangszalagon! A LOAD"" formátumú betöltés után a program rendesen fog dolgozni, de ha a MERGE"" utasítást adjuk, lesz meglepetés...
Programjainkat, illetve bizonyos részeiket mágnesszalagon szoktuk rögzíteni. A Spectrum esetében - mint ismeretes - lehetőség van a teljes BASIC program és a változóterület együttes felvételére, valamint a teljes memória bármely részének, továbbá egyetlen számtömbnek, illetve egyetlen karaktertömbnek a rögzítésére. A Spectrum ROM rutinjával készített bármely felvétel hasonló szerkezetet mutat:
Az adatsorra vonatkozó lényeges információkat az előző fejezetben említett ún. programfej (angolul header) tartalmazza. Betöltéskor ennek alapján tudja a Spectrum, hogy milyen jellegű és milyen hosszúságú programról van szó stb.
A programfej első bájtja megmutatja, hogy milyen típusú felvételről van szó. Az első bájt
jellegű a felvétel. A következő 10 bájt a felvétel nevének ASCII kódját tartalmazza. A 12. és a 13. bájt a felvétel hosszát adja meg. A további négy bájt szerepe a felvétel típusától függ. BASIC programban a 13. és a 14. bájt az autostart címét adja meg, tehát egy 0 és 9999 közé eső számot. Ha ez az érték ennél nagyobb (általában 32768), akkor nincs autostart. Az utolsó két bájt a tiszta, tehát a változóterület nélküli BASIC program hosszát adja.
Tömböknél a 14. bájt a tömbváltozó azonosítóját tartalmazza, azaz számtömb esetén egy 129 és 154, karaktertömb esetén pedig egy 193 és 218 közé eső számot. A többi bájt értéke ekkor nem túlságosan érdekes.
Kódos program esetén a 13. és a 14. bájt a programbetöltés kezdőcímét adja. Ekkor meg az utolsó két bájt az, ami nem fontos.
A gyakorlati programozás során egy adott, mágnesszalagon rögzített programról gyakran tudnunk kellene a hosszát, a betöltési helyét stb. A kívánt információk megszerzéséhez készítsünk programfej-olvasó programot!
7530 7530 DD21005B 7534 111100 7537 AF 7538 37 7539 CD3805 753C C9 |
1 2 3 4 5 6 7 8 9 |
ORG 30000 LD IX,23296 LD DE,17 XOR A SCF CALL 1336 RET |
; Betöltjük IX-be ; a kezdőértéket, ; DE-be a hosszt és ; A-ba 0-t. ; A C jelzőbitet ; 1-re állítjuk. ; Adatbehívó rutin. ; Vége! |
Ez a 13 bájt hosszúságú rutin gondoskodik róla, hogy a programfej 17 bájtja a 23296-os címtől kezdve betöltjődjék a nyomtató puffer-területének elejére. A fenti kis program - ebben a formában - kizárólag szabályos, tehát a ROM rutinnak megfelelő módon készült felvételek programfejének behívására való. Megfelelő gépi kódú vagy BASIC programmal kiegészítve az így kapott információ megjelenik a képernyőn. Az olvasó figyelmét fel kell hívnunk arra, hogy az összetett, tehát több részből álló programok egyes részei nem feltétlenül olyan szerkezetűek, mint az iménti felsorolás. Az első rész azonban mindig szabályos!
Az adatrögzítéssel kapcsolatban még egy kérdésre kitérünk. Gyakran merül fel az igény valamely változó mágnesszalagon való rögzítésére. Erre azonban közvetlenül semmiképpen sincs mód, hiszen a ROM rutin csak egyetlen numerikus vagy karaktertömb kimentését teszi lehetővé. De kis ügyeskedéssel a kívánt cél megvalósítható. A ravaszkodásnak az a lényege, hogy az egész változóterületet egyetlen karaktertömb-változó, mondjuk a Z$ adatterületévé "varázsoljuk", és a magnetofonra ezt vesszük fel. Újratöltéskor pedig egyszerűen "visszavarázsoljuk" az eredeti állapotot.
Ennek megfelelően minden olyan programot, amelynél célszerű a teljes változóterület kimentése, egészítsünk ki az alábbi BASIC-sorokkal:
1 DIM z$(10): REM Ez az indulo sor
9997 INPUT "cim ";y$: IF LEN y$>10 THEN GO TO 9997
9998 LET z$(1 TO LEN y$)=y$: RANDOMIZE USR 23296: SAVE z$(1 TO 10) DATA z$()t: STOP
9999 LOAD "" DATA z$(): RANDDMIZE USR 23330
A gépi kódú rutin pedig a következő:
5B00 5B00 2A4B5C 5B03 7E 5B04 FEDA 5B06 2802 5B08 CF 5B09 01 5B0A EB 5B0B 2A595C 5B0E 010300 5B11 A7 5B12 ED52 5B14 CD195B 5B17 23 5B18 EB 5B19 ED42 5B1B EB 5B1C 23 5B1D 73 5B1E 35 5B1F 23 5B20 72 5B21 C9 5B22 2A4B5C 5B25 7E 5B26 FEDA 5B28 2802 5B2A CF 5B2B 1A 5B2C 23 5B2D 230D 5B2F 23 5B30 3600 5B32 23 5B33 23 5B34 360A 5B36 23 2B37 3600 5B39 C9 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 L2 15 16 17 18 19 20 21 22 23 24 25 L1 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 L3 45 46 47 48 49 50 51 52 53 |
ORG 23296 LD HL,(23627) LD A,(HL) CP 218 JR Z,L2 RST 8 DEFB 1 EX DE,HL LD HL,(23641) LD BC,3 AND A SBC HL,DE CALL L1 INC HL EX DE,HL SBC HL,BC EX DE,HL INC HL LD (HL),E DEC (HL) INC HL LD (HL),D RET LD HL,(23627) LD A,(HL) CP 218 JR Z,L3 RST 8 DEFB 26 INC HL LF (HL),13 INC HL LD (HL),0 INC HL INC HL LD (HL),10 INC HL LD (HL),0 RET |
; A kezdőcím: ; a nyomtató puffer ; Betöltjük HL-be ; a 'VARS' címét, ; majd 'A'-ba az e ; címen található ; értéket. ; Megvizsgáljuk, hogy ; ez a 'Z tömb'-e? ; Ha igen, ugrás előre, ; ha nem, akkor ; hibakóddal megállunk ; Kimentjük a HL beli ; értéket és a HL-be ; töltjük az 'E LINE' ; rendszerváltozóban ; szereplő címet. ; Kiszámítjuk a ; változó teület ; hosszát ; és az új ; dimenzióindexet. ; Vége! ; Itt kezdődik a ; betöltő rutin, ami ; semmi mást nem ; csinál, mint vissza- ; állítja az eredeti ; állapotokat. ; Ha a betöltött ; változó ; nem 'Z tömb' típusú, ; hibakóddal megáll. Vége! |
Ha a gépi kódú részt valami miatt nem a nyomtató puffer-területének elejére töltjük, akkor néhány változtatást kell tennünk:
Lebegőpontos kalkulátor
Eddigi vizsgálódásaink során egy esetben és nagyon is érintőlegesen már felmerült ez a téma. Akkor a 9999-nél nagyobb, de 65536-nál kisebb egész számok nyomtatásához használtuk. A nem kifejezetten matematikai programok kivételével ennél több általában nem is kell. Mégis - a fejlettebb programozási módszerek alkalmazása érdekében - röviden összefoglaljuk a használatát, és utalunk néhány e témakörrel kapcsolatos ROM rutinra, függetlenül attól, hogy eddig szerepeltek-e vagy sem.
A lebegőpontos kalkulátor - mint a neve is mutatja - nagyjából úgy működik, mint az ismert programozható kalkulátorok: A rutint az RST 40 (kódja: 239) hívja meg, az utána szereplő egy bájt hosszúságú utasítások pedig azt a programot jelentik, amelyet a lebegőpontos kalkulátor az ún. kalkulátor-veremben lévő számokkal végrehajt. A programnak ez a része tehát
RST 40
DEFB ...
...
DEFB 56
alakú szerkezetet mutat. Az utolsó utasításnak "56"-nak kell lennie, ugyanis ez jelzi a lebegőpontos számítás végét.
A lebegőpontos kalkulátor az elemi aritmetikai műveleteken és a szokásos függvényeken kívül ismeri a logikai műveleteket, sőt a karakterekkel kapcsolatos műveleteket és függvényeket, valamint a belső ugróutasításokat is. Saját külön memóriaregiszterei is vannak, és bizonyos állandó értékekre is lehet hivatkozni (ilyen például az 1, a 0, a PI/2 stb.). Az alábbiakban felsorolunk néhány fontosabb adatbájtot a hozzájuk kapcsolódó utasításokkal együtt:
Adatbájt | Funkció |
1 2 3 4 5 6 15 26 31 32 33 34 35 36 37 38 39 40 |
csere törlés kivonás szorzás osztás hatványozás összeadás beolvasás színusz koszinusz tangens Arcsin Arccos Arctg In exp INT négyzetgyök stb. |
A lebegőpontos kalkulátorral kapcsolatos ROM rutinok:
Ehhez a témához tartozik még a kvázi-véletlenszám generálása, amely a ROM-ban a 9725-ős (25FDH) címen található. A ROM-beli rutin számos olyan dolgot is csinál, amire gyakran nincs szükség, éppen ezért közöljük a számítás rövid lényegét.
7530 7530 ED4B765C 7534 CD2B2D 7537 EF 7538 A1 7539 0F 753A 34 753B 37 753C 16 753D 04 753E 34 753F 80 7540 41 7541 00 7542 00 7543 80 7544 32 7545 02 7546 A1 7547 03 7548 31 7549 38 754A CDA22D 754D ED43765C 7551 C9 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
ORG 30000 LD BC,(23670) CALL 11563 RST 40 DEFB 161 DEFB 15 DEFB 52 DEFB 55 DEFB 22 DEFB 4 DEFB 52 DEFB 128 DEFB 65 DEFB 0 DEFB 0 DEFB 128 DEFB 50 DEFB 2 DEFB 161 DEFB 3 DEFB 49 DEFB 56 CALL 11682 LD (23670) RET |
; RND rutin ; Betöltjük a BC-be ; a 'SEED' nevű ; rendszerváltozó értékét, ; majd onnan a ; kalkulátor verembe, ; meghívjuk a ; lebegőpontos kalkulátort. ; 1 a veremben, ; SEED+1 a veremben, ; adat következik, ami ; 75. ; 75*(SEED)+1 a ; veremben, ; adat következik, ami ; 65537, ; 75*(SEED+1)/65537 ; maradéka a veremben ; a törlés után ; 1 a veremben, ; (maradék-1) a ; veremben, ; duplikálva a szám, ; a számítás vége. ; Az eredményt visszük ; a BC-be, majd onnan ; vissza a 'SEED' nevű ; rendszerváltozóba. ; Vége! |
BASIC szerkesztés
A Spectrumon való BASIC programozást ügyes ROM-beli rutinok segítik. Ezek beépítése saját gépi kódú programjainkba még hatékonyabbá teheti a programszerkesztést. A Spectrumban a BASIC terület kezdetét jelentő címet a PROG nevű rendszerváltozó, a végét jelentőt pedig a VARS nevű rendszerváltozó hordozza (pontosabban szólva a VARS-ban már eggyel nagyobb cím van). A következő ROM rutinok legtöbbje is ezzel a tartománnyal foglalkozik:
1. Helycsináló rutin
Cím: 5717 (1655H). Belépő paraméterek:
- a HL azt a címet tartalmazza, amely után a hely kell,
- a BC a hely hosszát tartalmazza.
Ha csak egyetlen helyre van szükségünk, a belépési cím: 5714 (1652H) lesz, és BC tartalma természetesen érdektelen.
Visszatérési paraméterek:
- a HL tartalma változatlan,
- a DE az előállított hely kezdetére mutat, tehát (DE) = (HL) +1.
2. BASIC-beli számjelző rutin
Cím: 6326 (18B6).
Belépő paraméterek:
- a HL egy BASIC-beli címet tartalmaz,
- az A az e címen található értéket tartalmazza.
Visszatérési paraméterek:
- ha ez az érték nem a számjelző (kódja 14), akkor visszatéréskor a regiszter tartalma változatlan,
- ha ez az érték a számjelző, akkor a HL cím hattal nő, és az e címen lévő érték töltődik A-ba.
3. Sorléptető rutin
Cím: 6415 (190FH). Belépő paraméterek:
- a HL az E PPC (23625) vagy az S TOP (23660) rendszerváltozók címét tartalmazza.
Ezekben a rendszerváltozókban pedig egy adott sor sorszáma van.Kilépési paraméterek:
- a rutin meghívása után a megfelelő rendszerváltozó a következő sor sorszámát tartalmazza.
Ha a rutin meghívásakor ilyen sorszám nem létezett, akkor a rendszerváltozó visszatéréskor a legközelebbi nagyobb, de már tényleges sorszámot tartalmazza. Ha az indulási paraméterként megadott sorszám a BASIC program utolsó sorszáma vagy ennél nagyobb, akkor visszatéréskor a rendszerváltozóba az utolsó BASIC-sor sorszáma kerül.
4. Sorcímkereső rutin
Cím: 6510 (196EH).
Belépő paraméterek:
- a HL a kívánt sorszámot tartalmazza.
Visszatérési paraméterek:
- a HL a sor kezdetének címét,
- a DE az előző sor kezdetének címét tartalmazza.
A pontatlanul megadott cím hatása hasonló, mint az előző, 3. rutinnál, de a Z jelzőbit 0 lesz.
5. Parancskereső rutin
Cím: 6536 (1988H).
Belépési paraméterek:
- a HL a vizsgálandó sor címét tartalmazza,
- a D a parancs sorszámát tartalmazza,
- az E a parancs kódját tartalmazza.
Visszatérési paraméterek:
- a HL azt a címet tartalmazza, amely után a kérdéses parancs áll.
6. A "következőt" kereső rutin
Cím: 6584 (19B8H).
A rutin megkeresi a következő sort vagy a változók területén a következő változó címét.
Belépési paraméterek:
- a HL az indulási (régi) címet tartalmazza.
Kilépési paraméterek:
- a HL változatlan,
- a DE az új címet tartalmazza,
- a BC a két cím közötti rész (például a sor) hosszát tartalmazza.
7. Különbségi hosszúságot képző rutin
Cím: 6621 (19DDH).
Belépési paraméterek:
- a HL a magasabb értéket tartalmazza,
- a DE az alacsonyabb értéket tartalmazza.
Kilépési paraméterek:
- a HL az alacsonyabb értéket tartalmazza,
- a DE a magasabb értéket tartalmazza,
- a BC a két érték különbségét tartalmazza.
8. Helymegszüntető rutin
Cím: I. 6629 (19E5H); II. 6632 (19E8H).
Ennek a rutinnak a hatása éppen ellentétes az 1-es rutin hatásával.
Belépési paraméterek:
I. eset:
- a HL az első el nem tüntetendő hely címét tartalmazza,
- a DE az első eltüntetendő hely címét tartalmazza.
II. eset:
- a HL az első eltüntetendő hely címét tartalmazza,
- a BC az eltüntetendő hely hosszát tartalmazza.
9. A szabad memóriaterületet meghatározó rutin
Cím: 7962 (1F1A).
Belépési paraméter nincs, kilépéskor a hasznos információkat a BC regiszterpár tartalmazza.
BASIC-ből is közvetlenül hívható:PRINT 65536 - USR 7962
utasítással, és ilyenkor a képernyőn megjelenik a még szabad terület hozzávetőleges hossza.
Lássunk most egy-két példát:
Blokktörlő rutin
A rutin két adott sorszámú sor közötti részt - a határokat is beleértve - töröl. Előzetesen gondoskodni kell arról, hogy a később beadott sorszám legyen a nagyobb. Sőt, most az egyszerűség kedvéért feltesszük, hogy a beadott sorszámok tényleges soroknak felelnek meg. Mindezek természetesen - akár gépi kódból is - könnyedén ellenőrizhetők, s hiba esetén egy hibakóddal a programot le lehet állítani.
A két sorszámot a program elején helyezzük el POKE utasítással!
5B00 5B00 005B 5B02 025B 5B04 2A005B 5B07 CD6E19 5B0A E5 5B0B 2A025B 5B0E 22495C 5B11 21495C 5B14 CD0F19 5B17 2A495C 5B1A EB 5B1B 21025B 5B1E A7 5B1F ED52 5B21 2807 5B23 CD6E19 5B26 D1 5B27 C3E519 5B2A 2A4B5C 5B2D 18F7 |
1 2 L1 3 L2 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 L4 25 26 27 L3 28 29 30 |
ORG 23296 DEFW N1 DEFW N2 ; ********** LD HL,(L1) CALL 6510 PUSH HL LD HL,(L2) LD (23625),HL LD HL,23625 CALL 6415 LD HL,(23625) EX DE,HL LD HL,12 AND A SBC HL,DE JR Z,L3 CALL 6510 POP DE JP 6629 LD HL,(23627) JR L4 |
; Nyomtató puffer ; Alacsonyabb sorszám. ; Magasabb sorszám. ; Betöltjük HL-be az ; alacsonyabb ; sorszámot. ; Megkeressük a címét, ; és kimentjük. ; Betöltjük a magasabb ; sorszámot és ; keresünk egy nála ; nagyobbat. ; Áttöltjük DE-be az ; újabb sorszámot és ; összehasonlítjuk a ; korábbival. ; Ha megeggyezik, akkor ; ugrás előre, ha nem, ; akkor kikeressük a ; címét, mint az imént ; visszahozzuk a másik ; címet és a törlő- ; rutinon át vissza. ; A BASIC végén voltunk, ; ezért a 'VARS' ; cím kerül a magasabb ; cím helyére. |
Átszámozó rutin
Nagyon egyszerű, ezért nem minden igényt kielégítő rutin. Fő gyengesége, hogy nem ad új értékeket a GO TO, GO SUB stb. utáni számoknak. Csak tízesével számoz át 10-tol indulva, bár ezen a kívánt érték megfelelő címre való eljuttatásával (POKE) lehet segíteni. Nem lehet vele résztartományt átszámozni, csak az egész programot. Ellenőrzés is csak minimális van benne: van-e egyáltalán BASIC program a gépben, és a BASIC memóriatartomány végére jutottunk-e?
7530 7530 2A535C 7533 EB 7534 2A555C 7537 A7 7538 ED52 753A CB 753B EB 753C 010A00 753F 70 7540 23 7541 71 7542 23 7543 210A00 7546 09 7547 44 7548 4D 7549 EB 754A 5E 754B 23 754C 56 754D 19 754E 23 754F ED5B4B5C 7553 EB 7554 ED52 7556 2803 7558 EB 7559 18E4 755B C9 |
1 2 3 4 5 6 7 8 9 10 11 12 13 L1 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 L2 |
ORG 30000 LD HL,(23635) EX DE,HL LD HL,(23637) AND A SBC HL,DE RET Z EX DE,HL LD BC,10 LD (HL),B INC HL LD (HL),C INC HL LD HL,10 ADD HL,BC LD B,H LD C,L EX DE,HL LD E,(HL) INC HL LD D,(HL) ADD HL,DE INC HL LD DE,(23627) EX DE,HL SBC HL,DE JR Z,L2 EX DE,HL JR L1 RET |
; Átsorszámozó rutin. ; Megvizsgáljuk, ; van BASIC? ; C jelzőbit törölve. ; Vége, ha nincs BASIC ; HL a BASIC tartomány ; elejére mutat. ; Betöltjük az induló ; címet. ; Betöltjük az induló ; és valamennyi ; további sorszámot.
|
Megszakítás
A teljességre törekedve az alábbiakban a megszakítás kezelésére bemutatunk egy igen egyszerű programot. A program egyszerűsége ellenére - a megszakítási hatás lenyűgöző volta miatt - igen látványos.
FE69 FE69 FF FE6A F3 FE6B C5 FE6C D5 FE6D E5 FE6E F5 FE6F 3E7F FE71 DBFE FE73 FEFC FE75 CC7EFE FE78 F1 FE79 E1 FE7A D1 FE7B C1 FE7C FB FE7D C9 FE7E 2A535C FE81 EB FE82 2A555C FE85 A7 FE86 ED52 FE88 C8 FE89 EB FE8A 010A00 FE8D 70 FE8E 23 FE8F 71 FE90 23 FE91 210A00 FE94 09 FE95 44 FE96 4D FE97 EB FE98 5E FE99 23 FE9A 56 FE9B 19 FE9C 23 FE9D ED5B4B5C FEA1 EB FEA2 ED52 FEA4 2803 FEA6 EB FEA7 18E4 FEA9 C9 FEAA 3E3F FEAC ED56 FEAE ED47 FEB0 C9 FEB1 3E09 FEB3 ED47 FEB5 ED5E FEB7 C9 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 REN 28 29 30 31 32 33 34 35 36 37 L1 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 L2 63 64 65 66 67 68 69 70 71 |
ORG 65129 RST 56 DI PUSH BC PUSH DE PUSH HL PUSH AF LD A,127 IN A,(254) CP 252 CALL Z,REN POP AF POP HL POP DE POP BC EI RET ; ************ LD HL,(23635) EX DE,HL LD HL,(23637) AND A SBC HL,DE RET Z EX DE,HL LD BC,10 LD (HL),B INC HL LD (HL),C INC HL LD HL,10 ADD HL,BC LD B,H LD C,L EX DE,HL LD E,(HL) INC HL LD D,(HL) ADD HL,DE INC HL LD DE,(23627) EX DE,HL SBC HL,DE JR Z,L2 EX DE,HL JR L1 RET ; ************ LD A,63 IM 1 LD I,A RET LD A,9 LD I,A IM 2 RET |
; 2-es megszakítási ; mód lévén külön ; gondoskodni kell a ; billentyűzettel kapcso- ; latos funkciókról. ; Letiltjuk a ; megszakítást és ; kimentjük a regisz- ; tereket, hogy ; visszatéréskor ugyanez ; legyen az állapot. ; Levizsgáljuk a ; billentyűzetet. ; Ha egyszerre lenomjuk ; a SYMBOL SHIFT ; és a SPACE billentyűket ; meghívjuk az ; átsorszámozási rutint. ; Visszatöltjük a ; regisztereket és ; lehetővé tesszük ; a megszakítást ; Vissza! ; Megvizsgáljuk, ; van-e BASIC? ; A C jelzőbit törölve. ; Vége, ha nincs BASIC! ; HL a BASIC tartomány ; elejére mutat ; Betöltjük az induló ; címet. ; Betöltjük az induló ; és valamennyi ; további sorszámot. ; Betöltjük a sorszám- ; növekményt. ; Előállítjuk a következő ; sorszámot ; BC-ben. ; DE-be betöltjük ; az adott BASIC sor ; hosszát. ; Ezzel növeljük HL-t. ; HL most az új sor ; vagy választerület ; elejére mutat. ; A C jelzőbit ; biztosan 0! ; Ha a végére értünk, ; ugrás előre ; ha nem, akkor ; vissza. ; Vége! ; 1-es megszakítási- ; mód-kapcsoló rutin. ; ; 2-es megszakítási- ; mód-kapcsoló rutin. |
A program az előző átszámozó rutint szubrutinként használja. Az I regiszterbe 9-et tölt, így a megszakítási ugrás a 65129 címre történik. 16 k-s Spectrumon az utasításoknál leírtak alapján például a 6-os használható, de akkor a programot értelemszerűen át kell címezni (pl. CALL stb. utasítások után!). A program betöltése előtt egy CLEAR 65128 utasítással biztosítsuk a gépi kódú program háborítatlanságát, majd a 65129-es címtől folyamatosan töltsük be!
A program RANDOMIZE USR 65201 utasítással be-, RANDOMIZE USR 65194 utasítással kikapcsolható.
Függelékek
A függelék - A BASIC feladatok megoldásai
Ebben a részben a 3. fejezet feladatainak megoldásait közöljük. A feladatoknak általában több - a közöltnél rövidebb - megoldása is lehet.
1. feladat
10 REM 1. feladat
20 LET x=(a+b)*(a-b)
30 LET s=(h^n-1)/(n-1)
40 LET z=2/(b-c^0.5)
50 LET t=(15*b*x-10*a*x)/(12*a*y-18*b*y)
60 LET y=(a*a+a^3+a^4+a^5)/(b^5-b^4-b^3-b^2)
2. feladat
10 REM 2. feladat
20 REM haromszog kerulete, terulete
30 LET a=3
40 LET b=4
50 LET c=5
60 LET k=a+b+c
70 LET s=k/2
80 LET t=(s*(s-a)*(s-b)*(s-c))^0.5
90 PRINT "A haromszog oldalai ";a;" ";b;" ";c
100 PRINT "A haromszog kerulete: ";k
110 PRINT "A haromszoq terulete: ";t
3. feladat
10 REM 3. feladat
20 REM haromszog kerulete, terulete
30 LET a=3
40 LET b=4
50 LET c=5
60 LET k=a+b+c
65 IF a>=b+c OR b>=a+c OR c>=a+b THEN PRINT "NINCS ILYEN HA ROMSZOG: ";a;" ";" ";b;" ";c: GO TO 120
70 LET s=k/2
80 LET t=(s*(s-a)*(s-b)*(s-c))^0.5
90 PRINT "A haromszog oldalai ";a;" ";b;" ";c
100 PRINT "A harooszog kerulete: ";k
110 PRINT "A haromszog terulete: ";t
120 PRINT "VEGE"
4. feladat
10 REM 4. feladat
20 REM masodfoku egyenlet megoldasa
30 LET a=1
40 LET b=-7
50 LET c=12
60 IF a=0 THEN PRINT "NEM MASODFOKU": GO TO 130
70 IF b*b-4*a*c<0 THEN PRINT "NINCS VALOS MEGOLDAS": GO TO 130
80 IF b*b-4*a*c=0 THEN PRINT "CSAK EGY MEGOLDAS VAN",-b/(2*a): GO TO 130
90 LET d=(b*b-4*a*c)^0.5
100 LET x1=(-b+d)/(2*a)
110 LET x2=(-b-d)/(2*a)
120 PRINT "x1=",x1,"x2=",x2
130 PRINT "VEGE"
5. feladat
10 REM 5. feladat
20 REM Fibonacci sor: 0 1 1 2 3 5 8
30 PRINT "HANYADIK","ERTEK"
40 LET a=0
50 LET b=1
60 PRINT 1;".",a
70 PRINT 2;".",b
80 LET i=2
90 LET i=i+1
100 LET c=a+b
110 PRINT i;".",c
120 If i<20 THEN LET a=b: LET b=c: GO TO 90
6. feladat
10 REM 6.feladat
20 REM faktorialis pl.: 5 faktorialis=1*2*3*4*5
30 LET n=5
40 LET f=1
50 LET i=1
60 LET f=f*i
70 LET i=i+1
80 IF i<=n THEN GO TO 60
90 PRINT n;" faktcrialis= ";f
7. feladat
10 REM 7. feladat
20 REM masodfoku egyenlet megoldasa
30 INPUT "Kerem a masodfoku egyenlet egyutthatoit! (a*X*X+b*X+c)","a=",a,"b=",b,"c=",c
60 IF a=0 THEN PRINT "NEM MASODFOKU": GO TO 130
70 IF b*b-4*a*c<0 THEN PRINT "NINCS VALOS MEGOLDAS": GO TO 130
80 IF b*-4*a*c=0 THEN PRINT "CSAK EGY MEGOLDAS VAN",-b/(2*a): GO TO 130
90 LET d=(b*b-4*a*c)^0.5
100 LET x1=(-b+d)/(2*a)
110 LET x2=(-b-d)/(2*a)
120 PRINT "x1=",x1,"x2=",x2
130 INPUT "Folytassuk? (i/n)",v$
140 IF v$="i" OR v$="I" THEN CLS : GO TO 30
8. feladat
10 REM 8. feladat
20 REM faktorialis / 2
30 INPUT "Hany faktorialist szamoljon (1-33)",n
40 IF n<1 OR n>33 THEN GO TO 30
50 LET f=1
60 FOR i=1 TO n
70 LET f=f*i
80 NEXT i
90 PRINT n;" faktorialis=";f
9. feladat
10 REM 9. feladat
20 REM 3-mal oszthato szamok osszege
30 LET sum=0
40 FOR i=3 TO 3000 STEP 3
50 LET sum=sum+i
60 NEXT i
70 PRINT sum
10. feladat
10 REM 10. feladat
20 REM Fibonacci szamok
30 LET a=0
40 LET b=1
50 PRINT "HANYADIK","SZAM"
60 PRINT 1,0,2,1
70 FOR i=3 TO 20
80 LET c=a+b
90 PRINT i,c
100 LET a=b
110 LET b=c
120 NEXT i
11. feladat
10 REM 11. feladat
20 REM 3 jegyu szamok /csak paratlan szamokbol/
30 FOR i=1 TO 9 STEP 2
40 FOR j=1 TO 9 STEP 2
50 FOR k=1 TO 9 STEP 2
60 PRINT i;j;k
70 NEXT k
80 NEXT i
90 NEXT i
12. feladat
10 REM 12. feladat.
20 REM atszamitasi tablazat
30 PRINT "Merf. km km merfold"
40 FOR i=10 TO 90 STEP 10
30 PRINT i;" ";i*1.60933,i;" ";;i/1.60933
60 NEXT i
13. feladat
10 REM 13. feladat
20 REM tomb kiiratasa
30 DIM t(10)
40 FOR i=1 TO 10
50 INPUT "Kerem a tomb ";(i);". elemet ";t(i)
60 NEXT i
70 PRINT "A tomb elemei, elolrol"
80 FOR i=1 TO 10
90 PRINT i;".",t(i)
100 NEXT i
110 PRINT "A tomb elemei, visszafele"
120 FOR i=10 TO 1 STEP -1
130 PRINT i;".",t(i)
140 NEXT i
14. feladat
10 REM 14. feladat
20 REM arbevetel
30 DIM e(10)
40 DIM m(10)
50 LET bev=0
60 FOR i=1 TO 10
70 INPUT "Kerem az ",(i);". egysegarat es mennyiseget",e(i);
80 LET bev=bev+e(i)*m(i)
90 NEXT i
100 PRINT "Az osszes arbevetel:",bev
15. feladat
10 REM 15. feladat
20 REM maximumkereses
30 DIM a(10)
40 FOR i=1 TO 10
50 INPUT "Kerem a ";(i);". elemet ";a(i)
68 NEXT i
70 LET max=a(1)
80 PRINT "A tomb elemei:"
90 FOR i=1 TO 10
100 PRINT i;".",a(i)
110 IF a(i)>max THEN LET max=a(i)
120 NEXT i
130 PRINT "A legnagyobb elem ";max
16. feladat
10 REM 16. feladat
20 REM tomb rendezese (novekvo)
30 DIM a(10)
40 FOR i=1 TO 10
50 INPUT "Kerem az ";(i);". tombelemet",a(i)
60 NEXT i
70 PRINT "A rendezetlen tomb:"
80 FOR i=1 TO 10
90 PRINT i;".",a(i)
100 NEXT i
110 REM most jon a rendezes
120 FOR i=1 TO 9
130 FOR j=i+1 TO 10
140 IF a(i)<=a(j) THEN GO TO 180
150 LET m=a(i)
160 LET a(i)=a(j)
170 LET a(j)=m
180 NEXT j
190 NEXT i
200 PRINT "A rendezett tomb:"
210 FOR j=1 TO 10
220 PRINT j;".",a(j)
230 NEXT j
17. feladat
10 REM 17. feladat
20 REM 2 dimenzios tomb
30 DIM a(4,3)
40 FOR i=1 TO 4
50 FOR j=1 TO 3
60 LET a(i,j)=i
70 NEXT j
80 NEXT i
90 REM kiiras
100 FOR i=1 TO 4
110 FOR j=1 TO 3
120 PRINT a(i,j);" ";
130 NEXT j
140 PRINT
150 NEXT i
18. feladat
10 REM 18. feladat
20 REM 2 dimenzios tomb
30 DIM a(4,3)
40 FOR j=1 TO 3
50 FOR i=1 TO 4
60 LET a(i,j)=j
70 NEXT i
80 NEXT j
90 REM kiiras
100 FOR i=1 TO 4
110 FOR j=1 TO 3
120 PRINT a(i,j);" ";
130 NEXT j
140 PRINT
150 NEXT i
19. feladat
10 REM 19. feladat
20 REM nevsorba rendezes
30 DIM n$(50,20)
40 INPUT "Hany nev lesz (3-50)",n
50 IF n<3 OR n>50 THEN GO TO 40
60 FOR i=1 TO n
70 INPUT "Keres az ";(i);". nevet",n$(i)
80 NEXT i
90 FOR i=1 TO n-1
100 FOR j=i+1 TO n
110 IF n$(i)<n$(J) THEN GO TO 150
120 LET m$=n$(i)
130 LET n$(i)=n$(j)
140 LET n$(j)=m$
150 NEXT j
160 NEXT i
170 PRINT "A nevsor:"
180 FOR i=1 TO n
190 PRINT n$(i)
200 NEXT i
20. feladat
10 REM 20. feladat
20 REM masodfoku egyenlet
30 INPUT "Kerem az egyutthatokat","a=";a;" b=";b;" c=";c
40 IF a<>0 THEN GO TO 70
50 GO SUB 1000
60 GO TO 150
70 LET d=b*b-4*a*c
80 IF d>=0 THEN GO TO 110
90 GO SUB 1100
100 GO TO 150
110 IF d>0 THEN GO TO 140
120 GO SUB 1200
130 GO TO 150
140 GO SUB 1300
150 INPUT "Kell meg szamolni (i/n)";v$
160 IF v$="I" THEN CLS : GO TO 30
170 STOP
1000 REM *****nem masodfoku
1010 PRINT "Ez nem masodfoku egyenlet"
1020 GO SUB 1500
1030 RETURN
1100 REM *****nincs valos gyok
1110 PRINT "NINCS VALOS MEGOLDAS"
1120 GO SUB 1500
1130 RETURN
1200 REM *****csak 1 megoldas van
1210 GO SUB 1500
1220 PRINT "CSAK 1 MEGOLDAS VAN:";-b/2/a
1230 RETURN
1300 REM *****2 valos megoldas:
1310 GO SUB 1500
1320 LET d=d^0.5
1330 LET x1=(-b+d)/(2*a)
1340 LET x2=(-b-d)/(2*a)
1350 PRINT "x1=";x1,"x2=";x2
1360 RETURN
1500 REM *****egyutthatok kiirasa
1510 PRINT "a=";a;" b=";-b;" c=";c
1520 RETURN
21. feladat
10 REM 21. feladat
20 REM sorozat osszege
30 INPUT "Kerem X erteket ";x
40 LET s=x
50 LET j=0
60 FOR i=3 TO 15 STEP 2
70 LET j=j+1
80 GO SUB 1000
90 LET h=x^i/f
100 IF -1^j<0 THEN LET h=-h
110 LET s=s+h
120 NEXT i
130 PRINT s
140 STOP
1000 LET n=i
1010 LET f=1
1020 FOR k=1 TO n
1030 LET f=f*k
1040 NEXT k
1050 RETURN
22. feladat
10 REM 22. feladat
20 REM parabolarajzolas
30 LET xel=1
40 LET yel=i
50 INPUT "Szorzok: x=";xa;" y=";ya,"eltolas: x=";xelt;" y=";yelt,"hatarok: also=";a;" felso=";f
60 IF xa<>0 THEN LET xel=xa
70 IF ya<>0 THEN LET yel=ya
80 FOR x=a TO f
90 LET vizsz=xa*x+xelt
100 LET fugg=ya*x*x+yelt
110 IF vizsz<0 OR vizsz>31 THEN GO TO 140
120 IF fugg<0 OR fugg>21 THEN GO TO 140
130 PRINT AT 21-fugg,vizsz;"*";
140 NEXT x
150 PRINT AT 0,0;"x szorzo:";xel;" eltolass";xelt
160 PRINT AT 1,0;"y szorzo:";yelt;" eltolass";yelt
23. feladat
10 REM 23. feladat
20 REM grafikon rajzolasa
30 DIM a(5,2)
40 INPUT "Kerem az osztalyzatokat","Negativ szam: vege az adatbevi- telnek",,n
50 IF n>5 OR n=0 THEN GO TO 40
60 IF n<0 THEN GO TO 90
70 LET a(n,1)=a(n,1)+1
80 GO TO 40
90 LET n=0
100 FOR i=1 TO 5
110 LET n=n+a(i,1)
120 NEXT i
130 IF n=0 THEN STOP
140 FOR i=1 TO 5
150 LET a(i,2)=a(i,1)*100/n
160 NEXT i
170 LET t$="*"
180 PRINT "osztalyzatok "
190 PRINT "jegy";TAB 4;"db.";TAB 7;"%"
200 FOR i=1 TO 5
210 PRINT i;TAB 4;a(i,1);TAB 7;a(i,2);TAB 19;"I";
220 FOR j=1 TO a(i,2) STEP 10
230 PRINT TAB 20+j/10;t$;
240 NEXT j
250 PRINT
260 NEXT i
24. feladat
10 REM 24. feladat
20 REM magyar zaszlo
30 CLS
40 FOR i=0 TO 7
50 FOR j=0 TO 31
60 PRINT AT i,j; INK 2;"X";
70 NEXT j
80 NEXT i
90 FOR i=14 TO 21
100 FOR j=0 TO 31
110 PRINT AT i,j; INK 4;"X:";
120 NEXT j
130 NEXT i
140 FOR i=64 TO 111
150 PLOT 0,i: PLOT 255,i
160 NEXT i
25. feladat
10 REM 25. feladat
20 REM parossag vizsgalata
30 INPUT "Kerek egy egesz szamot: ";n
40 IF n=2*INT (n/2) THEN PRINT n,"paros": STOP
50 PRINT n,"paratlan"
26. feladat
10 REM 26. feladat
20 REM penzvaltas
30 DATA 1000,500,100,50,20,10,5,2,1,0.5,0.2,0.1
40 DIM p(12)
50 FOR i=1 TO 12
60 READ p(i)
70 NEXT i
80 INPUT "A felvaltando osszeg:";p
90 LET p=ABS p
100 PRINT "A penz: ";p;" felvaltva:"
110 FOR i=1 TO 12
120 LET m=INT (p/p(i))
130 PRINT m;" darab ";p (i)
140 LET p=p-m*p(i)
150 NEXT i
27. feladat
10 REM 27. feladat
20 REM fej vagy iras szimulacio
30 DIM f(2)
40 LET n=10
50 GO SUB 500
60 PRINT "Dobasok szama: ";n,"fej= ";f(1);" ez ";f(1)*100/n;" %","iras= ";f(2);" ez ";f(2)*100/n;" %"
70 IF n<1e4 THEN LET n=n*10: GO TO 50
80 STOP
500 REM ez a lenyeg
510 LET f(1)=0
520 LET f(2)=0
530 FOR j=1 TO n
540 LET v=INT (1+RND*2)
550 LET f (v) =f (v)+1
560 NEXT j
570 RETURN
28. feladat
10 REM 28. feladat
20 REM felhasznaloi fuggveny
30 DEF FN s(x)=(EXP x-EXP -x)/2
40 DEF FN c(x)=(EXP x+EXP -x)/2
50 IMPUT "Kerem a fuggetlen valtozot ";n
60 PRINT "s= ";FN s(n);" c= ";FN c(n)
B függelék - A ZX SPECTRUM hibakódjai
Kód | Angol szöveg | Magyar jelentés |
0 | OK | A parancs vagy a program sikeres befejezése |
1 | NEXTwithout FOR | NEXT FOR nélkül |
2 | Variable not found | A változó még nincs meghatározva |
3 | Subscript wrong | Rosszak a határok a dimenzionált változóknál |
4 | Out of memory | Nincs elég memória |
5 | Out of screen | Kísérlet képernyőn kívüli írásra |
6 | Number big | A szám túl nagy |
7 | RETURN without GOSUB | RETURN GO SUB nélkül |
8 | End of file | Az állomány vége (microdrive-nál) |
9 | STOP statement | STOP utasítás |
A | Invalid argument | A függvény bemenő adata hibás |
B | Integer out of range | Az egész szám kiesik az ábrázolható tartományból |
C | Nonsense in BASIC | A BASIC-ben értelmetlen |
D | BREAK-CONT repeats | A BREAK billentyűt nyomtuk meg, a CONT hatására folytatódik |
E | Out of DATA | A READ utasítással több adatot próbáltunk kiolvasni, mint amennyi a DATA-ban volt |
F | Invalid file name | Hibás állománynév; a SAVE parancsnál üres karaktert vagy 10 karakternél hosszabb nevet adtunk meg |
G | No room for line | A memóriában nincs elég hely az új sor fogadására |
H | STOP in INPUT | STOP utasítás az INPUT-ban |
I | FOR without NEXT | FOR NEXT nélkül |
J | Invalid I/O device | Hibás B/K eszköz |
K | Invalid colour | Hibás színkód |
L | BREAK into program | A program végrehajtása során a BREAK billentyűt nyomtuk meg |
M | RAMTOP no good | A RAMTOP nevű rendszerváltozó hibás értéket kapott |
N | Statement lost | Az utasítás elveszett |
O | Invalid stream | Hibás csatorna |
P | FN without DEF | Az FN nincs meghatározva |
Q | Parameter error | Paraméterhiba az FN-nél |
R | Tape loading error | Hiba a mágnesszalagról való betöltéskor |
Egy szám adott számrendszerbeli ábrázolása azt jelenti, hogy a számot a számrendszer alapját jelentő szám hatványosaként állítjuk elő. Például a tízes számrendszerben a 6347
6*1000 + 3*100 + 4*10 + 7*1,
azaz
6*10^3 + 3*10^2 + 4*10^1 + 7*10^0
előállítást jelent.
A számítástechnikai gyakorlatban a 2-es és a 16-os (esetleg a 8-as) számrendszernek van nagyabb jelentősége. Így itt csak ezekkel foglalkozunk.
A kettes számrendszerben használható számjegyek a 0 ésaz 1, a 8-as számrendszerben a 0-tól 7-ig, a 16-os számrendszerben pedig a 0-tól 15-ig terjedő számok. Mivel a 10, a 11 stb. a 16-os számrendszerben egy helyértéknek felel meg, a kővetkező jelölést használjuk:
10 = A,
11 = B,
12 = C,
13 = D,
14 = E,
15 = F.
A 10-es számrendszerből bármilyen más számrendszerre való áttérés egyik, talán legegyszerűbb módja az ismételt osztás. Az eljárás a következő: a más számrendszerben ábrázolni kívánt számot addig osztjuk a számrendszer alapjával, amíg a hányados 0 nem lesz. A kapott maradékokat ezután fordított sorrendben leírjuk.
A 10-es számrendszerre közvetlen számolással lehet visszatérni.
Példakánt határozzuk meg a mér említett 6347 16-os számrendszerbeli megfelelőjét!
6347 / 16 = 396
11 = B396 / 16 = 24
12 = C24 / 16 = 1
81 / 16 =0
1
Tehát
634710 = 18CB16
Az 18CB16 jelölés helyett a számítástechnikában az 18CBH-t használjuk.
D függelék - A könyvben használt ZX Spectrum ROM rutinok
Ebben a részben röviden összefoglaljuk a könyvben, felhasznált ROM rutinokat az alábbi formában:
1 | 0 (0000), bekapcsolási rutin, -, -, -- |
2 | 8 (0008), hibakezelési rutin, -, -, hívás: RST 8, a hibakód utána adatként szerepel. |
3 | 16 (0010), karakternyomtatás, a kívánt értéket az A regiszter tartalmazza, -. hívás: RST 16. |
4 | 40 (0028), lebegőpontos kalkulátor, -, -, hívás: RST 40, a számolási utasítások utána adatként szerepelnek. |
5 | 56 (0038), a letiltható megszakítást kezelő rutin, -, -, hívás: RST 56, lépteti a belső órát és figyeli a billentyűzetet. |
6 | 654 (028E), billentyűzetfigyelő rutin, -, a billentyűzet állapotát a DE regiszterpár és a Z jelzőbit jelzi, -. |
7 | 703 (02BF), billentyűzetfigyelő ás dekódoló rutin, -, a kódot az A regiszter és a megfelelő rendszerváltozók tartalmazzák, -. |
8 | 949 (03B5), BEEP rutin, a hanghatás hosszára és magasságára vonatkozó adatokat a HL és a DE regiszterpár tartalmazza, -, a rutin letiltja a megszakítást. |
9 | 1366 (0556), magnetofonról történő adatbetöltő rutin, az IX címregiszter a kezdőcímet tartalmazza, a DE regiszterpár a hosszat, a C jelzőbit 1, hiba esetén a Z jelzőbit 1, a rutin letiltja a megszakítást. |
10 | 3330 (0D02), teljesképernyő-mozgatás, -, -, -. |
11 | 3435 (0D6B ), teljesképernyő-törlés, -, -, -. |
12 | 3545 (ODD9), képernyő-címbeállítás, az első karakter pozíciójának megfelelő sor, illetve oszlop vonatkozású értéket a B és a C regiszter tartalmazza, -, -, -. |
13 | 3582 (0DFE), egysornyi képernyőmozgatás, -, -, -. |
14 | 3583 (0DFF), a képernyő aljának mozgatása, -, -, a felső 10 sor változatlan. |
15 | 3684 (0E00), a képernyő aljának mozgatása -, -, a felső 9 sor változatlan. |
16 | 3652 (0E44), a képernyő aljának törlése, -, -, a felső 9 sor változatlan. |
17 | 5688 (1504), billentyűlenyomást váró rutin, -, -, hívása előtt a SET 5, (IY+2) utasításra van szükség. |
18 | 5833 (1601), csatornanyitó rutin, a kívánt csatornára vonatkozó értéket az A regiszter tartalmazza, -, -. |
19 | 5714 (1652), helycsináló rutin egy helyre, az a cím, amely után a hely kell, a HL regiszterpárban van, -, -. |
20 | 5717 (1655), helycsináló rutin, az a cím, amely után a hely kell, a HL regiszterpárban van, a BC regiszterpár pedig a kívánt helyek számát tartalmazza, -, -. |
21 | 6326 (18B6), számjelző rutin, a HL regiszterpár a BASIC terület címét, az A regiszter a címen lévő karakterkódot tartalmazza, a HL és az A változatlan, ha a kód nem számjelző (14), egyébként a HL hattal nő, az A-ban pedig az új helynek megfelelő kód lesz, -. |
22 | 6415 (190F), sorléptető rutin, a H L regiszterpár az S-TOP vagy az E-PPC rendszerváltozó címét tartalmazza, a hivatkozott rendszerváltozóban a következő sorszám lesz, -. |
23 | 6510 (196E), sorcím-kereső rutin, a HL regiszterpár a sorszámot tartalmazza, a H L-ben a sor címe, a DE-ben az előző sor címe lesz, -. |
24 | 6536 (1988), utasításkereső rutin, a HL regiszterpár a BASIC-sor címét, a D a soron belüli utasításszámot, az E pedig a karakterkódot tartalmazza, a H L-ben a keresett cím lesz, -. |
25 | 6584(19B8), a "következőt" kereső rutin, a H L regiszterpár az előző címet tartalmazza, a HL-ben az új cím, a DE-ben a régi cím, a BC-ben pedig e kettő különbsége lesz, a "következő" akár kővetkező BASIC-sor, akár kővetkező változó lehet. |
26 | 6621 (19DD), különbségképző rutin, a HL regiszterpár a nagyobb, a DE regiszterpár pedig a kisebb értéket tartalmazza, a BC-ben a különbség lesz, a HL és a DE regiszterpárok pedig értéket cserélnek, -. |
27 | 6629 (19E5), helymegszüntető rutin, a DE regiszterpár az első megszüntetendő hely címét, a HL regiszterpár az első maradó hely címét tartalmazza, -, -. |
28 | 6632 (19E8), helymegszüntető rutin, a HL regiszterpár az első megszüntetendő hely címét, a BC regiszterpár a megszüntetendő rész hosszát tartalmazza, -, -. |
29 | 6683 (1A1B), számkiíró rutin, a BC regiszterpár a kiíratandó számot (maximum 9999!) tartalmazza, -, előtte nyitás és pozícionálás kell. |
30 | 6696 (1A28), számkiíró rutin, a HL regiszterpár a kiíratandó szám címét (a szám maximum 9999 lehet!) tartalmazza, -, előtte nyitás és pozícionálás kell. |
31 | 7962 (1F1A), szabad memória rutin, -, a BC regiszterpár a már felhasznált terület hosszát tartalmazza, -. |
32 | 8020 (1F54), BREAK billentyű rutin, -, a C jelzőbit 0, amikor billentyűnyomás történik, -. |
33 | 8252 (203C), a szövegmező megjelenítése, a DE regiszterpár a szövegmező kezdőcímét, a BC regiszterpár pedig a szövegmező hosszát tartalmazza, -, előtte nyitás és pozícionálás kell. |
34 | 8859 (229B), a BORDER szín beállítása, az A regiszter a színkódot tartalmazza, -, -. |
35 | 8874 (22AA), képpont-(pixel) címet meghatározó rutin, a BC regiszterpár a képpont-koordinátákat tartalmazza, a HL regiszterpárban a memóriabeli cím, az A regiszterben pedig a bit sorszáma lesz, -. |
36 | 8933 (22E5), PLOT rutin, a BC regiszterpár a koordinátákat tartalmazza, -, -. |
37 | 9725 (25FD), RND rutin, -, -, -. |
38 | 10934 (2AB6), az A,E,D,C,B regiszterek tartalmát a lebegőpontos verembe vivő rutin, -, -, -. |
39 | 11249 (2BF1), a lebegőpontos verem tartalmát az A,E,D,C,B regiszterekbe vivő rutin, -, -, -. |
40 | 11563 (2D2B), a BC regiszterpár tartalmát a lebegőpontos verembe vivő rutin, -, -, -. |
41 | 11682 (2DA2), a lebegőpontos verem tartalmát a BC regiszterpárba vivő rutin, -, -, -. |
42 | 11747 (2DE3), a lebegőpontos verem tartalmát megjelenítő rutin, - - előtte nyitás és pozícionálás kell. |