Preprocesor

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++

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

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

  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

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

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

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

Niektó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: uses). Języki te obsługują również stałe w przeciwieństwie do języka C, który ich nie obsługuje (pojawiły się one dopiero w C++, w języku C zamiast nich stosuje się ciągi znaków zamieniane przez preprocesor, tzw. pseudostałe). Ponadto języki Pascal i Object Pascal nie obsługują makr preprocesora, jako że ich użyteczność jest niewielka. Zamiast nich stosowane są funkcje/procedury opatrzone klauzulą inline.

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 preprocesora

Jedną 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

  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, Warszawa: Wydawnictwo PLJ, 1991, ISBN 83-85190-20-1, OCLC 749775734.
  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. Global compiler directives | Free Pascal and Lazarus Wiki. wiki.lazarus.freepascal.org. [dostęp 2021-04-23]. (ang.).
  7. Local compiler directives | Free Pascal and Lazarus Wiki. wiki.lazarus.freepascal.org. [dostęp 2021-04-23]. (ang.).
  8. Delphi Compiler Directives (List) Index | Embarcadero Docwiki. docwiki.embarcadero.com/RADStudio/Sydney/en/Main_Page. [dostęp 2021-04-23]. (ang.).
  9. Dyrektywy preprocesora języka C# | Microsoft Docs. docs.microsoft.com. [dostęp 2021-04-23]. (ang.).
  10. C/Preprocesor (w: C). Wikibooks. [dostęp 2021-04-23]. (pol.).
  11. Teoria kompilacji: Preprocessing. cpp-polska.pl. [dostęp 2021-04-23]. (pol.).
  12. constexpr expressions instead of macros (w: C# preprocessor directives) | Microsoft Docs. docs.microsoft.com. [dostęp 2021-04-23]. (ang.).

Content Disclaimer

Informasi ini disarikan dari Wikipedia dan disajikan kembali untuk tujuan edukasi. Konten tersedia di bawah lisensi CC BY-SA 3.0. Kami tidak bertanggung jawab atas ketidakakuratan data yang bersumber dari kontribusi publik tersebut.

  1. The information displayed on this website is sourced in part or in whole from Wikipedia and has been adapted for the purpose of restating it. We strive to provide accurate and relevant information, however:
  2. There is no guarantee of absolute accuracy. Wikipedia is an open, collaborative project that can be edited by anyone, so information is subject to change.
  3. It is not intended to constitute professional advice. The content displayed is for informational and educational purposes only. For important decisions (e.g., medical, legal, or financial), please consult a professional.
  4. Content copyright. Wikipedia is licensed under the Creative Commons Attribution-ShareAlike License (CC BY-SA). This means that content may be reused with appropriate attribution and shared under a similar license.
  5. Responsible use. Any risk arising from the use of information from this website is entirely the responsibility of the user.
Kembali kehalaman sebelumnya