I. A NetREXX alapjai

Bevezetés

A NetREXX a REXX programozási nyelv legfiatalabb hajtása. A NetREXX a klasszikus REXX és a Java nyelv összeházasításából keletkezett, így a NetREXX örökölte a REXX nyelv könnyû tanulhatóságát és a Java programok hordozhatóságát és magas hatásfokát. A NetREXX nyelv tulajdonképpen a Java nyelv alternatívájának is tekinthetô, mivel segítségével Java programok vagy programocskák készíthetôk, többnyire sokkal egyszerûbben, mint a Java nyelven. Ebben a leckében röviden át fogjuk tekinteni a NetREXX jellemzôit, majd a többi leckében részletesen meg is tárgyaljuk azokat.

Egy egyszerû NetREXX program

A NetREXX programok struktúrája igen egyszerû, az alábbi kétsoros programocska (lecke01a.nrx) már elég is a futtatáshoz:

/* Az elsô NetREXX programom */
Say 'Helló NetREXX programozó!'

Aki tud egy kicsit REXX-ben programozni, annak valószínûleg magától értetôdô a program mûködése. Az elsô sor magyarázó szöveget tartalmaz, míg a második (Say utasítás) megjeleníti a Helló NetREXX programozó szöveget. A programocska futtatható a netrexxc lecke01a -run vagy nrc lecke01a -run parancsok kiadásával. Ha minden jól megy, akkor valami hasonlót kell látnunk a képernyôn:

C:\>nrc lecke01a.nrx -run
NetRexx portable processor, version 1.151
Copyright (c) IBM Corporation, 1999.  All rights reserved.
Program lecke01a.nrx
Compilation of 'lecke01a.nrx' successful
Running lecke01a ...
Helló NetREXX programozó!

A netrexxc/nrc parancs (NetREXX compiler) tulajdonképpen nem csinál mást, mint lefordítja a lecke01a.nrx programot, amelyet a java COM.ibm.netrexx.process.NetRexxC lecke01a parancs kiadásával is megtehetünk. A fordítás eredményeként keletkezik egy lecke01a.class nevû fájl, amelyet a java lecke01a parancs kiadásával akár magunk is futtathatunk. Természetesen a NetREXX sokkal többre is képes, mint egyszerû szövegek megjelenítésére. A NetREXX-bôl nagyon könnyen hozzáférhetünk a gyorsan gyarapodó Java osztálygyûjteményekhez, de akár új osztályokat is írhatunk ezen a nyelven.

Kifejezések, változók

A legtöbb NetREXX program tartalmaz kifejezéseket, amelyek elôbb vagy utóbb kiértékelésre kerülnek. A kifejezések gyakorlatilag megegyeznek a klasszikus REXX-bôl ismert kifejezésekkel. A NetREXX két fajta változótípust ismer, s ebbôl egyik a karakterlánc (NetREXX string), amely elvileg bármilyen hosszú lehet. A karakterláncot idézôjelek közzé kell tenni, s ez alól csak a számok kivételek. Ennek megfelelôen a kifejezésekben használható operátorok is karakterláncokat feltételeznek. A kiértékelt kifejezések eredményét változókhoz rendeljük. A változók nevében szereplô kis és nagybetûk között nem tesz különbséget a nyelv. Az alábbi példaprogramocska (lecke01b.nrx) jól példázza a kifejezések és változók használatát NetREXX-ben:

/* Program a felhasználó üdvözlésére */
/* Bekérjük a felhasználó nevét       */
Say 'Ird be a neved és nyomd meg az Entert!'
answer = ask 

/* Megvizsgáljuk a választ */  
IF answer = '' THEN 
	Say 'Helló idegen!'
ELSE 
	Say 'Helló' answer'!'

A példaprogram elôször rákérdez a felhasználó nevére, majd az ask utasítás segítségével bekéri a nevet, amelyet az answer változóban tárol el. Ezután teszteljük az answer tartalmát. šres válasz estén az idegent, valós válasz esetén pedig a megadott nevû felhasználót üdvözöljük.

A NetREXX-ben az utasítások a sor végével érnek véget. Ha egy utasítást folytatni akarunk a következô sorban, akkor azt az elválasztó jellel kell jelezni:

Say 'Itt egy utasítás, amely túl hosszú, ezért' -
     'a következô sorban folytattuk.'

