Języki programowania

advertisement
040 PROGRAMOWANIE
Prof. dr hab. Marek Wisła
Programowanie
• Programowanie to zapisywanie algorytmów w postaci
programów w językach zrozumiałych przez komputer
(czyli językach programowania), a właściwie
zrozumiałych przez specjalne programy zwane
translatorami, które mogą je (te programy) przekształcić
(przetłumaczyć) na ciągi rozkazów zapisane w języku
znanym przez komputer, zwanym językiem
maszynowym, w celu zmuszenia komputera do
wykonania pewnych czynności, np. rozwiązania
równania kwadratowego, obliczenia podatku,
narysowania koła na ekranie monitora, wysłania poczty
e-mail itp.
Programowanie jako proces
• W ogólności programowanie to złożony proces obejmujący:
• projektowanie:
• analiza wymagań
• specyfikacja programu
• kodowanie, czyli zapis w wybranym języku programowania
• przetłumaczenie, czyli translację na język maszynowy
• testowanie
• weryfikacja - czy program jest zgodny ze specyfikacją?
• walidacja - czy program jest zgodny z oczekiwaniami użytkownika?
• dokumentowanie
• dokumentacja użytkownika
• dokumentacja techniczna
• integrowanie i wdrażanie
• pielęgnowanie programu.
Algorytm
• W potocznym rozumieniu algorytm to metoda
rozwiązywania jakiegoś problemu (zadania,
wykonywania pewnych czynności), inaczej mówiąc, to nie
dopuszczający wieloznacznej interpretacji formalny
przepis (recepta) postępowania.
• Nie wymaga się przy tym rozumienia treści
rozwiązywanego zagadnienia, wystarczy ściśle wypełniać
podane w algorytmie wskazówki.
• Algorytm obrazuje metodę rozwiązywania danego
problemu za pomocą skończonej liczby operacji, gdy
rozwiązanie istnieje lub też metodę zatrzymującą
postępowanie po skończonej liczbie operacji, gdy
rozwiązanie nie istnieje.
Program
• Algorytm zapisany w języku programowania nazywamy
programem.
Język programowania
• Język programowania to formalny (sztuczny) język
służący do formułowania (zapisywania) algorytmów oraz
innych zadań, jakie komputer ma wykonać.
• Postać programu wyrażona w języku programowania
określana jest jako kod źródłowy.
• Język programowania to zbiór zasad określających kiedy
ciąg symboli stanowi program, czyli zapis opisujący
obliczenia, oraz jakie obliczenia ten zapis oznacza.
• Podobnie jak języki naturalne, język programowania
składa się ze zbiorów reguł syntaktycznych oraz
semantycznych, które opisują, jak należy budować
poprawne wyrażenia języka oraz jak komputer ma je
„rozumieć”.
Syntaktyka
• Aby dany ciąg znaków mógł być rozpoznany jako program
napisany w danym języku, musi spełniać reguły składni.
• Składnia (syntaktyka) opisuje:
• rodzaje dostępnych symboli – alfabet języka
• zasady, według których symbole mogą być łączone w większe
struktury
• Składnia najczęściej opisywana jest formalnie za pomocą
wyrażeń regularnych oraz notacji BNF (Backus-Naur Form) lub
Extended BNF.
• Przykład: notacja BNF
• <wyrażenie> ::= <składnik> | <wyrażenie> + <składnik>
• <składnik> ::= <czynnik> | <składnik> * <czynnik>
• <czynnik> ::= ( <wyrażenie> ) | a | b | c
Semantyka
• Semantyka języka programowania definiuje precyzyjnie
znaczenie poszczególnych symboli oraz ich funkcję w
programie.
• Semantykę najczęściej definiuje się słownie, ponieważ
większość jej elementów jest trudna lub wręcz niemożliwa
do ujęcia w jakikolwiek formalizm.
• Metody określania semantyki języka programowania:
• semantyka aksjomatyczna - zbiór aksjomatów i reguł
wnioskowania
• semantyka denotacyjna - znaczenie przypisują funkcje waluacji
• semantyka operacyjna - interpretacja z pomocą abstrakcyjnej
maszyny
• semantyka algebraiczna - wykorzystuje pojęcia algebraiczne.
Typy danych
• Język programowania operuje na jakimś zestawie
danych, dlatego niezbędne jest podzielenie danych na
odpowiednie typy, zdefiniowanie ich właściwości oraz
operacji, jakie można na nich realizować.
• Podstawowe typy danych:
• liczby całkowite (stałopozycyjne) – ograniczony zakres
• liczby zmiennopozycyjne – znacznie szerszy, ale
ograniczony zakres
• wartości logiczne – false i true
• ciągi znaków – teksty, łańcuchy znaków
Złożone typy danych
• Złożone typy danych:
• tablice – ciągi, macierze, …, wartości tego samego typu
• listy – ciągi o zmiennej długości, wartości różnych
typów
• rekordy – zestawy wartości różnych typów
• zbiory – odpowiedniki zbiorów w matematyce
• inne, zależnie od języka
Liczby zmiennopozycyjne
• Liczba zmiennopozycyjne (zmiennoprzecinkowe) –
reprezentacja liczby rzeczywistej zapisanej za pomocą notacji
naukowej.
• Wartość liczb zmiennopozycyjnej jest obliczana według wzoru:
𝑥 = 𝑧 ⋅ 𝑚 ⋅ 𝑏𝑒
gdzie:
• z – znak liczby 1 lub -1
• b – baza (b=2 dla systemów komputerowych)
• m – znormalizowana mantysa, liczba ułamkowa (𝟏 ≤ 𝒎 < 𝒃)
• e - wykładnik - liczba całkowita.
• Przykłady (dla bazy 𝑏 = 10 i ilości cyfr mantysy 4):
• 60,89523 = 6,089 ⋅ 101
• 0,0000125 = 1,25 ⋅ 10−5
Implementacje sprzętowe
• W implementacjach sprzętowych liczby
zmiennopozycyjne wyraża się liczbami dwójkowymi
(𝑏 = 2). Ma to następujące zaletę:
• mantysa należy do przedziału [1,2), jest więc postaci 1.xxxxx.... (x
– bit o dowolnej wartości). Ponieważ część całkowita jest znana, i
równa zawsze 1, więc nie jest zapamiętywana - daje to dodatkowy
bit na część ułamkową.
Operacje na liczbach zmiennopozycyjnych
• Arytmetyka zmiennopozycyjna nie jest łączna i rozdzielna!
Oznacza to, że można podać przykłady liczb 𝑥, 𝑦 i 𝑧 takich, że
• 𝑥+𝑦 +𝑧 ≠𝑥+ 𝑦+𝑧
• 𝑥⋅𝑦 ⋅𝑧 ≠𝑥⋅ 𝑦⋅𝑧
• 𝑥⋅ 𝑦+𝑧 ≠ 𝑥⋅𝑦 + 𝑥⋅𝑧
• Innymi słowy, kolejność wykonywania operacji wpływa na
końcowy wynik.
• Przy obliczeniach zmiennopozycyjnych występują też
anomalie:
• zaokrąglenia,
• nieprawidłowe operacje,
• przepełnienie,
• niedomiar.
Podział języków programowania
• Języki wewnętrzne komputera (języki maszynowe):
rozkazy procesora reprezentowane w formie binarnej
• Języki asemblera (klasa języków):
kody binarne rozkazów procesora i adresy binarne
komórek pamięci zastąpiono kodami i adresami
symbolicznymi
• Języki wysokiego poziomu (autokody):
operują instrukcjami ukierunkowanymi na potrzeby
dziedziny, której mają służyć, a nie instrukcjami
dobranymi, jak w przypadku asemblera, według specyfiki
rozkazów procesora.
Język maszynowy
• Program w języku maszynowym ma postać ciągu liczb
(reprezentowanych w postaci binarnej), które
odpowiadają rozkazom i danym bezpośrednio
pobieranym przez procesor wykonujący ten program:
• każdy typ procesora ma swój własny język
maszynowy, zatem kod maszynowy nie może być
wykonywany przez procesor innego typu
• kod jest praktycznie nieczytelny dla człowieka
• kod maszynowy jest generowany za pomocą
translatora, który przekształca czytelny dla programisty
zapis w języku programowania wysokiego poziomu w
kody rozkazów maszynowych
Języki asemblera (asemblery)
• Klasa języków programowania niskiego poziomu, których jedno
polecenie odpowiada zasadniczo jednemu rozkazowi
procesora
• języki te powstały na bazie języków maszynowych danego
procesora poprzez zastąpienie kodów binarnych rozkazów i
adresów binarnych komórek pamięci mnemonikami
(adresami i kodami symbolicznymi)
• bezpośrednia odpowiedniość mnemoników oraz kodu
maszynowego umożliwia zachowanie wysokiego stopnia
kontroli programisty nad działaniem procesora.
• Asemblery umożliwiają pełne wykorzystanie możliwości
procesora (szybkość), wady to pracochłonność
programowania i konieczność wnikania w budowę procesora.
Asembler
• Asembler to także program dokonujący tłumaczenia języka
asemblera na język maszynowy, czyli tzw. asemblacji
• Przykładowe polecenia asemblera MASM dla procesora
8086/8088:
MOV c, z
MOV ax, cx
ADD c, z
SUB c, z
prześlij do c wartość z (c:=z)
prześlij do rejestru ax zawartość rejestru cx
(ax:=cx)
dodaj do c zawartość z, (c:=c+z)
odejmij od c wartość z, (c:=c-z)
Przykład programu:
mov
mov
mov
mov
int
ax,
es,
al,
ah,
21h
0D625h
ax
24
0
Języki wysokiego poziomu
• Języki wysokiego poziomu operują instrukcjami
ukierunkowanymi na potrzeby dziedziny, której mają
służyć:
• składnia i słowa kluczowe mają maksymalnie ułatwić rozumienie
kodu programu dla człowieka, tym samym zwiększając poziom
abstrakcji
• programowanie w tych językach zwalnia programistę od myślenia o
szczegółach sprzętowych, za wygodę płaci się jednak
efektywnością programu.
Języki wysokiego poziomu
• Od początku lat 50-tych XX w. opracowano setki języków
(wiele już nie istnieje) i ciągle powstają nowe. Przyczyny
tego faktu to:
• nowe dziedziny zastosowań
• nowe możliwości sprzętowe (programowanie
współbieżne)
• nowe techniki programowania (programowanie
obiektowe, języki wizualne ze wsparciem graficznym).
Paradygmat programowania
• Paradygmat programowania to określony wzorzec
programowania, który definiuje sposób patrzenia
programisty na przepływ sterowania i wykonywanie
programu komputerowego.
• Najbardziej znane paradygmaty programowania to:
• programowanie imperatywne
• programowanie proceduralne
• programowanie obiektowe
• programowanie funkcyjne
• programowanie w logice (programowanie logiczne)
• programowanie zdarzeniowe.
Programowanie imperatywne
• Programowanie imperatywne jest najbardziej pierwotnym
sposobem programowania.
• program postrzegany jest jako ciąg poleceń dla komputera
• programista jawnie, krok po kroku definiuje jak wykonać zadanie
• obliczenia to sekwencja poleceń (instrukcji) zmieniających krok po
kroku stan komputera, aż do uzyskania oczekiwanego wyniku (stan
komputera to zawartość jego całej pamięci oraz rejestrów
procesora)
• sposób patrzenia na programy związany jest ściśle z budową
sprzętu komputerowego o architekturze von Neumanna, w którym
poszczególne instrukcje (w kodzie maszynowym) to właśnie
polecenia zmieniające ów globalny stan (przykładowo, instrukcje
podstawienia działają na danych pobranych z pamięci i
umieszczają wynik w tejże pamięci, abstrakcją komórek pamięci są
zmienne)
• Programowanie imperatywne uważane jest za synonim
programowania proceduralnego.
Elementy języka imperatywnego
• W językach imperatywnych można wyróżnić wiele wspólnych
elementów:
• instrukcje przypisania wykonują pewne zadanie na zlokalizowanych w
•
•
•
•
pamięci danych i zapisują tam wynik działania,
możliwe jest wykonywanie złożonych obliczeń wyrażeń składających się z
operacji arytmetycznych i logicznych oraz funkcji,
instrukcje warunkowe wykonują pewien blok kodu tylko wtedy, kiedy
spełniony jest określony warunek, w przeciwnym razie blok ten jest
pomijany podczas wykonywania,
instrukcje pętli umożliwiają wielokrotne wykonanie tego samego kodu, w
zależności od potrzeb, „wielokrotność” może oznaczać pewną określoną z
góry ilość powtórzeń lub wykonywanie fragmentu kodu do czasu
spełnienia pewnych warunków,
możliwe jest przekazanie sterowania do zupełnie innej części programu,
co jest realizowane poprzez skok bezwarunkowy (tego mechanizmu nie
dopuszcza programowanie strukturalne) oraz wywołanie procedury.
Przykład
programu
w Pascalu
program trojmian_kwadratowy;
{$APPTYPE CONSOLE}
uses SysUtils;
var a, b, c, delta, x1, x2 : real;
begin
writeln ('Podaj wspolczynniki a, b, c trojmianu kwadratowego: ');
readln (a, b, c);
delta := b*b-4*a*c;
if delta < 0 then writeln ('BRAK MIEJSC ZEROWYCH !')
else if delta > 0 then
begin x1 := (-b-sqrt(delta))/(2*a);
x2 := (-b+sqrt(delta))/(2*a);
writeln ('X1 = ' , x1);
writeln ('X2 = ' , x2);
end else begin
x1 := -b/(2*a);
writeln ('X1 = ' , x1);
end;
readln;
end.
Programowanie obiektowe
• Programowanie obiektowe:
• program to zbiór powiązanych się ze sobą obiektów, czyli
jednostek zawierających określone dane i umiejących wykonywać
na nich (tych danych) określone operacje
• umożliwia modelowanie zjawisk świata rzeczywistego w
uporządkowany, hierarchiczny sposób – od idei do szczegółów
technicznych.
Cechy programowania obiektowego
• Cechami charakterystycznymi programowania
obiektowego są:
• powiązanie (enkapsulacja) danych (czyli stanu) z operacjami na
nich (czyli poleceniami) w całość, stanowiącą odrębną jednostkę –
obiekt,
• mechanizm dziedziczenia, czyli możliwość definiowania nowych,
bardziej złożonych obiektów na bazie obiektów już istniejących,
• polimorfizm, czyli realizowanie przez operację różnych działań w
zależności od tego, do jakiego typu obiektu aktualnie się odnosimy.
• Najważniejsze języki obiektowe to: C++, Java, C#,
VB.NET, PHP i Python.
Przykład programu w Pythonie
#!/usr/bin/env python
class koszyk:
def __init__ (self):
self.koszyk = []
def dodaj(self,obiekt):
self.koszyk.append(obiekt)
def rozmiar(self):
return len(self.koszyk)
s = koszyk()
s.dodaj(„alfa")
s.dodaj(„beta")
print s.rozmiar()
del s
Programowanie funkcyjne
• Programowanie funkcyjne:
• program to złożona funkcja (w sensie matematycznym), która
otrzymawszy dane wejściowe wylicza pewien wynik
• zasadniczą różnicą w stosunku do poprzednich paradygmatów jest
brak stanu maszyny: nie ma zmiennych, a co za tym idzie nie ma
żadnych efektów ubocznych
• konstruowanie programów to składanie funkcji, zazwyczaj z
istotnym wykorzystaniem rekurencji
• charakterystyczne jest również definiowanie funkcji wyższego
rzędu, czyli takich, dla których argumentami i których wynikami
mogą być funkcje.
• Najbardziej znane języki funkcyjne to : Lisp, Scheme i
Haskell.
Przykład programu w Scheme
(define silnia
(lambda (x)
(if (= x 0)
1
(* x (silnia (- x 1))))))
(define fib
(lambda (n)
(cond ((= n 0) 0)
((= n 1) 1)
(else (+ (fib (- n 1)) (fib (- n 2)))))))
(silnia 5)
(fib 10)
Programowanie w logice
• Podobnie jak w programowaniu funkcyjnym, nie „wydajemy rozkazów”, a
•
•
•
•
•
jedynie opisujemy, co wiemy i co chcemy uzyskać (języki funkcyjne i
logiczne nazywa się łącznie językami deklaratywnymi).
Na program składa się zbiór zależności (przesłanki – reguły i fakty) oraz
pewne stwierdzenie (cel).
Wykonanie programu to próba udowodnienia celu w oparciu o podane
przesłanki, a więc pewien rodzaj automatycznego wnioskowania.
Język programowania w logice (a ściślej — jego interpreter) to właściwie
system automatycznego dowodzenia twierdzeń, działający w oparciu o nieco
uproszczony rachunek predykatów pierwszego rzędu.
Zastosowania programowania w logice obejmują przede wszystkim sztuczną
inteligencję (np. systemy ekspertowe, rozpoznawanie obrazów) i
przetwarzanie języka naturalnego.
Językiem, który uzyskał największą popularność jest Prolog.
Przykład programu w Prologu
rodzic(X, Y) :- ojciec(X, Y).
rodzic(X, Y) :- matka(X, Y).
malzenstwo(X, Y) :- ojciec(X, Z), matka(Y, T), Z = T.
malzenstwo(X, Y) :- matka(X, Z), ojciec(Y, T), Z = T.
przodek(X, Y) :- rodzic(X ,Y).
rodzenstwo(X, Y) :- matka(M, X), matka(M, Y), ojciec(O, X),
ojciec(O, Y), X \= Y.
ojciec(marek, jurek).
ojciec(marek, zosia).
matka(jola, jurek).
matka(jola, zosia).
rodzenstwo(jurek, zosia).
Programowanie zdarzeniowe
• Programowanie (sterowane zdarzeniami) polega zastąpieniu
zasadniczego toku sterowania wieloma drobnymi programami
obsługi zdarzeń, uruchamianymi w chwili wystąpienia
odpowiedniego zdarzenia
• Zdarzenia mogą być wywoływane przez urządzenia wejściawyjścia (np. naciśnięcie klawisza, ruch myszką) lub przez same
programy obsługi zdarzeń, oprócz zbioru programów obsługi
zdarzeń potrzebny jest też zarządca, który będzie je
uruchamiał
• Przykładem programu sterowanego zdarzeniami może być
system operacyjny, który jest, do pewnego stopnia, sterowany
zdarzeniami: reaguje na przerwania. Rolę zarządcy spełnia tu
procesor komputera.
• Z kolei sam system operacyjny jest zarządcą w stosunku do
uruchomionych pod jego kontrolą procesów.
Przegląd języków wysokiego poziomu
• FORTRAN (1954-1957, John Backus) - pierwszy język
•
•
•
•
imperatywny wysokiego poziomu, zastosowania to obliczenia
naukowo-techniczne.
ALGOL 60, ALGOL 68 (1958-1968) - umożliwiał łatwe
programowanie algorytmów numerycznych.
COBOL (1960-1962) - zorientowany na problemy ekonomiczne
i zarządzanie, używany przez banki i firmy handlowe
PL/1 - język uniwersalny, łączy zalety Algolu, Fortranu i Cobolu
BASIC (1964, J. Kemeny, T. Kurtz) - język uniwersalny, dla
początkujących, zdobył popularność dopiero po zastosowaniu
go w mikrokomputerach jako język umieszczony w pamięci
ROM.
Przegląd języków wysokiego poziomu
• PASCAL (1969-1971, Niklaus Wirth) - posiada zalety
dydaktyczne, wymusza programowanie systematyczne i
strukturalne metodą zstępującą „od ogółu do szczegółu”,
szeroka dziedzina stosowalności.
• C (1972, Dennis Ritchie, Ken Thompson, Brian Kernighan) łączy cechy języka wysokiego poziomu z możliwościami
asemblera, służy między innymi do pisania programów
systemowych, np. systemu UNIX.
• MODULA-2, MODULA-3 (1978, Niklaus Wirth) - ulepszone
wersje Pascala, pozwalają na konstruowanie niezależnych
modułów.
• ADA (1979, Jean Ichbiah) - powstał na zlecenie Departamentu
Obrony USA, służy do programowania komputerów
nadzorujących aparaturę techniczną (systemy czasu
rzeczywistego)
Przegląd języków wysokiego poziomu
• SIMULA (1967) - zapoczątkował programowanie obiektowe,
•
•
•
•
•
zastosowanie przy konstrukcji kompilatorów innych języków,
programów symulujących systemy biologiczne, ekonomiczne,
społeczne, komunikacyjne.
Clliper - język do programowania i manipulowania bazami danych.
SQL - standard dla relacyjnych baz danych.
Visual Basic - język obiektowy, pozwala tworzyć aplikacje dla
WINDOWS.
Lisp – (1960, J. McCarthy) wykorzystuje programowanie funkcyjne,
oparty na rachunku lambda, użyteczny do obliczeń symbolicznych
oraz budowania programów do automatycznego dowodzenia
twierdzeń, liczenia symbolicznego całek nieoznaczonych itp.
Prolog – zastosowania podobne do Lispu – sztuczna inteligencja.
Przegląd języków wysokiego poziomu
Języki zorientowane obiektowo:
• C++ (1985, Bjarne Stroustrup)
• Perl (1987, Larry Wall)
• Python (1990, Guido van Rossum)
• Java (1994, Sun Microsystems)
• PHP (1995, Rasmus Lerdorf)
• C# (2001, Anders Hejlsberg, Microsoft)
• VB.NET (2001, Microsoft)
Przegląd języków wysokiego poziomu
• Języki znaczników: HTML, VRML, XML, X3D, XHTML
• Języki skryptowe do programowania stron www:
• VB Script
• Java Script
• Języki skryptowe do tworzenia multimediow:
ActionScript, Lingo
Download