10. Modulok használata a Turbo Pascal-ban A szabványos Pascal nyelv semmilyen lehetőséget nem tartalmaz arra, hogy nagyobb program esetén a program egyes részeit külön lefordítva állítsuk elő a futtatható kódot. Sőt az objektumok felhasználás előtti kötelező deklarációja miatt, programkönyvtárat csak forrás nyelven lehet létrehozni, és azt a programba beépíteni (lásd a {$I file-név} dírektiva használatát). A Turbo Pascal nyelvet azonban ellátták a MODULA-2 és az ADA nyelvekből ismert modulkezelési mechanizmussal. A modul - önállóan lefordítható programegység (unit), amely jól definiált kapcsolódási felületen (interface) keresztül kapcsolódik a program más részeihez. Alapvető elv a moduláris programozás során, hogy a modulok belső része (implementation) rejtett a külvilág számára. A Turbo Pascal modulokat unit-oknak nevezzük. A modulok bevezetésével lehetővé vált programkönyvtárak kidolgozása, és a moduláris programozás megvalósítása Turbo Pascal nyelven. Nagy méretű programok fejlesztése során a modulok használata feltétlenül szükséges, hisz a fordító a főprogram kódméretét 64 Kbyte-ban (egy szegmens) korlátozza. A unit-okra nézve ez a korlátozás szintén érvényes, azonban a főprogram és a modulok együttes kódméretének nagysága csak a memória méretétől függ. 10.1. A Turbo Pascal modulok felépítése A unit-ok felépítése jellegében emlékeztet a főprogram felépítésére, azonban jelentősen el is tér attól: unit modulnév; { a modul fejléce, nem hagyható el } interface { a kapcsolódási felület rész } uses ... const ... type ... var ... eljárások és függvények fejlécei implementation { az implementációs rész } uses ... label ... const ... type ... var ... eljárások és függvények teljes deklarációja [[ begin { az inicializációs rész } Pascal utasítások ]] end. A unit-ok három jól elkülöníthető részből állnak, amelyek közül az inicializációs rész elhagyható. A továbbiakban részletesen ismertetjük az egyes részek használatával kapcsolatos szabályokat és lehetőségeket. 10.1.1. A modulok fejléce - a modulok közötti kapcsolat A modulok fejléce a unit foglalt szóból és az azt követő modulnévből áll -sohasem hagyható el. A modulnévnek (ellentétben a programnévvel) meg kell egyeznie a modult tartalmazó file nevével. Például a unit Global; modult a GLOBAL.PAS file-ban kell elhelyezni. A modul nevét használjuk más modulokkal illetve a főprogrammal való kapcsolat kialakítására: uses modulok listája; ahol a uses (használja) foglalt szót a felhasználni kívánt modulok neveinek vesszővel tagolt listája követi. Például: uses CRT, Graph, Global; Az interface részben deklarált Pascal objektumokra a főprogramból megismert módon hivatkozhatunk. Ha a felhasznált modulok közül többen azonos névvel fordul elő valamely eljárás vagy függvény, akkor a hivatkozást egyértelművé tehetjük a modulnév megadásával. Például a Line eljárás, amely a Graph unit-ban található, az alábbi alakban is hívható: Graph.Line(10,10,200,200); 10.1.2. Az interface rész A kapcsolódási felület részt az interface foglalt szó nyitja meg. Ebben a részben található a unit globális objektumainak (típusok, konstansok, változók és alprogramok) deklarációja, amelyek más modulokból is elérhetők. A globális eljárásoknak és függvényeknek csak a fejléce adható meg az interface részen belül: unit Cmplx; interface type complex=record re, im : real; end; Procedure AddC(x,y : complex; var z : complex); Procedure MulC(x,y : complex; var z : complex); Procedure WriteC(x:complex); Ha ezek után a főprogramban megadjuk a uses Cmplx; programsort, akkor a főprogram számára elérhetővé válik a complex típus és az AddC , a MulC a WriteC eljárás. Meg kell jegyeznünk, hogy az interface részben definiált típusos konstansokat és változókat szintén a program adatszegmensében tárolja a fordító (ennek maximális hossza 65520 byte). A const, type, var, procedure és function deklarációk száma és sorrendje tetszőleges, azonban forward deklaració használata nem megengedett. Az interface részben szintén hivatkozhatunk más modulokra (uses), abban az esetben, ha az ott definiált típusokat kivánjuk felhasználni. 10.1.3. Az implementation rész A modul implementációs része egyrészt az interface részben megadott globális eljárások és függvények teljes definícióját, másrészt pedig a unit lokális deklarációit (címke, konstans, típus, változó, eljárás és függvény) tartalmazza. A globális alprogramok fejlécét az implementation részben kétféleképpen is megadhatjuk: - vagy használjuk az interface részben megadott teljes formát, Procedure AddC(x,y : complex; var z : complex); begin end; - vagy a formális paraméterek (és a függvények esetén a visszatérési érték típusának jelölése) nélkül adjuk meg a fejlécet. Procedure AddC; Egészítsük ki az előző részben közölt interface részt teljes modullá: unit Cmplx; interface type complex=record re, im : real; end; Procedure AddC(x,y : complex; var z : complex); Procedure MulC(x,y : complex; var z : complex); Procedure WriteC(x:complex); implementation Procedure AddC; begin z.re := x.re + y.re; z.im := x.im + y.im; end; Procedure MulC; begin z.re := x.re * y.re - x.im * y.im; z.im := x.re * y.im + x.im * y.re; end; Procedure WriteC; begin write(x.re:3:1,'+',x.im:3:1,'i'); end; end. A fenti programot a CMPLX.PAS file-ban tárolva, a komplex számokkal való összeadás (Addc) , szorzás (Mulc) elvégzésére valamint a komplex szám kiírására alkalmas unit-ot kapunk. A modul felhasználását az alábbi főprogram mutatja be (COMPLEX.PAS): program Komplex_pelda; uses cmplx; const c:complex=(re:1;im:2); var x,y,z:complex; begin x:=c; y:=c; Addc(x,y,z); writeln; Writec(x); write(' + '); WriteC(y); write(' = '); WriteC(z); Mulc(x,y,z); writeln; Writec(x); write(' * '); WriteC(y); write(' = '); WriteC(z); end. Az implementációs részben deklarált típusos konstansok és az alprogramokon kívül definiált változók szintén a program adatszegmensében helyezkednek el, habár elérhetőségük az implementációs részre korlátozódik. 10.1.4. A inicializációs rész Az inicializációs rész a modul működéséhez szükséges tevékenységek elvégzésére szolgál (például kezdőértékek beállítása). A program futtatása során a unit inicializációs része egyetlen egyszer hajtódik végre, mégpedig ott, ahol a uses utasításban a modul neve először előfordul. Ez a rész el is hagyható, ekkor az implementációs részt zárja az end. utasítás. Nézzünk egy példát, amelyben az inicializációs részben egy szöveg file-t nyitunk meg: Unit FileText; Interface Procedure Print(s:string); Procedure Endprint; Implementation var f : text; const fname = 'out.txt'; Procedure Print; begin writeln(f,s); end; Procedure Endprint; begin flush(f); close(f); end; { -- Az inicializációs rész kezdete -- } begin assign(f,fname); rewrite(f); { -- Az inicializációs rész vége -- } end. 10.2. A modulok használatát bemutató példaprogram Hozzunk létre egy olyan unit-ot, amely segíti a szöveges képernyőn az ablaktechnika megvalósítását. A KERETU.PAS file-ban található modul globális eljárásai adott terület törlését illetve keretezését végzi el: unit keretu; { a KERETU.PAS file-ban kell megírni… } {--------------------- interface -----------------} interface var keretszin, torolszin: byte; { Adott képernyőterület keretezése } procedure keret(x1,y1,x2,y2,tipus,kszin:byte); { Adott képernyőterület törlése } procedure torol(x1,y1,x2,y2,szin:byte); {------------------- implementation---------------} implementation uses crt; function ellenor(a1,a2,b1,b2:byte):boolean; { A helyes területkijelölés ellenőrzése - (a1,a2) : a bal felső sarok koordinátái - (b1,b2) : a jobb alsó sarok koordinátái } var ok:boolean; begin ok:=true; if (a1>=b1) or (a2>=b2) then ok:=false; if not((a1 in [1..80]) and (a2 in [1..25])) then ok:=false; if (b1<1) or (b1>80) and (b2<1) or (b2>25) then ok:=false; ellenor:=ok; end; procedure torol(x1,y1,x2,y2,szin:byte); { - (x1,y1) : a bal felső sarok koordinátái - (x2,y2) : a jobb alsó sarok koordinátái - szin : a terület színe } var sor:string[80]; i:integer; begin if ellenor(x1,y1,x2,y2) then begin window(x1,y1,x2,y2); textbackground(szin); clrscr; window(1,1,80,25); end; end; procedure keret(x1,y1,x2,y2,tipus,kszin:byte); { - (x1,y1) : a bal felső sarok koordinátái - (x2,y2) : a jobb alsó sarok koordinátái - tipus : vonaltípus (1 - egyszeres, 2 - dupla , 3 vastag) - kszin : a keret színe } var i:byte; r:string[9]; begin if ellenor(x1,y1,x2,y2) then begin case tipus of 1: r:=#218+#191+#192+#217+#196+#179+#196; 2: r:=#201+#187+#200+#188+#205+#186+#205; 3: r:=#219+#219+#219+#219+#223+#219+#220; end; textcolor(kszin); gotoxy(x1,y1); write(r[1]); for i:=x1 to x2-2 do write(r[5]); write(r[2]); for i:=1 to ((y2-1)-y1) do begin gotoxy(x1,y1+i); write(r[6]); gotoxy(x2,y1+i); write(r[6]); end; gotoxy(x1,y2); write(r[3]); for i:=x1 to (x2-2) do write(r[7]); write(r[4]); end; end; {------------------ unit init ----------------} begin keretszin:=15; { feher } torolszin:=0 ; { fekete } textbackground(torolszin); clrscr; textcolor(keretszin); end. A unit működését bemutató főprogram különböző színű területeket keretez be, különböző kerettípus felhasználásával. A főprogramot a KERETPLD.PAS file tartalmazza: program keretezes_pelda; { a KERETPLD.PAS file tartalmazza … } uses crt,keretu; var i:integer; begin torol(1,1,80,25,4); keret(2,1,79,25,1,keretszin); for i:=1 to 3 do begin torol(10+i*2,1+i*2,70-i*2,24-i*3,i); keret(10+i*2,1+i*2,70-i*2,24-i*3,i,15-i); end; end. 10.3. Szabványos modulok A Turbo Pascal rendszer nyolc szabványos modullal rendelkezik, amelyek sok hasznos típust, konstanst, eljárást és függvény tartalmaznak. Ezek a modulok: SYSTEM, DOS, CRT, PRINTER, GRAPH, OVERLAY, TURBO3 és a GRAPH3. A GRAPH, TURBO3 és a GRAPH3 modulok különálló file-okban helyezkednek el (.TPU), míg a többi modult a TURBO.TPL (Turbo Pascal Library) könyvtár tartalmazza. A SYSTEM unit automatikusan hozzákapcsolódik minden Turbo Pascal programhoz, míg minden más unit eléréséhez a uses hivatkozás használata szükséges. Az alábbiakban röviden jellemezzük a szabványos modulokat: A CRT modul elsősorban a képernyő szöveges üzemmódját támogató eljárásokat és függvényeket tartalmaz. Ezek segítségével lehetőség van a kurzor pozícionálására, a használt színek beállítására és ablakok létrehozására. Ezen kívül a modul tartalmaz néhány eljárást, amelyek segítségével a billentyűzet speciális módon érhető el, és lehetőség adódik hanggenerálásra. A DOS modulban azok az eljárások és függvények vannak össze- gyűjtve, amelyek segítségével hatékonyabban kihasználhatjuk az MS-DOS operációs rendszer lehetőségeit. A GRAPH unit a képernyő grafikus üzemmódját támogató típusok, konstansok eljárások és függvények gazdag készletét tartalmazza. Ezek segítségével tetszőleges grafikus kép előállítható illetve a programozható karakterkészlet felhasználásával szövegek is megjeleníthetők. A GRAPH unit rutinjai a megfelelő BGI-vezérlő felhasználásával tetszőleges grafikus kártya esetén használhatók. A Turbo Pascal rendszer a CGA, a Hercules, az EGA, a VGA, az MCGA, az IBM8514, az ATT400 és a PC3270 grafikus adapterekhez tartalmaz BGI vezérlőt. Más kártya esetén a vezérlőt külön kell beszerezni. Az OVERLAY modul használata akkor szükséges, amikor nagy programok fejlesztése esetén az átlapolási (overlay) technika használata válik szükségessé. Ezzel a technikával a rendelkezére álló szabad memória méretét (550-620 Kbyte) meghaladó méretű programok is előállíthatók. A PRINTER modul leegyszerűsíti a szöveges információk nyomtatását. A modulban definiált a TEXT típusú LST file, amely a PRN logikai egységgel áll kapcsolatban. Az eredménynek a nyomtatón való megjelenítése ezáltal egyszerűen, az alábbi példában bemutatott módon végezhető el: uses printer; begin writeln(LST,'Turbo Pascal 5.0, 5.5, 6.0'); end. A SYSTEM unit tartalmazza a szabványos Pascal nyelv eljárásait és függvényeit illetve azokat a Turbo Pascal rutinokat (inc, dec, getdir ...), amelyek nem kerültek más modulba. Mint ahogy azt már említettük, a SYSTEM modul minden program fordításakor felhasználásra kerül függetlenül attól, hogy a uses utasításban hivatkoztunk rá, vagy sem. A TURBO3 és a GRAPH3 modulokat a Turbo Pascal 3.0-ás verziójával való forrásnyelvű kompatibilitás miatt tartalmazzák az újabb verziójú rendszerek. Az itt definiált rutinok használata nem ajánlott, hiszen az új könyvtárakban bőséges lehetőség kinálkozik minden tevékenység elvégzésére. ( A Turbo Pascal 6.0 a Turbo Vision lehetőségek használatához még további szabványos modulokat tartalmaz.) Felhívjuk a figyelmet arra, hogy saját készítésű modulokat tartalmazó főprogram sikeresen csak akkor fordítható le (Compile/Compile), ha a szükséges könyvtárak lefordított állapotban (.TPU) elérhetők a fordító számára. Amennyiben a modulok forrás file-ben vannak (.PAS) jelen, akkor a főprogram fordítását Compile/Make vagy Compile/Build választással kell elvégeznünk. Ekkor a Turbo Pascal rendszer automatikusan előállítja a lemezünkön a .TPU kiterjesztésű könyvtárakat. Ellenőrző kérdések: 1. Hasonlítsa össze a Turbo Pascal főprogramjának és unit- jainak szerkezetét … 2. Ismertesse a modulok felépítését… 3. Milyen deklarációkat lehet elhelyezni az interface és az implementation részekben? 4. Hogyan lehet a programokból modulokra hivatkozni? 5. Melyek a Turbo Pascal szabványos moduljai? 6. Milyen elvek érvényesülnek a moduláris programozás során? 7. Hogyan lehet a Pascal program kódja nagyobb, mint 64 Kbyte? 8. Mit tartalmaz a TURBO.TPL file? 9. Mely szabványos unit-ok helyezkednek el különálló file-ban? Feladatok: 1. A TEGLALAP.PAS programot (9. Fejezet 1. feladat) bontsuk szét TEGLAPR.PAS és TEGLAU.PAS modulokra. 2. Az FC_CONV.PAS programot (9. Fejezet 3. feladat) bontsuk szét FC_PR.PAS és FC_U.PAS modulokra. 3. A lemezen található PASPROG.PAS file térbeli vektorok kezelését mutatja be. Bontsa szét ezt a programot PPROG.PAS és PUNIT.PAS modulokra. 4. A kijelölt helyeken egészítse ki az alábbi programot (PELDAU.PAS), majd írjon hozzá működését bemutató főprogramot PELDAP.PAS) is… ____ peldau; ____________ const n=10; ______ arrt=array[-n..n] of char; var ac: arrt; function makesrt(a:arrt; n:integer):string; ______________ var i:integer; _________ ________ var k:integer; s:string; begin s:=''; ___ k:=-n to n do s:=s+a[k]; makestr:=s; end; __________ for i:=-n __ n do ac[i]:=#32; ___.