Programové struktury FoxPro

 

 

Charakteristika

Ve FoxPro nelze jinak programovat než strukturovaně. Tím je zajištěna přehlednost a čitelnost programů. Aniž by si to programátor uvědomoval, strukturalizací programu je optimalizována též jeho segmentace, což má vliv na rychlost výpočtu.

Ve své podstatě je programování FoxPro nadstavbou nad programováním v jazyku C. Není divu, že filozofie jazyka C se silně projevuje v syntaxi jazyka FoxPro. Struktura definice funkce je formálně shodná s definicí procedury i programu, výraz může být použit ve funkci příkazu, atd.

Na rozdíl od jazyka C není předepsán ukončovací znak příkazu. Zřejmě proto, že by jeho opomenutí mohlo vést ke zbytečným logickým chybám. Tím odpadla struktura "složený příkaz", ale bylo zavedeno označení konce struktury.

Příkazy se zapisují v pořadí jejich provádění. Na každém řádku může být zapsán pouze jeden příkaz. Znakem pokračováni příkazu na dalším řádku je středník.

Výraz ve funkci příkazu

 

= <výraz1> [,<výraz2>...]

 

Příkaz vyhodnotí seznam výrazů bez použití hodnoty. Některé operace nelze zajistit jinak než výrazy.

 

= CAPSLOCK(.F.)

= FCLOSE(c_souboru)

 

 

Podmíněný příkaz

IF <výrazL> ... [ELSE] ... ENDIF

 

Příkaz umožňuje podmíněné provádění povelů v programu. Každý IF musí končit ENDIF. Pokud je podmínka splněna (.T.), provedou se příkazy po ELSE nebo ENDIF, pokud nebyla splněna (.F.), provedou se příkazy mezi ELSE a ENDIF (jsou-li zapsány), jinak se pokračuje za ENDIF.

 

výpočet M=max(A,B)

IF A > B

M=A

ELSE

M=B

ENDIF

 

 

Přepínač

 

DO CASE ... CASE <výrazL> ... [OTHERWISE] ... ENDCASE

 

Příkaz zajistí zpracování programové sekvence v závislosti na první splněné podmínce. Při nesplnění žádné podmínky se provedou příkazy za OTHERWISE.

 

výpočet S=sign(c)

DO CASE

CASE c>0

S=1

CASE c<0

S=-1

OTHERWISE

S=0

ENDCASE

 

 

Cykly

Opakované provádění části se programuje dvěma typy cyklů. Počítaným a obecným. Pro oba typy cyklů existují příkazy pro předčasné ukončení cyklu (EXIT) a pro přerušení cyklu (LOOP).

a) Počítaný cyklus

 

FOR <proměnná>=<výrazN1> TO <výrazN2> [STEP <výrazN3>]...

<příkazy>...[EXIT]...[LOOP]...ENDFOR

 

Příkaz zpracování v cyklu se zvyšováním hodnoty řídící proměnné. Kde:

<výrazN1> je počáteční hodnota řídící proměnné cyklu.

<výrazN2> je konečná hodnota řídící proměnné cyklu, může být menší než počáteční.

<výrazN3> je hodnota pro přičtení po každém opakování (Je povolena záp. hodnota).

EXIT je příkaz, který přenese řízení z cyklu FOR na první příkaz za koncem cyklu - ENDFOR. Tím předčasně ukončí provádění cyklu. Příkaz je obvykle součástí struktury větvení nebo přepínání.

LOOP je příkaz, který přenese řízení v cyklu FOR zpět na počáteční příkaz FOR.

Tím předčasně ukončí jeden z průběhů cyklu. Příkaz je obvykle součástí struktury větvení nebo přepínání.

 

 Jeho analogie (SCAN), používaná při práci se souborem bude probírána v odpovídající kapitole.

 

b) Obecný cyklus

 

DO WHILE <výrazL>...<příkazy>...[LOOP]...[EXIT]...ENDDO

 

Příkaz cyklu, ve kterém se provádí skupina příkazů dokud je splněna podmínka <výrazL>. Podmínka je vyhodnocována při každém průběhu cyklem.

EXIT je příkaz, který přenese řízení z cyklu DO WHILE na první příkaz za koncem cyklu - ENDDO. Tím předčasně ukončí provádění cyklu. Příkaz je obvykle součástí struktury větvení nebo přepínání.

