I. Bevezetés

Amit a REXX-rôl tudni érdemes

"A REXX az OS/2 batch nyelve." - általában ennyire szokott az ember foglalkozni ilyesmikkel. A programozók "komoly" nyelveken programoznak, a nem-programozók meg amúgy sem érdeklôdnek az ilyen bonyolult dolgok iránt, mint egy programozási nyelv. (Természetesen az igazsághoz tartozik, hogy a REXX nem az OS/2 parancsnyelveként született, és nem is ez az egyetlen célja: a REXX az IBM operációs rendszereinek rendszerfüggetlen parancsnyelve, tehát éppúgy megtaláljuk IBM nagygépeken, mint az OS/2 alatt, és a programok - legalábbis az alap REXX-ben írt programok - változtatás nélkül futni is fognak.)

Valahogy én is így voltam vele egykor. Hogy mitôl és mikor változott meg a véleményem, azt már pontosan nem tudom megmondani. Talán akkor, amikor láttam egy példaprogramot, amely egy egész fájlt olvasott be egyetlen változóba és dolgozott rajta? Talán amikor láttam, hogy pár soros programocska elvégzett annyi mindent, amit én csak több képernyônyi programon tudtam volna megírni? Talán az, amikor elôször írtam öt perc alatt programot, amely megkímélt egy órányi munkától? A REXX mindenesetre érdekes nyelv. Ahhoz képest, hogy az OS/2 batch nyelve (vagyis elméletileg a DOS "*.BAT" programok utódjának foghatjuk fel), hihetetlenül sokat tud. Ahhoz képest pedig, hogy önálló, teljes programozási nyelv, nagyon könnyen megtanulható és igen gyorsan lehet vele mûködô programokat készíteni. Amit fel kell ismerni az az, hogy ennek a nyelvnek is megvan a maga helye: van, amit nem szabad REXX-ben írni, mert nagy, lassú vagy bonyolult lesz, de van amihez kiválóan megfelel: a rövid programokhoz, illetve azokhoz, ahol nem kritikus a program futási sebessége.

Az ObjectREXX (vagy röviden: OREXX) a tervek szerint az új OS/2 verzió parancsnyelveként fogja a REXX-et helyettesíteni. A REXX alapjaira épül, azt kiegészítve az OOP (ObjektumOrientált Programozás) elemeivel, valamint ennek kapcsán rengeteg hasznos újdonsággal. Amikor a REXX-rôl írok, akkor mindaz az OREXX-re is igaz.

A REXX tulajdonságai

A REXX interpretált (értelmezett) nyelv, ami azt jelenti, hogy a programot nem kell (és nem is lehet) lefordítani közvetlen gépi nyelvre, hanem a gép folyamatosan értelmezi és hajtja végre. Ennek hátránya a kisebb végrehajtási sebesség, elônye pedig az egyszerû programfuttatás és hibakeresés. A REXX minden programmódosítás utáni futtatáskor készít egy "elôfordított" (tokenizált) kódot, amivel meggyorsítja a végrehajtást, és ezt a kódot a REXX programfájl EA-ában (Extended Attribute, kiterjesztett tulajdonság) tárolja. A REXX programban szerepelhet minden olyan lehetôség, ami egy szokásos procedurális (eljárásalapú) nyelvben: vannak változók, lehet függvényeket és eljárásokat írni, lehet a külvilággal kapcsolatot tartani.

Azonban közelebbrôl megnézve a dolog nagyban eltér a "szokásos" nyelvektôl, mint például a C vagy a Pascal. A REXX egyfajta változót ismer: a stringet (vagyis karakterláncot). A REXX-ben minden változó karakteres, még az is, amelyben számokat tárolunk. Amikor mûveletet végzünk, akkor a REXX megpróbálja a változó tartalmát úgy értelmezni, ahogyan azt az adott mûvelet (például összeadás) megkívánja, és értesít minket, ha a változó tartalma nem értelmezhetô a megfelelô módon. Ez a módszer - kezdeti szokatlansága ellenére - nagyon kellemes, rugalmasan kezelhetô változókat eredményez, ahol a programozó szabadon farigcsálhatja a változók tartalmát. (Például megteheti azt, hogy egy számot nem szoroz meg százzal, hanem "utána ír két nullát".) Ezen változók hossza tetszôleges. Ez igazán már csak a DOS-on nevelkedett programozóknak szokatlan, de azért meglepô, amikor az ember ír egy egysoros programot a teljes fájl kisbetûrôl nagybetûre alakításához, úgy, hogy ehhez egy darab változót használ. A nyelvet úgy tervezték, hogy alkalmas legyen nagyobb rendszerek "makrónyelveként" is funkcionálni. Minden parancssort elôször megpróbál a REXX értelmezni, de ha ez nem sikerül, akkor feltételezi, hogy az a "gazdarendszernek" szól, és továbbítja neki. (Az OS/2 alaprendszerben ez azt jelenti, hogy ha a REXX talál egy értelmezhetetlen sort, akkor azt továbbítja a CMD.EXE-nek, vagyis az OS/2 parancssorának. Így például teljesen természetes az, ha egy REXX program közepén találunk például egy "copy" vagy egy "dir" parancsot...).

