1954-56 John Backus wraz zespołem inżynierów IBM
Transkrypt
1954-56 John Backus wraz zespołem inżynierów IBM
Materiały uzupełniające do wykładów z Języków Programowania II Języki Programowania materiały uzupełniające do wykładów 19 maj, 2006 Wojciech Sobieski Uniwersytet Warmińsko-Mazurski Wydział Nauk Technicznych Katedra Mechaniki i Podstaw Konstrukcji Maszyn 10-957 Olsztyn, ul. M. Oczapowskiego 11. tel.: (89) 5-23-32-40 fax: (89) 5-23-32-55 [email protected] Niniejszy dokument nie zawiera tekstów aktorskich lecz jest jedynie kompilacją różnych materiałów internetowych, powstałą w okresie opracowywania zakresu tematycznego przedmiotu Języki Programowania II (lata 2001-2003), realizowanego na specjalności Inżynierskie Zastosowania Komputerów WNT UWM w Olsztynie. Na podstawie zebranych materiałów (przedstawionych w opracowaniu oraz innych) opracowany został autorski cykl wykładów do tego przedmiotu. Olsztyn ©2006 1/64 Materiały uzupełniające do wykładów z Języków Programowania II Spis treści 1 Historia rozwoju komputerów.......................................................................................................... 3 1.1 Od Starożytności do Średniowiecza......................................................................................... 3 1.2 Wiek XVII i XVIII................................................................................................................... 4 1.3 Charles Babbage (1791 - 1871)................................................................................................ 5 1.4 Przełom XIX i XX wieku......................................................................................................... 6 1.5 Początek XX wieku.................................................................................................................. 7 1.6 Pierwsze komputery..................................................................................................................8 1.7 John von Neumann (1903 - 1957) ........................................................................................... 9 1.8 Komputer typu PC.................................................................................................................... 9 1.9 Kronika................................................................................................................................... 10 2 Języki programowania....................................................................................................................17 2.1 Rozwój programowania..........................................................................................................17 2.2 Generacje języków programowania........................................................................................19 2.3 Podstawowe definicje............................................................................................................. 20 2.4 Środowisko programistyczne..................................................................................................22 2.5 Etapy kompilacji..................................................................................................................... 23 2.6 Podział języków programowania............................................................................................24 2.7 Przegląd języków programowania..........................................................................................25 3 Elementy języków programowania................................................................................................ 31 3.1 Podstawowe cechy języków programowania:........................................................................ 31 3.2 Zmienne i stałe........................................................................................................................36 3.3 Wyrażenia............................................................................................................................... 37 3.4 Instrukcje................................................................................................................................ 39 3.5 Wyjątki....................................................................................................................................45 4 Styl programowania........................................................................................................................46 4.1 Elementy stylu programowania.............................................................................................. 46 4.2 Metody testowania programów.............................................................................................. 50 5 Algorytmy.......................................................................................................................................51 5.1 Rodzaje algorytmów............................................................................................................... 51 5.2 Rodzaje zapisu algorytmów....................................................................................................51 5.3 Schematy blokowe..................................................................................................................52 5.4 Zasady tworzenia schematów blokowych:............................................................................. 53 5.5 Etapy rozwiązywania problemów:..........................................................................................53 5.6 Realizacja pętli i instrukcji warunkowych..............................................................................54 5.7 Przykłady schematów blokowych:......................................................................................... 55 5.8 Poprawność algorytmów.........................................................................................................56 6 Technologia programowania.......................................................................................................... 58 6.1 Fazy powstawania programu komputerowego:...................................................................... 58 6.2 Rodzaje programowania......................................................................................................... 62 2/64 Materiały uzupełniające do wykładów z Języków Programowania II 1 Historia rozwoju komputerów. Ludzkość wytwarza coraz więcej informacji. Tak wiele, że jej przetwarzanie, czyli pamiętanie, klasyfikowanie, poszukiwanie, obrazowanie i zestawianie jest ponad ludzkie siły. Dlatego tak duże znaczenie osiągnęły "maszyny", które radzą sobie z tym zadaniem lepiej i szybciej od człowieka komputery. Komputery, czyli maszyny liczące (z ang. compute - obliczać) mają więcej lat niż się na ogół przypuszcza. Za przodków komputera uznać bowiem należy wszystkie urządzenia służące do liczenia. 1.1 Od Starożytności do Średniowiecza. W wykopaliskach między Mezopotamią i Indiami odnaleziono ślady stosowanych już w X wieku p.n.e. systematycznych metod znajdowania wyniku najprostszych operacji za pomocą specjalnie przygotowanych i poukładanych kamieni. Początkowo kamienie układano w rzędach na piasku tworząc w ten sposób plansze obliczeniowe, które nazywamy abakami (lub abakusami). Później zaczęto nawlekać kamienie na pręty, tworząc liczydła, czyli kompletne i przenośne przyrządy do obliczeń. W obu przypadkach, abakusa i liczydła, stan obliczeń określało rozmieszczenie elementów ruchomych na piasku lub na prętach. Liczydła przeżywały swój renesans w wiekach średnich. Wtedy na przykład ukształtował się japoński soroban w swej obecnej postaci. Jest on jeszcze dzisiaj dość powszechnie stosowanym liczydłem w Japonii. Soroban - jak każde liczydło ma wady, które zostały naprawione częściowo w kalkulatorze, a ostatecznie dopiero w komputerach. Służy on bowiem tylko do odnotowania bieżących wyników obliczeń, gdyż nie ma w nim miejsca ani na pamiętanie wyników pośrednich, ani na pamiętanie kolejno wykonywanych działań. Rys. 1. Starożytna figurka przedstawiająca człowieka z abacusem. Wiemy, że Leonardo da Vinci był geniuszem, którego pomysły wykraczały daleko poza jego epokę, ale mało kto wie, że próbował on również skonstruować maszynę liczącą. 13 marca 1967 roku amerykańscy naukowcy pracujący w Madrycie w Bibliotece Narodowej Hiszpanii napotkali dwie nieznane dotąd prace Leonarda da Vinci nazwane "Codex Madrid". Dotyczyły one maszyny liczącej. Dr Roberto Guatelli znany ekspert w dziedzinie twórczości Leonarda, tworzący także repliki jego prac postanowił razem ze swoimi asystentami odtworzyć również i tą maszynę. Dokonano tego w 1968 r. jednak dzisiejsze dzieje tej repliki są nieznane i nie wiadomo gdzie ona się znajduje. Specjaliści zarzucali Guatellemu, że w swojej rekonstrukcji nadmiernie kierował się intuicją i współczesną wiedzą oraz, że wyszedł poza projekt Leonarda. Tak więc Leonardo da Vinci - geniusz epoki renesansu wniósł również wkład w rozwój maszyn liczących. 3/64 Materiały uzupełniające do wykładów z Języków Programowania II Rys. 2. Na zdjęciach: oryginalne zapiski Leonarda da Vinci oraz replika maszyny jego pomysłu 1.2 Wiek XVII i XVIII. Na początku XVII wieku John Neper opublikował najpierw swoje dzieło o logarytmach a następnie przedstawił system wspomagający wykonywanie mnożenia, zwany pałeczkami Nepera. Genialność tego systemu polegała na sprowadzeniu mnożenia do serii dodawań. Pomysł Nepera wykorzystało wielu konstruktorów urządzeń liczących, jemu współczesnych i żyjących po nim. Za twórcę pierwszej w historii mechanicznej maszyny do liczenia jest uznawany Wilhelm Schickard (1592 - 1635), który przez długie lata był zupełnie zapomniany. Schickard opisał projekt swojej czterodziałaniowej maszyny, wykorzystując udoskonalone pałeczki Nepera w postaci walców, w liście do Keplera, któremu miała ona pomóc w jego astronomicznych (dosłownie i w przenośni) rachunkach. Niestety jedyny zbudowany egzemplarz maszyny spłonął w niewyjaśnionych okolicznościach, a dzisiejsze jej repliki zostały odtworzone dopiero niedawno na podstawie opisu z listu Keplera. W XVII wieku żyli i tworzyli wielcy matematycy Gottfried Wilhelm Leibniz (1646 - 1716) i Blaise Pascal (1623 - 1662). Pascal zainteresował się zbudowaniem maszyny liczącej z myślą o dopomożeniu swojemu ojcu, który był poborcą podatkowym. Wyprodukowano około 50 egzemplarzy Pascaliny - maszyny według pomysłu Pascala. Kilka egzemplarzy istnieje w muzeach do dzisiaj; część z nich była przeznaczona do obliczeń w różnych systemach monetarnych, a część dla różnych miar odległości i powierzchni (z przeznaczeniem dla geodetów). Pascal który zbudował maszynę wykonującą tylko dwa działania (dodawanie i odejmowanie) przez ponad trzysta lat uchodził niesłusznie za wynalazcę pierwszej mechanicznej maszyny do liczenia. Schickard i Pascal wprowadzili w swoich maszynach mechanizm do przenoszenia cyfr przy dodawaniu i odejmowaniu. Obie maszyny miały także pewne możliwości zapamiętywania niektórych wyników pośrednich. Leibniz odkrył na nowo pochodzący ze starożytnych Chin system dwójkowy (zwany także binarnym) do zapisu liczb. Przypisuje się jemu także zbudowanie pierwszej mechanicznej maszyny mnożącej. Chociaż w tym czasie istniała już Pascalina i Leibniz miał możność zapoznania 4/64 Materiały uzupełniające do wykładów z Języków Programowania II się z nią w Paryżu, projekt swojej "żywej ławy do liczenia" opisał przed pierwszą wizytą w Paryżu. W maszynie tej wprowadził wiele części, które zostały użyte w późniejszych maszynach biurowych. Maszyny Schickarda, Pascala, i Leibniza wymagały od użytkownika manualnej pomocy w wielu czynnościach związanych z kolejnymi krokami obliczeń. Za ich pomocą nie było jeszcze można w pełni automatycznie i w całości wykonać prostego działania na dwóch liczbach. Rys. 3. Z lewej: pascalina; z prawej: maszyna Laibnizta. W tym miejscu wypada wspomnieć o udziale naszego rodaka w dziele tworzenia maszyn liczących. Abraham Stern (1769 - 1842), z zawodu zegarmistrz, wykonał serię maszyn, które poza czterema działaniami podstawowymi, wyciągały także pierwiastki kwadratowe. Jedna z jego maszyn, raz uruchomiona, potrafiła wykonać za pomocą mechanizmu zegarowego wszystkie operacje bez ingerencji człowieka. Maszyny skonstruowane przez Sterna okazały się jednak mało praktyczne ze względu na wyjątkowo delikatną budowę. 1.3 Charles Babbage (1791 - 1871). Za najwybitniejszego twórcę maszyn liczących, żyjącego przed erą elektroniczną, uważa się Anglika Charlesa Babbage'a. Swoją pierwszą maszynę nazwaną maszyną różnicową, (gdyż wykonywała obliczenia metodą różnicową), konstruował przez ponad 10 lat. Trapiony jednak wieloma kłopotami rodzinnymi i finansowymi oraz nie mogąc do końca porozumieć się ze swoim głównym wykonawcą konstruktorem Clementem zaprzestał dalszych prac nad nią w 1842 roku. Zmontowaną część maszyny (podobno nadal sprawną) można oglądać w Muzeum Nauk w Londynie. Należy dodać, że w odróżnieniu od maszyn Leibniza i Pascala, po ręcznym ustawieniu początkowego stanu, dalsze działania maszyny różnicowej nie wymagają już żadnej ingerencji użytkownika poza kręceniem korbą. Prace Babbage'a zainspirowały wielu jemu współczesnych, którzy jak na przykład Szwedzi George i Edward Scheutzowie, często z większym powodzeniem ukończyli swoje, może mniej ambitne ale nadal praktyczne konstrukcje maszyn różnicowych. Ale Babbage nie poprzestał na próbie skonstruowania maszyny różnicowej. Marzył o maszynie, która mogłaby rozwiązywać bardziej złożone zadania. Tak narodził się jeszcze w trakcie prac nad maszyną różnicową pomysł zbudowania maszyny analitycznej, którym Babbage żył do śmierci. Było to przedsięwzięcie czysto abstrakcyjne - przewidywane przeszkody techniczne i trudności finansowe nie pozwoliły nawet na rozpoczęcie prac konstrukcyjnych. W projekcie Babbage zawarł jednak wiele pomysłów zrealizowanych dopiero we współczesnych komputerach. Między innymi rozdzielił pamięć (zwaną magazynem) od jednostki liczącej (młyna), czyli miejsce przechowywania danych od jednostki wykonującej na nich działania. Obie te części maszyny analitycznej miały być 5/64 Materiały uzupełniające do wykładów z Języków Programowania II sterowane za pomocą dodatkowego urządzenia kontrolnego, które otrzymywało polecenia na kartach perforowanych, udoskonalonych i rozpowszechnionych przez Jacquarda do programowania maszyn tkackich. Można więc uznać maszynę analityczną Babbege'a za pierwszy pomysł kalkulatora sterowanego programem zewnętrznym. Rys. 4. Maszyna Babbaga. Opis działania maszyny analitycznej trafił w ręce Ady ( jej pełne nazwisko: Ada Augusta hrabina Lovelace), znanej w owych czasach z błyskotliwego umysłu. Urzeczona doskonałością projektu uważała, że... " maszyna analityczna tkać będzie wzory algebraiczne, tak jak krosna Jacquarda tkają licie i kwiaty...". Nie czekając na skonstruowanie maszyny (czego i tak by nie doczekała), Ada zajęła się sporządzaniem opisów jej używania do rozwiązywania konkretnych zadań obliczeniowych. Opisy te nazwano by dzisiaj programami, dlatego uważa się ją za pierwszą programistkę komputerów. Dla uczczenia zasług Ady na tym polu nazwano jej imieniem jeden z najbardziej uniwersalnych języków programowania. 1.4 Przełom XIX i XX wieku. Koniec XIX wieku był początkiem rozwoju urządzeń mechanograficznych, których głównym przeznaczeniem było usprawnienie rachunków statystycznych, księgowych i biurowych. Zaczęło się w Stanach Zjednoczonych od Hermana Holleritha, który postanowił zautomatyzować prace statystyczne związane ze spisem ludności przeprowadzanym wtedy w Stanach co dziesięć lat. Hollerith sięgnął po elektryczność, jako źródło impulsów i energii, rozwinął postać karty perforowanej, na której zapisywano dane i zbudował elektryczny czytnik - sorter kart. Olbrzymim sukcesem Holleritha okazał się spis 1890 roku, którego wyniki zostały całkowicie opracowane za pomocą jego urządzeń na podstawie danych zebranych na jego kartach. W następnych latach Hollerith dostarczał lub wypożyczał swoje urządzenia do przeprowadzenia spisów w wielu krajach, w tym także w Europie, między innymi w Rosji. Na przełomie XIX i XX wieku powstało wiele firm, które początkowo oferowały maszyny sterowane kartami perforowanymi i z latami zyskiwały na swojej potędze a wiele z nich przetrwało do dzisiaj, jak na przykład IBM, Bull, Remington Rand, Burroughs, a także NCR (kasy), i Bell (telefony). Udoskonalona i znormalizowana karta perforowana przez wiele dziesięcioleci była uniwersalnym nośnikiem informacji, a pierwsze maszyny mechaniczne do przetwarzania danych zapoczątkowały stale rosnący popyt na przetwarzanie informacji. Wniosło to także zmiany w stosunkach 6/64 Materiały uzupełniające do wykładów z Języków Programowania II międzyludzkich, a w szczególności między państwem (posiadaczem maszyn do obróbki informacji) i obywatelem. 1.5 Początek XX wieku. Wśród modeli obliczeń powstałych w pierwszej połowie XX wieku największą popularność zdobyły maszyny Turinga. W swojej fundamentalnej pracy z 1936 roku, Alan Turing bardzo przystępnie opisał tok mylenia prowadzący od obliczeń wykonywanych ręcznie do obliczeń wykonywanych przez bardzo prostą maszynę. Oto jej opis. Obliczenia ręczne są najczęściej wykonywane na pokratkowanej kartce papieru, której pojedyncze kratki są wypełnione cyframi i symbolami działań. Dysponujemy tylko skończoną liczbą znaków ( cyfr, np. 0 oraz 1 i symboli działań ), które mogą być wpisywane w kratki. To, co robimy w ustalonej chwili, zależy od znaków, które obserwujemy i od działania, jakie podjęliśmy. Można przyjąć, że liczba kratek obserwowanych w danej chwili jest ograniczona. Przejrzenie za większej ich liczby sprowadza się do wykonania ciągu obserwacji. Możemy także założyć, że liczba wszystkich stanów, w jakich może znaleźć się nasz umysł wykonujący obliczenia, chociaż duża jest skończona. Turing doszedł do koncepcji swojej maszyny wprowadzając pewne uproszczenia i uściślenia w działaniach na kartce i nad nią. Po pierwsze, zapis obliczeń na kartce papieru (a dokładniej na dwuwymiarowym układzie kratek) można sprowadzić do zapisu na jednowymiarowej pokratkowanej kartce, czyli na tamie podzielonej na kratki. Wystarczy w tym celu treść obliczeń wypełniających kartkę zapisać wierszami. Traci się przy tym czytelność, ale zyskuje redukcję wymiaru kartki. Po drugie, umysł wykonujący obliczenia można zastąpić przez obiekt bardziej fizyczny zwany głowicą, która znajduje się nad tamą, może się poruszać w obie strony tamy, a w danej chwili widzi jedynie symbol umieszczony w kratce, nad którą zawisła. Działanie głowicy jest określone przez ustalony zbiór instrukcji, zgodnie z którymi może poruszać się w lewo, w prawo lub stać w miejscu, potrafi rozpoznawać symbole i może zmieniać zawartości kratki, nad którą się znajduje. Wykonanie instrukcji przez maszynę Turniga jest działaniem głowicy, uzależnionym od stanu, w jakim się znajduje i co widzi. Obliczenia wykonywane za pomocą maszyny Turinga zależą od początkowego zapisu symboli na tamie i od przyjętego zestawu dozwolonych instrukcji. Zatem działa ona podobnie jak dzisiejsze komputery - wyniki obliczeń zależą od zapisanych w pamięci komputera danych i od zestawu wykonywanych instrukcji. Zawartoć tamy po zatrzymaniu się maszyny zależy od obu tych czynników. Nieodparcie nasuwa się pytanie o to, co można policzyć za pomocą tak prostych maszyn. Okazuje się, że bardzo wiele. Sam Turing sformułował tezę, iż na maszynie tego typu można zrealizować każdy algorytm. Do dzisiaj nie obalono tej tezy. Zauważa się, że w związku z tym można przyjąć, iż algorytmem jest dowolny opis wykonania obliczeń na maszynie Turinga. Analizując moc swoich maszyn, Turing doszedł jednak do wniosku, że istnieją funkcje, których wartości nie mogą one obliczać. Wspomnieć tutaj należy jeszcze o dwóch innych dziedzinach działalności Turinga ściśle związanych z automatyzacją obliczeń i komputerami. W latach II wojny światowej Turing został włączony do grupy specjalistów zajmujących się w Wielkiej Brytanii deszyfracją kodów Enigmy maszyny, którą Niemcy używali do kodowania meldunków i rozkazów rozsyłanych swoim jednostkom na wszystkich frontach. W 1941 roku działalność tej grupy przyczyniła się do zredukowania brytyjskich strat na morzach o 50%. Brytyjscy specjaliści korzystali z materiałów ( wśród których był egzemplarz Enigmy oraz maszyna deszyfrująca zwana bombą ) przekazanych im w 1939 roku przez grupę Polaków kierowaną przez Mariana Rejewskiego, zajmujących się od 7/64 Materiały uzupełniające do wykładów z Języków Programowania II pięciu lat skonstruowaniem maszyny deszyfrującej. Chociaż Brtyjczycy udoskonalili maszynę deszyfrującą otrzymaną od Polaków, pozostawała ona nadal maszyną mechaniczną i jej działanie nie nadążało za ciągle udoskonalanymi i zmienianymi przez Niemców egzemplarzami Enigmy. Ocenia się że w szczytowym okresie II wojny światowej Niemcy używali ponad 70 tysięcy maszyn szyfrujących Enigma. Prace nad maszyną deszyfrującą Enigmę przyczyniły się do powstania pod koniec wojny w Wielkiej Brytanii kalkulatorów elektronicznych. Powstało kilka wersji maszyny o nazwie Coloss, których głównym konstruktorem był T.H. Fowers. Były to już maszyny elektroniczne, w których wykorzystano arytmetykę binarną, sprawdzane były warunki logiczne (a więc można było projektować obliczenia z rozgałęzieniami), zawierały rejestry, mogły wykonywać programy (poprzez uruchomienie tablic rozdzielczych) i wyprowadzać wyniki na elektryczną maszynę do pisania. 1.6 Pierwsze komputery. Pierwsze komputery zbudowano dopiero w naszym stuleciu, chociaż pomysły, jakie w nich zrealizowano, pojawiły się przynajmniej sto lat wcześniej, już za czasów Babbage'a. Zastosowane w komputerach środki techniczne pojawiły się bowiem dopiero w latach międzywojennych. Za największego inspiratora powstania komputera w jego obecnej postaci uważa się Johna von Neumanna. Ale najpierw trzeba oddać właściwe miejsce twórcom rzeczywiście najwcześniejszych konstrukcji, pretendujących do miana komputera. Pojawienie się większości z nich przyspieszyła II wojna światowa. W 1941 roku Konrad Zuse ukończył w Niemczech prace nad maszyną Z 3, która wykonywała obliczenia na liczbach binarnych zapisanych w reprezentacji, nazywanej dzisiaj zmiennopozycyjną, sterowane programem zewnętrznym podawanym za pomocą perforowanej tamy filmowej. Maszyna Z 3 została całkowicie zniszczona w czasie bombardowania w 1945 roku. Następny model maszyny Zusego, Z 4 przetrwał i działał do końca lat pięćdziesiątych. Maszyny Zusego były kalkulatorami przekaźnikowymi. W tym czasie znane już były prace Claude Shannona dotyczące działań binarnych (logicznych) za pomocą układów elektronicznych zgodnie z regułami Boole'a. Rys. 5. ENIAC. W roku 1942 zespół specjalistów pod kierunkiem J.W. Mauchly'ego i J.P. Eckerta zaprojektował i zbudował maszynę ENIAC (ang. Electronic Numerical Integrator And Computer). Pierwsze obliczania maszyna ta wykonała w listopadzie 1945 roku. Maszyna ENIAC jest uznawana powszechnie za pierwszy kalkulator elektroniczny, chociaż w 1976 roku okazało się, że wczeniej zaczęły pracować w Wielkiej Brytanii maszyny Coloss I i II. Maszyna ENIAC była monstrualną konstrukcją złożoną z 50 szaf o wysokości 3 metrów zawierających około 20 tysięcy lamp. 8/64 Materiały uzupełniające do wykładów z Języków Programowania II Słabością tej maszyny było: użycie zwykłego systemu dziesiętnego do pamiętania liczb, brak rozdziału między funkcjami liczenia i pamiętania oraz bardzo uciążliwy sposób zewnętrznego programowania. Wady te zostały usunięte dopiero w projekcie EDVAC. 1.7 John von Neumann (1903 - 1957) . John von Neumann, z pochodzenia Węgier, był w swoich czasach jednym z najwybitniejszych matematyków. W 1946 roku zainspirował on prace w projekcie EDVAC (ang. Electronic Discrete Variable Automatic Computer ), których celem było zbudowanie komputera bez wad poprzednich konstrukcji. Zaproponowano architekturę, zwaną odtąd von neumannowską, według której buduje się komputery do dzisiaj. W komputerze von Neumanna można wyróżnić przynajmniej następujące elementy: pamięć złożoną z elementów przyjmujących stan 0 lub 1, arytrometr zdolny wykonywać działania arytmetyczne, logiczne i inne, sterowanie, wprowadzanie danych i wyprowadzanie wyników. Program, czyli zbiór instrukcji, według których mają odbywać się obliczenia, jest wpisywany do pamięci. Kolejne rozkazy programu są pobierane przez jednostkę sterującą komputerem w takt centralnego zegara i rozpoznawane zgodnie z mikroprogramem wpisanym w układ elektroniczny. Należy podkreślić, że program jest przechowywany w pamięci komputera i jego działanie może zmieniać zawartość dowolnego obszaru pamięci (programy mogą się także same modyfikować). Fizycznie nie ma żadnej różnicy między danymi i programami przechowywanymi w pamięci komputera: są podobnie kodowane jako ciąg zer i jedynek i tak samo zrealizowane technicznie. Można więc powiedzieć, że celem działania komputera von neumannowskiego jest przejście w takt zegara od jednego stanu zawartości pamięci (danego na początku) do innego, zawierającego oczekiwany wynik. Można zauważyć podobieństwo tego spojrzenia na komputer von Neumanna do maszyny Turinga. Nie ma w tym nic dziwnego gdyż von Neumann bardzo dobrze znał osiągnięcia Turinga. Postęp w elektronice umożliwił dalszy rozwój komputerów. W latach sześćdziesiątych lampy zastąpiono tranzystorami. Pierwszy tranzystorowy komputer zbudowano w 1956 roku w Massachusettes Institute of Technology. Z kolei układy scalone zastąpiły tranzystory (układ scalony zawierał w jednej obudowie kilkadziesiąt tranzystorów i innych elementów elektronicznych). Dalszy postęp produkcji tych układów pozwolił umieszczać w jednej "kostce" dziesiątki tysięcy tranzystorów. Obwody takie nazwano układami wielkiej skali integracji ( VLSI z ang. Very Large Scale of Integration ). Wymyślono termin: " generacja komputerów " i nazwano komputery lampowe mianem pierwszej generacji, tranzystorowe - drugiej, zbudowane z układów scalonych - trzeciej, a w technologii VLSI - czwartej. Postęp w technologii produkcji komputerów odbywał się tak szybko, że zaczęto mówić o rewolucji komputerowej. Wprowadzenie na rynek tanich układów scalonych umożliwiło powstanie mikrokomputerów, w których elementy przetwarzające informacje umieszczono w jednym układzie - mikroprocesorze. 1.8 Komputer typu PC. Pierwsze komputery osobiste (PC z ang. Personal Computer) zostały opracowane przez IBM. Ponieważ firma ta nie miała nic przeciwko temu, by inne przedsiębiorstwa skorzystały z jej pomysłu i podążyły jej śladem, wielu producentów sprzedaje dziś własne komputery, które jednak są wciąż budowane według tej samej koncepcji firmy IBM. Ponieważ na rynku pojawiało się coraz więcej produktów, zaczęto pisać programy dla tego typu komputerów. Producenci sprzętu 9/64 Materiały uzupełniające do wykładów z Języków Programowania II odpowiedzieli na to kolejną falą unowocześnionych komputerów typu IBM - PC. Proces ten rozwijał się na zasadzie lawiny: komputery, nowe komponenty i oprogramowanie są obecnie tworzone przez setki najróżniejszych producentów. Tym sposobem PC stał się najbardziej rozpowszechnionym typem komputera na wiecie. Niemal w tym samym czasie, którym narodził się PC, firma Apple zaczęła budować swój własny typ komputera osobistego, dzieło Steve Woźniaka i Steve Jobsa. System Apple nie był jednak zgodny z IBM - PC ani pod względem sprzętu, ani oprogramowania. Swój sukces zawdzięczał on faktowi, iż po raz pierwszy wykorzystano tam graficzny sposób komunikowania się z użytkownikiem bazujący na obrazkach i oknach - na rok przed rozpowszechnieniem się Windows firmy Microsoft. Komputery Apple od samego początku były systemami kompletnymi. Oznaczało to, że w ich przypadku nie było już konieczne kupowanie dodatkowych komponentów, aby na przykład osiągnąć dźwięk odpowiedniej jakości. W przeciwieństwie do ówczesnych komputerów PC - tów, komputery Apple były znacznie prostsze w obsłudze. Mac, jak chętnie nazywa się komputer firmy Apple, szybko stał się ulubionym narzędziem ludzi z kręgów twórczych. Używali go przede wszystkim architekci, muzycy i projektanci, którym najczęściej potrzebny był właśnie wydajny i łatwy w obsłudze komputer. Tak więc Mac wciąż pozostaje główną alternatywą dla komputerów typu IBM - PC, a fakt, iż w porównaniu z PC -tem jest mniej dostępny na rynku, wynika głównie stąd, że firma Apple nie udostępniła nikomu praw do kopii swojego projektu. Większość producentów skorzystała co prawda z koncepcji peceta firmy IBM, niemniej niektórzy wyłamali się i podążyli własną drogą tworząc komputery osobiste niezgodne ze standardem. Stąd też oprogramowanie stworzone dla typowego komputera PC z reguły nie może być na nich uruchamiane. W zupełnym oderwaniu od standardu IBM - a powstały rozwiązania, które przewyższają pierwowzór czy to pod względem ceny, czy przydatności do gier, czy też obróbki dźwięku czy też grafiki. Niejeden z tego typu systemów był i wciąż jeszcze jest wspaniałym narzędziem, jednakże przeznaczonym wyłącznie dla specjalistów skupiających się na wykonywaniu określonej grupy zadań. 1.9 Kronika1. 1642: • Blaise Pascal skonstruował jedną z pierwszych maszyn matematycznych. 1822: • 1 Brytyjski matematyk Charles Babbage zaprezentował model maszyny różnicowej, który miał różnice drugiego rzędu i osiem miejsc po przecinku. Zajął się on następnie maszyną o różnicach siódmego rzędu i 290 miejscach po przecinku, poniósł jednak porażkę przy rozwiązywaniu problemu wykonania skomplikowanego napędu zębatego. http://www.republika.pl/pomoce/komputer.htm http://www.computerworld.pl http://386.bajo.pl/chronologicznie.htm http://fizar.pu.kielce.pl/history/hist1.html http://www.teleinfo.com.pl/ti/1999/51/t30.html 10/64 Materiały uzupełniające do wykładów z Języków Programowania II 1833: • Charles Babbage przedstawił pomysł pierwszej cyfrowej maszyny analitycznej. Nie została ona nigdy zbudowana. Projekt przewidywał jednak istotne składniki nowoczesnego przetwarzania danych. 1930: • W Massachusetts Institute of Technology w Cambridge (USA) grupa naukowców pod kierownictwem inżyniera elektryka Vannevara Busha konstruuje pierwszy - pracujący elektromechanicznie - komputer analogowy. 1936: • Francuz R. Valtat zgłosił do opatentowania maszynę liczącą, której zasada działania oparta była na systemie dwójkowym. 1937: • • Niemiec Konrad Zuse zbudował elektromechaniczną maszynę liczącą opartą na systemie dwójkowym. George Stibitz zbudował binarną maszynę sumującą Model K. George Stibitz tworzy w Laboratoriach Bella pierwszy cyfrowy obwód. 1940: • Alianci zbudowali pierwszą nadającą się do użytku maszynę deszyfrującą. 1941: • Niemiecki inżynier Konrad Zuse zaprezentował swoją cyfrową maszynę liczącą "Zuse Z3".Była to pierwsza sterowana programowo maszyna matematyczna, o wysokich parametrach eksploatacyjnych. "Zuse Z3" posiadała binarny mechanizm liczący z prawie 600 przekaźnikami jako bistabilnymi elementami i pamięcią z około 1400 przekaźnikami. 1942: • Amerykanin John V. Atanasoff ukończył pierwszą sprawną elektroniczną maszynę liczącą w technice lampowej. Atanasoff podjął plan już w roku 1937. Był przekonany, że metoda cyfrowa i zastosowanie liczb binarnych będzie najwłaściwsze do budowy maszyn liczących. 1943: • Niemiecki inżynier Henning Schreyer zgłosił do opatentowania pełnoelektroniczną pamięć i urządzenie liczące z lampami jarzeniowymi. Schreyer od 1937 r. wspólnie z Konradem Zuse zajmował się konstruowaniem układu połączeń lampowych do przetwarzania danych. Teraz opracował on ideę budowy pełnoelektronicznej maszyny liczącej. Jednakże w czasie wojny w Niemczech brakowało środków na realizację jego planów. 1944: • • Węgiersko-amerykański matematyk i chemik John von Neuman rozpoczął próby z modelem pierwszej maszyny liczącej z pamięcią EDVAC (Electronic Discrete Variable Automatic Computer). W urządzeniu kodowano program, składający się z serii pojedynczych instrukcji. Program zawierał instrukcje warunkowe, które umożliwiały tworzenie pętli. Każda instrukcja programowa mogła być zmieniona przez samą maszynę, jak każdy inny argument operacji. Z takim sposobem działania maszyna zdecydowanie górowała nad wszystkimi dotychczasowymi maszynami matematycznymi. Fizyk Howard Hathavay oddał do użytku na Universytecie Harvarda cyfrową maszynę liczącą. Nazywała się MARK I bądź ASCC - miała potężne wymiary i była pierwszą sterowaną programowo maszyną liczącą USA. 11/64 Materiały uzupełniające do wykładów z Języków Programowania II 1945: • • Na Uniwersytecie Pensylwania uruchomiono pierwszą wielką elektroniczną maszynę liczącą wiata ENIAC (Electronic Numerical Integrator and Computer). Zbudowana została przez Johna Prespera Ecckerta i Johna Williama Mauchly. Do czasu aż wszystkie jej zespoły stały się całkowicie zdolne do użytku, minęły jeszcze dwa lata. Wielka maszyna matematyczna wyposażona była w lampy elektronowe i liczyła 2000 razy szybciej niż komputer z elektromechanicznymi przekaźnikami. ENIAC zajmował powierzchnię zasadniczą 140 m.kw., posiadał przeszło 17 486 lamp elektronowych, 1500 przekaźników i zużywał 174 000 W mocy. Całe urządzenie waży ok. 80 ton i może wykonać maksymalnie 5000 operacji dodawania i 360 mnożenia w ciągu sekundy. Komputer cechuje duża awaryjność – średnio co 5 minut przepala się jedna z kilkunastu tysięcy lamp elektronowych. Szybkość taktowania zegara ENIAC-a wynosi 100. Powstaje pierwszy podręcznik obsługi komputera. Instrukcję posługiwania się komputerem ENIAC pisze Amerykanka Emily Goldstine. Grace M. Hopper w prototypie komputera Mark II znajduje pierwszą „pluskwę”. Jest nią ćma, która spowodowała błąd w pracy jednego z przekaźników. John von Neumann opracowuje koncepcję programu, który – umieszczony w pamięci – steruje komputerem. Rozpoczyna karierę termin „bit”. Niemiecki inżynier Konrad Zuse zakończył prace nad swoją maszyną liczącą " Zuse Z4". Komputer był rozwinięciem poprzedniego typu Z3. 1947: • • W Stanach Zjednoczonych zbudowano maszynę liczącą " Mark II " w technice przekaźnikowej. Amerykańska firma IBM buduje komputer SSEC z 12500 lampami i 21400 przekaźnikami. Jest on sterowany za pomocą tamy dziurkowanej. Umożliwiono ingerencję w program. 1948: • • • W toku rozwoju elektronicznych maszyn liczących, opartych na dwójkowym systemie liczbowym, znaczenie praktyczne zyskuje ugruntowana już przed ok. stu laty algebra Boole'a. Posługuje się ona wartościami logicznymi "Tak / Nie" lub " 0 / 1". Ten " krok binarny" określa matematyk John W. Tukey jako " bit" (binarny digit). Bit staje się jednostką informacji w przetwarzaniu danych. IBM 604 jest pierwszą dużą maszyną liczącą sterowaną tamą perforowaną. Richard Hamming opracowuje sposób wykrywania błędów w programach. 1949: • • • Short Order Code, wymyślony przez Johna Mauchly, jest pierwszym językiem programowania wysokiego poziomu. Na Uniwersytecie Manchester (Anglia) pod kierownictwem Maurica V. Wilkesa skonstruowano po trzech latach pierwszy komputer lampowy z programowalną pamięcią EDSAC (Electronic Delay Storage Automatic Computer). W tym samym czasie również IBM uruchamia w Nowym Jorku pod kierownictwem Johna Prespera Eckerta układ z programowalną pamięcią - SSEC (Selective Sequence Electronic Calculator). EDSAC pracuje z 4500 lampami elektronowymi, a SSEC z 12500 lampami elektronowymi i 21400 przekaźnikami. Nowością w tych komputerach jest to, że tak przebieg programu jak i obróbka danych są zakodowane w pamięci maszyny, program zawiera rozkazy warunkowe, które umożliwiają rozgałęzienia i skoki i wreszcie każdy rozkaz programowy z operacyjną częścią adresową może samodzielnie zmienić. Koncepcję tych komputerów opracował już w 1944 r. matematyk amerykański pochodzenia węgierskiego John von Neamann. Jednakże jego urządzenie EDVAC rozpoczyna pracę dopiero w roku 1952. Np. w 1945 r. Zuse sformułował ogólny algorytmiczny język formuł, który uwzględniał możliwe warianty programowania pamięci. 12/64 Materiały uzupełniające do wykładów z Języków Programowania II 1950: • • Univac I firmy Eckert and Mauchly Computer Company jest komputerem produkowanym seryjnie. Komputer " Mark III " używa tamy magnetycznej zamiast kart perforowanych. 1951: • • Grace Murray Hopper wymyśla pierwszy kompilator A-0. Na Uniwersytecie Harwarda w Cambridge (Massachusetts) matematyk Howard H. Aiken uruchomił swoją maszynę cyfrową MARK III. Urządzenie to było kontynuacją urządzeń poprzednich MARK I i MARK II, które Aiken budował już od roku 1939. W niedługim czasie Aiken buduje pierwszy, wykonany w pełni w technice lampowej maszynę liczącą MARK IV. 1952: • • Pierwsze asemblery. Howard H. Aiken uruchomił w USA lampową maszynę liczącą MARK IV. 1954: • J.W. Backus stworzył język komputerowy FORTRAN (formula translator). Umożliwia on dialog pomiędzy użytkownikiem a bankiem danych bez konieczności korzystania z pomocy programisty. FORTRAN jest skomplikowanym językiem komputerowym, który nie tylko przekazuje maszynie polecenia, lecz zawiera w sobie szereg wzorów ułatwiających programowanie. 1955: • W Bell Telephone Laboratory w USA rozpoczęła pracę pierwsza tranzystorowa maszyna licząca " Tradic " skonstruowana przez zespół pod kierownictwem J. H. Felkera. Jest ona znana jako " komputer drugiej generacji ".Wkrótce pojawiły się na rynku tranzystorowe komputery ("7090 IBM" i "Gamma 60 Bull"). 1957: • • Fortran II. John McCarthy tworzy wydział sztucznej inteligencji na Uniwersytecie MIT. 1958: • Opracowano komputerowy język programowania ALGOL (Algorithmic Language). Podobnie jak FORTRAN - ALGOL jest językiem problemowo zorientowanym, ale nie bardziej niż te, które są specjalistycznymi językami naukowo-technicznymi. Ma on inną strukturę niż FORTRAN. 1959: • John McCarthy opracowuje język programowania Lisp (list processing). 1960: • • • • Powstaje język programowania Algol 60. Zostaje opracowany język programowania COBOL (Common Business Oriented Language). COBOL używa stosunkowo dużej liczby symboli słownych. Powstaje LISP. W listopadzie firma DEC przedstawia PDP-1, pierwszy komputer wyposażony w monitor i klawiaturę. 13/64 Materiały uzupełniające do wykładów z Języków Programowania II 1962: • • • Powstaje APL, APL/PC, APL*PLUS. Powstaje SIMULA. Maleńkie tranzystory zwiększają prędkość elektronicznego przetwarzania danych (trzecia generacja komputerów). 1963: • • • Powstaje program Eliza, który wykazuje pewne przejawy inteligencji. Potrafi prowadzić proste rozmowy z człowiekiem. Na uniwersytecie Kalifornijskim rozpoczynają się prace nad logiką rozmytą (fuzzy logic), która ma pomóc w stworzeniu komputera myślącego. Zatwierdzony zostaje 7-bitowy kod ASCII. 1964: • • Powstaję języki PL/I, dialekty: EPL, PL/S, XPL. Thomas Kurz i John Kemeny opracowują w Dartmouth College prosty język programowania Basic. 1966: • Fortran IV (1966). 1967: • • • • Ole-Johan Dahl i Kristen Nygaard z Norwegian Computing Centre opracowują język Simula, który jest pierwszym obiektowo zorientowanym językiem programowania. Holender Edsger Dijkstra opracowuje zasady programowania strukturalnego. Powstaje firma Intel założona przez dwóch byłych pracowników Fairchild Semiconductor. Powstaje pierwszy radziecki superkomputer - BESM-6. 1968: • • • • Powstaje Algol 68. Edsger Dijkstra przekonuje, że instrukcja GOTO może być szkodliwa i nie powinno się jej stosować. Monolityczne układy przełączające zastępują minitranzystory i hybrydowe układy scalone. Zaczyna się czwarta generacja komputera. Podczas gdy komputery drugiej generacji wykonywały na sekundę 1300 dodawań, a trzeciej 160 000 dodawań, to nowe urządzenia wykonują ponad 300 000. Dzięki upowszechnieniu się komputerów Odra powstają pierwsze ZETO - Zakłady Elektronicznej Techniki Obliczeniowej. 1969: • • • IBM podejmuje decyzję o niedostarczaniu programów aplikacyjnych razem ze sprzętem. Tak powstaje rynek oprogramowania. Szwajcar Niklaus Wirth opracowuje język programowania Pascal. Douglas Engelbart z Xerox PARC (Palo Alto Research Center) tworzy podstawy hipertekstu (pierwowzoru HTML). Engelbart jest również twórcą myszy komputerowej (1964 r.). 1970: • • Powstaje Prolog, Prolog-2, Prolog++, Prolog-D-Linda. W IMM powstają dwa zespoły zajmujące się technikami kompilacji. Zespół Jana Walaska buduje kompilatory COBOL i Pascala. Zespół Stanisława Niewolskiego tworzy kompilator Fortran IV dla RIAD. Prace te podjęto, by możliwe było samodzielne opracowywanie i 14/64 Materiały uzupełniające do wykładów z Języków Programowania II rozpowszechnianie kolejnych języków oprogramowania oraz tworzenie przy ich użyciu programów systemowych i aplikacyjnych. 1972: • • • Dennis Ritchie opracowuje język programowania C w firmie Bell Labs. W laboratoriach PARC powstaje obiektowy języka programowania Smalltalk, stworzony przez Alana Kaya. Powstaje procesor Intel 8008 (200 Khz), pierwszy 8 bitowy układ, zastąpiony niebawem przez Intel 8080. 1974: • W kwietniu powstaje 8 bitowy procesor 8080 (2 Mhz). Składa się z 6 tys. tranzystorów. 1976: • • • Departament Obrony USA ogłasza przetarg na opracowanie środowiska i języka do produkcji oprogramowania, które ma być wbudowane w postaci sterowników do dział okrętowych, stacji radiolokacyjnych, wyrzutni rakietowych. W konkursie wygrywa zespół reprezentujący kilka wydziałów informatyki uczelni francuskich. Ostatecznie Departament Obrony zatwierdza specyfikację wynikową języka ADA oraz związane z nim środowisko programistyczne. Cray 1 - pierwszy komputer wektorowy do intensywnych obliczeń numerycznych. Zilog wprowadza na rynek procesor Z80. 1977: • Fortran 77 1978: • W czerwcu Intel przedstawia pierwszy 16-bitowy procesor - 8086 (4,77 Mhz). Składał się z 29 tys. tranzystorów. 1979: • Powstają Modula-2, Modula-2+, Modula-3, Modula-P, Modula/R. 1980: • • • • Powstaje język programowania Ada. Powstaje dBASE II - wersje późniejsze: dBASE III, III+, IV, V Brytyjscy inżynierowie wprowadzili na rynek komputer osobisty (Sinclair ZX - 80). Microsoft tworzy pierwowzór DOS-u. 1981: • IBM dostarcza pierwszy Personal Computer (PC) z 16-bitowym procesorem 8088, pracującym z częstotliwością 4,7 MHz pod kontrolą DOS. 1982: • • W lutym Intel prezentuje 16-bitowy procesor 80286 (6 Mhz). Zawiera on 134 tys. tranzystorów. John Warnock opracowuje w firmie Adobe język PostScript. 1983: • • • Bjarne Stroustroup opracowuje C++. Borland wprowadza Turbo Pascal. Powstaje Smalltalk-80, Smalltalk/V na PC. 15/64 Materiały uzupełniające do wykładów z Języków Programowania II • • Powstaje standard Ada 83, rozszerzenia Ada++, Ada 9X. Microsoft wprowadza edytor Word dla DOS. 1984: • • Powstaje Macintosh. Microsoft prezentuje system operacyjny Windows. 1985: • • Powstaje COBOL 85 W październiku Intel przedstawia 32 bitowy procesor 80386. 1986: • Intel wprowadza procesor 80386. 1989: • W kwietniu powstaje procesor Intel 80486, który zawiera 1,2 mln tranzystorów. 1990: • • Powstaje procesor Intel i486. Microsoft wprowadza ikony do Windows 3.0. 1991: • • Fortran 90 Linus Thorvalds opracowuje system operacyjny Linux. 1992: • Pojawia się Windows 3.1 przeznaczony dla krajów naszego regionu. System Microsoftu nie ma jeszcze polskego menu, ale obsługuje polskie znaki diakrytyczne. 1993: • • W marcu powstaje procesor Pentium Microsoft wprowadza Windows NT. Do sprzedaży trafiają polskie wersje Word i Excel. Z Wordem konkuruje edytor QR-Tekst firmy Malkom. 1994: • Uchwalona przez Sejm Ustawa o prawie autorskim miała ograniczyć piractwo komputerowe. 1995: • • • Sun przedstawia światu język Java. Powstaje Visual Fortran 95. 24 sierpnia na rynku pojawia się Windows 95. 1996: • Powstaje Pentium Pro 1998: • • W kwietniu Intel przedstawia procesor Pentium II (350 MHz i 400 MHz). W czerwcu Microsoft wypuszcza system operacyjny Windows 98. 16/64 Materiały uzupełniające do wykładów z Języków Programowania II 2 Języki programowania. 2.1 Rozwój programowania. Możliwość zaprogramowania maszyny, a tym samym dostosowanie jej działania do wymogów użytkownika w danym momencie, przyczyniła się do tego, że komputer stał się obecnie urządzeniem niemal niezbędnym w wielu dziedzinach. Byłoby to niemożliwe bez znaczących postępów w programowaniu, a w szczególności bez rozwoju języków i narzędzi automatyzujących pracę programisty. Pierwsze komputery były programowanie przez fizyczną zmianę układów elektronicznych (tzw. hardware'u) lub przestawienie przeznaczonych do tego przełączników. Była to metoda powolna, kosztowna, o bardzo ograniczonych możliwościach. W ten sam sposób były wprowadzane dane. Z biegiem czasu ilość danych do opracowywania wzrosła tak bardzo, że nie pozostało nic innego, jak tylko poszukać nowego systemu. Tak powstały dziurkowane karty i taśmy. Kolejnym krokiem było zastosowanie takich samych kart i taśm do przechowywania programów. Dzięki temu komputery zyskały pewną elastyczność. Można było stosunkowo szybko i łatwo załadować dany program do pamięci maszyny. Możliwość przechowywania w pamięci komputera programu i danych stanowiła wielki krok naprzód, lecz jednocześnie stworzyła nowe problemy. Teraz bowiem okazało się, że potrzebny jest prosty system porozumiewania się z komputerem i kodowania programów, które maszyna ma wykonywać. I tak doszło do pojawienia się pierwszych języków programowania. Żeby komputer wykonał określone zadanie, należy wskazać mu sposób, w jaki ma to uczynić. Nie jest to proste, gdyż trzeba posłużyć się językiem zrozumiałym dla maszyny, którego podstawę stanowi szereg precyzyjnych instrukcji. Takie porozumiewanie się z komputerem odbywa się za pomocą środków, których dostarczają języki programowania, a które w swoich początkach były bardzo prymitywne i trudne w użyciu. Wszystkie języki programowania wykorzystują system ściśle ustalonych reguł, które w większym lub mniejszym stopniu mają zbliżyć do siebie język naturalny człowieka i maszyny; są pośrednikiem między skompilowanym kodem maszynowym (zrozumiałym dla komputera) a językiem naturalnym. Ponieważ jednak komputer rozumie i posługuje się tylko tzw. językiem binarnym, którego podstawę stanowi rozróżnienie dwóch stanów, jakie może przyjąć wyłącznik (włączone/wyłączone), a reprezentowanych przez 0 i 1, to ciąg instrukcji - czyli program - trzeba przetworzyć tak, aby stał się zrozumiały dla maszyny. Na szczęście, tłumaczenie takiego kodu na język zrozumiały dla komputera jest procesem mechanicznym i powtarzalnym, więc może być wykonane przez samą maszynę. Służy do tego specjalny program tłumaczący zwany translatorem. Obecnie do tłumaczenia kodu z języka programowania na język maszynowy używa się dwóch typów programów tłumaczących: kompilatorów i interpreterów. Kompilator przekształca program napisany w języku wysokiego poziomu na program w języku zrozumiałym dla maszyny. W ten sposób otrzymuje się tak zwany kod wynikowy, który może być wykonywany dowolnie wiele razy. W przypadku kompilatorów należy rozróżniać trzy języki: ten, w którym napisano program i który jest mniej lub bardziej zbliżony do naturalnego (kod źródłowy); właściwy dla danego typu komputera język maszynowy, na który tłumaczony jest program (kod wynikowy); język samego kompilatora, którym może być język programu źródłowego lub maszynowy (albo jeszcze jakiś inny). Interpreter natomiast tłumaczy kolejno poszczególne instrukcje programu napisanego w języku wysokiego poziomu (może to być ten sam język, co w przypadku kompilatora), a te są natychmiast wykonywane. Tak więc, odmiennie niż kompilator, który jednorazowo przekształca program w całości, interpreter tłumaczy każdą instrukcję oddzielnie, bezpośrednio przed jej wykonaniem. Interpreter nie generuje programu wynikowego. Dlatego za każdym razem, kiedy wykonuje się 17/64 Materiały uzupełniające do wykładów z Języków Programowania II dany program, interpreter ponownie musi go tłumaczyć linia po linii. Co więcej, również powtarzające się fragmenty programu muszą być tłumaczone oddzielnie, za każdym razem od nowa. W przypadku interpretera rozróżnia się tylko dwa języki. Jeden - to język programu źródłowego, a drugi - to język, w jakim został napisany sam interpreter. Nie wyodrębnia się kodu wykonywalnego, gdyż jest on podawany stopniowo, w miarę jak mikroprocesor zgłasza taką potrzebę. Programy interpretowane wykonują się wolniej niż kompilowane, ale interpreter, jako środowisko programowania i uruchomieniowe, jest bardziej elastyczny, gdyż wszelkie błędy (termin przejęty z angielskiego: bug - pluskwa) mogą być wyłapywane i poprawiane już w trakcie normalnego wykonywania programu. Techniki programowania rozwijały się równolegle do ewolucji komputera. Pierwsze języki starały się maksymalnie wykorzystać niewielką moc ówczesnych procesorów oraz skromne możliwości systemów operacyjnych. W tamtym czasie do programowania używano często języka niskiego poziomy zwanego asemblerem (w jęz. angielskim assembler), który jest językiem symbolicznym, lecz ściśle związanym z maszyną, na której program będzie wykonywany. W asemblerze jedna instrukcja tłumaczy się na jedną instrukcję procesora. Mimo tej niedogodności asembler był dobrą alternatywą dla żmudnego wprowadzania do pamięci maszyny nie kończących się ciągów zer i jedynek lub liczb szesnastkowych, z drugiej strony, wpisany weń stopień komplikacji sprawił, że środowisko to było wyłączną domeną wysokiej klasy profesjonalistów. Wprowadzenie asemblera przyczyniło się głównie do tego, że programy stały się czytelniejsze, chociaż do kodu symbolicznego dodano instrukcje nie mające swojego odpowiednika w rozkazach procesora. Służą one do przekazywania informacji kompilatorowi i zostały nazwane "pseudorozkazami". Pseudorozkazem są na przykład te, które określają początek i koniec pewnych części programu (podprogramów i procedur) lub wskazują kompilatorowi sposób wykonania konkretnego zadania. Wkrótce stwierdzono, że język symboliczny nie rozwiązuje ostatecznie problemów związanych z programowaniem, gdyż zmiana procesora wymaga nowego asemblera, dostosowanego do instrukcji nowej maszyny, a programowanie w asemblerze wymaga bardzo dobrego poznania mikroprocesora, jego rejestrów, struktury pamięci i wielu innych rzeczy. Mimo tych wad języki symboliczne są nadal stosowane z dwóch zasadniczych powodów. Po pierwsze, istnieje jeszcze olbrzymia ilość oprogramowania napisanego w tych językach, z którego nie można po prostu zrezygnować. Po drugie, z języków symbolicznych korzysta się do pisania niektórych krytycznych sekcji programów, gdyż dzięki temu, że stoją blisko języka wewnętrznego maszyny, mają bardzo wydajny kod, co pozwala budować zajmujące niewiele miejsca i szybko działające programy, specjalnie dostosowane do danego modelu. Reasumując można powiedzieć, że programowanie w języku maszynowym lub symbolicznym ma pewne zalety (lepsze dostosowanie do sprzętu, maksymalna prędkość działania, minimalne zajęcie pamięci), ale i znaczne wady (niemożność napisania kodu nie związanego z maszyną, wyższy stopień trudności przy pisaniu programu oraz w rozumieniu kodu programu). Kolejny krok naprzód w dziedzinie programowania nastąpił wraz z pojawieniem się języków wysokiego poziomu. Ponieważ języki te nie są tak ściśle związane z konkretną maszyną, programista znający którykolwiek z nich jest w stanie zaprogramować dowolny komputer, pod warunkiem, że istnieje odpowiedni dla niego kompilator lub interpreter. Zazwyczaj kompilatory języków wysokiego poziomu działają dwuetapowo. W pierwszej fazie kod źródłowy jest przekształcany do pewnej postaci pośredniej, również niezależnej od maszyny. W drugiej fazie, otrzymany w ten sposób kod pośredni jest tłumaczony na kod wewnętrzny maszyny, na której ma być wykonywany dany program. W ten sposób, zmieniając jedynie program tłumaczący w drugiej fazie, niewielkim wysiłkiem można przekształcić dany kod do postaci różnych języków maszynowych. 18/64 Materiały uzupełniające do wykładów z Języków Programowania II Pierwsze języki wysokiego poziomu, jak COBOL, FORTRAN i APL, pochodzą z lat pięćdziesiątych i sześćdziesiątych. Choć znacznie uprościły proces, w praktyce nie wyszły poza krąg zastosowań zawodowych. Wszystkie języki programowania - również asembler - muszą być tłumaczone na język zrozumiały dla komputera, a ten rozumie tylko ciągi zer i jedynek i jedynie na nich operuje. Obecnie oprócz języków dysponujących zarówno kompilatorem jak i interpreterem, na przykład BASIC, stosowane są inne, tradycyjnie interpretowane, np. APL, oraz takie, które są niemal wyłącznie kompilowane, np. COBOL i FORTRAN. W miarę pojawiania się na rynku kolejnych języków wysokiego poziomu użytkownicy stwierdzili, że do konkretnych zadań jedne były lepsze od innych. Dlatego też COBOL stał się ulubionym narzędziem do tworzenia aplikacji dotyczących zarządzania, podczas gdy FORTRAN rozpowszechnił się jako język do prac naukowo-technicznych dzięki łatwości, z jaką radzi sobie z wyrażeniami i skomplikowanymi działaniami matematycznymi. Pomimo że języki, o których wyżej mowa, są nadal stosowane, to obecnie zawodowi programiści korzystają zazwyczaj z bardziej rozwiniętych języków wysokiego poziomu, w szczególności dla środowiska komputerów osobistych PC, które bardzo upraszczają programowanie. Takimi językami są np. PASCAL i C, choć ten ostatni jest stopniowo wypierany przez swoją wydajniejszą odmianę C++. Innym, szybko rozpowszechniającym się językiem, jest JAVA. Z założenia przeznaczony do wykorzystania w Internecie, umożliwia jednak konstruowanie złożonych aplikacji. Główne cechy wyróżniające język JAVA to przenośność pomiędzy różnymi platformami sprzętowymi i systemami operacyjnymi oraz czytelny kod źródłowy programów napisanych w tym języku. Do tworzenia stron Internetu korzysta się również z innego języka - HTML (angielski skrót nazwy Hypertext Markup Language). Oferuje on mniej możliwości niż Java, a zasadniczym jego przeznaczeniem jest właśnie tworzenie stron WWW. Odpowiedzią na konieczność szybkiego i łatwego konstruowania złożonych programów było pojawienie się na rynku tzw. języków programowania wizualnego. Są to narzędzia, które na bazie języków wysokiego poziomu, takich jak BASIC, PASCAL i C++ , pozwalają na budowanie programu przez wybranie obiektów i elementów, które mają pojawić się na ekranie. Główną zaletą języków wizualnych jest to, że udostępniają użytkownikowi środowisko graficzne, pozwalające budować kompletne aplikacje, nawet bez dobrej znajomości skomplikowanej składni danego języka. Spośród tego typu środowisk programistycznych należy wymienić, w szczególności, Delphi i ObjectVision firmy Borland oraz Visual Basic Microsoftu. Czasem narzędzia te są określane także mianem automatycznych generatorów kodu źródłowego. 2.2 Generacje języków programowania. Języki programowania można podzielić na pięć wyraźnie różniących się generacji (niektórzy mówią o czterech). W miarę jak zmieniał się komputer, wystąpiła konieczność dostarczania użytkownikowi narzędzi programistycznych, które umożliwiłyby mu maksymalne wykorzystanie sprzętu. Nie ma jednak pełnej zbieżności chronologicznej między poszczególnymi generacjami języków i sprzętu. Pierwsza generacja - Programowanie pierwszych komputerów akceptujących zmianę oprogramowania odbywało się bezpośrednio w kodzie binarnym, który można przedstawić jako ciągi zer i jedynek. Każdy typ komputera operuje własnym kodem, który dlatego został określony nazwą język maszynowy lub wewnętrzny. I to właśnie stanowi główną wadę tych języków, gdyż programista każdorazowo musi dostosowywać się do języka konkretnej maszyny. Druga generacja - Ponieważ operowanie ciągami zerojedynkowymi nie jest wygodne dla programisty, przypisano im łatwiejsze do zrozumienia znaki mnemotechniczne. Tak narodziły się 19/64 Materiały uzupełniające do wykładów z Języków Programowania II języki symboliczne, zwane też asemblerami. Choć stanowią proste tłumaczenie języka maszynowego na symbole i są ściśle związane z danym modelem komputera, to ułatwiają pisanie instrukcji i czynią je bardziej czytelnymi. Trzecia generacja - Kolejnym krokiem w rozwoju języków programowania było powstanie języków wysokiego poziomu. Symbole asemblera reprezentujące konkretne instrukcje zostały zastąpione kodem nie związanym z maszyną, bardziej zbliżonym do języka naturalnego lub matematycznego. Czwarta generacja - Na czwartą generację języków programowania składa się szereg narzędzi, które umożliwiają budowę prostych aplikacji przez zestawianie „prefabrykowanych” modułów. Obecnie wielu specjalistów uważa, że nie są to języki programowania w ścisłym znaczeniu, gdyż częstokroć stanowią jedynie rozszerzenie języków już istniejących. Niektórzy autorzy proponują stosować nazwę „czwarta generacja” wyłącznie w odniesieniu do programowania obiektowego (OOP). Piąta generacja - Nazwę „język piątej generacji” stosuje się czasem w odniesieniu do języków używanych do tworzenia programów wykorzystujących tzw. sztuczną inteligencję (AI) lub inaczej - systemów ekspertowych. 2.3 Podstawowe definicje. Język - jest to ogólna nazwa zdefiniowanego zbioru znaków i symboli oraz reguł określających sposoby i kolejność ich użycia. Język, który jest stosowany do przetwarzania algorytmów nosi nazwę języka algorytmicznego, a przy zastosowaniu go do celów programowania określony jest jako język programowania. Ponieważ komputer posługuje się językiem binarnym, tzn. rozróżnia stany 0,1, program w języku programowania należy przetworzyć tak, aby był zrozumiały dla maszyny – zadaniem tym zajmują się translatory. Język programowania - zbiór zasad składni, instrukcji, dzięki którym powstaje kod źródłowy programu. Procesor jest w stanie wykonywać program w kodzie maszynowym. Jednakże tworzenie programów w tym języku jest praktycznie niemożliwe. Dlatego programista używa języka zrozumiałego dla człowieka, który następnie jest kompilowany bądź interpretowany do postaci maszynowej. Istnieje wiele rodzajów języków programowania. Można je podzielić na języki strukturalne i obiektowe. Innym kryterium podziału jest zastosowanie języków (innych używa się do tworzenia programów multimedialnych, a innych do obliczeń numerycznych czy np. aplikacji sieciowych). Niektóre z języków są bardziej uniwersalne niż inne. Język niskiego poziomu (angielskie low-level language) – język programowania, w którym środki strukturalizacji kodu są ograniczone do co najwyżej podprogramów i makroinstrukcji. Polecenia w nim są zapisywane symbolicznie, a jednemu rozkazowi dla komputera odpowiada jeden rozkaz programisty. Do języków niskiego poziomu zalicza się języki adresów symbolicznych, czyli asemblery. Poziom języków programowania nie określa jego jakości, lecz rodzaj zastosowań. Język wysokiego poziomu (angielskie high-level language) – język programowania, zazwyczaj o budowie blokowej, spełniający wymagania programowania strukturalnego, programowania z użyciem obiektów lub nawet programowania obiektowego. Typowymi i najczęściej używanymi językami wysokiego poziomu są języki: C, C++, Smalltalk, Java, Pascal i Lisp, lecz również języki specjalizowane, np. język SQL służący do formułowania zapytań do baz danych lub edukacyjny język Logo. Istnieje wiele modyfikacji języków starszej generacji, np. Fortranu, Basica lub Cobolu, które po unowocześnieniu spełniają w zupełności kryteria języków wysokiego poziomu. Cechą znamienną dla nich jest możliwość bezpieczniejszego programowania, tj. programowania mniej 20/64 Materiały uzupełniające do wykładów z Języków Programowania II podatnego na błędy, i wynikająca z tego możliwość opracowywania większych programów (powyżej 10 000 wierszy kodu). Język maszynowy, język wewnętrzny (angielskie machine language) - wewnętrzna, dwójkowa reprezentacja rozkazów procesora. Do początku lat siedemdziesiątych rozruch niektórych typów komputerów wymagał wprowadzenia z konsoli elementarnego programu ładującego w postaci dwójkowych kodów języka maszynowego. Moduły wyrażone w dowolnym języku programowania są po ostatecznym przetłumaczeniu sprowadzane do postaci języka maszynowego. Język strukturalny (angielskie structural language) - język spełniający paradygmat programowania strukturalnego, tj. zaopatrzony w instrukcje strukturalne. Większość języków zaprojektowanych po 1970 spełnia wymogi strukturalności. Język proceduralny (angielskie procedural language) - język spełniający paradygmat programowania proceduralnego, np. Fortran, Pascal lub C, lecz także każdy nowszy język w swej warstwie proceduralnej. Język imperatywny (angielskie imperative language) – język, w którym program jest pojmowany jako ciąg wykonywanych po sobie instrukcji. Programista używający języka imperatywnego osiąga zamierzony efekt przez manipulowanie wartościami zmiennych. Przykładami języków imperatywnych są Pascal i C. Język problemowy - jest przeznaczony do określonych zadań. Do tworzenia programów powiązanych czymś ze sobą. Jego przeciwieństwo to język uniwersalny, taki jak np. Pascal, który może być zastosowany praktycznie do wszystkiego. Język obiektowy (angielskie object-oriented language) – język, który umożliwia realizowanie paradygmatu obiektowego, tzn. programowanie z użyciem hierarchii klas (zwłaszcza klas abstrakcyjnych). Popularnymi językami obiektowymi są: C++, Java, Smalltalk, Object Pascal, Beta, Theta, CLOS, Eiffel, Ada98, Python i in. W języku angielskim rozróżnia się też słabsze pojęcie: object-based language, tj. język umożliwiający stosowanie obiektów, w którym użytkownik może definiować i stosować własne typy danych. Od lat osiemdziesiątych języki obiektowe uważa się za szczytowe osiągnięcie inżynierii oprogramowania. Kod maszynowy - język rozumiany przez procesor. Program w kodzie maszynowym składa się z ciągu wartości binarnych, które oznaczają zarówno instrukcje jak i dane. Program, który jest napisany w pewnym języku programowania, musi zostać skompilowany, aby mógł być wykonywany przez komputer. Postać kodu maszynowego zależy od architektury procesora, na który dany program jest przeznaczony. Dlatego program musi zostać skompilowany na konkretnej maszynie, ewentualnie na systemie kompatybilnym z systemem docelowym. Kod źródłowy - program komputerowy napisany w języku programowania. Jest to postać programu, która jest zrozumiała dla programisty (bez konieczności jego uruchamiania). Kod źródłowy jest przekształcany na kod maszynowy w procesie kompilacji programu. Kod wynikowy (angielskie object code) - rezultat pracy translatora (np. kompilatora), nadający się do bezpośredniego wykonywania przez procesor albo wymagający dalszej obróbki (np. konsolidacji). 21/64 Materiały uzupełniające do wykładów z Języków Programowania II 2.4 Środowisko programistyczne. Jak zostało to wcześniej wspomniane, stworzenie działającego programu komputerowego wymaga posiadania translatora. Większość języków programowania, powstałych szczególnie w ostatnich latach, zawiera jednak znacznie więcej elementów: translator – służy do wykonania kompilacji lub interpretacji kodu źródłowego. Standardowym katalogiem, w których umieszcza się pliki translatora jest katalog BIN (w systemach Windows) w głównym katalogu aplikacji. Aby proces translacji był możliwy, system operacyjny musi znać dokładne położenie translatora i jego bibliotek. W tym celu należy dokonać odpowiedniego wpisu w pliku wsadowym autoexec.bat (czasami wpis tworzony jest automatycznie podczas instalacji). Przykłady: Fortran 90 SET PATH=C:\F90\BIN;"%PATH%" SET INCLUDE=C:\F90\INCLUDE;"%INCLUDE%" SET LIB=C:\F90\LIB;"%LIB%" VFort SET PATH=%PATH%;C:\VFort\Bin SET LIBRARY_PATH=C:\VFort\Lib Delphi 6.0 SET PATH=C:\ DELPHI6\BIN;C:\ DELPHI6\PROJECTS\BPL;%PATH% FreePascal SET PATH=C:\FreePas\Bin\Win32;%PATH% Przykłady są przedstawione dla przypadku, gdy każdy program zainstalowany jest bezpośrednio w katalogu głównym – inne położenie wymaga odpowiedniego wpisu. Podczas instalacji programu (języka programowania) należy pamiętać, że niektóre translatory, szczególnie starsze, nie akceptują długich nazw (np. kompilator G77) – co może stać się powodem niezrozumiałych z pozoru błędów (translator nie będzie działał). Może się również zdarzyć, że w pliku autoexec.bat będzie tak dużo wpisów do zmiennej PATH, że zajmą one całą przeznaczoną na nią pamięć, co w efekcie może doprowadzić do problemów z uruchomieniem systemu (plik win.com) – należy wówczas w miarę możliwości ograniczyć długości ścieżek. biblioteki i dodatkowe pliki wsadowe – służą do rozszerzania możliwości języka, szczególnie w zakresie pewnych zastosowań (np. obliczeń matematycznych, numerycznych, obróbki grafiki). Standardowo instalowane są w katalogach LIBRARY i INCLUDE w głównym katalogu aplikacji. Biblioteki podstawowe dostarczane są wraz z środowiskiem programistycznym, biblioteki dodatkowe rozprowadzane są w postaci osobnych pakietów. edytor kodu – służący do pisania tekstu kodu źródłowego. Edytory mogą być uniwersalne (np. ConText, Amigo, Crimson, Codex, EditPlus, UltraEdit, Editeur, EmEditor i inne) lub też zintegrowane z konkretną implementacją języka (np. Borland Delphi, Compaq Visual Fortran i inne). Edytory uniwersalne pozwalają na podłączanie kompilatorów jednego lub wielu języków i są rozprowadzane jako oddzielne programy. Podłączenie konkretnego kompilatora odbywa się poprzez odpowiednią definicję opcji programu. Zaletą edytorów jest to, że poprawiają znacznie przejrzystość i wygodę tworzenia kodu, a także „pomagają” pisać kod źródłowy programu 22/64 Materiały uzupełniające do wykładów z Języków Programowania II wyróżniając, zazwyczaj kolorem lub wytłuszczoną czcionką, słowa kluczowe danego języka – łatwo wówczas zauważyć błąd już na etapie jego popełniania. debugger (analizator kodu) – służy do analizy poprawności tworzonego kodu źródłowego i stanowi zazwyczaj integralną część translatora (może być to również oddzielny program). Podczas analizy kodu źródłowego generowane są informacje o błędach – czasami wymaga to podania dodatkowych opcji kompilacji – na bieżąco (analizator zatrzymuje się w miejscu wykrycia błędu) lub też w postaci końcowego raportu. Oprócz sygnałów o błędach, analizatory podają również tzw. ostrzeżenia, tzn. informacje o znalezieniu niejasności w kodzie lub o wykryciu miejsca potencjalnie niebezpiecznego. Typowym ostrzeżeniem jest wiadomość o wykryciu deklaracji zmiennej, która nie została nigdzie w kodzie wykorzystana. edytor formularzy – służy do budowy okien widzianych przez użytkownika po uruchomieniu programu (formularzy). Element ten występuje jedynie w językach wizualnych, takich jak Visual Basic, Delphi, Compaq Visual Fortan i innych. W różnych implementacjach języków, edytor formularzy może być dostępny bezpośrednio po uruchomieniu programu lub też po wybraniu odpowiedniej opcji z menu. Zaletą stosowania tego narzędzia jest łatwość tworzenia dowolnie skomplikowanych okien i określania ich właściwości. Nie traci się wówczas czasu na pisanie elementów kodu, odpowiedzialnych za tworzenie się formularzy i ich elementów, a programista skupia się jedynie na realizacji założonego algorytmu. Brak edytora formularzy nie przesądza o tym, że nie można tworzyć standardowych, „okienkowych” aplikacji – wygląd definiowany jest wówczas przez programistę w kodzie źródłowym. menadżer projektu – służy do zarządzania modułami i plikami projektu. Rzadko bowiem tak się zdarza, że cały kod źródłowy zawarty jest w jednym pliku – przeważnie jest ich wiele i zawierają nie tylko poszczególne moduły kodu, ale również biblioteki, różne pliki wsadowe, grafikę i pliki multimedialne. Zazwyczaj istnieje główny plik projektu zawierający wszystkie potrzebne do kompilacji informacje. Z pomocą menadżera łatwo można modyfikować zawartość i strukturę projektu. narzędzia dodatkowe – służą do tworzenia systemu pomocy, ikon i kursorów, programów instalacyjnych. Ilość narzędzi i poziom ich zaawansowania zależy od implementacji języka. system pomocy – służy do uzyskiwania informacji o środowisku programistycznym, zasadach jego użytkowania, elementach języka (wraz z przykładami), rodzaju licencji, autorach i kontaktach. Zależnie od implementacji języka oraz jego rodzaju pomoc może być mniej lub bardziej rozwinięta. Dobrze zorganizowanie, obszerne systemy pomocy zawierają często kompendium wiedzy na temat danego języka programowania. 2.5 Etapy kompilacji. Proces przetwarzania kodu źródłowego na plik wykonywalny typu *.exe składa się kilku etapów: etap preprocesingu – jego zadaniem jest wstępne przygotowanie programu do właściwej kompilacji. W tej fazie mogą być również dołączane dodatkowe pliki, realizuje się to specjalną instrukcją (np. INCLUDE) umieszczoną na początku kodu źródłowego. Po napotkaniu takiej instrukcji preprocesor wstawi zawartość odpowiedniego pliku. Zazwyczaj w ten sposób włącza się do kodu źródłowego pliki z deklaracjami funkcji lub informacją o rozmiarach zmiennych indeksowanych. etap kompilator – służy do przetłumaczenia kodu źródłowego na kod wynikowy (binarny), zrozumiały dla komputera. 23/64 Materiały uzupełniające do wykładów z Języków Programowania II etap konsolidacji (linkowania) – służy do dołączania bibliotek do tworzonego programu. Jeżeli dany program używa funkcji z bibliotek, niezbędne jest aby taka biblioteka została do tego programu dołączona. Biblioteka jest również pewnym „programem”, który różni się tylko tym iż nie może być samodzielnie uruchomiony. Po prostu zawiera on tylko funkcje, do których odwołują się inne programy. Po konsolidacji program jest gotowy do użycia. kod źródłowy preprocesor kompilator konsolidator (linker) plik wykonywalny Rys. 1. Etapy kompilacji. 2.6 Podział języków programowania. Podział ze względu na rodzaj translacji: • • kompilowane, interpretowane. Podział ze względu na strukturę2 (1): • • języki proceduralne (imperatywne) – programista określa JAKIE operacje maja być wykonane i JAKIEJ KOLEJNOŚCI języki nie proceduralne (deklaratywne) – programista opisuje to, CO chce wykazać. Decyzja JAK to wykonać należy do kompilatora. Podział ze względu na strukturę3 (2): • • 2 3 języki strukturalne – program rozbity na procedury (podprogramy), z których każda odpowiada za rozwiązanie określonego problemu. Procedury stanowią wtedy odrębne, samodzielnie działające całości, które możemy wykorzystać także i w innych pisanych programach. języki niestrukturalne – brak wydzielonych obszarów odpowiedzialnych za rozwiązywanie określonych problemów. http://orfi.geo.kortowo.pl/kierunek/przedmioty/wstep/99/jez1.htm http://orfi.geo.kortowo.pl/kierunek/przedmioty/wstep/99/jez1.htm 24/64 Materiały uzupełniające do wykładów z Języków Programowania II Podział języków ze względu na zastosowania4: a) algorytmiczne: do zapisywania algorytmów • • • • • algebraiczne (Fortran, Pascal, C) - do zapisu algorytmów numerycznego przetwarzania informacji ekonomiczne (COBOL, PL/1) - opis algorytmów przetwarzania informacji o charakterze ekonomicznym, bankowym, handlowym. Rozbudowane mechanizmy operacji we/wy i pewne możliwości wykonywania operacji na danych nienumerycznych. do symbolicznego przetwarzania informacji (LISP) - do zapisu algorytmów przetwarzania informacji numerycznych i na danych symbolicznych języki symulacyjne (SIMULA) - ułatwiają opisywanie algorytmów modelowania i symulacji bezpośredniego dostępu (BASIC) - pozwalają na konwersję z maszyną. b) problemowe - ściśle dostosowane do konkretnej klasy zadań. Podział według struktury (3): • • języki strukturalne (Fortran, Pascal, Algol) języki zorientowane obiektowo5 (C++ , Visual C++, Turbo Pascal, Delphi, Smalltalk, Objective-C, Eiffel , Lisp, Oberon, Actor , CLOS, Ada95, Prolog++, Zink, JAVA, J++, Visual Objects, Python): W ostatnich latach w projektowaniu oprogramowania zorientowanego obiektowo wykształcił się wyraźny podział na: • • • OOA - Object Oriented Analysis (Analiza Zorientowana Obiektowo) OOD - Object Oreinted Design (Projektowanie Zorientowane Obiektowo) OOP - Object Oriented Programming (Programowanie Zorientowane Obiektowo) 2.7 Przegląd języków programowania. Asembler – język najbliższy kodu maszynowego. Języki wyższego rzędu często tłumaczą najpierw na asembler, potem na kod maszynowy. Darmowe kompilatory: Flat Assembler, New Basic Assembler. Visual Assembler. BASIC (Begginers All-purpose Symbolic Instruction Code) - przełomowy w chwili powstania w 1964, potem mocno krytykowany za brak strukturalności, prosty, interpretowany język programowania, spopularyzowany w komputerach ośmiobitowych i kalkulatorach programowanych. Jego twórcy – J. Kemeny i T. Kurtz (Dartmouth College, USA) – przedstawili go jako rewolucyjną propozycję wobec języków algolopodobnych. Basic z założenia nadawał się do pracy interakcyjnej i miał ujmować prostotą (m. in. brak typów, numerowane instrukcje ułatwiały redagowanie programu). Pierwsze implementacje Basica były wykonywane na minikomputerach, a nawet na komputerach stacjonarnych (m. in. na polskich komputerach ODRA 1204 i ODRA 1305, także w wersji kompilowanej). Oprzyrządowany w podstawowe operacje plikowe Basic na długo stał się nie tylko podstawowym językiem mikrokomputerów, lecz także ich systemem operacyjnym. Mimo przydatności do programowania doraźnego w małej skali, oryginalny Basic został odrzucony jako nieprzystosowany do nauczania początkowego informatyki i wyparty przez strukturalny język Logo. Odrodzony i zmetamorfozowany zarówno pod względem struktur sterowania i danych, jak i 4 5 http://orfi.geo.kortowo.pl/kierunek/przedmioty/wstep/99/jez1.htm 27 25/64 Materiały uzupełniające do wykładów z Języków Programowania II interfejsu systemowego Basic znajduje szerokie zastosowanie w programowaniu aplikacji dla komputerów typu PC pod postacią platformy programowania RAD o nazwie VisualBasic. W tym nowoczesnym produkcie z Basica pozostała głównie nazwa. Fortran (FORmula TRANslation - czyli „tłumacz formuł") - jeden z pierwszych szeroko używanych, algorytmicznych języków programowania, opracowany przez J. Backusa w 1957 roku. Po wielu unowocześnieniach jest stosowany do dzisiaj. Język Fortran powstał jako wynik wczesnych doświadczeń w programowaniu komputerów za pomocą autokodów z lat 1951-56. Pierwszą implementację Fortranu wykonano dla maszyny IBM-704. W 1958 powstała wersja Fortran II wprowadzająca możliwość kompilacji niezależnej (IBM-704), a w 1959 jej odpowiednik dla komputera IBM-709. Kolejna wersja Fortranu nosiła nazwę XTRAN, jej autorzy weszli w skład grupy projektującej język Algol 58. Wersja Fortran IV nosiła już wyraźny wpływ języka Algol. Kolejne implementacje to: Fortran II, Fortran IV, Fortran 77, Fortran 90, Fortran 95, Lahey Fortran, Compaq Visual Fortran. W latach sześćdziesiątych XX wieku IBM-owski Fortran spopularyzował się na komputerach różnych typów – zaletą jest duży stopień standaryzacji: od PC do superkomputerów. Fortran posiada z reguły kompilatory (interpreter o nazwie „Watfive” mało popularny). Główne zastosowanie Fortranu to zastosowania numeryczne (rozbudowane biblioteki procedur numerycznych), naukowe i inżynierskie, wymagające programów o dużej szybkości działania. Darmowe kompilatory: G77 (VFort, Prospero). APL (A Programming Language) - język wysokiego poziomu, stosowany do obliczeń w wyższej matematyce i zagadnieniach inżynierskich (w USA w środowisku inżynierów 80% programów bazuje na APL). Cechą charakterystyczną środowiska APL są specjalne klawiatury z greckimi literami. Język APL umożliwia wykorzystania komputera jako super-kalkulatora: oferuje wielowymiarowe tablice liczb - główne struktury danych. Język J - nowsza wersja APL, nie wymagającą znaków specjalnych na klawiaturze. APL2 - lansowany przez IBM jako interakcyjne narzędzie do rozwiązywania problemów, wizualizacji danych i dostępu do baz danych. Pascal – strukturalny język programowania stworzony w 1971 roku N. Wirth z Politechniki w Zurychu jako język przeznaczony do nauki programowania. Pozostaje on przez to jednym z najszerzej znanych i popularnych języków, zwłaszcza wśród początkujących programistów. Popularność zdobył dzięki implementacji TurboPascal (1983) firmy Borland. TP ma wiele rozszerzeń, dobre zintegrowane środowisko: edytor, debuger, projekty, doskonała pomoc, stosunkowo duża szybkość kompilacji i wykonania, ale bardzo długo ograniczenia pamięci do 64 K. Istnieje wiele udanych kompilatorów i narzędzi do programowania w Pascalu. Siła języka rozbudowane struktury danych. Typ prosty porządkowy, wyliczeniowy, okrojony, całkowity (shortint, longint, byte), logiczny znakowy (bajt), rzeczywisty (single, double, extended, comp), łańcuchowy, strukturalny, tablicowy, rekordowy, zbiorowy, plikowy, wskaźnikowy. Darmowe kompilatory: Free Pascal, TMTPascal, Inno Pascal, Bloodshed Dev-Pascal, Virtual Pascal, Compas, Ipcute, Irie Pascal. Modula, Modula-2 - wersje języka programowania wysokiego poziomu, będącego pochodną języka pascal. Język Modula-2 został opracowany przez N. Wirtha w 1980 (pierwsza implementacja na PDP-11 w 1979). W języku Modula (podobnie jak w nowszych wersjach języka Pascal), doceniono znaczenie modularyzacji w budowie oprogramowania. Poszczególne części programu w tym języku mogą niezależnie opracowywać różne osoby, przy czym istnieje system komunikacji między modułami będącymi jednostkami kompilacji. Język pozwala odwoływać się bezpośrednio do sprzętu oraz umożliwia programowanie współbieżne. Implementacje języka: 26/64 Materiały uzupełniające do wykładów z Języków Programowania II Modula-Prolog - do programowania logicznego Modula/R - do programowania baz danych. Modula-2 i Modula-3 o orientacji obiektowej. Oberon, Oberon-2 – są to kolejne dwa języki Wirtha, zbliżone do języków obiektowych, mało znane. Język C – proceduralny język programowania wysokiego poziomu, zaprojektowany w 1972 przez D. M. Ritchiego i zrealizowany pod systemem operacyjnym UNIX dla komputera PDP-11. Początkowo C był językiem oprogramowania systemowego (powstał jako język do przeprogramowania systemu UNIX). Szybko zyskał popularność jako uniwersalny język programowania. Cechami języka C są zwięzłość i elastyczność, przy jednoczesnym przerzucaniu dużej odpowiedzialności na programistę (nie ma np. wbudowanej kontroli indeksowania tablic). Język C ma duże możliwości, pozwala dobierać się do rejestrów procesora podobnie jak asembler, łatwo przenosić programy C między różnymi systemami komputerowymi. Struktury danych w C są prostsze niż w Pascalu. W latach 1983-1988 język C uległ standaryzacji. Znormalizowany język C nosi nazwę ANSI C. Jest to jeden z najczęściej obecnie używanych języków na PC. Ada - język powstał na zlecenie Departamentu Obrony (DoD) USA, gdyż żaden istniejący język nie spełniał ich wymagań. Wymagania: zmniejszyć koszty oprogramowania, zapewnić bezbłędność programu (bezpieczeństwo), ułatwić dalszy rozwój oprogramowania (czytelność), stosować naturalne konstrukcje, zapewnić sprawność. Ada 95 - rozszerza wymagania o większe możliwości współpracy z innymi językami, giętkość konstrukcji języka (używanie obiektów), kontrolę nad zarządzaniem bazami danych i synchronizacją rozproszonych danych oraz standaryzacją bibliotek oprogramowania. Ada 95 jest pierwszym obiektowo zorientowanym językiem, który przeszedł przez proces standaryzacji. Jest uniwersalnym językiem programowania, nadaje się również do programowania w czasie rzeczywistym (sterowanie procesami). Pozwala nawet wstawiać fragmenty kodu maszynowego do programu. Ada jest językiem bogatym, niełatwo go dobrze opanować. Przeprowadzone w połowie lat 90-tych badania efektywności programowania w C i w Adzie pokazały, ze koszty rozwoju programów w C były dwukrotnie wyższe. Składa się na to kiepska czytelność programów napisanych w C i trudności w usuwaniu w nich błędów. Na etapie tworzenia programów zanotowano 70% mniej błędów, a na etapie obsługi klienta aż 90% mniej błędów korzystając z Ady zamiast C. Kompilatory muszą przejść ostre testy zgodności ze standardem. GNAT to darmowy kompilator Ady 95. Darmowe kompilatory: Gnat. Forth - ciekawy język, opracowany przez Charlesa Moore około 1970 roku do sterowania radioteleskopem, początkowo realizacje na 8-bitowych komputerach, 1994 - standard ANSI Forth. Prosty język, programy są niewielkie, efektywne ale mało czytelne. Odwrotna Polska notacja (Reverse Polish Notation, RPN), używaną również w popularnych kalkulatorach HewlettaPackarda. Np. (3+4)*5 trzeba napisać: 3 4 + 5 * . __35 ok. Programowanie = definiowanie słów z listy ok. 30 słów bazowych, słowa kompilowane są w całość i dodawane do listy słów. Hierarchia słów = program. Wady: mało używany i nie ma chyba szans na rozpowszechnienie. Darmowe kompilatory: Forth, Forth CMP, GForth, KForth, PForth, Tile-Forth, WForth Logo – edukacyjny język programowania, biorący początek z badań nad psychologią uczenia się i jego wpływem na kształtowanie osobowości (J. Piaget). Logo stworzone zostało w latach 60-tych przez Daniela Bobrowa, Wallace'a Feurzeiga oraz Seymura Paperta, profesora informatyki z MIT (język ten został spopularyzowany przez niego w książce, rewolucyjnej z punktu widzenia metodologii nauczania, pt. Burze mózgów – dzieci i komputery - Wydawnictwo Naukowe PWN, 1996). Logo "ucieleśnia" wiele idei Piageta dotyczących sposobu uczenia się dzieci. Język programowania ma umożliwiać łatwy start - już siedmiolatki mogą go używać - a przy tym 27/64 Materiały uzupełniające do wykładów z Języków Programowania II stwarzać nieograniczone możliwości w miarę nauki. Sterowanie "żółwiem" na ekranie lub prawdziwym robotem: "DOPRZODU 10" (FORWARD 10) lub "WPRAWO 90" (RIGHT 90). Logo jest stosowane w początkowym nauczaniu matematyki oraz jako język komunikacji dziecka z komputerem; odznacza się interakcyjnością, znakomicie przemyślanym, prostym zestawem operacji graficznych i ogólnością składni wzorowanej na języku Lisp. W Polsce język Logo jest powszechny od połowy lat osiemdziesiątych XX w. Ze względu na swoje szczególne zastosowanie słownik języka Logo ma liczne realizacje narodowe, w szczególności z użyciem wyrazów polskich, np. AC Logo, lub Logo Komeniusz (pracujące w systemie Windows). Darmowe kompilatory: MSW Logo, Visual Logo, Berceley Logo, Elica, Geomland, rLogo, NetLogo, StarLogo, TinyLogo. Cobol (COmmon Business Oriented Language) - uniwersalny język programowania do zastosowań gospodarczych, głównie do zagadnień finansowych, dla banków, mniej administracyjnych (brak bazy danych). Bardzo wielu programistów i wielkie na nich zapotrzebowanie, gdyż problem roku 2000 - głównie z powodu programów napisanych w Cobolu. Język wywodzi się z USA z końca lat pięćdziesiątych. Raport pierwotny o języku Cobol z 1961 (G. Hopper), ulepszany do 1965, kolejne wersje do 1973. Proces normalizacji języka Cobol podjęto w 1963. Język Cobol umożliwia przetwarzanie tabel, sekwencyjny i bezpośredni dostęp do danych, sortowanie i indeksowanie, generowanie raportów, segmentowanie programu i stosowanie bibliotek. Charakterystyczną cechą tego języka jest rozwlekła notacja (konstrukcje zbliżone do naturalnego opisu problemu w języku angielskim, autodokumentacja). Programy długie ale łatwo zrozumiałe. Rozbudowane struktury danych, np. rozgałęzione typu drzewa, rekordy. W Cobolu wykonano olbrzymie ilości oprogramowania przetwarzania danych użytkowanego do dzisiaj. Ostatni standard ISO/ANSI wprowadzony w 1985 roku. The Cobol Foundation dba o rozwój języka. Istnieją dobre kompilatory na PC, również darmowe. Środowiska do budowania graficznego interfejsu użytkownika i środowiska 4 generacji. Darmowe kompilatory: Fujitsu Cobol, Tiny Cobol, Cobol 650, GNU Cobol2c. PL/I – język opracowany w 1964 roku, stanowi połączenie Fortranu i Algolu z COBOLem. Rozbudowane i niezależne od sprzętu typy danych, dynamiczna alokacja pamięci, prawie 200 wbudowanych operacji na zmiennych numerycznych i tekstowych, dobra komunikacja z urządzeniami zewnętrznymi. Nigdy nie zdobył większej popularności. LISP (LISt Processing) – język programowania oparty na przetwarzaniu list. Główny wkład w jego powstanie w latach 50. wniósł J. McCarthy, profesor wielu amerykańskich uczelni, m.in. Instytutu Technologicznego Massachusetts i Uniwersytetu Stanforda. Wywodzi się z badań teoretycznych nad tzw. rachunkiem lambda i stał się podstawowym językiem sztucznej inteligencji. Prowadzenie dialogu w języku naturalnym, programy diagnostyki medycznej, systemy algebry symbolicznej. Język aplikatywny: wszystkie konstrukcje LISPu są wynikiem zastosowania funkcji do argumentów. Np. wyrażenie x^2+y wymaga funkcji plus i times: (plus (times x x) y). Rekurencja, programy jak i dane są listami, programy mogą zmieniać siebie. Wiele implementacji: Common LISP (1984), rozszerzenia, np. CLOS, CLIM, Iterate i Screamer. PROLOG (PROgraming in LOGic) – język programowania używany w logice (stąd jego nazwa będąca akronimem słów). Rozwijany od początku lat 70-tych, Marsylia, Edynburg. Łatwiejszy niż LISP, reprezentacja logiczna wiedzy, analiza języka naturalnego. Wbudowana baza danych, rekurencja. Dobre realizacje na PC, np. TurboProlog (Borland). Liczne rozszerzenia, Prolog II, Prolog III, Prolog ++ (obiektowy), Visual Prolog. Używany do budowy powłok systemów ekspertowych (Expert system shells) - wystarczy wpisać wiedzę by prowadzić rozumowania. KEE - Knowledge Engineering Environment, czyli Środowisko Inżynierii Wiedzy. LOOKS system reprezentacji wiedzy do projektowania systemów doradczych korzystających z programowania logicznego; POP (Package for On-Line Programming, czyli pakiet programowania 28/64 Materiały uzupełniające do wykładów z Języków Programowania II interakcyjnego) i nowsze wersje: POP-11, POP++, POPLER, POPLOG (środowisko), PopTalk do programowania systemów doradczych. Autoprogramowanie i języki naturalne: do prostych zastosowań, np. raportów z baz danych.The Last One - język autoprogramowania, napisany już w 1982 roku ... Smalltalk - uniwerslany język obiektowy, dla potrzeb muzyki, gier komputerowych, inteligentnych baz danych, programów dla robotów, przetwarzania sygnałów z oscyloskopu, zarządzania centralami telefonicznymi (USA), systemami kolejkowania na dużych instalacjach komputerowych, testowania półprzewodników i oceny kosztów produkcji samochodów, zastosowania w systemach informacyjnych dla potrzeb biznesu. Sporo udanych implementacji, darmowy kompilator GNU Smalltalk. Darmowe kompilatory: Dolphin, Squeak. Eiffel – język obiektowy, dobry do treningu metod konstrukcji oprogramowania i do nauczania programowania. Darmowe kompilatory: Eiffel. C++ - najczęściej stosowany język obiektowy - nie jest to język czysto obiektowy, ma pewne ograniczenia. Ogromne rozbudowanie i trudne do opanowania środowiska, pełne bardzo rzadko używanych obiektów. Wiele udanych realizacji: Borland C++ Builder, środowisko 4GL dla C++. Darmowe kompilatory: Bloodshed C++, Borland C++ Builder, LCC Win, Mars. Visual C++ - Warsztat Programisty (Visual Workbench) - środowisko obiektowe do tworzenia programów, pozwalające na edycję, kompilację i śledzenie błędów w opracowywanym programie; Studio Aplikacji (AppStudio) - do budowania graficznego systemu dialogu z użytkownikiem i edycji programów; Czarodziej Aplikacji (AppWizard) - szybkie "składanie" obiektów znajdujących się w bibliotece i tworzenie szkieletu programu; Czarodziej Klas (ClassWizard) - śledzenie wykonywania programu i modyfikację obiektów. SQL – popularny język do zarządzania bazami danych. Bazy danych zawierają własne języki, np.: Oracle, Ingres, Informix, Paradox, dBase, Sybase, FoxPro, MS Access. HTML (HyperText Markup Language) – specjalny język służący do opisu strony oraz odniesień z poszczególnych jej elementów do innych dokumentów. Język ten powstał na potrzeby internetowej usługi WWW. Umożliwia umieszczenie na stronie tekstu zdefiniowanych dyrektyw co do sposobu jego prezentacji, wyróżnienia pewnych jego elementów edytorskich jak akapity, nagłówki itp. Pozwala także umieszczać bezpośrednio na opisywanych stronach grafikę, a w najnowszych wersjach również inne typy dokumentów. Pewne zdefiniowane przez autora strony elementy (np. fragmenty tekstu) mogą dodatkowo wskazywać na inne dokumenty. Wskazanie takie odbywa się przez zdefiniowanie tzw. URL jednoznacznie określającego dokument w obrębie odpowiedniej przestrzeni (np. w lokalnej kartotece lub w sieci Internet). Technikę tą określa się mianem hipertekstu. Strony napisane tym języku są interpretowane przez przeglądarkę WWW taką jak np. Netscape Navigator lub Internet Explorer. HTML jest stale rozwijany, a kolejne jego wersje wzbogacane są o nowe możliwości. Pliki zawierające strony napisane w języku HTML charakteryzują się rozszerzeniem “.html” bądź “.htm”. DHTML - (z angielskiego Dynamic HTML), rozszerzenie języka HTML o wzorce stylu (style sheets), rozmieszczanie elementów na stronie WWW według upodobań użytkownika (content positioning) oraz możliwość stosowania indywidualnych krojów pisma, sprowadzanych z komputera macierzystego danej strony WWW (downloadable fonts). Java - popularny język programowania obiektowego autorstwa J. Goslinga, zaprojektowany w firmie Sun Microsystems, używany szeroko do oprogramowywania specjalizowanych mikroprocesorów, wzbogacania prezentacji danych zawartych w dokumentach HTML, 29/64 Materiały uzupełniające do wykładów z Języków Programowania II pamiętanych w komputerach sieci Internet oraz do opracowywania samodzielnych aplikacji wielowątkowych i rozproszonych. Kompilatory języka Java produkują bajtokod, który nadaje się do interpretacji w środowisku JVM. Znaczenie języka Java systematycznie rośnie. 30/64 Materiały uzupełniające do wykładów z Języków Programowania II 3 Elementy języków programowania. Języki programowania wymyślono po to, by można było dzięki nim tworzyć różnorodne programy komputerowe. Oczekuje się również, że tworzone aplikacje będą wykonywać swoje zadania w sposób jednoznaczny i zgodny z określoną na etapie projektowania specyfikacją wymagań - języki programowania muszą się więc opierać na ogólnie obowiązujących zasadach logiki i arytmetyki. Z tego też względu, można wyodrębnić w strukturach różnych języków szereg elementów uniwersalnych, spełniających w nich analogiczną rolę. 3.1 Podstawowe cechy języków programowania6: • Ściśle określony zbiór znaków i symboli. Używanie znaków niedozwolonych spowoduje wystąpienie błędów podczas translacji kodu źródłowego. Zakres znaków obejmuje duże i małe litery alfabetu (rozróżniane bądź nie), cyfry oraz znaki specjalne i symbole wieloznakowe. Mimo, że wiele języków programowania posiada podobny zestaw znaków dopuszczalnych, niektóre z nich mogą mieć zupełnie inne znaczenie. Przykładem może być znak „//” - w FORTRANIE służący do łączenia łańcuchów tekstowych, zaś w PASCALU do oznaczenia wiersza komentarza. Fortran Pascal ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz 1234567890 +-/*.,= ( ):_ + - * / = ^ < > ( ) [ ] { } . , : ; ‘ # $ @ spacja _ .LT. .LE. .EQ. .NE. .GE. .GT. .AND. .OR. := <> <= >= .. (. .) (* *) .NOT. .EQV. .NEQV. Tab. 1. Zestaw znaków i symboli dopuszczalnych w językach Fortran oraz Pascal. • Skończona (zazwyczaj) liczba słów kluczowych i deklaratorów. Słowa kluczowe są to określone zbiory znaków posiadające konkretne znaczenie dla translatora (najczęściej są to wyrazy z języka angielskiego, np. WRITE, READ, PROGRAM, FOR, DO, itd.). Fortran assign backspace block data call character close common complex continue data dimension do double precision else elseif end endif endfile entry equivalence err external file format function goto if implicit integer inquire intrinsic iostat logical open Pascal parameter pause print program read real return rewind save single status stop subroutine then unit write and array asm begin case const constructor destructor div do downto else end file for function goto if implementation in inherited inline interface label mod nil not object of or packed procedure program record repeat set shl shr string then to type unit until uses var while with xor Tab. 2. Zestaw słów kluczowych występujących w językach Fortran oraz Pascal. 6 Poniższy rozdział dotyczy języków najbardziej przydatnych z punktu widzenia inżyniera nie-informatyka, takich jak: FORTRAN, PASCAL czy BASIC. 31/64 Materiały uzupełniające do wykładów z Języków Programowania II Bardzo często edytory kodu źródłowego stosują wyróżnienia dla słów kluczowych (pogrubienie czcionki lub kolory), co ułatwia jego pisanie i zmniejsza prawdopodobieństwo wystąpienia błędu. W przypadku braku automatycznego wyróżnienia należy stosować duże i małe litery, np. instrukcje pisać dużymi literami, a inne nazwy małymi. Nazwy takie jak SIN, COS, LOG, MOD, itd. nie są słowami kluczowymi lecz nazwami funkcji wewnętrznych. Oprócz słów kluczowych w językach programowania występują również deklaratory, czyli słowa odpowiadające za określanie obiektów lub ich właściwości. • Ściśle określona struktura i zasady pisania kodu źródłowego. Kod źródłowy składa się z przynajmniej jednego modułu (programu), który musi mieć sztywno określoną budowę. Moduł musi posiadać wyraźnie określony początek i koniec, obszary deklaracji obiektów i typów występujących zmiennych oraz obszary zawierające bloki instrukcji, funkcji lub procedur. Budowa kodu źródłowego zależy w decydujący sposób od rodzaju języka i sposobu realizacji drogi punktu sterowania. Fortran Używanie jedynie znaków dopuszczalnych Brak rozróżnienia znaków pisanych małą lub wielką literą. Znaków narodowych nie należy używać (nawet w komentarzach). Nazwy (identyfikatory) zmiennych, stałych, podprogramów, funkcji, itd. powinny zaczynać się od litery i nie powinny być dłuższe niż 6 znaków (słowa kluczowe mają budowę identyfikatorów, ale mogą być dłuższe). Treść instrukcji wpisuje się między 7 a 72 kolumną. Nie ma obowiązku zaczynania od 7 kolumny. Znaki za 72 kolumną są ignorowane. Odstępy umieszczane w instrukcjach są ignorowane. Dlatego też nie ma różnicy pomiędzy np. instrukcją GOTO 10 a GO TO 10. W celu zwiększenia czytelności programu należy stosować wcięcia – szczególnie podczas stosowania instrukcji zagnieżdżonych. W jednym wierszu może znajdować się tylko jedna instrukcja (polecenie wykonujące jakiś fragment algorytmu programu). Instrukcje przypisania realizowane są za pomocą znaku „=”. Na końcu wiersza nie stawia się żadnego znaku. Poszczególne bloki programu zaczynają się i kończą w sposób dowolny. Pascal Używanie jedynie znaków dopuszczalnych Brak rozróżnienia znaków pisanych małą lub wielką literą. Znaków narodowych nie należy używać (nawet w komentarzach). Nazwy (identyfikatory) zmiennych, stałych, podprogramów, funkcji, itd. powinny zaczynać się od litery – długość dowolna. Treść instrukcji wpisuje się w dowolnej kolumnie. Odstępy w kodzie (spacje) są ignorowane. Dlatego też nie ma różnicy pomiędzy zapisem np. x:=4 a x := 4. W celu zwiększenia czytelności programu należy stosować wcięcia – szczególnie podczas stosowania instrukcji zagnieżdżonych. W jednym wierszu może znajdować się kilka instrukcji, np. if x=1 then y:=1 else y:=0; Instrukcje przypisania realizowane są za pomocą znaku „;=”. Na końcu wiersza stawia się zazwyczaj średnik. Poszczególne bloki programu zaczynają się i kończą w sposób dowolny, ale muszą być umieszczone między słowami BEGIN i END. Główny blok programu rozpoczyna się słowem Główny blok programu rozpoczyna się słowem PROGRAM z nazwą, a kończy słowem END. Po PROGRAM z nazwą, a kończy słowem END z kropką END nie stawia się kropki. na końcu. Warunki arytmetyczne i logiczne określane są Warunki arytmetyczne określane są znakiem „=”. znakami literowymi (patrz punkt 1). Jedna instrukcja może zajmować maksymalnie 20 Jedna instrukcja może zajmować dowolną liczbę wierszy, przy czym pierwszy wiersz nazywa się wierszy. wierszem początkowym, a pozostałe wierszami kontynuacji. Każdy wiersz kontynuacji należy zaznaczyć poprzez umieszczenie w szóstej kolumnie znaku różnego od zera i spacji. W programie należy umieszczać komentarze. Są to W programie należy umieszczać komentarze. Blok fragmenty programu, które są ignorowane przez komentarza zaznacza się nawiasem klamrowym kompilator i służą jedynie do orientacji dla { komentarz }. Pojedyncze wiersze komentarza można 32/64 Materiały uzupełniające do wykładów z Języków Programowania II programisty. Wiersz komentarza zaczyna się znakiem * lub C w pierwszej kolumnie – dalej mogą być dowolne znaki. Komentarz można również dodać na końcu linii, w której znajdują się instrukcje – należy wówczas postawić znak !. Wiersze z samymi spacjami traktowane są jak wiersze komentarzy. W kolumnach 1-5 można wpisywać tzw. etykiety – niepowtarzalny ciąg cyfr (do 5 cyfr) – identyfikujące określone miejsce w programie. Numery etykiet powinny być nadawane w odstępach – standardowo co 10 – daje to możliwość dopisania nowych etykiet pomiędzy już istniejące. W programie najpierw umieszcza się deklaracje, a dopiero po nich instrukcje. Deklaracja zmiennych: typ nazwa Zmienne są lokalne, tzn. obowiązują w obszarze jednego modułu. Wymiana wartości jest możliwa poprzez stosowanie określonych instrukcji. Podczas pisania programu należy dążyć do zminimalizowania liczby zmiennych. Podczas pisania programu należy dbać o jego przejrzystość - dlatego też zalecane jest używanie podprogramów i funkcji. zaczynać od znaku //. Brak etykiet (istnieje możliwość przypisywania etykiet instrukcją LABEL). – W programie najpierw umieszcza się deklaracje, a dopiero po nich instrukcje. Deklaracja zmiennych: nazwa : typ; Zmienne mogą być lokalne lub globalne. Zależy to od miejsca deklaracji zmiennej (PRIVATE lub PUBLIC). Podczas pisania programu należy dążyć do zminimalizowania liczby zmiennych. Podczas pisania programu należy dbać o jego przejrzystość - dlatego też zalecane jest używanie podprogramów i funkcji. Tab. 3. Zasady pisania kodu źródłowego w językach Fortran oraz Pascal. • Występowanie zasady jednoznaczności identyfikatorów w obrębie jednego projektu. Identyfikatory są to nazwy programów, modułów, bloków, podprogramów, procedur, funkcji i zmiennych. Ponieważ działanie każdego programu oparte jest na pewnych logicznych zasadach, nie może dochodzić do sytuacji, w których translator nie wie o jaki moduł, funkcję czy procedurę chodzi. Większość języków programowania kontroluje, przynajmniej w podstawowym zakresie, nazwy poszczególnych struktur i zgłasza błędy o powtarzających się nazwach lub ich błędnej budowie. Podobnie jest z nazwami zmiennych, istnieje jednak możliwość deklarowania takich samych nazw w obszarach różnych podprogramów, funkcji lub procedur (tzw. zmienne lokalne) – może to jednak prowadzić do wystąpienia niejasności i w konsekwencji błędów. Fortran Przykłady: program Silnia program Write integer n, krok real program, sin procedure read Pascal Przykłady: - poprawnie - błędnie - poprawnie - błędnie - błędnie program Kalkulator; program Public; n, krok : byte; program, sin : real; procedure open; - poprawnie - błędnie - poprawnie - błędnie - błędnie Tab. 4. Przykłady poprawnego i błędnego deklarowania nazw w językach Fortran oraz Pascal. • Konieczność komunikacji z użytkownikiem. Potrzeba taka dotyczy również innych urządzeń komputera, a także zapisu i odczytu danych z plików. Czynności takie nazywane są operacjami wejścia-wyjścia. Standardowo do komunikacji z użytkownikiem służy klawiatura (ewentualnie myszka) i monitor. Pobieranie danych z klawiatury (lub pliku) wymaga wcześniejszego zadeklarowania typu zmiennej (chyba, że istnieje możliwość niejawnej deklaracji typu) - wprowadzany typ będzie wówczas jednoznaczny i zgodny z oczekiwaniami. Podczas wyprowadzania danych na monitor (lub do pliku) należy ustalić ich format (wygląd). Podczas zapisu (odczytu) danych do pliku należy dodatkowo określić rodzaj pliku. 33/64 Materiały uzupełniające do wykładów z Języków Programowania II • Potrzeba sterowania formatem (wyglądem) zmiennych. Formatowanie jest dokonywane podczas wyprowadzania wartości danych na ekran monitora lub podczas zapisu do plików. Formatowanie zmiennych nie zawsze jest konieczne (każdy język programowania posiada domyślne sposoby zapisu poszczególnych typów zmiennych) ale może być bardzo przydatne – można zażądać, aby wszystkie liczby miały tą samą ilość znaków i były zapisane np. w postaci wykładniczej o określonej liczbie cyfr po przecinku. • Konieczność jawnego lub niejawnego deklarowania typów zmiennych. Rozróżnia się typ całkowity, rzeczywisty, zespolony, tekstowy, logiczny i inne. Zależnie od języka, poszczególne typy mogą mieć wiele odmian. Oprócz typów prostych, wiele języków umożliwia tworzenie własnych typów lub struktur danych o bardziej złożonej budowie. Odpowiednie dobranie typów zmiennych pozwala zaoszczędzić pamięć operacyjną oraz skrócić czas wykonywania obliczeń. Często istnieje konieczność konwersji typów, czyli zamiany zawartości jednego typu na inny. Należy pamiętać, że nie każdy rodzaj konwersji jest możliwy (przykładowo: nie da się zamienić łańcucha liter na liczbę) i że nie zawsze konwersja jest dokładna (np. podczas konwersji zmiennej rzeczywistej na całkowitą traci się część ułamkową). Konwersję wykorzystuje się między innymi podczas używania kodów ASCII (często stosowane w FORTANIE), wyprowadzania danych na ekran monitora (OBJECT PAASCAL) lub dostosowywania do innych standardów danych (np. konwersja typów STRING i PCHAR w języku OBJECT PASCAL). Nazwa typu Fortran INTEGER REAL DOUBLE PRECISION COMPEX DOUBLE COMPEX LOGICAL CHARACTER Pascal INTEGER SHORTINT LONGINT BYTE REAL SINGLE DOUBLE EXTENDED COMP BOOLEAN STRING Zakres min. - 2.147483648 - 3.4028235.1038 - 1.797693134862316.10308 Zakres max. Bajty Dokładność + 2.147483647 + 3.4028235.1038 + 1.797693134862316.10308 4 4 8 6-7 15-16 Wartość typu COMPEX jest uporządkowaną parą liczb typu REAL. Typ DOUBLE COMPEX jest uporządkowaną parą liczb typu DOUBLE PRECISION. TRUE lub FALSE 0 znaków - 32768 - 128 - 2147483648 0 - 2.9.1039 - 1.5.1045 - 5.0.10324 - 1.9.104951 0 TRUE lub FALSE 0 znaków 256 znaków + 32767 + 128 + 2147483647 255 + 1.7.1038 + 3.4.1038 + 1.7.10308 + 1.1.104932 + 9.2.1018 256 znaków 4 1 na znak 2 1 4 1 6 4 8 10 8 4 1 na znak 11-12 7-8 15-16 19-20 19-20 - Tab. 5. Typy występujących zmiennych oraz ich zakresy w językach Fortran oraz Pascal. • Potrzeba wymiany danych między różnymi modułami (podprogramami, funkcjami i procedurami). Sposób wymiany danych (wartości zmiennych) zależy w dużej mierze od organizacji i struktury konkretnego języka programowania. Podstawowe metody to: 34/64 Materiały uzupełniające do wykładów z Języków Programowania II • • • • • • • deklarowanie wspólnych bloków pamięci, deklarowanie wspólnych adresów pamięci, deklarowanie bloków zawierających zbiory zmiennych (ładowanych następnie do wybranych podprogramów, procedur lub funkcji), przenoszenie wartości zmiennych w nagłówkach nazw procedur i funkcji, podział zmiennych na zmienne lokalne i publiczne, ładowanie pliku wejściowego, wykorzystanie plików (zapis i odczyt). • Potrzeba wykonywania działań na zmiennych. Rozróżnia się trzy podstawowe rodzaje zmiennych: liczbowe, tekstowe i logiczne, przy czym każda grupa wymaga innego podejścia. Zdarza się, że języki programowania (szczególnie starsze) są ukierunkowane na jeden rodzaj danych. Działania na zmiennych wymagają stosowania operatorów, relacji, wyrażeń, instrukcji, funkcji lub procedur. • Potrzeba wykonywania działań na plikach. Bardzo często programy komputerowe odczytują pewne dane z plików, przekształcają je lub na ich podstawie obliczają nowe dane, a następnie zapisują wyniki do pliku. Język programowania powinien nie tylko umożliwiać zapis i odczyt, ale także wykonywanie podstawowych działań na plikach (tworzenie, kasowanie, przenoszenie czy zmiana nazwy). Zależnie od rodzaju języka i jego implementacji możliwości w tym zakresie są bardzo zróżnicowane. • Potrzeba komunikacji z systemem operacyjnym. Przydatnym elementem języka programowania jest możliwość korzystania w funkcji systemu operacyjnego. Jest to zazwyczaj możliwe na dwa sposoby: • • język posiada własne instrukcję odpowiadające poleceniom systemu operacyjnego (ale i tak przeważnie w jakiś sposób z nich korzysta), język posiada mechanizm wywoływania poleceń systemowych i ich parametrów. Cecha ta w znacznym stopniu rozszerza możliwości języka programowania, dając nowe sposoby realizacji zadań. • Potrzeba zarządzania pamięcią operacyjną komputera. Istnieją dwa podstawowe rodzaje zarządzania pamięcią: statyczne i dynamiczne. Zarządzanie statyczne polega na ścisłym przydzielaniu zmiennym określonej ilości pamięci operacyjnej (identyfikowanej tzw. adresami), przy czym ilość ta zależna jest od zadeklarowanego typu zmiennej. Ilość przydzielonej pamięci nie może się już zmienić – wskutek czego nie można np. zadeklarować tablicy o nieznanym z góry rozmiarze. Zarządzanie dynamiczne nie posiada takich ograniczeń, a pamięć operacyjna przydzielana jest automatycznie, w zależności od potrzeb. Zarządzanie dynamiczne umożliwia ponadto swobodne zwalnianie zajmowanej wcześniej pamięci. Zarządzanie pamięcią odnosi się nie tylko do zmiennych, ale i innych obiektów, np. formularzy, list, plików graficznych, wideo, itd. • Potrzeba obsługi błędów (wyjątków). Jest to konieczne ze względu na dwa podstawowe czynniki: niemożność przewidzenia wszystkich działań użytkownika oraz możliwość wystąpienia awaryjnych stanów pracy komputera (np. uszkodzenie pliku, nośnika danych, systemu operacyjnego). 35/64 Materiały uzupełniające do wykładów z Języków Programowania II 3.2 Zmienne i stałe. Zmienna - jest to symboliczna nazwa komórki w pamięci operacyjnej komputera i służy do zapisu wartości liczbowej, tekstowej, logicznej, itd. Zmienne są podstawowym elementem algorytmu obliczeniowego. W czasie działania programu wartości przypisane zmiennym mogą się dowolnie zmieniać, zależnie od wykonywanych operacji. Zmienne są rozróżniane po nazwach, czyli tzw. identyfikatorach. Nadanie wartości zmiennym odbywa się poprzez instrukcję przypisania – bezpośrednio podczas deklaracji typu lub później (zależy to od języka programowania). Zmienna indeksowana – zmienna zawierająca nie jedną wartość lecz cały ich zbiór. W przypadku zmiennych indeksowanych oprócz deklaracji typu należy podać jej wymiar. Służy do zapisywania list, wektorów i tablic. Maksymalna ilość wymiarów zmiennej indeksowanej jest zależna od języka programowania. Stała – jest to symboliczna nazwa komórki w pamięci operacyjnej komputera i również służy do zapisu określonej wartości. Różnica pomiędzy zmienną a stałą jest taka, że wartości stałej nie można zmienić podczas wykonywania obliczeń. Deklaracja stałej i nadanie wartości realizuje się odpowiednią instrukcją. Podstawowy podział zmiennych i stałych: a) ze względu na typ: • • • • • • • zespolone, rzeczywiste, całkowite, logiczne, walutowe, daty lub czasu, tekstowe. b) ze względu na sposób deklaracji: • • deklarowane jawnie, deklarowane niejawnie. c) ze względu na dokładność (dotyczy zmiennych zespolonych i rzeczywistych): • • o pojedynczej precyzji, o podwójnej precyzji. d) ze względu na strukturę: • • prosty, indeksowany (wektory i tablice). e) ze względu na ilość zajmowanej pamięci: • • o określonej ilości bajtów (1, 2, 4, 6, 8 lub 10 bajtów), o dowolnej ilości bajtów. 36/64 Materiały uzupełniające do wykładów z Języków Programowania II f) ze względu na sposób przydziału pamięci: • • statyczne, dynamiczne. 3.3 Wyrażenia. Rozróżnia się następujące rodzaje wyrażeń: a) arytmetyczne – służą do obliczania wartości zmiennych liczbowych na podstawie wzorów matematycznych. W wyrażeniach arytmetycznych mogą wystąpić następujące elementy: • • • • stałe arytmetyczne, odwołania do zmiennych, odwołania do elementów tablic, wywołania funkcji wewnętrznych i zewnętrznych. Wyrażenia realizowane są przy pomocy operatorów (znaków dodawania, odejmowania, mnożenia, dzielenia i potęgowania) oraz funkcji (wewnętrznych i zewnętrznych). Podczas tworzenia wyrażeń arytmetycznych należy zwrócić uwagę na typ wyniku, szczególnie w przypadku, gdy w wyrażeniu biorą udział zmienne różnych typów. Operatory arytmetyczne Fortran Pascal + - * / ** + - * / ** div mod shl shr BASIC + - * / (**) C++ + - / * % ++ -- << >> Tab. 6. Rodzaje operatorów arytmetycznych w językach Fortran G77, Pascal, BASIC i C++. Generalnie panuje zasada, że typ wyniku będzie zgodny z najbardziej dokładnym typem zmiennej, wg kolejności: zmienne zespolone, zmienne rzeczywiste o podwyższonej dokładności, zmienne rzeczywiste o standardowej dokładności, zmienne całkowite. Kolejność wykonywania operacji zależy od priorytetu operatora, wg kolejności: potęgowanie, mnożenie i dzielenie oraz dodawanie i odejmowanie. Kolejność wykonywania działań można dowolnie zmienić stosując nawiasy. b) Tekstowe – służą do wykonywania działań na zmiennych tekstowych. Elementami wyrażeń tekstowych są: • • • stałe i zmienne tekstowe, podłańcuchy, wywołania funkcji tekstowych. Funkcje tekstowe służą do przetwarzania zmiennych tekstowych (np. tworzenie podłańcuchów) oraz do zbierania określonych informacji (np. określanie długości łańcucha, położenia określonego znaku w łańcuchu, itp.) c) relacji – służą do porównania wartości dwóch wyrażeń arytmetycznych lub logicznych. Dostępne operatory relacji to znaki: • • mniejsze niż, mniejsze lub równe, 37/64 Materiały uzupełniające do wykładów z Języków Programowania II • • • • równe, nierówne, większe lub równe, większe niż. Operatory relacji mogą być zapisywane symbolami matematycznymi lub tekstowymi w zależności od języka programowania. Często zdarza się, że operator relacji nie pokrywa się z operatorem przypisania - poniżej przedstawiony jest przykład: F77 = .EQ. operator przypisania operator relacji – równe F90/95 = = PASCAL := = BASIC = = Tab. 7. Operatory przypisania w językach Fortran, Pascal oraz BASIC. d) logiczne – służą do wyznaczania wartości logicznej typu PRAWDA lub FAŁSZ. Elementami wyrażenia logicznego są: • • • • stałe i zmienne logiczne, elementy tablic logicznych, wywołania funkcji logicznych, wyrażenia relacji. Najczęściej stosowane operatory logiczne to: • • • • • negacja, koniunkcja, alternatywa, tożsamość, nie tożsamość. Podane operatory zostały uporządkowane według priorytetów, czyli kolejności w jakiej wykonywane są operacje podczas wyznaczania wartości wyrażenia logicznego. Argumenty operatorów logicznych muszą być typu logicznego. Kiedy dwa następujące po sobie w wyrażeniu operatory mają równe priorytety, to najpierw wykonywana jest operacja stojąca z lewej strony. Operator negacji poprzedza argument, pozostałe operatory wymagają podania dwóch argumentów w porządku (operator w środku). A B 1 1 0 0 1 0 1 0 negacja (zmienna A) 0 0 1 1 koniunkcja alternatywa tożsamość nie tożsamość 1 0 0 0 1 1 1 0 1 0 0 1 0 1 1 0 Tab. 8. Tabela wyrażeń logicznych. Jeżeli w jakimś wyrażeniu występują jednocześnie operatory arytmetyczne, relacji i logiczne, to kolejność wykonywania działań jest następująca: • • • operacje arytmetyczne, operacje relacji, operacje logiczne. 38/64 Materiały uzupełniające do wykładów z Języków Programowania II 3.4 Instrukcje. Instrukcje są jednym z najbardziej podstawowych elementów języka programowania. Podstawowe instrukcje, występujące w wielu językach programowania (np. FORTRAN, PASCAL, BASIC) to: a) instrukcje czynne: • • instrukcja przypisania, instrukcje sterujące: • instrukcja skoku, • instrukcja zatrzymania, • instrukcja wstrzymania, • instrukcja końca, • instrukcja powrotu, • instrukcja warunkowa, • instrukcja wyboru, • instrukcje powtórzeń (pętli), • instrukcje wejścia-wyjścia, b) instrukcje bierne: • • • • • specyfikacje segmentów i ich wejść, specyfikacje cech obiektów, specyfikacje formatu danych, instrukcje funkcji i procedur, instrukcje inicjowania danych. Instrukcje czynne związane są bezpośrednio z tokiem obliczeń i wpływają na wartości poszczególnych zmiennych. Instrukcje bierne są elementami pomocniczymi, służącymi do organizacji kodu źródłowego i określenia ogólnych właściwości poszczególnych obiektów. Instrukcja przypisania – zwana inaczej instrukcją podstawienia, pozwala nadawać zmiennym określoną wartość. Instrukcja przypisania ma postać: zmienna = wyrażenie gdzie zmienna oznacza zmienną prostą lub element tablicy, zaś wyrażenie jest dowolną wartością liczbową, logiczną lub tekstową (w zależności od typu zmiennej) lub odpowiednio wzorem matematycznym, funkcją tekstową lub zwrotem logicznym. Zależnie od języka programowania, jako symbol przypisania stosuje się znak „=” (np. FORTRAN, BASIC), „:=” (np. PASCAL) lub też wyrażenie słowne. W wyniku zastosowania instrukcji przypisania zmienia się bezpowrotnie wartość lewej strony zależności, elementy strony prawej nie ulegają zmianie. Tworząc instrukcję przypisania pamiętać należy o odpowiednim doborze typów i konsekwencjach ich mieszania. Warto podkreślić, że instrukcja przypisania nie jest tożsama ze wzorem matematycznym, stąd możliwe są podstawienia typu i = i+1, fałszywe z punktu widzenia matematyki, ale poprawne i często stosowane w językach programowania. Instrukcja skoku – służy do przeniesienia punktu sterowania w inne, wcześniej zdefiniowane, miejsce programu. Instrukcja skoku nie jest zalecana przez teoretyków programowania, jednak często znacznie ułatwia realizację algorytmu. Instrukcja skoku ma ogólną postać logiczną: 39/64 Materiały uzupełniające do wykładów z Języków Programowania II IDŹ DO nazwa miejsca gdzie nazwa miejsca musi być już jednoznacznie zdeklarowana: może to być etykieta (FORTRAN) lub nazwa (PASCAL). Instrukcja zatrzymania – służy do bezwarunkowego zakończenia wykonywanego programu. Instrukcja często spotykana w blokach podejmowania decyzji, uruchamiana gdy nie są spełnione warunki do wykonywania dalszych działań. Instrukcja wstrzymania – służy do chwilowego zatrzymania wykonywania programu. Kontynuacja może być podjęta wskutek działania użytkownika bądź też po upływie określonego czasu. Instrukcja powrotu – służy do wyjścia z podprogramu, procedury, funkcji lub też do wskazania ponownego wykonania pętli. Instrukcja końca – służy do określenia końca programu, procedury, funkcji, bloku deklaracji, bloku instrukcji bądź bloku inicjacji danych. Instrukcje warunkowe – służą do określania dalszego toku postępowania (podejmowania decyzji) w zależności od postawionych warunków. Typową instrukcją warunkową jest instrukcja JEŻELI (IF) o następującej budowie logicznej: JEŻELI warunek TO instrukcja lub JEŻELI warunek1 TO instrukcja1 W INNYCH PRZYPADKACH instrukcja2 gdzie warunek jest dowolnym wyrażeniem arytmetycznym, relacją lub wyrażeniem logicznym, a instrukcja dowolnym blokiem poleceń, wykonywanym gdy warunek jest prawdziwy. Często zachodzi konieczność rozważenia większej liczby możliwości, wówczas stosuje się inną konstrukcję logiczną: JEŻELI warunek1 TO instrukcja1 JEŻELI ZAŚ warunek2 TO instrukcja2 JEŻELI ZAŚ warunek3 TO instrukcja3 …… W INNYCH PRZYPADKACH instrukcjaN Zależnie od języka programowania budowa instrukcji warunkowych może być nieco inna, mogą też występować odmiany instrukcji. Tworząc instrukcję warunkową należy uwzględnić wszystkie możliwe przypadki – zaniedbanie może spowodować błędne działanie programu lub też jego zawieszenie. Inną typową instrukcją warunkową, występującą w wielu językach programowania, jest instrukcja wyboru (CASE) o ogólnej postaci logicznej: WYBIERZ ZALEŻNIE OD WARTOŚCI zmienna JEŻELI (lista przypadków 1) TO instrukcja1 JEŻELI (lista przypadków 2) TO instrukcja2 JEŻELI (lista przypadków 3) TO instrukcja3 ... DOMYŚLNIE instrukcjaN 40/64 Materiały uzupełniające do wykładów z Języków Programowania II gdzie zmienna jest identyfikatorem zmiennej, zaś lista przypadków zawiera oczekiwane wartości, dla których mają być wykonane odpowiednie instrukcje. W instrukcji wyboru występuje często możliwość określenia wartości domyślnej instrukcjaN, dla przypadku, gdy wartość zmiennej nie należy do żadnej wymienionej wyżej listy przypadków. Konkretna realizacja instrukcji wyboru zależy od składni użytego języka programowania. Instrukcje powtórzeń (pętle) – służą do wielokrotnego wykonania tego samego bloku instrukcji. Rozróżnia się dwa podstawowe typy instrukcji powtórzeń: a) o znanej z góry liczbie powtórzeń: • • realizowane „od dołu”, realizowane „od góry”, b) o nieznanej z góry liczbie powtórzeń: • • z warunkiem „na początku”, z warunkiem „na końcu”. Ogólna postać logiczna pętli o znanej liczbie powtórzeń wygląda następująco: POWTARZAJ OD wartość1 DO wartość2 instrukcje gdzie wartość1 i wartość2 są liczbami typu całkowitego, a instrukcje dowolnym zestawem poleceń. Zestaw poleceń musi posiadać wskazanie początku i końca bloku. Czasami możliwe jest również określenie kroku przyrostu – licznik pętli nie musi bowiem wzrastać lub maleć zawsze o 1. Ogólna postać logiczna pętli o nieznanej liczbie powtórzeń z warunkiem na początku wygląda następująco (tzw. warunek WHILE w PASCALU): JEŻELI warunek = prawda WYKONAJ instrukcje I POWRÓĆ = fałsz WYJDŹ Z PĘTLI Należy podkreślić, że w przypadku, gdy warunek jest od razu fałszywy blok instrukcje nie zostanie wykonany ani razu. Ogólna postać logiczna pętli o nieznanej liczbie powtórzeń z warunkiem na końcu wygląda następująco (tzw. warunek REPEAT-UNTIL w PASCALU): WYKONAJ instrukcje I JEŻELI warunek = prawda WYJDŹ Z PĘTLI = fałsz POWRÓĆ W tym przypadku blok instrukcje wykonany zostanie przynajmniej raz. Konkretna struktura i budowa pętli zależy od użytego języka programowania. Instrukcje wejścia-wyjścia – służą do przesyłania danych pomiędzy różnymi elementami komputera, takimi jak monitor, klawiatura, drukarka czy plik. Dla informacji wysyłanych domyślnym urządzeniem jest monitor, zaś dla informacji wczytywanych: klawiatura. Przesyłane 41/64 Materiały uzupełniające do wykładów z Języków Programowania II informacje składają się z rekordów. Rekord jest to elementarna porcja informacji, jaka może być przesyłana pomiędzy urządzeniami zewnętrznymi a pamięcią operacyjną. W przypadku monitora i klawiatury pojedynczy rekord odpowiada wierszowi znaków na ekranie monitora, w przypadku drukarki wierszowi poleceń. Proces wprowadzania i wyprowadzania danych może być ograniczony do jednej tylko zmiennej, lub może być bardziej rozbudowany – służą do tego celu tzw. listy wejścia i wyjścia. Lista zawiera spis zmiennych, którym mają być przypisywane wprowadzane wartości według ich kolejności. Ważne jest, aby wartości wprowadzane odpowiadały zadeklarowanym typom zmiennych i aby liczba wprowadzonych wartości była zgodna z liczbą elementów listy. Składnikami listy mogą być zmienne proste, elementy tablic, łańcuchy znakowe oraz nazwy tablic (oznacza to przesłanie wszystkich elementów tej tablicy). W przypadku korzystania z plików należy określić rodzaj pliku oraz wskazać, że to on będzie „odbiorcą” lub „dawcą” informacji. Rozróżnia się dwa podstawowe rodzaje plików: o dostępie sekwencyjnym. Pliki o dostępie sekwencyjnym oferują odczyt elementów pliku „od początku”. W takim przypadku, aby odczytać n-ty element pliku, należy najpierw odczytać wszystkie elementy go poprzedzające. Pliki o dostępie sekwencyjnym są wygodne w przypadku zapisu i odczytu zmiennych indeksowanych (wektorów lub tablic), w których i tak trzeba przejść przez wszystkie indeksy. Pliki takie nie nadają się natomiast do zapisu i odczytu informacji przetwarzanych „na wyrywki” – jest to co prawda możliwe, ale dużo wolniejsze niż w przypadku korzystania z plików o dostępie swobodnym. o dostępie swobodnym. Pliki o dostępie swobodnym składają się z ponumerowanych rekordów, umożliwiających bezpośredni zapis i odczyt w dowolnym rekordzie (bez konieczności odczytu rekordów poprzedzających). Są bardzo przydatne do przetwarzania danych o strukturze baz danych. Oba typy plików umożliwiają zapis od początku (jeżeli w pliku były jakieś dane, to zostaną one skasowane) lub też kontynuację zapisu w miejscu końca pliku. Specyfikacje segmentów i ich wejść – służą do wyodrębniania określonych bloków instrukcji i poleceń stanowiących pewną logiczną całość. Segmentem może być podprogram, procedura lub funkcja. Segmenty mogą być wywoływane w głównym bloku programu lub też w innych segmentach (co zależy często od odpowiedniej deklaracji). Podprogram (moduł) – samodzielny fragment programu, posiadający zazwyczaj budowę podobną do segmentu głównego: zawiera oznaczenie początku i końca, obszar deklaracji typów, bloki instrukcji, itd. Podprogram może być wywoływany w segmencie głównym lub w innych podprogramach. W całym programie może być zazwyczaj tylko jeden podprogram o określonej nazwie, zaś ilość podprogramów jest nieograniczona. Ogólna budowa logiczna podprogramu jest następująca: POCZĄTEK BLOKU segment … instrukcje instrukcje WYWOŁAJ PODPROGRAM nazwa instrukcje instrukcje 42/64 Materiały uzupełniające do wykładów z Języków Programowania II … KONIEC BLOKU segment PODPROGRAM nazwa … instrukcje … KONIEC PORPROGRAMU nazwa gdzie segment oznacza główny segment programu lub inny podprogram, instrukcje – dowolny zestaw poleceń i instrukcji, nazwa – identyfikator podprogramu. Procedura – element podobny do podprogramu, stanowiący jego rozszerzenie dla języków sterowanych zdarzeniami w systemie. Ogólna postać logiczna procedury sterowanej zdarzeniem jest następująca: PROCEDURA nazwa JEŻELI zdarzenie … instrukcje … KONIEC PROCEDURY nazwa gdzie nazwa jest identyfikatorem procedury, instrukcje - dowolnym zestawem poleceń i instrukcji, zaś zdarzenie – dowolnym, ale konkretnie określonym zdarzeniem w systemie. Procedury nie muszą być sterowane zdarzeniami - spełniają wówczas rolę podprogramów i mogą być wywoływane z dowolnego miejsca programu (jeżeli mają status „publiczny”), lub też w obrębie bieżącego modułu (jeżeli mają status „prywatny”). W nagłówku procedury może być zawarta lista przekazywanych zmiennych. Nie jest to zazwyczaj konieczne i zależy od woli programisty. Zdarzenie – dowolne działanie wykonane przez program lub użytkownika (zdarzeniem może być np. kliknięcie myszką, naciśnięcie klawisza, wybór elementu menu, najechanie kursorem na element formularza, aktywacja lub zamknięcie formularza, itd.). Funkcja – jest to również samodzielny segment programu. W odróżnieniu od podprogramu lub procedury, funkcja wykonuje konkretne działania na zdefiniowanych wcześniej zmiennych i zwraca wynik. Funkcja wymaga zazwyczaj przekazania listy zmiennych o określonych typach. Ogólna postać logiczna funkcji jest następująca: FUNKCJA nazwa (lista zmiennych) … instrukcje … KONIEC FUNKCJI nazwa gdzie nazwa jest identyfikatorem funkcji, instrukcje - dowolnym zestawem poleceń i instrukcji, zaś lista zmiennych – uporządkowanym zbiorem nazw zmiennych, niezbędnych do obliczenia funkcji. W funkcjach mogą być wykorzystane zmienne liczbowe, tekstowe, walutowe lub typu data i czas. Specyfikacje cech obiektów – służą do określenia pewnych właściwości zmiennych, procedur lub funkcji. Zazwyczaj jest to rodzaj definiowanego obiektu (zmienna czy stała), rozmiar zmiennej indeksowanej, obszar obowiązywania (obiekt „publiczny” czy „lokalny”), zasady organizacji 43/64 Materiały uzupełniające do wykładów z Języków Programowania II pamięci, itd. Zależnie od języka programowania, jego możliwości w zakresie definicji cech obiektów mogą być bardzo zróżnicowane. Specyfikacje formatu danych – służą do określania wyglądu zmiennych podczas wyprowadzania lub wprowadzania danych. Procesowi formatowania podlegają najczęściej następujące elementy: całkowita liczba zajmowanych znaków. Określa liczbę możliwych do wykorzystania przez konkretną zmienną znaków (na ekranie monitora lub w pliku). W przypadku gdy liczba znaków jest krótsza od zadeklarowanej, pozostałe znaki uzupełniane są spacjami (z przodu lub na końcu). W przypadku zaś, gdy liczba znaków jest dłuższa, znaki ostatnie są obcinane lub też zgłaszany jest błąd wejścia-wyjścia. Symbole takie jak spacja, znak wartości liczby (plus-minus) czy separator dziesiętny zajmują jeden znak. - 1 2 6 8 8 . 7 7 1 2 5 2 2 P O N I E D Z I A Ł E K 1 2 0 0 0 4 7 6 . 1 6 7 7 7 7 7 liczba cyfr po przecinku (dla liczb rzeczywistych). Należy pamiętać, że zmiana formatu nie wpływa na zapisaną w pamięci komputera, bieżącą wartość danej ani też na jej dokładność. Przykład formatu zmiennej o wartości 1234,56789: 1 2 3 4 . 5 6 7 8 1 2 3 4 . 5 6 7 8 9 0 0 1 2 3 4 . 5 6 1 2 3 9 0 8 4 • znak separatora dziesiętnego (dla liczb rzeczywistych) – przecinek lub kropka. Znak separatora może być definiowany w języku programowania lub też może być zmieniany poprzez zastosowanie własnoręcznie napisanej funkcji. • postać danej (dla liczb rzeczywistych). Dostępne możliwości to postać prosta lub wykładnicza. W postaci wykładniczej można zazwyczaj określić całkowitą liczbę znaków oraz ilość cyfr wykładnika. Przykład formatu zmiennej o wartości 1234,56789 w postaci wykładniczej: . 1 2 3 4 . • 1 2 3 4 5 7 E + 0 0 4 5 6 7 8 9 0 0 E + 0 4 sposób interpretacji znaku wartości liczby. Domyślnie liczby dodatnie nie posiadają podczas wyświetlania na monitor (lub zapisu do pliku) znaku „+”, można to jednak zmienić w większości języków programowania. • • sposób interpretacji spacji (dotyczy wprowadzania danych). Określa, czy podczas wprowadzania wartości liczbowych, znak spacji ma być ignorowany czy też nie. • • sposób zapisu czasu i daty. W przypadku czasu określa dokładność wyświetlania, (godzina, minuta, sekunda), zaś w przypadku daty określa kolejność składników oraz sposób wyświetlania roku (dwie lub cztery cyfry). 44/64 Materiały uzupełniające do wykładów z Języków Programowania II Instrukcje funkcji i procedur – są tworzone przez programistę i służą do realizacji jednostkowych zadań algorytmu programu. Instrukcje inicjowania danych – służą do nadawania początkowych wartości zmiennych. Nadają się szczególnie do określania wartości wektorów i tablic - jest to zazwyczaj znacznie wygodniejsze i szybsze niż indywidualne przypisywanie wartości każdemu elementowi zmiennej indeksowanej. 3.5 Wyjątki. Wyjątki są to różne błędy, mogące pojawić się podczas działania programu. Przykładem może być dzielenie przez zero lub wprowadzenie nieodpowiedniego typu danej. Program zgłosi wówczas błąd i przestanie działać (czasem nawet zawiesi komputer). Aby tego uniknąć konieczne jest zastosowanie odpowiednich środków zaradczych. Można to uzyskać na kilka sposobów: poprzez stosowanie obsługi wyjątków. Niektóre języki posiadają specjalne instrukcje pozwalające na kontrolę i eliminację błędów. Ogólna struktura logiczna obsługi błędów jest następująca: WYKONAJ instrukcje A JEŚLI SIĘ COŚ NIE UDA instrukcje KONIEC lub WYKONAJ instrukcje A JEŚLI SIĘ COŚ NIE UDA GDY błąd1 TO instrukcja1 GDY błąd2 TO instrukcja2 GDY błąd3 TO instrukcja3 ... KONIEC Zależnie od języka programowania i jego implementacji obsługa błędów może dotyczyć dowolnej instrukcji w programie lub też wybranego zbioru instrukcji (np. tylko instrukcje wejścia-wyjścia). Pozostałe fragmenty programu muszą być wówczas zabezpieczane inaczej. poprzez tworzenie własnych procedur wprowadzania danych. Proces wprowadzania danych można tak zorganizować, że program nie przyjmie żadnej innej wartości niż prawidłowa. Poprzez odpowiednie stosowanie instrukcji warunkowych można określić dopuszczalny typ danej oraz zakres jej wartości. W każdym innym przypadku program wyświetli komunikat o błędzie i poprosi o ponowne wprowadzenie danej. Taki system nie spowoduje przerwania pracy programu. poprzez stosowanie tzw. masek wprowadzania. Maska wprowadzania jest to pewien wzór, według którego mają być wprowadzane dane. W takim przypadku nie da się wprowadzić danych o innym wzorze niż zadeklarowany. Maski wprowadzania występują jedynie w aplikacjach posiadających formularze. 45/64 Materiały uzupełniające do wykładów z Języków Programowania II 4 Styl programowania. Jedną z podstawowych zasad obowiązujących podczas pisania programów jest czytelność i przejrzystość kodów źródłowych. Dobrze napisany kod umożliwi innym programistom (a często i autorowi) późniejsze ich zrozumienie i usprawnienie. Jest to bardzo ważne gdyż raczej rzadko zdarza się napisać od razu program w wersji ostatecznej, nie wymagającej poprawek i usprawnień. Najczęściej dzieje się wręcz odwrotnie – tworzy się mały program a następnie nieustannie go ulepsza. Istnieje pewna ilość zaleceń i schematów, których przestrzeganie wpłynie na poprawność stylu pisanego kodu źródłowego. Należy jednak pamiętać, że najważniejszy jest efekt działania programu (a nie sam program) i w uzasadnionych przypadkach możne dojść do pewnych odstępstw od przyjętych reguł. Oto kilka cech uważanych za takie, które charakteryzują dobry program: • • • • • • poprawność (zgodność z wymogami użytkownika), niezawodność (dobre dane wejściowe -> dobre wyniki), przenośność (łatwość instalacji na różnych komputerach), łatwość konserwacji (Prosto napisany program łatwo przystosować do różnych warunków pracy), czytelność (Prostota jest jedną z najważniejszych cech dobrych programów), prawidłowe wykorzystanie zasobów (pamięci, dyski, itp.), szybkość. 4.1 Elementy stylu programowania Styl programowania jest często indywidualną sprawą programisty, ale powinien też spełniać pewne reguły ogóle. Dotyczą one następujących spraw7: • • • • • • • • • • • nazwy zmiennych w programie, wielkości stałe, liczba zmiennych globalnych, dostępnych wszędzie w programie, deklaracje typów zmiennych, komentarze, puste linie, odstępy poziome, akapity, wcięcia, itd. podział na sekcje, podprogramy, uniwersalność i standaryzacja modułów, funkcjonalność i wygoda użytkowników, formułowanie celów, złożoność systemu. Nazwy zmiennych. Wybór nazw zmiennych ma pomóc w zrozumieniu ich znaczenia i zastosowania. Najlepiej jest używać nazw, które coś oznaczają, powiadamiając tym samym użytkownika (intencjonalnie) o możliwościach funkcji czy procedury, czy też wskazując sens zmiennych, itd. Z reguły języki programowania nie narzucają nazewnictwa zmiennych. Nazwy można tworzyć opierając się na typach zmiennych (np. wszystkie zmienne liczb zespolonych mogą mieć nazwę zaczynającą się od „ZESP_”), obszarach obowiązywania (np. zmienne obowiązujące w całym programie zaczynają się od „GLOBAL_”, a obowiązujące w podprogramie, procedurze lub 7 http://tytan.umcs.lublin.pl/~baran/tut/99/ww1.htm 46/64 Materiały uzupełniające do wykładów z Języków Programowania II funkcji od „LOCAL_”) lub ich funkcjach (np. zmienne sterujące są inaczej nazywane niż zmienne obliczeniowe, itd.). Dobrze jest stosować rzeczowniki dla oznaczania nazw wszelkich danych, czasowniki dla funkcji i procedur (rozkazy, np. dziel, dodaj itp), przymiotniki dla zmiennych logicznych (w Pascalu boolean). Generalnie można tworzyć dowolne, byle przejrzyste, zasady nazywania zmiennych – ważne jest jedynie aby te zasady przestrzegać. Zbyt długie nazwy można zastąpić ich skrótami (np. zamiast temperaturamaksymalna – tempmax lub temp_max, itp.). Jeżeli translator nie rozróżnia małych i dużych liter, powinno się pisać duże litery na początku każdego słowa (np. nazwa maksymalnatemperaturaroczna jest mniej przejrzysta niż MaksymalnaTemperaturaRoczna). Tworzone skróty powinny być standardowe dla danej instytucji lub dziedziny. Do skracania dobrze nadają się poniższe reguły: • • • • • skraca się każde znaczące słowo w nazwie, pierwsza litera musi wystąpić, spółgłoski są ważniejsze od samogłosek, początek słowa jest ważniejszy niż koniec, tworzy się skróty na 6 do 15 liter. Z reguł tych wynika następujący algorytm: usuwa się od końca najpierw samogłoski potem spółgłoski, oprócz pierwszej litery, aż do osiągnięci pożądanej długości. Porządkowanie list zmiennych wg alfabetu znacznie ułatwia ich odszukiwanie i określenie typu. Wielkości stałe. Z wyjątkiem zera, jedynki i może jeszcze kilku innych stałych, nie należy wprost używać stałych w całej treści programu, w jego wnętrzu. Najlepiej zadeklarować (zgłosić) je w części opisowej, specjalnie do tego przeznaczonej, np. za pomocą słowa Pascala const. Zmiana sprzętu często powoduje idące za nią zmiany przybliżonych wartości różnych stałych. Ile czasu zmarnujemy wyszukując w programie miejsca, w których występuje stała zapisana jako liczba zmiennoprzecinkowa z dokładnością do 9 miejsc znaczących by zamienić ją na liczbę o 12 miejscach znaczących. Nie używajmy gołych stałych! Powiedzmy, że w programie używamy tablicy, której rozmiar 100 zgłosiliśmy kilkakrotnie pisząc między innymi ciąg znaków [1..100]. Załóżmy, że zmienimy wymiar 100 wszędzie, automatycznie, za pomocą edytora tekstu, na 200, a przy okazji, całkiem nieświadomie, zamienimy temperaturę jakiegoś procesu też na 200, ale stopni. Co się wtedy stanie? Zmienne globalne. Należy minimalizować liczbę zmiennych globalnych, dostępnych z całego programu. Zmiany w procedurach czy funkcjach, których jest wiele w programach, są zmianami lokalnymi. Często zapominamy przy nich o zmiennych globalnych. W ten sposób łatwo o błędy. Deklaracje typów zmiennych. Wszystko, co tylko się da, należy umieszczać w deklaracjach typu, włączając w to podzakresy, definicje tablic oraz rekordów. Komentarze. Są to teksty nie podlegające translacji, służące do opisu kodu źródłowego. Mają one mówić jak rozumieć program, ale nie opisywać drugi raz tego co wynika z kodu (np. komentarz „tutaj pod zmienną x podstawiamy 7”, uczyniony w miejscu x: = 7 jest niepoprawny). Powinny zawierać logiczny sens zastosowania danej sekwencji instrukcji, o ile nie jest on oczywisty podczas lektury samego kodu (nadmiar komentarzy może też zatracić przejrzystość samego kodu!). Najczęściej objaśnia się ważniejsze pętle, skoki, sprawdzanie warunków, itp. Komentarze muszą być przynajmniej równie czytelne jak kod, powinny poprawiać czytelność kodu, dlatego powinny mieć tę samą szerokość wcięcia co kod, a mogą też być wyróżnione znakami specjalnymi, ramkami, itp. 47/64 Materiały uzupełniające do wykładów z Języków Programowania II Na początku programu powinien znaleźć się komentarz wstępny, zawierający: • • • • • • • • • • • opis działania programu, sposób użycia - jak wywołać program, listę i opis ważniejszych zmiennych, opis plików WE/WY, nazwy używanych podprogramów, nazwy wszelkich specjalnych metod, które zostały użyte, wraz ze wskazaniem, gdzie można znaleźć dalsze informacje, informacje o czasie działania (jeśli ma to znaczenie), wymagania sprzętowe i systemowe, opis specjalnych poleceń dla operatora / użytkownika, informacje o autorach i kontaktach, datę napisania (ew. datę ostatniej modyfikacji lub numer wersji). W długich programach warto stosować przewodniki, czyli rodzaj spisu treści podającego nazwę, miejsce i funkcje każdego modułu. Puste linie. Oddzielają poszczególne fragmenty programu ułatwiając późniejsze ich poszukiwanie. Puste linie (jedna, dwie) POWINNY! oddzielać różne fragmenty programu i podprogramy. Odstępy poziome (spacje). Zwiększają czytelność kodu, w szczególności zaś wyrażeń arytmetycznych, list parametrów i in. Wcięcia. Odzwierciedlają wzajemne powiązania instrukcji i grup instrukcji, uzewnętrzniają logiczną strukturę programu (lub danych). Akapity. Akapitów używamy w instrukcjach złożonych. Należy do dobrego tonu podpatrzenie jak radzą sobie z tym inni. Decydując się na jakiś styl trzymajmy się go zawsze. Nie mieszajmy różnych stylów. Programy tracą wtedy na czytelności. Z czasem praktyka pokaże, że trzymanie się jednego stylu opłaca się. Tymczasem należy się do tego przyzwyczajać. Numeracja linii (w językach których to dotyczy). Numeracja powinna być prowadzona co 10, aby można było zawsze coś wstawić w środek. Przenoszenie słów. Nie jest zalecane. Jeżeli już jest to konieczne, to linia powinna się kończyć tak, by było widać, że logicznie nie jest zakończona i że jej kontynuacja musi następować dalej (np. w wyrażeniach arytmetycznych ostatni w linii powinien być operator, a nie operand). Rozmieszczenie instrukcji. Jest jednym z najważniejszych elementów stylu. Powinny one być od siebie odseparowane (ale nie za bardzo), najlepiej gdy będzie jedna instrukcja w linii. Nawiasy. Używanie nawiasów jest bardzo zalecane, szczególnie przy długich wyrażeniach arytmetycznych. W takim przypadku błędna formuła obliczeniowa (brak lub złe miejsce wstawienia nawiasu) może być przyczyną trudnych do wykrycia błędów. Sekcje. W przypadku dużych programów należy je dzielić na elementy według następujących zasad: • algorytm programu należy dzielić na pojedyncze zadania o ściśle określonym celu. Uwaga programisty skupia się wówczas na konkretnym problemie, nie związanym bezpośrednio z 48/64 Materiały uzupełniające do wykładów z Języków Programowania II resztą programu, zmniejsza to znacznie prawdopodobieństwo popełnienia błędu. Poszczególne segmenty mogą być oddzielnie testowane, co ułatwia wyszukiwanie i usuwanie błędów w całym programie. W przypadku dużych programów, poszczególne moduły mogą być ponadto pisane przez różnych programistów. • segmenty powinny być uniwersalne. Oznacza to, że należy je tak budować, aby dało się je wykorzystać w innych programach. Jest to szczególnie przydatne, gdy programista tworzy aplikacje z określonej dziedziny i często musi rozwiązywać podobne problemy. Korzystanie z gotowych i przetestowanych segmentów może znacznie przyspieszyć i ułatwić pracę. • każdy segment powinien realizować swoje zadania niezależnie od innych segmentów. • konkretne zadanie powinno być w programie rozwiązane tylko raz. Jeżeli to tylko możliwe nie należy mieszać i powielać zadań z różnych segmentów – może to znacznie utrudnić znajdowanie błędów: nie wiadomo bowiem który segment jest odpowiedzialny za powstanie błędu. • należy dążyć do tego, aby jak najwięcej użytych w programie zmiennych miało zasięg lokalny (czyli obowiązywały w obrębie podprogramów, procedur i funkcji). Znacznie łatwiej jest wówczas kontrolować zawartość zmiennych, a przypadkowa i nieprzewidziana zmiana ich wartości jest mniej prawdopodobna. Uniwersalność. Można ją osiągnąć przez stosowanie: • • • • parametryzacji, używanie standardowych bibliotek, standaryzację postaci wejścia-wyjścia, stosowanie standardów stylu. Parametryzacja. Oznacza niezależność od konkretnego zestawu danych, może być osiągnięta przez parametryzację. Pozwala to na łatwe i szybkie zmiany w programie, dlatego najczęściej używane parametry to: • • • wymiary tablic i list; dane specjalne, np. stopa procentowa, podatkowa; desygnatory urządzeń WE/WY (też ścieżki dostępu i nazwy plików). By zmienić program bez parametryzacji trzeba ręcznie pozmieniać wszystkie wystąpienia danej wartości, ale można łatwo coś przeoczyć lub zmienić coś, co ma taką samą wartość, ale odnosi się do innej zmiennej. Używanie standardowych bibliotek, funkcji i procedur. Są to elementy już zoptymalizowane i przetestowane, przez co zapewniają lepszą efektywność i mniejsze prawdopodobieństwo wystąpienia błędu. Oszczędność na czasie kodowania też jest olbrzymia. Standaryzacja postaci WE/WY – musi być szczegółowo zaprojektowana przed kodowaniem. Najlepszy jest naturalny i jednorodny układ zmiennych i formatów. Standardy stylu. Standard stylu jest to zbiór określonych zasad pisania programów. Standardy mogą być narzucone z góry lub mogą być tworzone indywidualnie. Mają tę zaletę, że zmniejsza się możliwość nieporozumienia, jeżeli robi się tę samą rzecz za każdym razem tak samo. Potrzebny jest 49/64 Materiały uzupełniające do wykładów z Języków Programowania II tylko niewielki wysiłek, by przestrzegać standardów stylu. Standardy mogą ograniczać przyszły rozwój i postęp, być zbyt krępujące lub nieporęczne. Dobre standardy nie posiadają tych cech (lecz i tak istnieją rzadkie przypadki, w których można nie zastosować się do standardu). Instytucja narzucając standardy stylu sprawia, że powstające tam programy będą jej własnością, a nie poszczególnych programistów. Funkcjonalność i wygowa użytkowników. Jest obecnie popularnym hasłem zawartym w pojęciu "User friendly program". Oznacza to, że użytkownik programu (operator) powinien mieć możliwość korzystania z programu w sposób naturalny, bez specjalnego przygotowania. Program powinien przewidywać zadania użytkownika i służyć mu podpowiedziami i pomocą, nie dopuszczając jednocześnie do wywołania błędu użytkownika. Formułowanie celów. Musi się dokonać na początku projektowania (różne cele mogą być konfliktowe, np.: duża niezawodność, dotrzymanie terminów, minimalny koszt lub czas produkcji, efektywność w użyciu pamięci / szybkości, możliwość późniejszej modyfikacji, uniwersalność, prostota / łatwość obsługi i konserwacji. Podstawową zasadą obowiązującą podczas formułowania celów jest zasada „skromności”: "Skromny, działający program jest bardziej użyteczny niż program imponujący, ale niedokończony." Złożoność. Złożoność wpływa na trudności w testowaniu, uruchamianiu i konserwacji. Mniej złożony produkt znacznie łatwiej opanować. Ograniczenie złożoności osiąga się dzięki dzieleniu programu na moduły i projektowaniu zstępującemu, co zmniejsza liczbę poziomów rozumienia. Moduły zmniejszają liczbę możliwych dróg w programie (więc łatwiej dokonywać zmian nie wpływających na inne elementy programu) oraz izolują błędy wewnątrz modułu. 4.2 Metody testowania programów. Stosowanie „testu kolegi” - nieczytelnych programów można uniknąć przez wprowadzenie wymogu złożenia pod dokumentacją podpisu programisty i jakiejś drugiej osoby, która przeczytała program i zrozumiała go. 50/64 Materiały uzupełniające do wykładów z Języków Programowania II 5 Algorytmy. Algorytm - dokładny przepis podający sposób rozwiązania określonego zadania w skończonej liczbie kroków; zbiór poleceń odnoszących się do pewnych obiektów, ze wskazaniem porządku, w jakim mają być realizowane. Nabrał znaczenia z rozwojem informatyki, gdzie opisuje logiczny ciąg operacji, które ma wykonać program. Algorytmy charakteryzują się możliwością wyrażania ich w różnych językach i przez skończoną liczbę symboli, bez odwoływania się do analogii, a także faktyczną wykonalnością i możliwością wielokrotnej realizacji. Termin algorytm wywodzi się od zlatynizowanej formy (Algorismus, Algorithmus) nazwiska matematyka arabskiego z IX w: AlChuwarizmiego8. Algorytm zapisany przy pomocy języka programowania jest programem. 5.1 Rodzaje algorytmów. Według typu przetwarzanych danych: • • algorytmy numeryczne, operujące na liczbach (np. algorytm Euklidesa); nienumeryczne, operujące na obiektach innych niż liczby (np. sortowanie dokumentów). Według sposobu wykonywania9: • • • • iteracyjne – rodzaj algorytmu i programu, w których wielokrotnie wykonuje się pewne instrukcje, dopóki nie zostanie spełniony określony warunek; rekurencyjne – takie procedury, które w swojej definicji posiadają wywołanie samej siebie; sekwencyjne – algorytmy, w których instrukcje wykonywane są w porządku, w jakim zostały wprowadzone; niesekwencyjne (równoległe, współbieżne) – algorytmy, w których następstwo między pewnymi operacjami nie jest określone. 5.2 Rodzaje zapisu algorytmów. Istnieje kilka różnych sposobów zapisu algorytmów, zależnie od ich charakteru i przeznaczenia10: 8 9 10 • Algorytm opisany obrazkami - występuje szeroko w instrukcjach opisujących sposób montażu zabawek dla dzieci (np. klocki LEGO), modeli do sklejania, instrukcjach obsługi (np. telewizora, magnetowidu, lodówki). • Algorytm opisany słownie - występuje we wszystkich instrukcjach obsługi, sprzętu domowego, aparatury naukowej, na lekcjach wielu przedmiotów w postaci opisu doświadczenia i w informatyce jako element poprzedzający właściwe programowanie. • Algorytm opisany schematem blokowym - występuje głównie w nauczaniu elementów informatyki i służy do graficznego prezentowania i rozwiązywania problemu, powinien być poprzedzony opisem słownym. Schemat blokowy stanowi doskonałą bazę do stworzenie programu, w łatwy do zrozumienia sposób może powstać taki schemat. Graficznie ukazuje to co w programie jest najważniejsze, pokazuje zależności między kolejnymi poleceniami. http://wiem.onet.pl/wiem/00f18c.html http://eduseek.ids.pl/artykuly/artykul/ida/1833/idc/1/ilk/8/idk/2279 http://www.ids.poznan.pl/lo17/strony/informatyka/algorytmy/blokowe.htm 51/64 Materiały uzupełniające do wykładów z Języków Programowania II • Algorytm opisany językiem programowania - (program) stanowi realizację projektu w konkretnym języku programowana, powinien być poprzedzony opisem słownym i schematem blokowym 5.3 Schematy blokowe. Jednym ze sposobów przedstawienia algorytmu jest schemat blokowy, tzn. rysunek składający się z szeregu figur geometrycznych o określonych kształtach (skrzynki lub bloki) połączonych ze sobą liniami (ścieżki sterujące). Figury służą do przedstawienia rodzaju działań zaprojektowanych w algorytmie, zaś linie wskazują kolejność wykonywania tych działań. Każda figura w schemacie blokowym prezentuje określony rodzaj operacji. Zasadniczą zaletą schematów blokowych jest to, że graficznie prezentują one działanie programu, zarówno od strony występujących w nim działań, jak i ich kolejności. operacja lub grupa operacji, w wyniku których ulega zmianie wartość, postać lub miejsce zapisu danych w pamięci operacyjnej komputera operacje wprowadzania operacyjnej komputera i wyprowadzania danych do/z pamięci operacja warunkowa (IF), określająca wybór jednej z dwóch możliwych dróg działań proces określony poza programem i z tego powodu nie wymagający zdefiniowania w rozpatrywanym programie (podprogram), przy definiowaniu tych elementów należy pamiętać, że ich wykonanie nie rozpoczyna się od START i nie kończy na STOP (najczęściej podprogram kończy się wykonaniem instrukcji powrotu (RETURN) do głównego programu) określa kierunek przepływu danych lub kolejność wykonywania działań łącznik stronicowy, wskazujący wejście lub wyjście z wyodrębnionych fragmentów schematu rozmieszczonych na tych samych stronach (arkuszach papieru) łącznik międzystronicowy, wskazujący wejście lub wyjście z wyodrębnionych fragmentów schematu rozmieszczonych na różnych stronach (arkuszach papieru) oznaczenie miejsca rozpoczęcia, zakończenie lub przerwania działania programu. komentarz 52/64 Materiały uzupełniające do wykładów z Języków Programowania II Operacje arytmetyczne oraz aplikacje typu WSTAW oznaczone są za pomocą prostokąta, w którym wpisuje się komentarz uściślający daną operację. Przy tym, jeśli kilka operacji tworzy logiczną całość, to wszystkie one mogą być umieszczone w jednej skrzynce. Nie zaleca się jednak umieszczania zbyt dużej ilości operacji nawet wtedy, kiedy są one powiązane ze sobą bezpośrednio – może to zmniejszyć czytelność schematu. Operacje odczytywania danych oraz wprowadzania wyników oznaczone są za pomocą równoległoboków, w środku których powinien znajdować się odpowiedni komentarz. Operacja warunkowa JEŻELI jest oznaczona za pomocą rombu, w którym wpisuje się odpowiedni warunek. Operacje warunkowe prowadzą zawsze do konieczności rozważenie dwóch dróg: jednej (TAK) kiedy rozpatrywany warunek jest spełniony i drugiej, kiedy warunek nie jest spełniony (NIE). Operacje START i STOP są oznaczane figurą podobną do elipsy z odpowiednim komentarzem. 5.4 Zasady tworzenia schematów blokowych11: Schemat powinien być prosty i czytelny. W razie złożonego rozwiązania schemat należy podzielić na mniejsze części i zamieścić na osobnych arkuszach. Do rysowania schematów dobrze jest używać szablonów, polepsza to czytelność schematu. W blokach niezbędne jest komentowanie zarówno zaprojektowanej operacji, jak i kolejności ich wykonania. Komentarze powinny być krótkie, lecz dokładnie wyjaśniające znaczenie opisywanych elementów. Należy unikać rysowania przecinających się ścieżek sterowania. W razie konieczności lepiej jest wprowadzić odpowiedni łącznik, który pozwoli wyeliminować niektóre z linii. Powinno się unikać zapisywania wprowadzanych operacji za pomocą instrukcji języków programowania. Należy dokładnie numerować arkusze, na których został narysowany schemat blokowy. Trzeba liczyć się z możliwością wystąpienia konieczności poprawek do schematu, dlatego wskazane jest tak tworzyć arkusze, aby możliwe było naniesienie poprawek bez konieczności przerysowania całego schematu. Należy unikać zarówno zbyt dużej szczegółowości jak i zbytniej ogólności schematów. Nie należy umieszczać zbyt dużej liczby operacji w jednym bloku. Operacja warunkowa JEŻELI zawsze prowadzi do konieczności rozważenia dwóch dróg, gdy warunek jest spełniony i gdy nie jest. 5.5 Etapy rozwiązywania problemów12: 1. 2. 3. 4. 5. 11 12 Sformułowanie zadania. Określenie danych wejściowych. Określenie celu, czyli wyniku. Poszukiwanie metody rozwiązania, czyli algorytmu. Przedstawienie algorytmu w postaci: - opisu słownego, http://wiem.onet.pl/wiem/00f18c.html http://www.ids.poznan.pl/lo17/strony/informatyka/algorytmy/blokowe.htm 53/64 Materiały uzupełniające do wykładów z Języków Programowania II - listy kroków. - schematu blokowego, - jednego z języków programowania. 6. Analiza poprawności rozwiązania. 7. Testowanie rozwiązania dla różnych danych - ocena efektywności przyjętej metody. 5.6 Realizacja pętli i instrukcji warunkowych13. CASE. FOR 13 http://wiem.onet.pl/wiem/00f18c.html 54/64 Materiały uzupełniające do wykładów z Języków Programowania II WHILE REPEAT-UNTIL 5.7 Przykłady schematów blokowych: Rozwiązanie równania kwadratowego14. 14 http://wiem.onet.pl/wiem/00f18c.html 55/64 Materiały uzupełniające do wykładów z Języków Programowania II Rozwiązywanie równań stopnia nie wyższego niż drugi15. 5.8 Poprawność algorytmów. Praktyka programistyczna dowodzi, że nie da właściwie napisać programu, który by działał bezbłędnie: “Jeżli uważasz, że jakiś program kompurteowy jest bezbłędny, to się mylisz – po prostu nie zauważyłeś jeszcze skutków błędu, który jest w nim zawarty16”. W programie może wystąpić kilka rodzajów błędów: Błędy językowe – powstają w wyniku naruszenia składni języka programowania, którego używamy do zapisania agorytmu, np.: zamiast for i:=1 to N jest for i:=1 do N Możliwe skutki i znaczenie: • • • 15 16 zatrzymanie kompilacji lub interpretacji z komunikatem lub bez; przerwanie realizacji programu nawet jeżli kompilator nie wykrył błędu; są błędy niezbyt poważne i dość do naprawienia. http://cku.wodzislaw.pl/notatki/spis13_6.htm J. Sikorski: Wstęp do informatyki. Wyższa Szkoła Informatyki Stosowanej i Zarządzania. 56/64 Materiały uzupełniające do wykładów z Języków Programowania II Błędy semantyczne – wynikają z niezrozumienia semantyki używanego języka programowania, np. sądzimy, że po zakończeniu iteracji: for:=1 to N do X[i]:=i, zmienna i ma wartość N, a nie N+1. Możliwe skutki i znaczenie: • • program nie realizuje poprawnie algorytmu; są to błędy trudne do przewidzenia i potencjalnie groźne ale są do uniknięcia przy większej wiedzy i starannym sprawdzeniu znaczenia używanych instrukcji. Błędy logiczne – wynikają ze złego planu rozwiązania problemu, np. stosujemy podczas przeszukiwania tekstu znak “.” do określenia końca zdania, a nie przewidzieliśmy, że znak ten może wystąpić również w środku frazy, np.: Na rys. 4 pokazano ... Możliwe skutki i znaczenie: • • • • algorytm przestaje być poprawnym rozwiązaniem zadania algorytmicznego; dla pewnych zestawów danych wejściowych algorytm podaje wyniki niezgodne z oczekiwaniami; procesor może nie być w stanie wykonać pewnych instrukcji (np. żądamy dzielenia przez 0); są to błędy bardzo groźne – mogą być trudne do znalezienia i pozostawać długo w ukryciu nawet w trakcie używania programu w postaci kodu. Błędy algorytmiczne – wynikają z wadliwie skonstruowanych struktur sterujących, np. niewłaściwych zakresów iteracji, niewłaściwych warunków arytmetycznych i logicznych, błędnego przeniesienia punktu sterowania, itd. Możliwe skutki i znaczenie: • • • algorytm dla pewnych dopuszczalnych danych wejściowych daje niepoprawny wynik; wykonywanie programu realizującego algorytm jest przerywane w trybie awaryjnym; proces realizujący algorytm nie kończy w normalnym trybie sewgo zadania. 57/64 Materiały uzupełniające do wykładów z Języków Programowania II 6 Technologia programowania. Technologia programowania - nauka o procesach wytwarzania systemów informatycznych (programów komputerowych). W zakres technologii programowania wchodzą17: • • • • • • • • • sposoby prowadzenia projektów informatycznych, metody analizy i projektowania systemów, techniki planowania, szacowania kosztów, harmonogramowania i monitorowania projektów informatycznych, techniki zwiększania niezawodności oprogramowania, sposoby testowania systemów i szacowania niezawodności, sposoby przygotowania dokumentacji technicznej i użytkowej, procedury kontroli jakości, metody redukcji kosztów konserwacji, techniki pracy zespołowej. Program komputerowy - ciąg instrukcji do wykonania dla komputera. Można też powiedzieć, że program to algorytm zapisany w języku programowania. Program może występować w dwóch postaciach: jako program wykonywalny (czyli zapisany w języku maszynowym) albo jako kod źródłowy, czyli postać zrozumiała dla programisty. 6.1 Fazy powstawania programu komputerowego: Fazy powstawania programu komputerowego: • • • • • • • • • określanie wymagań, wybór języka programowania, tworzenie algorytmu, projektowanie systemu, implementacja, scalanie systemu, testy końcowe, tworzenie dokumentacji użytkowej, konserwacja systemu. Każda faza powinna posiadać własną dokumentację. W każdej fazie, szczególnie w końcowej części, powinna odbywać się weryfikacja (kodu i dokumentacji) oraz testowanie. Określanie wymagań – służy do sprecyzowania potrzeb. Na tym etapie formułuje się wyobrażenia o programie i jego działaniu oraz precyzuje wymagania. Na podstawie wymagań tworzona jest tzw. specyfikacja projektu, czyli zakres czynności, jaki dany program ma wykonywać. Jeżeli program jest tworzony na zamówienie, należy w pewnym momencie zażądać zamrożenia specyfikacji – w przeciwnym razie klient może zażądać zmian (nawet po napisaniu programu), a wykonawca będzie to musiał zrobić nieodpłatnie. Czasami nawet mała zmiana wymagań może w decydujący sposób wpłynąć na sposób realizacji zamówienia, co może nawet doprowadzić do konieczności rozpoczęcia praktycznie od nowa. 17 Ze względu na charakter skryptu, w rozdziale omówione zostaną jedynie podstawowe zagadnienia z zakresu technologii programowania. 58/64 Materiały uzupełniające do wykładów z Języków Programowania II Tworzenie wymagań możliwe jest to na kilka sposobów: • • • • • • • wywiad strukturalny (rozmowa z klientem lub użytkownikiem) – polega na zadawaniu wcześniej opracowanej listy pytań, wywiad swobodny – polega na zadawaniu dowolnych pytań i notowaniu odpowiedzi, ankieta wysyłana do dużej liczby potencjalnych klientów, analiza formularzy i innych dokumentów klienta, analiza cyklu pracy i wykonywanych czynności, analiza scenariuszy używania systemu, konstrukcja prototypu. Dokumentacja fazy określania wymagań powinna zawierać: • • • • • • • wprowadzenie: zakres systemu, cele i konteksty jego używania, opis ewolucji systemu: przewidywane zmiany w systemie, specyfikację wymagań funkcjonalnych: jakie czynności i operacje system powinien wykonywać, specyfikację wymagań niefunkcjonalnych: przy jakich ograniczeniach system powinien powstać i działać, opis modelu systemu lub jego prototypu, opis wymagań sprzętowych, słownik zawierający wyjaśnienia używanych w dokumentacji pojęć fachowych i informatycznych. Jeżeli program komputerowy powstaje na użytek programisty, faza określania wymagań może zostać skrócona do minimum. Nie powinno się jednak pomijać fazy dokumentacji – powinna oba być prowadzona przynajmniej w zakresie podstawowym, umożliwiającym rozwój i modyfikację programu nawet po wielu latach. Wybór języka programowania – zależy głównie od przeznaczenia aplikacji. Przeważnie istnieje przynajmniej kilka języków programowania nadających się budowy systemu spełniającego wymagania. Wybór języka programowania może być: • • • • • • • narzucony przez zamawiającego, pozostawiony woli wykonawcy – musi on wówczas uwzględnić: dziedzinę aplikacji, doświadczenie zespołu programistów, posiadane narzędzia, dostępność gotowych modułów i bibliotek, potrzeby innych prowadzonych równolegle prac. Wybór języka programowania może być dokonany przed lub po stworzeniu algorytmu. W pierwszym przypadku dobór języka może w znaczny sposób wpłynąć na tok rozumowania i zdeterminować budowę algorytmu. Tworzenie algorytmu - jest to jeden z najważniejszych etapów projektowania, wymaga on od programisty (bądź projektanta) starannego przemyślenia i przygotowania. Nie należy przystępować do pisania programu nie mając wyobrażenia o jego budowie. Takie postępowanie wydłuży zapewne czas realizacji projektu, zwiększy prawdopodobieństwo wystąpienia błędów oraz nie daje gwarancji optymalności rozwiązań. Dużych i rozbudowanych programów praktycznie nie da się napisać bez 59/64 Materiały uzupełniające do wykładów z Języków Programowania II odpowiednich przygotowań. Jeżeli to jest tylko możliwe należy korzystać z istniejących i sprawdzonych algorytmów. Projektowanie systemu – służy do stworzenia szkieletu kodu źródłowego (systemu). Techniki projektowania: • • • • projektowanie strukturalne: zorientowane na akcję, zorientowane na dane, projektowanie obiektowe. Faza projektowania składa się z następujących etapów: • • • • projektowanie architektury systemu, organizacja danych i ich nazewnictwa, szczegółowe projektowanie modułów, weryfikacja i testowanie. Projekt systemu informatycznego powinien również uwzględniać ergonomiczność aplikacji, obejmującą: • • • • • • • właściwy dobór systemów menu, w tym menu kontekstowych, wprowadzenie ikon, grafiki i sterowania aplikacji wskaźnikiem myszy, dobór kolorów, czcionek i właściwe rozmieszczenie informacji na ekranie, łatwość wyboru funkcji systemu, szybkość obsługi (skróty klawiszowe dla najczęściej wykonywanych operacji), możliwość dostosowywania wyglądu aplikacji i jego elementów (menu, ikon, przycisków) do indywidualnych potrzeb użytkowników, jednolitość interface’u w różnych częściach systemu. Implementacja – jest to właściwa faza budowy programu. Małe systemy informatyczne mogą być realizowane przez jednego programistę. Systemy większe wymagają utworzenia zespołu bądź też grupy zespołów programistycznych. Scalanie systemu – w przypadku tworzenia aplikacji przez zespół programistów należy połączyć wszystkie moduły w jedną całość. Rozróżnia się trzy podstawowe techniki integracji systemu informatycznego: • • • metoda zstępująca – najpierw integrowane są moduły sterujące, a później moduły wykonawcze, metoda wstępująca – najpierw integrowane są moduły wykonawcze a później sterujące, metoda mieszana – moduły sterujące integrowane są metodą zstępującą, a wykonawcze – wstępującą. Na końcu części wykonawcze są dołączane do sterujących. Testy końcowe – służą do ostatecznego potwierdzenia poprawności systemu. Rozróżnia się następujące etapy testów: • • • • testowanie przez Dział Kontroli Jakości, alfa-testy przez wybraną (najczęściej małą) grupę użytkowników, beta-testy przez wybraną (większą) grupę użytkowników. testy akceptacji (na rzeczywistych danych), wykonywane przez odbiorcę. 60/64 Materiały uzupełniające do wykładów z Języków Programowania II Zalety Wady brak izolacji błędów, poważne błędy projektowe są wykrywane bardzo późno. izolacja błędów, poważne błędy projektowe są wykrywane wcześnie. izolacja błędów, moduły, które mogą być powtórnie użyte są dobrze przetestowane. izolacja błędów, poważne błędy projektowe są wykrywane wcześnie. moduły, które mogą być powtórnie użyte są dobrze przetestowane. moduły, które mogą być powtórnie użyte nie są w pełni przetestowane. poważne błędy projektowe są wykrywane bardzo późno. integracja całości metoda zstępująca metoda wstępująca metoda mieszana Tab.9. Porównanie metod scalania systemu Dokumentacja użytkowa – powinna zawierać następujące elementy: • • • • • • • • • • • • • • • opis funkcjonalny – opis przeznaczenia oraz głównych możliwości programu, podręcznik użytkownika – opis przeznaczony dla typowych użytkowników, powinien zawierać: sposoby uruchamiania oraz kończenia pracy z systemem, sposoby realizacji najczęściej wykorzystywanych funkcji systemu, metody obsługi błędnych sytuacji, sposoby korzystania z systemu pomocy, kompletny przykład korzystania z systemu, kompletny opis systemu – część przeznaczona dla doświadczonych użytkowników, powinien zawierać: szczegółowy opis wszystkich funkcji systemu, informacje o wszystkich sposobach wywoływania tych funkcji, opisy formatu danych, opisy błędów, które mogą pojawić się w trakcie pracy z systemem, informacje o wszelkich ograniczeniach dotyczących np. zakresu danych. opis instalacji – przeznaczony dla administratorów systemu. Powinien zawierać opis procedury instalacyjnej i konfiguracji programu, podręcznik administratora systemu – zawierający opis możliwości modyfikacji ustawień systemu oraz sposoby udostępniania go użytkownikom końcowych. Na jakość dokumentacji mają wpływ następujące czynniki: • • • • • • • • • • • struktura podręcznika, zachowanie standardów, sposób pisania, w tym: stosowanie formy aktywnej, poprawność gramatyczna i ortograficzna, krótkie zdania, oszczędność sów, precyzyjna definicja używanych terminów, powtarzanie trudnych opisów, stosowanie tytułów i podtytułów sekcji, wyliczeń i wyróżnień, zrozumiałe odwołania do innych rozdziałów. 61/64 Materiały uzupełniające do wykładów z Języków Programowania II Konserwacja systemu – zawiera zespół czynności, dokonywanych po stworzeniu obejmujących: • • • aplikacji, poprawianie błędów, udoskonalanie produktu, dostosowywanie do nowych warunków. Koszty konserwacji są często bardzo duże – do 2/3 nakładów finansowych na aplikacje. Wynika to z następujących przyczyn: • • • poprawki mogą być przyczyną nowych błędów, udoskonalenie wymaga przejścia przez wszystkie fazy produkcji i dokonania zmian w specyfikacji, projekcie i dokumentacji, poprawione powinny być wszystkie dokumenty, w których znajdują się informacje dotyczące zmienionych fragmentów produktu. Zarządzanie fazą konserwacji: • • • • • raport o błędzie – formalna metoda dokumentacji wykrytych przez użytkowników błędów systemu – musi zawierać informacje wystarczające do odtworzenia błędu, błędy krytyczne muszą być poprawiane natychmiast, dla pozostałych powinny zostać opisane przyczyny błędu i ewentualne metody ich obejścia, opisane raporty o błędach wraz z datą ich poprawienia powinny być udostępniane wszystkim użytkownikom, błędy niekrytyczne powinny być poprawiane paczkami – obniża to koszty testowania i modyfikacji dokumentacji, zmodyfikowany produkt powinien być sprawdzony przez niezależny zespół kontroli. 6.2 Rodzaje programowania Programowanie (ang. programming) - czynności związane z wpisywaniem poleceń języka programowania przez programistów celem tworzenia oprogramowania komputerowego. Rodzaje programowania: • programowanie strukturalne - rodzaj programowania, w którym program podzielony jest na niewielkie moduły - procedury bądź funkcje. Programowanie strukturalne ułatwia projektowanie, testowanie a także utrzymanie kodu programu. Do najpopularniejszych języków strukturalnych zalicza się Pascal, C, Modula-2. • programowanie obiektowe - rodzaj programowania, w którym dane i wykonywane na nich operacje są połączone. Ten formalny zabieg umożliwia szybsze pisanie większych programów, przez „składanie ich” ze wzajemnie powiązanych obiektów, które odpowiadają za daną funkcję programu (np. przygotowanie danych, wykonanie obliczeń, zaprezentowanie wyników). Do najpopularniejszych języków programowania obiektowego należą C++, Java, Eiffel. • programowanie modularne (angielskie modular programming) - paradygmat programowania zalecający stosowanie modułów, jako nadrzędnych w stosunku do procedur bloków tworzących program. Moduł w pojęciu programowania modularnego grupuje funkcjonalnie związane ze sobą dane i procedury i jest reprezentacją obiektu występującego w programie w jednym egzemplarzu. 62/64 Materiały uzupełniające do wykładów z Języków Programowania II • programowanie proceduralne (angielskie procedural programming) - paradygmat programowania zalecający stosowanie procedur i instrukcji strukturalnych, wystarczający do programowania większości metod numerycznych oraz obliczeń inżynierskich lub matematycznych. • programowanie funkcjonalne (angielskie functional programming) - koncepcja programowania bez używania przypisań; w programowaniu funkcjonalnym obliczenie tej samej procedury z tymi samymi parametrami powoduje zawsze powstanie tego samego wyniku, procedury w programowaniu funkcjonalnym mogą zatem być rozważane jako funkcje w rozumieniu matematycznym. • programowanie RAD, Rapid Application Development - termin komercyjny („błyskawiczne opracowywanie aplikacji”) określający możliwości pakietu oprogramowania działającego w graficznym środowisku okienkowym, służącego do zestawiania aplikacji, w szczególności – ich interfejsów, z modułów wybieranych z bibliotek udostępnianych w postaci drzew tematycznych. W zależności od wybranego elementu pakiet RAD wytwarza fragmenty kodu (np. w języku C++) wraz z odpowiednimi wywołaniami. Szczegóły odbiegające od standardu uzupełnia ręcznie programista. Aplikacje wytworzone w środowiskach RAD są z reguły słabo przenośne i zajmują dużo pamięci, jednak możliwość automatycznego oprogramowania ich najżmudniejszych elementów (interfejs graficzny) oraz ułatwiony kontakt ze standardowymi bazami danych powoduje, że programowanie RAD staje się coraz popularniejsze. • programowanie liniowe - maksymalizacja lub minimalizacja funkcji wielu zmiennych, gdy zmienne te, lub niektóre z nich, podlegają liniowym warunkom ograniczającym w postaci równań lub nierówności. Nazwa "programowanie" wskazuje w tym kontekście na schemat działań. • programowanie nieliniowe - metody rozwiązywania problemów opisywanych przez równania różniczkowe nie dające się sprowadzić do równań liniowych (programowanie liniowe). • programowanie dynamiczne - metoda zapewniająca wybór ciągu zgodnych rozwiązań optymalnych w wielostopniowych problemach decyzyjnych. W istocie jest to proces sekwencyjnego podejmowania decyzji. • programowanie w logice (angielskie logic programming) - kierunek rozwojowy języków programowania, korzystający istotnie z doświadczeń i osiągnięć logiki matematycznej. Instrukcje języków programowania w logice przyjmują postaci wzorów logicznych (predykatów). Programowanie w logice znajduje zastosowanie przy budowaniu inteligentnych baz wiedzy, systemów ekspertowych, w eksperymentach ze sztuczną inteligencją. • programowanie współbieżne (angielskie concurrent programming) - programowanie procesów współbieżnych realizowane za pomocą specjalnie zaprojektowanych języków programowania (np. Linda), języków odpowiednio dostosowanych (np. Concurrent Pascal) lub przy użyciu bibliotek synchronizacji procesów i wątków. • programowanie programowania użytkownika i Programowanie z użyciem obiektów (angielskie object-based programming) - paradygmat dopuszczający możliwość tworzenia typów zdefiniowanych przez posługiwania się w programach danymi nowo zdefiniowanych typów. z użyciem obiektów jest zalecane tam, gdzie programowanie proceduralne 63/64 Materiały uzupełniające do wykładów z Języków Programowania II lub modularne okazują się niewystarczające z uwagi na potrzebę użycia nowych typów danych i liczne ich reprezentacje (obiekty), natomiast programowanie obiektowe jest niepotrzebne z powodu prostych właściwości przedmiotu programowania. • programowanie wstępujące - w programowaniu strukturalnym rozwiązywanie problemu za pomocą wydzielonych prostszych zadań. • programowanie zstępujące - w programowaniu strukturalnym rozwiązywanie problemu w jednym ogólnym, dobrze przemyślanym planie. Wojciech Sobieski ©2006 64/64