Paradygmaty Składnia Semantyka, Składnia i semantyka


Składnia i semantyka

Reprezentacja algorytmu wymaga użycia pewnej formy języka. Ludzie mogą wykorzystywać język naturalny (etniczny, np. polski, angielski, francuski,…) lub język obrazowy (np. algorytm składania ptaka z kwadratowego kawałka papieru [2]). Często komunikowanie się w języku naturalnym prowadzi do nieporozumień ze względu na wieloznaczność (np. słowo: „lalka”, „zamek”; zdanie: „Odwiedziny wnuków mogą być stresujące” - może oznaczać problemy, gdy nas odwiedzają, albo też, że wizyta u nich jest stresująca). Często pojawiają się także problemy dotyczące wymaganego poziomu (stopnia) szczegółowości (poziom szczegółowości należy dobierać w zależności od tego, do kogo jest adresowany algorytm, zależy od jego wiedzy, doświadczenia…). Oznacza to, że źródłem problemów jest brak precyzyjnej definicji języka (języka algorytmicznego) stosowanego do opisu algorytmu lub niewłaściwy poziom szczegółowości przekazywanej informacji [2].

W informatyce rozwiązywane są te problemy poprzez tworzenie dobrze określonego zestawu cegiełek, z których można konstruować reprezentacje algorytmów. Takie cegiełki nazywane są konstrukcjami pierwotnymi (primitives). Problemy niejednoznaczności usuwa się, przypisując pierwotnym konstrukcjom ścisłe definicje. Natomiast wymaganie, aby algorytmy opisywano za pomocą tych konstrukcji pierwotnych (cegiełek), ustanawia jednolity poziom szczegółowości [2].

Zestaw konstrukcji pierwotnych razem z zestawem reguł definiujących sposób ich łączenia ze sobą (w tym zestaw reguł budowy złożonych konstrukcji z pierwotnych konstrukcji) w celu reprezentacji bardziej złożonych obiektów składają się na język programowania [2].

Każdą konstrukcję pierwotną definiuje się za pomocą dwóch elementów [2]:

Składnia opisuje symboliczną reprezentację konstrukcji pierwotnej.

<Składnia>::= <opis symbolicznej reprezentacji konstrukcji pierwotnej>.

Semantyka jest znaczeniem konstrukcji pierwotnej, czyli pojęcie, które konstrukcja reprezentuje [2].

< Semantyka >::= < znaczenie konstrukcji pierwotnej, pojęcie, które konstrukcja reprezentuje>.

Na przykład, napis „powietrze”- składniowo jest ciągiem 9 symboli (liter alfabetu), a semantyką jest znaczenie tego słowa - jest to substancja lotna otaczająca kulę ziemską [2]. Zdanie „Ten kamień jest głupi” nie ma znaczenia w języku polskim (nie ma sensu).

Zestaw konstrukcji pierwotnych do reprezentacji algorytmów przeznaczonych do wykonania na komputerze można uzyskać na podstawie rozkazów maszynowych konkretnego komputera (z listy rozkazów mikroprocesora). Algorytm wyrażony na tym poziomie szczegółowości z całą pewnością pozwoliłby na otrzymanie programu, który można by wykonać na komputerze. Reprezentacja algorytmu na tym poziomie szczegółowości jest jednak żmudna (złożona) i podatna na błędy, dlatego też zwykle stosuje się pierwotne konstrukcje językowe „ z wyższego poziomu”. Każda z nich jest narzędziem abstrakcyjnym, które można zbudować, posługując się konstrukcjami pierwotnymi niższego poziomu dostępnymi w języku maszynowym komputera. Dzięki takiemu zabiegowi uzyskuje się formalny język programowania, w którym algorytmy można wyrażać na wyższym poziomie abstrakcji niż w języku maszynowym konkretnego komputera [2].

Składnia to zbiór reguł, opisujących jak wygląda poprawny program w danym języku, czyli np. [3]:

Jak widać z powyższego wyliczenia, jesteśmy tak bardzo przywiązani do języków imperatywnych i obiektowych, że chyba nie bardzo wyobrażamy sobie język bez poleceń, pętli while, zmiennych...

