Példa:
x := 2 * ( x + y ) + sin(alfa);A kifejezés kiértékelése során előálló érték kerül a változó címére a memóriába. A kifejezések formálisan operandusokból, műveleti jelekből (operátorok) és kerek zárójeleből épülnek fel. Operandusok konstansok (pl. 2, 'szöveg'), változók (pl. x, alfa) és függvényhívások (pl. sin(alfa)) lehetnek.
Read(v1 [,v2...])
ReadLn(v1 [,v2...])
A változók numerikus, karaktes és string (karakterlánc) típusúak lehetnek.
A részletesebb leírást ld. szöveges állományok.
Példa:
ReadLn(fizetes);A program ennél a sornál megáll, a leütött karakterek a képernyőn is megjelennek, és az Enter leütéséig szerkeszthetők. Majd a változóba bekerül a megfelelő típusú érték. Ha a beírtak nem felelnek meg a változó típusának, akkor a program futási hibával leáll (I/O hiba lép fel).
Karakteres, karakterlánc típusú változók olvasásakor a Read használata kellemetlen félreértéseket okozhat, használjuk a ReadLn eljárást. A Read eljárás a billentyűzet pufferból kiolvassa a változónak megfelelő értéket, de nem törli a puffert, míg a ReadLn eljárás olvasás után törli a puffert. Próbáljuk ki a következő programrészletet:
Read(a); Read(b); Read(c); WriteLn(a); WriteLn(b); WriteLn(c);
Write(k1 [,k2...])
WriteLn(k1 [,k2...])
Az eljárások az aktuális pozíciótól kezdődően kiírják a kifejezések
értékeit. A WriteLn eljárás ezután sort emel. A kifejezések numerikus,
karaktes és string (karakterlánc) és logikai típusúak lehetnek. A kiírást
módosíthatjuk, mezőszélességet illetve valós kifejezés esetén a tizedesjegyek
számát adhatjuk meg: Write(k[:MezSzel[:Tized]]). A mezőben jobbra igazítva,
illetve a megfelelő számú tizedesjegyre kerekítva jelenik meg a kifejezés
értéke.
Példa:
Write('A dolgozó fizetése: ', fizetes:10);
A PROGRAM fenntartott szó után
álló azonosító lesz a programunk neve.
Ez célszerűen megegyezhet a forrásprogram,
a lemezen tárolt PAS kiterjesztésű állomány nevével. Mindez elhagyható,
de használata jaánlott.
A USES kulcsszó után a programunk
által használt egységeket soroljuk fel. A
System egység, amely a leggyakrabban használt deklarációkat - konstansokat,
változókat, eljárásokat, függvényeket - tartalmazza automatikusan hozzászerkesztődik
a programunkhoz.
A későbbiek során részletesebben tárgyaljuk a deklarációs rész egyes
elemeit.
A Var kulcsszó után álló változódeklarációs szakaszban a programblokkban
használt összes változót fel kell sorolni, és típusát megadni. A típusmegadás
történhet áttételesen is, a Type utáni típusdeklaráció segítségével
(ld. tömb).
A konstansok használata programozói
munkánkat könnyítheti meg (Const).
Címkék igen ritkán fordulnak elő egy
Pascal programban (Label).
A Pascal szabad formátumú nyelv, azaz több utasítás is szerepelhet egy
sorban vagy akár egy utasítást több sorra is tördelhetünk. Célszerű a program
olvashatóságára, áttekinthetőségére törekedni. Az egyes utasításokat ;
-vel választjuk el egymástól. (Szemben pl. a C nyelvvel, ahol minden utasítás
végére ; -t kell írnunk.)
A Pascal nyelv nem különbözteti meg a kis és nagy betűket (szemben
a C nyelvvel).
Programunkban korlátlan hosszúságú megjegyzést
helyezhetünk el a { ... } illetve a (* ... *) jelek között.
A program szövegében használhatunk:
Típus |
|
|
Byte |
|
|
ShortInt |
|
|
Word |
|
|
Integer |
|
|
LongInt |
|
|
b. Egész típusú konstans
Decimális egészek, pl. 25, -123
Hexadecimális egészek, pl. $33, -$A2D6
c. Végezhető műveletek
Az eredmény is egész típusú:
+,- (előjel), *, +, -
div egész osztás, pl. 13 div 3 = 4
mod maradékképzés, pl. 13 mod 3 = 1
not bitenkénti negálás, pl not 28 = -29 ; (not 00011100 = 11100011)
and bitenkénti és, pl. 5 and 6 = 4; (00000101 and 00000110
= 00000100)
or bitenkénti vagy, pl. 5 or 6 = 7; (00000101 or 00000110
= 00000111)
xor bitenkénti kizáró vagy, pl. 5 xor 6 = 3; (00000101
and 00000110 = 00000011)
shl bitenkénti eltolás balra, pl. 5 shl 3= 40; (00000101 shl
3 = 00101000)
shr bitenkénti eltolás jobbra, pl. 5 shr 2= 1; (00000101 shr
2= 00000001)
Az eredmény kivezet az egész számok köréből:
/ az eredmény mindig valós (6/2-t már nem egész számként kezeli a rendszer)
<, >, <=, >=, =, <> relációs műveletek, az eredmény logikai
típusú
in halmaz elemvizsgálat, logikai eredmény (ld. halmaz
adattípus)
d. Fontosabb szabványos eljárások, függvények
Függvények: Abs, Sqr,
Trunc, Round,
Ord, Pred, Succ,
Random.
Eljárások: Inc, Dec,
Str, Val, Randomize.
Megj.
A függvények mindig egy értéket állítanak elő (visszatérési érték),
kifejezésekben hívhatjuk meg őket, pl. egy értékadó utasítás jobb oldalán;
a := Abs(a) + 2 . A függvények paraméteri kifejezések lehetnek, pl. Sqr(a
+ Round(x)).
Az eljárásokat utasításszerűen hívjuk, pl. Inc(i).
A Turbo Pascalban a következő valós típusokat definiálták: Real (6 byte),
Single (4 byte), Double (8 byte), Extended (10 byte), Comp (8 byte), azonban
a Real típus kivételével mindegyik használatához matematikai társprocesszorra,
vagy annak emulálására van szükség.
A Real típus ábrázolása 6 bájton, lebegőpontosan
történik. Az értéktartomány:
Smin = 2,9*10-39
Smax = 1,7*1038
A pontosság 11-12 decimális számjegy. (Ennyi értékes számjegye egy valós számnak, a többi jegyet nem ábrázolja a rendszer, pl. a 1234567890,1234567 számból a színes jegyek elvesznek.)
b. Konstansok
Pl. 5.12, -123.2313, 12.54E6, 21.12E-5
c. Műveletek
Az eredmény is valós típusú: +,- (előjel), *, /, +, -
Az eredmény logikai típusú: <, >, <=, >=, =, <>
d. Fontosabb szabványos eljárások, függvények
Függvények: Abs, Sqr,
Sqrt, Sin, Cos,
ArcTan, Exp,
Ln, Int, Frac,
Random, Round,
Trunc, Pi
Eljárások: Str, Val,
Randomize
Egy bájtos típus, tehát 28 = 256 különböző érték , az ASCII kódrendszer 256 elemének a tárolására képes. A karakter típusú változó egy ASCII kódot tartalmaz. Pl. ha a változóhoz tartozó memóriarekesz értéke 65, akkor mivel változónk típusa Char, ezt a rendszer 'A' betűként értelmezi.
b. Konstansok
Formája: 'A', '*', '4', #65 (ez utóbbi a 65-ös ASCII kodú karaktert,
azaz 'A'-t jelenti).
Lehetnek: betűk, számjegyek, írásjelek, speciális karakterek (pl. '@',
'#', '$', ...), vezérlő karakterek (pl. a gyakran használt #27 - Escape),
egyéb karakterek (az ASCII kódtábla 128-255 része, pl. 'é').
c. Műveletek
Relációs műveletek: <, >, <=, >=, =, <> (az eredmény természetesen
logikai típusú, a karakter ASCII kódja határozza meg. Pl. 'A' < 'B'
igaz, 'A' = 'a' hamis.)
in halmaz elemvizsgálat, logikai eredmény (ld. halmaz
adattípus)
d. Fontosabb szabványos eljárások, függvények
Függvények: Ord, Chr, UpCase, Pred, Succ
Eljárások: Inc, Dec
Egy logikai típusú változó két értéket vehet fel: igaz vagy hamis. Ábrázolására egy bájton történik (akár egy bit is elég lenne). Ha a bájt értéke 0, akkor a logikai típusúként értelmezett érték hamis, nullától eltérő érték esetén pedig igaz.
b. Konstansok
Két előredefiniált konstans: True (igaz), False (hamis)
c. Műveletek
Az eddig tanult típusokra értelmezett relációs operátorok (valamint az in halmazművelet) mindig logikai értéket állítanak elő.
Logikai műveletek: not, and, or, xor (az
operandusok logikai típusúak). A műveletek igazságtáblái:
|
|
|
|
||||||||||
|
|
|
|
|
|
|
|
|
|
|
|||
|
|
|
|
|
|
|
|
|
|
|
|||
|
|
|
|
|
|
|
|
|
|
|
|||
|
|
|
|
|
|
|
|
|
|||||
|
|
|
|
|
|
|
|
|
d. Logikai értéket előállító függvények
Odd, Eof, Eoln
A típus megadásakor fel kell sorolnom a lehetséges értékeit. Ezek csak
azonosítók lehetnek.
A konstansok a felsorolás sorrendjében sorszámot kapnak 0-tól kezdődően.
Tarolás a konstansok számától függően 1 vagy 2 bájton történik.
Pl.
var tantargy: (magyar, matek, fizika, tesi);
...
tantargy := matek;
b. Konstansok
Konstansai a felsorolásban szereplő azonosítók.
c. Műveletek
Relációs műveletek:<, >, <=, >=, =, <> (az eredmény természetesen
logikai típusú, a felsorolt típusú érték sorszáma határozza meg. Példánkban:
matek < tesi igaz.)
in halmaz elemvizsgálat, logikai eredmény (ld. halmaz
adattípus)
d. Függvények, eljárások
A sorszámozás alapján értelmezhetőek az alábbi
függvények:Ord, Pred, Succ;
eljárások: Inc, Dec.
Pl.
var nap: (hetfo, kedd, szerda, csutortok, pentek, szombat, vasarnap); {felsorolt típus} munkanap: hetfo..pentek; betu: 'A'..'Z'; szamjegy: '0'..'9';A felsorolt típus használata a program tesztelésekor hasznos lehet. (A fenti példában szamjegy := 'e' fordítási hibát, szamjegy beolvasásakor az 'e' karakter pedig futási hibát eredményez ($R+ fordítási direktíva esetén).)
A Pascal nyelv három ciklust definiál: két feltételes ciklust valamint egy előírt lépésszámú (más néven számláló vagy léptető) ciklust.
WHILE feltétel DO utasítás
Kezdőfeltételes ciklus. Amíg a feltétel igaz, addig ismétli az utasítást, ha hamis, akkor a program következő utasítására ugrik. A feltétel egy logikai (boolean) kifejezés. Ha több utasítás szerepel a ciklus magjában, akkor Begin - End ún. utasítás zárójelet kell alkalmaznunk. Ha a feltétel már először sem teljesül, akkor a ciklusmag egyszer sem kerül végrehajtásra (üres ciklus), ha pedig a feltétel soha nem vesz fel hamis értéket, akkor a program végtelen ciklusba kerül.
Tipikus használata: a ciklus végrehajtása attól függ, hogy van-e még feldolgozandó adat, az ismétlések számát előre nem ismerjük, akár 0 is lehet.
Példa: Képezzük a billentyűzetről érkező pozitív számok összegét,
a számsorozat végét a 0 vagy egy negatív szám jelezze.
Megoldás
Az ilyen típusú feladatok általános megoldási sémája:
- az első adat előállítása (pl. beolvasása)
- ciklusfej
- az adat feldolgozása
- a következő adat előállítása (pl. beolvasása)
- ciklus vége
REPEAT [utasítás [; utasítás...]] UNTIL feltétel
Végfeltételes ciklus. Az utasítás(ok) végrehajtását meg kell ismételni,
ha a feltétel hamis. Ha a feltétel igaz, a program a ciklus utáni utasítással
folytatódik.
A ciklusmag legalább egyszer végrehajtódik. A ciklusmagot a Repeat
- Until kulcsszavak fogják közre, nem kell Begin - End
utasítás zárójelet használnunk.
A While és a Repeat ciklust hasonló típusú feladatok megoldására használhatjuk. Esetleg az egyik egy kicsit kényelmesebb megoldást nyújt.
Az előző fejezet (5.1.1) példájának megoldása Repeat-Until ciklus alkalmazásával.
FOR ciklusváltozó := kezdőérték TO / DOWNTO végérték DO utasítás
ahol a ciklusváltozó sorszámozott típusú
változó hivatkozás, a kezdőérték és a végérték pedig sorszámozott
típusú kifejezések.
A ciklusváltozó a kezdőértéktől a végértékig egyesével
nő (To) vagy csökken (DownTo). Az utasítás (vagy a
Begin - End utasítás zárójelek közé zárt utasításcsoport)
a ciklusváltozó minden értékénél végrehajtódik. Elöltesztelő ciklus, így
ha a kezdőérték > végérték (To esetén) vagy a kezdőérték
< végérték (DownTo esetén), akkor a ciklusmag egyszer
sem kerül végrehajtásra (üres ciklus).
A ciklusváltozó értékét a ciklusmagban felhasználhatjuk, de nem változtathatjuk
meg (egy elrettentő példa).
Tipikus használata: az ismétlések száma a ciklusba való belépés előtt már ismert vagy kiszámítható.
Példák:
1. Írjunk ki N darab csillagot a képernyőre!
Megoldás
2. Számoljuk ki N! értékét!
Megoldás
IF feltétel THEN utasítás1 [ELSE utasítás2]
ahol a feltétel egy logikai kifejezés.
Ha a feltétel igaz, akkor az utasítás1 hajtódik végre,
egyébként az utasítás2. Az Else ág elhagyható, ilyenkor az
utasítás1 kimarad, a program a következő utasítással folytatódik.
Egy ágon több utasítás is végrehajtható a Begin - End utasítás
zárójelek alkalmazásával. Vigyázzunk, az Else előtt a pontosvessző
szintaktikai hiba, mivel azzal lezárjuk a teljes If utasítást!
Példa:
ReadLn(Oszto); ReadLn(Osztando); if Oszto <> 0 then Hanyados := Osztando / Oszto else WriteLn('0-val való osztás, nincs értelmezve.');Akár az utasítás1 vagy az utasítás2 is lehet újabb If utasítás, és ezáltal többirányú elágazást is megvalósíthatunk.
CASE szelektor OF
állandó [..állandó] [,állandó[..állandó]...]
: utasítás;
[állandó [..állandó] [,állandó[..állandó]...]
: utasítás;
[ELSE utasítás]
END
ahol a szelektor egy sorszámozott típusú kifejezés. Abban az ágban lévő utasítás (vagy Begin - End közé zárt utasításcsoport) hajtódik végre, ahol a szelektor értéke megegyezik az egyik állandóval vagy beleesik az egyik megadott tartományba. Ha ez egyik esetre sem teljesül, akkor az Else ágra kerül a vezérlés. Ez utóbbi elhagyható.
ahol 1 <= maxhossz <= 255, ha elhagyjuk, maxhossz = 255. Dinamikus hosszúságú karaktersorozat: hossza futás közben változhat, elemei Char típusúak.
Karakterlánc konstans: 'aposztrófok közötti szöveg'
Hivatkozhatunk a karakterlánc egy elemére (amely Char típusú):
azonosító[index], pl. karlanc[5].
A karakterlánc típusú változó értékét megváltoztathatjuk értékadással,
valamint beolvasással. Értékét kiírathatjuk a képernyőre.
Pl. karlanc := 'hahó'
Műveletek:
+ összefűzés, pl. file_spec := utvonal + file_nev;
Relációs műveletek: <, >, <=, >=, =, <> (az eredmény természetesen
logikai típusú, az első nem egyenlő karakter ASCII kódja határozza meg.
Pl. 'ATTILA' < 'ALFONZ' hamis.)
Adatábrázolás:
A rendszer a karakterek ASCII kódját tárolja maxhossz+1 bájton. A karakterlánc 0. bájtja egy tartalmazza a karakterlánc hosszát, Ord(karlanc[0]) = Length(karlanc).
Szabványos függvények, eljárások:
Függvények: Length, Pos, Copy, Concat.
Eljárások: Str, Val, Delete, Insert.
Lehetőleg a string műveleteket és függvényeket használjuk a karakterláncok kezelésére, a karakterenkénti hozzáférést körültekintően végezzük. (Egy így fellépő hiba.)
Példa:
Olvassunk be egy modatot, és írjuk ki csupa nagybetűvel!
Megoldás
Deklarálása: ARRAY[indextípus [,indextípus...]] OF elemtípus
Pl.
vektor: array[1..10] of integer; {Tíz elemű egydimenziós tömb.}
matrix: array[1..5, 1..4] of integer; {5 sorból és 4 oszlopból álló
kétdimenziós tömb, mátrix, elemei integer típusúak.}
A tömb olyan adatcsoport, melynek elemei azonos típusúak, az elemek száma rögzített (statikus méretű), sorrendjük kötött (indexelés), az elemekhez közvetlenül hozzáférhetünk. Meghatározása: név, dimenzió, elemeinek típusa, indexeinek típusa és tartománya.
Az indextípus csak sorszámozott típus lehet (kivéve Longint), többnyire
intervallum típus,
pl.
array[1..10] of real {általában egész típus intervalluma}
array['a'..'z'] of real {ritkábban karakteres típus intervalluma}
array[byte] of real {még ritkábban egy előre definiált típus}.
Többdimenziós tömbök: a tömb elemei maguk is tömbök,
pl.
m: array[1..10, 1..20] of integer,
vagy
m: array[1..10] of array[1..20] of integer.
A hivatkozás a tömb egy elemére az index segítségével történik,
pl.
vektor[3] {a vektor nevű tömb 3. eleme, Integer típusú},
matrix[2, 3] vagy matrix[2][3] {a matrix nevű kétdimenziós tömb 2.
sorának 3. eleme}.
Műveletek:
Két azonos típusú tömbre az értékadás és az egyenlőség vizsgálat megengedett. Egy vektor bemásolható a mátrix egy sorába (ld. tömb típus deklarálása).
A tömbökkel végzett műveletek során többnyire a for ciklust használjuk,
úgy hogy a ciklusváltozót végigléptetjük a tömb indextartományán.
Pl. egy a vektor nevű tömb beolvasása a billentyűzetről:
for i := 1 to 10 do begin Write('Kérem a tömb ',i,'. elemét: '); ReadLn(t[i]) end;Tömb típusú konstans:
Tömb konstanst csak a Const deklarációs
részben adhatunk meg tipizált konstansként.
Az elemeket zárójelben, vesszővel elválasztva kell felsorolnunk.
Pl.
const T1 : array[1..3, 1..4] of byte = ( (1, 3, 4, 1), (2, 3, 4, 2),
(1, 6, 3, 5) );
Adatábrázolás:
A rendszer a tömböt sorfolytonosan tárolja a memóriában. A foglalt terület az elemek száma szorozva egy elem méretével.
Tömb típusú változók használatakor célszerű először a Type
típusdeklerációs részben a megfelelő típusokat deklarálni, majd ezeket
a saját típusainkat használhatjuk a változók deklarálásakor (a Var után).
A Pascal nyelv logikája ezt az áttételes deklarálást támogatja, és bizonyos
esetekben ez nem is kerülhető meg (ld. alprogramok).
Pl.
type VektorTip = array[1..4] of integer; MatrixTip = array[1..5] of VektorTip; var v1, v2: VektorTip; m1, m2: MatrixTip;A fenti példában elvégezhető a következő értékadás: pl. m1[2] := v1.
Példák:
1. Töltsünk fel egy 10 elemű integer tömböt. Számítsuk ki az
elemek számtani átlagát.
Megoldás
2. Állítsuk elő a Fibonacci sorozat (1, 1, 2, 3, 5, 8, 13...)
első 20 elemét.
Megoldás
Deklarálása:
Deklarálásakor a Record és End kulcsszavak között fel kell sorolnunk az egyes mezők neveit valamint típusait. A rekord tartalmazhat egy változó részt is, amely a fix rész egy mezőjétől (szelektor mező) függően más-más adatokat tartalmazhat.
RECORD
[mezőlista;]
[CASE szelektormező: sorszámozott típus OF
állandók: (mezőlista)
[állandók: (mezőlista)...]]
END
ahol mezőlista:
mezőazonosító [,mezőazonosító...]: típus
[;mezőazonosító [,mezőazonosító...]:
típus...]
Példák:
1. type DolgozoTip = record Nev: string; Hazas: boolean; Fizetes: longint; end; var Dolgozok: array[1..50]of DolgozoTip; d1, d2: DolgozoTip; 2. type RekTip = record Nev: string[50]; Lakohely: string[50] case Nagykoru: boolean of True: (Gyerek_Szam: byte); False: (Anyja_Neve: string[50]; Apja_Neve: string[50]); end;Hivatkozás a rekord egy mezőjére:
A With utasítás
Ha egy programrészletben gyakran hivatkozunk egy (vagy több) rekord mezőire, akkor a With utasítással ez leegyszerűsíthető, a rekordazonosító elhagyható.
Szintaktikája: WITH rekordazonosító [, rekordazonosító]
DO utasítás
Pl.
with d1 do begin ReadLn(Nev); ReadLn(Fizetes) end;Ha több rekordazonosítót sorolunk fel, akkor az utolsónak a legnagyobb a prioritása.
Rekord típusú konstans:
Hasonlóan a tömb konstanshoz csak tipizált konstans
kezdőértékeként adhatjuk meg a Const
deklarációs részben.
Pl.
const Origo: record x, y: integer; end = (x: 320; y: 240);Adatábrázolás:
A memóriában elfoglalt hely egyszerűen a mezők helyfoglalásának az összege (fix rész + legnagyobb változó rész).
Deklarálása: SET OF alaptípus
ahol az alaptípus csak olyan sorszámozott típus lehet, amelynek maximálisan 256 eleme van.
Halmaz típusú konstans:
Szögletes zárójelben a halmaz elemeit (az alaptípussal megegyező típusú
konstansokat) vagy azok intervallumait felsoroljuk.
Pl.
const Betuk = ['A'..'Z', 'a'..'z'];
H1 := [1, 4, 6, 8..12]
H2 := [] {üres halmaz}
A programunkban egy halmaznak a halmaz konstanstól egy kicsit különböző
halmazkonstruktorral is értéket adhatunk. Itt a szögletes zárójelben
felsorolt kifejezések változókat is tartalmazhatnak.
Pl.
k := '?';
H := [k, '!','.'];
Műveletek:
* metszet
+ egyesítés
- különbség
Logikai típusú eredményt szolgáltatnak:
= egyenlőség
<> különbözőség
<=, >= tartalmazás (részhalmaz)
IN elemvizsgálat (a következő példában a
Char típusnál látott programot pontosítjuk a segítségével)
Adatábrázolás:
Egy lehetséges halmazelemnek egy bit felel meg a memóriában. Ha az lehetséges elem benne van a halmazban, akkor a bit 1, ellenkező esetben 0. Gyakran az első és az utolsó bájt olyan biteket is tartalmazhat, amelyek nem vesznek részt a tárolásban.
Példa:
A halmazokat gyakran használjuk arra, hogy menüből való választás esetén
programunk csak a megfelelő billentyűkre reagáljon. Egy
menü váza.
Hasonló a programéhoz.
Eljárás fej: | PROCEDURE azonosító [ ( formális paraméter lista ) ]; |
Deklarációs rész:
|
Label...
Const... Type... Var... Procedure... Function... |
Végrehajtandó rész: | Begin
utasítások End; |
Például:
procedure Teglalap(a, b: integer; var t, k: integer); begin t := a * b; k := 2 * (a + b) end;b, Az eljárás hívása:
azonosító [ (aktuális paraméter lista)]
ahol az aktuális paraméter lista elemei kifejezések vagy változók lehetnek (ld. paraméterátadás) egymástól vesszővel elválasztva.
Pl. Teglalap(5, 4, Ter, Ker)
c, Az eljárások hatásköre:
A Pascal nyelv befelé struktúrált, az alprogramokat egymásba ágyazhatjuk
(az alprogram deklarációs részében is lehet alprogram). Ezért fontos tisztán
látnunk, hogy hogy a főprogramból illetve egy alprogramból mely eljárásokat
hívhatjuk meg:
- A program illetve egy eljárás meghívhatja (ismeri) azokat az alprogramokat,
melyeket a program vagy az adott alprogram deklarációs részében deklaráltunk,
de azok alprogramjait már nem.
- Egy alprogram meghívhatja az ugyanazon deklarációs részben (, ahol
őt deklaráltuk) korábban deklarált alprogramokat.
- Egy alprogram meghívhatja az őt tartalmazó eljárásokat.
- Egy alprogram meghívhatja saját magát.
Nézzük a fenti eseteket egy példán keresztül.
d, Paraméterek:
A paraméterek az eljárás és az őt hívó programrész közötti adatcserét,
kommunikációt szolgálják. A formális paraméterekkel írjuk le az alprogram
tevékenységét. Híváskor ezek helyére konkrét objektumokat, aktuális paramétereket
írunk.
Az aktuális és a formális paramétereknek meg kell egyezniük számban,
sorrendben és típusban.
Vigyázzunk, hogy a formális paraméterek típusának megadásakor csak
típusazonosítót használhatunk, így pl. a következő eljárásfej hibás: procedure
elj (t: array[1..10] of real);
A paraméterátadás két féle módon történhet:
- Érték szerinti paraméter átadás (a deklarációban a formális paraméter előtt nincs Var)
Ekkor az aktuális paraméter értéke kerül át a formális paraméterbe.
Az eljárás minden egyes hívásakor a rendszer tárterületet rendel a verem
memóriában a formális paraméterekhez, és ide másolja be az aktuális paraméterek
értékeit. Az eljárás végeztével ez a terület felszabadul. Az aktuális paraméter
értékét az eljárás nem változtathatja meg, így ez csak bemenő paraméter.
Az aktuális paraméter kifejezés lehet.
- Cím szerinti paraméter átadás (a deklarációban a formális paraméter elé Var -t írunk)
Az aktuális paraméter címe kerül át a formális paraméterhez, ha változik
a formális paraméter, akkor változik az aktuális is. Ezáltal egyaránt használhatjuk
be- és kimenő paraméterként is.
Az aktuális paraméter csak változó lehet.
e, Lokális és globális változók
Egy eljárásban deklarált változókat ezen eljárás lokális változóinak nevezzük. Ezek a program más részein nem ismertek. (Így különbőző eljárásokban előfordulhatnak azonos nevű változók, amelyeknek azonban semmi közük egymáshoz.) A lokális változókhoz (az eljárás paramétereihez hasonlóan) a rendszer a veremben rendel tárterületet, dinamikus módon, azaz csak akkor van címe a változóknak, ha az eljáráson van a vezérlés. A lokális változók értéke az eljárás két hívása között elvész.
Egy eljárásra nézve globális változó egy őt tartalmazó eljárásban vagy a főprogramban deklarált változó. Ezt az eljárás ismeri, hacsak nem deklaráltunk egy vele azonos nevű lokális változót vagy az eljárásnak nincs egy vele azonos nevű paramétere. Ekkor a lokális változó "eltakarja" a globálisat. A globális változó értéke természetesen nem vész el. (Abban az esetben használhatunk egy a lokálissal azonos nevű globális változót, ha az a főprogram változója. Ekkor a program nevével kell minősítenünk a globális változót: programnév.változónév.)
Egy példa a lokális és globális változók értelmezésére.
f, Információ csere
Összefoglalva elmonhatjuk, hogy egy alprogram kétféle módon kommunikálhat
az őt hívó programegységgel,
- a paramétereken keresztül,
- a globális változók segítségével.
FUNCTION azonosító [ ( formális paraméter lista ) ]: típusazonosító;
ahol a típusazonosító csak csak sorszámozott, valós, karakterlánc vagy mutató lehet.
Pl.
function Tangens(Alfa: real): real; begin if cos(Alfa) <> 0 then Tangens := Sin(Alfa) / Cos(Alfa) end;
A rekurzió alkalmazásának egyik területe, amikor úgy oldunk meg egy
problémát, hogy visszavezetjük egy egyszerűbb esetre, majd ezt addig folytatjuk,
míg el nem jutunk a triviális esetig. A módszer a matematikai indukción
alapszik.
A megoldás lépései:
1. Megkeressük azt a legegyszerűbb esetet, ahol a megoldás már magától
értetődő - triviális eset. Ekkor áll le a rekurzív hívások sorozata.
2. Megvizsgáljuk, hogy ismételt egyszrűsítésekkel hogyan juthatunk
el a triviális esethez. (Az általános esetet visszavezetjük az eggyel egyszerűbbre.)
Példák:
1. Faktoriális számítás
- Triviális eset: 1! = 1
- Egyszerűsítés: N! = N*(N-1)!
Ezzel a problémát megoldottuk, már csak kódolnunk kell.
Megoldás
Megj.: Bár a feladat kitűnő példa a rekurzív algoritmusra, az iterációs
(ciklussal történő) megodás jobb, mivel az ismételt függvényhívások időigényesek.
2. Fibonacci sorozat (1, 1, 2, 3, 5, 8, 13...) N. eleme
- Triviális eset: az első és a második elem értéke 1.
- Egyszerűsítés: az N. elem az N-1 - edik és az N-2 - dik elemek összege.
Megoldás
Összetett típus, fizikailag egy lemezes állomány. Egyforma méretű elemekből
(komponensekből) áll. Az elemek számának csak a lemez mérete szab határt.
A típusos állományból való olvasás illetve az állományba való írás
egysége a komponens.
Az elemekhez a rendszer sorszámot rendel 0-tól kezdődően. Az elérés
szekvenciálisa (Read, Write)
vagy a komponensek sorszáma szerint direkt módon történhet (az állomány
mutató mozgatásával).
A program mindig egy logikai állományt kezel, melyet hozzá kell rendelnünk egy fizikai állományhoz (Assign), majd használat előtt meg kell nyitnunk. A Rewrite eljárás létrehozza, és megnyitja a logikai fájlhoz rendelt fizikai állomány. Ha a fizikai fájl már létezett, akkor törli annak tartalmát. A Reset eljárással egy már létező állományt nyithatunk meg. Ekkor az állománymutató az 0. komponensre áll. (Ezért ezt az eljárást használhatjuk egy nyitott állomány elejére való ugrásra is.) Használat után a Close eljárással zárjuk le fájlunkat!
A típusos állományból a Read eljárás olvas be változókba adatokat. Ügyeljünk arra, hogy a változó típusa egyezzen meg a fájl alaptípusával! Beolvasás után az állomány mutató automatikusan a következő komponensre lép (szekvenciális elérés). Egy változó (vagy kifejezés) értékét a Write eljárással írhatjuk ki egy fájlba. Hasonlóan az olvasáshoz a változó típusának meg kell egyeznie a fájl elemeinek a típusával, valamint az eljárás után az állomány mutató továbblép. Ha az állomány mutató a fájl végén (az utolsó elem mögött) áll, akkor az Eof függvény értéke True. Nézzünk egy példát a fájl szekvenciális feldolgozására:
Reset(f) while not Eof(f) do begin Read(f,v); {a v változóban lévő adat feldolgozása} end;Az állomány mutató direkt pozicionálását a Seek eljárás valósítja meg. A FilePos függvénnyel lekérdezhetjük az aktuális pozíciót, a FileSize függvény pedig az állomány elemeinek a számát (méretét) adja vissza. Példák a pozicionálásra.
Az I/O műveletek során nagy a hibalehetőség (pl. a lemezegység, fájl nem elérhető). Az esetleges futási hibákat tudnunk kell kezelni, ha megbízhatóan működő programot szeretnénk írni. Ha az I/O műveletek ellenőrzése aktív (ez az alapértelmezés), akkor programunk futási hibával leáll egy I/O hiba esetén. Ezért I/O műveletek ellenőrzését inaktívvá kell tennünk a {$I-} fordítási direktívával a kényes műveletek esetén. A művelet után az esetleges hiba kódját az IOResult függvénnyel kérdezhetjük le. Erre egy példa:
Assign(f, 'adatok.dat'); {$I-} Reset(f); {megpróbáljuk megnyitni a fájlt} {$I+} if IOResult <> 0 then {ha hiba történt, tehát a fájl nem létezik, } Rewrite(f); {akkor létrehozzuk az állományt}A Truncate eljárással levághatjuk a fájl komponenseit az aktuális pozíciótól kezdődően.
Lezárt állományokra használhatjuk a Rename valamint az Erase eljárásokat a fájlok átnevezésére illetve törlésére.
Példa:
1. A program egy bolt árucikkeinek adatait (név, kód, ár) tárolja és
kezeli egy állományban.
Megoldás
A Pascal programban szöveges állományként kezelhetjük az egyszerű ASCII
szövegeket. (Például a .pas kiterjesztésű forrásprogramjainkat.) A szöveges
állomány változó hosszúságú sorokból áll, melyeket a sorvégjel zár le (CR/LF).
Az állományt az állományvégjel zárja(^Z). Az Eoln
illetve az Eof függvény értéke True,
ha az aktuális pozíció egy sorvégjelen vagy az állomány végén áll. A SeekEoln
illetve a SeekEof függvények az állomány
következő TAB szóköz illetve TAB szóköz és sorvégjel karaktereit átugorva
tájékoztatnak arról, hogy sorvégjelen illetve az állomány végén állunk-e.
A szöveges állományt csak szekvenciálisan érhetjük el. Az állomány
csak olvasásra vagy csak írásra lehet megnyitni. Az állományból olvasni
a Read, ReadLn, illetve írni a Write,
Writeln eljárásokkal tudunk. Ha az eljárásoknak a fájl azonosító
paraméterét elhagyjuk, akkor az olvasás / írás az alapértelmezett input
/ output szöveges állományból / -ba történik, ami a billentyűzet illetve
a monitor. Szöveges állományból (azaz a billentyűzetről is) olvashatunk
egész, valós, karakteres és sztring típusú változokba adatokat. Az állományba
az előbbi típusokon kívül még logikai értéket is kiírathatunk.
Az fizikai állományhoz az Assign eljárással
rendelhetünk egy Text típusú változót, azaz a logikai állományt. A Rewrite
eljárás csak írásra nyitja meg a szöveges állományt, ha nem létezett
létrehozza, egyébként törli a tartalmát. A Reset
eljárással csak olvasásra nyithatunk meg egy már létező fájlt. Az
Append eljárás egy létező állományt nyit meg
írásra, és az állománymutató a fájl végére állítja. Az állományt a Close
eljárással zárhatjuk be.
Az I/O műveletek hibakódját az IOResult függvény
adja vissza (bővebben ld. Típusos állományok).
Lezárt állományokra használhatjuk a Rename
valamint az Erase eljárásokat a fájlok átnevezésére
illetve törlésére.
A Fluss és a SetTextBuf
eljárásokkal az írás, olvasás során a rendszer által használt átmeneti
tárolóhoz (pufferhez) férhetünk hozzá.
Példa:
1. A doga.txt állományban egy feladatsor van, kérdések és válaszok
felváltva egymás után. Minden kérdés illetve válasz új sorban kezdődik.
A kérdések egy számjeggyel kezdődnek, és kérdőjellel fejeződnek be. Készítsünk
két új szöveges állományt úgy, hogy az egyik csak a kérdéseket, a másik
pedig csak a válaszokat tartalmazza.
Megoldás
Általában gyors adatmozgatás vagy ismeretlen állomány esetén használjuk. Hasonló a típusos állományhoz, de az elemeinek nem a típusa, hanem a hossza a lényeges. A komponensek hosszát a fájl megnyitásakor adhatjuk meg (Reset, Rewrite), az alapértelmezés 128 bájt. Az állomány írható, olvasható, az elérés szekvenciálisan (BlockRead, BlockWrite eljárásokkal) vagy az elemek sorszáma szerint direkt módon történhet.
További függvények, eljárások: Assign, Close, Eof, Erase, FilePos, FileSize, IOResult, Rename, Seek, Truncate
Példa:
1. Tördeljünk szét egy állományt egy kilobájt hosszúságú kisebb állományokra!
Megoldás
Színek:
A karakteres képernyő tartalma megtalálható az ún. képernyő memóriában. Itt egy karaktert két bájton tárol el a rendszer, melyek a karakter ASCII kódja (1 bájt) valamint a karakter attribútuma (1 bájt). Ez utóbbi a színinformációt hordozza, az alábbi módon:
A 0.-3. bit a karakter tintaszínét határozza meg, R, G, B az additív
színkeverés három alapszíne, I pedig az intenzitás. Például 0100 - piros,
1100 - világospiros, 0101 - lila. A 4.-6. bitek a karakter háttérszínét
kódolják. Ha a 7. bit (V) egyes, akkor a karakter villog.
A fentiekből következik, hogy összesen 16 tinta- és 8 háttérszínt használhatunk.
A színek kódjait könnyen kiszámolhatjuk, ezeket a megfelelő eljárásokban
használhatjuk, de a könnyebb megjegyezhetőség kedvéért a Crt unit az alábbi
szín konstansokat definiálja.
Tinta- és háttérszínek: | További tintaszínek: | ||||
Balck |
|
Fekete | DarkGray |
|
Sötétszürke |
Blue |
|
Kék | LightBlue |
|
Világoskék |
Green |
|
Zöld | LightGreen |
|
Világoszöld |
Cyan |
|
Türkiz | LightCyan |
|
Világostürkiz |
Red |
|
Piros | LightRed |
|
Világospiros |
Magenta |
|
Lila | LightMagenta |
|
Világoslila |
Brown |
|
Barna | Yellow |
|
Sárga |
LightGray |
|
Világosszürke | White |
|
Fehér |
Pl: TextColor(Lightred+Blink), ezzel egyenértékű: TextColor(12 + 128) vagy TextColor(140).
Fontosabb eljárások, függvények:
Képernyőkezelés:
Függvények: WhereX, WhereY
Eljárások: TextBackground, TextColor, ClrScr,
CrlEol, DelLine, InsLine, GotoXY, Window, NormVideo, TextMode
Billentyűzetkezelés:
Függvények: KeyPressed, ReadKey
Hang, késleltetés:
Eljárások: Sound, Delay, NoSound
Példa:
1. Mozgassunk egy téglalapot (egy kis képernyőt) benne egy szöveggel
a képenyőn a kurzormozgató billentyűk segítségével!
Megoldás
Az egység fontosabb eljárásai, függvényei, típusai, konstansai:
A grafikus képrnyő inicializálása (átkapcsolás karakteres képernyőről
grafikusra), bezárása:
Eljárások: InitGraph, DetectGraph, CloseGraph,
stb.
Függvények: GraphResult, stb.
Konstansok: grafikus meghajtók (Pl. Detect = 0, CGA = 1 stb.); grafikus
üzemmódok (pl. VGALo, VGAMed, VGAHi stb.)
Pl.:
uses Graph; var Meghajto, Uzemmod: integer; begin Meghajto := Detect; {Automatikusan beállítja grafikus üzemmódot a legnagyobb felbontással.} InitGraph(Meghajto, Uzemmod, 'C:\TP70\BGI'); {Inicializálás} If GraphResult <> 0 then begin WriteLn('Grafikus hiba!'); {Nem sikerült az inicializálás, kilépés a programból} ReadLn; Halt end; ...{Grafika használata} CloseGraph {Grafikus képernyő bezárása} endSzínek:
Rajz:
Típusok: LineSettingsType (ld. GetLineSettings),
stb.
Konstansok: vonalstílus (pl. SolidLn, DottedLn, stb. ld. SetLineStyle),
vonalvastagság ( NormWidth. ThickWidth ld. ld. SetLineStyle),
rajzolási mód (pl. CopyPut, XorPut, stb. ld. SetWritMode)
Eljárások: PutPixel, Line, LineTo, LineRel, Circle,
Rectangle,SetLineStyle,GetLineSettings, SetWriteMode, stb.
Kitöltött rajz:
Típusok: FillSettingsType (ld. GetFillSettings),
stb.
Konstansok: kitöltési stílus (pl. SolidFill, LineFill, stb. ld. SetFillStyle)
Eljárások: Bar, Bar3D, FillEllipse, FloodFill,
SetFillStyle, GetFillSettings, stb.
Szöveg:
Típusok: TextSettingsType (ld. GetTextSettings),
stb.
Konstansok: betűtípus, szövegállás, szövegigazítás
Eljárások: OutText, OutTextXY, SetTextStyle,
GetTextSettings stb.
Kurzor:
Függvények: GetX, GetY, stb.
Eljárások: MoveTo, MoveRel, stb.
Egyéb:
Kép mentése egy változóba, visszatöltése: ImageSize,
GetImage, PutImage.
Példa:
1. Kérjük be grafikus képernyőn egy parabola és egy egyenes egyenletét.
Ábrázoljuk a görbéket, és metszéspontjaikat határozzuk meg grafikusan valamint
analitikusan. A program tegye lehetővé, hogy a le- ill. felfele nyíllal
Y irányban mozgathassuk az egyenest, a jobbra ill. balra nyíllal a meredekségét
változtathassuk, a PgUp ill. PgDn billentyűkkel pedig a koordinátarendszer
méretarányát (képpont/egység) változtathassuk.
Megoldás
Pl. Var p1, p2: ^real;
A mutató egy memóriacímet (4 bájtos: szegmens, ofszet) tartalmaz, egy
alaptípusú változóra mutat. A mutatóhoz futás közben rendelhetünk
memóriacímet és így tárterületet (dinamikus adattárolás).
A New eljárás a heap
memóriában foglalterületet a mutatott változó számára, a Dispose
eljárás pedig felszabadítja a lefoglalt területet. Így lehetővé válik,
hogy egy nagy helyfoglalású adatstruktúra számára csak akkor kössünk le
memóriát, amikor használjuk a változót. Nézzünk erre egy példát:
type TTomb = array[1..1000]of real; var t: TTomb; {A rendszer már a program idításakor lefoglal 6000 bájtot az adatszegmensben} pt: ^TTomb;{A rendszer a program idításakor csak 4 bájtot foglal le a mutató számára} begin ... New(pt); {A heap-ben létrejön a mutatott változó} ... {Használhatom a pt által mutatott változót (pt^)} Dispose(pt) {A terület felszabadul a heap-ben} end.A mutatót ráirányíthatjuk egy az alaptípusával megegyező típusú változóra a @ operátorral vagy az Addr függvénnyel. Pl. pt := @t; vagy pt := Addr(t).
Hivatkozás a mutatott változóra: mutató-azonosító^
(pl.: pt^[12] := 1)
Mutató típusú konstans: Nil.
A Nil nem mutat sehová. (Pl. láncolt lista végének a jelzésére használhatjuk).
Műveletek:
Címe: @
Egyenlőség vizsgálat: =, <>
További szabványos eljárások, függvények:
Eljárások: Mark, Release
Függvények: MaxAvail, MemAvail, Ofs, Seg
Láncolt listák
A különböző típusú láncolt listák nagyon fontos adatszerkezetek a számítástechnikában. Az egyes adatelemek (rekordok) közötti csatolást mutatókkal valósíthatjuk meg, így a rekordnak van egy mutató típusú mezője, melynek alaptípusa maga a rekord. Az alábbi példában figyeljük meg, hogy a mutató típus deklarálásánál olyan azonosítót használunk, amely a programunkban csak később szerepel. (A Pascal ebben az egy esetben engedi ezt meg.)
type Mutato = ^Adatelem; Adatelem = record Adat: real; Kovetkezo: Mutato; end; var Elso, Uj, Aktualis: Mutato;Példák:
Egy négy bájtos memóriacímet tartalmaz. A mutatott változónak nincs
típusa. A típusnélküli műveleteknél használjuk (pl. adatmozgatás).
A GetMem eljárással foglalhatunk le egy megadott méretű területet a
heap-ben a mutatónk számára. Ha a memóriaterületre már nincs szükségünk
a FreeMem eljárással azt felszabadíthatjuk.
A mutatót ráirányíthatjuk akármilyen címre vagy változóra a @ operátorral
vagy az Addr függvénnyel. Pl. p := @tomb1;
vagy p := Addr(tomb1).
A Ptr függvénnyel a mutatónak egy tetszőleges
memóriacímet adhatunk értékül.
Egy mutató értékadó utasítással egy másik mutató címét is felveheti.
A mutatott változóhoz rendelhetünk típust: típus(mutató-azonosító^).
Hivatkozás a mutatott változóra: mutató-azonosító^
Mutató típusú konstans: Nil.
Műveletek:
Címe: @
Egyenlőség vizsgálat: =, <>
További szabványos függvények: MaxAvail, MemAvail, Ofs, Seg
Példa:
1. Mentsünk el egy garfikát egy típus nélküli állományba, majd
olvassuk vissza!
Megoldás
PSP (Program Segment Prefix)
Az DOS hozza létre a program betöltésekor.
Kódszegmensek
A főprogramnak és minden unitnak van egy kódszegmense. A System egység
kódszegmense minden prograhoz automatikusan hozzászerkesztődik. Ezután
(fordított sorrendben) következnek a Uses kulcsszó után megadott unitok
kódszegmensei. Egy kódszegmens mérete legfeljebb 64 kB lehet. Nagy program
írásakor könnyen ütközhetünk ebbe a korlátba. Ekkor főprogramunk méretét
csökkenthetjük saját unitok készítésével,
melyeknek mérete természetesen külön-külön 64 kB lehet.
Adatszegmens
Programunknak egy adatszegmense van, amely tartalmazza a főprogram
és az összes unit globális deklarációit (típusos konstansok, változók).
Maximális mérete 64 kB lehet. Ha ez nem elegendő a heap memóriát (ld. mutatók)
vagy a verem memóriát (lokális változók) használhatjuk adataink tárolására.
Veremszegmens
LIFO (Last In First Out) szervezésű memória, az utolsónak beírt adatot
olvashatom ki belőle először. A renndszer itt tárolja az alprogramok visszatérési
címeit, paramétereit, lokális változóit. Méretét a $M fordítási
direktívával megadhatjuk, maximálisan 64kB.
Heap
Futás közben a heap-ben foglalhatunk le illetve szabadíthatunk fel
memóriát a mutatók számára. Alapértelmezés szerint a lefoglalja az egész
maradék memóriát. Méretét a $M fordítási direktívával korlátozhatjuk.
Az alábbi példa a képernyő 5. sorának 10. oszlopába kiír egy szines A betűt (ld CRT unit).
var sor, oszlop: byte; begin sor := 5; oszlop := 10; Mem[$B800:sor*160+oszlop*2] := Ord('A'); {$B800 a képernyőmemória kezdőcíme} Mem[$B800:sor*160+oszlop*2+1] := $14 {Kék háttéren piros betű} end.b, Az Absolute direktíva segítségével egy változóhoz közvetlenül rendelhetünk rendelhetünk memóriacímet a deklaráció során. Ez lehet egy abszolút memóriacím (szegmens:eltolás), vagy egy másik változó címe.
Az előző példa egy másik megoldása:
var kepernyo: array[1..25,1..80,1..2]of byte absolute $B800:0; begin kepernyo[5, 10, 1] := Ord('A'); kepernyo[5, 10, 2] := $14 end.Az alábbi példaprogram a beolvasott sztring hosszát írja ki:
uses Crt; var s: string; b: byte absolute s; begin ReadLn(s); WriteLn(b); {A sztring 1. (0. indexű) bájtját írja ki, mint egy egész számot} end.
Például az alábbi program a d és i integer változók (2-2 bájt) valamint az r rekord (2+2+6 bájt) együttes méretét (azaz 14-et) írja ki bájtokban:
uses Crt; var d: integer; r: record a, b: integer; x: real; end; i, j: integer; begin WriteLn(Ofs(j) - Ofs(d)); end.
A Dos egység további segítséget nyújt az állománykezeléshez, valamint a rendszerközeli programozáshoz. A teljesség igénye nélkül nézzünk néhány területet:
Állománykezelés
A FindFirst a paramétereiben meghatározott fájlok közül megkeresi az elsőt, és jellemzőit elhelyezi a (unit által definiált) SearchRec típusú paraméterében. A SearchRec deklarációja:
SearchRec = record Fill: array[1..21] of byte; {A DOS számára foglalt} Attr: byte; {Az állomány attribútuma} Time: longint; {Létrehozási idő (pakoltan)} Size: longint; {Az állomány mérete} Name: string[12]; {Az állomány neve} end;A FindNext az előzőleg FindFirst eljárással definiált fájlok közül a következőt keresi ki. Mint a Dos unit legtöbb eljárása, így ezen két eljárás is a DosError változóban adja vissza az információt a végrehajtás sikerességéről (értéke 0, ha talált állományt).
Megj.: További eljárások: FSplit, GetFAttr, SetFAttr; függvények: FExpand, FSearch.
Példa:
Írjunk programot, amely az aktuális könyvtár pas kiterjesztésű állományaiban
keres egy szót. A program írja ki, hogy mely állományok és ott mely sorokban
fordul elő a keresett szó!
Megoldás
A rendszerdátum és idő kezelése
A GetDate és a GetTime eljárásokkal az aktuális dátumot és időt kérdezhetjük le, míg a SetDate és SetTime eljárásokkal beállíthatjuk azokat. Például az aktuális idő kiírása:
uses Dos; var ora, perc, mperc, szazadmp: word; begin GetTime(ora, perc, mperc, szazadmp); WriteLn(ora,':',perc,':',mperc) end.Megj.: A GetFTime, SetFTime, PackTime, UnPackTime eljárások egy állomány utolsó módosításának az idejét kezelik. Ezen eljárások használják a unit által definiált DateTime típust.
Megszakítások kezelése
Az Intr eljárás meghívja a paramétereként megadott megszakítást. A megszakítás működését a mikroprocesszor regisztereinek a beállításával szabályozhatjuk, valamint a megszakítás eredményét a regiszterekben kapjuk vissza. A regiszterekhez való hozzáférést a unit által deklarált Registers típus segíti. Az alábbi programocska kiír 10 piros csillagot kék háttéren a képernyőre a képernyőkezelő $10 (hexadecimális 10) BIOS megszakítás segítségével:
uses Dos; var r: registers; begin r.ah := $9; {A megszakítás $9 funkciója (karakterek megjelenítése)} r.al := ord('*'); {A karakter kódja} r.bl := $14; {A karakter attribútuma (szín, háttérszín)} r.cx := 10; {Az ismétlések száma} Intr($10, r) {A 10h megszakítás hívása a fent beállított regiszterekkel} end.Megj.: Az MsDos eljárás a Dos függvényeket megvalósító $21 megszakítást hívja meg. A GetIntVec illetve SetIntVec eljárással egy megszakításvektort kérdezhetünk le illetve állíthatunk be.
Külső program indítása
Az Exec eljárással futtathatunk egy külső programot. A {$M} fordítási direktívával a heap felső határát le kell csökkenteni úgy, hogy a külső program beférjen a memóriába. Az eljárás előtt és után hívjuk meg a SwapVectors eljárást. Például:
{$M 16000, 0, 0} {A verem, a heap minimális és a heap maximális méretének beállítása} uses Crt, Dos; begin ClrScr; SwapVectors; Exec('c:\command.com', '/c dir *.pas'); {command.com esetén az első parancssor paraméter} SwapVectors; {/c kell hogy legyen} ReadKey; SwapVectors; Exec('c:\vc\vc.com', ''); SwapVectors; end.
Célszerű az egyes egérkezelési teendőkre eljárásokat és függvényeket írni (akár egy külön unit-ban elhelyezni), majd ezeket használni a programban. Ezt láthatjuk az alábbi példában is.
Példa:
Rajzolhassunk az egérrel (balgomb), a jobboldali gomb lenyomása után
téglalapokat rajzolhassunk, újabb jobbgomb, kilépés a programból.
Megoldás
Az azonosítót kell megadnunk a Uses kulcsszó után abban a programban vagy egységben, ahol a unitot használni szeretnénk, továbbá az azonosító legyen a neve az elmentett forrásnyelvű unitnak.
Továbbá globális deklarációk (konstansok, típusok, címkék, változók, eljárások, függvények), melyeket az egységet használó programokban illetve egységekben is elérhetünk. Az eljárásoknak, függvényeknek itt csak a fejlécei szerepelnek.
Továbbá egység hatáskörű deklarációk (konstansok, típusok, címkék, változók, eljárások, függvények), melyeket csak ebben az egységben érhetünk el. Itt fejtjük ki az Interface részben deklarált eljárásokat, függvényeket is.
A főprogram első utasítása előtt egyszer végrehajtódik, elhagyható.
Ha több egység egymást kölcsönösen használja, akkor mindegyikben a többi egység nevét az implementációs rész Uses kulcsszava után kell megadni.
Ha az egységet elkészítettük, .pas kiterjesztéssel metjük lemezre. Az egységet le kell fordítanunk (a fordítást lemezre kérjük). A lefordított egység kiterjesztése .tpu lesz.
Példa:
Az egérkezelést megvalósító rutinokat lehelyezhetjük egy unitban.
Megoldás