język programowania
 
Encyklopedia PWN
język programowania,
inform. narzędzie do formułowania programów dla komputerów; jest językiem formalnym, którego składnia określa zasady zapisu programów (w sposób jednoznaczny i łatwy do analizy), a semantyka przypisuje programom ich interpretację (określa efekty działania programu zapisanego w języku programowania).
Składnia języka programowania jest najczęściej definiowana za pomocą gramatyki bezkontekstowej (gramatyka formalna), w której można wygodnie opisać zagnieżdżone struktury (np. instrukcje złożone, wyrażenia arytmetyczne z nawiasami); dodatkowe warunki składniowe, których nie można zdefiniować w ten sposób (np. wymaganie, aby funkcje użyte w programie były w nim zdefiniowane), są najczęściej zapisywane w języku naturalnym. Semantyka jest zwykle opisywana tekstem w języku naturalnym, choć można ją określić w sposób w pełni precyzyjny i formalny, np. podając reguły tłumaczenia konstrukcji języka programowania na ciąg operacji pewnego hipotetycznego komputera (semantyka operacyjna) albo określając sposób konstruowania funkcji przekształcającej dane wejściowe programu w jego wyniki (semantyka denotacyjna).
Program zapisany w języku programowania (tzw. kod źródłowy) może być wykonany na 2 sposoby — interpretacji bądź kompilacji. W wypadku interpretacji program (tekst programu) jest analizowany i niezwłocznie wykonywany przez interpreter; każdorazowe wykonanie programu polega na przeprowadzeniu analizy składniowej, podzieleniu programu na poszczególne jednostki (wyrażenia, instrukcje) i wykonaniu czynności wynikających z semantyki języka programowania. W wypadku kompilacji program jest analizowany jeden raz — przez program zwany kompilatorem, który następnie generuje kod wynikowy programu (zwany też kodem binarnym), czyli ciąg instrukcji procesora; ciąg ten może być później załadowany do pamięci komputera i wielokrotnie wykonany przez procesor, bez potrzeby ponownego sięgania do kodu źródłowego; w wypadku niektórych instrukcji języka programowania (np. związanych z wejściem/wyjściem) kompilator generuje wywołania procedur bibliotecznych. Interpretacja jest wygodniejsza w wypadku jednorazowego wykonania programu; pozwala dokładniej lokalizować błędy w trakcie wykonywania programu, dlatego często bywa używana przy jego uruchamianiu. Kompilacja jest efektywniejsza, jeśli program ma być wykonywany wielokrotnie. W systemach mieszanych kompilator generuje pewien kod pośredni zawierający instrukcje pewnego hipotetycznego procesora dostosowanego do cech kompilowanego języka programowania; kod może być zapamiętany, a następnie wielokrotnie wykonany przez prosty interpreter; w ten sposób wykonuje się np. programy napisane w Javie.
Podział języków programowania. W językach imperatywnych program jest zapisany jako ciąg wykonywanych kolejno instrukcji — odpowiada to intuicyjnemu sposobowi zapisu algorytmów. Typowym konstrukcjom strukturalnym (wybór jednej z możliwych instrukcji, wielokrotne wykonanie instrukcji) odpowiadają instrukcje złożone. Wyniki obliczeń dokonywanych w czasie wykonywania instrukcji są przypisywane zmiennym (inform.), tak aby były dostępne w następnych instrukcjach.
Pierwszymi językami imperatywnymi były języki maszynowe o bardzo prostej składni, których instrukcje odpowiadały instrukcjom procesora. Wraz ze wzrostem możliwości komputerów wprowadzono języki symboliczne, w których programista nadaje pewnym miejscom w pamięci nazwy; faktyczne adresy są wyliczane w czasie pracy translatora i wpisywane w miejsce nazw. Takie języki i ich translatory nazywa się asemblerami. Programowanie w asemblerze jest mało wydajne i podatne na błędy, a programu nie można łatwo przenieść na komputer z innym procesorem. Asembler pozwala jednak najlepiej wykorzystać możliwości instrukcji procesora. Do lat 80. w asemblerach powstawała większość programów specyficznych dla konkretnego komputera, takich jak systemy operacyjne i systemy zarządzania bazami danych. Asemblery tradycyjnie nazywa się językami pierwszej generacji.
Języki drugiej generacji to wczesne języki imperatywne z przełomu lat 50. i 60. (Basic, Fortran, Cobol); języki te mają niewielkie możliwości definiowania typów danych i nie są dostosowane do programowania strukturalnego (brak instrukcji złożonych, konieczność korzystania z instrukcji skoku). Języki trzeciej generacji mają bardziej rozbudowaną składnię i semantykę (Algol: 60 i 68, Simula 67, PL/1, Pascal, Ada, C, Modula, Java); w programach można korzystać z instrukcji złożonych, dzięki którym algorytmy są zapisane w sposób bardziej czytelny i mniej podatny na błędy niż w językach 2. generacji. Obecnie także część języków 2. generacji została rozbudowana o mechanizmy charakterystyczne dla języków 3. generacji (Fortran 77 — stosowany do obliczeń numerycznych, Visual Basic — używany do pisania prostych programów do wprowadzania i wypisywania danych z wykorzystaniem graficznego interfejsu użytkownika). Językami czwartej generacji (4GL, 4. Generation Language) nazywa się języki umożliwiające dostęp do baz danych; mogą one być związane z konkretnym systemem zarządzania relacyjną bazą danych; korzystają z wyrażeń języka SQL rozbudowanych o zmienne i instrukcje; wyniki wyrażeń SQL mogą być przypisane zmiennym, a następnie przetwarzane, tak jak w językach 3. generacji. Instrukcje języków 4. generacji pozwalają także na łatwe generowanie raportów na podstawie zawartości bazy danych.
W językach funkcyjnych program składa się z definicji i wywołań funkcji — przypomina standardową notację matematyczną; nie występują instrukcje ani zmienne. Język programowania Lisp jest oparty na koncepcji λ-rachunku Churcha, rozszerzonej o możliwości definiowania struktur danych w postaci drzew (inform.), które mogą być przekazywane jako argumenty oraz wyniki funkcji; Lisp jest używany do zapisu algorytmów przetwarzania symbolicznego. Język programowania Hope stanowi rozwinięcie języka Lisp o nowsze pojęcia, np. typy danych. W języku programowania SQL funkcja jest wykonywana w algebrze relacji, a jej wynikiem jest relacja spełniająca zadane kryteria.
W językach bardzo wysokiego poziomu, zwanych też językami programowania w logice (np. Prolog) program składa się z ciągu formuł logicznych, a wykonanie programu polega na próbie zweryfikowania poprawności zadanej formuły.
Niektóre języki nie należą do żadnej z powyższych klas; np. APL (ang. A Programming Language) powstał w celu programowania w trybie interakcyjnym, szczególnie obliczeń numerycznych — ma bardzo skondensowany zapis, wzorowany na notacji matematycznej, z operatorami zapisywanymi w postaci liter greckiego alfabetu, Snobol (ang. String Oriented and Symbolic Language) służy do symbolicznego przetwarzania tekstu — podstawową instrukcją jest dopasowanie słowa do ustalonego wzorca i przypisanie części słowa zmiennym tekstowym.
Przy tworzeniu programów korzystających z graficznego interfejsu użytkownika korzysta się ze środowisk graficznych obejmujących języki programowania 3. generacji (Visual Basic, Pascal, C, C++, Java), bibliotekę procedur dostępu do funkcji interfejsu oraz programu generatora, automatycznie tworzącego szkielet programu na podstawie prostych operacji wykonywanych przez programistę (np. wybranie przez programistę obiektu typu „lista rozwijana” i umieszczenie go na ekranie powoduje wygenerowanie instrukcji wywołującej procedurę biblioteczną, której wykonanie spowoduje wyświetlenie listy rozwijanej na ekranie w czasie pracy programu).
Poszczególne języki programowania różnią się m.in. zbiorem dostępnych instrukcji i typów danych. Wprawdzie w komputerze wszystkie dane są przechowywane w postaci ciągu bitów, to jednak w języku programowania poszczególnym obiektom (np. zmiennym) nadaje się typy określające zbiór możliwych wartości i ich interpretację (np. liczba całkowita, znak, napis); reguły składniowe języków programowania określają, które działania mogą być dokonywane na wartościach należących do różnych typów; ten sam symbol może oznaczać różne operacje, zależnie od typów argumentów (np. jeśli a i b mają typ „liczba”, to wyrażenie a + b może oznaczać arytmetyczne dodawanie, natomiast jeśli a i b są ciągami znaków, czyli napisami, to samo wyrażenie może oznaczać konkatenację, czyli połączenie obu napisów).
W językach obiektowych (np. Simula 67, Smalltalk, C++) programista może definiować nowe typy danych (tzw. klasy), definiując funkcje i procedury operujące na obiektach danego typu (tzw. metody). Można np. zdefiniować klasę liczb zespolonych oraz metody odpowiadające operacjom arytmetycznym na obiektach z tej klasy albo klasę okien dialogowych wyświetlanych na ekranie z metodami określania wielkości okna, jego położenia na ekranie, zestawu wyświetlanych przycisków itp. Na podstawie już zdefiniowanej klasy można definiować podklasy, które dziedziczą właściwości klasy macierzystej i dołączają nowe; np. w podklasie klasy okien dialogowych może być dołączona metoda zmiany koloru tła. Elegancki i spójny mechanizm dziedziczenia został zaproponowany w opracowanym w Polsce języku Loglan.
W językach programowania (poza asemblerami) programista nie korzysta z bezpośredniego adresowania słów w pamięci — ma dostęp jedynie do zmiennych, których rozmieszczenie w pamięci określa kompilator lub interpreter; konsekwentne stosowanie tej reguły chroni przed błędami, które powstałyby np. wskutek omyłkowego lub celowego zapisania nowych danych w miejscu przeznaczonym na kod programu. Niektóre języki pozwalają jednak na obejście tej reguły, np. w języku programowania C programista może zdefiniować tzw. wskaźnik zawierający dowolny adres. Umożliwia to sięgnięcie do dowolnego adresu i może spowodować bardzo poważne błędy. W Javie wprowadzono ograniczenie dotyczące wskaźników — mogą one zawierać wyłącznie adresy prawidłowo utworzonych obiektów właściwego typu.
Jarosław Deminet
Przeglądaj encyklopedię
Przeglądaj tabele i zestawienia
Przeglądaj ilustracje i multimedia