Programfejlesztés a dBase rendszerben

 

Áttekintés a dBase programok fejlesztésérõl

 

Az elõzõ fejezetben megismerhettük az xBase modellen alapuló adatkezelési technikát, amelynek egyik fõ jellegzetessége az volt, hogy az adatokat rekordonként kezeli. Az eddigiekben ismertetett utasítások egy vagy több rekordot érintõ adatkezelési fukciót láttak el. Egy összetettebb tevékenységhez az adatkezelõ utasítások sorozatát kell kiadni. Az említett interaktív kezelõ felület azonban nem alkalmas ilyen célokra, több okból sem:

 

- az interaktív felület igényli az utasítások pontos ismeretét

- túl nagy szabadságot ad a felhasználónak

- az utasítások begépelése igen idõigényes tevékenység

- ismétlõdõ tevékenységek unalmassá teszik a munkát

- az eredmények megjelenítése igen egyhangú, kevésbé tagolható

- az interaktív felület nagymértékben zárt utasításkörrel rendelkezik

- nem lehet az egyszer elvégzett tevékenységeket megismételni

 

E kifogás lista láttán, melyet természetsen tovább is lehetne folytatni, bizonyára mindenki számára érhetõ, hogy miért nem valósítható meg az, hogy egy interaktív dBase felület legyen a felhasználók elõtt, pl. a bankban, a pénztárakban vagy a postahivatalokban. Az ott ülõ alkalmazottak a rendszert segédeszközként alkalmazzák, melyet egyszerûen és célirányosan lehet használni. Az interaktív felület ezzel szemben sokkal több számítástechnikai ismeretet követelne tõlük, kevésbé tudnánk az igazi munkájukkal törõdni, s igen lassú lenne a feldolgozás menete is.

 

Az elõbb elmondottak persze nem azt jelenti, hogy el kell temetni az interaktív felületet. Az interaktív felületnek meg van a célja és haszna, csak nem éppen a felhasználók körében. Az interaktív felület egyfajta rendszer karbantartási eszköz szerepét tölti be. Számítástechnikai szakemberek, az adatrendszer gazdái, kezelõi fogják használni az apróbb-nagyobb karbantartási tevékenységek elvégzésénél. Ezek a tevékenységek rendszerint néháy utasítással megoldhatók, s nincs szükség igazán kifinomult képernyõ formátumra sem.

 

Az adatbázisok felhasználás estén tehát a felhasználók nem az interaktív kezelõ felülettel, hanem egy alkalmazással találkoznak. Az adatbázisra ülõ alkalmazás biztosítja a megfelelõ képernyõ formátumot, s az alakalmazás hajtja végre a szükséges adatkezelõ utasításokat is. Természetesen sokkal gyorsabban és biztosabban mintha kézzel kellene ezen utasításokat felvinni. Az alkalmazások emellett gondoskodnak a tevékenységek megfelelõ algoritmusban történõ lefutásáról is. Az alkalmazások tehát olyan programoknak tekinthetõk, melyek biztosítják a megfelelõ, szabályzott adatforgalmat a felhasználó és az adatbázis között.

 

Az alkalmazások fejlesztéséhez olyan programozási nyelv szükséges, amely lehetõvé teszi az adatokhoz való hozzáférés mellett az algoritmikus és képernyõkezelési elemek megvalósítását is. Az elmút évtizedekben nagyon sok különbözõ ilyen programfejlesztési technika és módszer terjedt el. Mi most a dBase által nyújtott lehetõségeket fogjuk bemutatni. A dBase üttörõ szerepének köszönhetõen, egy olyan programfejlesztési eszközt ismerhetünk meg, amely az xBase rendszerek családjában általánoan ismert és elfogadott. A többi xBase variáns programfejlesztõ nyelvei is mind a dBase nyelvre épülnek.

 

A dBase-ben a programfejlesztési eszközöket úgy biztosítják, hogy a megismert adatkezelõ utasítások mellett egyéb, programfejlesztéshez szükséges utasításokat is értelmezni tud a rendszer. Így a dBase kereten belül van lehetõség az alkalmazás elkészítésére, s a kapott program magába integrálja az adatkezelõ funkciókat, eljárásokat is. A dBase induláskor interpreteres formában jelent meg, így az alkalamzás futtásához egy interprettere, a dBase rendszerre is szükség van. A fejlesztés során a szöveges program állományt állíjuk elõ, amlyet a futtatás során az interpreter soronként beolvas, értelmez és végrehajt. A dBase által értelemezett utasítások között tehát ott szerepelnek az adatkezelõ utasítások mellett az algoritmikus és felhasználó interface-t leíró utasítások is.

 

Mint majd késõbb látni fogjuk ez a megoldás, vagyis az adatkezelõ és a programozási nyelvi elemek ilyen szoros kapcsolata, nem azonos a nagyobb relációs adatbáziskezelõknél alkalmazott megolsásokkal. Ott, a szabványként elfogadott SQL nyelv csak az adatkezelési elemekre szorítkozik, s az alkalamzás egyéb utasítási komponenseinek megválasztásánál nagyobb szabadságot engedélyez. A szoros kapcsolat elõnye, hogy a felhasználónak elegendõ csak egy terméket, a dBse-t beszereznie, hogy alkalmazásokat készítsen. A hátrány viszont az, hogy így sokkal merevebb lesz a fejlesztés technikája, nem lehet kihasználni más programfejlesztési eszközök által nyújtott szolgáltatásokat.

 

A dBase nyelv az adatkezelô utasítások mellett az alábbi két utasítás csoportot tartalmazza:

 

- képernyôkezelô (adatbevitel, kiírás)

- folyamatvezérlô (ciklus, elágazás)

 