Semantyka to znaczenie wspomnianych wyżej form, czyli „co one robią”. Weźmy dla przykładu typową instrukcję warunkową [3]:

Powyższy opis semantyki instrukcji warunkowej jest, co prawda niezbyt formalny, ale zupełnie zrozumiały [3]:

Na razie warto zrezygnować z wprowadzenia formalnego języka programowania. W miejsce jego można zdefiniować mniej formalny, bardziej intuicyjny system notacyjny, zwany pseudokodem.

<Pseudokod>::= <intuicyjny system notacyjny, w którym nieformalnie wyraża się koncepcje związane z opracowywanym algorytmem>.

Pseudokod można uzyskać, rozluźniając wymagania stawiane językowi formalnemu, w którym ma być wyrażona końcowa wersja algorytmu. Takie podejście stosuje się często, jeśli jest znany z góry docelowy język programowania. Pseudokod stosowany we wczesnych fazach tworzenia oprogramowania składa się ze struktur składniowo - semantycznych, które przypominają struktury występujące w docelowym języku programowania, lecz są mniej formalne.

Czym jest język i jak go opisać?

Pojęcie język jest rozumiane jako skończony zbiór symboli języka (alfabet) wraz ze zbiorem reguł łączenia (składania) poszczególnych symboli (liter /znaków alfabetu) w ciągi (słowa) i zbiorem reguł (semantycznych) nadających ciągom symboli znaczenie (sens) merytoryczne.

Język jest to, więc ogólna nazwa zdefiniowanego zbioru znaków oraz reguł lub konwencji określających sposoby i kolejności, w jakich znaki te mogą być łączone dla nadania im znaczenia w tym języku.

Język można traktować jako uporządkowaną czwórkę elementów [26]:

J = {A, W, D, Z},

gdzie: A jest alfabetem języka, W - zbiorem wyrażeń poprawnych, D - dziedzina języka, Z - znaczenie języka.

Alfabet języka jest to zbiór skończony znaków zwanych literami. Każdy ciąg skończony liter nazywamy napisem.

Zbiór wyrażeń poprawnych języka jest to pewien wyróżniony zbiór napisów w alfabecie tego języka. O tym, czy dany napis jest wyrażeniem poprawnym języka, czy też nim nie jest decydują reguły gramatyczne języka, które określają strukturę wyrażeń poprawnych. Spis tych reguł tworzy gramatykę języka (w szerokim sensie obejmuje również reguły morfologii języka). Wyrażeniem poprawnym jest, więc nie tylko zdanie ( w tym ujęciu), lecz także każdy poprawnie zbudowany wyraz. Od reguł gramatycznych nie wymaga się, aby określały sens wyrażeń, uznanych przez nie za poprawne.

Dziedzina języka jest zbiór wiadomości /informacji, którego elementy stanowią treść (sens) wyrażeń poprawnych języka. Inaczej mówiąc, dziedziną języka jest zbiór wszystkich wyrażalnych w tym języku wiadomości / informacji (może zawierać pojęcia nie wyrażalne w innych językach).

Znaczenie języka jest relacją wiążącą wyrażenia poprawne języka z elementami jego dziedziny.

Element dziedziny pozostający w tej relacji z pewnym wyrażeniem poprawnym języka nazywa się znaczeniem tego wyrażenia. Jedno wyrażenie może mieć wiele znaczeń, np. lalka, skok, zamek itp. Wiele wyrażeń może mieć to samo znaczenie, np. samochód, auto, pojazd dwuśladowy itp.; wyrażenia pozbawione sensu nie mają znaczeń. Reguły określające omawianą relację nazywamy regułami znaczeniowymi lub semantycznymi języka. Język, który jest stosowany do przedstawienia algorytmów, nosi nazwę języka algorytmicznego, a przy stosowaniu go do celów programowania, określany jest jako język programowania.

Algorytm przedstawiony w języku programowania nazywa się programem.

