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Ě.