utasításcsoportok. Látható, hogy ezekkel a komponensekkel kiegészítve az adatok kezelésére szolgáló utasításokat, az alkalmazói program megírását is lehetôvé válik. A dBase ezzel szemben minden olyan programozási elemet integráltan tartalmaz, amellyel egy komplett adatbázis-kezelô alkalmazás elkészíthetô. Az adatbázis-kezelés és az alkalmazásfejlesztés összekapcsolásának ezen szintje számos elônyös vonást hordoz magában. Többek között e megoldással sikerül biztosítani, hogy

 

- a procedurális utasítások jobban illeszkedjenek az adatbázis-kezelési feladatokhoz

- a procedurális utasítások jobban illeszkedjenek a felhasználói igényekhez

- a feladatspecifikusabb utasítások révén gyorsabbá, hatékonyabbá tehetô a fejlesztési menete, hiszen kevesebb és szemléletesebb utasítással lehet dolgozni

 

A megmutatkozó elônyökbôl fakadóan, ez a fajta szoros kapcsolódás más rendszerekbe is átkerült, s mintegy önálló életre kellve, kifejlôdött a késôbbiekben a programozási nyelvek egy új csoportja, melyet röviden 4GL rendszereknek neveznek. E csoportbeli rendszerek közös vonása, hogy a relációs adatbázisokat felhasználó alkalmazói programok gyors, hatékony kifejlesztését támogatják. Természetesen a mai 4GL rendszerek nagyon-nagyon távol állnak már a régi dBase III megoldásoktól, de elviekben és céljaikban közös alapokon nyugszanak, még ha eszközeikben más-más megoldásokat választottak, a korszak lehetôségeitôl függôen.

Mivel a mai adatbázis-alkalmazások döntôen már a 4GL rendszerek futnak, a késôbbiekben részletesebben visszatérünk alkalmazásukra, mûködésükre.

 

A futtatandó program állományt egy külsõ dBase független szövegszerkesztõvel is létre lehet hozni, de a dBase is tartalmaz egy beépített egyszerûbb szövegszerkesztõt. A program utasításait tartalmazó állománynak az alapértelmezési kiterjesztése, amit célszerû nekünk is alkalmazni a PRG kiterjesztés. A beépített szövegszerkesztõt a

 

MODIFY COMMAND állomány

 

utasítással lehet meghívni az interaktív felületrõl. A paraméterként megadott állomány a szerkesztendõ programállomány azonosító neve. Így például a

 

MODIFY COMMAND ELSO

 

utasítással egy ELSO.PRG programállomány nyílik meg szerkesztésre.

 

Az elkészített programállományt a

 

DO állomány

 

utasítással lehet lefuttatni, ahol az állomány alapértelmezési kiterjesztése szintén PRG. Az elõbbi példában megadott program tehát a

 

DO ELSO

 

paranccsal futtatható le.

 

A program a már ismertetett adatkezelõ utasítások mellett procedurális és képernyõkezelést szolgáló utasításokat is tartalmazhat, melyeket a következõ alfejezetekben vesszük sorra, példákkal is szemléltetve az utasítások használatát.

 

A dBase program felépítése

 

Az dBase lehetôséget ad a program tagolására, modularizálására is. A program felbontható eljárásokra, s egy eljárásból több másik eljárás is meghívható. Egy dBase program több, egymástól függetlenül megadható eljárások összességének tekinthetõ. A függetlenség itt arra utal, hogy az eljárások nem ágyazódnak egymásba, azaz az eljárásokat egymás után, esetleg több forrásállományba is szétszórtan definiáljuk. Az eljárást egy eljárás azonosító fejléccel kell kezdeni, amelyet a

 

PROCEDURE eljárásnév

 

utasítással lehet megadni. Az innen kezdôdô és a forrásállomány végéig vagy a következô PROCEDURE utasításig tartó utasítás rész fog tartozni ezen eljáráshoz. Az eljárásból a vezérlés vagy az eljárás utólsó utasításának befejezése után vagy a

 

RETURN

 

utasítás végrehajtásánál tér vissza a hívó programegységhez.

 

A programállomány elején található utasításokat nem kötelezõ egy PROCEDURE fejléccel bevezetni, mivel azokat a rendszer egy implicit eljárásként értelmezi, olyan eljárásként, melynek azonosító neve megegyezik az állomány nevével. A program futtatásakor a vezérlés erre a modulra kerül elsõként, így ez az implicit eljárás tekinthetõ a program fõ eljárásának. Egy dBase program tehát a következõ általános struktúrát mutatja:

 

fõ eljárásás utasításai

PROCEDURE el1

el1 eljárás utasításai

PROCEDURE el2

el2 eljárás utasításai

...

 

Az eljárások meghívása a

 

DO eljárásnév

 

utasítással történik. Ugyanez a parancs szolgál arra is, ha egy önálló dBase programot kívánunk elindítani, azaz a

 

DO ALMA

 

hatására a dBase rendszer egy ALMA.PRG állományt keres (ugyanis PRG a programállományok default kiterjesztése) végrehajtásra. Ha megtatálta, akkor elkezdõdik a fõ eljárásban megadott utasítások végrehajtása.

 

A dBase eljárásoknak, hasonlóan a többi programozási nyelv eljárásaihoz, tartozhatnak paraméterek is. Ha az eljárásnak paraméterei is vannak, akkor az aktuális paramétereket a

 

DO eljárásnév WITH paraméterlista

 

alakban adhatjuk át cím vagy érték szerint. A paraméterlistában vesszôvel kell az egyes elemeket elválasztani egymástól.

A eljárás definíciójakor természtesen közölni kell az értelmezõvel, hogy készüljön fel a paraméterek fogadására. Az eljárás formális paramétereinek megadása a PARAMETERS utasítással történik, amelyet közvetlenül a PROCEDURE fejléc után kell kiadni:

 

PROCEDURE eljárásnév

PARAMETERS memóriváltozólista

 

