Preprocesor

Z Wikipedii, wolnej encyklopedii
Skocz do: nawigacja, szukaj

Preprocesorprogram 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++[edytuj | edytuj kod]

Zobacz podręcznik na Wikibooks: CPreprocesor

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żą:

  • #include … - dyrektywa włączająca tekst innego pliku źródłowego w miejscu jej wystąpienia w pliku podlegającym aktualnie przetwarzaniu, przy czym możliwe jest zagłębione występowanie dyrektywy include,
  • #define … - definiuje stałe i makroinstrukcje (pseudofunkcje)
  • #undef … - usuwa definicje stałej lub makra
  • #if … - dyrektywy kompilacji warunkowej
  • #elif … - działa podobnie jak else if w języku C
  • #endif … - oznacza koniec bloku kompilacji warunkowej
  • #ifdef … - znaczy to samo co #if defined(…)
  • #ifndef … - znaczy to samo co #if !defined(…)
  • i inne.

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 nazwa.h obejmie się instrukcjami:

#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 #pragma, jej ewentualna obsługa jest rozszerzeniem wprowadzonym przez dany kompilator i nie jest przenośna pomiędzy różnymi narzędziami.

Preprocesor języka Clipper[edytuj | edytuj kod]

W 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ładania 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:

  1. #define
  2. #translate
  3. #command

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 Pike[edytuj | edytuj kod]

Ró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/1[edytuj | edytuj kod]

Najbardziej 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:

  •  %DECLARE – deklaracje zmiennych preprocesora,
  •  %vv=ee – przypisania,
  •  %GOTO – skoku,
  •  %IF – warunkowa,
  •  %DO - grupująca
  •  %DO vv=ee TO … BY … - pętli,
  •  %PROCEDURE - procedury
  • i inne,

oraz specyficzne dla preprocesora, jak

  •  %INCLUDE – włączająca,
  • i inne.

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 asemblera[edytuj | edytuj kod]

W 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 kompilatora[edytuj | edytuj kod]

Niektóre implementacje języków programowania (np. 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 znacznie bardziej uboga i o znikomych możliwościach w porównaniu z preprocesorem[6].

Zobacz też[edytuj | edytuj kod]

Przypisy

  1. Jan Bielecki, Od C do C++, programowanie obiektowe w języku C, Wydawnictwa Naukowo-Techniczne, Warszawa 1990, ISBN 83-204-1332-X
  2. Jan Bielecki, Turbo C z grafiką na IBM PC, Wydawnictwa Naukowo-Techniczne, Warszawa 1990, Seria: Mikrokomputery, ISBN 83-204-1101-7
  3. Wojciech Rogowski, Arkadiusz Serodziński, Clipper 5.0, Wydawnictwo PLJ, Warszawa 1991, ISBN 83-85190-20-1
  4. Jan Bielecki, Rozszerzony PL/I i JCL w systemie OS/RIAD, Państwowe Wydawnictwo Naukowe, Warszawa 1986, Seria: Biblioteka Informatyki, ISBN 83-01-06146-4
  5. Eugeniusz Wróbel: Asembler 8086/88. Wyd. 2.. Warszawa: Wydawnictwa Naukowo-Techniczne, 1992, seria: Mikrokomputery. ISBN 83-204-1504-7.
  6. Andrzej Marciniak, Borland Pascal 7.0, Wyd. Nakom, Poznań 1994 r., seria: Biblioteka Użytkownika Mikrokomputerów, ISBN 83-85060-53-7, ISSN 0867-6011