Természetesen egy sorban több utasítás is kerülhet, ezeket akkor pontos vesszôvel kell elválasztani egymástól:

IF answer='Yes' THEN DO; Say 'OK!'; EXIT; END

Vezérlôutasítások

A program futását befolyásoló vezérlôutasítások terén sincs lényeges eltérés a klasszikus REXX-ben tanultaktól. A NetREXX-ben is használhatók a jól ismert IF...THEN...ELSE, SELECT...WHEN...OTHERWISE...END vagy DO...END struktúrák, bár ez utóbbi, egy változó értékének folyamatos léptetésére használt változatát a LOOP...END váltotta fel:

/* Az i értékét 10-szer növeljük, 2-vel */
LOOP i=0 TO 20 BY 2
	Say i
END

A LOOP-ot lehet kombinálni a REXX-bôl ismert WHILE, UNTIL vagy akár a FOREVER feltételekkel is, s a hurok végrehajtását lehet módosítani az ITERATE vagy LEAVE utasításokkal.

Aritmetika

A NetREXX aritmetikája sem tartogat különösebb meglepetéseket a hagyományos REXX-ben járatosak számára. A számokat itt is karakterláncok reprezentálják, s a velük való számolás pontosságát a NUMERIC utasítás szabja meg. Az alábbi programrészlet pl. 50 jegyre pontosan számolja ki az 1/7 értékét:

NUMERIC DIGITS 50
Say 1/7

A decimális számábrázolás elônyös a programozó számára, azonban hátrányosan hat a futási sebességre. Éppen ezért vezették be a NetREXX-ben a bináris számábrázolás használatát. Ha ezt kívánjuk használni, akkor a program elején meg kell adni az OPTIONS BINARY utasítást.

Karakterláncok használata

A REXX-bôl ismert karakterlánc-manipuláló függvények itt is jelen vannak, ám az írási mód a Java nyelvre emlékeztet, s nem függvényeknek, hanem metódusoknak hívjuk ôket:

phrase = 'Now is the time for a party'
Say phrase.word(7).pos('r')

A fenti programrészlet pl. értéket ad a phrase változónak, majd pedig megjeleníti a phrase-ben található 7. szóban az r betû elsô elôfordulásának a pozícióját, vagyis 3-at.

A karakterláncok kielemzésére használt PARSE utasítás is megtalálható, igaz, használata kissé módosult. A legegyszerûbb használati forma a szavakra bontás:

PARSE 'Ezt a mondatot akarjuk szavakra bontani.' sz1 sz2 sz3

A fenti kódrészletben például a szóközök mentén három részre bontjuk a PARSE után álló karakterláncot. Az sz1 értéke tehát 'Ezt', az sz2-é 'a', az sz3-é pedig 'mondatot akarjuk szavakra bontani.' lesz. A változók között karakterláncokat is megadhatunk, ha éppen nem a szóközök alapján akarjuk a kiértékelést elvégezni:

PARSE 'Ezt a mondatot !nem! akarjuk szavakra bontani.' sz1 '!nem!' sz2 sz3

Ebben az esetben az sz1 az 'Ezt a mondatot', az sz2 az 'akarjuk', az sz3 pedig az 'szavakra bontani.' értéket kapja. A felbontáshoz felhasznált karakterláncot változóként is megadhatjuk, ám ekkor zárójelek közé kell tenni:

darab = '!nem!'
PARSE 'Ezt a mondatot !nem! akarjuk szavakra bontani.' sz1 (darab) sz2 sz3

Indexelt karakterláncok

Az indexelt karakterláncok a REXX-bôl ismert összetett változók leszármazottjai. Igazából csak az írásmódban van különbség, mivel az indexet itt nem ponttal különítjük el, hanem (a tömbökhöz hasonlóan) szögletes zárójelek közé tesszük. Amennyiben inicializálni akarjuk az összes elemet, akkor index nélkül adunk értéket:

valami    = 0      -- Az összes valami[] értékét 0-ra állítjuk
valami[3] = 'abc'  -- Értéket adunk a valami[3]-nak

Az indexnek nem muszáj számnak lennie, elvileg bármilyen karakterlánc állhat az index helyében. Az indexelt karakterláncok akár többdimenziósak is lehetnek:

pelda['kutya'] = 'farkas'
pelda['kutya', 'macska'] = 'nem barát'

