Programowanie modularne w Turbo Pascalu
Moduły są podstawą programowania modularnego i służą do grupowania funkcji i procedur w biblioteki. Rozróżnia się biblioteki standardowe, dostępne wraz z kompilatorem, oraz biblioteki użytkownika.
W systemie Turbo Pascal występuje dwa rodzaje zbiorów z modułami:
zbiory .TPU (Turbo Pascal Unit) do których wprowadzane są skompilowane moduły, przy czym każdy zbiór może zawierać tylko jeden moduł,
zbiór .TPL (Turbo Pascal Library), który może zawierać wiele modułów.
Podczas pracy z interakcyjnym systemem Turbo Pascal do pamięci ładowany jest automatycznie zbiór TURBO.TPL zawierający moduły standardowe: CRT, DOS, GRAPH, OVERLAY, PRINTER, SYSTEM.
Moduł System dostępny jest automatycznie przez każdy program, zawiera m. in. funkcje i procedury obsługi plików (wejścia/wyjścia), funkcje do wykonywania konwersji, funkcje arytmetyczne, wskaźnikowe, do wykonywania operacji na łańcuchach i sterujące dynamicznym przydziałem pamięci.
Moduł DOS umożliwia wykonywanie funkcji systemu operacyjnego, sterowanie datą i czasem, przeszukiwanie katalogów i wykonywanie programów.
Moduł CRT zawiera funkcje i procedury obsługi ekranu i klawiatury w trybie rozszerzonym.
Moduł GRAPH to pakiet funkcji i procedur do obsługi grafiki ekranowej przy różnych kartach graficznych zamontowanych w komputerze.
Moduł OVERLAY umożliwia dzielenie dużych programów na tzw. nakładki ładowane do pamięci operacyjnej komputera w momencie, w którym są potrzebne do pracy programu.
Moduł PRINTER to najmniejszy z modułów standardowych - ułatwia dostęp do drukarki.
Z powyższych modułów tylko moduł System dostępny jest automatycznie. Użycie funkcji i procedur z pozostałych modułów wymaga ich zadeklarowania za pomocą dyrektywy uses np.
uses CRT, Graph;
która powinna wystąpić jako pierwsza w części deklaracyjnej programu.
Podobnie należy zadeklarować użycie własnych modułów.
Moduł zawiera zbiór eksportowanych definicji i deklaracji typów, stałych, zmiennych, funkcji i procedur które można z niego importować. Moduł zaczyna się od słowa kluczowego unit, po którym wymienia się nazwę modułu. Nazwą modułu jest nazwa pliku w którym elementy modułu są umieszczone. Moduł może używać elementów z innych modułów użytkownika i modułów standardowych zadeklarowanych za pomocą dyrektywy uses podobnie jak w programie głównym.
Definicje i deklaracje eksportowane przez moduł są umieszczone w sekcji rozpoczynającej się słowem interface. Tu też znajduje się deklaracja używanych modułów. W sekcji tej umieszcza się tylko nagłówki eksportowanych procedur i funkcji. Pełna ich implementacja znajduje się w sekcji implementation.
Moduł może zawierać też definicje i deklaracje lokalne oraz część inicjującą. Definicje i deklaracje lokalne stanowią własność prywatną modułu, służą do realizacji zadań zaimplementowanych podprogramów i nie są widziane na zewnątrz modułu. Część inicjująca (opcjonalna) stanowi blok instrukcji wywoływanych przed rozpoczęciem wykonywania programu wykorzystującego moduł. W części inicjującej moduł może ustalić wartości początkowe zmiennych i struktur danych deklarowanych w module. Jeżeli program wykorzystuje wiele modułów, ich części inicjujące są wykonywane w kolejności deklarowania użycia modułów.
Struktura modułu jest więc następująca:
unit Nazwa_Pliku_Modułu;
interface
uses Lista_używanych_modułów;
Definicje i deklaracje eksportowane z modułu;
implementation
Definicje i deklaracje lokalne modułu;
Implementacje procedur i funkcji;
[ begin
Część inicjująca modułu;]
end.
Przykład modułu
unit cplxproc;
interface type complex=record re,im:Real end; procedure addcplx(a,b:complex; var c:complex); procedure subcplx(a,b:complex; var c:complex); procedure multcplx(a,b:complex; var c:complex); procedure divcplx(a,b:complex; var c:complex);
implementation procedure addcplx; begin c.re:=a.re+b.re; c.im:=a.im+b.im end;
|
procedure subcplx; begin c.re:=a.re-b.re; c.im:=a.im-b.im end; procedure multcplx; begin c.re:=a.re*b.re-a.im*b.im; c.im:=a.re*b.im+a.im*b.re end; procedure divcplx; var divn:Real; begin divn:=sqr(b.re)+sqr(b.im); c.re:=(a.re*b.re+a.im*b.im)/divn; c.im:=(a.im*b.re-a.re*b.im)/divn end; end. |
Przykład
Moduł umożliwiający działania na ułamkach zwykłych.
unit ulmk;
interface
uses crt;
var l1,l2,m1,m2,wl,wm:integer;
function nwd(a,b:integer):integer;
function nww(a,b:integer):integer;
procedure dodaj(l1,m1,l2,m2:integer; var wl,wm:integer);
procedure skrot(x,y:integer; var wl,wm:integer);
procedure odejmij(l1,m1,l2,m2:integer; var wl,wm:integer);
procedure wymnoz(l1,m1,l2,m2:integer; var wl,wm:integer);
procedure podziel(l1,m1,l2,m2:integer; var wl,wm:integer);
implementation
function nwd(a,b:integer):integer;
begin
while a<>b do
if a>b then a:=a-b
else b:=b-a;
nwd:=a;
end;
function nww(a,b:integer):integer;
begin
nww:=a*b div nwd(a,b);
end;
procedure dodaj(l1,m1,l2,m2:integer; var wl,wm:integer);
var d,g1,g2:integer;
begin
d:=nww(m1,m2);
g1:=l1*(d div m1);
g2:=l2*(d div m2);
wm:=d;
wl:=g1+g2;
end;
procedure skrot(x,y:integer; var wl,wm:integer);
var d:integer;
begin
if x<>0 then
begin
d:=nwd(abs(x),abs(y));
wl:=x div d;
wm:=y div d;
end;
end;
procedure odejmij(l1,m1,l2,m2:integer; var wl,wm:integer);
var d,g1,g2:integer;
begin
d:=nww(m1,m2);
g1:=l1*(d div m1);
g2:=l2*(d div m2);
wm:=d;
wl:=g1-g2;
end;
procedure wymnoz(l1,m1,l2,m2:integer; var wl,wm:integer);
begin
wl:=l1*l2;
wm:=m1*m2;
end;
procedure podziel(l1,m1,l2,m2:integer; var wl,wm:integer);
begin
wl:=l1*m2;
wm:=m1*l2;
end;
end.
Moduły są jednostkami, które mogą być kompilowane niezależnie od programu głównego. Natomiast wykonywanie zawartych w nich procedur i funkcji odbywa się poprzez wywołanie ich w programie. Jeden moduł może być wykorzystywany w różnych programach, czyli importowany przez wiele programów. Programy mogą włączać moduł już skompilowany, bądź też kompilacja modułu może być wykonywana łącznie z kompilacją programu. Każdy program korzystający z modułu działa na własnej kopii tego modułu. Moduł programu, wykorzystywany przez inne moduły tego samego programu, jest do programu wynikowego włączony tylko jeden raz.
Polecenie Compile (ALT+F9) tłumaczy program lub moduł znajdujący się aktualnie w edytorze i umieszcza go na dysku w zbiorze nazwa.exe lub nazwa.tpu. Opcja Destination określa, czy program ma być zapamiętany na dysku, czy przechowywany tylko w pamięci
Polecenie Make (F9) sprawdza, czy poleceniem Primary File określono zbiór pierwszoplanowy. Jeśli tak, to jest on kompilowany, a jeśli nie, to kompilowany jest zbiór ostatnio wczytany do edytora. Następnie sprawdzane i dołączane są wszystkie moduły wyspecyfikowane w deklaracji USES oraz dołączane dyrektywą I kompilatora (*.OBJ). Jeśli moduły te były modyfikowane od poprzednich kompilacji to są ponownie kompilowane. MAKE uaktualnia wszystkie zbiory od których zależy moduł lub program kompilowany.
Polecenie Build działa podobnie jak MAKE z tym, że ponownie kompilowane są wszystkie zbiory.
W systemie Turbo Pascal występują dwa rodzaje zbiorów z modułami:
zbiory .TPU (Turbo Pascal Unit), do których wprowadzane są skompilowane moduły, przy czym każdy z tych zbiorów może zawierać tylko jeden moduł;
zbiór .TPL (Turbo Pascal Library), który może zawierać wiele modułów i w którym standardowo znajdują się moduły Crt, Dos, Overlay, Printer i System.
Za pomocą programu TPUMOVER można moduły TPU przenosić do zbioru TPL, a także pomiędzy zbiorami TPL.
Dyrektywa I dołącza zbiór źródłowy z katalogu bieżącego, katalogu określonego w opcji Directories/Include Directories lub podanego przed nazwą zbioru dołączanego.
{$I nazwa_zbioru}
Przykład
Dołączanie procedury w kodzie źródłowym:
procedure VGAinit;
var błąd, sterownik, tryb: Integer;
begin
DetectGraph(sterownik,tryb);
InitGraph(sterownik, tryb,'');
błąd:=GraphResult;
if błąd<>grOK then
begin
Writeln(`Błąd trybu graficznego: `, GraphErrorMsg(błąd));
Halt(1);
end;
end;
Dołączenie w programie głównym:
program ALFA;
uses Graph;
var ........
{$I VGAInit.PAS}
begin
VGAInit;
Dyrektywa L dołącza zbiór zawierający półskompilowany program w języku assembler. Zbiór ma rozszerzenie OBJ i jest szukany w katalogu bieżącym, wyspecyfikowanym w opcji Directories/Object Directories lub podanym przed nazwą zbioru.
Podprogram taki (funkcja lub procedura) powinny być zadeklarowane jako zewnętrzne np. deklaracja procedury i funkcji zewnętrznej ze zbioru AM.OBJ:
{$L AM}
procedure aproc ( n : Integer; var x : Real ); external;
function afun : char; external;
Przykład
Wykorzystanie funkcji i procedur standardowych z modułu CRT.
program okna;
uses Crt;
const okno : ARRAY[1..3] of ARRAY[1..7] of byte =((1,1,20,10,1,1,LightGray),(30,1,50,10,1,1,LightGray), (60,1,80,10,1,1,LightGray));
{ dla każdego okna określono w tablicy współrzędne okna X1, Y1, X2, Y2,
pozycje kursora w oknie X, Y
atrybut - razem siedem bajtów}
var
OrigMode: Word;
Ch: Char;
Koniec: Boolean;
nr_okna: byte;
procedure rysuj_okno(nr_okna:byte); {rysuje ramkę o współrzędnych (x1,y1) i (x2,y2)}
var i,k:byte;
begin
gotoxy(okno[nr_okna,1],okno[nr_okna,2]); {rysowanie pierwszej linii ramki}
write(#218);
for i:=(okno[nr_okna,1]+1) to (okno[nr_okna,3]-1) do write(#196);
writeln(#191);
for k:=(okno[nr_okna,2]+1) to (okno[nr_okna,4]-1) do {rysowanie środkowych linii ramki}
begin
gotoxy(okno[nr_okna,1],k);
write(#179);
for i:=(okno[nr_okna,1]+1) to (okno[nr_okna,3]-1) do write(#32);
write(#179);
end;
gotoxy(okno[nr_okna,1],okno[nr_okna,4]); {rysowanie ostatniej linii ramki}
write(#192);
for i:=(okno[nr_okna,1]+1) to (okno[nr_okna,3]-1) do write(#196);
write(#217);
end;
procedure Inicjalizacja;
begin
OrigMode:=LastMode; { Zapamiętanie oryginalnego trybu video }
GoToXY(1,24); { Wyświetlenie menu pomocy }
TextBackground(Black);
TextColor(LightGray);
Write('Ins-Wstaw_linie ',
'Del-Kasuj_linie ',
#27#24#25#26'-Kursor ',
'TAB-zmiana_okna ',
'Esc-Exit'#13#10,
'F1-jasny ',
'F2-migajacy ',
'F3-podkreslony (tylko dla MONO)');
for nr_okna:=1 to 3 do
begin
rysuj_okno(nr_okna);
end;
end; { Inicjalizacja }
procedure zmiana_okna;
begin
okno[nr_okna,5]:=whereX;
okno[nr_okna,6]:=whereY;
nr_okna:=nr_okna mod 3 + 1;
window(okno[nr_okna,1]+1,okno[nr_okna,2]+1,okno[nr_okna,3]-1,okno[nr_okna,4]-1);
GotoXY(okno[nr_okna,5],okno[nr_okna,6]);
TextAttr:=okno[nr_okna,7];
end;
procedure Jasny;
begin
TextAttr:=TextAttr xor 8;
okno[nr_okna,7]:=TextAttr;
end;
procedure Migajacy;
begin
TextAttr:=TextAttr xor 128;
okno[nr_okna,7]:=TextAttr;
end;
procedure Podkreslony;
begin
if LastMode=Mono then
begin
TextAttr:=TextAttr xor 6;
okno[nr_okna,7]:=TextAttr;
end;
end;
begin {program główny}
clrscr;
Inicjalizacja;
Koniec:=False;
nr_okna:=1; {ustawienie numeru okna początkowego}
window(okno[nr_okna,1]+1,okno[nr_okna,2]+1,okno[nr_okna,3]-1,okno[nr_okna,4]-1);
repeat
Ch:=ReadKey;
case Ch of
#0: { klawisze funkcyjne }
begin
Ch:=ReadKey;
case Ch of
#59: Jasny; { F1 }
#60: Migajacy; { F2 }
#61: Podkreslony; { F3 }
#72: GotoXY(WhereX,WhereY-1); { Up }
#75: GotoXY(WhereX-1,WhereY); { Left }
#77: GotoXY(WhereX+1,WhereY); { Right }
#80: GotoXY(WhereX,WhereY+1); { Down }
#82: InsLine; { Ins }
#83: DelLine; { Del }
end;
end;
#9: Zmiana_Okna; { TAB }
#13: WriteLn; { Enter }
#27: Koniec:=True; { Esc }
else
Write(Ch);
end;
until Koniec;
TextMode(OrigMode);
end.