Programem nazywamy opis sposobu przetwarzania danych. Jest to uporządkowany zbiór (ciąg) rozkazów (instrukcji) i innych danych (struktur danych) związanych z rozkazami [36]. Program działa na podstawie algorytmu, który z kolei jest ściśle związany ze strukturami danych (obiekty proste, złożone), na których operuje tzn. [37]:

ALGORYTMY + STRUKTURY DANYCH = PROGRAMY.

Język to zbiór napisów utworzonych ze znaków z ustalonego alfabetu [3]:

Mówiąc o językach programowania, chcemy takie właśnie języki móc precyzyjnie opisywać [3]:

Jak zatem my będziemy opisywać języki programowania lub ich elementy?

Notacja BNF (Backus Naur Form) jest powszechnie używana właśnie do opisu składni języków programowania. Stworzona została w trakcie prac nad językami Fortran i Algol na przełomie lat pięćdziesiątych i sześćdziesiątych XX wieku

Często stosuje się dodatkowe symbole i konwencje, upraszczające zapis

typ ::= char | int | float | double

instr_warunkowa ::= if wyr_logiczne then instr [ else instr ]

lista_arg ::= arg { "," arg }

liczba_ze_znakiem ::= ("+" | "-") liczba_bez_znaku

Chcąc opisać powtarzające się elementy, możemy stworzyć definicję rekurencyjną lub wykorzystać nawiasy klamrowe:

lista_identyfikatorów  ::= identyfikator

| lista_identyfikatorów "," identyfikator

lista_identyfikatorów  ::= identyfikator { "," identyfikator }

Klasyczny przykład użycia notacji BNF to opis składni notacji BNF:

składnia ::= { reguła }

reguła ::= identyfikator "::=" wyrażenie

wyrażenie ::= składnik { "|" składnik }

składnik ::= czynnik { czynnik }

czynnik ::= identyfikator

| symbol_zacytowany

| "(" wyrażenie ")"

| "[" wyrażenie "]"

| "{" wyrażenie "}"

identyfikator ::= litera { litera | cyfra }

symbol_zacytowany ::= """ { dowolny_znak } """

Zauważmy, że niektóre symbole, formalnie terminalne, są właściwie niedodefiniowanymi symbolami nieterminalnymi. Gwoli ścisłości powinniśmy, zatem dopisać:

litera ::= "A" | "B" | "C" | ...

cyfra ::= "0" | "1" | ... | "9"

dowolny_znak ::= ...

Jak widać, użyliśmy kolejnego niedodefiniowanego symbolu, a mianowicie wielokropka. Nie brnijmy jednak dalej w formalizowanie rzeczy jasnych i znanych...

Na pewno wszyscy wiedzą, jak uruchomić program napisany np. w języku C++. Dla naszych rozważań istotne jest to, że program taki musi zostać przetłumaczony na język wewnętrzny maszyny, na której program zamierzamy uruchomić. Owo tłumaczenie może być dokonane na jeden z dwóch sposobów:

Nie zamierzamy zagłębiać się tu w tajniki budowy kompilatorów, czyli programów tłumaczących

Dlaczego w takim razie chcemy mówić o implementacji?

Przykład

for i := 1 to length(s) do ...

for (i = 1; i <= strlen(s); ++i) ...

Uwagi bibliograficzne

Pisząc wykłady omawiające kwestie implementacyjne (2-4) oraz wykłady przeglądowe (5-7) korzystaliśmy z ciekawie opracowanej, rozległej tematycznie książki Sebesty „Concepts of Programming Languages”.

Wykład o rachunku lambda bazuje na „Wybranych zagadnieniach z teorii rekursji”, zaś wykład o rachunku sigma — na „A Theory of Objects” Abadiego i Cardellego. Wiele informacji do wykładów o Haskellu zaczerpnęliśmy z „Introduction to Functional Programming using Haskell” Birda, zaś do wykładów o Prologu — z „Logic, Programming and Prolog” Nilssona i Małuszyńskiego. Pozostałe pozycje ze spisu literatury również stanowiły cenne źródło informacji.

