PreprocesorPreprocesor – program komputerowy, którego zadaniem jest przetworzenie kodu źródłowego, w sposób określony przez programistę za pomocą dyrektyw preprocesora, na kod wyjściowy – tak przetworzony kod źródłowy poddawany jest następnie analizie składniowej, kompilacji, a w końcu konsolidacji. Preprocesor jest najczęściej zintegrowany z kompilatorem języka programowania. Preprocesor języków C i C++Najbardziej znane języki, które wyposażone są w preprocesor „wbudowany w język”, to C i C++. Dyrektywy preprocesora mogą występować w ogólności w dowolnym miejscu programu, a rozróżnienie ich od tekstu kodu źródłowego w językach C i C++ dokonywane jest poprzez poprzedzenie dyrektywy znakiem hash – „#”[1][2]. Do najważniejszych dyrektyw należą:
Dyrektywy preprocesora C/C++ wykorzystuje się często do zabezpieczenia plików nagłówkowych przed wielokrotnym dołączaniem do tego samego projektu. Jeżeli treść pliku nagłówkowego #ifndef _NAZWA_H_ /* (1) */ #define _NAZWA_H_ /* (2) */ /* ... treść właściwa ...(to co chcesz definiować np. struktury) */ #endif /* (3) */ to przy pierwszej próbie dołączenia pliku, kompilator najpierw sprawdzi, czy zdefiniowano stałą _NAZWA_H_ (może ona mieć dowolną nazwę, ten sposób jest jednak dobrym zwyczajem promowanym przez programistów) (1) – jeżeli nie, zostanie ona zdefiniowana (2) i do programu zostanie dołączona treść między (2) i (3), oznaczający koniec części dodawanej tylko przy spełnieniu warunku (1). Niektóre kompilatory obsługują także następującą konstrukcję: #pragma once Zapobiega ona ponownemu załączeniu treści całego pliku, w którym została użyta. Metoda ta jednak nie ma oparcia w oficjalnym standardzie. Podobnie, jak wszystkie użycia dyrektywy Preprocesor języka ClipperW wersji 5.x języka Clipper został zaimplementowany preprocesor wzorowany na preprocesorze języka C[3]. Znalazły się więc w nim takie dyrektywy jak: #define, #ifdef, ifndef, #include, #undef. Ale preprocesor ten zawiera również dwie dodatkowe dyrektywy: #command i #translate. Ich składnia jest następująca: #command <szablon rozpoznawczy> ⇒ <szablon wynikowy> i identycznie dla dyrektywy translate. Dyrektywy te umożliwiają definiowanie rozkazów i pseudorozkazów. Analizowany kod źródłowy jest sprawdzany pod kątem wystąpienia zdefiniowanych szablonów w następującej kolejności:
Po znalezieniu wzorca następuje podstawienie w jego miejsce tekstu utworzonego według szablonu wynikowego i ponowne sprawdzenie, czy nie występuje kolejny szablon rozpoznawczy w utworzonym kodzie. Preprocesor języka PikeRównież preprocesor języka Pike wzorowany jest na preprocesorze języka C. W zasadzie składnia dyrektyw preprocesora tego języka jest identyczna jak w C. Zasadnicze różnice to: brak plików nagłówkowych dołączanych dyrektywą include (choć sama dyrektywa istnieje i służy do dołączania plików z kodem źródłowym), oraz dodatkowe dyrektywy jak np. string dołączająca plik jako wartość tekstową. Preprocesor języka PL/1Najbardziej rozbudowanym zestawem instrukcji dysponuje preprocesor języka PL/1 (implementacje IBM w systemie OS)[4]. W tym przypadku znakiem wyróżniającym dyrektywę preprocesora jest znak procentu ‘%’, a semantyka poleceń preprocesora jest niemal zgodna z semantyką analogicznych instrukcji języka PL/1. Lista instrukcji tego preprocesora obejmuje większość analogicznych instrukcji samego języka, w tym takich jak:
oraz specyficzne dla preprocesora, jak
Choć preprocesor tego języka, podobnie jak w C, był wbudowany w kompilator, dzięki pewnym sztuczkom mógł być stosowany jako preprocesor dla innych języków programowania, np. FORTRAN. Preprocesor asembleraW asemblerach rolę analogiczną do preprocesora pełnią makroinstrukcje, dyrektywy i pseudoinstrukcje. Powodują one wykonanie operacji na tekście kodu źródłowego w trakcie translacji wykonywanej przez program asemblera[5]. Niektóre asemblery, np. makroasembler IBM, w ramach pakietu oprogramowania dostarczają programy ułatwiające pisanie kodów źródłowych w asemblerze. Przykładem jest program SALUT wchodzący w skład ww. pakietu, który przekształcał instrukcje strukturalne na instrukcje asemblera. Działał on więc na zasadzie preprocesora lecz nie wbudowanego w program główny, tylko jako osobny program. Przed uruchomieniem procesu asemblacji należało uruchomić program SALUT, i dopiero plik wynikowy tego programu poddać procesowi asemblowania. W programie tym instrukcje strukturalne zapisane są w pliku źródłowym i poprzedzone znakiem dolara '$'. Program dostarcza takich konstrukcji programowania strukturalnego jak instrukcja warunkowa $IF ... $ELSE ... $ENDIF, instrukcja pętli $DO w różnych wariantach, czy instrukcja przeszukiwania $SEARCH. Preprocesor a dyrektywy kompilatoraNiektóre implementacje języków programowania (np. Pascal, Object Pascal), choć nie posiadają wbudowanego preprocesora, to udostępniają dyrektywy kompilatora, które są rozpatrywane w trakcie kompilacji, a nie jak w przypadku preprocesora przed jej wykonaniem. Zwykle lista takich dyrektyw jest dużo mniejsza w porównaniu z listą dyrektyw preprocesora.[6][7][8]. Wynika to z budowy języków Pascal i Object Pascal, które nie używają plików nagłówkowych, natomiast instrukcje dołączania plików bibliotecznych są częścią składni języka (słowo kluczowe: W języku C# istnieje preprocesor i jest on częścią kompilatora[9]. Jednak w odróżnieniu od preprocesora języków C i C++ jest on podobny w działaniu do dyrektyw kompilatora używanych w języku Object Pascal. Oczywiście lista dyrektyw preprocesora języka C# różni się od listy dyrektyw kompilatora języka Object Pascal. Najważniejszą (ale nie jedyną) rolą dyrektyw kompilatorów języków Pascal i Object Pascal oraz dyrektyw preprocesora języka C# jest kompilacja warunkowa. Wady preprocesoraJedną z wad preprocesora jest to, że makra i pseudostałe mogą powodować problemy w trakcie kompilacji plików źródłowych w języku C/C++, ponieważ nie są sprawdzane przez kompilator, który otrzymuje kod źródłowy już po zamianie dokonanej przez preprocesor[10][11]. Także podczas debugowania programu makra mogą sprawiać problemy - kompilator nie mając o nich wiedzy, nie generuje dla nich symboli debugowania. Z tego m.in. powodu makra nie są stosowane w nowszych językach programowania takich jak: C#, Java czy Object Pascal. Natomiast w języku C++ zalecane jest używanie szablonów oraz konstrukcji językowych wprowadzonych wraz z nowszymi standardami tego języka[12]. Zobacz teżPrzypisy
|