A REXX-ben használatos ciklusok fajtái
Korábban már volt szó a DO-END párosról, amely segítségével szerkezetek csoportját definiáljuk. A DO-END ugyanakkor egymás után többször is végrehajtott szerkezetcsoportok, más szóval ciklusok megvalósítására is felhasználható. A legtöbb ciklus feltételvezérelt. Ez azt jelenti, hogy egy feltétel határozza meg, hogy mikor fejezôdjön be a ciklus. Amikor a feltétel a ciklus elején kerül kiértékelésre, akkor do-while típusú ciklusról van szó, ami azt jelenti, hogy a ciklus addig kerül végrehajtásra, amíg a feltétel teljesül. Ennek az ellentettje a do-until konstrukció, amikor a feltétel a ciklus törzsének végrehatása után kerül megvizsgálásra. Ha a feltétel nem teljesül, akkor a ciklus törzse újra végrehajtódik, egészen addig, amíg a feltétel igazzá nem válik. Lényeges különbség a két forma között, hogy a do-until esetben a ciklus törzse legalább egyszer végrehatásra kerül, míg a do-while ciklus esetében ez egyáltalán nem garantált. Egy harmadik típus a számlálóhoz kötött ciklus. Ebben az esetben elôre megadjuk, hogy hányszor akarjuk végrehajtani a törzset és ezt egy számlálóval kontrolláljuk. Egyes programnyelvekben a számláló definiálásáról, értékének növelésérôl és a határérték elérésének vizsgálatáról a programozónak kell gondoskodni. Ebben az esetben nem is nagyon van értelme errôl a harmadik típusról külön megemlékezni, mivel ez tulajdonképpen visszavezethetô az elôzô két típus valamelyikére:
szam = 0 DO WHILE szam < 10 SAY 'I am busy!' szam = szam + 1 END
A REXX-ben szerencsére a számlálóval nem kell külön törôdnünk, mivel a fenti feladat e nélkül is megvalósítható:
DO 10 SAY 'I am busy!' END
A do-while és do-until ciklusok
A REXX programokban a do-while és do-until típusú ciklusok a DO WHILE END, illetve a DO UNTIL END utasításhármassal valósíthatók meg. Az elôzôekben láttunk már egy példát a DO WHILE END használatára, amikor a számlálókhoz kötött ciklusokról volt szó. Most lássunk egy komolyabb példát a DO UNTIL END alkalmazására. Az alábbi példában szereplô program bankszámlánk egyenlegét tartja nyílván:
/* Egyenlegszámítás */ SAY '' SAY 'Kérem az induló egyenleget!' PULL egyenleg SAY 'A tranzakciókat a<összeg> formában kell megadni!' SAY 'A következô kódok használhatók: F - pénz felvétel' SAY ' B - pénz berakás' SAY ' E - egyéb kiadás' DO UNTIL kod = '' SAY Right('Egyenleg:', 20) Format(egyenleg,,2)'Ft' PARSE UPPER PULL kod osszeg SELECT WHEN kod = 'F' THEN egyenleg = egyenleg - osszeg WHEN kod = 'B' THEN egyenleg = egyenleg + osszeg WHEN kod = 'E' THEN egyenleg = egyenleg - osszeg OTHERWISE NOP; END END EXIT
A futtatáskor a program bekéri a nyitó egyenleget, majd elkezdi végrehajtani a ciklus törzsében található utasításokat. A ciklustörzs minden egyes végrehajtásakor kiírja az aktuális egyenleget és vár a következô tranzakcióra. A tranzakciók a SELECT utasításban megadott kódok alapján befolyásolják az egyenleget. A hibás beviteli adatokat a program figyelmen kívül hagyja. A ciklus akkor fejezôdik be, amikor a felhasználó üres sort visz be.
Számlálók
Az elôzôekben már említettük, hogy a ciklusok egy részét számláló vezérli. Ez azonban fordítva is igaz lehet, mivel sokszor pontosan azért hozunk létre ciklusokat, hogy valamit számláljunk velük. A számlálóval vezérelt ciklusok kiemelkedô szerepük miatt külön csoporttá nôtték ki magukat a REXX-ben. A DO TO BY FOR END utasítások variálásával a számlálóvezérelt ciklusok igen változatos példányait fogalmazhatjuk meg könnyen és tömören. A leggyakrabban használt párosítás a DO TO END:
DO i = 1 TO 5 SAY i END
Ebben az esetben egyszerûen arról van szó, hogy 5-ször hajtjuk végre a ciklust, mivel 1-tôl 5-ig számlálunk az i-vel. Ha nem egyesével akarjuk a számláló értékét növelni, akkor a növekedés értékét a BY utasítással adhatjuk meg:
DO i = 1 TO 9 BY 3 SAY i END
Itt 3-szor fog a ciklus lefutni, mivel 1-tôl számolunk 9-ig, 3-as növekedéssel. A BY paramétere lehet negatív is. Ekkor minden lépésben csökkenni fog a számláló értéke a BY után megadott negatív szám abszolút értékével:
DO i = 10 TO 1 BY -1 SAY i END
Egy másik lehetôség a FOR használata, amellyel kerek-perec megmondhatjuk, hogy hányszor akarjuk a ciklust végrehajtani:
DO i = 1 BY 3 FOR 5 SAY i END
Ebben az esetben tehát ötször fut le a ciklus. A számláló értéke 1-rôl indul és ötször növekszik 3-mal. Elvileg a FOR és a TO egy szerkezetben is használható. Ekkor a ciklus végrehajtása akkor fog leállni, amikor az egyik szabályozó feltétel teljesül. A számláló nevét megadhatjuk a ciklust lezáró END paramétereként. Ez hasznos lehet akkor, ha egymásba ágyazott ciklusokkal dolgozunk:
DO i = 1 TO 9 BY 3 DO j = 1 FOR 4 SAY i j END j END i
Ilyen esetben ügyelnünk kell arra, hogy ne cseréljük fel a számlálókat az END utasítások mellett, mivel akkor szintakszis hibát fog jelezni az értelmezô.
Végtelen ciklusok
A végtelen ciklusok általában úgy jönnek létre, hogy olyan feltételtôl tesszük függôvé a ciklusból való kilépést, amely sohasem teljesül:
i = 1 DO WHILE i < 5 SAY i END
A fenti példában az i értéke a ciklus végrehajtása alatt végig 1 marad, így a kilépést kontrolláló feltétel (i < 5) végtelen ideig igaz marad. Egy ilyen ciklusból csak akkor tudunk kiszabadulni, ha megszakítjuk a program futását a CTRL-BREAK megnyomásával. Egy másik (hiba)lehetôség végtelen ciklus létrehozására a TO vagy FOR nélküli BY:
DO i = 1 BY 2 SAY i END
A végtelen ciklusok azonban hasznosak is tudnak lenni. Ha például nem tudjuk elôre, hogy hányszor kell egy ciklust végrehajtani (pl. várunk egy bizonyos billentyû leütésére), akkor általában kénytelenek vagyunk a várakozást végtelen ciklussal megoldani és valamilyen más módon gondoskodunk róla, hogy a kérdéses billentyû megnyomásakor mégiscsak elhagyjuk a ciklust. Ha szándékosan hozunk létre végtelen ciklust, akkor azt lehetôleg a DO FOREVER konstrukcióval tegyük:
DO FOREVER SAY 'Ez itt egy szándékos végtelen ciklus!' END
Kiugrás a ciklusokból
Mint ahogy azt a szándékosan létrehozott végtelen ciklusok esetében is láttuk, idônként szükség lehet arra, hogy a ciklusból egy ún. kiskapun keresztül is kiléphessünk. Erre az esetre hozták létre a LEAVE utasítást, mely végrehajtása azonnal leállítja a ciklus futását:
DO FOREVER SAY 'Ez itt egy szándékos végtelen ciklus, amelybôl' SAY 'csak a STOP paranccsal lehet kilépni.' PULL parancs IF parancs = 'STOP' THEN LEAVE END
Egymásba ágyazott ciklusok esetén, a ciklus számlálóját a LEAVE paramétereként megadva szabályozhatjuk, hogy melyik ciklusból ugorjunk ki:
DO i = 1 TO 25 DO j = 1 TO 100 IF i * j > 100 THEN LEAVE i END j END i
A fenti példában i-t adtuk meg paraméternek, ezért mindkét ciklusból kiugrunk, ha az i*j > 100 feltétel teljesül. Egy másik hasznos ciklusokkal kapcsolatos utasítás az ITERATE. Ezt akkor szoktuk használni, amikor valamilyen feltétel teljesülése esetén nem akarjuk már a ciklus maradék részét végrehajtani, hanem kezdeni akarjuk a következô iterációt. Azt is lehet mondani, hogy az ITERATE utasítással a vezérlés egybôl a ciklus elejére ugrik. A következô példában az ITERATE használatával kikerüljük a SAY utasítás végrehajtását:
DO 1000 SAY 'Eleged van már?' PULL valasz IF valasz <> 'YES' THEN ITERATE SAY 'Nem hinném!' END
Az ITERATE utasítást szinte mindig az IF vagy a SELECT utasítások valamelyikével kombináljuk. A LEAVE használatával kapcsolatban annyit érdemes megjegyezni, hogy lehetôleg kerülni kell alkalmazását, mivel a GOTO-hoz hasonlóan nehezen áttekinthetôvé teszi a programot. Csak akkor használjuk, ha ezzel jelentôsen egyszerûsíthetô a program!
REXX GYÍK:
K1. Hogyan döntsem el, hogy WHILE vagy UNTIL típusú ciklust használjak?
V1. Ökörszabályként azt lehet mondani, hogy ez attól függ, hogy a ciklus törzsét a ciklusfeltétel ellenôrzése elôtt vagy után kell végrehajtatni. Ha ez mellékes és a két megvalósítási forma bonyolultsági fokát tekintve sincs lényeges különbség, akkor használjunk WHILE ciklust!
K2. Miért nem csinál a DO i = 1 to 10 BY -1 semmit?
V2. A kiértékeléskor az értelmezô elôször megnézi a BY paraméterének elôjelét, hogy megállapítsa, hogy melyik irányba kell változtatni a számláló értékét. Ezután összehasonlítja a számláló kezdô és végértékét. Ebben az esetben azonban a kezdôérték már eleve kisebb, mint a végérték, így további csökkentésnek már nincs semmi értelme.
Gyakorlatok:
1. A következô program egy háromszöget nyomtat ki. Alakítsa át a programot, hogy a háromszög a 'feje tetejére' forduljon!
/* Háromszög */ string = '*********' DO i = 1 TO Length(string) BY 2 SAY Center(Left(string, i), Length(string)) END EXIT
2. Készítsen egy programot, amely bekér egy pozitív egész számot és egészen addig ismétli a kérést, amíg a felhasználó a feltételeknek eleget tevô adatot nem visz be!
3. Készítsen egy programot, amely bekér egy karakterláncot és megszámolja a karakterláncban található mássalhangzókat!
| Kádár Zsolt 1998. 04. 18. | [ Elôzô lecke | Következô lecke | Tartalom ] |