A PARAMETERS után megadott lista memóriaváltozókat tartalmaz. A memóriaváltozók a program normál változóinak felelnek meg, melyek használatát a következõ részben fogjuk ismertetni. A listában szereplô memóriaváltozók szolgálnak az eljárás formális paramétereiként. A listában az egyes memóriaváltozó azonosítókat vesszõvel elválasztva adjuk meg. Az eljárás meghívásakor az aktuális paraméterként átadott értékek a lista alapján meghatározott sorrendben bekerülnek a PARAMETERS kulcsszót követô memóriaváltozókba. Az aktuális és a formális paraméterlistának azonos darabszámú elemet kell tartalmaznia.

 

Az elmondottak illusztrálására egy kis példát veszünk, melyben a meghívott

eljárás megnöveli eggyel a paraméter értékét.

 

x = 1

DO novel WITH x

...

 

PROCEDURE novel

PARAMETERS y

y = y + 1

RETURN

 

Ha az aktuális paraméter memóriaváltozó a dBase eljárásoknál, akkor értéke cím szerint adódik át, ha viszont egy kifejezés, akkor érték szerint paraméterátadás van. A cím szerinti átadásnál, mint ismert az aktuális és formális paraméterek ugyanazon memóriahelyet foglalják el, így a formális paraméter megváltoztatása megváltoztatja az aktuális paramétert is. Ha egy memóriaváltozó értékét mégis értékként szeretnénk átadni, akkor kifejezéssé kell átalakítani, amit legegyszerûbben egy + jel eléje írásával tehetünk meg.

 

Így például az

 

x = 1

DO novel WITH x

? x

...

PROCEDURE novel

PARAMETERS y

y = y + 1

? y

RETURN

 

programrészletben a képernyõre a

 

2

2

 

értékek fognak kiíródni,mivel cím szerinti értékadást valósítottunk meg. Ha viszont a programban módosítjuk az aktuális paraméter átadását az alábbi módon:

 

x = 1

DO novel WITH +x

...

 

PROCEDURE novel

PARAMETERS y

y = y + 1

RETURN

 

akkor érték szerinti paraméterátadást írunk elõ, így ennek megfelelõen az x memóriaváltozó értéke nem fog megváltozni az alprogramban történõ értékadások hatására. Az képernyõn megjelenõ értékek:

 

2

1

 

A dBase-ben nem lehet saját függvényeket definiálni. Gyári függvények ugyan léteznek, de mi magunknak csak eljárásokat készíthetünk. Ez egy kicsit körülményessé teheti kifejezéseinket, hiszen a visszatérési értéket csak paraméteren keresztül adhatjuk vissza a hívó programnak.

 

A dBase rendszerben, a többi xBase-es rendszerek zömétõl eltérõen, a

 

DO azonosító

 

utasítás elsõdleges egy programállomány futtatására vonatkozik, ezért a rendszer egy ilyen azonosítójú különálló PRG állományt fog keresni majd végrehajtani. Ha nem létezik ilyen állomány, akkor hibaüzenettel leáll a futás, hiába hoztunk létre ilyen azonosító névvel eljárásokat a programban. A dBase filozófiája szerint az eljárásoknak egy különálló eljárás állományban kell elhelyezkedniük,melyet külön ki kell jelölnünk a futtatás során. Az eljárásállomány megadása a

 

SET PROCEDURE TO állomány

 

utasítással történik. Ezután a rendszer átolvassa a megadott eljárás állományt is, hogy ott a megadott azonosítójú eljárást felkutassa és behívja végrehajtásra. Eljárásállományként lehet ugyanazt az állományt is megadni, mint amelyik a fõprogramot tartalmazza.

 

Memóriaváltozók

 

Mivel a procedurális elemeknél, az összetettebb mûveleteknél és a felhasználói interface esetén az adatbázisbeli adatok mellett egyéb kiegészítô adatokat is tárolnunk kell, a dBase bevezette a memóriaváltozók fogalmát. A memóriaváltozók a program futása alatt ideiglenes létezô, a program memóriaterületére kerülõ adatok tárolására szolgálnak, szemben az adatbázismezôkkel, melyek a hosszúidejû, a program lefutása után is megmaradó, az adattáblákban tárolt adatokat ôrzik. A memóriaváltozók a hagyományos programnyelvek változóinak feleltethetõk meg.

 

A memóriaváltozók szükségessége megmutatkozik pl. akkor, ha a felhasználótól a menün keresztül kérek be választ, ugyanis a felhasználó által adott választ nem célszerû adatbázisban letárolni, hiszen annak semmi köze a modellezett problémához, és csak nagy ritkán van szükség a válasz hosszú idejû letárolására, hogy például a késôbbiek folyamán, mondjuk egy félév mulva is meg tudjuk mondani, hogy milyen funkciókat választott ki az illetõ. Ezért a választ nem az adatbázisban, hanem memóriaváltozóban célszerû tárolni. Hasonlóan szükség van az ideiglenes adatok programon belüli megôrzésére az eljárásokon belül az aktuális paraméterek fogadásánál is, s emellett még számtalan példát lehetne még felhozni a memóriaváltozók létjogosultságára.

 

Memóriaváltozókat többféle módon lehet létrehozni. A memóriaváltozó létrehozásának egyik módja az értékadás mûvelete, amelynek formátuma

 

memóriaváltozó = kifejezés

 

Az értékadás hatására a kifejezés bekerül a kijelölt memóriaváltozóba, illetve ha a memóriaváltozó korábban nem létezett volna, akkor létre is jön elõbb a memóriaváltozó. A dBase rendszer interpreteres jellegébõl következõen a változókat nem deklarációval hozzuk létre, hanem dinamikus értékadásokkal. A változó tehát az értékadással egyben létre is hozható. A dinamikus jelleg másik következménye, hogy a változó tipusa is rugalmasan kezelhetõ, azaz a változókhoz nem tartozik rögzített tipus. A memóriaváltozóknak nem rögzített tipusuk, hanem aktuális tipusuk van, amit az éppen benne tárolt érték határoz meg. Így egy változó lehet elõbb numerikus, majd karakteres tipusú, mint ahogy azt az alábbi minta is mutatja:

 

