VIII. Döntéshozatal a programok futása közben

Programvezérlés

Az eddig látott példaprogramok többségének végrehajtási sorrendje megegyezett a szerkezetek kódbafoglalásának a sorrendjével. Ebben a leckében megismerkedünk azokkal a vezérlô szerkezetekkel, amelyekkel a lépések végrehajtási sorrendjébe avatkozhatunk be. Az elsô alapfogalom, amelyet tisztáznunk kell, az állítás. Az állítás értéke az igazságtartalomtól függôen 0 (hamis) vagy 1 (igaz) lehet. Az állítást tulajdonképpen úgy is definiálhatjuk, mint egy operátor, amelynek végeredménye kizárólag 0 vagy 1 lehet. A leggyakrabban elôforduló állítások relációs operátorokkal végzett összehasonlításon alapszanak. Bonyolultabb esetekben a relációs operátorokkal képzett összehasonlításokat kombináljuk logikai operátorokkal is. Lássuk hogyan!

Relációs és logikai operátorok használata

A relációs operátorok szerepe tulajdonképpen megegyezik egy olyan kérdésfelvetéssel, amelyben azt kérdezzük, hogy két adat milyen viszonyban (pl. egyenlô, kisebb stb.) van egymással. Az alábbi táblázatban összefoglaltuk a REXX-ben elôforduló relációs operátorokat, jelölésüket és jelentésüket.

OperátorJelentésPélda
=egyenlôa = b
>nagyobba > b
<kisebba < b
<>, ><, \=, ª=nem egyenlôa <> b
\>, ª>nem kisebba \> b
>=nagyobb vagy egyenlôa >= b
<=kisebb vagy egyenlôa <= b

Egyes operátoroknak több megjelenési formája is lehet. A legjobb példa erre a nem egyenlôség kifejezése, melyet négyféleképpen is megtehetünk. A relációs operátorokat az aritmetikai operátorokhoz hasonlóan használhatjuk, s az összehasonlítás eredményét változóban is eltárolhatjuk, s a késôbbiekben újra felhasználhatjuk. A sok elmélkedés után lássunk erre egy példát!

/* Relációs operátorok használata */

SAY 'Gépelj be egy számot!'
PULL szam

SAY szam '= 10 eredménye; ' (szam = 10)
SAY szam '< (2 ** 32 - 1) eredménye: ' (szam < (2 ** 32 - 1))
SAY szam '> 0 eredménye: ' (szam > 0)

EXIT

Ez a példaprogram bekér egy számot és ez alapján kiértékeli a három összehasonlítást. Az eredménytôl függôen 0-át (hamis állítás) vagy 1-et (igaz állítás) kapunk vissza.

A logikai operátoroknak három fajtája ismert a REXX-ben: & (logikai és - AND), | (logikai vagy - OR), && (kizáró vagy - XOR). Tulajdonképpen ide tartozik még a negálás is (\ vagy ª), mely segítségével ellenkezôjére változtathatjuk egy összehasonlítás eredményét (invertálás). A logikai operátorok nagyon fontosak, mivel segítségükkel kombinálhatjuk az összehasonlításokat, és így egy lépésben írhatunk el bonyolult feltételeket. Ha kombinálunk, akkor mindig érdemes (bár nem kötelezô) zárójeleket használni, hogy néhány nap eltelte után is könnyedén tudjuk értelmezni a kifejezést:

potencialis_times_vasarlo = (kor < 100) & (kor > 1)

Az alábbi táblázatban összefoglaltuk a logikai operátorokat:

KifejezésJelentésÉrték igaz, ha...
feltétel1 & feltétel2feltétel1 AND feltétel2mindkét feltétel igaz
feltétel1 | feltétel2feltétel1 OR feltétel2egyik vagy mindkét feltétel igaz
feltétel1 && feltétel2feltétel1 XOR feltétel2csak az egyik feltétel igaz
ª feltétel, \ feltételNOT feltétela feltétel hamis

A relációs és logikai operátorok viszonya

Az ötödik leckében volt szó az operátorok kiértékelési sorrendjérôl. A relációs és logikai operátorok valamint az egyéb operátorok között is létezik elsôbbségi sorrend, amelyet az alábbi táblázat tartalmaz:

Operátor csoportPéldákSorrend
unáris operátorok- + \ ªLegelsô
hatványozás**
szorzás, osztás* / % //
összeadás, kivonás+ -
összehasonlítás= <> \> >=
logikai és&
vagy, kizáró vagy| &&Legutolsó