Az OREXX a fentieket annyiban módosította, hogy létrejöttek az objektum típusú változók, innentôl kezdve minden változó objektumokat tárol. A hagyományos REXX programozást az segíti, hogy az objektumok alapértelmezett be és kimenete karakterlánc, vagyis ezek is használhatók "hagyományos" REXX változókként, mintha mi sem történt volna. A REXX programot úgy írjuk, mint egy szokásos OS/2 "batch" (parancsköteg-) fájlt, vagyis készítünk egy .CMD végû fájlt. A rendszer onnan tudja, hogy REXX programról, és nem batch fájlról van szó, hogy az elsô sor mindig megjegyzés sort tartalmaz (kötelezôen). Ezzel rá is veszi a programozót hogy írja le hogy a program mire jó, mit csinál. Nézzük a legegyszerûbb REXX programot, amely a szokásos köszöntést eredményezi:

/* HelloWorld.Cmd: Ez az elsô programom */
say "Hello" 'World!'

A programot elindítva láthatjuk az eredményt. A REXX elég nagy szabadságot biztosít mindenféle szempontból: a karakterlánckonstansokat írhatjuk idézôjelekkel vagy aposztrófokkal, és meglehetôsen szabadon bánhatunk a szóközökkel is, ahol lehetôségünk van rá. OS/2 alatt a REXX-ben "több forrásból" használhatunk függvényeket és eljárásokat: használhatjuk a REXX belsô függvényeit (mint például a SubStr), használhatjuk az OS/2 alatti REXXUtil könyvtár függvényeit (mint pl. a SysFileTree), és használhatunk saját magunk vagy mások által írt külsô, tetszôleges nyelven írt függvényeket, mint például egy modemeket kezelô, vagy adatbáziskezelô függvénykönyvtárat. Ha a REXX belsô függvényein kívül mást is használunk, akkor az a program már nem lesz 100%-ig hordozható, azaz valószínûleg nem fog változtatás nélkül futni más operációs rendszerek alatti gépeken. Álljon itt mutatóba a program, amely egy egész fájlt átír nagybetûsre:

/* Nagybetu.Cmd: A parancssorban megadott elsô fájlt átírja nagybetûsre 
és kimenti a második megadott fájlba. (Nincs hibakezelés) */
Parse Arg infile outfile
CALL CharOut outfile,Translate(CharIn(infile,Chars(infile)))

A programban láthatjuk a REXX egyik leghasznosabb (és egyben legbonyolultabb) utasítását, a PARSE-t, valamint azt, hogy a nyelv segítôkészen elvégez helyettünk olyan magától értetôdô feladatot, mint egy fájl megnyitása ha írni akarunk bele, illetve ha olvasunk belôle. Ezeket természetesen egy hosszabb programnál nem illik a rendszerre hagyni, és magunk is nyithatjuk-zárhatjuk a fájlokat. Ezen kívül kihasználtuk azt a jellegzetességet is, hogy a függvények sok mindenre képesek (jelen esetben a Translate), de egyes paraméterek elhagyásával képesek az egyszerû, mindennapi feladatok elvégzésére. (A Translate például univerzális kódátalakító függvény, amely tetszôleges módon képes a bemenetben karaktereket kicserélni, alapértelmezése azonban az a csere, amely nagybetûket eredményez a kisbetûk helyén.) Az, hogy a számokat a REXX stringekben tárolja, lehetôvé tesz néhány különlegességet a számokkal kapcsolatban. Futtassuk le próbaképp ezt az apró programot:

