7. PŘÍKAZY PRO VĚTVENÍ PROGRAMU 7.1. Příkaz IF - - |příkaz ... | Formát: IF podmíněný-výraz THEN |NEXT SENTENCE| - - -- -- | - -| | |příkaz ... || |{ ELSE | OTHERWISE } |NEXT SENTENCE|| [END-IF] | - -| -- -- Funkce: Příkaz IF způsobí provádění nebo přeskočení příkazů uvedených za THEN resp. za ELSE (OTHERWISE) v závislosti na pravdivosti uvedeného podmíněného výrazu. Podrobný popis funkce příkazu IF je uveden v 7.3. 7.2. Příkaz ON Formát: ON { celé-číslo | celočíselná-položka } [ AND EVERY { celé-číslo | celočíselná-položka } ] [ UNTIL { celé-číslo | celočíselná-položka } ] - - |příkaz ... | THEN |NEXT SENTENCE| - - -- -- | - -| | |příkaz ... || |{ ELSE | OTHERWISE } |NEXT SENTENCE|| [END-IF] | - -| -- -- Funkce: Celá čísla uvedená v příkazu ON musí být kladná a nejvýše rovná 2147483647; totéž musí platit pro hodnoty uvedených celočíselných položek. Přitom tyto hodnoty se při prvním provádění příkazu ON uschovají, načež v následujícím výpočtu se již pracuje pouze s těmito uschovanými počátečními hodnotami stejně tak, jako kdyby v příkazu ON byla uvedena takováto celá čísla. Případné další změny těchto položek již nemají na činnost příkazu ON žádný vliv. Každý příkaz ON si určitým způsobem počítá, kolikrát již byl prováděn. Každému průchodu určitým příkazem ON je takto přiřazeno přirozené číslo 1,2,3,4,... udávající, po kolikáté se tento příkaz ON právě provádí. Pomocí formátu příkazu ON je určena jistá posloupnost přirozených čísel, která může být konečná anebo nekonečná (případně i prázdná). Tím jsou všechny průchody příkazem ON rozděleny na "označené", jejichž pořadová čísla patří do této posloupnosti, a na "neoznačené", jejichž pořadová čísla do této posloupnosti nepatří. Jsou-li x, y, z celá čísla nebo hodnoty uvedených celočíselných položek při prvním provádění příkazu ON, jsou pořadová čísla "označených" průchodů určena takto: a) ON x AND EVERY y UNTIL z Pro x >= z nejsou žádné označené průchody. Pro x < z mají označené průchody pořadová čísla x, x+y, x+2y, x+3y, ..., x+ny, kde pořadové číslo posledního označeného průchodu je posledním číslem z této posloupnosti, které je ještě menší než z (tedy x+ny < z, ale x+ny+y >= z). b) ON x UNTIL z Má stejný význam jako "ON x AND EVERY 1 UNTIL z" (tzn. je-li uvedena klauzule UNTIL, lze klauzuli "AND EVERY 1" vynechat). Pro x >= z nejsou tedy žádné označené průchody, pro x < z mají označené průchody pořadová čísla x, x+1, x+2, ..., z-2, z-1. c) ON x AND EVERY y Označenými průchody jsou průchody s pořadovými čísly x, x+y, x+2y, x+3y, ... bez horního omezení. d) ON x Je pouze jediný označený průchod, a to průchod s pořadovým číslem x. Příkaz ON způsobí provádění nebo přeskočení příkazů uvedených za THEN resp. za ELSE (OTHERWISE) v závislosti na tom, zda právě prováděný průchod příkazem ON je "označený" nebo "neoznačený". Podrobný popis funkce příkazu ON je uveden v 7.3. Poznámka: V jazyce COBOL neexistuje žádná možnost, jak znovu inicializovat příkaz ON (např. po jeho "vyčerpání") tak, aby následující průchod byl považovaný opět za první, tj. aby se průchody začaly počítat zase od začátku. (Při dobré znalosti cílového C-programu by ovšem bylo možné provést inicializaci příkazu ON pomocí příkazu UFO modifikujícího čítače používané tímto příkazem ON; vhodnější je však definovat si v takovém případě vlastní počitadlo a používat příkaz IF.) Poznámka: Je účelné považovat příkaz ON za zvláštní případ příkazu IF: "označený" průchod odpovídá pravdivému podmíněnému výrazu, zatímco "neoznačený" průchod odpovídá nepravdivému podmíněnému výrazu. 7.3. Činnost příkazů IF a ON Pravidla: a) Slova ELSE a OTHERWISE jsou ekvivalentní; v dalším textu budeme proto mluvit pouze o ELSE. b) Zápis NEXT SENTENCE má význam prázdného příkazu, který neprovádí žádnou akci; v jazyce MX COBOL však může být zápis NEXT SENTENCE vždy vynechán. Bývá obvyklé (i když to není povinné), aby za slovy NEXT SENTENCE (resp. pouze NEXT) následovala tečka nebo některá z klauzulí ELSE, OTHERWISE, END-IF, END-PERFORM nebo WHEN. c) Určení, která klauzule ELSE resp. END-IF patří ke kterému příkazu IF/ON, a dále definice konce rozsahu příkazu IF/ON viz 5.1.F. S určitými výjimkami (jež vznikají v důsledku klauzulí WHEN a END-PERFORM) většinou platí, že ELSE patří k nejblíže předcházejícímu IF/ON, které dosud nemělo ELSE ani END-IF, že END-IF patří k nejblíže předcházejícímu IF/ON, které dosud nemělo END-IF, a že konec rozsahu příkazu IF/ON je určen klauzulí klauzulí END-IF nebo tečkou. Funkce: a) Formát bez ELSE: Je-li podmíněný výraz pravdivý (resp. průchod "označený"), přechází se na příkazy bezprostředně následující za příkazem IF/ON (tj. za nepovinným slovem THEN).Je-li podmíněný výraz nepravdivý (resp. průchod "neoznačený"), přeskočí se příkazy bezprostředně následující za příkazem IF/ON (tj. za THEN) a jako další se bude provádět první příkaz za koncem rozsahu příkazu IF/ON (tj. většinou za odpovídající klauzulí END-IF nebo za tečkou). Příklad: IF A = B MOVE 0 TO C ADD 1 TO D. MOVE X TO Y ... -------------------->------------------ ne | | --------- ano -------- ---------- | -------- --->|A = B ?|-------| 0->C |-----| D+1->D |------| X->Y |--> --------- -------- ---------- -------- Stejné schéma bychom obdrželi i v případě IF A = B MOVE 0 TO C ADD 1 TO D END-IF MOVE X TO Y ... b) Formát s ELSE: Je-li podmíněný výraz pravdivý (resp. průchod "označený"), přechází se na příkazy bezprostředně následující za příkazem IF/ON (tj. za nepovinným slovem THEN); při dosažení klauzule ELSE se pak přeskočí příkazy uvedené za ELSE a jako další se bude provádět první příkaz za koncem rozsahu příkazu IF/ON (tj. většinou za odpovídající klauzulí END-IF nebo za tečkou). Je-li podmíněný výraz nepravdivý (resp. průchod "neoznačený"), přeskočí se příkazy bezprostředně následující za příkazem IF/ON (tj. za THEN) a jako další se bude provádět první příkaz za klauzulí ELSE. Příklad: IF A < B MOVE A TO C ADD 1 TO D ELSE MOVE B TO C SUBTRACT 1 FROM D. MOVE X TO Y ... -------- ---------- ano------->| A->C |---->| D+1->D |--- ------- -------- ---------- | -------- ---->| A| X->Y |---> ------- -------- ---------- | -------- ne------->| B->C |---->| D-1->D |--- -------- ---------- Stejná schéma bychom obdrželi i v případě IF A < B MOVE A TO C ADD 1 TO D ELSE MOVE B TO C SUBTRACT 1 FROM D END-IF MOVE X TO Y ... Poznámka: Klauzule END-IF znamená vlastně jakousi "soukromou tečku" pro odpovídající příkaz IF/ON. Tzv. "rozsah" příkazu IF/ON s klauzulí END-IF pak sahá pouze po toto END-IF a nikoliv až po tečku ukončující větu programu (jak by tomu většinou bylo bez klauzule END-IF), kterážto tečka pak již nemá k tomuto příkazu IF/ON vůbec žádný vztah, tzn. tento příkaz IF/ON ani jeho případná klauzule ELSE ani žádný další podmíněný příkaz začínající uvnitř jeho rozsahu nikdy nezpůsobují skok za tuto tečku. Klauzule END-IF je velmi užitečná v případě, že chceme ukončit "rozsah" určitého příkazu IF/ON, nemůžeme to však učinit pomocí obvyklé tečky, neboť bychom takovou tečkou zároveň ukončili "rozsahy" i jiných podmíněných příkazů předcházejících před naším příkazem IF/ON v téže větě programu (např. dalšího příkazu IF, ON, SEARCH, příkazu s klauzulí AT END, INVALID KEY, ON SIZE ERROR, ON OVERFLOW, AT EOP resp. AT END-OF-PAGE nebo NO DATA anebo příkazu PERFORM bez procedury), jejichž "rozsahy" dosud ukončit nechceme. Tato situace nastává obzvláště ve větách programu obsahujících několik příkazů IF/ON anebo ve větách typu READ S AT END MOVE A TO B IF C = 1 MOVE D TO F ELSE MOVE E TO F END-IF IF G = 0 ADD 2 TO H END-IF COMPUTE M = F * H / 50 (Tečka za příkazem COMPUTE ukončuje rozsah příkazu READ, nikoliv však rozsahy obou příkazů IF, kteréžto rozsahy končí již na odpovídajících klauzulích END-IF.) Poznámka: Klauzule END-IF znamená "soukromou tečku" nejen pro odpovídající příkaz IF/ON, ale též pro všechny příkazy SEARCH a příkazy s klauzulemi AT END, INVALID KEY, ON SIZE ERROR, ON OVERFLOW, AT EOP resp. AT END-OF-PAGE nebo NO DATA ležící mezi začátkem tohoto příkazu IF/ON a slovem END-IF. I jejich "rozsahy" jsou tedy touto klauzulí END-IF ukončeny, tzn. při dosažení klauzule WHEN resp. při neuplatnění příslušné klauzule se skáče nikoliv až na první příkaz za tečkou, nýbrž již na první příkaz za slovem END-IF. Navíc klauzule ELSE nebo END-IF ukončuje "rozsahy" všech příkazů PERFORM bez procedury začínajících mezi začátkem odpovídajícího příkazu IF/ON a slovem ELSE resp. END-IF, které dosud nebyly ukončeny (stejně jako kdyby bezprostředně před tímto ELSE resp. END-IF byla pro každý takový příkaz PERFORM explicitně uvedena klauzule END-PERFORM). Obráceně explicitně uvedená nebo implicitně předpokládaná klauzule END-PERFORM ukončuje "rozsahy" všech příkazů IF/ON začínajících mezi začátkem odpovídajícího příkazu PERFORM bez procedury a slovem END-PERFORM, které dosud nebyly ukončeny (stejně jako kdyby bezprostředně před tímto END-PERFORM byla pro každý takový příkaz IF/ON explicitně uvedena klauzule END-IF). Příklad: IF A = 0 READ S AT END GO TO P END-IF MOVE X TO Y ... Nedojde-li ke "konci souboru", odskočí příkaz READ nikoliv až za tečku, nýbrž jen na příkaz MOVE následující za END-IF. Poznámka: Klauzule END-IF, za níž by bezprostředně následovala tečka nebo klauzule END-PERFORM, by neměla žádný smysl a ignorovala by se, neboť tečka i klauzule END-PERFORM zahrnují funkci klauzule END-IF implicitně. Podobně klauzule "ELSE NEXT SENTENCE", za níž by bezprostředně následovala tečka nebo klauzule END-IF nebo klauzule END-PERFORM, by neměla žádný smysl a ignorovala by se, neboť tečka, END-IF i END-PERFORM zahrnují u příkazu IF/ON bez klauzule ELSE zároveň funkci klauzule "ELSE NEXT SENTENCE" implicitně. (Za klauzulí "ELSE NEXT SENTENCE" má smysl jedině klauzule ELSE od příkazu IF/ON předcházejícího před naším příkazem IF/ON.) Příklad: IF A = 0 IF B = 0 IF C = 0 MOVE 1 TO T ELSE MOVE 2 TO T ELSE MOVE 3 TO T COMPUTE X = - C / B ELSE COMPUTE X = - B / (A + A) COMPUTE P = B**B - 4 * A * C IF P NOT NEGATIVE MOVE 4 TO T COMPUTE P = P ** .5 COMPUTE P = P / (A + A) COMPUTE Y = X - P ADD P TO X ELSE MOVE 5 TO T COMPUTE P = (- P) ** .5 COMPUTE Y = P / (A + A). Příklad: IF A = 0 ON 5 AND EVERY 10 DISPLAY B ELSE DISPLAY C ELSE IF A = 1 ON 20 AND EVERY 20 UNTIL 100 DISPLAY D ELSE NEXT SENTENCE ELSE IF A = 2 ON 200 UNTIL 250 DISPLAY E SPACE F. Příklad: IF A = 0 MOVE 1 TO B IF C = 1 MOVE 3 TO D ELSE MOVE 7 TO D END-IF MOVE 2 TO E IF F = 1 IF G = 1 MOVE 3 TO H ELSE MOVE 5 TO H END-IF ELSE IF G = 1 MOVE 8 TO H ELSE MOVE 4 TO H END-IF MOVE 5 TO U IF M NOT = 0 COMPUTE M = 1 / M END-IF MOVE 6 TO V END-IF IF I = 0 ADD 1 TO J ELSE ADD 2 TO J ELSE IF C = 1 MOVE 5 TO D ELSE MOVE 6 TO D END-IF IF F = 1 MOVE 9 TO H ELSE MOVE 7 TO H. Příklad: IF P = 1 READ S1 AT END IF Q = 1 GO TO V1 ELSE GO TO V2 ELSE READ S2 AT END IF R = 1 GO TO V3 ELSE GO TO V4. Příklad: a) ON 5 AND EVERY 7 UNTIL 40 DISPLAY A ELSE DISPLAY B. Při 5., 12., 19., 26. a 33. průchodu se vytiskne A, při všech ostatních průchodech se vytiskne B. b) ON 1000 UNTIL 1010 NEXT SENTENCE ELSE ADD A TO B. Při 1000., 1001, 1002., ..., 1008., 1009. průchodu se neprovádí nic, při všech předcházejících i při všech následujících průchodech se provádí příkaz ADD. c) ON 1 UNTIL 100 ADD A(I) TO B MOVE 1 TO J GO TO ZNOVU. Při prvních 99 průchodech se provádějí příkazy ADD, MOVE a GO, při všech následujících průchodech se tyto příkazy přeskakují a přechází se až na první příkaz za tečkou. d) ON 2 AND EVERY 2 DISPLAY A ELSE DISPLAY B. Při sudých průchodech (2., 4., 6., ...) se tiskne A, při lichých průchodech (1., 3., 5., ...) se tiskne B. e) ON 1000 DISPLAY A DISPLAY B DISPLAY C. Při tisícím průchodu se vytisknou položky A, B a C. Při všech předcházejících i pře všech následujících průchodech se tyto příkazy přeskakují a přechází se až na první příkaz za tečkou.