LOOP je příkaz, který přenese řízení v cyklu DO WHILE zpět na počáteční příkaz DO WHILE. Tím předčasně ukončí jeden z průběhů cyklu. Příkaz je obvykle součástí struktury větvení nebo přepínání.

 

**************** Cyklus počítá hodnotu y=n!, pak je zobrazen výsledek

n=15

...

y=1

FOR i=1 TO n

y=y*i

ENDFOR

? y

1307674368000

 

**************** Cyklus tabeluje hodnotu úhlů v rozsahu 0 až 90 a sinus úhlu,

**************** s přesností na 6 desetinných míst.

SET DECIMAL TO 6

i=0

DO WHILE I<=90

?i,SIN(DTOR(I))

i=i+1

ENDDO

 

Funkce, procedura, program

Funkce (Functions), procedury (Procedures) a programy (Programms) jsou programové jednotky, které mají jednotnou strukturu a jednotný způsob volání. Jednotka, která je volána (aktivována) nějakou jinou jednotkou je vtom okamžiku jejím podprogramem. Jednotka může volat sama sebe. Pak mluvíme o rekurzivitě jednotky.

Jednotnost formy definování a volání není kvůli snadnému zvládnutí programování. Je podmíněna nezbytností postupného budování rozsáhlých informačních systémů, kdy program se může stát podprogramem jiné jednotky, proceduru bude vhodné použít jako funkci, funkci bude nutno odladit a tudíž s ní bude zacházeno jako s programem, atd.

 

 

Definování funkce

Popis definování zahájíme nejsložitější definicí. Všechny další definice budou založeny na metodě postupného zjednodušování. Definice funkce je program napsaný uživatelem v jazyce FoxPro, uvedený počáteční formulí:

 

PROCEDURE <název funkce>

nebo

FUNCTION <název funkce>

 

Pokud je nutná definice formálních parametrů, pak ihned za počáteční formuli nutno zapsat příkaz:

 

PARAMETERS <seznam formálních parametrů>

 

Formální parametry jsou místa v paměti, rezervována pro předání vstupních hodnot funkci (při jejím volání). Mají vlastnosti paměťových proměnných. Slouží k definování algoritmu funkce a jsou vždy soukromé (private). Počet formálních parametrů je prakticky neomezen.           Logické ukončení algoritmu se zapisuje příkazem a ukončený příkazem:

 

RETURN <výraz - vrácená hodnota>

 

Příkaz zajistí předání výstupní hodnoty a návrat z definice. V jedné funkci může být více příkazů return. To znamená, že funkce může předat výstupní hodnoty různých typů. 

 

**************** funkce sečte nanejvýše tři zadané hodnoty

FUNCTION Soucet3

PARAMETERS n1,n2,n3

RETURN n1 + n2 + n3

 

 

Volání funkce

Funkce se volá z hlavního programu nebo procedury obdobně jako standartní funkce FoxPro systému svým názvem a dvojicí závorek, uvnitř nichž mohou být případně uvedeny vstupní parametry. Jména uživatelem definovaných funkcí se nesmí shodovat s žádným rezervovaným jménem standartní funkce FoxPro.

Vstupním parametrům se říká též argumenty funkce nebo skutečné parametry. Skutečných parametrů může být méně než formálních (neuvedené se doplní prázdnou hodnotou). Nesmí jich být více. Existují dva způsoby předání skutečných parametrů: předání hodnotou a předání odkazem.

Předání hodnotou (value) je nejčastěji používaným způsobem (standard) předání vstupní hodnoty. Předává se hodnota výrazu, který je uveden v seznamu skutečných parametrů. I když je výraz tvořen pouze proměnnou, její hodnota se v žádném případě nezmění.

Předání odkazem (reference), někdy se říká předání jménem nebo (v terminologii jazyka C) ukazatelem, se od předání hodnotou odlišuje tím, že v průběhu funkce lze změnit hodnotu skutečného parametru. Musí být splněny tři podmínky:

a) skutečným parametrem je paměťová proměnná (ne výraz),

b) odpovídajícímu formálnímu parametru je přiřazena jiná hodnota,

c) je nastaven režim pro předání odkazem.

Režim se nastavuje (logicky před voláním) příkazem:

 