Wykaz literatury podstawowej:

  1. Bertrand M. Programowanie zorientowane obiektowo, Helion, Gliwice 2005

  2. Brookshear J. G. Informatyka w ogólnym zarysie. WNT, Warszawa 2003

  3. http://wazniak.mimuw.edu.pl/

  4. Kluźniak F., Szpakowicz S. Prolog, WNT, Warszawa 1983

  5. Oficjalna strona języka CLIPS: http://www.ghg.net/clips/CLIPS.html

  6. Prata S. Szkoła Programowania. Język C. Wyd. V, Helion, Gliwice 2006

  7. Prata S. Szkoła Programowania. Język C++. Wyd. V, Helion, Gliwice 2006

  8. Sebesta R., Concepts of Programming Languages, Addison Wesley, 2005

  9. Ullman L., Liyanage M. Programowanie w języku C. Szybki startEdytuj. Błyskawiczny kurs programowania w języku C. HELION, Gliwice 2005

  10. Ullman L., Singel A. Szybki start. Programowanie w języku C++. Błyskawiczny kurs tworzenia aplikacji w jednym z najpopularniejszych języków programowania. HELION, Gliwice 2007

Wykaz literatury uzupełniającej:

  1. Daniluk A. C++ Builder Borland Developer Studio 2006. Helion, Gliwice 2006

  2. Garbacz B., Koronkiewicz P., Grażyński A. Programowanie, koncepcje, techniki i modele. Helion, Gliwice 2005

  3. Grębosz J.: Symfonia C++ standard, Edition 2000, 2005

  4. Grębosz J.: Pasja C++, Oficyna Kallimach, Kraków, 2003

  5. Eckel B.: Thinking in Java. Edycja polska. Wydanie IV, Helion 2006

  6. Kochan S. G. Język C. Wprowadzenie do programowania. Helion 2005

  7. Liberty J. C++ księga eksperta. Helion, Gliwice 1999

  8. Liberty J. C++ dla każdego. Helion, Gliwice 2002

  9. Liberty J., MacDonald B.: C# 2005. Wprowadzenie, Helion 2007

  10. Neibauer A. R. Języki C i C++”. HELP Warszawa 1995, Wyd. IV, 2005

  11. Nilsson U., Małuszyński J., Logic, Programming and Prolog, John Wiley & Sons, 1995

  12. Savitch W. W tonacji C++. RM, Warszawa 2005

  13. Solter N. A., Kleper S. J. C++. Zaawansowane programowanie. Helion, Gliwice 2006

  14. Stasiewicz A. Wkrocz w świat programowania w C ++. Ćwiczenia praktyczne C++. Wyd. II, Helion, Gliwice 2006

  15. Thinking in C++ Edycja polska BRUCE ECKEL (tłumaczenie: Imiela P.). HELION, Gliwice 2002

Wykaz literatury dodatkowej:

  1. Borowiec J. i inni pod red. R. Marczyńskiego. Problemy przetwarzania informacji. WNT, Warszawa, 1970

  2. Jankowscy J. i M.: Przegląd metod i algorytmów numerycznych. Część 1, WNT, Warszawa 1988

  3. Majgier D. Kurs XHTML / HTML/CSS http://algorytmy.pl/doc/xhtml/

  4. Maguire S. Niezawodność oprogramowania. Helion, Gliwice 2002

  5. Myers G. J. Projektowanie niezawodnego oprogramowania. WNT, Warszawa 1980

  6. Myers G. J.,Sandler C., Badgett T., Thomas T. M. Sztuka testowania oprogramowania. Helion, Gliwice 2005

  7. Nabajyoti Brkakati. Biblia Turbo C++. Oficyna Wydawnicza LT&P

  8. Oualline S. Jak nie programować w C++, czyli 111 programów z błędami i 3 działające. MIKOM, Warszawa 2003

  9. Sysło M. Algorytmy. Wyd. Szkolne i Pedagogiczne, Warszawa 1997

  10. Tanenbaum A. S. Organizacja maszyn cyfrowych w ujęciu strukturalnym. WNT, Warszawa 1980

  11. Turski W. M. Propedeutyka informatyki. PWN, Warszawa 1989

  12. Wirth N. Algorytmy + struktury danych = programy. WNT, Warszawa 1980

2



Wyszukiwarka