X = 34

? X

X = 'ALMA'

? X

 

A példában az X változó elõbb 34 számértéket, majd az ALMA szöveget tárolja.

 

Az érékadással létrehozott memóriaváltozók a létrehozó eljárás végéig élnek. Az eljárásból való kilépés után, a változó megszûnik, tovább nem használható. A megszûnéséig azonban a program bármelyik elérhetõ szeletében látható és felhasználható. Mivel az eljárásból a vezérlés átadható meghívott al-eljárásokba, mielõtt kilépnénk az eljárásból, ezért a létrehozott memóriaváltozó a létrehozó eljáráson kívül, az eljárásból meghívott al-eljárásokban is látható és használható. A vázolt láthatósági területtel és élettartammal rendelkezõ változókat privát változóknak nevezzük.

 

A memóriaváltozók másik csoportját azon memóriaváltozók alkotják, melyek nem szûnnek meg a létrehozó programegység leállásakor. Ezen memóriaváltozók a létrehozás pillanatától a program bejezéséig élnek, s ez idõ alatt a program bármelyik egységébõl elérhetõk, haszálhatók. A memóriaváltozók ezen csoportját globális, publikus memóriaváltozóknak nevezzük. Egy publikus memóriaváltozót a

 

PUBLIC memóriaváltozó

 

utasítással lehet létrehozni. Az így létrehozott változó nem fog megszûnni a programegységbôl történô kilépéskor. A rendszer a megadott nevet feljegyzi, mint publikus változó azonosítót, így ezen változó névre történõ hivatkozásokkor e globális változó értéke kerül felhasználásra, módosításra.

 

Egy adott eljáráson belül kiadott

 

X = 24

 

értékadó utasításhoz a körülményektõl függõen több különbözõ végrehajtás tartozhat. Ha ugyanis az eljárásban látható egy X nevû globális változó, akkor annak az értéke fog 24-re módosulni. Ha viszont egy külsõ eljárás privát változója látható, akkor annak az értéke fog módosulni. Ha viszont sem globális sem külsõ privát változó nem él, akkor a rendszer egy saját privát változót fog létrehozni, amely eztkövetõen felveszi a 24 értéket. Tehát az értékadás konkrét alakja külsõ, más eljárás moduloktól, az azokban bevezett változók körétõl is függ. Ez az jelenti, hogy igencsak figyelni kell a többi modul belsõ felépítésére is. A figyelmetlenség igen furcsa és kellemetlen következményekkel járhat.

 

A kellemetlen mellékhatások csökkentésére a dBase lehetõséget ad a külsõ eljárásokban definiált változók elfedésére, letakarására. Ezt azt jelenti, hogy létre lehet hozni olyan memóriaváltozót, amely az eljárásra nézve privát hatáskörû lesz és azonosító neve megegyzehet a globálisan vagy külsõ blokkban megadott változók azonosító neveivel. Ezen névre történõ hivatkozások e privát változót fogják látni, s nem a külsõ változókat. Az utasítás alakja:

 

PRIVATE memóriaváltozó

 

Ezen utasítás elrejti az ilyen néven esetlegesen létezõ külsô változókat. Az ezen eljárásból meghívott eljárásokban is ez a változó fog a továbbiakban látszani. A PRIVATE utasítás nem hoz létre véltozót, csak eltakarja a külsõ változókat, maga az új privát változó csak az elsõ értékadás után fog létrejönni.

E tény szemléltetésére vegyük az alábbi kis példát. A

 

PUBLIC X

? X

 

hatására a képernyõre egy .F. érték fog kiíródni, ami jelzi, hogy az X azonosítójú memóriaváltozó létezik, és default értéke a logikai hamis érték. Ezzel szemben a

 

PRIVATE X

? X

 

kipróbálásakor a kiíratásnál hibüzenetet kapunk, hogy az X változó nem létezik, mivel a PRIVATE nem hozza létre az X-et. Ekkor az X csak az elsõ értékadás után jön létre.

 

A dBase egyik jellemzõje, hogy értéket közvetlenül csak memóriaváltozóknak adhatunk, adatbázismezôknek nem. Az adatbázismezõk értékeinek módosítására a már ismertett REPLACE utasítás szolgál. A szabályok ugyan nem tiltják, hogy olyan memóriaváltozót hozzunk létre, melynek neve megegyezik a munkatáblázat egy mezôjének azonosító nevével, de ebben az esetben egy újabb potenciáis hibalehetõséget építünk be a programunkba. A dBase-ben ugyanis a hivatkozáskor a mezônév elsôbbséget élvez, s úgymond eltakarja a memóriaváltozót. Az egyenlõség jellel megadott értékadáskor viszont az értékadás csak a memóriaváltozóra vonatkozhat. A memóriaváltozók és mezõazonosítók viszonyának szemléltetésére álljon itt egy kis példa, egy kis program forrásszövege:

 

USE auto

ar = "alma"

x = "korte"

? ar

? x

x = ar + 1

? x

USE

? ar

 

Ha feltesszük, hogy az auto táblázatban létezik egy ar mezô, a kocsi árának jelölésére (tehát numerikus típusú), és a táblázat elsô rekordjában 555555 az értéke az ar mezônek, akkor a program futtatása a következô adatokat írja ki a képernyôre:

 

555555

korte

555556

alma

 