/* PiciSzam.CMD: REXX szamabrazolas, ketto 2048-ik hatvanya */
numeric digits 1e3
say 2**2048

Objektumorientált programozás

(Aki tudja, mi az az OOP az át is ugorhatja - persze csak a szemével - ezt a részt.) Az Objektumorientált programozás mostanában éli virágkorát, és lassan eljutunk odáig hogy aki programot ír, kénytelen megismerkedni a módszerrel és annak használatával. Aki még nem tudná - és ilyen egyre kevesebb van manapság - az OOP lényege az, hogy a programok nem különálló függvényekbôl, eljárásokból, és különbféle változókból (tömbök, struktúrák, stringek, négydimenziós vektorok, ...) állnak, hanem úgynevezett objektumokból. Az objektum egy "doboz", amely tudja magáról hogy ô éppen milyen állapotban van (például egy kapcsoló objektum tudja magáról hogy ô most be vagy ki van kapcsolva), ezt az állapotot azonban nem hagyja megváltoztatni, hanem csak általa is ismert és engedélyezett módon tartja a kapcsolatot a külvilággal (például a kapcsoló objektum tudja, hogy egy KapcsolóHelyzet nevû változóban tárolja, hogy ô most éppen ki van-e kapcsolva, de a külvilág ezt nem tudja sem megnézni, sem megváltoztatni; a kapcsoláshoz például azt kell "mondani" a kapcsolónak hogy BE, vagy hogy KI, és azt, hogy be van-e kapcsolva, például az KapcsolóÁllapot mondja meg a kapcsoló). Ez több okból is nagyon kellemes: egyrészt a változók, függvények és eljárások nem szétszórva vannak a programon belül, hanem objektumonként csoportosítva, és így nem fordulhat elô, hogy például valaki KI akar kapcsolni egy Ceruza objektumot; másrészt a kapcsoló biztos lehet abban, hogy nem történik meg az, hogy miközben ô azt hiszi magáról, hogy ki van kapcsolva, addig egy másik rutin "véletlenül" átírta a változóját minden értesítés nélkül. Az objektumnak ezt a tulajdonságát "zártságnak" hívják. Az objektumoknak üzeneteken keresztül mondhatjuk meg, hogy mit várunk el tôlük. Az üzenetek eredményezhetik az objektum belsô állapotának megváltozását (például a Kapcsoló KI vagy BE üzenete), vagy eredményezhetnek egy objektum által visszaadott értéket (például a KapcsolóÁllapot üzenet).

Az objektumoknak a zártságon kívûl vannak még fontos tulajdonságaik:

Polimorfizmus, amelyet talán változatosságnak lehetne fordítani. Ez szintén a programozó dolgának könnyítését szolgálja. Például tegyük fel, hogy van string típusú és array (tömb) típusú változónk! Szeretnénk egy olyan lehetôséget, hogy a string tartalmát meg tudjuk fordítani: és erre van is lehetôségünk a reverse üzenettel. Ezt átadva egy string objektumnak az eredmény a string fordítottja lesz. Ha ugyanezt szeretnénk egy tömbbel megcsinálni (hogy az elsô elem legyen az utolsó és így tovább) akkor nem kell külön ReverseArray vagy hasonló üzenetet készíteni, hanem itt is használhatjuk a reverse szót. Azt, hogy a megfordítást pontosan hogyan kell végrehajtani, azt az objetum tudni fogja magáról.

Öröklés: új objektumtípust nem csak úgy hozhatunk létre, hogy az alapoktól kezdve megírjuk, hanem megtehetjük, hogy egy már létezô objektumból származtatjuk, vagyis egy olyan új objektumot készítünk, amely ugyanaz tudja mint az "ôse", némi változtatással. Példa lehet erre a SípolóKapcsoló, amely ugyanazt tudja mint a Kapcsoló (Ki, Be, KapcsolóÁllapot), de a kikapcsolásnál sípol egyet. Ezt megoldhatjuk úgy, hogy minden tulajdonságát a Kapcsoló objektumból örökli (azokat nem kell újraírni), és csak a Ki eljárást (pontosabban az objektumoknál ezeket egységesen metódusoknak nevezzük) kell módosítani. Egy objektumfajtából (ezt nevezzük objektumosztálynak, angolul "class") természetesen egyszerre több "példány" (instance) is létezhet. Készíthetünk Kapcsoló objektumosztályt, amely alapján késôbb létrehozunk egy villany és egy fûtéskapcsolót, amelyek ugyanúgy mûködnek (vagyis a programjuk ugyanaz), viszont mindegyiknek saját állapota van, és a programunk más és más célra használja ôket. Ez a több példány létrehozásának lehetôsége szintén jellemzô az OOP-re.