A lecke01c.nrx példaprogramban további példákat találhatunk az indexelt karakterláncok használatára.

Tömbök

A NetREXX támogatja fix méretû tömbök használatát is. A tömbök nagyon hasonlítanak az indexelt karakterláncokra. A különbség csak az, hogy a tömböket elôre definiálni kell és az index természetesen csak egész szám lehet:

array    = String[3]            -- Definiálunk egy három karakterláncból álló tömböt
array[0] = 'Az elsô string'     -- Megadjuk a tömb elemeit
array[1] = 'A második string'
array[2] = 'A harmadik string'
loop i = 0 to 2                 -- Kiíratjuk a tömb elemeit
	Say array[i]
end

Figyeljük meg a -- jeleket, amelyeket már az elôzô kódrészletek egyikében is használtunk. Ezek a jelek egyszerûen csak a magyarázó szövegeket jelölik, vagyis ugyanaz a funkciójuk, mint a /* */ jeleknek.

Objektumok

Az eddig használt változók mind karakterlánc típusúak voltak, ám a NetREXX, a Java-val történt összeházasítás következtében ismeri az objektum típust is. Az objektumok osztályokból származnak, amelyek meghatározzák az objektumokban tárolt adatok típusát és a metódusokat, amelyekkel az adatok manipulálhatóak. Vegyük pl. a téglalap osztályt. Tegyük fel, hogy az osztályban a téglalap szélességét és magasságát definiáljuk, amelyeket a téglalap osztály tulajdonságainak (properties) is nevezünk. Az osztályban olyan metódusokat definiálunk, amelyekkel a téglalap tulajdonságai (méretei) manipulálhatóak. Egy másik metódus pedig az osztályból leszármaztatott objektumok elkészítésére szolgál (constructor method). A Java-ban a constructor metódus neve mindig megegyezik az osztály nevével, így a NetREXX-ben is ezt a hagyományt követik. Ugyanez vonatkozik az osztályt tartalmazó fájl nevére is. Bár nem mindig kötelezô, a legtöbb esetben a fájl neve is megegyezik az osztály nevével. Az alábbiakban bemutatjuk a téglalap osztály egyik lehetséges megvalósítását.

/* téglalap osztály */
class teglalap
width       -- szélesség
height      -- magasság
  
/* constructor metódus új téglalap készítéséhez */
method teglalap(newwidth, newheight)

	/* beállítjuk a téglalap szélességét és magasságát */
	width = newwidth; height = newheight
  
/* metódus a téglalap méretének újraállításához */
method size(newwidth, newheight) returns teglalap

	width = newwidth; height = newheight
      	return this  
  
/* metódus a téglalap méretének változtatásához */
method relsize(relwidth, relheight) returns teglalap

      width = width + relwidth; height = height + relheight
      return this
  
/* metódus a téglalap méretének lekérdezésére */
method print

      Say 'A téglalap mérete:  'width 'x' height

Figyeljük meg a következô dolgokat!

A teglalap osztály ugyanúgy lefordítható a NetREXX compilerrel, mint a többi példaprogram (nrc teglalap). A fordítás után keletkezik egy teglalap.class fájl, amelyet aztán felhasználhatunk más programokból:

/* a téglalap osztály felhasználása */
  
elso = teglalap(5,3)      -- csinálunk a 5x3-as téglalapot
elso.print                -- kinyomtatjuk adatait
elso.relsize(1,1).print   -- megnöveljük az oldalakat egy egységgel és újra kinyomtatjuk az adatokat

Ha pl. OS/2 alatt futtatjuk ezt a programot, akkor a fordítás után találni fogunk egy .crossref kiterjesztésû fájlt, amelyben a fordító kilistázza a programban használt változókat és azok típusát. Figyeljük meg, hogy az elso változó típusaként teglalap van megnevezve! Ha egy változóhoz már hozzárendeltünk egy adott típust, akkor az adott változó más típusú adatokat már nem tartalmazhat.

Tulajdonképpen az összes eddig ismertetett példaprogram is egy-egy osztálynak felel meg. A NetREXX környezet ugyanis automatikusan kiegészíti a programokat a szükséges class és method utasításokkal, hogy a program önálló futásra is képes legyen.

Módosított osztályok