ugyanis az elsô kiíratásnál a mezônév eltakarta a memóriaváltozót, így az aktuális (nyitás után a táblázat elsô) rekordjában tárolt ar mezôérték íródik ki. A második kiíratás x változót szöveges típusúként, a harmadik kiíratásnál pedig numerikus típusúként kezeli, hiszen elôtte egy numerikus típusú kifejezés értékét vette fel. Az utolsó kiíratásnál újra él az ar memóriaváltozó, mert az auto táblázatot lezártuk, adatai nem érhetôk el a programból.

 

A memóriaváltozók használatának szemléltetésére egy kis példaprogramot adunk, amely egy p2.prg állományban került letárolásra. Ugyanabben az állományban lettek megadva a meghívott eljárások is. Ezért kell a programot a SET PROCEDURE TO utasítással kezdeni.

 

SET PROCEDURE to p2

m1 = 1

m2 = 2

DO al1 WITH m1

? m1, m2

DO al2 WITH +m1

? m1, m2, m4

*** ? m3

CLOSE ALL

RETURN

PROCEDURE al1

PARAMETERS x

m3 = 4

m2 = 8

? x, m3

x = x +1

m2 = m2 + 1

RETURN

PROCEDURE al2

PARAMETERS x

PRIVATE m2

PUBLIC m4

m2 = 8

m4 = 5

? x, m4

*** ? m3

x = x + 1

m2 = m2 + 2

RETURN

 

A dBase programokban a * jellel kezdôdô sorok megjegyzések, melyek nem hajtódnak végre. A mi esetünkben azok a kiíratások kerültek megjegyzésbe, melyeket nem lehet végrehajtani. A futtatás eredménye:

 

1 4

2 9

2 5

2 9 5

 

A program mûködése a következôkben foglalható össze. Elsôként az al1 eljárás kerül meghívásra, ahol az átadott paraméter, az m1 átkerül az x változóba. Mivel cím szerinti átadás történt, x és m1 ugyanazon címre mutatnak. Így a kiíratásnál x értéke megegyezik m1 értékével (1) és m3 értéke pedig 4. A cím szerinti paraméterátadás miatt amikor x értékét megnöveljük eggyel, akkor m1 értéke is megnövekszik eggyel, így új értéke 2 lesz. Mivel egy változó a meghívott eljárásokban is látható, ezért az m2 as al1 eljáráson belül a fômodulban létrehozott m2-t jelenti, így annak értéke az eljárásban elôbb 8-ra, majd 9-re változik. Így a fômodulban, az eljáráshívást követô kiíratásnál m1 értéke 2, m2 értéke 9 lesz.

Ezután következik al2 meghívása, az átadott paraméter most az m1 lesz, mely és most is egy x változóba kerül át. Az al2 meghívásánál viszont m1 nem cím szerint, hanem érték szerint adódik át, tehát x változtatása nem fogja érinteni m1 értékét. Az al2-ben létrehozott m2 változó az al2 eljárás saját változója, melynek címe és értéke független a fômodul m2 változójától, így hiába rendeljük hozzá a 10 értéket, a fômodulbeli m2 értéke továbbra is 9 marad, mint ahogy azt a kiíratás mutatja. Az ugyanitt létrehozott m2 globális változó, így az az al2-bôl történô kilépés után is megmarad, értéke 5 lesz. Mivel az m3 az al1-ben jött létre, így amikor a vezérlés kilépett belõle, m3 is megszûnt, ezért nem iratható ki al2-ben sem. Visszatérve a fômodulra, m1 és m2 értéke maradt változatlan. Az m4 értéke a fômodulban is látható lesz, hiszen m4 a program végéig élni fog, míg m3 értéke már nem látható, mert az al1-bôl történô kilépéskor megszûnt. A fôprogram végén található

 

CLOSE ALL

 

utasítást azért célszerû megjegyezni, mert segítségével az összes megnyitott állományt lezárhatjuk, mintegy alaphelyzetbe hozva a dBase rendszert. Ez az utasítás fôleg a hibával történô leállás után nyújt nagy segítséget.

 

Vezérlési szerkezetek

 

Az folyamatvezérlô utasítások körében lehetôség van ciklusok és elágazások képzésére. Ciklusból csak egy fajta áll rendelkezésre, míg az elágazás szerkezetnél használhatunk egyszerû és többszörös elágazást is.

 

Az egyszerû elágazás parancsa jól ismert IF szerkezet, amely a dBase-ben a következô szintaktikával használható:

 

IF feltétel

igaz ág utasításai

[ELSE

hamis ág utasításai]

ENDIF

 

Amint látható, az igazági parancsoknak az IF kulcsszót követô sorban kell elhelyezkedniük. Az igazági parancsok több soron keresztül is folytatódhatnak. Az IF után nem szerepelhet a megszokott THEN kulcsszó, s a szerkezet végét az ENDIF utasítással kell lezárni. feltételként logikai értékkel rendelkezõ kifejezést lehet szerepeltetni. Az egyes utasítások végét a sorvégjel jelzi, azaz alapértelmezés szerint minden utasítás egy sort foglal le. Ha egy utasítás egy sorra nem férne el, akkor lehet folytatósort is használni, melyet a sor végén álló pontosvesszõ karakterrel jelzünk.

 

A többszörös elágazás parancsa a

 

DO CASE

CASE felt1

felt1 ág utasításai

[...

CASE felti

felti ág utasításai]

[OTHERWISE

különben ág utasításai]

ENDCASE

 

szerkezet. A többszörös elágazás mûködése a következô. Elsôként a felt1 kifejezést értékeli ki a rendszer, s ha az igaz értéket ad, akkor végrehajtja az felt1 ágban megadott utasításokat, majd utána kilép az ENDCASE-t követô sorra. Ha az elsô feltétel nem igaz, akkor folytatja tovább a keresést, mindaddig, míg igaz értéket kielégítõ feltételt nem talál a CASE ágakban. Ha igaz kifejezést talál, akkor végrehajtja az oda tartozó utasításágat, majd kilép az ENDCASE utáni sorra. Ha egyetlen egy CASE feltétel sem teljesülne, akkor ha van, ráugrik az OTHERWISE után megadott utasításokra.

 