A programok formája

Az OREXX programok nagyon hasonlóak a "sima" REXX programokhoz, azonban a programfájl végén megtaláljuk az objektumok adatait. Az objektumokat az alábbi formában használjuk:

eredmény=objektum~metódus(paraméterek)

Az eredmény az, amit az objektum válaszol arra, hogy elküldtük neki a metódus nevû üzenetet a megadott paraméterekkel. A REXX szokásainak megfelelôen a formátum meglehetôsen szabad, tehát lehet hogy nincs eredmény, esetleg nincsenek paraméterek; és természetesen az objektumok által visszaadott objektumoknak is lehet további üzeneteket és paramétereket adni. Példaként nézzük meg a "Hello World" program kissé módosított változatát:

/* ObjectHello.CMD: Üdvözlés objektumokkal */
udv = 'Hello world'
say udv~string

A program szörnyen sok fölösleget tartalmaz, a példa kedvéért. Elôször is létrehoztunk egy udv nevû, string típusú objektumot. A második sorban ennek az objektumnak elküldtük a string üzenetet, ami azt jelenti (minden OREXX objektumnál), hogy az objektum szíveskedjen magáról közölni egy rá jellemzô karakterláncot. Ez egy string objektumnak nem okozhat gondot, így egyszerûen az eredmény a string tartalma, amelyet a say parancs ki is ír. Természetesen a string objektum nagyon sok mindent tud (végülis ô a REXX alapja), tehát egyszerûen megmondhatjuk neki hogy például fordítsa meg magát ("say udv~reverse~string"), vagy például daraboljuk fel ("say udv~reverse~substr(7,4)"). (A "~string" üzenet fölösleges, mert a Say "kierôszakolja".) Itt látható az, hogy ha egy üzenetre adott eredmény objektumot ad, akkor annak lehetséges újabb üzeneteket küldeni.

Bonyolultabb példa:

/* Kapcsolo.cmd: kapcsolo objektum */

villany = .kapcsolo~new
gaz     = .kapcsolo~new
villany~be
say 'Villany' villany~KapcsoloAllapot', gaz' gaz~kapcsoloallapot

return

/**** Objektumok definíciói ****/
::class kapcsolo

::method 'init'
expose KapcsoloHelyzet
KapcsoloHelyzet = 'ki'
return

::method 'ki'
expose KapcsoloHelyzet
KapcsoloHelyzet = 'kikapcsolva'
return

::method 'be'
expose KapcsoloHelyzet
KapcsoloHelyzet = 'bekapcsolva'
return

::method 'KapcsoloAllapot'
expose KapcsoloHelyzet
return KapcsoloHelyzet

Ez a példa már általunk készített objektumokat tartalmaz. A fôprogram a fájl elején található, az objektumok belsô leírása a fájl végén. Az OREXX objektumokat megadó utasításai két kettôsponttal kezdôdnek. A class azt adja meg, hogy új objektumosztályt hozunk létre, amelybôl késôbb objektumpéldányokat gyárthatunk. A method sorok adják meg azt, hogy az objektum milyen üzeneteket ismer (azokon kívül persze, amelyeket esetleg örökölt, de ebben a példában ezzel nem kell foglalkozni), ezek a sorok mindig a legközelebbi class-hoz tartoznak. A method alatt található az, hogy az objektum mit csináljon, ha ezt az üzenetet megkapja. Az expose - hasonlóan a REXX-ben használatos expose-hoz, amely lehetôvé teszi, hogy zárt eljárás külsô változókat "lásson" - megadja, hogy a method milyen objektumváltozókat akar kezelni. (Az expose-zal nem megadott változók lokálisak, kilépésnél tartalmuk elvész.) Látható, hogy miután megadtuk az objektumosztály definícióját, annyi objektumot készítünk amennyi jólesik, és nem kell törôdni azzal hogy számon tartsuk, hogy melyik változó melyik objektumot írja le, melyik objektum éppen milyen állapotban van.

Az OREXX adatstruktúrái

