IV.  

PŘÍKAZY


Příkazy předpisují provedení jistých algoritmických činností. Podle struktury je lze dělit na jednoduchéstrukturované. Mohou být opatřeny návěštím, použitelným jako cíl skoku v příkazech goto.

Obrázek 13: Příkaz

IV.1. 

Jednoduché příkazy

Jednoduché jsou příkazy bez vnitřní struktury, neobsahující již žádný příkaz dílčí. Turbo Pascal implementuje celkem čtyři jednoduché příkazy:

Obrázek 14: Jednoduché příkazy

Přiřazovací příkaz   Přiřazovací příkaz realizuje přiřazení hodnoty proměnné nebo definici výstupní hodnoty funkce v jejím těle (kapitola V). Hodnota je získána vyhodnocením výrazu. Typ výrazu musí být kompatibilní vzhledem k přiřazení s typem proměnné (funkce). Kompatibilita typů je diskutována v kapitole VI. Pokud je proměnná (funkce) ordinálního typu, může být součástí přiřazovacího příkazu test, zda přiřazovaná hodnota náleží do rozsahu hodnot proměnné (funkce). Test je do kódu příkazu začleněn v případě nastavení direktivy kompilátoru {$R+}, nesplnění uvedené podmínky pak generuje běhovou chybu a ukončení běhu programu.

Obrázek 15: Přiřazovací příkaz

Příkaz skoku   Příkazem skoku se přenese činnost programu na příkaz, označený návěštím, uvedeným za rezervovaným slovem goto (jdi na). Syntaktickým tvarem návěští je celé číslo bez znaménka (maximálně však 9999) nebo identifikátor. Musí být deklarováno ve stejném bloku, ve kterém je použito — deklarace návěští, příkaz skoku i příkaz označený návěštím musí být ve stejném bloku. Není tedy dovolen například skok ven z podprogramu nebo naopak dovnitř podprogramu. Skok dovnitř strukturovaného příkazu není sice výslovně zakázán, ale může mít nedefinované následky (nehledě k tomu, jaké újmy dozná srozumitelnost zdrojového textu).

Obrázek 16: Deklarace návěští a příkaz skoku

Příkaz skoku dovoluje v jazycích, postrádajících strukturované příkazy, jejich realizaci skokovými konstrukcemi. V Turbo Pascalu je používán pouze ve výjímečných případech, kdy se jeho použitím výrazně zjednoduší zdrojový text nebo zefektivní běh programu. Časté používání příkazu skoku neúnosně komplikuje orientaci ve zdrojovém textu.

Volání procedury   Příkazem volání procedury je aktivována procedura (podprogram). Po jejím ukončení je řízení programu vráceno zpět na místo, odkud byla volána — běh programu pokračuje příkazem, bezprostředně následujícím za voláním procedury. Syntax příkazu volání procedury a jeho podrobná diskuse je uvedena v kapitole V.

Prázdný příkaz   Prázdný příkaz je příkaz, kterému neodpovídá žádná akce. Ze syntaktického hlediska je výhodné, aby byl prázdný příkaz přípustný, především v souvislosti se strukturovanými příkazy. Prázdným příkazem může být například ošetřena nepodstatná alternativa v podmíněných příkazech nebo jím může být tvořeno tělo čekací smyčky (opakuj nic dokud…).

Obrázek 17: Prázdný příkaz

IV.2. 

Strukturované příkazy

Strukturované příkazy předpisují postupné, podmíněné nebo opakované provádění svých příkazů dílčích. Každý ze strukturovaných příkazů je jako celek ze syntaktického hlediska jediným příkazem — tam, kde je ve zdrojovém textu povolen příkaz, může být uveden buď jednoduchý nebo strukturovaný příkaz (i dílčím příkazem strukturovaného příkazu může tedy být příkaz rovněž strukturovaný).

Obrázek 18: Strukturované příkazy


Pomocí podmíněných příkazů lze větvit běh programu podle aktuálních výsledků jeho výpočtu. Podmíněným příkazem je vybrán a proveden jediný z uvedených příkazů dílčích.

