Dr inż. Robert Wójcik
E-mail: wojcik@ict.pwr.wroc.pl
Języki i metody programowania
2. Struktura programu w języku Pascal 2.1. Program sekwencyjny
2.2. Elementy języka 2.3. Typy danych
2.4. Definiowanie stałych i deklarowanie zmiennych 2.5. Modyfikowanie zawartości zmiennych
2.6. Standardowe wejście i wyjście
2. Struktura programu w języku Pascal
2.1. Program sekwencyjny
Działania określone w algorytmie są zapisywane za pomocą instrukcji języka programowania (np. writeln, readln). Każda instrukcja języka ma określone znaczenie i sposób użycia (np. wypisanie tekstu na ekranie writeln(’To jest tekst’)). Instrukcje są budowane z elementów leksykalnych, do których należą:
słowa kluczowe (słowa angielskie o określonym znaczeniu w języku programowania, np. begin, end, procedure, const, var),
identyfikatory (np. nazwy zmiennych),
liczby (np. całkowite, rzeczywiste),
napisy (np. ’To jest napis’),
komentarze (np. { to jest komentarz } ),
separatory (np. średnik, kropka, dwukropek, spacja).
Elementy leksykalne są budowane ze zbioru symboli podstawowych języka Pascal, na który składają się: litery, cyfry, znaki specjalne.
Program w języku Pascal składa się z:
części deklaracyjnej (deklaracje modułów, definicje stałych, deklaracje zmiennych, procedur i funkcji),
części wykonawczej (zawiera instrukcje realizujące określony algorytm).
Program może być poprzedzony nagłówkiem, który składa się ze słowa kluczowego Program, nazwy programu i średnika.
Najprostszy program nie wykonuje żadnego zadania, a jedynie zawiera informacje o miejscu rozpoczęcia programu (begin) i miejscu jego zakończenia (end).
Przykład 2.1. Najprostszy program.
BEGIN {początek programu}
{ komentarz - najprostszy program w języku Pascal } END. { koniec programu }
Program ten można uzupełnić o nagłówek zawierający nazwę programu.
START
STOP
START
STOP Wyświetl tekst:
’To jest tekst!’
Czekaj na Enter Program M1; { nagłówek }
BEGIN
{ program z nagłówkiem } END.
Do programu można wprowadzać dane wejściowe z urządzeń wejścia
(np. z klawiatury) lub z plików dyskowych oraz można wyprowadzać wyniki do urządzeń wyjścia (np. monitor, drukarka) lub do plików dyskowych.
W praktyce urządzenia wejścia / wyjścia są traktowane jak pliki o unikalnych nazwach, np. ’CON’ – monitor (dla wyjścia), klawiatura (dla wejścia), ’LPT1’ – drukarka. Do wyprowadzania danych z programu (domyślnie na ekran) służą procedury write, writeln, natomiast do wczytywania danych do programu (domyślnie z klawiatury) służą procedury read i readln.
Przykład 2.2. Wyprowadzenie napisu na ekran i zatrzymanie programu w oczekiwaniu na Enter.
Begin {początek programu}
writeln('To jest tekst!');
readln; { czekaj na enter } End. { koniec programu }
Przykład 2.3. Obliczanie sumy dwóch liczb całkowitych a i b.
Schemat blokowy
Podczas pisania programów należy pamiętać o tym, że na danym etapie programu można używać tylko tych elementów, które wcześniej zostały zdefiniowane lub są elementami standardowymi języka. W kolejnym przykładzie w celu wykorzystania procedury umożliwiającej czyszczenie ekranu dołączono moduł crt zawierający deklarację procedury clrscr.
Program dodawania dwóch liczb całkowitych
uses crt; { modul definiujacy procedure clrscr }
START
STOP Czekaj na Enter
Czyść ekran
Wczytaj a i b
suma = a + b
Pisz
’Suma liczb = ’, suma
{ obliczanie sumy liczb całkowitych}
Var a, b: integer; { zmienne calkowite od -32768.. 32767 } suma1, suma2: longint;
{ suma1,suma2 - zmienne calkowite o wiekszym } { zakresie od -2147483648..2147483647 }
Begin {początek programu}
clrscr; { czyszczenie ekranu }
write('Podaj liczbe calkowita a = '); readln(a);
write('Podaj liczbe calkowita b = '); readln(b);
suma1:=a+b; {obliczenie suma1 – możliwość przepełnienia } {zakresu integer dla a = b = 20000 }
suma2:=longint(a)+b; { obliczenie suma2 } writeln('Suma_1 liczb = ', suma1);
writeln('Suma_2 liczb = ', suma2);
readln; { czekaj na enter } End. { koniec programu }
W niniejszym programie zadeklarowano dwie zmienne całkowite a i b typu integer oraz zmienne suma1 i suma2 typu longint. W przypadku, gdy wprowadzone zostaną wartości a=20000 oraz b=20000, które są dopuszczalne dla zmiennych typu integer, uzyskane wyniki będą następujące:
suma1=a+b=-25536 (wynik błędny) oraz suma2=longint(a)+b=40000 (wynik poprawny).
W przypadku sumowania dwóch liczb typu integer wynik jest składo- wany w zmiennej pomocniczej, której typ jest typem składnika o większym zakresie. W rozpatrywanym przypadku wynik dodawania 40000 jest składowa- ny w zmiennej pomocniczej typu integer, której zakres wartości należy do przedziału -32768...32767. Zmienne typu integer są pamiętane na dwóch bajtach, gdzie najstarszy bit jest bitem znaku. W zapisie szesnastkowym i binarnym pom = 40000 = 9C40 hex = 1001 1100 0100 0000 bin. Ustawiony najstarszy bit oznacza, że jest to liczba ujemna. Wartość modułu liczby wyznacza się dokonując negacji bitów i dodając jeden. Stąd, wartość zmiennej suma1 = - (0110 0011 1100 0000 bin) = - (63C0 hex) = -25536 (wynik sumowania jest błędny).
W drugim przypadku dokonano konwersji (rzutowania) typu zmiennej a do typu longint. Wynik dodawania jest składowany w zmiennej pomocniczej typu longint. Stąd, wartość zmiennej suma2 = 40000 (wynik sumowania jest poprawny).
Wniosek: podczas wykonywania operacji na zmiennych należy pamiętać, aby
właściwie dobrać ich typy, tak aby nie dochodziło do przekroczenia zakresu.
Przykład 2.4. Zmienne całkowite można wyprowadzać na określonej liczbie pozycji ekranowych. W tym celu należy w procedurze writeln podać po dwukropku liczbę pozycji dla zmiennej, np. writeln(’Zmienna x = ’, x:5).
Zmienna całkowita x zostanie wyprowadzona na 5 polach ekranowych. Puste pola zostaną wypełnione spacjami. Jeśli liczba zajmuje więcej niż 5 pól, to zostanie ona wyprowadzona w całości.
W przypadku liczb rzeczywistych można podać liczbę pozycji przeznaczonych dla zmiennej (łącznie z kropką dziesiętną i znakiem) oraz liczbę uwzględnianych cyfr po przecinku (ostatnia cyfra liczby będzie zaokrąglona na podstawie cyfry poprzedniej), np. writeln(’Zmienna y = ’, y:9:2). Zmienna rzeczywista y zostanie wyprowadzona na 9 polach z uwzględnieniem 2 miejsc po przecinku.
uses crt;
var x: integer; { zmienna typu całkowitego } y: real; { zmienna typu rzeczywistego } Begin {początek programu}
x:=200;
clrscr; { czyszczenie ekranu }
writeln(‘Zmienna x = ‘, x:1); {200 } writeln(‘Zmienna x = ‘, x:2); {200 } writeln(‘Zmienna x = ‘, x:3); {200 } writeln(‘Zmienna x = ‘, x:4); { 200 } writeln(‘Zmienna x = ‘, x:5); { 200}
readln;
y:=1.235;
writeln(y:2:2); { 1.24 } writeln(y:3:2); { 1.24 } writeln(y:4:2); { 1.24 } writeln(y:5:2); { 1.24 } writeln(y:6:2); { 1.24 } writeln(y:7:2); { 1.24 } writeln(y:8:2); { 1.24}
readln;
End.
Ogólna struktura programu w języku Pascal
program nazwa_programu; {Nagłówek programu - opcjonalny}
... { SEKCJA DEKLARACJI } uses lista_nazw_modułów ;
const sekwencja_definicji_stałych ; {Definicje stałych}
type sekwencja_definicji_typów ; {Definicje typów}
label lista_etykiet ; {Deklaracja etykiet}
var sekwencja_deklaracji_zmiennych ; {Deklaracje zmiennych}
procedure nazwa_procedury_1 ; {Definicje procedur}
begin { Definicje składowych procedury_1 – kod procedury } end;
procedure nazwa_procedury_2 ( lista_parametrów ) ;
begin { Definicje składowych procedury_2 – kod procedury } end;
. . .
function nazwa_funkcji_1 : typ_wartosci ; {Definicje funkcji}
begin
{ Definicje składowych funkcji_1 – kod funkcji }
nazwa_funkcji_1:= wynik; { przekazanie wyniku funkcji na zewnątrz } end;
function nazwa_funkcji_2( lista_parametrów ) : typ_wartości ; begin
{ Definicje składowych funkcji_2 – kod funkcji }
nazwa_funkcji_2:= wynik; { przekazanie wyniku funkcji na zewnątrz } end;
. . .
... { SEKCJA INSTRUKCJI } begin
instrukcja_1 ; instrukcja_2 ; . . .
instrukcja_N ; end .
Struktura programu wykonywalnego w języku Pascal
Program wykonywalny przeznaczony dla systemu DOS rezerwuje w
pamięci operacyjnej obszar przeznaczony na segment kodu programu,
segment danych programu, segment stosu programu i stertę.
Segment kodu programu - fragment pamięci, w której umieszczone są instrukcje realizowane w programie (może być kilka modułów po 64 KB).
Segment danych programu - fragment pamięci, w której znajdują się zmienne globalne umieszczone w części deklaracyjnej programu; są to zmienne statyczne istniejące przez cały czas działania programu; obszar ten zajmuje 64 KB.
Segment stosu (stos) - fragment pamięci, w której przechowywane są zmienne lokalne i adresy powrotów z procedur i funkcji; obszar ten może zajmować maksymalnie 64KB.
Sterta - fragment pamięci, w której tworzone i przechowywane są zmienne dynamiczne; dla tych zmiennych pamięć może być alokowana i zwalniana na bieżąco w trakcie działania programu; obszar ten może zajmować całą dostępną pamięć do 640KB.
Uwaga: pamięć jest rezerwowana zawsze w kierunku rosnących adresów.
Model pamięci programu wykonywalnego w trybie rzeczywistym DOS 2.2. Elementy języka
Elementy leksykalne języka, tj. słowa kluczowe, identyfikatory, liczby, napisy, komentarze i separatory są budowane ze zbioru symboli języka.
Zbiór symboli języka: małe i wielkie litery, cyfry, symbole operatorów
arytmetycznych (np. +, -), symbole operatorów relacji (np. <, <=, <>), symbole
nawiasów, symbole znaków przestankowych (np. kropka, średnik, dwukropek) oraz symbole innych znaków mających specjalne znaczenie.
Symbole leksykalne:
słowa kluczowe: słowa w języku angielskim mające określone znaczenie w języku programowania, np. begin, end, const, type, do, else, procedure, function i inne; nie mogą być przedefiniowywane;
identyfikatory: ciąg liter, cyfr lub znaków pokreślenia, zaczynający się od litery lub podkreślenia (np. x, y_1, wynik, _a34); reprezentują nazwy elementów programu, tj. nazwy zmiennych i stałych, nazwy typów danych, nazwy procedur i funkcji, oraz inne nazwy; nie mogą zawierać znaku spacji;
małe i wielkie litery nie są rozróżniane; maksymalna długość identyfikatora zależy od kompilatora, np. dla systemu Turbo Pascal wynosi ona 63 znaki;
niektóre identyfikatory mogą być standardowo zdefiniowane w danej implementacji języka; są to wówczas słowa zastrzeżone języka reprezentujące nazwy typów zmiennych (np. char, integer, real), nazwy stałych (np. Maxint) lub nazwy procedur i funkcji (np. cos, sin, dec, readln, writeln, sqrt, sqr, round, abs, ord, chr, inc, true, false); słowa zastrzeżone mogą być przedefiniowywane w przez programistę, ale wówczas tracą swoje znaczenie, np. można zadeklarować zmienną o nazwie char typu real (char: real; gdzie char jest nazwą typu znakowego służącego do przechowywania znaków kodu ASCII – znaki o kodach od #0 .. #255) i potem dokonać podstawienia char:=5;
liczby: ciąg znaków będących cyframi (np. 124, -12, +34, 1.23, 1E-2); mogą być poprzedzone znakiem (+) lub (-), który określa znak liczby; liczby rzeczywiste mogą być zapisywane w postaci wykładniczej, jako potęgi 10 (np. 3e2, 9.0e-2); przed kropką dziesiętną muszą zawierać co najmniej jeden znak (.1e2 – błąd); liczby w kodzie szesnastkowym są poprzedzone znakiem $ (np. $41 = 65; x:=$30);
napisy (łancuchy): ciągi znaków umieszczone pomiędzy dwoma
apostrofami, np. ’To jest napis’, ’Tekst na ekran’; w celu wyprowadzenia
apostrofu należy poprzedzić go apostrofem, np. ’To jest ”Turbo Pascal’’ i to
też’; maksymalna długość tekstu zależy od implementacji; w systemie
Turbo Pascal wynosi ona 255; w systemie tym istnieje typ string, który
umożliwia deklarowanie zmiennych typu łańcuchowego o podanej długości
(np. var nap: string[20] – długość 20 znaków; d: string – długość 255
znaków);
komentarze: ciągi znaków umieszczane pomiędzy parą nawiasów klamrowych { } lub (* *), np. { komentarz }, (* komentarz *); treść komentarza nie podlega kompilacji;
separatory: symbole służące do oddzielenia elementów i symboli leksykal- nych; są to najczęściej: spacja, symbole operatorów arytmetycznych, logicznych i relacji, znaki przestankowe, dwukropek; dwa dowolne identyfikatory muszą być rozdzielone separatorem; każda deklaracja lub instrukcja kończy się średnikiem; znak kropki kończy program (np. end.).
Za pomocą elementów leksykalnych języka kodowane są określone działania.
Przykład 2.5. Wyprowadzanie tekstu na zadanej pozycji ekranu. Wykorzysta- nie procedury GotoXY(a,b), która ustawia kursor na pozycji (a,b) ekranu i jest standardową procedurą systemu Turbo Pascal 7.0.
uses crt;
Begin {początek programu}
clrscr; { czyszczenie ekranu }