A ciklusok szervezésére a WHILE ciklus struktúra áll rendelkezésre. A ciklus utasítás formátuma:

 

DO WHILE feltétel

ciklusmag utasításai

ENDDO

 

A ciklusmag akkor kerül végrehajtásra, ha a feltétel igaz értékû. A ciklusmag végrehajtása után újra a feltétel kerül kiértékelésre.

A ciklushoz kapcsolódóan két speciális utasítást lehet megemlíteni, a LOOP és EXIT utasításokat. A

 

LOOP

 

utasítás hatására a vezérlés átugorja a ciklusmag hátralévõ utasításait, s újra a feltételt ellenõrzi, hogy kiléphet-e a ciklusból.

Az

 

EXIT

 

utasítás pedig a ciklusból történõ közvetlen kilépsére szolgál. Hatására a vezérlés rögtön a ciklus utáni utasításra kerül át.

 

Az elágazások és ciklusszervezõ utasításainak szemléltetésére példaként vegyük azt az esetet, amikor a piros színû autókat egyenként kiírjuk a képernyõre, s minden autónál az ár függvényében megadjuk, hogy olcsó, közepes árú, vagy drága, és a végén megadjuk, hogy sok vagy kevés drága autó szerepel a nyilvántartásban:

 

*** piros színû autók kiírása

SELECT 1

USE auto

db = 0

LOCATE FOR szin = 'PIROS'

DO WHILE FOUND()

DO CASE

CASE ar < 1500000

megj = "olcso"

CASE ar >= 1500000 .AND. ar < 4000000

megj = "kozepes arfekves"

OTHERWISE

megj = "draga"

db = db + 1

ENDCASE

szoveg = rsz + ":" + tipus + ":" + str(ar) + ":" + megj

? szoveg

CONTINUE

ENDDO

IF db > 100

? 'sok drága autó van'

ELSE

? 'kevés drága autó van'

ENDIF

USE

 

Amennyiben a végrehajtás nemcsak egy egyedi alkalommal szükséges, akkor megéri a kersesésnél az indexelést felhasználni a végrehajtási idõ csökkentése céljából. Mivel a keresés a szín mezõ értéke alapján történik, ezért a szín mezõhöz szükséges az indexet kötni. A következõ program az elõzõ feladat egy másik megoldását mutatja, amely akkor használható, ha létezik index szín mezõhöz.

 

*** piros színû autók kiírása

SELECT 1

USE auto INDEX szin

db = 0

SEEK 'PIROS'

DO WHILE .NOT. EOF() .AND. szin = 'PIROS'

DO CASE

CASE ar < 1500000

megj = "olcso"

CASE ar >= 1500000 .AND. ar < 4000000

megj = "kozepes arfekves"

OTHERWISE

megj = "draga"

db = db + 1

ENDCASE

szoveg = rsz + ":" + tipus + ":" + str(ar) + ":" + megj

? szoveg

SKIP 1

ENDDO

IF db > 100

? 'sok drága autó van'

ELSE

? 'kevés drága autó van'

ENDIF

USE

 

Ez az algoritmus gyorsabb végrehajtást eredményez, mint az elõzõ, hiszen a gyorskeresés hamarabb megtalálja az érintett rekordokat mint a szekvenciális pásztázás.

 

A két említett módszeren kívül még egyéb megvalósítási ötlete is lehetnek az említett feladathoz. Így például lehetne a SET FILTER TO utasítást is használni. Igen érdekes eredményt kapunk, ha összehasonlítjuk a különözõ módszerek hatékonyságát. A teszteléshez egy 10000 rekodszámú mintatáblát használtunk. A táblázat mutatja az egyes változatokban alkalamzott módszereket és a hozzájuk tartozó relatív idõket.

 

Módszer

Idõtartam

LOCATE FOR

10

SET FILTER TO

13

INDEX, SEEK

3

INDEX, SET FILTER TO

18

 

A táblázat is mutatja, hogy ugyan az index gyorsítja a keresést, de azért nem szabad minden esetben vakon rá bízni magunkat. Az indexek használata elõtt célszerû egy hatékonyság vizsgálati elemzést elvégezni, hogy mi magunk is meggyõzõdjünk az index szükségességérõl.

 

Felhasználói felület

 

A felhaszná lói felület programozására lehetôség van a képernyô kezelésére is, mely alatt a képernyô illetve részeinek törlése, adatok formátumozott kiíratása, keretek kirajzolása és az adatok beolvasása értendôk. A direkt input-output mellett lehetôség van a billentyûk benyomásának indirekt figyelésre is, s mintegy triggerszerûen megadható egy utasítással, hogy a billentyû lenyomása esetén milyen parancsot hajtson végre a rendszer. Az utasítás kijelölése az

 

ON esemény utasítás

 

paranccsal hívható meg, melyben az esemény az alábbi három típus valamelyike lehet:

 

ERROR : dBase hiba

ESCAPE : Esc billentyû lenyomása

KEY : valamilyen billentyû lenyomása

 

Az esemény bekövetkezése után a megadott utasítás automatikusan végrehajtódik.

 

Az esemény figyelését az

 

ON esemény

 

utasítással szüntethetjük meg.

 

A képernyôkezelô utasítások közül a leggyakrabban használtak mutatjuk be a következô felsorolásban:

 

? kifejezéslista : a kifejezések értékeinek kiíratása a képernyôre

 