Cykly jsou strukturované příkazy, které řídí opakované provádění svých příkazů dílčích — těla cyklu — testováním hodnoty podmínky cyklu. Turbo Pascal implementuje tři typy cyklů — s podmínkou na začátku (while), s podmínkou na konci (repeat) a cyklus s počtem průchodů řízeným hodnotou řídící proměnné cyklu (for).

Příkaz with realizuje hromadný přístup k položkám záznamů. Zde je uveden pouze kvůli úplnosti, podrobně popsán je v kapitole VIII.

Složený příkaz   Předepisuje postupné (sekvenční) provádění dílčích příkazů, uzavřených mezi rezervovanými slovy beginend. Dílčí příkazy jsou vzájemně odděleny středníky. Jeho použití má smysl tam, kde je třeba uvést příslušnou posloupnost příkazů, a kde je syntaxí jazyka předepsán příkaz jediný (v některých strukturovaných příkazech).

Obrázek 19: Složený příkaz

První z následujících složených příkazů obsahuje tři dílčí příkazy: přiřazovací příkaz, příkaz volání procedury Write a prázdný příkaz. Druhý složený příkaz obsahuje pouze dva dílčí příkazy:

begin A := B; Write(A); end
begin A := B; Write(A) end
Příkaz if   Příkazem if (jestliže platí) je vybrán a proveden jeden ze dvou alternativních dílčích příkazů, uvedených ve dvou větvích — větvi then (pak) a větvi else (jinak).

Obrázek 20: Příkaz if

Pokud větev else není uvedena (tzv. neúplný příkaz if), je jejím dílčím příkazem prázdný příkaz. Typem uvedeného výrazu — podmínky větvení — musí být Boolean. Po jeho vyhodnocení je vybrán a proveden příkaz větve then v případě, kdy hodnotou výrazu je True, jinak je proveden příkaz větve else. Po provedení příkazu if pokračuje výpočet programu příkazem následujícím.

V následujícím příkladu bude za platnosti podmínky A < B proveden příkaz Minimum := A jinak příkaz Minimum := B:

if A < B then Minimum := A else Minimum := B
Pokud je třeba v některé z větví provést více dílčích příkazů, je nutné použít složeného příkazu:
if A < B then begin
               Minimum := A;
               Maximum := B
              end
         else begin
               Minimum := B;
               Maximum := A
              end
Začátečníci, zvyklí zcela automaticky za každým příkazem uvádět středník, se často dopouštějí této typické chyby:
if A < B then Minimum := A;
         else Minimum := B;
Chyba spočívá v uvedení dvojice dílčích příkazů ve větvi then (druhým příkazem je prázdný příkaz) místo předepsaného příkazu jediného. Při překladu je první řádka syntakticky správným zápisem příkazu if bez větve else, druhá řádka však začíná vyhrazeným slovem else, k němuž není nalezeno příslušné if.


PŘÍKLAD: Ukázkový program řeší kvadratickou rovnici ax2 + bx + c = 0 v oboru komplexních čísel. Vstupem programu je trojice reálných čísel — koeficientů abc rovnice, výstupem zpráva o nalezených kořenech.

{======================================================================}
program KvadratickaRovnice;
{======================================================================}

 var A, B, C,                                    { koeficienty rovnice }
     D        : Real;                            { diskriminant        }