Az OOP nyelvek jellemzôen szeretik elkényeztetni a programozót az objektumalapú, különleges adatstruktúrákkal, és ez alól az OREXX sem kivétel. Csak megemlítenék néhány adatstruktúrát, amely ismeretlen a szabvány REXX-ben:

Tömb (számokkal indexelt elemek), szótár (szavakkal indexelt elemek), tábla (tetszôleges objektumokkal indexelt elemek), reláció (tetszôleges objektumokkal indexelt elemek, ahol elôfordulhat egy index-elemhez több elem is), lista (elemek sorozata), sor (elemek sorozata, amely csak a végein módosítható), halmaz (tartalmaz, vagy nem tartalmaz egy objektumot), zsák (olyan halmaz, amely megjegyzi hogy hányszor tartalmaz egy-egy elemet). Ezeken kívül találhatunk még számos érdekes osztályt, mint például az Alarm (ébresztôóra) osztályt, amely egy adott idôben elküld egy üzenetet egy objektumnak, vagy a Stream osztályt, amely az OOP stílusú fájlkezelésért felelôs.

Többszálú programfutás

Igen, bármilyen hihetetlenül is hangzik elsôre, az OREXX nem csak hogy képes többszálú (multithread) programokat futtatni, de ezek elkészítése szinte gyerekjáték. Vizsgáljuk meg az alábbi kis programot:

/* MultiThread1.cmd: multithreaded programpélda */

gep = .szamolo~new	/* Letrehozzuk az objektumot */
say gep~ad1	/* Az elso szamlalo inditasa */
say gep~ad2	/* A masodik inditasa */
say gep~udvozles	/* Udvozles, hogy mutassa, fut a program */
gep~eredmeny	/* Belenezunk a szamlalokba */
gep~eredmeny	/* Egy kicsit kesobb is */
return	/* Program vege */
::class szamolo

::method 'udvozles'
return "Udvozollek!"

::method 'ad1' unguarded
expose szam1
szam1 = 0
reply "ad1 fut!"	/* A vezerles visszaadasa a foprogramnak!*/
do i=1 to 10000	/* Hosszas szamolgatas... */
  szam1 = szam1 + 1
end
say "ad1 befejezve!"
return

::method 'ad2' unguarded
expose szam2
szam2 = 0
reply "ad2 fut!"
do i=1 to 10000
  szam2 = szam2 + 3
end
say "ad2 befejezve!"
return

::method 'eredmeny'
expose szam1 szam2
say "Az szamlalok erteke jelenleg" szam1 "es" szam2"."
return

Futáskor szépen látható, hogy elindul az elsô számláló, majd a reply hatására (ami a return utasítás multithread megfelelôje) két szálra bomlik a program: egyrészt az objektum visszalép egy értékkel, másrészt tovább fut a számlálást végzô szál is. Ezután elindul a második számláló is a harmadik szálon. A fôprogram kiírja az üdvözlést (csak hogy mutassa, hogy tényleg fut miközben mennek a számlálók), majd párszor beleolvas abba, hogy a számlálás éppen hol tart. A program végét elérve a fôszál befejezôdik, és vele együtt a többi szálé is. Így megalkottuk az elsô többszálú programunkat. (Akinek gondja van azzal, hogy a szálak nem indulnak el, iktasson be várakozó ciklust a program elejére.) Az unguarded kapcsolónak általában nem kell szerepelnie. A guard ("ôrzô") mechanizmus azt biztosítja, hogy a többszálúság ne okozhasson problémákat a változók értékének megváltoztatásakor. (Például beolvassuk a változót, majd picit késôbb hozzáadunk egyet és visszaírjuk. Ha a kiolvasás után de a visszaírás elôtt egy másik szál megnövelné a változó értékét, akkor ez kellemetlen és nehezen felfedezhetô hibákat eredményezne.) A példa rövidsége miatt egy objektumot használtam, és így az ôrzômechanizmus nem futtatná addig ugyanazon objektumot egy másik szálon, amíg az elôzô üzenet feldolgozása le nem zajlott. Mivel én tudom, hogy az egyik szál nem befolyásolja a másikat, megadhattam a kapcsolót, és így be tudom mutatni egy objektummal is a többszálúságot. (A guard mechanizmusnak még számos lehetôsége van a védelem szabályozására.)

Összehasonlítás

