Język programowania – zbiór zasad określających, kiedy ciąg symboli tworzyprogram komputerowy oraz jakie obliczenia opisuje[1]. Teorią języków programowania winformatyce zajmuje się teoriajęzyków formalnych.
Podobnie jakjęzyki naturalne, język programowania składa się ze zbiorów regułsyntaktycznych orazsemantyki, które opisują, jak należy budować poprawne wyrażenia oraz jakkomputer ma je rozumieć. Wiele języków programowania posiada pisemną specyfikację swojej składni oraz semantyki, lecz inne zdefiniowane są jedynie przez oficjalneimplementacje.
Język programowania pozwala na precyzyjny zapisalgorytmów oraz innych zadań, jakie komputer ma wykonać. W niektórych pracach pojęciejęzyka programowania jest ograniczane wyłącznie do tych języków, w których można zapisać wszystkie istniejące algorytmy – od strony matematycznej oznacza to, że język musi być przynajmniejkompletny w sensie Turinga[2], jednak można się także spotkać z wykorzystaniem tego pojęcia na określenie również bardziej ograniczonych języków.
przeznaczenie: języki naturalne służą do komunikacji między ludźmi, natomiast języki programowania umożliwiają wydawanie poleceń maszynom. Niektóre z języków są wykorzystywane również do kontrolowania jednego urządzenia przez inne. Przykładowo, program wykonywany na komputerze może wygenerować kodPostScript do sterowania pracą drukarki bądź wyświetlacza.
moc:teoria obliczeń klasyfikuje języki według rodzajów obliczeń, które można za ich pomocą zrealizować (hierarchia Chomskiego). We wszystkich językach zupełnych w sensie Turinga da sięzaimplementować ten sam zbiór algorytmów. Przykładem często stosowanego języka niezupełnego jestSQL służący do komunikacji zbazą danych.
Memetyczna ewolucja niektórych języków programowania według deklaracji autorów lub oficjalnych specyfikacji
Obecnie na świecie istnieją tysiące języków programowania i każdego roku powstają nowe. Od języków naturalnych odróżniają się wysoką precyzją oraz jednoznacznością. Człowiek podczas komunikacji między sobą stale popełnia niewielkie błędy lub pozostawia niedomówienia wiedząc, że drugi rozmówca najczęściej go zrozumie. Maszyny wykonują zadania dokładnie, dlatego każdą czynność trzeba opisać ściśle krok po kroku, ponieważ komputer nie potrafi dociec, co programista miał na myśli.
Wiele języków zostało zaprojektowanych od zera, lecz powszechna jest praktyka rozwijania już istniejących rozwiązań oraz celowego upodabniania jednego języka do innego. Pozwala to na szybsze opanowanie nowego języka przez programistów mających już doświadczenie w tworzeniu aplikacji. Potrzeba istnienia wielu różnorodnych języków wynika z dużej liczby sytuacji, w których są one wykorzystywane – każda posiada pewne specyficzne wymagania:
wielkość programów waha się od niedużych skryptów pisanych przez amatorów do potężnych aplikacji rozwijanych przez setki programistów
doświadczenie użytkowników waha się od nowicjuszy lub programistów okazjonalnych wymagających przede wszystkim prostoty, do ekspertów potrafiących zrobić użytek z oferowanych możliwości
tworzone programy muszą spełniać określone wymagania dotyczące szybkości,skalowalności oraz wielkości
istniejące języki mogą być zbyt rozbudowane do pewnych zadań
programy mogą nie zmieniać się z biegiem lat lub być poddawane stałym modyfikacjom
programiści mają różne gusta – każdy z nich ma swój ulubiony język, w którym pisze mu się najwygodniej.
Z tych powodów nie powiodły się do dziś próby stworzenia języka uniwersalnego.
Obecnie panuje tendencja do tworzenia języków umożliwiających rozwiązywanie problemów na wyższym poziomie abstrakcji. Pierwsze języki programowania były mocno związane z konkretnym sprzętem. Z biegiem czasu wynalezione zostały nowe techniki tworzenia oprogramowania znacznie poprawiające przenośność oraz opracowane algorytmy pozwalające automatycznie realizować zadania, którymi dotąd musiał zajmować się programista. Skraca to czas tworzenia aplikacji i zmniejsza liczbę okazji do popełnienia błędu, lecz w niektórych sytuacjach odbija się to negatywnie na wydajności (np. językJava).
Kolorowanie składni jest wykorzystywane w edytorach kodu do wizualnego różnicowania poszczególnych elementów składni, co ułatwia czytanie kodu. Ilustracja przedstawia pokolorowany kod w językuPython.
Postaćprogramu wyrażona w języku programowania określana jest jakokod źródłowy. Na język programowania składa się kilka elementów:
Aby dany ciąg znaków mógł być rozpoznany jako program napisany w danym języku, musi spełniać pewne reguły, zwane składnią. Składnia opisuje:
rodzaje dostępnych symboli
zasady, według których symbole mogą być łączone w większe struktury.
Składnia najczęściej opisywana jest w formalnym zapisie będącym połączeniemwyrażeń regularnych oraz notacjiBNF lubEBNF. Poniżej przedstawiony jest przykład prostej gramatyki wzorowanej na językuLisp:
wyrazenie::=atom| listaatom ::= liczba |symbolliczba::=[+-]?['0'-'9']+symbol::=['A'-'Z''a'-'z'].*lista::='('wyrazenie*')'
Zapis ten określa wygląd i budowę kolejnych symboli:
wyrażeniem nazwiemy atom i listę
atomem nazwiemy każdą liczbę lub symbol
liczbą nazwiemy ciąg cyfr, który może zaczynać się opcjonalnie od znaku+ lub–
symbolem nazwiemy dowolną sekwencję dużych i małych liter alfabetu łacińskiego
listą nazwiemy parę nawiasów, w której może się znaleźć zero lub więcej wyrażeń.
Przykładowe ciągi, które spełniają podane reguły składni to: „12345”, „()”, „(a b c232 (1))”.
Zauważmy, że na etapie przetwarzania składni w ogóle nie jest brane pod uwagę znaczenie poszczególnych symboli. W praktyce kod poprawny składniowo nie musi być poprawny semantycznie. Występuje tu analogia do języków naturalnych. Zdanie „Łolopy się mucioszą” jest poprawne pod względem gramatycznym, lecz nie posiada żadnego znaczenia, ponieważ zostały w nim użyte nieistniejące słowa.
Semantyka języka programowania definiuje precyzyjnie znaczenie poszczególnych symboli oraz ich funkcję w programie. Semantykę najczęściej definiuje się słownie, ponieważ większość z jej zagadnień jest trudna lub wręcz niemożliwa do ujęcia w jakikolwiek formalizm. Część błędów semantycznych można wychwycić już w momencie wstępnego przetwarzania kodu programu, np. próbę odwołania się do nieistniejącej funkcji, lecz inne mogą ujawnić się dopiero w trakcie wykonywania.
Każdy język operuje na jakimś zestawie danych, dlatego niezbędne jest podzielenie danych na odpowiednie typy, zdefiniowanie ich właściwości oraz operacji, jakie można na nich realizować. Większość języków posiadatypy danych do reprezentowania:
Od strony sprzętowej wszystkie te informacje wyrażane są za pomocą sekwencji zer i jedynek. Język programowania nakłada jedynie odpowiednie ograniczenia i zasady ich przetwarzania. Zjawiskokonwersji wartości jednego typu na inną nazywa się rzutowaniem.
Dla większości języków zdefiniowana jest takżebiblioteka standardowa zawierająca podstawowy zestaw funkcji pozwalających realizować wszystkie najważniejsze operacje, np.:
podstawowe typy danych oraz funkcje do zarządzania nimi
operacje na ciągach tekstowych.
Użytkownicy traktują bibliotekę standardową często jako część języka, lecz od strony twórców są to osobne twory. Przykładowo, programiści piszący w językuD mają do dyspozycji zarówno oficjalną bibliotekęPhobos, jak i alternatywny projektTango.
Aby program napisany w danym języku mógł być wykonany, niezbędne jest przetworzenie jego kodu źródłowego:
kompilacja –kod źródłowy jest tłumaczony do postacijęzyka maszynowego, czyli sekwencji elementarnych operacji gotowych do bezpośredniego przetworzenia przezprocesor komputera. Jeżeli dany język programowania podlega kompilacji, określany jest mianemkompilowanego języka programowania
interpretacja – kod źródłowy jest na bieżąco tłumaczony i wykonywany przez dodatkowy program zwanyinterpreterem. Jeżeli język podlega interpretacji, nazywany jestinterpretowanym językiem programowania.
Wykonanie polegające na kompilacji dokodu maszynowego zapewnia najwyższą wydajność programom, lecz wygenerowany kod jest ściśle powiązany z platformą sprzętową. Ponadto kompilowane języki są bardziej zbliżone do sposobu funkcjonowania sprzętu, przez co programowanie w nich jest trudniejsze. Języki interpretowane zapewniają większąprzenośność programów, które często są niezależne od platformy isystemu operacyjnego. Aby programy wyrażone w języku interpretowanym można było uruchomić na innej platformie, wystarczy napisać dla niej interpreter. Jednak taki sposób wykonywania odbija się negatywnie na wydajności. Alternatywnym rozwiązaniem jest kompilacja programów do postaci pośredniej, tzw.kodu bajtowego. Jest ona wykonywana przezwirtualne maszyny tłumaczące elementarne rozkazy kodu bajtowego narozkazy procesora.