@s,o SAY kifejezés PICTURE formátum : a megadott kifejezés értékének kiíratása a képernyô s. sorának o. pozíciójától kezdôdôen. A SAY utasításhoz még formátumleíró elemek is tartozhatnak egy PICTURE opciót követve. A kiíratott érték formátuma követi a megadott formátumleíró kifejezést. A formátum leíró kifejezés tartalmazhat

- funkció és

- karekter minta

elemeket. A funkció a teljes kijelzési imezõre vonatkozik, akijelzés általános, globális megjelenési módját szabályozza. A legfontosabb funkciók a következõk:

B : numerikus adat balra tömörítve

Z : nulla értéket szóközökkel jelenít meg

E : európai dátumformátum

A : csak alfabetikus karakterek

! : nagybetûre konvertálás

A funkciójelet egy @ szimbólum elõzi meg a formátum leíróban.

A karakter minta egyetlen egy karakter megjelenését szabályozza. A legfontosabb minta tipusok:

9 : számjegy

A : betû

L : logikai adat

X : bármilyen karakter

! : nagybetûre alakít

. : tizedespont pozició

A formátum leírót egy szövegkonstansként kell megadni az utasításban, pl.

@3,2 SAY n PICTURE '@B999999'

 

@s1,o1 TO s2,o2 [DOUBLE] : keret rajzolása a képernyôre, a megadott pontok, mint átellenes sarkok között. A keret dupla keret lesz, ha megadjuk a DOUBLE kulcsszót is

 

CLEAR : képernyôtörlés

 

@s1,o1 CLEAR TO s2,o2 : a megadott képernyôterület törlése

 

@s,o GET memóriaváltozó PICTURE formátum RANGE a,b: érték beolvasása a megadott memóriaváltozóba a képernyô megadott pozíciójától kezdve. Az utasítás nem indítja el a lekérdezést, csak kijelöli a képernyôn a beolvasási területet. A beolvasás tényleges elvégzése a READ utasítással történik. A PICTURE opcióval megszabható az adatbeviteli formátum. A formátum leíró jelentése és szintaktikája megegyezik a SAY utasításnál megadott formátummal. A bevitt érték ellenõrzésére szolgál a RANGE opció. Megadása esetén a dBase csak azon értékeket fogadja el, amelyek értéke nagyobb engyenlõ mint a és kisebb egyenlõ mint b.

A GET utasításnál arra kell ügyelni, hogy a megadott memóriaváltozónak már léteznie kell a GET utasítás végrehajtásakor. Ennek legfõbb oka, hogy a dBAse enélkül nem tudja meghatározni az adatbevitel számára lefoglalandó mezõszélességet. Ezért az adatbeviteli memóriaváltozót a kívánt tipusú értékkel létre kell hozni a GET utasítás elõtt. Az adtbevitelkor megjelenõ default érték ezzel szemben a READ utasításkor tartalmazott érték lesz. Mivel a GET és a READ egymástól elválasztva foglal helyett a programban, elõfordulhat az, hogy a kijelölt memóriaváltozó más tipusú a GET utasításnál és más lesz a READ utasításnál. mivel a két utasítás között új értéket és vele együtt új tipust vett fel a változó.

 

READ : a kijelölt GET beolvasások elvégzése GET memóriaváltozó

 

@s,o SAY kifejezés PICTURE formátum PICTURE formátum RANGE a,b: A SAY és a GET utasítások összevonása, amely úgy mûködik, hogy elõbb, mintegy prompt szerûen kiíródik a SAY után megadott szöveg, majd eztkövetõen kikerül mögé az adatbeviteli mezõ is. A bevitt érték a GET után megadott memóriaváltozóba kerül le.

 

INKEY() : a felhasználó által utoljára benyomott billentyû kódját adja vissza. Ezzel a függvénnyel válik lehetôvé a funkcióbillentyûk kezelése is. Ha nincs lenyomva billentyû, akkor a 0 érték kerül visszaadásra. A normál karakterek esetén a karakter ASCII kódjával egyezik meg a visszatérési érték. Egyéb speciális karakter INKEY() értéke:

balra nyíl : 19

jobbra nyíl : 4

felfelé nyíl : 5

lefelé nyíl : 24

DEL : 7

HOME : 1

 

Mintaprogramok

 

A dBase fejezet zárásaként egy pár összetettebb példát mutatunk be.

 

Elsõ programunkban autók adatait visszük fel, ahol a tulajdonos mezô csak létezô emberre mutathat. A példához adott az alábbi két táblázat:

 

AUTO (rendszam, tipus, tulaj)

EMBER (kod, nev, varos)

 

Az autó adatokat egymásután egy ciklusban kérjük be, amíg van felvivendô rekord. A programhoz feltesszük, hogy létezik egy E1 indexállományt, melyet a következô parancs hozott létre:

 

USE ember

INDEX ON kod TO e1

 

A program szövege a magyarázatokkal kiegészítve a következô:

 

**** zavaró üzenetkiírások letiltása

SET TALK OFF

SET STATUS OFF

**** adattáblázatok megnyitása

SELECT 1

USE auto

SELECT 2

USE ember INDEX e1

SELECT auto

**** képernyôre a fix részek kiírása

CLEAR

@2,2 TO 16,78 DOUBLE

@4,31 SAY "Uj auto felvitele"

@8,20 SAY "Rendszam :"

@10,20 SAY "Tipus :"

@12,20 SAY "Tulajdonoskod :"

**** memóriaváltozók létrehozása a beolvasáshoz

m_rendszam = SPACE(6)

m_tipus = SPACE(20)

m_tulaj = 0

**** beviteli ciklus

DO WHILE .T.

**** beolvasás a memóriaváltozókba

@8,40 GET m_rendszam

@10,40 GET m_tipus

@12,40 GET m_tulaj

READ

**** ellenôrzés, hogy van-e ilyen emberkód

SELECT ember

SEEK m_tulaj

talalt = FOUND()

SELECT auto