Az OREXX sok hasonlóságot mutat más objektumorientált nyelvekkel, mint például az elterjedt C++, vagy például a SmallTalk. Maga a REXX alap jelenti inkább az eltéréseket, míg az objektumkezelés logikája, a rendszer alapjai ugyanazok: az objektumok itt is ugyanazon fontos tulajdonságokkal rendelkeznek. Lehetôségünk van objektumosztályok (class) létrehozására, ezek öröklésére. Létrehozhatóak MetaClass-ok, amelyekkel az objektum-osztályok gyártását könnyíthetjük meg. Lehetôségünk van itt is private metódust készíteni, amely csak az objektumon belül érhetô el. Viszont találhatunk olyan lehetôségeket is, amelyek az interpretált nyelvbôl következôen biztosítanak nagy rugalmasságot: hasonlóan a SmallTalk-hoz itt is képesek vagyunk program futása közben új objektumokat létrehozni, vagy objektumokhoz új metódusokat rendelni. Néhány nyelvvel ellentétben itt minden metódus "virtuális", azaz mindig a megfelelô helyen keresi a nyelv az üzenetet végrehajtó metódust: alapesetben az aktuális objektum kapja az üzenetet, de ha nem tudja kezelni, az üzenetek automatikusan megérkeznek az objektum ôséhez, ha ott sem ismert, akkor annak az ôséhez, végig az egész leszármazási fán. Egy példa erre, melybôl láthatjuk azt is, hogy miképp lehet egy objektumból a saját, illetve az ôsének a metódusait meghívni.

/* Virtualis.cmd: virtualis metodusok, orokles, superclass */

a = .nagy~new	/* Letrehozzuk a papat [Nagy] */
b = .kicsi~new	/* ...es a fiat [Kicsi] */
a~dolgozik	/* bemutatkozas */
b~dolgozik
b~papa	/* a szulo bemutatasa */
return

/*** a papa definicioi ***/
::class 'Nagy'
::method 'uzen'
say self~string 'iranyitasaval:' "Nagy vagyok! " '0d0a'x
return	/* a '0d0a'x jelentese CR+LF, soremeles */

::method 'dolgozik'
say self~string 'iranyitasaval:' "A nevem:"
self~uzen	/* virtualis metodus hivasa */
return

/*** a leszarmazott definicioi ***/
::class 'Kicsi' subclass nagy
::method 'uzen'	/* virtualis metodus */
say self~string 'iranyitasaval:' "Kicsi vagyok!" '0d0a'x
return

::method 'papa'
say self~string 'iranyitasaval:' "Az en papam mondja:" 
self~uzen:super	/* a szulo metodusanak hivasa */
return

A hibák kiszûrésén kívül sok programozási feladatot megkönnyít az unknown ("ismeretlen") metódus használata: ez minden olyan esetben megkapja a vezérlést, amikor egy objektum olyan üzenetet kap, amit nem tud értelmezni. Az objektum-alapú adatstruktúrákról már ejtettem szót: ezek szintén megtalálhatóak ugyanilyen formában a többi OOP nyelvben is. Az OREXX igen alaposan integrálódik az OS/2 rendszerébe. A nyelv többi részéhez hasonlóan a többi magasszintû nyelvhez képest sokkal egyszerûbb elérni a WorkPlace Shellt (WPS, Grafikus munkafelület), és így manipulálni a Munkaasztalt, ikonokat, objektumokat mozgatva, módosítva azon. Nagyon egyszerûen illeszthetô egy OREXX program az OS/2 System Object Model-jébe (SOM), ami elôsegíti a rendszerrel és más, tetszôleges nyelveken írt programokkal való integrációt. Az OREXX ezen külsô objektumosztályokat pontosan ugyanúgy látja és kezeli, mintha a "sajátjai" lennének. Az OREXX a REXX-hez hasonlóan gazdag nyomkövetési és hibakezelési lehetôségekkel segíti a programok logikai vagy futási hibáinak felderítését.

Egy ilyen rövid ismertetôbôl nem lehet igazán megismerni egy nyelv mûködését, programozását. Azonban arra talán megfelelô, hogy kedvet kapjunk ahhoz, hogy a megfelelô helyeken utánanézzünk a nyelv részletesebb leírásának. A folytatásban esetleg elindulhatunk az alapoktól, és az ismertetésen túl valóban megtanulhatjuk az OREXX programozását.

Gervai Péter
1996. 08. 09.
[ Következô lecke | Tartalom ]