Az objektum orientált nyelvekben bevett gyakorlat egy új osztály leszármaztatása egy már meglévô osztályból. Ha pl. azt szeretnénk, hogy a téglalap osztály print funkciója ki is rajzolja a téglalapot, akkor nem kell teljesen új osztályt készítenünk, hanem a már meglévô osztály felhasználásával képezhetünk egy újat:

/* kirajzolós téglalaposztály */
class ujtegla extends teglalap
printchar       -- a rajzoláshoz használt karakter
  
/* constructor téglalapobjektum készítéséhez */
method ujtegla(newwidth, newheight, newprintchar)
	super(newwidth, newheight) -- új téglalap készítése
	printchar = newprintchar     -- beállítjuk a rajzolókaraktert
  
/* a téglalap kirajzolása */
method print
	loop for super.height
        	say printchar.copies(super.width)
        end

A class utasítás paramétereként megadott extends teglalappal jelezzük, hogy az ujtegla osztály a teglalapból származik. Ez egyben azt is jelenti, hogy a teglalap által tartalmazott tulajdonságokat és metódusokat az ujtegla automatikusan örökli. Azt is szokták mondani, hogy az ujtegla alosztálya (subclass) a teglalapnak (super class). Az új osztály új tulajdonságként definiálja a rajzoláshoz használt karaktert (printchar). A constructor metódus a magasság és szélesség mellett ezt a paramétert is igényli. A metódus egyébként elôször meghívja a teglalap constructor metódusát, majd pedig beállítja a rajzolókaraktert. Végül az ujtegla osztály újradefiniálja a print metódust, amely kirajzolja a mérethelyes téglalapot. Az ujtegla print metódusa fölülírja (override) a teglalap print metódusát, mivel az abban az osztályban is definiálva volt. A többi metódust nem írjuk fölül, ezért ezek továbbra is változatlan formában használhatóak:

/* példa az ujtegla osztály használatára */
  
elso = ujtegla(5,3,'#')     -- új téglalap készítése
elso.print                   -- kirajzoltatása
elso.relsize(1,1).print      -- átméretezés utáni kirajzoltatás

A NetREXX metódusoknak lehetnek opcionális paraméterei is, ám ezeknek rendelkezni kell elôre definiált értékekkel is. Ha pl. azt szeretnénk, hogy a constructor metódus rajzolókaraktere opcionálisan megadható legyen, akkor azt a következô módon adhatjuk meg:

method ujtegla(newwidth, newheight, newprintchar='X')

Hibakövetés

Ugyanúgy mint a REXX-ben, a hibakövetési funkció a NetREXX-ben is a nyelv része. A program végrehajtása ugyanis a trace utasítás megadása után a képernyôn nyomon követhetô. Ha pl. a trace result utasítást adjuk meg egy programban, akkor valami ilyesmit láthatunk a futtatás során:

 2 *=*   number=1/7
    >v> number "0.142857143"
  3 *=*   parse number before '.' after
    >v> before "0"
    >v> after "142857143"
  4 *=*   say after'.'before
    >>> "142857143.0"

Az *=* jellel megjelölt sorok mutatják a végrehajtott utasításokat. A >v> jelek a köztes eredményeket, a >>> pedig a kimenetre küldött adatot jelenti. A metódusok végrehajtását is figyelemmel kísérhetjük, ha a trace method utasítást alkalmazzuk. Ebben az esetben találkozunk még a >a> jelöléssel, amely a metódusok argumentumait és azok értékét jelöli.

Bináris típusú változók és azok konverziója

A legtöbb programnyelv, többek között a Java is, támogatja a bináris adattípusok (byte, short, int, long, float, double, char, boolean) használatát. Ezek az adattípusok a számítógép hardvere által biztosított szolgáltatásokhoz kapcsolódnak, így a velük végzett mûveletek gazdaságosabban hajthatók végre, mint egyéb adattípusokkal. A NetREXX automatikusan konvertálja a színfalak mögött a karakterlánc típusú változókat. Az alapszabály az, hogy a konverzió során nem veszhet el információ. Amennyiben egy átalakításról ez nem állapítható meg elôre biztonsággal, akkor a konverzió csak a futás során fog megtörténni, amikor a konkrét értékek már ismertek. Ez a megközelítés nagyon kellemes a programozó számára, ugyanakkor rontja a futás sebességét, és bizonyos programok esetében ez nem megengedhetô. Ha el akarunk térni az alapmechanizmustól, akkor használhatjuk programunkban az options strictassign (szigorú típusellenôrzés mindenféle konverzió nélkül), vagy a már korábban ismertetett options binary (bináris aritmetika a decimális helyett). A bináris aritmetika általában jobb teljesítményt nyújt, ám ilyenkor a programozónak kell ügyelni pl. a túlcsordulások elkerülésére. Az option utasítást az elsô class utasítás elôtt kell megadni. Az options binary utasítást lehet használni egy osztályon belül is.