SET UDFPARMS TO VALUE │ REFERENCE

 

VALUE předání hodnoty, změna hodnoty se nepřenese. REFERENCE předání jménem, změna hodnoty se přenese. Mnemotechnika: (UDF=User-Defined Function, PARaMeterS)           Zřejmě ze setrvačnosti lze předat funkci jméno pole (tabulky, matice) jako skutečný parametr pouze ve tvaru řetězcového výrazu ( v uvozovkách). Odpovídající formální parametr musí mít před jménem znak & (o tomto znaku bude ještě podáno vysvětlení v kapitole nazvané "Makrosubstituce"). V tomto případě nemusí být zadán příkaz SET UFDPARMS TO REFERENCE a funkce se bude chovat tak, jako by byl nastaven režim předávání odkazem. (Platí i pro práci s proměnnými a položkami!)

Poznámka: Bylo již řečeno, že skutečných parametrů může být méně než formálních. Pak ale za zvláštních okolností může dojít k chybě. Proto se programuje kontrola počtu skutečných parametrů pomocí funkce:

 

PARAMETERS()

 

Funkce vrátí počet parametrů, které vstoupily do procedury. Funkci lze s výhodou využít v procedurách, kde může být proměnlivý počet vstupních parametrů.

 

? vypocet(12,"text",datum)       &&   Funkce volaná z výrazu.

revers()                                   &&   Funkce volaná jako  příkaz, bez skutečných parametrů

Do vypocet with 12, "text", datum                   &&   Funkce volaná jako procedura.

 

 

Definování procedury a programu

Definování procedury (nebo programu) je stejné jako definování funkce. Nedoporučuje se používat formule FUNCTION (kvůli čitelnosti). Úvodní formule vůbec nemusí být v případě, že procedura je uvedena samostatně (v odděleném souboru) a volá se jménem souboru (má tvar programu). Příkaz RETURN nemusí mít uveden výraz. Procedura (nebo program) nemusí mít vůbec příkaz return, když její logický konec je současně koncem fyzickým. Program může obsahovat příkaz PARAMETERS s formálními parametry, které lze zadat při aktivaci programu.

U procedur sloužících k testování chybových stavů a vybízejících obsluhu k jejich odstranění (velice často k testování připravenosti tiskárny) se používá příkazu:

 

RETRY

 

Příkaz vrátí řízení do volajícího programu a zopakuje provedení posledního příkazu. Je adekvátní příkazu RETURN s tím rozdílem, že po RETURN je prováděn následující příkaz programu. Procedura má tedy dva výstupy, podmíněné indikací chyby.

 

 

Volání procedury a programu

Volání procedury (nebo programu) se provádí příkazem:

 

DO <jméno procedury nebo jméno souboru>

[WITH <seznam_parametrů>]

 

Příkaz zajistí zpracování příkazového souboru nebo procedury s možností předaní parametrů. Maximální počet vnoření DO je závislý na operačním systému (24-30).

 

DO inverze      && volání procedury nebo programu bez skutečných parametrů

 

DO zobraz with objekt, radek, sloupec

&& volání procedury nebo programu se skutečnými parametry

 

 

Knihovna podprogramů a funkcí

Procedury a funkce nohou být umístěny ve stejném souboru jako program, nebo ve zvláštním souboru - knihovně. Propojení programu s knihovnou se provede příkazem:

 

SET PROCEDURE TO [<soubor>]

 

Příkaz otevře určený soubor procedur. V jednom časovém okamžiku může být otevřen pouze jeden soubor procedur.

 

SET PROCEDURE TO kpr1

DO vstup with par1,par2                   && Volání procedury vstup umístěné na knihovně kpr1

 

 

Cvičení

Výpočet dne v týdnu

Příklad se skládá z části ověření funkce a z definice funkce. Před ověřováním na počítači vymažte řádky zobrazující výsledky.

 

? datum("Dnes je",date())                 && Volání funkce s dnešním datem.

Dnes je středa, 25.09.91                    && Zobrazení výsledků.

? datum("Zítra je",date()+1)                        && Volání funkce se zítřejším datem.

Zítra je čtvrtek, 26.09.91                  && Zobrazení výsledků.

RETURN                                            && Konec zkušebního programu

 

FUNCTION datum                            && Definování funkce.