begin { program }
 Writeln;                                        { tisk titulku        }
 Writeln('řešení rovnice A.X^2 + B.X + C = 0');
 Writeln;
 Write('koeficienty A B C: ');                   { načtení koeficientů }
 Readln(A, B, C);
 Writeln;
 if A = 0 then                                   { lineární rovnice    }
  if B = 0 then
   if C = 0 then
    Writeln('kořeny jsou všechna komplexní čísla')
   else { C <> 0 }
    Writeln('kořeny neexistují')
  else { B <> 0 }
   Writeln('jednoduchý reálný kořen X = ', -C/B)
 else { A <> 0 }                                 { kvadratická rovnice }
  begin
   D := Sqr(B) - 4*A*C;                          { diskriminant        }
   A := 2*A;
   B := - B/A;
   if D = 0 then                                 { dvojnásobný kořen   }
    Writeln('dvojnásobný reálný kořen X1 = X2 = ', B)
   else if D > 0 then                            { reálné kořeny       }
    begin
     D := Sqrt(D)/A;
     Writeln('dva reálné kořeny X1 = ', B + D);
     Writeln('                  X2 = ', B - D)
    end
   else { D < 0 }                                { komplexní kořeny    }
    begin
     D := Abs(Sqrt(-D)/A);
     Writeln('dva komplexně sdružené kořeny X1 = ', B, ' + ', D, '.i');
     Writeln('                              X2 = ', B, ' - ', D, '.i')
    end
  end;
 Writeln
end. { program }

Příkaz case   Příkazem case je vybrán a proveden jeden z několika alternativních dílčích příkazů, uvedených ve větvích jednotlivých případů a větvi else. Pokud větev else není uvedena, je jejím dílčím příkazem prázdný příkaz.

Obrázek 21: Příkaz case

Mezi rezervovanými slovy case (vyber případ) a of (z následujících) je uveden ordinální výraz, tzv. selektor větvení. Za of následuje seznam větví jednotlivých případů (aspoň jeden případ), případná větev else (ostatní případy) a rezervované slovo end, které zde má význam ukončení seznamu větví příkazu case. Větve jednotlivých případů jsou vzájemně odděleny středníky. Větev posledního případu může, ale nemusí, být ukončena středníkem. Větev else (pokud je uvedena) může, ale nemusí být ukončena jedním nebo více středníky. Větev každého případu musí obsahovat seznam jedné nebo více konstant, které musí být přípustnými hodnotami typu selektoru. Konstanty mohou být uvedeny formou konstantních výrazů a jsou v seznamu vzájemně odděleny čárkami, souvislý úsek konstant lze do seznamu začlenit jako interval (..).

Po vyhodnocení selektoru se prochází postupně větvemi jednotlivých případů. Při průchodu každé větve je otestován její seznam konstant na přítomnost konstanty, rovné hodnotě selektoru. Pokud je konstanta nalezena, provede se příkaz, uvedený v této větvi a příkaz case je ukončen (průchod zbývajícími větvemi se již neprovádí, výpočet pokračuje příkazem následujícím až za seznamem větví case). Pokud hledaná konstanta není obsažena ve větvi žádného případu, je proveden příkaz větve else. Je-li třeba v některé z větví provést více dílčích příkazů, je nutné použít složeného příkazu.


PŘÍKLAD: Následující jednoduchý program DenTydne vypíše název dne v týdnu jako odezvu na jeho zadané pořadové číslo.

{======================================================================}
program DenTydne;
{======================================================================}

 var Cislo: Byte;          { vstupní údaj - pořadové číslo dne v týdnu }

begin { program }
 Writeln;                              { tisk záhlaví                  }
 Writeln('Den týdne');
 Writeln('---------');
 Writeln;
 Write('pořadové číslo dne v týdnu: ');{ načtení pořadového čísla dne  }
 Readln(Cislo);
 case Cislo of                         { tisk odpovídajícího názvu dne }
  1:   Writeln('pondělí');
  2:   Writeln('úterý');
  3:   Writeln('středa');
  4:   Writeln('čtvrtek');
  5:   Writeln('pátek');
  6:   Writeln('sobota');
  7:   Writeln('neděle')
  else Writeln('chybné číslo dne')
 end;
 Writeln
end. { program }

Příkaz while   V cyklu while je opakovaně prováděn jediný dílčí příkaz — tělo cyklu — po dobu platnosti podmínky cyklu. Pokud má být tělo cyklu tvořeno více než jedním dílčím příkazem, je nutné použít složeného příkazu. Podmínkou je výraz typu Boolean, uvedený mezi vyhrazenými slovy while (dokud platí) a do (dělej).