Igény esetén közvetlenül is meg lehet adni egy adott változó típusát:

i=int 3000000  -- integer, amelynek értéke 3000000
j=int 4000000  -- integer, amelynek értéke 4000000
k=int          -- integer érték nélkül
Say i*j        -- i és j szorzatának megjelenítése
k=i*j          -- i és j szorzatának hozzárendelése k-hoz

Érdemes felfigyelni rá, hogy automatikus konverzió esetén a compiler jelezné a túlcsordulást a k értékének kiszámításakor (1.20000000E+13). Bináris aritmetika használata esetén a hiba nem derülne ki automatikusan, és k a helytelen -138625024 értéket kapná.

Hibák automatikus lekezelése

A REXX-hez hasonlóan a NetREXX-ben is ismert a signal utasítás, amely a program egy elôre meghatározott részére adja a vezérlést, ha valamilyen váratlan esemény (exception) történik. A NetREXX esetében a váratlan eseményt lekezelô kódrészlet a catch utasítás után található:

Say 'Adjon meg egy számot, megmondom a reciprokát!'
number=ask
DO
	Say 'A szám reciproka:' 1/number
catch Exception
	Say 'Sajnos az 1-et nem lehet a 'number' értékkel osztani!'
END

A fenti kódrészlet a felhasználó által megadott szám reciprokát számolja ki. Ha pl. a felhasználó 0-át vagy nem számot ad meg bemeneti adatként, akkor a reciprok nem értelmezhetô. Ezekben az esetekben hajtódik végre a catch utasítás utáni kódrészlet, amely a hiba bekövetkezésérôl és okáról tájékoztatja a felhasználót. A catch utasítás használható mindazon esetekben, amikor END-re végzôdô (DO, LOOP, SELECT) konstrukcióról van szó. Egy konstrukción belül több catch utasítás is szerepelhet.

A NetREXX nyelv elérhetôsége

A NetREXX környezet ingyen letölthetô a http://www2.hursley.ibm.com/netrexx/" címrôl. A csomag elvileg futtatható minden olyan platformon, amelyik rendelkezik a Java Development Kit 1.1-es verziójával (Win9x, NT, 2000, Linux, Solaris, OS/2, stb.). A fejlesztôkörnyezeten kívül megtalálható itt a nyelv teljes dokumentációja és a példaprogramok széles skálája is.


REXX GYÍK:

K1. Készült-e a NetREXX-rôl piros könyv?
V1. Igen. A NetREXX-rôl, ugyanúgy mint a többi REXX változatról és IBM-es termékrôl készítettek piros könyvet. Letölthetô az http://www.redbooks.ibm.com címrôl, ha keresünk az SG24-2216 névre.

K2. Jelent-e meg egyéb könyv a NetREXX-rôl?
V2. Igen, bár csak angol nyelven. A REXX és NetREXX nyelvek szerzôje, Mike Cowlishaw írta 1997-ben a "The NetREXX Language" könyvet, amelynek ISB száma 0-13-806332-X, kiadója Prentice Hall.

K3. Letöltöttem a NetREXX 1.1x verzióját, de a telepítés után nem akar mûködni a gépemen lévô 1.0-ás Java motorral. Miért?
V3. A NetREXX 1.1x verziói minimum 1.1-es Java motort igényelnek. A leckében említett honlapról azonban letölthetô még a NetREXX 1.0-ás kiadása is, amely mûködik a pl. a Warp 4-be beépített 1.02-es motorral. A jobb teljesítmény érdekében azonban érdemes áttérni a Java motor újabb verziójára.


Gyakorlatok:

1. Töltse le a NetREXX honlapról a példaprogramokat és tanulmányozza ôket!

2. Hordozza néhány REXX-ben írt programját NetREXX alá!

Kádár Zsolt
1999. 12. 23.
[ Következô lecke | Tartalom ]