Mint ahogyan azt már megtanultuk, a kiértékelés sorrendje megváltoztatható zárójelezéssel. A &, | és && operátorok használatakor a sorrend nem mindig magától értetôdô, ezért ekkor is használjunk zárójeleket! A táblázatból az is látszik, hogy a logikai és összehasonlító operátorok precedenciája alacsonyabb, mint az aritmetikai operátoroké. Ez azt jelenti, hogy pl. az a_kisebb_mint = a < 1 + 5 * 4 kifejezést a REXX minden további nélkül helyesen fogja kiértékelni, azonban a könnyû értelmezhetôség érdekében itt is érdemes zárójelezni.

Az IF utasítás

A relációs és logikai operátorokkal felépített állítások tesztelésére és a szerkezetek végrehajtásának sorrendjébe való beavatkozásra használjuk az IF utasítást. Az IF ugyanis a feltételtôl függôen végrehajtatja vagy figyelmen kívül hagyatja a kapcsolt szerkezetet. Lássunk erre egy példát:

IF modem = 'BUSY' THEN
	SAY 'A hívott szám foglalt!'

A végrehajtás során elôször a modem = 'BUSY' összehasonlítás kerül kiértékelésre. Ha az eredmény igaz, akkor a kapcsolt szerkezet végrehajtódik és a 'A hívott szám foglalt!' üzenet jelenik meg. Ha az eredmény nem igaz, akkor a kapcsolt szerkezet nem hajtódik végre, hanem a vezérlés a sorban következô szerkezetre ugrik. Az IF utasítások egymásba is ágyazhatók. Íme egy példa:

IF time >= '09:00' THEN
	IF time <= '17:00' THEN
		SAY 'Munkaidô'

A kiértékelés során elôször az elsô feltétel kerül megvizsgálásra. Ha az eredmény igaz, akkor a második lépés a második feltétel kiértékelése. Csak ha ez is teljesül, akkor jelenik meg a 'Munkaidô' üzenet. Az egymásbaágyazással ugyanazt az eredményt érjük el (csak sokkal bonyolultabban), mint a logikai és operátorral:

IF time >= '9:00' & time <= '17:00' THEN
	SAY 'Munkaidô'

Figyeljük meg az egymásbaágyazott IF utasítások struktúráját! Minden szinten egy kicsit beljebb kezdtük a szöveget, hogy a logikai felépítést ezzel is visszaadjuk. Elvileg erre nem lenne szükség; az IF-eket egyszerûen egymás alá is írhattuk volna, a program ettôl ugyanolyan jól futna. A kód könnyû értelmezhetôségére való tekintettel azonban nagyon is kívánatos, hogy programíráskor mindenki a fenti sémához tartsa magát.

Az ELSE utasítás

Az ELSE utasítás szorosan együttmûködik az IF-fel. Amikor az IF feltétele hamis, akkor az ELSE-hez kapcsolt szerkezet kerül végrehajtásra. Ha pl. az idôpont alapján közölni akarjuk, hogy munkaidô van-e vagy sem, akkor azt a következôképpen oldhatjuk meg:

IF time >= '9:00' & time <= '17:00' THEN
	SAY 'Munkaidô'
ELSE
	SAY 'Nem munkaidô'

Természetesen ugyanezt ELSE nélkül, csak IF-ekkel is megoldhatjuk, bár ekkor többet kell írni:

IF time >= '9:00' & time <= '17:00' THEN
	SAY 'Munkaidô'
IF time > '9:00' | time < '17:00' THEN
	SAY 'Nem munkaidô'

Természetesen az ELSE utasításokat is egymásba lehet ágyazni, ekkor azonban nagyon ügyelni kell arra, hogy a program valóban azt csinálja, amit akarunk. Az ELSE utasítás ugyanis mindig az utolsó IF-hez kapcsolódik, s ezt sokan figyelmen kívül hagyják! Tekintsük meg az alábbi kódrészletet!

IF a = b THEN
	IF c = d THEN
		SAY 'Találat'
ELSE
	SAY 'Nincs találat'

A struktúra alapján nyilvánvaló, hogy a programozó szándéka az volt, hogy a 'Találat' szöveg jelenjen meg, ha a = b és c = d, minden más esetben pedig a 'Nincs találat'. Az ELSE utasítás azonban a második IF-hez tartozik, ezért - a programozó elgondolásával ellentétesen - a 'Nincs találat' csak akkor fog megjelenni, ha c <> d. A probléma megoldása lehet egy ál ELSE beiktatása:

IF a = b THEN
	IF c = d THEN
		SAY 'Találat'
	ELSE
		NOP
ELSE
	SAY 'Nincs találat'

A NOP utasítás hatására nem történik semmi, viszont elértük, hogy a második ELSE a megfelelô (elsô) IF-hez kapcsolódjon.

Csoportos utasítások

