KURS
PASCALA
WSTĘP
Od autora
Chciałbym wszystkim przypomnieć, że język Turbo Pascal (okrojony Borland Pascal 7.0) jest bardzo
popularnym językiem programowania, przeznaczonym dla szrokiego kręgu odbiorców, przede wszystkim dla
nieprofesjonalistów. Język Turbo Pascal, wbrew pozorom, nie jest wcale taki trudny do opanowania, można się
go stosunkowo szybko nauczyć. Najczęściej jest on preferowany w szkołach średnich (uczą się go nawet
studenci), stosowany jako "przedsmak" do języków jeszcze bardziej skomplikowanych tj. C/C++ czy Assebler.
Kurs ten został napisany w dużej mierze na podstawie książki Andrzeja Marciniaka pt. "Turbo Pascal 7.0 z
elementami programowania", z książki zaczerpnięte zostały poszczególne definicje elementów języka.
LEKCJA 1
Słowa kluczowe i dyrektywy języka
W wersji 7.0 języka Turbo Pascal słowem kluczowym nazywamy każdy z 49. następujacych wyrazów
języka angielskiego:
and
file
nil
shr
array
for
not
string
asm
function
object
then
begin
goto
of
to
case
if
or
type
const
implementation
packed
unit
constructor
in
procedure
until
destructor
inherited
program
uses
div
inline
record
var
do
interface
repeat
while
downto
label
set
with
else
mod
shl
xor
end
Słowa kluczowe są integralną częścią języka TP i są zastrzeżone, tzn. nie mogą być zdefiniowane przez
programistę.
Oprócz słów kluczowych w wersji 7.0 Pascal-a występują dyrektywy języka. Dyrektywą jest każdy z 10.
następujących wyrazów:
absolute
far
near
public
assembler
forward
private
virtual
external
interrupt
W odróżnieniu od słów kluczowych, dyrektywy języka nie są zastrzeżone - podane wyrazy mogą więc być
identyfikatorami zdefinowanymi przez programistę, co jednak nie jest zalecane. Penym wyjątkiem są dyrektywy
private i public, które w obiektach (ale tylko w nich) są słowami zastrzeżonymi.
LEKCJA 2
Jak wygląda program w Pascalu ?
Podstawowych pojęć jakimi się operuje programując w TP jest wprawdzie niewiele i nie są one trudne do
zrozumienia, ale niewiedząc "z czym je jeść" nie mamy co zabierać się do programowania - wszystkie te pojęcia
składają się na szkielet programu. Oto lista tych pojęć:
Struktura programu
Deklaracja modułów
Etykiety
Stałe
Typy danych
Zmienne
Procedury i funkcje
Program napisany w TP 7.0 składa się z nagłówka programu (PROGRAM), deklaracji modułów, bloku i
znaku . (kropka). W nagłówku programu podaje się zwykle jego nazwę. Za pomocą deklaracji modułów określa
się moduły standardowe i moduły użytkownika. Blok składa się z opisu danych i części wykonawczej, a kropka
kończy tekst programu. Dopuszcza się możliwość opuszczenia nagłówka (jest on pomijany przez kompilator),
deklaracji modułów i opisu danych, a wiersz programu nie może zawierać więcej niż 127 znaków. Oto szkielet
programu paskalowego:
PROGRAM Nazwa_Programu; {Nagłóewk programu}
USES {Deklaracja modułów}
{Początek części opisowej}
LABEL
CO2ST
TYPE
VAR
PROCEDURE
FU2CTIO2
{Koniec części opisowej}
BEGI2
{Część wykonawcza programu}
E2D.
Deklaracja modułów (USES) jest klauzurą pozwalającą nam zdefiniować dowolną ilość modłów w
naszym programie, np.
USES CRT,DOS;
Powyższa deklaracja definiuje dla naszego programu dwa standardowe moduły DOS i CRT.
Etykiety (LABEL) deklarujemy zaraz po deklaracji modułów klauzurą USES, powodują one skok do
określonej części programu - wywołujemy je słowem kluczowym GOTO, np.
LABEL skok_1,skok_2;
...
BEGI2
GOTO skok_1;
...
...{Jakieś funkcje czy procedury.}
...
skok_1: Writeln('Skok do etykiety skok_1');
skok_2: Writeln('Skok do etykiety skok_2');
E2D.
Powyższy przykład obrazuje skok do etykiety skok_1. Podczas tej operacji omijane są wszelkie procedury i
funkcje znajdujące się w wykropkowanych miejscach.
Stałe (CONST) deklarujemy po deklaracji etykiet (LABEL), gdy zadeklarujemy jakąś stałą to w dalszej
części programu nie możemy przypisać jej już innej wartości niż wartość początkowa. Zmiennym nie musimy
przypisywać konkretnego typu danych, lecz w niektórych, bardziej złnożoych programach jest to wskazane, np.
CO2ST MaxWysokosc = 100;
MaxPredkosc = 10;
lub
CO2ST MaxWysokosc : Typ = Wartosc;
MaxPredkosc : Typ = Wartosc;
W drugim przykładzie Typ oznacza dowolny typ danych, wtedy wartość stałej przypisujemy zgodnie z typem.
Typy (TYPE) deklarujemy po deklaracji stałych (CO2ST). Każdą zmienną w programie należy
zadeklarować tzn. określić jej nazwę oraz wartości, które może ona przyjmować. Zbiór wartości zmiennej
nazywa się typem zmiennej. Typy dzielimy na standardowe (predefiniowane, nie wymagające opisu) i
niestandardowe (wprowadzane ręcznie przez programistę). O typach będzie jeszcze mowa w następnych
lekcjach, więc podam tu tylko przykłady, np.
TYPE Dzien = (pon, wt, sr, czw, pt, sob, nie);
Numer = Integer;
Zmienne (VAR) deklarujemy po deklaracji typów (TYPE). Jak już wspomniałem, wszystkie zmienne
używane w programie powinny być zadeklarowane. Deklaracje zmiennych składają się ze słowa kluczowego
VAR, po którym następuje wykaz deklaracji. Każdą zadeklarowaną zmienną (wartość zmiennej) możemy w
głebi programu dowolnie definiować (przypisywać jej inne wartości), np.
VAR Wynik = Byte;
...
BEGI2
Wynik:=0; {Wartość początkowa}
...
Wynik:=10; {Wartość przypisana później}
E2D.
P
rocedurę (PROCEDURE) lub funkcję (FU2CTIO2) deklarujemy po deklaracji zmiennych (VAR).
Są to wyodrębnione części programu, stanowiące pewną całość, posiadające jednoznaczną nazwę i ustalony
sposób wymiany informacji z pozostałymi częściami programu. Procedury i funkcje są stosowane do wykonania
czynności, które mogą być wykorzystane w różnych programach lub do wykonania czynności wielokrotnie
powtarzanych przez dany program. Różnica pomiędzy procedurą a funkcją polega na sposobie przekazywania
wartości. Zadaniem procedury jest wykonanie pewnej sekwencji czynności, polegających zwykle na obliczaniu
jedej lub wielu wartości. Natomiast zadaniem funkcji jest obliczenie jedej wartości (typu prostego lub
wskaźnikowego). Odmienne są też sposoby wywołania procedur i funkcji, np.
Definicja procedury:
PROCEDURE Nazwa_Procedury(lista_parametrów);
...Część_opisowa
BEGI2
...Ciąg_instrukcji
E2D;
W definicji procedury listę parametrów możemy pominąć.
Definicja funkcji:
FU2CTIO2 Nazwa_Funkcji(lista_parametrów): Typ_wyniku;
...Część_opisowa
BEGI2
...Ciąg_instrukcji
E2D;
W obu przypadkach lista parametrów zawiera deklarację parametrów, przy czym poszczególne deklaracje
oddziela się średnikami. W przypadku funkcji w ciągu instrukcji musi wystąpić co najmniej jedna instrukcja
przypisania w postaci:
Nazwa_Funkcji:=Wyrażenie
powodująca przypisanie wartości pod nazwę funkcji, przy czym co najmniej jedna z tych instrukcji musi być
wykonana po wywołaniu funkcji. Typ wyniku funkcji jest określony za pomocą identyfikatora typu.
LEKCJA 3
Typy danych i ich krótki opis
Co to jest mniej więcej "typ" pisałem w poprzednim dziale, a w niniejszym opiszę dość dokładnie
poszczególne typy wraz ze sposobami ich definicji w programie.
Podział typów danych:
Typy proste
Typy porządkowe
Typ wyliczeniowy
Typy całkowite
Typy logiczne
Typ znakowy
Typy okrojone
Typy rzeczywiste
Typy łańcuchowe
Typy strukturalne
Typy tablicowe
Typ rekordowy
Typ zbiorowy
Typ plikowy
Typy wskaźnikowe
Typy proceduralne
Typ obiektowy
Typy proste są podstawowymi typami języka Turbo Pascal i za ich pomocą określa się bardziej złożone
struktury danych. Wszystkie typy proste składają się ze skończonego i uporządkowanego zbioru wartości. Dzięki
temu na wartościach tych typów możemy m.in. wykonywać operacje porównań. Typy proste dzielimy na typy
porządkowe i typy rzeczywiste.
Typami porządkowymi nazywamy wszystkie typy proste z wyjątkiem typów rzeczywistych. Wyróżnienie
to jest spowodowane faktem, że typy rzeczywiste często nie mogą występować w kontekście dozwolonym dla
innych typów prostych. Dla wartości każdego typu porządkowego są określone wartości poprzednie i następne (z
wyjątkiem wartości krańcowych). Do typów porządkowych zaliczamy: typ wyliczeniowy, typy całkowite,
logiczne, typ znakowy i typy okrojone.
Typ wyliczeniowy stosuje się zwykle dla zbiorów o niewielkiej liczbie elementów, na których nie
wykonuje się operacji arytmetycznych. Definicja jednego typu wyliczeniowego jest następująca:
TYPE identyfikator_typu = (lista_identyfikatorów);
Elementy typu wyliczeniowego są uporządkowane zgodnie z kolejnością ich wyliczenia w definicji typu i
posiadają liczby porządkowe odpowiednio 0,1,2 itd.
Przyklady:
TYPE Uczniowie = (Antek, Franek, Zenek);
{Antek ma 0, Franek ma 1, a Zenek 2}
P_roku = (wiosna, lato, jesien, zima);
Typy całkowite są w języku TP predefiniowane i nie wymagają opisu w programie. Wszystkie typy
całkowite są podzbiorami zbioru liczb całkowitych. Wśród typów całkowitych wyróżniamy:
ShortInt, przedział od -128 do 127
Byte, przedział od 0 do 255
Integer, przedział od -32768 do 32767
Word, przedział od 0 do 65535
LongInt, przedział od -2147483648 do 2147483647
Przyklad:
Przypuśćmy, że zdefiniowaliśmy nowy typ:
TYPE Liczba = Integer;
W takim razie poniższa deklaracja
VAR i,j: Liczba;
jest równoważna deklaracji
VAR i,j: Integer;
Standardowymi typami logicznymi są typy Boolean, ByteBool, WordBool i LongBool. Wartości typów
logicznych są oznaczone za pomocą dwu predefiniowanych literałów (stałych): True i False, oznaczających
odpowiednio wartości logiczne fałsz i prawda, przy czym w sensie uporządkowania stała False poprzedza stałą
True. Liczbami porządkowymi elementów typu Boolean są tylko 0 (False) i 1 (True). Elemanty pozostałych
typów logicznych mogą posiadać inne (wyższe) liczby porządkowe.
Do oznaczenia typu znakowego służy predefiniowany identyfikator Char. Elementami typu znakowego są
znaki ASCII, z których każdy jest pamiętany w jednym bajcie pamięci.
Typy okrojone służą do ograniczania zakresów wartości dowolnego z dotychczas opisanych typów
porządkowych. Definicja jednego typu okrojonego ma postać
TYPE identyfikator_typu = stała .. stała;
Pierwsza stała podaje ograniczenie dolne i nie może być większa od drugiej - ograniczenia górnego. Stałe te
muszą być tego samego typu porządkowego.
Przyklad:
TYPE Litery = 'A' .. 'Z';
Do typów prostych należą także standardowe typy rzeczywiste, które jednak nie są typami porządkowymi.
Każdy z dostępnych typów rzeczywistych jest dyskretnym i skończonym podzbiorem zbioru liczb
rzeczywistych. Dostępnych jest pięć standardowych typów rzeczywistych o następujących predefiniowanych
identyfikatorach:
Real, elementy zajmują po 6 bajtów pamięci
Single, typ o pojedyńczej długości (4 bajty pamięci)
Double, typ o podwójnej długości (8 bajtów pamięci)
Extended, typ o rozszerzonej długości (10 bajtów pamięci)
Comp, elementy to liczby całkowite z przedziału od -2
63
+1 do 2
63
-1
Typy łańcuchowe służą do reprezentowania ciągu znaków, w tym niewidocznego znaku spacji.
Elementami typu łańcuchowego są łańcuchy o długości od 0 do długości podanej w definicji typu
łańcuchowego. Typ ten definiuje się następująco:
TYPE identyfikator_typu = String[rozmiar];
lub
TYPE identyfikator_typu = String;
gdzie rozmiar jest liczbą typu Byte. Brak wyspecyfikowania rozmiaru powoduje domyślne przyjęcie długości
255 znaków (warość maksymalna).
Przykład:
TYPE Nazwisko = String[20];
Typy stukturalne stosuje się do opisu obiektów złożonych, przy czym dany obiekt możemy opisać na
kilka róznych sposobów. Każdy z typów strukturalnych definiowany jest przez podanie typów składowych i
metody strukturalizacji, która zarazem określa sposób dostępu do elementów składowych. W ogólności definicja
pojedyńczego typu strukturalnego ma postać:
TYPE Identyikator_typu = Opis_typu_strukturalnego;
przy czym opis typu strukturalnego może być opisem typu tablicowego, rekordowego, zbiorowego lub
plikowego.
Typ tablicowy, a konkretnie tablica składa się z ustalonej liczby elementów tego samego typu, zwanego
typem składowym, który może być zarówno typem prostym lub łańcuchowym, jak i typem strukturalnym. Za
pomocą tablic są reprezentowane regularne układy danych, np. wektory i macierze. Dostęp do poszczególnych
elementów tablic uzyskuje się za pomocą indeksowania. Indeksem może być dowolne wyrażenie, którego
wartość jest zgodna w sensie przypisania z typem indeksowym. Dopuszczalny zakres indeksów jest podany w
definicji typu tablicowego. Definicja pojedynczego typu tablicowego ma postać:
TYPE Identyfikator_typu = array[typy_indeksowe] of typ_składowy;
gdzie typy indeksowe są opisami typu porządkowego (z wyjątkiem typu LongInt), przy czym poszczególne
opisy oddziela się przecinkami. Typ składowy oznacza dowolny typ.
Przykłady:
TYPE Macierz = array[1..20,1..30] of Real;
Tablica = array[Boolean,1..20,znak] of Char;
Typem rekordowym, a dokładniej rekordem nazywamy złożoną strukturę danych, której składowe,
zwane polami, mogą mieć rózne charakterystyki (należeć do różnych typów). Poszczególne pola mogą być same
strukturami złożonymi, przy czym liczba pól rekordu jest ustalona. Definicja typu rekordowego określa typ i
identyfikator dla każdego pola. Definicja ta rozpoczyna się słowem kluczowym record, po którym podaje się
deklarację każdego pola, a kończy słowem kluczowym end. Poszczególne deklaracje pól oddziela się
średnikami. Ostatnia deklaracja może być wariantowa (case .. of). Definicja pojedynczego typu rekordowego ma
postać:
TYPE Identyfikator_typu = record
Lista_deklaracji_pól
end;
gdzie każda z deklaracji pól ma postać:
lista_nazw_pól : opis_typu;
a ostatnia deklaracja może mieć postać (deklaracja wariantowa):
case deklaracja_pola_wyróżnikowego of wykaz_wariantów;
lub
case identyfikator_typu_porządkowego of wykaz_wariantów;
przy czym deklaracja pola wyróżnikowego wygląda następująco:
identyfikator_pola_wyróżnikowego :
identyfikator_typu_porządkowego;
lub
lista_etykiet_wyboru : (lista_deklaracji_pól);
Przykłady rekordów:
TYPE Data = record
rok : Integer;
miesiac : 1 .. 12;
dzien : 1 .. 31;
end;
TYPE Rejestry = record
case Integer of
1: (AX, BX, CX, DX : Word);
2: (AL, AH, BL, BH, CL, CH,
DL, DH : Byte);
end;
end;
Typ zbiorowy jest zbiorem potęgowym danego typu porządkowego, tzn. jest zbiorem wszystkich
podzbiorów tego typu, w tym zbioru pustego. Liczba elementów typu zbiorowego nie może przekraczać 256
(przedział od 0 do 255). Definicja pojedynczego typu zbiorowego ma postać:
TYPE Identyfikator_typu = set of typy_porządkowy;
Przykład:
TYPE Klasy = set of (LO_1d, LO_2d, LO_3d,LO_4d);
ementami typu Klasy może być dowolny podzbiór zbioru podanych nazw klas, m.in.:
[ LO_1d, LO_2d ] - podzbiór dwuelementowy
[ LO_3d ] - podzbiór jednoelementowy
[ ] - zbiór pusty
[ LO_1d, LO_2d, LO_3d, LO_4d ] - podzbór czteroelementowy
Typy plikowe są ściśle powiązane z plikami. Plik jest ciągiem elementów tego samego typu, tyle że liczba
jego składowych jest zmienna. Jest ona uzależniona od przebiegu wykonywania programu, a w szczególności od
skojarzenia pliku z fizycznym zbiorem danych. Od tablicy plik różni się ponadto metodą dostępu do
poszczególnych elementów. Definicja pojedynczego typu plikowego ma postać:
TYPE Identyfikator_typu = file of opis_typu_elementów_pliku;
lub
TYPE Identyfikator_typu = file;
Jeżeli w definicji typu plikowego pominięto słowo kluczowe of i opis typu jego elementów, to przyjmuje się, że
dany typ plikowy jest niezdefiniowany. Niezdefiniowane pliki są stosowane głównie w celu dostępu do
fizycznych zbiorów dyskowych zgodnie z ich wewnętrznym formatem. W Pascalu istnieje predefiniowany plik
tekstowy o nazwie Text (standardowy typ plikowy).
Przykłady:
TYPE Dane = file of Integer;
Zbior = file;
Wyniki = Text;
Typy wskaźnikowe. Zmienne dotychczas omówionych typów, tj. typów prostych i strukturalnych,
charakteryzują się tym, że istnieją przez cały czas wykonywania tej części , w której są zadeklarowane. Są to
tzw. zmienne statyczne. W języku Turbo Pascal występują też zmienne dynamiczne reprezentujące obiekty, dla
których pamięć jest przydzielana i zwalniana na okreśolne żądanie. Zmienne te nie posiadają identyfikatorów, a
odwołanie do nich następuje za pomocą wskaźnika. Wartościami wskaźników są elementy typu wskaźnikowego,
które określają adresy pamięci zmiennych dynamicznych. Zastosowanie w programie zmiennych dynamicznych
pociąga za sobą konieczność zdefiniowania odpowiednich typów wskaźnikowych. Definicja pojedynczego typu
wskaźnikowego ma postać:
TYPE Identyfikator_typu = ^Identyfikator_typu_bazowego;
Poprzyjmy to przykładem:
TYPE wskaznik = ^zapis;
zapis = record
Tekst: String[80];
Liczba: Integer;
end;
Definicja ta wiąże typ wskaznik ze zbiorem wskazań danych typu zapis. Jeśli wprowadzimy teraz deklarację:
VAR adres : wskaznik;
to zmiennej wskażnikowej adres będą mogły być w programie przypisywane adresy pamięci danych typu zapis.
W Pascalu występują dwa predefiniowane typy wskaźnikowe są to typy Pointer (zmienne tego typu są zgodne z
dowolnym innym typem wskaźnikowym) i PChar (reprezentuje wskaźnik do łańcuchów zakończonych znakiem
pustym).
Jednym ze słów kluczowych jest słowo nil, które oznacza stałą typu wskaźnikowego nie określającą żadnego
adresu (nil wskazuje na adres pusty).
Procedury i funkcje mogą być traktowane nie tylko jako części programu wykonywane na skutek
wywołania, ale także jako elementy, które mogą być przypisywane do zmiennych i przekazywane do innych
funkcji lub procedur jako parametry. Zmienne tego rodzaju powinny być typu proceduralnego Definicja
pojedynczego typu proceduralnego może mieć jedną z następujących postaci:
TYPE Nazwa = procedure;
lub
TYPE Nazwa = procedure(lista_parametrów);
lub
TYPE Nazwa = function: typ_wartości_funkcji;
lub
TYPE Nazwa = function(lista_parametrów):
typ_wartości_funkcji;
Przykłady:
TYPE Procedura = procedure;
Proc = procedure(x,y: Byte);
Funkcja = function(x,y: Byte): Boolean;
Typ obiektowy. Obiektem w Pascalu nazywa się złożoną strukturę danych o ustalonej liczbie elementów
składowych, z których każdy może być polem lub metodą (m.in. procedurą lub funkcją), tj. elementem
opisującym operację wykonywaną na danym obiekcie. W definicji typu obiektowego, podobnie jak w definicji
typu rekordowego, dla każdego pola specyfikuje się jego typ i identyfikator. Opis metody składa się z nagłówka
procedury, funkcji, konstruktora lub destruktora, przy czym definicja pojedynczego typu obiektowego może
zawierać opisy wielu metod. Opis typu obiektowego rozpoczyna się od słowa kluczowego object, a kończy
słowem kluczowym end. Definicja pojedynczego typu obiektowego ma postać:
TYPE Identyfikator_typu = object dziedzictwo
Lista_deklaracji_pól
Lista_deklaracji_metod
end;
lub
TYPE Identyfikator_typu = object dziedzictwo
Lista_deklaracji_pól
Lista_deklaracji_metod
Sekcje_list
end;
przy czym elementy wyszczególnione pomiędzy słowami object i end są opcjonalne, a każda z sekcji list może
mieć jedną z poniższych postaci:
private
Lista_deklaracji_pól
Lista_deklaracji_metod
lub
public
Lista_deklaracji_pól
Lista_deklaracji_metod
przy czym w sekcjach tych oba elementy są także opcjonalne.
Dziedzictwo oznacza ujęty w nawiasy okrągłe identyfikator innego, zdefiniowanego wcześniej, typu
obiektowego. Jeśli w definicji typu obiektowego wystąpi ten element, oznacza to, że dany typ obiektowy
zawiera (dziedziczy) wszystkie elementy podane w definicji typu obiektowego o wyspecyfikowanej nazwie.
Każda z deklaracji pól ma postać:
Lista_nazw_pól : opis_typu;
a każda deklaracja metody jest następująca:
nagłowek_metody;
lub
nagłowek_metody; virtual;
gdzie nagłowek metody oznacza nagłowek funkcji, procedurey, konstruktora lub destruktora. Słowo kluczowe
virtual określa daną metodę jako wirtualną (?).Definicję poszczególnych metod podaje się poza definicją typu
obiectowego. Każda definicja metody zawiera w nagłówku nazwę funkcji, procedurey, konstruktora lub
destruktora, poprzedzoną kropką i nazwą odnośnego typu obiektowego.
Jeśli definicja typu obiektowego zawiera dyrektywę private, oznacza to, że zakres ważności pól i (lub) metod
podanych po tej dyrektywie jest ograniczony do modułu (lub programu), który zawiera definicję danego typu
obiektowego. Tego typu pola i metody nazywami polami i metodami prywatnymi. Użycie po sekcji z dyrektywą
private dyrektywy public powoduje anulowanie ograniczenia zakresu ważności dla dalszych pól i (lub) metod.
Przykłady:
TYPE punkt = object
X, Y:Integer;
end;
TYPE piksel = object (punkt)
Kolor:Byte;
end;
Typ obiektowy piksel zawiera elementy typu obiektowego punkt.
TYPE odcinek = object
X, Y:Byte;
procedure zaznacz(dx, dy: Byte);
end;
Dla powyższego typu konieczne jest podanie w dalszej części programu definicji procedury zaznacz:
procedure odcinek.zaznacz(dx, dy: Byte);
begin
... Jakieś_instrukcje
end;
LEKCJA 4
Instrukcje
Czynności wykonywane na danych są opisywane za pomocą instrukcji. Instrukcjie języka Turbo Pascal
dzielą się na instrukcje proste, tj. takie, które nie zawierają jako składowych innych instrukcji, oraz instrukcje
strukturalne, zbudowane na podstawie pewnego schematu strukturalizacji kilku instrukcji.
Oto pełen podział instrukcji:
Instrukcje proste
Instrukcje przypisania
Instrukcje skoku
Instrukcje puste
Instrukcje wywołania procedury
Instrukcje inline
Instrukcje strukturalne
Instrukcje złożone
Instrukcje warukowe
Instrukcje if .. then ("jeśli")
Instrukcje case .. of (wyboru)
Instrukcje iteracyjne
Instrukcje for .. do ("dla")
Instrukcje while .. do ("dopóki")
Instrukcje repeat .. until ("powtarzaj")
Instrukcje wiążące
Instrukcje asemblerowe
Co nazywamy instrukcją prostą wytłumaczyłem po krótce już na wstępie. Teraz przypomne tylko na jakie
składowe dzielimy te instrukcje. Więc do instrukcji prostych zaliczamy: instrukcje przypisania, instrukcje skoku,
instrukcje puste, instrukcje wywołania procedury, instrukcje inline.
Instrukcja przypisania służy do przypisania zmiennej nowej wartości. Ogólna jej postać jest następująca:
Odwołanie_do_zmiennej:=wyrażenie;
lub
Nazwa_funkcji:=wyrażenie;
Dla każdego przypisania wartość wyrażenia musi być zgodna w sensie przypisania z typem zmiennej.
Przykłady:
a:=1;
tekst:="Kurs Pascala";
x:=x+1
warunek:=a=b;
Instrukcja skoku jest jedyną instrukcją, której stosowanie nie jest zalecane. Jej stosowanie zmniejsza
przejrzystość programu, utrudnia jego optymalizację...(można by pisać i pisać...). Instrukcja ta może być zawsze
zastąpiona instrukcjami "dopóki" lub "powtarzaj". Ogólna jej postać jest następująca:
GOTO etykieta;
Powoduje to przekazanie sterowania do instrukcji programu poprzedzonej podaną etykietą.
Przykład:
PROGRAM Etykiety;
LABEL et;
...
BEGI2
...
GOTO et;
...
x := a+2;
...
E2D.
Zapisanie instrukcji pustej nie wymaga użycia żadnego symbolu języka i nie powoduje ona wykonania
żadnych czynności. Instrukcję tą stosuje się w tych kontekstach, w których jest wymagane użycie instrukcji, ale
chce się uniknąć wykonania jakiejkolwiek czynności, lub w celu ułatwienia opracowania programu.
Instrukcja wywołania procedury jak sama nazwa wskazuje służy do wywoływania w programie
procedur. Ogólna postać wywołania jest następująca:
Nazwa_Procedury;
lub
Nazwa_Procedury(lista_parametrów);
Przykład:
Jeśli w części opisowej programu zadeklarujemy następującą procedurę:
PROCEDURE(X,Y:Byte;Tekst:String[10]);
BEGI2
...
E2D;
To aby tą procedurę wywołać to w części wykonawczej programu piszemy:
PROCEDURE(10,10,"Kurs Pascala");
Do dołączania w programie lub module paskalowym krótkich podprogramów lub instrukcji napisanych w
kodzie maszynowym (zgroza!) służy dyrektywa i instrukcja inline.. Jej postać jest następująca:
I2LI2E (lista_elementów_inline);
Nie będę się więcej rozpisywać na ten temat gdyż instrukcja ta bez znajomości Assemblera jest bezużyteczna - w
końcu to kurs dla początkujących, a oni raczej Assemblera nie znają.
Przykład:
I2LI2E ($CD/$12/$89/$46/$04);
Co nazywamy instrukcją strukturalną wytłumaczyłem po krótce już na wstępie. Teraz przypomne tylko
na jakie składowe dzielimy te instrukcje. Więc do instrukcji strukturalnych zaliczamy: instrukcje złożone,
instrukcje warunkowe, instrukcje iteracyjne, instrukcje wiążące, instrukcje asemblerowe.
Instrukcja złożona jest ciągiem instrukcji poprzedzonym słowem kluczowym begin i zakończonym
słowem kluczowym end. Instrukcje wchodzące w skład instrukcji złożonej wykonywane są sekwencyjnie.
Struktura tej instrukcji jest następująca:
BEGI2
Instrukcja_1;
Instrukcja_2;
...
Instrukcja_n
E2D
Przykład:
BEGI2
a:=1;
b:=a+4;
c:=a-b;
GOTO Franek;
E2D
Instrukcje warunkowe uzależniają wykonywanie innych instrukcji od spełnienia określonego warunku.
W Pascalu istnieją dwie instrukcje warunkowe: instrukcje if .. then ("jeśli"), instrukcje case .. of (wyboru).
Instrukcja "jeśli" uzależnia wykonywanie innej lub innych instrukcji od spełnienia lub niespełnienia
podanego warunku. Ogólna jej postać jest następująca:
IF wyrażenie THE2 instrukcja
lub
IF wyrażenie THE2 instrukcja
ELSE instrukcja
Przy czym wartością wyrażenia powinna być wartość logiczna True lub False. Instrukcja występująca po słowie
kluczowym then lub else może być dowolną instrukcją prostą lub strukturalną. Jeśli wartością
wyspecyfikowanego wyrażenia jest True, to zostanie wykonana instrukcja podana po słowie then. W
przeciwnym przypadku wykonana będzie następna instrukcja po instrukcji "jeśli" (gdy brak else) lub instrukcja
podana po słowie else.
Przykład:
IF X=Y THE2 A:=0
ELSE A:=1;
W programowaniu często mamy do czynienia z sytuacją, gdy wykonanie różnych operacji jest uzależnione
od wartości pewnej zmiennej. Pomocna może się tu okazać instrukcja wyboru, której ogólna postać jest
następująca:
CASE wyrażenie OF
sekwencja_instrukcji_wyboru
E2D
lub
CASE wyrażenie OF
sekwencja_instrukcji_wyboru
ELSE instrukcja
E2D
gdzie wartość wyrażenia musi być typu porządkowego. Sekwencja instrukcji wyboru składa się z instrukcji, przy
czym każda z nich poprzedzona jest jedną lub kilkoma stałymi, zwanymi stałymi wyboru, które od instrukcji
oddzielone są dwukropkiem. Poszczególne stałe wyboru oddzielamy przecinkami.
Przykład:
CASE znak OF
'+' : BEGI2
d:=d+1;
z:=z-1;
E2D;
'-' : BEGI2
d:=d-1;
z:=z+1;
E2D;
E2D;
Instrukcje iteracyjne służą do organizowania cykli programowych, tj. wielokrotnego wykonywania
pewnych sekwencji instrukcji. W Pascalu istnieją trzy rodzaje instrukcji iteracyjnych: instrukcje for .. do ("dla"),
instrukcje while .. do ("dopóki") i instrukcje repeat .. until ("powtarzaj").
Instrukcje "dla" tzw. pętlę stosuje się zwykle w celu wykonania pewnej grupy instrukcji w przypadku,
gdy liczba powtórzeń jest znana w danym miejscu programu. Instrukcja ta może mieć jedną z dwu następujących
postaci:
FOR zmienna:=wyrażenie_1 TO wyrażenie_2 DO intrukcja
lub
FOR zmienna:=wyrażenie_1 DOW2TO wyrażenie_2 DO intrukcja
Zmienna, zwana zmienną sterującą, musi być identyfikatorem typu porządkowego i powinna być lokalna w
bloku zawierającą daną instrukcję "dla". Wartość wyrażenia 1 i wyrażenia 2 powinna być zgodna w sensie
przypisania z typem zmiennej sterującej. Instrukcja występująca po słowie kluczowym DO może być dowolną
instrukcją prostą lub strukturalną.
Przykłady:
FOR i:=1 TO 10 DO x:=x+i;
Instrukcja wykonywana 10-krotnie powoduje zwiększenie zmiennej X o aktualną wartość zmiennej I.
FOR j:=10 DOW2TO 1 DO x:=x+j;
Instrukcja wykonywana 10-krotnie (od "tyłu" :-)) powoduje zwiększenie zmiennej X o aktualną wartość
zmiennej J.
Instrukcja "dopóki" służy do opisywania interacji ze sprawdzeniem warunku na początku i ma postać:
WHILE wyrażenie DO intrukcja
Wyrażenie, które najczęściej jest wyrażeniem porównania, powinno w wyniku dawać wartość logiczną (True
lub False), a instrukcja występująca po słowie do może być dowolną instrukcją prostę lub strukturalną.
Instrukcja ta wykonywana jest tak długo jak długo wartością wyrażenia jest True.
Przykład:
k:=1;
WHILE k<10 DO BEGI2
x:=x*x;
k:=INC(k) {INC(k) działa jak k:=k+1;};
E2D;
Instrukcja "powtarzaj" służy do opisywania interacji ze sprawdzeniem warunku na końcu i ma postać:
REPEAT
Instrukcja_1
Instrukcja_2
...
Instrukcja_n
U2TIL wyrażenie
Wyrażenie powinno dawać w wyniku wartość logiczną, a każda z instrukcji może być dowolną instrukcją prostą
lub strukturalną. Instrukcje wewnętrzne są wykonywane conajmniej jeden raz, a zakończenie przetwarzania
instrukcji "powtarzaj" następuje, gdy wartością wyrażenia występującego po słowie kluczowym until jest True.
Przykład:
i:=1;
REPEAT
Writeln('Linia ',i);
i:=i+1;
U2TIL i=10;
Do odwołania się do poszczegolnych pol rekordu lub obiektu służą desygnatory pól, składające się z
indentyfikatora odpowiedniego pola i nazwy zmiennej rekordowej lub obiektowej. Zastosowanie instrukcji
wiążącej pozwala na wygodniejsze odwołanie się do wspomnianych pól, a także zwiększa czytelność programu.
Jej postać jest następująca:
WITH lista_zmiennychDO instrukcja
przy czym lista zmiennych zawira oddzoelone przecinkami identyfikatory zmiennych rekordowych lub
obiektowych, a instrukcja po słowie kluczowym do może być dowolną instrukcją prostą lub strukturalną.
Umieszczenie zmiennej rekordowej lub obiektowej po słowie kluczowym with pozwala wewnątrz instrukcji
wiążącej na odwołanie się do pól tej zmiennej za pomocą samych identyfikatorów pól. Identyfikatory te
traktowane są w instrukcji wewnętrznej jako zmienne.
Przykład:
Załóżmy następującą deklarację:
VAR comp: RECORD
re,im: Real;
E2D;
Przypisanie do tego rekordu w instrukcji wiążącej
jest następujące:
WITH comp DO
BEGI2
re:=1;
im:=1;
E2D;
Jest to równoważne z takim przypisaniem w instrukcji
złożonej:
BEGI2
comp.re:=1;
comp.im:=1;
E2D;
Instrukcje asemblera wewnętrznego w tekście źródłowym języka Turbo Pascal są zapisywane jako
instrukcja asemblerowa, która ma postać:
ASM
instrukcja_asemblera_1
instrukcja_asemblera_2
...
instrukcja_asemblera_n
E2D;
Nie będę się więcej rozpisywać na ten temat gdyż instrukcja ta bez znajomości Assemblera jest bezużyteczna - w
końcu to kurs dla początkujących, a oni raczej Assemblera nie znają. (Ups ! Chyba to już pisałem...)
LEKCJA 5
Moduły
Moduły są podstawą programowania modularnego i służą przede wszystkim do grupowania procedur i
funkcji w biblioteki, a także do dzielenia dużych programów na powiązane logicznie części. Moduł nie stanowi
samoistnego programu a jego użycie w programie wymaga deklaracji(USES). Po zadeklarowaniu modułu w
danym programie dostępna jest każda procedura i funkcja zdefiniowana w danym module, jak również
zadeklarowane w nim stałe, typy i zmienne. Uruchomienie skompilowanego programu zawierającego deklaracje
modułu wymaga, aby moduł taki był również wcześniej skompilowany.
Dokładna postać modułu jest następująca:
U2IT Nazwa_modułu;
I2TERFACE
{Początek części opisowej modułu}
Deklaracje_modułów;
Definicje_literałów;
Definicje_typów;
Deklaracje_zmiennych;
Lista_nagłówków_procedur_i_funkcji;
{Koniec części opisowej modułu
i początek części implementacyjnej}
IMPLEME2TATIO2
Deklaracje_etykiet;
Deklaracje_literałów;
Definicje_typów;
Deklaracje_zmiennych;
Definicje_funkcji_i_procedur_wewnętrznych;
Definicje_funkcji_i_procedur;
{których nagłówki podano w części opisowej}
{Koniec części implementacyjnej}
E2D.{Część inicjująca modułu}
Część inicjująca modułu może być także instrukcją złożoną, która będzie wykonywana w celu zainicjowania
modułu. Nazwa modułu jest identyfikatorem wykorzystywanym do deklaracji danego modułu w programie lub
innym module - nazwa ta musi być unikatowa.
Jeśli chciałbyś się dowiedzieć jeszcze czegoś więcej o modułach to nie wahaj się
napisać
.
LEKCJA 6
Tryb 13H
Zacznę od wyjaśnienia, co to jest to tajemnicze 13H. Otóż tryb 13H jest to pewien tryb graficzny, który można
uzyskać na chyba każdej karcie graficznej bez żadnych dodatkowych sterowników. Daje on nam rozdzielczość
320x200 i 256 kolorów. Dzięki temu można tworzyć programy wykorzystujące więcej kolorów, np. ogień.
Ogień jest prostym efektem graficznym, którego nie da się uzyskać w zwylym trybie graficznym w Turbo
Pascal-u. Tryb ten ma również inne zalety. Bardzo łatwo się go używa, nasze procedury zapisane w Assemblerze
są szybsze i pewniejsze.
Jak już wspomniałem tryb ten daje nam rozdzielczość 320x200 i 256 kolorór. Tryb ten zajmuje więc 64000
bajtów pamięci (320x200=64000). Wiemy również, że mniej więcej tyle właśnie zajmuje jeden segment pamięci
komputera. Segment pamięci ekranu w trybie 13H zaczyna się o adresie A000H. Literka H oznacza, że liczba
zapisana jest w systemie szesnastkowym.
Do obsługi trybu graficznego służy przerwanie 10H. Funcka 0H (Ah=0) ma za zadanie zmiany trybu
graficznego/tekstowego. Dostępne są następujące tryby:
AL
Rodzaj
Rozdz.
Kolory
Karta
Segment pamięci
0
tekstowy
40x25
16/8
CGA/EGA
B800H
1
tekstowy
40x25
16/8
CGA/EGA
B800H
2
tekstowy
80x25
16/8 (odcieni)
CGA/EGA
B800H
3
tekstowy
80x25
16/8
CGA/EGA
B800H
4
graficzny
320x200
4
CGA/EGA
B800H
5
graficzny
320x200
4 (odcienie)
CGA/EGA
B800H
6
graficzny
640x200
2
CGA/EGA
B800H
7
tekstowy
80x25
3
MDA/EGA
B000H
0DH
graficzny
320x200
16
EGA/VGA
A000H
0EH
graficzny
640x200
16
EGA/VGA
A000H
0FH
graficzny
540x350
3
EGA/VGA
A000H
10H
graficzny
640x350
4 lub 16
EGA/VGA
A000H
11H
graficzny
640x480
2
VGA
A000H
12H
graficzny
640x480
14
VGA
A000H
13H
graficzny
320x200
156
VGA
A000H
My włączamy tryb 13H, czyli nasza procedura InitGraph wygląda tak:
Procedure Init; Assembler;
Asm;
MOV AX,0013H
INT 10H
end;
Na koniec pracy w grafice trzeba ten tryb zamknąć, a dokładnie mówiąc wywołać tryb standardowy tekstowy.
Nasza procedura CloseGraph wygląda więc tak:
Procedure Close; Assembler;
Asm;
MOV AX,0003H
INT 10H
End;
Punkt o współrzędnych [0,0] ma adres A000H:0. Tak więc punkt o współrzędnych [X,Y] znajduje się w pamięci pod adresem A000:Y*320+X.
Turbo Pascal daje nam możliwość odwoływania się do komórek pamięci za pomocą instrukcji MEM. Jeśli chcemy odczytać wartość danej komórki
piszemy:
X:=MEM[segment:offset];
Jeśli chcemy zmienić wartość danej komórki, napiszemy:
MEM[segment:offset]:=X;
Prosta procedura rysująca punkt na ekranie mogłaby wyglądać więc tak:
Procedure PutPixel(X,Y : Integer; Kolor : Byte);
Begin
MEM[$A000:Y*320+X]:=Kolor;
End;
Funkcja odczytująca kolor punktu pogłaby wyglądać tak:
Function GetPixel(X,Y : Integer) : Byte;
Begin
GetPixel:=MEM[$A000:Y*320+x];
End;
Opisze te instrukcje ze względu na działanie patematyczne (Y*320+X) oraz użycie Pascal'wej instrukcji MEM
są bardzo proste. Dlatego należy używać procedury do wstawiania punktu napisanej w Assemblerze ? Wiemy, że
ten język jest najszybszy. W Assemblerze nasza procedura PutPixel wyglądałaby tak:
Procedure PutPixel(X,Y : Integer; Kolor : Byte); Assembler;
Asm
MOV AX,0A000H
MOV ES,AX
MOV DX,Y
MOV DI,X
SHL DX,6
ADD DI,DX
SHL DX,2
ADD DI,DX
MOV AL,Kolor
MOV ES:[DI],AL
End;
Może być ? Ta procedura jest znacznie szybsza od poprzedniej. Działa w następujący sposób:
MOV AX,0A000H
MOV ES,AX
W rejestrze ES mamy teraz segment naszego ekranu. Wystarczy wykonać działanie Y*320+X. Można to zrobić
używając instrukcji MUL, która służy do mnożenia, jednak jest ona strasznie wolna. Lepiej zastosować tutać
SHL, czyli przesunięcie logiczne. Jest znacznie szybsze, a można za pomocą niego wykonać mnożenie przez
potęgę liczby 2. Działanie 320*Y zapisujemy jako Y*256+Y*64. Liczby 256 i 64 są potęgami liczby 2.
Dlaczego akurat 256 i 64? Bo wiemy ze wzoru (a+b)*C=A*c+b*c, czyli (256+64)*Y.
Instrukcja GetPixel w Assemblerze jest bardzo podobna.
Function GetPixel(X,Y : Integer) : Byte; Assembler
Asm
MOV AX,0A000H
MOV ES,AX
MOV DX,Y
MOV DI,X
SHL DX,6
ADD DI,DX
SHL DX,2
ADD DX,DI
MOV AL,ES:[DI]
MOV @Result,AL
End;
LEKCJA 7
Wyrażenia
Wyrażenia składają się z argumentów i operatorów. Dzięki operatorom możemy wykonywać różne operacje na
argumentach. Kolejność wykonywania działań jest określona tzw. priorytetem. Poniżej znajduje się tabela
poszczególnych operatorów i ich priorytety:
Operatory
Priorytety
@, NOT
1
*,/, DIV, MOD, AND, SHL, SHR
2
+,-, OR, XOR
3
=, <>, <, >, <=, >=, IN
4
Jeśli dwa operatory mają ten sam priorytet, to zostają wykonane od lewej do prawej.
Operatory arytmetyczne
Operator
Znaczenie
Typ argumentu
Typ wyniku
+
zachowanie znaku
całkowity lub rzeczywisty
całkowity lub rzeczywisty
-
zmiana znaku
całkowity lub rzeczywisty
całkowity lub rzeczywisty
+
dodawanie
całkowity lub rzeczywisty
całkowity lub rzeczywisty
-
odejmowanie
całkowity lub rzeczywisty
całkowity lub rzeczywisty
*
mnożenie
całkowity lub rzeczywisty
całkowity lub rzeczywisty
/
dzielenie
całkowity lub rzeczywisty
rzeczywisty
DIV
dzielenie całkowite
całkowity
całkowity
MOD
dzielenie modulo
całkowity
całkowity
Operatory bitowe
Operator
Znaczenie
Typ argumentu
Typ wyniku
NOT
negacja
całkowity
całkowity
AND
iloczyn
całkowity
całkowity
OR
suma
całkowity
całkowity
Operatory logiczne
Operator
Znaczenie
Typ argumentu
Typ wyniku
NOT
negacja
logiczny
logiczny
AND
iloczyn
logiczny
logiczny
OR
suma
logiczny
logiczny
XOR
suma modulo 2
logiczny
logiczny
Operatory relacyjne
Operator
Znaczenie
Typ argumentu
Typ wyniku
=
równość
typy proste wskaźnikowe,
zbiorowe łańcuchowe
logiczny
<>
nierówność
typy proste wskaźnikowe,
zbiorowe łańcuchowe
logiczny
<
mniejszość
typy proste lańcuchowe
PChar
logiczny
>
większość
typy proste lańcuchowe
PChar
logiczny
<=
mniejszy-równy
typy proste lańcuchowe
PChar
logiczny
>=
większy-równy
typy proste lańcuchowe
PChar
logiczny
<=
jest podzbiorem
zgodne zbiorowe
logiczny
=>
jest nadzbiorem
zgodne zbiorowe
logiczny
IN
zawarty w
logiczny
LEKCJA 8
Błędy podczas programowania
Błędy podczas kompilacji
1. Invalid function number - czyli - Bledny numer funkcji
2. File not found - czyli - Plik nie zostal znaleziony
3. Path not found - czyli - Sciezka dostepu nie zostala znaleziona
4. Too many open files - czyli - Zbyt duzo otwartych plikow
5. File access denied - czyli - Brak dostepu do pliku
6. Invalid file handle - czyli - niewlasciwy uchwyt pliku
12. Invalid file access code - czyli - Niewlasciwy kod dostepu do pliku
15. Invalid driver number - czyli - Niewlasciwy numer stacji
16. Cannot remove current directory - czyli - Niemozliwe usuniecie biezacego katalogu
17. Cannot rename across drives - czyli - Niemozliwa zmiana nazwy pliku
18. No more files - czyli - Brak plikow o nazwach okreslonych w wywolaniach procedur FindFirs i FindNext
100. Disk read error - czyli - Blad odczytu z dysku
101. Disk write error - czyli - Blad zapisu na dysku
102. File not assigned - czyli - Plik nie zostal powiazany ze zmienna plikowa
103. File not open - czyli - Plik nie jest otwarty
104. File not open for input - czyli - Plik nie jest otwarty do odczytu
105. File not open for output - czyli - Plik nie jest otwarty do zapisu
106. Invalid numeric format - czyli - Bledny format numeryczny
150. Disk is write-protected - czyli - Dysk jest zabezpieczony przed zapisem
151. Bad drive request struct length - czyli - Bledna nazwa stacji
152. Drive not ready - czyli - Stacja nie jest gotowa
153. Unknown command - czyli - Neeznana komenda
154. CRC error in data - czyli - Blad danych
156. Disk seek error - czyli - Blad przeszukiwania dysku
157. Unknown media type - czyli - Nieznany typ urzadzenia
158. Sector not found - czyli - Sektor nie zostal znaleziony
160. Device write fault - czyli - Blad urzadzenia podczas zapisu
161. Device read fault - czyli - Blad urzadzenia podczas odczytu
162. Hardwere failure - czyli - Uszkodzenie sprzetu
200. Devision by zero - czyli - Dzielenie przez zero
201. Range chceck error - czyli - Blad przekroczenia zakresu
202. Stack overlow error - czyli - Blad przepelnienia stosu
203. Heap overlow error - czyli - Blad przepelnienia sterty
204. Invalid pointer operation - czyli - Bledna operacja wskaznikowa
205. Floating point overlow - czyli - Przepenienie w wyniku operacji zmiennoprzecinkowej
206. Floating point underflow - czyli - Nadmiar w wyniku operacji zmiennoprzecinkowej
207. Invalid floating point operation - czyli - Bledna operacja zmiennoprzecinkowa
208. Overlay manager not installed - czyli - Program zarzadzajacy nakladkowaniem nie zostal zainstalowany
209. Overlay file read error - czyli - Blad odczytu z pliku nakladkowego
210. Object not initialized - czyli - Objekt nie zostal zainicjowany
211. Call to abstract method - czyli - Wywolanie abstrakcyjne metody wirtualnej
212. Stream registration error - czyli - Blad rejestracji strumienia
213. Collection index out of range - czyli - Indeks kolekcji jest poza zakresem
214. Collection overlow error - czyli - Blad przepenienia kolekcji
215. Arithmetic overlow error - czyli - Blad przepenienia lub wynik operacji arytmetycznej poza zakresem
216. General Protection fault - czyli - Odwolanie sie przez program do pamieci dla niego niedostepnej
Błędy podczas wykonywania programu
1. Out of memory - czyli - Brak pamieci
2. Identifier expected - czyli - Oczekiwano identyfikatora
3. Unkown identifier - czyli - Nieznany identyfikator
4. Duplicate identifie - czyli - Podwojny identyfikator
5. Syntax error - czyli - Blad skladni
6. Error in real constant - czyli - Blad w stalej rzeczywistej
7. Error in integer constant - czyli - Blad w stalej calkowitej
8. String constant exceeds line - czyli - Stala lancuchowa przekracza wiersz
9. Brak danych
10. Unexpeced end of file - czyli - Niespodziewany koniec pliku
11. Line too long - czyli - Zbyt dluga linia - maksymalnie 127 znakow
12. Type identifier expected - czyli - Oczekiwany identyfikator typu
13. Too many open files - czyli - Zbyt duzo otwartych plikow
14. Invauld file name - czyli - Bledna nazwa pliku
15. File not found - czyli - Nie znaleziono pliku
16. Disk full - czyli - Dysk jest pelny
17. Invaild compiler directive - czyli - Bledna dyrektywa kompilatora
18. Too many files - czyli - Zbyt duzo plikow
19. Undefined type in pointer definition - czyli - Niezdefiniowany typ w definicji wskaznika
20. Variable identifier expected - czyli - Oczekiwano identyfikatora zmiennej
21. Error in type - czyli - Blad w deklaracji typu
22. Structure too large - czyli - Zbyt duzy typ strukturalny
23. Set base type out of range - czyli - Typ bazowy przekracza zakres
24. File components may not be files or object - czyli - Skladnikami pliku nie moga byc pliki ani objekty
25. Invaild string length - czyli - Bledna dlugosc lancucha
26. Type mismatch - czyli - Niezgodnosc typow
27. Invaild subrange base type - czyli - Bledny typ bazowy typu okrojonego
28. Lower boud greater than upper bound - czyli - Dolny zakres jest wiekszy od zakresu gornego
29. Ordinal type expected - czyli - Oczekiwano typu porzadkowego
30. Integer constant expected - czyli - Oczekiwano stalej calkowitej
31. Constant expected - czyli - Oczekiwano stalej
32. Integer or real constant expected - czyli - Oczekiwano stalej calkowitej lub rzeczywistej
33. Pointer Type identifier expected - czyli - Oczekiwano identyfikatora typu wskaznikowego
34. Invalid function result type - czyli - Bledny typ wyniku funkcji
35. Label identufier expected - czyli - Oczekiwano identyfikatora etykiety
36. BEGIN expected - czyli - Oczekiwano BEGIN
37. END expected - czyli - Oczekiwano END
38. Integer expression expected - czyli - Oczekiwano wyrazenia calkowitego
39. Ordinal expression expected - czyli - Oczekiwano wyrazenia porzadkowego
40. Boolean expression expected - czyli - Oczekiwano wyrazenia logicznego
41. Operand types do not match operator - czyli - NIezgodnosc typow operandow dla operatora
42. Error in expression - czyli - Blad w wyrazeniu
43. Illegal assignment - czyli - Niedozwolone przypisanie
44. Field identifier expected - czyli - Oczekiwano identyfikatora pola
45. Object file too large - czyli - Zbyt duzy plik OBJ
46. Undefined external - czyli - Niezdefinowany podprogram zewnetrzny
47. Invalid object file record - czyli - Bledna zawartosc pliku OBJ
48. Code segment too large - czyli - Zbyt duzy segment kodu
49. Data segment too large - czyli - Zbyt duzy segment danych
50. DO expected - czyli - Oczekiwano DO
51. Invalid PUBLIC definition - czyli - Bledna definicja PUBLIC
52. Invalid EXTRN definition - czyli - Bledna definicja EXTRN
53. Too many EXTRN definitions - czyli - Zbyt duzo definicji EXTRN
54. OF expected - czyli - Oczekiwano OF
55. INTERFACE expected - czyli - Oczekiwano INTERFACE
56. Invalid relocatable reference - czyli - Bledne odwolanie relokowalne
57. THEN expected - czyli - Oczekiwano THEN
58. TO or DOWNTO expected - czyli - Oczekiwano TO lub DOWNTO
59. Undefined forward - czyli - Niezdefiniowana deklaracja forward
60. Brak danych
61. Invalid typecast - czyli - Niewlasciwa konwersja
62. Devision by zero - czyli - Dzielenie przez zero
63. Invalid file type - czyli - Niewlasciwy typ plikowy
64. Cannt read or write variables of this type - czyli - Bledny typ argumentu
65. Pointer variable expected - czyli - Oczekiwano zmiennej wskaznikowej
66. String variable expected - czyli - Oczekiwano zmiennej lancuchowej
67. String expression expected - czyli - Oczekiwano wyrazenia lancuchowego
68. Circular unit reference - czyli - Zapetlenie odwolan mieszy modulami
69. Unit name mismatch - czyli - Niezgodnosc nazwy modulow
70. Unit version mismatch - czyli - Niezgodnosc wersji modulow
71. Internal stack overflow - czyli - Przepelnienie wewnetrzne stosu
72. Unit file format error - czyli - Blad formatu pliku TPU
73. IMPLEMENTATION expected - czyli - Oczekiwano IMPLEMENTATION
74. Constant and case types do not match - czyli - Niezgodnosc stalej i pola wyboru
75. Record or objest variable expected - czyli - Oczekiwano zmiennej rekordowej lub objektowej
76. Constant out of range - czyli - Stala poza zakresem
77. File variable expected - czyli - Oczekiwano zmiennej plikowej
78. Pointer expression expected - czyli - Oczekiwano wyrazenia wskaznikowego
79. Integer or real expression expected - czyli - Oczekiwano wyrazenia calkowitego lub rzeczywistego
80. Label not wihin current block - czyli - Brak etykiety w biezacym bloku
81. Label already defined - czyli -Etykieta jest juz zdefiniowana
82. Undefined label in proceding statement part - czyli - Wystapila niezdefiniowana etykieta
83. Invalid @ argument - czyli - Vledny argument operatora @
84. UNIT expected - czyli - Oczekiwano UNIT
85. ; expected - czyli - Oczekiwano srednika
86. : expected - czyli - oczekiwano dwukropka
87. , expected - czyli - Oczekiwano przecinka
88. ( expected - czyli - Oczekiwano nawiasu poczatkowego
89. ) expected - czyli - Oczekiwano nawiasu konczacego
90. = expected - czyli - Oczekiwano znaku roznosci
91. := expected - czyli - Oczekiwano znaku przypisania
92. [ or (. expected - czyli - Oczekiwano nawiasu poczatkowego [ lub (.
93. ] or .) expected - czyli - Oczekiwano nawiasu konczacego ] lub .)
94. . expected - czyli - Oczekiwano kropki
95. .. expected - czyli - Oczekiwano dwoch kropek
96. Too many variables - czyli - Zbyt duzo zmiennych
97. nvalid FOR control variable - czyli - Bledna zmienna sterujaca w instrukcji FOR
98. Integer variable expected - czyli - Oczekiwano zmiennej calkowitej
99. Files types are not allowed here - czyli - Pliki sa tutaj niedozwolone
100. String length mismatch - czyli - Niezgodnosc dlugosci lancuchow
101. Invalid ordering of fields - czyli - Bledne uporzadkowanie pol
102. String constant expected - czyli - Oczekiwano stalej lancuchowej
103. Integer or real variable expected - czyli - Oczekiwano zmiennej calkowitej lub rzeczywstej
104. Ordinal variable expected - czyli - Oczekiwano zmiennej porzadkowej
105. INLINE error - czyli - Blad w instrukcji kodu INLINE
106. Character expression expected - czyli - Oczekiwano wyrazenia znakowego
107. Too many relocation items - czyli - Zbyt duzy program EXE
108. Overlow in arithmetic operation - czyli - Przepelnienie w wyniku przekroczenia zakresu operacji
arytmetycznej
109. No enclosing FOR, WHILE or REPEAT statement - czyli - Procedury Break i Continue wystapily poza
instrukcjami FOR, WHILE, REPEAT
110. Debug information table oferlow - czyli - Przepelnienie podczas generowania do pliku EXE informacji dla
debuggera
111. Berak danych
112. CASE constant out of range - czyli - Stala wybory poza zakresem
113. Error in statement - czyli - Blad w instrukcji
114. Cannot call an interrupt procedure - czyli - Niemozliwe wywolanie procedury obslugi przerwania
115. Brak danych
116. Must be in 8087 mode to compile this - czyli - Kompilacja mozliwa przy uzyciu dyrektywy {$N+}
117. Target address not found - czyli - Nie znaleziono adresu docelowego
118. Include files are not allowed here - czyli - W tym miejscu dolaczenie pliku jest niemozliwe
119. No inherited methods are accessible here - czyli - Uzycie slowa kluczowego INHERITED poza metoda lub
w metodzie bez przodka
120. NIL expected - czyli - Oczekiwano NIL
121. Invalid qualifier - czyli - Bledny kwalifikator
122. Invald variable reference - czyli - Bledne odwolanie do zmiennej
123. Too many symbols - czyli - Zbyt duzo symboli
124. Statement part too large - czyli - Zbyt duza czesc wykonawcza
125. Brak danych
126. Files must be var parametrs - czyli - Pliki musza byc parametrami przekazywanymi przez zmienna
127. Too many conditional symbols - czyli - Zbyt duzo warunkowych nazw symbolicznych
128. Misplaced conditional directive - czyli - Niewlasciwie umieszczona dyrektywa warunkowa
129. ENDIF directive missing - czyli - Brak dyrektywy ENDIF
130. Error in initial condidtional defines - czyli - Blad w definicji warunkowej nazwy symbolicznej
131. Header does not match previous definition - czyli - Niezgodnosc naglowka z poprzednia definicja
132. Brak dancych
133. Cannot evaluate this expression - czyli - Obliczenie wyrazenia jest niemozliwe
134. Expression incorrectly terminated - czyli - Nieprawidlowe zakonczenie wyrazenia
135. Invalid format specifier - czyli - Bledny format elementu opisujacego
136. Invalid indirect reference - czyli - Bledne odwolanie posrednie
137. Structured variables are not allowed here - czyli - Uzycie zmiennych strukturalnych w tym miejscu nie jest
dozwolone
138. Cannot evaluate without System unit - czyli - Bez modulu System nie mozna wykonac danych obliczen
139. Cannot access this symbol - czyli - Brak dostepu do danego symbolu
140. Invalid floating point operation - czyli - Bledna operacja zmiennoprzecinkowa
141. Cannot compile overlays to memory - czyli - Kompilowanie nakladek do pamieci jest niemozliwe
142. Pointer or procedural variable expected - czyli - Oczekiwano zmiennej wskaznikowej lub proceduralnej
143. Invalid procedure or function reference - czyli - Bledne odwolanie do procedury lub funkcji
144. Cannot overlays this unit - czyli - Modul nie byl skompilowany z dyrektywa {$O+} i nie moze byc
stosowany jako nakladka
145. Too many nested scopes - czyli - Zbyt duzy zakres zagniezdzen - 512 dla calego programu lub 128 dla
modulu
146. File access denied - czyli - Brak dostepu do pliku
147. Object type expected - czyli - Oczekiwano typu objektowego
148. Local object types are not allowed - czyli - Lokalne typy objektowe nie sa dozwolone
149. VIRTUAL expected - czyli - Oczekiwano VIRTUAL
150. Method identifier expected - czyli - Oczekiwano identyfikatora metody
151. Virtual constructors are not allowed - czyli - onstruktory wirtualne nie sa dozwolone
152. Constructor identifier expected - czyli - Oczekiwano identyfikatora konstruktora
153. Destructor identifier expected - czyli - Oczekiwano identyfikatora destruktora
154. Fail only allowedwithin constructors - czyli - Procedura Fail moze byc wywolana tylko z wnetrza
konstruktora
155. Invalid combination of opcode and operands - czyli - Bledna kombinacja kodu operacji i operatorow
156. memory reference expected - czyli - Oczekiwano odwolania do pamieci
157. Cannot add or subtract relocatable symbols - czyli - Symbole relokowalne nie moga byc dodawane lub
odejmowane
158. Invalid register combination - czyli - Bledna kombinacja rejestrow
159. 286/287 instructions are not enabled - czyli - Instrukcje procesora 80286 i koprocesora arytmetycznego
80287 nie sa dozwolone
160. Invalid symbol reference - czyli - Bledne odwolanie do symbolu
161. Code generation error - czyli - Bledna generacja kodu
162. ASM expected - czyli - Oczekiwano ASM
163. Duplicate dynamic method index - czyli - Dwukrotne uzycie indeksu metody dynamicznej
164. Duplicate resourceidentifier - czyli - Dwukrotne uzycie identyfikatora zasobu
165. Duplicate or invalid export index - czyli - Dwukrotne uzycie lub bledny index eksportu
166. Procedure or function identifier expected - czyli - Oczekiwano identyfikatora procedury lub funkcji
167. Cannot export this symbol - czyli - Symbol nie moze byc eksportowany
168. Duplicate export name - czyli - Dwukrotne uzycie nazwy eksportowej
169. Executable file header too large - czyli - Zbyt duzy naglowek pliku wykonywalnego
170. Too many segments - czyli - Zbyt duzo segmentow
LEKCJA 9
Kody klawiszy
Oznaczenie
Sam klawisz
Z SHIFT
Z CTRL
Z ALT
0
48
41
-
0 129
1
49
33
-
0 120
2
50
64
-
0 121
3
51
35
-
0 122
4
52
36
-
0 123
5
53
37
-
0 124
6
54
94
-
0 125
7
55
38
-
0 126
8
56
42
-
0 127
9
57
40
-
0 128
A
97
65
1
0 30
B
98
66
2
0 48
C
99
67
3
0 46
D
100
68
4
0 32
E
101
69
5
0 18
F
102
70
6
0 33
G
103
71
7
0 34
H
104
72
8
0 35
I
105
73
9
0 23
J
106
74
10
0 36
K
107
75
11
0 37
L
108
76
12
0 38
M
109
77
13
0 50
N
110
78
14
0 49
O
111
79
15
0 24
P
112
80
16
0 25
Q
113
81
17
0 16
R
114
82
18
0 19
S
115
83
19
0 31
T
116
84
20
0 20
U
117
85
21
0 22
V
118
86
22
0 47
W
119
87
23
0 17
X
120
88
24
0 45
Y
121
89
25
0 21
Z
122
90
26
0 44
-
45
95
31
0 130
=
61
43
-
0 131
\
92
124
28
-
/
47
63
-
-
SPACJA
32
32
32
32
F1
0 59
0 84
0 94
0 104
F2
0 60
0 85
0 95
0 105
F3
0 61
0 86
0 96
0 106
F4
0 62
0 87
0 97
0 107
F5
0 63
0 88
0 98
0 108
F6
0 64
0 89
0 99
0 109
F7
0 65
0 90
0 100
0 110
F8
0 66
0 91
0 101
0 111
F9
0 67
0 92
0 102
0 112
F10
0 68
0 93
0 103
0 113
DO GÓRY
0 72
56
-
8
W PRAWO
0 77
54
0 116
6
W LEWO
0 75
52
0 115
4 lub 0 132
W DÓŁ
0 80
50
-
2 lub 0 130
HOME
0 71
55
0 119
7
END
0 79
49
0 117
1 lub 0 129
PgUp
0 73
57
0 132
9
PgDn
0 81
51
0 118
3 lub 0 131
Ins
0 82
48
-
-
Del
0 83
46
-
-
5 (num)
-
53
-
5 lub -
* (szary)
42
PrtSc
0 114
-
- (szary)
45
45
-
-
+ (szary)
43
43
-
-
ESC
27
27
27
-
BackSpace
8
8
127
-
TAB
9
0 15
-
-
ENTER
13
13
10
-
LEKCJA 10
Algorytmy sortowania
InsertionSort
Algorytm InsertionSort (przez wstawianie) jest jednym z najprostrzych algorytmów sortowania. Jest on używany
bardzo często w prostych programach osób, które dopiero zaczynają programować. Trudno popełnić w nim błąd
ze względu na krótki i prosty jego zapis. Nie jest jednak wskazane używanie jego w poważniejszych
zastosowaniach, kiedy mamy do czynienia z sortowaniem bardzo dużych tablic. Jest on klasy O(N
2
), czyli jest
strasznie wolny.
Polega on na tym, że przeglądamy po kolei całą tablicę. Jeżeli któryś z elementów nie znajduje się na swoim
miejscu, to wstawiamy go tam, gdzie powinien się znajdować, gdyby tablica była uporządkowana. Dlatego
najpierw przesuwamy całą zawartość tablicy tak, by się zwolniło miejsce, a później uzupełniamy je naszą np.
liczbą.
W Pascalu, algorytm mógłby wyglądać np. tak:
Procedure InsertionSort(Var TAB : Tablica);
Var i,j : Integer;
Temp : integer;
begin
for i:=2 to Ilosc do
begin
Temp:=TAB[i];
TAB[0]:=Temp;
j:=i-1;
While Temp<TAB[j] do
Begin
TAB[j+1]:=TAB[j];
j:=j-1;
end;
TAB[j+1]:=Temp;
End;
End;
BubbleSort
Jest to jeden z najprostrzych algorytmów sortowania. Jako, że jest klasy O(N
2
), nie nadaje się do profesionalnych
zastosowań, gdzie mamy do czynienia z sortowaniem bardzo dużych tablic. Jeśli jednak tablica jest mała, to ze
względu na jego bardzo prostą budowe, nadaje się wyśmienicie.
BubbleSort, czyli Sortowanie Bąbelkowe opiera się na zasadzie porównania i ewentualnej zmiany par
sąsiadujących ze sobą elementów. Jeśli np. liczba 1 znajduje się na 5 pozycji w tablicy (a powinna na 1), to za
pierwszym przebiegiem znajdzie się na pozycji 4, za kolejnym przebiegiem na 3, itd. aż dojdzie do 1. Nazwa
sortowania pochądzi więc stąd, że w pionowo ustawionym ciągu elementy o małej wartości w czasie sortowania
"wypływają do góry", jak bąbelki powietrza np. w wodzie.
Przykładowa funkcja sortująca algorytmem BubbleSort w Pascalu może wyglądać tak:
Procedure BubbleSort(Var TAB : Tablica);
Var i,j : Integer;
Temp : integer;
begin
for i:=2 to Ilosc do
for j:=Ilosc DownTo i Do
if TAB[j-1]>A[j] Then
begin
Temp:=TAB[j-1];
TAB[j-1]:=TAB[j];
TAB[j]:=TEMP
End;
End;
ShakerSort
Jest to poprawiona wersja sortowania bąbelkowego, często nazywana "Sortowaniem pęcherzykowym". Różnica
między nim, a BubbleSort jest taka, że nie rozpoczyna w każdym przebiegu zmiany elementów od początku,
lecz na przemian od początku i od końca. Dzięki temu następuje niewielka (ale jednak) oszczędność czasu
sortowania. Mniej jest pustych przebiegów. Zwiększenie szybkości jest szczególnie widoczne w częściowo
posortowanych już tablicach.
Algorytm ten w Pascalu wygląda następująco:
Procedure ShakerSort(Var Tab : Tablica);
Var j,k : Integer;
temp : Integer;
left,right : Integer;
Begin
left:=1;
right:=Ilosc;
k:=Ilosc;
Repeat
for j:=right DownTo 1 do
if Tab[j-1]>Tab[j] Then
Begin
Temp:=Tab[j-1];
Tab[j-1]:=Tab[j];
Tab[j]:=Temp;
k:=j;
End;
left:=k+1;
for j:=left to right do
if Tab[j-1]>Tab[j] Then
Begin
Temp:=Tab[j-1];
Tab[j-1]:=Tab[j];
Tab[j]:=Temp;
k:=j;
End;
right:=k-1;
Until l>r;
End;
QuickSort
Jest to jeden z najszybszych algorytmów sortowania, klasy O(N log
2
N). Autorem jego jest C.A.Hoare.
Procedura sortowania dzieli się na dwie części: część służącą do właściwego sortowania (tzn. wywoływania
samego siebie - rekurencji) oraz procedury rozdzielania elementów tablicy względem pewnej wartości komórki
tablicy służącej za oś podziału. Sortowanie jest wykonywane właśnie przez tę procedurę, a rekurencja zapewnia
"sklejenie" wyników cząstkowych i w konsekwencji posortowanie całej tablicy.
Procedura podziału działa w taki sposób, że:
•
w pierwszym momencie odczytuje wartość elementu osiowego P (zazwyczaj jest to pierwszy element
tablicy)
•
w kolejnym kroku, tenże fragment tablicy jest dzielony (elementy tablicy są przemieszczane) tak, że po
lewej stronie od P znajdują się elementy <P, a po prawej >=P
•
ostatnim krokiem jest wykonanie tego samego dla tablicy (kawałka tablicy) po prawej stronie od P i po
lewej stronie od P. Dokonuje się to wywołując rekurencyjnie samą siebie.
Można się spotkać z różnymi wersjami tego algorytmu. Na przykład taki jak poniżej (dla Pascala):
Procedure QuickSort(Var Tab : Tablica);
Procedure Sort(Left,Right : Integer);
Var i,j : Integer;
x,temp : Integer;
Begin
i:=Left;
j:=Right;
X:=Tab[ (Left+Right) div 2];
Repeat
While Tab[i]<x do i:=i+1;
While x<Tab[j] do j:=j-1;
if i<=j Then
Begin
Temp:=Tab[i];
Tab[i]:=Tab[j];
Tab[j]:=Temp;
i:=i+1;
j:=j-1;
End;
Until i>j;
if Left<j Then Sort(L,j);
if i<Right Then Sort(i,Right);
End;
Begin
Sort(1,Ilosc);
End;
LEKCJA 11
Tryb graficzny [GRAPH.TPU]
Wstęp
Wszystkie procedury i funkcje związane z grafiką znajdują się w mdule GRAPH. By skorzystać z funkcji i
procedur jakie daje nam ten moduł należy najpierw przełączyć się do trybu graficznego. Do tego celu służy
procedura InitGraph. Jako pierwszy parametr podajemy typ sterownika graficznego, jaki mamy zainstalowany,
jako drugi parametr podajemy tryb, w jaki chcemy przejść i trzeci parametr określa ściężkę dostępu do plików
BGI. Trzeba zauważyć, że po skompilowaniu programu napisanego w trybie graficznym, może on u innej osoby
nie działać poprawnie. Z tego względu, że kompilator nie dołącza plików BGI oraz plików czcionek CHR
automatycznie do pliku wynikowego. Jak dołączyć pliki BGI do naszego programu dowiemy się w dalszej
części tego artykułu. Po przejściu w tryb graficzny niektóre procedury nie działają, m.in. Write i Writeln. Do
wyświetlania napisów służą inne procedury, ale o tym później.
Ogólna składnia InitGraph jest następująca:
InitGraph(var GraphDrive : Integer; var GraphMode : Integer; PathToDriver : String);
W miejsce GraphDrive i GraphMode podajemy wartości typu całkowitego np. 9, można również posłużyć się
stałym przyjmującymi wartości odpowiednich trybów np. VGA. Poniżej znajduje się tabela ze stałymi
określającymi kartę graficzną, czyli GraphDrive:
KARTA GRAFICZ2A
WARTOŚĆ
CurrentDriver
-128 (aktualny sterownik przesłany do procedury GetModeRange)
Detect
0 (automatyczne rozpoznanie sterownika graficznego)
CGA
1
MCGA
2
EGA
3
EGA64
4
EGAMono
5
IBM8514
6
HercMono
7
ATT400
8
VGA
9
PC3270
10
Jeśli więc nie wiemy, jaką kartę graficzną posiadamy możemy w jej miejsce wpisać wartość 0, bądz DETECT, a
komputer automatycznie rozpozna zainstalowaną kartę graficzną.
W poniższej tabeli zamieściłem stałe określające wartości dla różnych trybów graficznych. Wartość tą
wpisujemy do GraphMode:
STAŁA
WARTOŚĆ
ROZDZIELCZOŚĆ
2R. PALETY
LICZBA
STRO2
KOLORY
CGAC0
0
320x200
0
1
LightGreen,
LightRed,
Yellow
CGAC1
1
320x200
1
1
LightCyan,
LightMagenta,
White
CGAC2
2
320x200
2
1
Green, Red,
Brown
CGAC3
3
320x200
3
1
Cyan, Magenta,
LightGray
CGAHi
4
640x200
1
MCGAC0
0
320x200
0
1
LightGreen,
LightRed,
Yellow
MCGAC1
1
320x200
1
1
LightCyan,
LightMagenta,
White
MCGAC2
2
320x200
2
1
Green, Red,
Brown
MCGAC3
3
320x200
3
1
Cyan, Magenta,
LightGray
MCGAMed
4
640x200
1
MCGAHi
5
640x480
1
EGALo
0
640x200
4
16
EGAHi
1
640x350
2
16
EGA64Lo
0
640x200
1
16
EGA64Hi
1
640x350
1
4
EGAMonoHi
3
640x350
1
64K
HercMonoHi
0
720x348
2
ATT400C0
0
320x200
0
1
LightGreen,
LightLightRed,
Yellow
ATT400C1
1
320x200
1
1
LightCyan,
LightMagenta,
White
ATT400C2
2
320x200
2
1
Green, Red,
Brown
ATT400C3
3
320x200
3
1
Cyan, Magenta,
LightCray
ATT400Med
4
640x200
1
ATT400Hi
5
640x400
1
VGALo
0
640x200
4
16
VGAMed
1
640x350
2
16
VGAHi
2
640x350
1
16
PC3270Hi
0
720x350
1
IBM8514Lo
0
640x480
256
IBM8514Hi
1
1024x768
256
Jeśli nie znamy nazwy naszej karty graficznej, ani nie wiemy, jaki jest najlepszy tryb dla tej karty, możemy
posłużyć się procedurą, która rozpoznaje kartę i tryb. Ogólna jej składnia wygląda tak:
DetectGraph(var GraphDriver, GraphMode : Integer)
Po wykonaniu tej procedury parametry GraphDriver i GraphMode możemy podać do procedury InitGraph. Tak
więc by przejść do trybu graficznego, dla każdej karty graficznej (komputer sam ją rozpozna) należy napisać
następujący ciąg instrukcji:
uses Graph;
var Karta, Tryb : Integer;
begin
DetectGraph(Karta,Tryb);
InitGraph(Karta,Tryb,'c:\bp\bgi');
...
End.
Każdy ewentualny błąd jaki powstanie podczas wykonywania instrukcji graficznych zwraca funkcja
GraphResult. Wszystkie ewentulne błędy są reprezentowane przez stałe. Poniżej znajduje się tabela z kodami i
stałymi błędów, jaki zwraca funkcja GraphResult:
STAŁA
WARTOŚĆ
OPIS
grOK
0
operacja graficzna wykonana pomyślnie
grNoInitGraph
-1
nie zainstalowano trybu graficznego
grNoDetect
-2
nie wykryto karty graficznej
grFileNotFund
-3
nie znaleziono pliku sterownika graficznego (BGI)
grInvalidDriver
-4
zastosowano niewłaściwy do załadowania sterownik graficzny
grNoLoadMem
-5
brakuje pamięci do załadowania sterownika graficznego
grNoScanMem
-6
przekroczenie pamięci przy wypełnianiu obszaru metodą scan
grNoFloodMem
-7
przekroczenie pamięci przy wypełnianiu obszaru metodą flood
grFontNotFund
-8
nie znaleziono pliku definiującego czcionki
grNoFontMem
-9
brakuje pamięci do załadowania kroju czcionek
grInvalidMode
-10
zastosowano niewłaściwy tryb lub sterownik graficzny
grError
-11
błąd operacji graficznych
grIOerror
-12
błąd wejścia - wyjścia graficznego
grInvalidFont
-13
zastosowano niewłaściwy krój czcionek
grInvalidFontNum
-14
zastosowano niewłaściwy numer kroju czcionek
Zawsze na koniec pracy w trybie graficznym należy przywrócić tryb tekstowy, by nie wystąpiły ewentualne
błędy. Do zamknięcia trybu graficznego służy procedura CloseGraph. Jest to procedura bezparametrowa i
powoduje powrót do trybu tekstowego. W programach można wiele razy włączć i wyłączć tryb graficzny. Jeśli
już włączyłeś ten tryb i jesteś ciekaw jaką kartę graficzną masz zainstalowaną możesz to uczynić funkcją
GetDriverName. Zwraca ona łańcuch zawierający nazwę aktualnego sterownika graficznego. Funckja
GetModeName zwraca łańcuch zawierający nazwę aktualnego trybu graficznego.
W trybie graficznym każdy punkt na ekranie ma swoje współrzędne X i Y. Współrzędna X rośnie od lewej do
prawej, a Y z góry na dół. Punkt o współrzędnych X=1 i Y=1 leży w lewym górnym rogu ekranu. Moduł Graph
daje nam również dwie bardzo pożyteczne funkcje. GetMaxX i GetMaxY. Funkcja GetMaxX zwraca największą
wartość współrzędnej poziomej X, natomiast GetMaxY pionowej Y. Jeśli chcesz więc napisać program, który
niezależnie od karty graficznej, a co za tym idzie rozdzielczości wstawił punkt w samym środku ekranu użycie
tej funkcji jest niezbędne. Środek ekranu ma współrzędne X=GetMaxX div 2, a Y=GetMaxY div 2.
Większość z nas ma karty zgodne z VGA, więc będzie pracować w trybie graficzny określonym dla tych kart.
Niestety tryb ten daje nam do dyspozycji tylko 16 kolorów. Jak sprawdzić na innych kartach, lub potwierdzić
moje słowa o ilości dostępnych kolorów, należy posłużyć się funkcją pezparametrową GetMaxColor, która
zwraca największy z możliwych numerów koloru. W języku Turbo Pascal kolory mają swoje numery i stałe je
reprezentujące. Poniżej znajduje się tabela z kolorami i odpowiadjącymi im nazwami:
STAŁA
WARTOŚĆ
KOLOR
Black
0
czarny
Blue
1
niebieski
Green
2
zielony
Cyan
3
truskawkowy
Red
4
czerwony
Magenta
5
karmazynowy
Brown
6
brązowy
LightCray
7
jasnoszary
DarkCray
8
ciemnoszary
LightBlue
9
jasnoniebieski
LightGreen
10
jasnozielony
LightCyan
11
jasnotruskawkowy
LightRed
12
jasnoczerwony
LightMagenta
13
jasnokarmazynowy
Yellow
14
żółty
White
15
biały
Pierwsze kroki
Nauczyliśmy się już jak włączyć i wyłączyć tryb graficzny. Poradzimy sobie z ewentualnymi błędami. Potrafimy
również kożystać z funkcji GetMaxX i GetMaxY. Przejdźmy teraz do ciekawszych i przynoszących jakieś
efekty procedur i funkcji. Zacznijmy od najprostrzej procedury PutPixel. Ogólna składnia tej procedury jest
następująca:
PutPixel(X,Y : Integer; Pixel : Word);
Procedura wstawia w punkt o współrzędnych określonych przez X, Y i kolorze określonym przez Pixel. Jej
odwrotnością jest bardzo przydatna funkcja GetPixel. Tej składnia jest następująca:
GetPixel(X,Y : Integer);
Funkcja ta zwraca numer koloru punktu, króry mieści się na ekranie o współrzędnych określonych przez X i Y.
Przykładowy program z wykorzystaniem procedury PutPixel może wyglądać tak:
uses Graph;
var Karta, Tryb, i : Integer;
begin
DetectGraph(Karta, Tryb);
InitGraph(Karta, Tryb, 'c:\bp\bgi');
if GraphResult<>grOk then halt;
for i::=1 to 360 do PutPixel(GetMaxX div 2+Round(SIN(i)*10), GetMaxY div 2+Round(COS(i)*10),Yellow);
Readln;
CloseGraph;
End.
Powyższy program rysuje na środku ekranu (dzięki funkcjom GetMaxX div 2 i GetMaxY div 2) okrąg o
promieniu 10 i kolorze żółtym. Nie jest on najpiękniejszy, ale dla nas wystarczy. Oczywiście Pascal umożliwia
nam na prostrze rysowanie okręgów. Jest do tego celu specjalnie stworzona procedura. Składnia jej jest
następująca:
Circle(X,Y : Integer; Radius : Word);
Rysuje ona okrąg o środku w punkcie określonym przez współrzędne X ,Y i promieniu Radius. Promień jest
typu Word, a więc nie może przyjmować wartości ujemnych. Ten sam rezultat co wyżej za pomocą procedury
Circle wyglądał by tak:
uses Graph;
var Karta, Tryb, i : Integer;
begin
DetectGraph(Karta, Tryb);
InitGraph(Karta, Tryb, 'c:\bp\bgi');
if GraphResult<>grOk then halt;
SetColor(Yellow);
Circle(GetMaxX div 2, GetMaxY div 2, 10);
Readln;
CloseGraph;
End.
Procedura SetColor z parametrem Yellow, który jest typu Word, określa kolor w jakim zostanie narysowany
okrąg. Większość funkcji i procedur rysuje figury na kolor określony właśnie za pomocą tej procedury.
Wszystkie figury będą rysowane na kolor określony przez SetColor dopóki nie zostanie on zmieniony za pomocą
tej właśnie procedury. By uzyskać informacje o aktualnym kolorze, czyli takim jakim rysujemy, trzeba posłużyć
się bezparametrową funkcją GetColor. Zwraca ona numer aktualnego koloru. Do ustawiania koloru tła służy
procedura SetBKColor o składni:
SetBkColor(Color : Word);
gdzie Color - jest kolorem tła
By sprawdzić, jakie aktualnie mamy tło użyjemy funkcji GetBkColor. Zwraca ona numer koloru tła.
Kiedy mamy już zamazany cały ekran i przychodzi chwila, kiedy trzeba go wyczyścić, używamy procedury
ClearDevice.
Kolejnym często używanym poleceniem jest Line. Składnia tej procedury jest następująca:
Line(X1,Y1, X2, Y2 : Integer);
Procedura rysuje linię prostą o końcach o współrzędnych X1,Y1 i X2,Y2.
Odpowiednikiem procedury GotoXY w trybie graficznym jest procedura MoveTo. Składnia tej procedury jest
następująca:
MoveTo(X,Y : Integer);
Procedura przesuwa kursor na pozycję o współrzędnych określonych przez X,Y. W trybie graficznym można
używać również dwóch funkcji: GetX i GetY. Zwracają one wartość współrzędnej kursora (X lub Y).
Procedura MoveRel o takiej samej składni przesuwa wpółrzędne kursora względem aktualnej pozycji o X,Y.
Procedura LineTo o składni:
LineTo(Dx,Dy : Integer);
rysuje odcinek o współrzędnych: aktualnej pozycji kursora i współrzędnych punktu określonego przez Dx i Dy.
Procedura LineRel o takie samej składni rysuje linię od punktu o współrzędnych aktualnych przez aktualną
pozycję kursora, do punktu o współrzędnych przesuniętych względem pozycji kursora o Dx i Dy. Trochę to
zagmatfane, ale chyba wszyscy zrozumieli :-))).
Pascal umożliwia nam wybór rodzaju linii, jaką chcemy rysować. Do tego celu służy procedura SetLineStyle. Jej
składnia jest następująca:
SetLineStyle(LineStyle : Word; Pattern : Word; Thickness : Word);
Parametr LineStyle określa rodzaj linii, Pattern - wzorzec i Thickness - grubość. By dowiedzieć się jakim
aktualnie rysujemy stylem linii trzeba posłużyć się procedurą GetLineSettings. Jej składnia wygląda tak:
GetLineSettings(var LineInfo : LineSettingsType);
Procedura w zmiennej Linenfo, która jest typu LineSettingsType zwraca rodzaj, wzorzec oraz grubość linii,
którą aktualnie rysujemy. Typ LineSettingsType ma postać:
TYPE LineSettingsType = RECORD
LineStyle : Word;
Pattern : Word;
Thickness : Word;
END;
Narysujmy teraz przy pomocy linii prostokąt.
Line(100,50,200,50);
Line(200,50,200,150);
Line(200,150,100,150);
Line(100,150,100,50);
Do rysowania prostokątów Pascal daje nam odzielną procedurę. Powyższy program można zapisać jako:
Rectangle(100,50,200,150);
Procedura ta ma następującą składnię:
Rectangle(X1,Y1, X2, Y2 : Integer);
Współrzędne X1,Y1 są współrzędnymi lewego górnego rogu prostokąta, natomiast X2,Y2 prawego dolnego.
Można to sobie wyobrazić jako przekątną danego prostokąta.
Procedura Arc o składni:
Arc(X,Y: Integer; StAngle, EndAngle, Radius: Word);
powoduje narysowanie łuku okręgu o środku w punkcie X,Y i promieniu Radius. Początek łuku określony jest
przez StAngle, a koniec przez EndAngle. Podobną do instrukcji Arc jest procedura Ellipse. Ma ona następującą
składnię:
Ellipse(X,Y : Integer; StNagle, EndAngle : Word;XRadius,YRadius : Word);
Powoduje ona narysowanie wycinka elipsy o środku w punkcie X,Y, kącie początkowym StAngle, kącie
końcowym EndAngle oraz promieniach X-XRadius i Y-YRadius.
2apisy
By wstawić jakiś napis na ekran w trybie graficznym, nie można posłużyć się procedurami Write ani Writeln. W
Pascal'u zostały stworzone do tego celu specjalne procedury. Teksty są na ekranie rysowane, mogą być rysowane
różnymi czcionkami, dlatego wstawienie dwóch liter w tym samym miejscu ekranu, nie spowoduje zamazanie
tej pierwszej, tylko narysowanie jej na wcześniejszej.
Procedura OutText ma następującą składnię:
OutText(TextString : String);
Powoduje ona narysowanie napisu TextString na ekranie w miejscu określonym położeniem kursora. Do
określania położenia kursora używa się wcześniej opisaną procedurę MoveTo. Druga procedura do rysowania
napisów na ekranie ma następującą składnię:
OutTextXY(X,Y : Integer; TextString : String);
Różni się ona od poprzedniej tym, że możemy określić miejsce rysowania naszego napisu. Obie procedury
rysują napisy w kolorze określonym przez SetColor.
Do określania czcionki itp. służy procedura SetTextStyle. Jej struktura wygląda tak:
SetTextStyle(Font : Word; Direction : Word; CharSize : Word);
•
Font - rodzaj czcionki, (0..10)
•
Direction - kierunek (0-poziomo; 1-pionowo)
•
CharSize - wielkość czcionki (1..10)
Procedury OutText i OutTextXY pozwalają na wstawianie napisów na ekran. By wstawić jakąś liczbę, trzeba
posłużyć się procedurą Str:
Str(X[:Width [:Decimals] ]; var S);
Powoduje ona zmianę wartości numerycznej X na wartość łnńcuchową S. Odwrotnością jej jest procedura Val:
Val(S; var V; var Code : Integer);
Procedura ta powoduje zmianę wartości łańcuchową S na liczbową V. W przypadku wystąpienia jakiegoś błędu
zmienna Code ma wartość różną od 0.
W trybie graficznym każda litera, ciąg liter może mieć różną długość i wysokość. Do określania tych
właściwości służą dwie funkcje:
•
TextHeight(TextString : String);
•
TextWidth(TextString : String);
Pierwsza zwraca wysokość naszego tekstu (TextString), natomiast druga jego długość. By np. wstawić napis
BINBOY dokładnie na środku ekranu, napisalibyśmy:
...
Napis:='BINBOY';
OutTextXY(GetMaxX div 2-TextWidth(Napis) div 2,GetMaxY div 2-TextHeight(Napis) div 2, Napis);
...
Wypełnianie figur
Procedura FloodFill o składni:
FloodFill(X,Y : Integer; Border : Word);
powoduje wypełnienie wnętrza obszaru zamkniętego linią i obejmującego punkt o współrzednych X,Y. Brzeg
tego obszaru zostanie zaznaczony kolorem określonym przez Border. Wypełniany obszar jest w sposób
określony przez SetFillStyle.
< p>
Procedura ustala sposób wypełniania figur. Zmienna Pattern określa rodzaj wypełnienia (1..10), zmienna Color
ustala kolor wypełnienia.
Procedura Bar o składni:
Bar(X1,Y1,X2,Y2 : Integer);
Rysuje prostokąt w ten sam sposób co Rectangle, tyle że zostaje on wypełniony w sposób określony procedurą
SetFillStyle;
Podobną do instrukcji Bar jest procedura Bar3D. Ma ona następującą składnię:
Bar3D(X1,Y1, X2, Y2 : integer; Depth: Word; Top: Boolean);
Powoduje ona narysowanie trójwymiarowego wypełnionego prostopadłościanu. Ściana czołowa ma współrzędne
(X1,Y1) (X2,Y2). Zmienna Depth określa głębie prostopadłościanu, natomiast zmienna Top określa, czy ma być
rysowana górna powierzchnia prostopadłościanu.
Wycinanie obrazów
By wyciąć dany element obrazu trzeba przydzielić mu odpowiednią ilość pamięci. W tym celu trzeba użyć
funkcji ImageSize. Ma ona następującą składnię:
ImageSize(X1,Y1,X2,Y2 : Integer);
Gdzie za pomocą prostokąta o wierzchołkach X1,Y1 i X2,Y2 obliczamy ilość pamięci jaka będzie potrzebna do
zapamietania obrazka. Wiedząc już ile pamięci będzie nap potrzebne, trzeba przydzielić tą pamięć. Do tego celu
służy procedura GetMem. Ogólna jej składnia jest następująca:
GetMem(var P : Pointer; Size: Size);
Powoduje przydzielenie bloku pamięci o wielkości Size i zwraca wskaźnik na ten blok w zmiennej P. Odwołanie
do tego bloku następuje poprzez P^. By sprawdzić ile w danej chwili mamy dostępnej pamięci trzeba użyć
funkcji MaxAvail, która zwraca jej wartość. Po zakończeniu programu należy zwolnić przydzieloną wcześniej
pamięć używając procedury o składni:
FreeMem(var P : Pointer; Size: Word);
Powoduje ona zniszczenie zmiennej wskazywanej przez P i zwolnienie zajmowanej przez nią pamięci.
Mając już przydzieloną pamięć należy skopiować do niej nasz rysunek. Do tego celu służy procedura GetImage
o składni:
GetImage(X1,Y1,X2,Y2 : Integer; var BitMap);
Gdzie za pomocą X1,Y1 i X2,Y2 ustalamy okno, które jest kopiowanej pod adres BitMap.
Mamy już zapamietany obrazek. By go wyświetlić posłużymy się procedurą PutImage. Ma ona następującą
składnię:
PutImage(X,Y : Integer; var BitMap; BitBlt : Word);
Procedura ta służy do wyświetlania na ekranie uprzednio zapamiętanego prostokątnego obrazu po zmienną
BitMap. Współrzędne X,Y określają lewy górny róg tego obrazka, a parametr BitBld określa stosowany operator
binarny podczas nakładania zapamiętanego obrazu na ekranie. Może on przyjąć następujące wartości:
•
CopyPut 0 (operacja MOV)
•
XORPut 1 (operacja XOR)
•
ORPut 2 (operacja OR)
•
ANDPut 3 (operacja AND)
•
NOTPut 4 (operacja NOT)
Strony
Turbo Pascal umożliwia nam pracę na kilku stronach graficznych, w zależności od rodzaju i trybu pracy karty
graficznej. Jest to bardzo przydatne. Do obsługi stron służą dwie procedury:
SetActivePage(Page : Word);
Ustala aktywną stronę, czyli są na której będziemy rysować,oraz
SetVisualPage(Page : Word);
Ustala stronę, którą w danej chwili widzimy. Stosując strony można np. wyświetlić napis "Loading...", podczas
którego przygotowywać kolejną stronę. Jeśli pisałeś kiedyś jakąś animację, na pewno ekran strasznie skakał.
Było widać jak rysuje się dany element, a później ściera. Strony pozwalają je wyeliminować.
Dołączanie sterowników
Zauważyłeś pewnie, że po skompilowaniu programu jeśli zaniesiesz go koledze, to może nie działać.
Spowodowane jest to, że albo ten kolega nie ma sterowników BGI używanych w twoim programie, albo ma je w
innym miejscu. Sterowniki BGI są odpowiedzialne za obsługę grafiki i nie są dołączane do pliku
wykonywalnego EXE. Jednak można to zrobić samemu. W tym celu trzeba zrobić:
•
Utworzyć pliki OBJ z plików BGI. Do tego celu służy program BINOBJ. Jego użycie jest następujące:
BINOBJ <plikBGI> <plikOBJ> <NazwaProcedury>
•
Jeśli mamy już pliki OBJ dołączamy je do naszego programu używając dyrektywy $L, np. {$L
EGAVGA.OBJ}
•
Tworzymy procedury EXTERNAL procedure EgaVgaDriverProc : external;
•
Teraz musimy tylko zarejestrować obecność sterownika w pliku:
RegisterBGIDriver(@EGAVGADriverProc); Jest to funkcja. Jeśli przyjmie ona wartość <0 tzn. że
wystąpił błąd.
•
Inicjujemy tryb graficzny InitGraph(karta,tryb,'');
W ten sam sposób można dołącza do pliku sterowiniki do czcionek. Postępowanie jest takie same, tylko
rejestrujemy je komendą RegisterBGIFont.