Obrázek 22: Příkaz while

Při vstupu do cyklu je nejdříve vyhodnocena podmínka. Pokud je její hodnotou False, dílčí příkaz není proveden a cyklus je ukončen — výpočet pokračuje příkazem následujícím. Pokud je aktuální hodnota podmínky True provede se dílčí příkaz a návrat na začátek cyklu. Počet průchodů tělem cyklu je nulový v případě, kdy podmínka má hodnotu False již před prvním průchodem cyklu.


PŘÍKLAD: Program NSD vypočte největšího společného dělitele (xy) zadaných celých čísel xy. Algoritmus výpočtu využívá těchto vlastností největšího společného dělitele:

{======================================================================}
program NSD;
{======================================================================}

 var X, Y,                                          { zadaná čísla     }
     A, B : LongInt;                                { pomocné proměnné }

begin { program }
 Writeln;                                { výpis titulku               }
 Writeln('Výpočet největšího společného dělitele čísel X a Y');
 Writeln('--------------------------------------------------');
 Writeln;
 Write('čísla X Y: ');                   { vstup dvojice celých čísel  }
 Readln(X, Y);
 Writeln;
 A := Abs(X); B := Abs(Y);               { inicializace proměnných A,B }
 if (A = 0) and (B = 0) then             { triviální případy           }
  Writeln('(0, 0) není definován')
 else if (A = 0) or (B = 0) then
  Writeln('(', X, ', ', Y, ') = ', A + B)
 else { (A > 0) and (B > 0) }            { netriviální případy         }
  begin
   while A <> B do
    if A < B then B := B - A
             else A := A - B;
   Writeln('(', X, ', ', Y, ') = ', A)
  end;
 Writeln
end. { program }

Příkaz repeat   Tělo cyklu repeat je tvořeno sekvencí dílčích příkazů, uzavřenou mezi vyhrazená slova repeat (opakuj) a until (dokud není). Příkazy jsou v sekvenci vzájemně odděleny středníky. Podmínkou je výraz typu Boolean, uvedený za vyhrazeným slovem until.

Obrázek 23: Příkaz repeat

Při vstupu do cyklu je nejdříve provedena sekvence příkazů, tvořící jeho tělo, teprve poté je vyhodnocena podmínka. Pokud je její hodnotou True, cyklus je ukončen a výpočet pokračuje následujícím příkazem, v opačném případě následuje návrat na začátek cyklu. Na rozdíl od cyklu while je tedy průchod tělem cyklu repeat uskutečněn vždy aspoň jednou.


PŘÍKLAD: Cyklus repeat je použit v programu CastecnySoucet, který pro daná reálná čísla xepsilon vypočte součtet prvních n + 1 členů řady 1 + x + x2/2! + x3/3! +…, kde n je nejmenší přirozené číslo, splňující požadavek |xn/n!| < epsilon. Aby nebylo nutné pro každý člen řady počítat vždy znovu mocninu a faktoriál, je využito rekurzivního vztahu mezi sousedními členy řady ai = x/i . ai–1.

{======================================================================}
program CastecnySoucet;
{======================================================================}

 var X, Eps,                           { vstupní data                  }
     Clen,                             { hodnota aktuálního členu řady }
     Soucet : Real;                    { aktuální hodnota součtu       }
     I      : Word;                    { index aktuálního členu řady   }

begin { program }
 Writeln;                                   { výpis titulku            }
 Writeln('Částečný součet řady');
 Writeln('--------------------');
 Writeln;
 Write('X         : '); Readln(K);          { načtení vstupních údajů  }
 repeat
  Write('Eps (> 0): '); Readln(Eps)
 until Eps > 0;
 Writeln;
 Soucet := 1; Clen := 1; I := 0;            { inicializace             }
 repeat                                     { opakuj                   }
  Inc(I);                                   { aktualizace indexu členu }
  Clen := Clen * X/I;                       { hodnota aktuálního členu }
  Soucet := Soucet + Clen                   { aktualizace součtu       }
 until Abs(Clen) < Chyba;                   { dokud není…              }
 Writeln('součet        :', Soucet);        { výpis výsledků           }
 Writeln('poslední index: ', I);
 Writeln('poslední člen :', Clen);
 Writeln