**** ha nincs, üzenet kiírás

IF .NOT. talalt

@14,20 SAY "Nincs ilyen emberkod"

ELSE

**** ha van a rekord felvitele

APEND BLANK

REPLACE rendszam WITH m_rendszam, tipus WITH m_tipus,;

tulaj WITH m_tulaj

ENDIF

**** a felhasználó további lépésének bekérdezése

@14,45 SAY "Kilep:x Uj rekord:u"

i = 0

DO WHILE I <> ASC("u") .AND. I <> ASC("x")

i = INKEY()

ENDDO

**** kilépés a ciklusból

IF i = ASC("x")

EXIT

ENDIF

**** üzenetsor törlése

@14,4 CLEAR TO 14,76

ENDDO

**** adatok lezárása, kilépés

CLEAR

CLOSE ALL

 

A következõ programban az összetartozó autó és ember adatokat listázzuk ki a képernyõre. A képernyõn egyidejûleg nem lehet több rekord kilistázva,mint három. A megjelenõ adatoknak egy keretben kell elhelyezkedniük és egy fejlécnek is meg kell jellenie a képernyõn. A listában az autó rendszáma, tulajdonos kódja, valamint a tulajdonos neve és kódja jelenjen meg. A listázásnak úgy kell mûködnie, hogy három rekord kilistázása után várakozzon, s ha a felhasználó lefele nyilat üt le a billentyûn, akkor menjen tovább elõre, ha felfele nyilat üt le, akkor menjen vissza az elõzõ rekordokra, míg ha ESC billentyût üt le, akkor álljon le a program. A kilistázásnál ügyelni kell arra, hogy ne szaladjunk ki az utólsó rekord után, és ne próbáljunk az elsõ rekord elé sem mozogni. A két alaptábla:

 

AUTO (TIP, RSZ, TUL, AR)

EMBER (ID, NEV, CIM, KOR)

 

A következõ lista egy megoldást mutat be a feladatra.

 

**** zavaró üzenetkiírások letiltása

set echo off

set talk off

**** elsõ mukaterületre az auto tábla kerül be

select 1

use auto

**** a második munkaterületre az ember jön, a szükséges ****indexxel együtt

select 2

use ember index embind

**** kapcsolat kiépítése a két tábla között

select auto

set relation to tul into ember

**** rekordok száma a mozgás ellenõrzéséhez

max = reccount()

go top

**** aktuális rekordpozició

pos = 1

**** segésváltozó amely jelzi, hogy kell-e még további listázás

KELL = .T.

**** ciklus amíg kell

do while kell

**** képernyõ felrajzolás

clear

@4,2 to 16,78 double

@2,30 say 'A U T O A D A T O K'

**** adatrekordok kilistázása

db = 1

do while db < 4

@6+2*db, 5 say rsz + " " + str(tul) + " " + ember->nev +

" " + str(ember->id) + " " + str(pos)

db = db + 1

pos = pos + 1

**** ha utólsó rekord is kiíródott, kilépés a kiírási ciklusból

if pos > max

exit

endif

**** különben ugrás a következõ rekordra

skip 1

enddo

**** billenytû benyomás figyelése

c = 0

do while c = 0

c = inkey()

enddo

**** elágazás a billntyû kód függvényében

do case

**** ESC kód, kilépés

case c = 27

kell = .f.

**** mozgás vissza

case c = 5

pos = pos - 6

**** ha túlléptünk az elején

if pos < 1

pos = 1

endif

goto pos

**** mozgás elõre

case c = 24

**** ha túlléptünk a végén

if pos > max

pos = max - 2

if pos < 1

pos = 1

endif

goto pos

endif

**** egyéb billentyû, helyben marad

otherwise

@20,2 say 'Nem ertelmezett'

pos = pos - 3

goto pos

endcase

**** nagy ciklus vége

enddo

**** táblák lezárása

clear

use

select ember

use

 

A követekezõ feladat egy egyszerû összegfokozatos listát készítünk. A megoldandó feladat egy autólista elkészítése, melyben az elõbbi autó táblából elõ kell állitani egy olyan listát, amely az autók tipusait tartalmazza a tipuhoz tartozó autók átlagárainak értékeivel. Ezenkívül adjuk meg a program végén a teljes autó állományra vonatkozó átlagárat is. A képernyõn egyidejûleg nem lehet 4 sornál több sor kijelezve a tipusokat listázó részben.

 

Egy megoldást mutat be a következõ lista.

 

 

**** környezeti paraméterek beállítása

set echo off

set talk off

**** adattábla megnyitása indexelve

select 1

use auto index autip

**** képernyõ felrajzolás

clear

@2,4 say 'AUTO TIPUSOK ES ATLAGARAIK'

@4,4 say ' TIPUS ATLAGAR'

otip = ' '

pos = 6

goto top

**** számlálók beállítása

otip = tip

ossz = 0

OOSSZ = 0

db = 0

ODB = 0

**** ciklus az összes autóra

do while .not. eof()

**** ciklus az azonos tipusú autókra

do while tip = otip .and. .not. eof()

ossz = ossz + ar

db = db + 1

skip 1

enddo

**** részösszeg kiirása

@pos,5 say otip + ' ' + str(ossz/db)

pos = pos + 1

**** globális változók aktualizálása

OOSSZ = OOSSZ + OSSZ

ODB = ODB + DB

**** uj képernyõ, ha megtelt az elõzõ

if pos > 9

wait 'Enter: tovabb'

@6,0 clear to 23,78

pos = 6

endif

**** változók inicializálása

if .not. eof()

otip = tip

db = 0

ossz = 0

endif

**** rekordciklus vege

enddo

wait 'vege'

@12,4 say 'GLOBÁLIS ÁTLAGÁR:' + ' ' + STR (OOSSZ/ODB)

**** állomány lezárása

use

clear