Gyakran fordul elô, hogy az IF vagy az ELSE utasítás után egynél több szerkezetet is végre akarunk hajtatni. Ekkor jön jól a DO - END utasításpár, amely a szerkezetek csoportosítására szolgál. Minden DO - END pár közé írt szerkezetcsoport kívülrôl egy szerkezetnek látszik, így tehát jól használható a fenti példaprobléma ál-ELSE nélküli áthidalására is:

IF a = b THEN
	DO
	IF c = d THEN
		SAY 'Találat'
	END
ELSE
	SAY 'Nincs találat'

A SELECT utasítás

Sokszor jön elô az is, hogy a program végrehajtása során ellenôrizni akarjuk egy változó értékét és a lehetséges értékektôl függô kódrészletet akarunk végrehajtani. Ez természetesen megoldható egy hosszú, egymásba ágyazott IF - ELSE struktúrával:

IF input = '1' THEN
	SAY 'Micimackó'
ELSE IF input = '2' THEN
	SAY 'Lacimaci'
ELSE IF input = '3' THEN
	SAY 'Cooper ügynök'
ELSE
	SAY 'Ismeretlen'

A kódrészlet futásakor az input változó értékétôl függô nevek vagy az 'Ismeretlen' felirat jelenik meg a képernyôn. Ettôl sokkal elegánsabban megoldható a feladat a SELECT utasítással:

SELECT
WHEN input = '1' THEN
	SAY 'Micimackó'
WHEN input = '2' THEN
	SAY 'Lacimaci'
WHEN input = '3' THEN
	SAY 'Cooper ügynök'
OTHERWISE
	SAY 'Ismeretlen'
END /* SELECT */

Minden SELECT szerkezetet END-nek kell lezárnia. A kiértékelés során a REXX sorban teszteli a feltételeket és végrehajtja a kapcsolt utasítást, ha az eredmény igaz. Ezután a vezérlés az END-re ugrik, s a többi feltétel nem kerül feldolgozásra. Ha egyik feltétel sem igaz, akkor az OTHERWISE-hoz kapcsolt utasítás hajtódik végre. A SELECT utasítás nem kívánja meg, hogy ugyanazt a változót teszteljük a struktúrán belül. Lássunk erre az utasításra egy példát egy kissé komolyabb programban, amely a már korábban megismert Zeller eljárás segítségével megmondja a bevitt születési dátum alapján, hogy melyik napon született az adott személy. Reméljük, hogy a program mûködése az elôzôek alapján mindenkinek érthetô lesz!

/* A születés napja */

SAY 'Gépeld be a születési dátumodat! (hó nap év sorrendben)'
SAY 'Példa: 03 24 1968'
PULL honap nap ev

tmp = Zeller()

SELECT
WHEN tmp = 0 THEN
	valasz = 'Hétfô'
WHEN tmp = 1 THEN
	valasz = 'Kedd'
WHEN tmp = 2 THEN
	valasz = 'Szerda'
WHEN tmp = 3 THEN
	valasz = 'Csütörtök'
WHEN tmp = 4 THEN
	valasz = 'Péntek'
WHEN tmp = 5 THEN
	valasz = 'Szombat'
OTHERWISE
	valasz = 'Vasárnap'
END

SAY 'Születésed napja: 'valasz
EXIT

Zeller:
IF honap > 2 THEN
	DO
		kepzett_honap = honap - 2
		kepzett_ev    = ev
	END
ELSE
	DO
		kepzett_honap = honap + 10
		kepzett_ev    = ev - 1
	END

evszazad       = kepzett_ev % 100
ev_a_szazadban = kepzett_ev - 100 * evszazad
a_het_napja    = ((13 * kepzett_honap - 1) % 5 + nap +,
                 ev_a_szazadban + ev_a_szazadban % 4 - evszazad -,
                 - evszazad + 77) // 7
RETURN a_het_napja


REXX GYÍK:

K1. Hogyan különbözteti meg a REXX az értékadást az összehasonlítástól? Mindkettô a = jellel történik!
V1. A REXX ezt a szövegkörnyezetbôl állapítja meg. Minden olyan szerkezet, amelyben egy változót az egyenlôségjel követ, értékadásként lesz értelmezve. Minden más helyzetben pedig összehasonlításként.


Gyakorlatok:

1. Melyik operátor élvez végrehajtási elsôbbséget?
a. < vagy +
b. \ vagy **
c. && vagy &
d. \> vagy <>

2. A következô programban hiba van. Keresse meg!

/* Hibás program */
SAY 'Tegyél be egy lemezt!'
SAY 'Nyomja meg az ENTERT-t, ha kész!'
PULL .
XCOPY C:\OS2\*.INI A:\ > NUL
IF RC <> 0 THEN
	SAY 'Error'
EXIT

Kádár Zsolt
1998. 03. 08.
[ Elôzô lecke | Következô lecke | Tartalom ]