end. { program }

Příkaz for   Zápis cyklu for ve zdrojovém textu sestává ze záhlaví cyklutěla cyklu. V záhlaví je uvedena řídící proměnná cyklu, její počáteční hodnota, způsob aktualizace hodnoty a mez — podle způsobu aktualizace maximální resp. minimální hodnota. Tělo cyklu je tvořeno jediným dílčím příkazem (lze však uvést příkaz složený) a od záhlaví odděleno vyhrazeným slovem do.

Obrázek 24: Příkaz for

Identifikátorem je určena řídící proměnná cyklu, jejíž typ musí být ordinální. Oba výrazy musí být typu kompatibilního vůči přiřazení s typem řídící proměnné. Hodnota prvního výrazu je použita jako počáteční hodnota k inicializaci řídící proměnné pro první průchod tělem cyklu. Před každým dalším průchodem je hodnota řídící proměnné aktualizována hodnotou svého následníka (to) resp. předchůdce (downto) v daném typu. Průchod tělem cyklu (včetně prvního) je uskutečněn pouze tehdy, je-li aktuální hodnota řídící proměnné menší nebo rovna (to) resp. větší nebo rovna (downto) hodnotě meze, získané výpočtem druhého výrazu. Počáteční hodnota i mez jsou vyhodnoceny pouze na začátku cyklu — před prvním průchodem jeho tělem, uvnitř cyklu je nijak nelze změnit.

Počet průchodů cyklem for je pevně dán počáteční hodnotou řídící proměnné a hodnotou meze (pokud ovšem nebude v těle cyklu manipulována hodnota řídící proměnné). Vzhledem k tomu, že for je v podstatě cyklem s podmínkou na začátku, může být počet průchodů jeho tělem i nulový (počáteční hodnota větší resp. menší než mez pro to resp. downto).


PŘÍKLAD: Jako příklad aplikace cyklu for je uveden program Tabulka, který vytiskne tabulku hodnot funkcí sinus a kosinus.

{======================================================================}
program Tabulka;
{======================================================================}

 const Prevod  = Pi/180;        { činitel převodu ze stupňů na radiány }
 var   Pocet,                   { počet tabelovaných hodnot            }
       PocUhel,                 { počáteční úhel                       }
       Krok    : Integer;       { distance tabelovaných hodnot         }
       Deg     : Integer;       { aktuální úhel ve stupních            }
       Rad     : Real;          { a radiánech                          }
       I       : Integer;       { řídící proměnná cyklu                }

begin { program }
 Writeln;                                      { tisk titulku          }
 Writeln('Tabulka hodnot funkcí SIN a COS');
 Writeln('-------------------------------');
 Writeln;
 Write('počet tabelovaných hodnot : ');        { načtení vst. údajů    }
 Readln(Pocet);
 Write('počáteční úhel [deg]      : ');
 Readln(PocUhel);
 Write('krok [deg]                : ');
 Readln(Krok);
 Writeln;
 Writeln('------------------------------------'); { záhlaví tabulky    }
 Writeln('         úhel           sin      cos');
 Writeln('    [deg]    [rad]');
 Writeln('------------------------------------');
 Deg := PocUhel - Krok;                        { inicializace před     }
                                               { prvním průchodem      }
 for I := 1 to Pocet do                        { poč. průchodů = Pocet }
  begin
   Inc(Deg, Krok);                             { další úhel            }
   Rad := Deg*Prevod;                          { převod na radiány     }
   Writeln(Deg:9, Rad:9:2,                     { výpis tabelovaných    }
           Sin(Rad):9:2, Cos(Rad):9:2)         { údajů                 }
  end;
 Writeln('------------------------------------'); { konec tabulky      }
 Writeln
end. { program }