mikroszámítógépes BASIC programozási nyelv From Wikipedia, the free encyclopedia
A Commodore BASIC vagy PET BASIC a BASIC programozási nyelvnek a Commodore International 8 bites személyi számítógépeiben használt dialektusa, az 1977-es PET-től az 1985-ös C128-asig. A nyelv alapját a 6502-es mikroprocesszoron futó Microsoft BASIC képezte, ezért sok közös vonása volt a kor más 6502-es BASIC-jeivel, mint amilyen az Applesoft BASIC is volt. A Commodore részéről Jack Tramiel egyszeri fizetéssel vásárolta meg a Microsofttól a BASIC korlátlan licenceit, azzal utasítva el Bill Gates 3 dolláros gépenkénti ajánlatát, hogy „már házas vagyok”, így összesen 25 000 dollárt költöttek az öröklicencre.[1]
A Commodore a megvásárolt BASIC forráskódot fejlesztette tovább a többi 8 bites személyi számítógépükre. Csak a Commodore 128 megjelenésével (a V7.0-nál) kezdték a Microsoft szerzői jogát megjeleníteni. A kód eredeti, a Commodore PET-en futó 2.0 verziójában lévő, a Microsoft által elrejtett üzenet (Easter egg) a WAIT 6502, 1
beírása után a Microsoft!
feliratot jelenítette meg a képernyőn. A kód jól el volt rejtve – az üzenetet nem látszott a parancsértelmező kódjában.[2]
A népszerű Commodore 64 a ROM-ba épített BASIC v2.0-val jelent meg, annak ellenére, hogy addigra a PET/CBM-sorozatban már a 4.0 változat is megjelent. Ennek oka az volt, hogy a 64-est otthoni számítógépnek szánták, míg a PET/CBM sorozatot üzleti és oktatási célra, ahol feltették, hogy a beépített programozási nyelv nagyobb használatnak lesz kitéve. Ez csökkentette a gyártási költségeket, mivel a V2-es kisebb ROM modulokban is elfért.
A Commodore memóriarezidens (ROM-ban tárolt) BASIC parancsértelmezőjének és KERNAL-jának kényelmes funkciója volt a teljes képernyős, szöveges szerkesztőfelület.[3][4] Bár a Commodore-ok billentyűzete csak két nyílbillentyűvel rendelkezett, melyek mozgatási irányát a shift lenyomásával lehetett megfordítani, a teljes képernyős szerkesztővel a képernyő bármely területén ki lehetett adni közvetlen parancsokat vagy szerkeszteni lehetett a programsorokat. Ha a képernyő egy sora számmal kezdődött, azt sorszámként értelmezte, és tokenizálás után a programmemóriában tárolta. A nem számmal kezdődő sorokat a RETURN
gomb megnyomása után végrehajtotta, amennyiben a kurzor éppen azon a soron tartózkodott. Ez jelentős előrelépés volt a korábbi otthoni számítógépek BASIC-jeinek beviteli felületéhez képest, melyek általában külön EDIT
paranccsal aktiválható sorszerkesztőt használtak vagy „copy cursort”, ami a kurzor pozíciójának megfelelő helyen egyetlen karaktert engedett módosítani.
Képes volt továbbá névvel ellátott fájlként elmenteni a programot bármilyen eszközre, köztük magnókazettára – ami népszerű tárolóeszköz volt a PET idejében, és a 8 bites Commodore gépek életciklusa alatt végig olcsó tömeges tárolóeszköznek számított. Analóg hangfelvételi médiaként széles körben elterjedtek voltak. A legtöbb rendszer csak mágneslemezen tette lehetővé fájlnevek használatát, ami a többi tárolóeszközön nehézkessé tette egynél több fájl lementését. A felhasználó annyit tehetett, hogy feljegyezte a magnó számlálójának a fájl kezdetekori állását, de ez pontatlan és bizonytalan megoldás volt. A PET (és a BASIC 2.0) megjelenésével lehetett a fájlokat név szerint bekérni a kazettáról. Az eszköz ilyenkor is szekvenciálisan olvasta a kazetta tartalmát, átlépve a megadottól eltérő fájlneveken. A kazettás tároláshoz hatékony rekordstruktúra is tartozott. A Commodore kazettákon digitálisan tárolták az adatokat, szemben az akkoriban gyakori, kevésbé megbízható (bár olcsóbb) analóg megoldásokkal. Ezért specializált kazettás egységet, a Commodore Datasette-et kellett használni. Léteztek a szokásos szalagos egység használatát lehetővé tevő analóg-digitális átalakítók, de ezek alig voltak olcsóbbak a Datasette-nél.
Mivel a Commodore ugyanazt a BASIC nyelvet használta különböző hardverarchitektúrákon, ezért a LOAD parancs egy paraméterével befolyásolni lehetett, hogy a program milyen memóriacímre töltődjön be. A
LOAD "*",8
parancs a programot a BASIC memóriaterület elejére tölti be, míg a
LOAD "*",8,1
parancs arra a területre, ahonnan elmentésre került. BASIC programoknál általában az első változatot alkalmazták, mivel a BASIC memóriaterülete az egyes modelleknél más-más volt. Egyes Commodore BASIC-változatok ismerték a BLOAD
és BSAVE
parancsokat, melyek – az Applesoft BASIC-beli megfelelőjükhöz hasonlóan – a megadott memóriaterületekről bittérképeket mentettek ki vagy töltöttek be oda.
A kiindulásul szolgáló Microsoft BASIC értelmezőhöz hasonlóan a Commodore BASIC is jóval lassabb a natív gépi kódnál. Tesztek szerint 16 kilobájtnyi adat ROM-ból RAM-ba történő másolása gépi kódban kevesebb mint egy másodpercet vesz igénybe, BASIC-ben pedig egy percnél is többet. A BASIC programok felgyorsítására a programozók különböző technikákat alkalmaztak. Az egyik az volt, hogy a gyakran használt lebegőpontos értékeket változókban tárolták, mert a változónevet gyorsabban dolgozta fel a parancsértelmező a konstans értékeknél. Mivel a lebegőpontos volt az alapértelmezett számformátum, gyorsabb volt az egész számok helyett ezeket használni. Egyes programozók a valóban sebességkritikus programhelyeket 6502-es vagy 6510-es assembly nyelvre konvertálták, a BASIC program végén található DATA kulcsszavakból a memóriába POKE-olták vagy külön fájlból betöltötték, és a SYS
BASIC paranccsal elindították (BASIC loader). Amikor pedig az assembly kód futási sebessége túl nagy, például egy számítógépes játékban, vagy amikor a program felhasználói adatbevitelre várakozik, programozott lekérést (polling) hajtanak végre a végrehajtás késleltetésére vagy felfüggesztésére, méghozzá a megfelelő memóriaterületek PEEK
-elésével (ez pl. $A6 a C-64-en vagy $D0 a C-128-on, ami a billentyűzet-várakozási sor méretére utal).
A Commodore BASIC kulcsszavai általában rövidíthetők az első karakter shift nélküli, majd a következő shifttel történő lenyomásával. Ez a karakter legfelső bitjét 1-re állítja, amire a parancsértelmező abbahagyja az olvasást és egy keresőtábla alapján próbálja értelmezni a kifejezést. Tehát a teljes parancs beírása helyett az első néhány karakter beírása elegendő. Mivel azonban az összes BASIC parancsszó a memóriában egybájtos tokenekként tárolódik, ezért ez csak a bevitelt teszi kényelmesebbé, a program tárolását nem optimalizálja.
Az alapértelmezett, csupa nagybetűs karakterkészletben a shiftelt karakterek grafikus szimbólumokként jelennek meg; például a GOTO
parancs G{Shift-O}
-ként rövidíthető (ami a képernyőn így mutatkozik: GΓ
). A legtöbb ilyen parancs kétbetűs, egyes esetekben hosszabb. Kétértelműség esetén több shifteletlen karaktert kellett beütni, például a GO{Shift-S}
(GO♥
) a GOSUB
parancsnál. Egyes parancsokat nem lehetett rövidíteni, rövidségük vagy más parancsokkal való összetéveszthetőségük miatt. Például az INPUT
-nak nem volt rövidítése, mert a parancsszó alakja ütközött az INPUT#
paranccsal, ami közelebb helyezkedett el a kulcsszó-keresőtábla elejéhez. A gyakran használt PRINT
parancsnak a többi BASIC dialektushoz hasonlóan a ?
volt a rövid alakja. A parancsok shiftelt alakkal való rövidítése a Commodore BASIC egyedi sajátossága.
A kulcsszavak rövidítésével valamivel több kód fért el egy programsorban (a program egy sora 2 vagy 4 képernyősor hosszúságú lehetett, modelltől függően). Ez jelentett némi megtakarítást, mivel minden új sorhoz tartozott némi memória-overhead, de nem túl sokat. Minden BASIC parancs token formájában tárolódott és csak egyetlen bájtot foglalt a memóriából (illetve a BASIC 7 és 10 esetében több parancs két bájtot) a beírás módjától függetlenül. Ráadásul az ilyen hosszú sorokat utólag elég nehéz volt szerkeszteni. A LIST
parancs mindig a teljes kulcsszavakkal listázta a programot – akkor is, ha így a sorok túlterjeszkedtek a 2 vagy 4 képernyősor hosszúságon, ami még lehetővé tette a bevitelüket.
További optimalizálást tett lehetővé,[5] hogy a BASIC programok nem igényelnek szóközöket (bár a LIST parancs a sorszám és a parancs közé automatikusan beszúr egyet), pl. a
100 IFA=5THENPRINT"YES":GOTO160
egy érvényes programsor. Gyakori is volt a szóközök nélküli programozás, mivel a kulcsszavak közötti szóközöket a tokenizált programban extra 0x20
bájtokként tárolták, amiken a parancsértelmező futtatás során átlépett. A sorok okozta overhead megtakarítására szokás volt továbbá minél több kódot egyetlen sorba írni, az egyes parancsokat kettősponttal elválasztva.
Az elágazás nélküli programvégrehajtás során a végrehajtás sorrendjét nem a sorszámozás határozza meg. A BASIC program ugyanis egyszeresen láncolt lista: minden sor a következő sor elejére mutató kétbájtos mutatóval kezdődik (ahol a 0 pointer a program végét jelzi), a következő két bájt a sor száma, majd a nullbájttal lezárt tokenizált parancssor következik.[6][7] Mivel a GOTO és GOSUB parancsok fix programsorszámokra hivatkoznak, a konstansok kódolása miatt a GOTO 10000 parancs három bájttal többet foglal a memóriából a GOTO 10 parancsnál; emiatt a programok átsorszámozása 1,2,3… sorszámokra a lehetséges optimalizációk közé tartozott (az egymást követő sorok összevonása, szóközök kihagyása stb. mellett), melyek utólagos elvégzésére külön segédprogramok léteztek.[5] A program sorról sorra történő beírásakor a BASIC azonnal átrendezi a memóriában a programsorokat, hogy a sorszámok és a mutatók emelkedő sorrendben legyenek. Ha már a program a memóriában van, PEEK és POKE utasításokkal a sorszámok átírhatók, vagy akár minden sor száma megegyezhet. Azokban az időkben, amikor BASIC nyelven kereskedelmi programokat írtak, ezt a megoldást használták is a programok módosítása elleni védelmi technikaként.
A változónevek csak két karakter erejéig voltak megkülönböztetve, így a VARIABLE1
, VARIABLE2
és VA
mind ugyanarra a változóra utalt.
Az eredeti MS BASIC-kel megegyezően a Commodore BASIC natív számformátuma is lebegőpontos. A legtöbb kortárs BASIC-implementáció három bájtot használt az értékes számjegyekre (mantissza) és egy bájtot a kitevőre (karakterisztika). A három bájtos mantisszával a lebegőpontos számok pontossága kb. 6,5 decimális jegy, a kerekítési hibák gyakoriak. A Commodore azonban az MS BASIC négy bájtos mantisszáját vette át, ami a Commodore BASIC-et sokkal használhatóbbá tette az üzleti alkalmazások számára.
Bár a Commodore BASIC támogatja a (százalékjellel jelölt) előjeles egész szám változótípust, melynek értéke −32768 és 32767 közé eshet, a gyakorlatban ennek előnyei kizárólag tömbváltozóként jelennek meg: memóriát spórol, mivel így a tömb tagjai egyenként csak két bájtot foglalnak. Az egyszerű skalár változót egész számnak jelölve a BASIC mindig visszakonvertálja azt lebegőpontossá, ami lelassítja a program futását, és még pazarló is, hiszen a százalékjel egy bájtot elfogyaszt a memóriából. Az előjeles egész változókkal nem is lehet megcímezni a memória 32767 fölötti részeit a POKE vagy PEEK utasításokkal.
A karakterlánc típus jelölése a változónév után írt dollárjellel történik. Tehát az AA$
, AA
és AA%
változókat a Commodore BASIC mind különbözőnek tekinti.
A gyári BASIC 2.0 hiányosságai miatt a Commodore 64-hez számos BASIC-kiterjesztést dobtak piacra. Az egyik legnépszerűbb kiterjesztés a Commodore 1541 Test/Demo Disken megtalálható DOS Wedge volt. Ez az 1 KB-os kiterjesztés főleg lemezkezelési parancsokkal bővítette az eredeti utasításkészletet, például lehetővé tette a lemez tartalomjegyzékének listázását a memóriában lévő program törlése nélkül. Ezeket a képességeket később több BASIC-kiterjesztés örökölte, köztük a népszerű Epyx FastLoad cartridge is. Más BASIC-kiterjesztések például a sprite-ok, hangok és a nagy felbontású grafikus mód kezelését tették lehetővé, ilyen volt például a Simons' BASIC.
Bár a BASIC 2.0-nak a grafika és a hang kezelésében mutatott hiányosságai a felhasználók számára frusztrálóak voltak, egyes kritikusok szerint még hasznosak is voltak, mert rákényszerítették a felhasználók a gépi kódú programozás elsajátítására.
A C64-es BASIC 2.0 korlátai miatt gyakran előfordult, hogy BASIC-ből a beépített ROM-ban lévő vagy saját gépi kódú rutinokat hívtak meg.
A Loadstar nevű C64-es diszkmagazin a hobbiprogramozók színtere volt, akik (egyebek mellett) saját gyártású BASIC parancsokat is megosztottak egymással, melyeket a
SYS memóriacím + eltolás
paranccsal lehetett meghívni.
Modern programozási megközelítésből a Commodore BASIC korai verziói számos rossz programozási gyakorlat csapdájába ejtették a felhasználót. A legtöbb ilyen probléma a Microsoft BASIC-ből fakadt, bár gyakorlatilag minden korabeli mikroszámítógép BASIC-e hsaonló problémákkal küzdött.[8] A Microsoft BASIC programok minden sorához egy sorszám tartozott. Ezeket gyakran fix értékkel (5, 10 vagy 100) növelték, hogy megkönnyítsék későbbi programsorok beszúrását a program továbbfejlesztése vagy hibakeresés céljából. Ha nem sikerült jó előre megtervezni a program szerkezetét, később új programrészek beszúrásához az egész kódot át kellett strukturálni. Ennek elkerülésére az egyik technika az volt, hogy a program alacsony sorszámokon, egy ON...GOSUB ugrótáblával kezdődött, a programot pedig főbb programrészekre osztották, melyek a nekik kijelölt nagyobb sorszámoknál kezdődtek, pl. 1000, 2000 stb. Ha egy nagyobb szekcióval kellett bővíteni a programot, a következő nagyobb sorszámtól lehetett kezdeni a számozását, a sorszámot pedig csak be kellett illeszteni az ugrótáblába.
A Commodore és más platformok későbbi BASIC-verzióiba már bekerültek az átstrukturálást segítő DELETE és RENUMBER parancsok, valamint az AUTO sorszámozó parancs, ami a beállított növekmény szerint automatikusan megadta a következő sorszámot.
A Commodore BASIC-ben minden változó globális. Nehéz jól definiált ciklusokat létrehozni, ezért a programozó gyakran a GOTO utasításra hagyatkozik (ezt később a BASIC 3.5-ben a DO, LOOP, WHILE, UNTIL és EXIT parancsokkal hozták helyre). Egyes feladatokhoz muszáj volt flag változókat létrehozni. A Commodore korai BASIC-változatai nem rendelkeztek a debugolást segítő parancsokkal, ezért a hibakeresés és optimalizálás a beépített eszközökkel nehézkes volt.
Más otthoni számítógépekhez hasonlóan a Commodore-modelleknél is a rendszerindítás közvetlen a BASIC parancsértelmezőt indította el. A BASIC fájlkezelő és programozási parancsait interaktív üzemmódban („direkt mód”) be lehetett írni, például programok betöltésére és futtatására. Egy program futását a RUN/STOP billentyűvel megállítva, a változók értékei a memóriában maradtak, és ki lehetett PRINT-elni őket hibakeresés céljából. A fejlett teljes képernyős szerkesztővel együtt ez már szinte a Lisp-féle REPL-szerű programozási környezetre emlékeztetett; a programozók a képernyőn bárhol szerkeszthették a programot, beilleszthettek sorokat, interaktívan építve a programot.[9] Az előbbiekkel szemben a kor üzleti célú operációs rendszerei, mint a CP/M vagy az MS-DOS jellemzően egy parancssoros felhasználói felülettel indultak el. Ha egy programozási nyelvre volt szükség, azt külön be kellett tölteni.
Bár a Commodore BASIC egyes verziói tartalmaztak lemezspecifikus DLOAD
és DSAVE
parancsokat, a népszerű Commodore 64 BASIC-ében a felhasználónak kellett megadnia a lemez eszközszámát (jellemzően 8 vagy 9), egyébként a LOAD
parancs alapértelmezésben a kazettás egységre vonatkozott. A Commodore 64-ben található BASIC 2.0 másik hiányossága volt, hogy nem volt benne a memóriában lévő program felülírása nélküli tartalomjegyzék-listázást végző DIRECTORY
parancs.
A CBM BASIC verziói idősorrendben, a hozzáadott újdonságokkal:
WAIT6502,1
parancs kiírja, hogy MICROSOFT!
DLOAD,DSAVE,COPY,SCRATCH
stb. (összesen 15)DS,DS$
BANK
BLOAD, BSAVE, DCLEAR
PRINT USING, PUDEF
DISPOSE
ELSE
TRAP, RESUME, ERR$()
DATA
-beolvasás: RESTORE [
linenumber]
INSTR
JOY
DEC(),HEX$()
DO, LOOP, WHILE, UNTIL, EXIT
KEY
(interaktív üzemmódban is)AUTO, DELETE, RENUMBER
TRON, TROFF
MONITOR
SYS 52651
SPRDEF
IF THEN ELSE
-szerkezetekben: BEGIN, BEND
POT, PEN
XOR
POINTER
WINDOW
SLEEP
SWAP, FETCH, STASH, FRE(1)
BOOT, DVERIFY
FAST, SLOW
(2 vagy 1 MHz)GO64
RREG
(SYS
után kiolvassa a processzor regisztereit)OFF, QUIT
SYS 32800,123,45,6
VOLUME
a VOL
helyettEXIT
a QUIT
helyettFAST, SLOW
parancsok nem léteznekPOPUPS
PALETTE, GENLOCK
MOUSE, RMOUSE
SEQ
) segédeszköz: TYPE
FIND, CHANGE
DMA, FRE(2)
PAINT, LOCATE, SCALE, WIDTH, SET, VIEWPORT
PASTE, CUT