parameters text,datum                                  && Deklarace formálních parametrů.

set date to german                             && Nastavení obvyklého způsobu zobrazování data.

dny='neděle ,pondělí ,úterý ,středa ,'+;        && Řetězec dnů v týdnu. Všimnete si středníku.

'čtvrtek  ,pátek   ,sobota  '     && Pokračování řetězce.

den=dow(datum)                               && Pořadové číslo dne v týdnu.

pozice=(den-1)*9+1                          && Výpočet pozice dne v řetězci.

extrakce=substr(dny,pozice,8)                                  && Vyjmutí dne z řetězce.

return text+' '+trim(extrakce)+', '+dtoc(datum)     && Konečná úprava výstupního textu

 

Příklad klasického volání a definování procedury

 

DO Soucet WITH 3,4,12                    && Volání procedury pro sečtení a zobrazení tří čísel

RETURN

PROCEDURE Soucet

PARAMETERS s1,s2,s3

? "Výsledná hodnota součtu : " + STR(s1 + s2 + s3)

RETURN

 

Příklad předávání jména matice jako parametru

 

publ aaa[10,10]         && Deklar. rozměru matice aaa, zkracování a malá písmena povolena

aaa=0                         && Definování nulové matice

do E_mat with 'aaa',10          && Volání zápisu jednotek na diagonálu

do Z_mat with 'aaa',10          && Volání procedury zobrazující matice

&& Nedefinovaný fyzický a logický konec programu

PROCEDURE e_mat             && Procedura dosazení jednotek do diagonály

PARAMETERS x,r                 && Formální parametry

FOR i=1 to r                          && Cyklus zápisu jedničky na diagonálu matice

&x[i,i]=1                   && Všimnete si zápisu formálního parametru

ENDFOR                                && Konec cyklu a současně konec procedury

&& Návrat z procedury nemusí být definován

PROCEDURE z_mat             && Procedura zobrazení matice

PARAMETERS x,r                 && Formální parametry

?                                             && Nový řádek

FOR i=1 to r                          && Cyklus řádků

FOR j=1 to r              && Cyklus sloupců

?? &x[i,j]      && Dvojitý otazník je příkaz zobrazení na stejném řádku

ENDFOR                    && Konec cyklu sloupců

?                                 && Nový řádek

ENDFOR                                && Konec cyklu řádků

&& ZDE NEJSOU UVÁDĚNY KONCE PROCEDUR PŘÍKAZEM RETURN POUZE

&& Z DŮVODŮ DEMONSTRAČNÍCH. DOPORUČUJI RETURN ZAPISOVAT!!!

 

Příklad  univerzálnosti definice  a volání

Jde o skutečně fungující program, který je tvořen jediným výrazem ve funkci příkazu. Volá proceduru aaa formou pro volání funkce. Procedura zobrazí skutečný parametr "FUNGUJI!". Kompilátor pozná, že fyzicky skončila programová jednotka, jelikož začíná jiná. Tento konec musí pokládat současně za logický. Jelikož nebyl programován příkaz RETURN, zařadí za něj výskok z programu (procedury). Zkracování a malá písmena jsou povolena.

 

= aaa ( "FUNGUJI!")

proce aaa

para text

?text

return

Příklad rekursivní procedury

Procedura aaa volá sama sebe, (vnořuje se do sebe 29 krát). Procedura zobrazí postup vnořování 1,2,3,... a postup vynořování 29,28,..

 

DO aaa WITH 1                     && Volání procedury s počáteční hodnotou.

RETURN                                && Konec programu.

 

PROCEDURE aaa                 && Definice procedury aaa.

PARAMETERS vnoreni         && Deklarace formálního parametru.

IF vnoreni>29                                   && Test hloubky vnoření (nesting).

?vnoreni                     && Zobrazení postupu vynořování.

RETURN                    && Návrat z procedury po dosažení stanovené hloubky.

 

else                              && Následující příkaz zase volá proceduru jako funkci.

DO aaa WITH vnoreni+1      && Rekursivní volání.

&& Zde formální parametr vystupuje jako skutečný.

?vnoreni                                 && Zobrazení postupu vnořování.

RETURN                                && Návrat při nedosažené hloubce.

ENDIF                                               && REKURZIVNÍ FUNKCE SE PROGRAMUJÍ STEJNĚ.