Preprocesor: Porovnání verzí

Z Wikipedie, otevřené encyklopedie
Smazaný obsah Přidaný obsah
m Oprava překlepů
úprava výrazů
Řádek 17: Řádek 17:
Na ukázku, připojení souborů <code><[[math.h]]></code> a <code><[[stdio.h]]></code> ze standardní C/C++ knihovny umožňuje využívat matematické a I/O operace.
Na ukázku, připojení souborů <code><[[math.h]]></code> a <code><[[stdio.h]]></code> ze standardní C/C++ knihovny umožňuje využívat matematické a I/O operace.


Zmíněný lexikální preprocesor není schopný ohlídat vícenásobné připojení jednoho hlavičkového souboru nebo dokonce cyklické připojování hlavičkových souborů. Mimo jiné je tento přístup pomalý, neboť je nutné před každou kompilací připojovat hlavičkové soubory i když se v nich nic nezměnilo.
Zmíněný lexikální preprocesor není schopný sám ohlídat vícenásobné připojení jednoho hlavičkového souboru nebo dokonce cyklické připojování hlavičkových souborů. Mnohonásobné připojení musí v tomto případě ohlídat programátor za pomocí podmíněného překladu. Mimo jiné je tento přístup pomalý, neboť je nutné před každou kompilací připojovat hlavičkové soubory i když se v nich nic nezměnilo.


Od roku 1970, bylo vymyšleno mnoho alternativ hlavičkových souborů z jazyka C/C++. Tyto alternativy jsou mnohdy efektivnější, rychlejší a použití je přehlednější. Vybrané implementace zdílených souborů: [[Java_(programovací_jazyk)|Java]] a [[Common Lisp]] používají balíčky, [[Pascal_(programovací_jazyk)|Pascal]] má unity, [[Modula-2|Modula]], [[OCaml]], [[Haskell_(programovací_jazyk)|Haskell]] a [[Python]] mají moduly a [[C_Sharp|C#]] využívá importy jmených prostorů z připojených knihoven.
Od roku 1970, bylo vymyšleno mnoho alternativ hlavičkových souborů z jazyka C/C++. Tyto alternativy jsou mnohdy efektivnější, rychlejší a použití je přehlednější. Vybrané implementace zdílených souborů: [[Java_(programovací_jazyk)|Java]] a [[Common Lisp]] používají balíčky, [[Pascal_(programovací_jazyk)|Pascal]] má unity, [[Modula-2|Modula]], [[OCaml]], [[Haskell_(programovací_jazyk)|Haskell]] a [[Python]] mají moduly a [[C_Sharp|C#]] využívá importy jmených prostorů z připojených knihoven.


==== Makra ====
==== Makra ====
Makra jsou primárně používána v jazyce C. Umožňují vkládat drobné části kódu na mnoho míst, čímž se šetří velikost zdrojového kódu a přehlednost. V makrech je možné používat i zástupné znaky (něco jako parametry funkcí). Makra jsou zpracovávána preprocesorem, proto je tento kód kompilovám vícekrát, ikdyž je zapsán pouze jednou. Makra nemají vliv na rychlost překladu.
Makra jsou primárně používána v jazyce C. Umožňují vkládat drobné části kódu na mnoho míst, čímž se šetří velikost zdrojového kódu a přehlednost. V makrech je možné používat i zástupné znaky (něco jako parametry funkcí). Makra jsou zpracovávána preprocesorem, proto je tento kód kompilovám vícekrát, i když je zapsán pouze jednou. Makra nemají vliv na rychlost překladu.


Na ukázku:
Na ukázku:
<source lang="c">#define max(a,b) a > b ? a : b</source>
<source lang="c">#define max(a,b) a > b ? a : b</source>
definuje makro <tt>max</tt> se dvěma parametry <tt>a</tt> a <tt>b</tt>. Takovéto makro může být "voláno" jako funkce (stejnou syntaxí).
definuje makro <tt>max</tt> se dvěma parametry <tt>a</tt> a <tt>b</tt>. Takovéto makro může být „voláno“ jako funkce (stejnou syntaxí).
Využití maker je v C/C++ velmi významné hlavně při ladění, kdy je možné rychle předefinovat makro a měnit tak kód na mnoha místech zaroveň.
Využití maker je v C/C++ velmi významné hlavně při ladění, kdy je možné rychle předefinovat makro a měnit tak kód na mnoha místech zaroveň.


To, že se makra nechovají stejně jako funkce si ukážeme na následujícím příkladu, kde <tt>f</tt> a <tt>g</tt> jsou dvě funkce vracející Integer. Zavolání <source lang="c">z = max(f(), g());</source>
To, že se makra nechovají stejně jako funkce si ukážeme na následujícím příkladu, kde <tt>f</tt> a <tt>g</tt> jsou dvě funkce vracející integer. Zavolání <source lang="c">z = max(f(), g());</source>
nevyčíslí <tt>f()</tt>jednou a <tt>g()</tt> taky jednou jak by se dalo čekat u funkce, nýbrž jedna z fukcí <tt>f</tt> nebo <tt>g</tt> bude vyčíslena dvakrát (v závislosti na tom, která vrací větší číslo). Toto chování může mít za následek katastrofální chování v případě, že záleží na počtu volání <tt>f</tt> nebo <tt>g</tt>.
nevyčíslí <tt>f()</tt>jednou a <tt>g()</tt> taky jednou jak by se dalo čekat u funkce, nýbrž jedna z fukcí <tt>f</tt> nebo <tt>g</tt> bude vyčíslena dvakrát (v závislosti na tom, která vrací větší číslo). Toto chování může mít za následek katastrofální chování v případě, že záleží na počtu volání <tt>f</tt> nebo <tt>g</tt>.


Řádek 35: Řádek 35:


==== Podmíněný překlad ====
==== Podmíněný překlad ====
Preprocesor jazyka C/C++ podporuje podmíněnou kompilaci. To umožňuje mít více verzí stejného kódu, který se například liší ve výpisu logovacích informací nebo je platformě závislý. Takto je možné do jednoho zdrojového kódu napsat program kompilovatelný na více platforem, či různé jazykové mutace, ...
Preprocesor jazyka C/C++ podporuje podmíněnou kompilaci. To umožňuje mít více verzí stejného kódu, který se například liší ve výpisu logovacích informací nebo je platformě závislý. Takto je možné do jednoho zdrojového kódu napsat program kompilovatelný pro více platforem, či různé jazykové mutace, ...


Nejčastěji se používá následující konstrukce:
Nejčastěji se používá následující konstrukce:
Řádek 71: Řádek 71:


=== Přizpůsobení syntaxe ===
=== Přizpůsobení syntaxe ===
Dobrý příklad se nachází na adrese http://caml.inria.fr/pub/docs/manual-camlp4/manual007.html. Program může být zapsán dvěma různými syntaxemi při zachování stejné funkčnosti a záleží hlavně na subjektivním posouzení programátorem.
Pěkný příklad naleznete na internetové adrese http://caml.inria.fr/pub/docs/manual-camlp4/manual007.html. Program může být zapsán dvěma různými syntaxemi při zachování stejné funkčnosti a záleží hlavně na subjektivním posouzení programátorem.


Velký počet programů napsaných v [[OCaml]] přispůsobuje syntaxi doplněním nových operátorů. Definici vlastních operátorů podporuje i jazyk C++.
Velký počet programů napsaných v [[OCaml]] přispůsobuje syntaxi doplněním nových operátorů. Definici vlastních operátorů podporuje i jazyk C++.
Řádek 78: Řádek 78:
Jedna z neobvyklých vlastností jazyka [[Lisp]] je možnost použít makra k vytvoření vlastního minijazyka uvnitř projektu. Typicky ve velkých projektech bývají některé moduly napsány v minijazycích. Modul pro přístup k [[SQL]] databázi využívá dialekt se základem právě v SQL příkazech. Jiné moduly mohou využívat jiné minijazyky, například modul pro práci s [[GUI]], tiskem, atd. Standardní knihovna [[Common Lisp]] obsahuje příklad, kdy se k využívá ke složitému iterování v cyklu minijazyk založený na jazyce [[Algol]].
Jedna z neobvyklých vlastností jazyka [[Lisp]] je možnost použít makra k vytvoření vlastního minijazyka uvnitř projektu. Typicky ve velkých projektech bývají některé moduly napsány v minijazycích. Modul pro přístup k [[SQL]] databázi využívá dialekt se základem právě v SQL příkazech. Jiné moduly mohou využívat jiné minijazyky, například modul pro práci s [[GUI]], tiskem, atd. Standardní knihovna [[Common Lisp]] obsahuje příklad, kdy se k využívá ke složitému iterování v cyklu minijazyk založený na jazyce [[Algol]].


== Všeobecně použitelné preprocesory ==
== Univerzální preprocesory ==
Drtivá většina preprocesorů je zaměřena na jeden konkrétní jazyk, resp. spolupracuje s konkrétním kompilátorem. Ale existují také tzv. ''všeobecně použitelné'' preprocesory, které nejsou svázány s konkrétním jazykem. V takových případech je možné preprocesor "programovat" vlastními pravidly pro konkrétní programovací jazyk.
Drtivá většina preprocesorů je zaměřena na jeden konkrétní jazyk, resp. spolupracuje s konkrétním kompilátorem. Ale existují také tzv. ''univerzální'' preprocesory, které nejsou svázány s konkrétním jazykem. V takových případech je možné preprocesor "programovat" vlastními pravidly pro konkrétní programovací jazyk.


== Související články ==
== Související články ==

Verze z 27. 5. 2009, 10:02

Preprocesor je počítačový program, který zpracovává vstupní data tak, aby výstup mohl dále zpracovávat jiný program. Preprocesor je často používán pro předzpracování zdrojového kódu před vlastní kompilací. Druh a míra předzpracování závisí zejména na schopnostech preprocesoru. Většina preprocesorů je relativně jednoduchá, zvládá nahrazování textu a jednoduchá makra. Existují též sofistikované preprocesory, případně plně rozvinuté programovací jazyky.

Některé programovací jazyky (například jazyk C) vždy používají preprocesor ve fázi, která se nazývá preprocesing.

Lexikální preprocesory

Lexikální preprocesory jsou nejnižším stupněm preprocesorů. Pro svoji činnost využívají pouze lexikální analýzu, tzn. že, pracují se zdrojovým kódem jako s obyčejným textem. Ve vstupním textu provádějí úpravy typu: najít a nahradit, použít makro, připojit externí soubor, atd.

Preprocesing v jazyce C/C++

Nejznámějším a hojně využívaným preprocesorem je preprocesor jazyka C/C++. Tento preprocesor funguje na výše zmíněném principu.

Připojení externích souborů

Preprocesoru v jazyce C/C++ se nejčastěji používá pro připojení hlavičkových souborů.

#include "..."

nebo

#include <...>

Rozdíl mezi těmito příkazy je v umístění, kde bude preprocesor zadaný soubor hledat. "..." značí lokální hlavičkový soubor v projektu. <...> znamená soubor umístěný v některém společném úložišti hlavičkových souborů pro všechny projekty. Na ukázku, připojení souborů <math.h> a <stdio.h> ze standardní C/C++ knihovny umožňuje využívat matematické a I/O operace.

Zmíněný lexikální preprocesor není schopný sám ohlídat vícenásobné připojení jednoho hlavičkového souboru nebo dokonce cyklické připojování hlavičkových souborů. Mnohonásobné připojení musí v tomto případě ohlídat programátor za pomocí podmíněného překladu. Mimo jiné je tento přístup pomalý, neboť je nutné před každou kompilací připojovat hlavičkové soubory i když se v nich nic nezměnilo.

Od roku 1970, bylo vymyšleno mnoho alternativ hlavičkových souborů z jazyka C/C++. Tyto alternativy jsou mnohdy efektivnější, rychlejší a použití je přehlednější. Vybrané implementace zdílených souborů: Java a Common Lisp používají balíčky, Pascal má unity, Modula, OCaml, Haskell a Python mají moduly a C# využívá importy jmených prostorů z připojených knihoven.

Makra

Makra jsou primárně používána v jazyce C. Umožňují vkládat drobné části kódu na mnoho míst, čímž se šetří velikost zdrojového kódu a přehlednost. V makrech je možné používat i zástupné znaky (něco jako parametry funkcí). Makra jsou zpracovávána preprocesorem, proto je tento kód kompilovám vícekrát, i když je zapsán pouze jednou. Makra nemají vliv na rychlost překladu.

Na ukázku:

#define max(a,b) a > b ? a : b

definuje makro max se dvěma parametry a a b. Takovéto makro může být „voláno“ jako funkce (stejnou syntaxí). Využití maker je v C/C++ velmi významné hlavně při ladění, kdy je možné rychle předefinovat makro a měnit tak kód na mnoha místech zaroveň.

To, že se makra nechovají stejně jako funkce si ukážeme na následujícím příkladu, kde f a g jsou dvě funkce vracející integer. Zavolání

z = max(f(), g());

nevyčíslí f()jednou a g() taky jednou jak by se dalo čekat u funkce, nýbrž jedna z fukcí f nebo g bude vyčíslena dvakrát (v závislosti na tom, která vrací větší číslo). Toto chování může mít za následek katastrofální chování v případě, že záleží na počtu volání f nebo g.

Většina moderních programovacích jazyků již nevyužívá tyto možnosti maker, právě z těchto nejednoznačných důvodů a snadného zaměnění za funkce. Z toho důvodu existují v dnešních jazycích pouze funkce nebo metody.

Podmíněný překlad

Preprocesor jazyka C/C++ podporuje podmíněnou kompilaci. To umožňuje mít více verzí stejného kódu, který se například liší ve výpisu logovacích informací nebo je platformě závislý. Takto je možné do jednoho zdrojového kódu napsat program kompilovatelný pro více platforem, či různé jazykové mutace, ...

Nejčastěji se používá následující konstrukce:

#ifndef SOUBOR_H
#define SOUBOR_H
...(zdrojový kód hlavičkového souboru)...
#endif

Programátor tím zabraňuje mnohonásobnému připojení hlavičkového souboru. Tímto problémem jsme se zabývali výše.

Podmíněný překlad je možné využít v kompexnějších případech jako je tento:

 #ifdef DEBUG
 ...
 #else
 ...
 #endif

nebo

 #if DEBUG
 ...
 #else
 ...
 #endif

Naneštěstí většina moderních programovacích jazyků odstraňuje tuto schopnost a uchyluje se k tradičnímu použití if...then...else.... To má za následek pomalejší běh programu, neboť podmínka musí být vyhodnocena za běhu programu a nikoliv pouze při kompilaci.

Syntaktické preprocesory

Syntaktické preprocesory byly poprvé představeny v jazyce Lisp. Jejich úkolem je převést syntaktický strom na sérii uživatelem definovaných přepisovacích pravidel. V několika jazycích jsou pravidla napsána ve stejném jazyce jako program (compile-time reflection), případ právě jazyka Lisp a OCaml. Ostatní jazyky mají tyto pravidla definována v jiných jazycích jako například XSLT preprocesor pro XML.

Syntaktické preprocesory jsou typicky použity pro individuální přizpůsobení jazyka, doplnění nových primitiv, atd. Takto je možné dosáhnout všeobecně použitelného programovacího jazyka.

Přizpůsobení syntaxe

Pěkný příklad naleznete na internetové adrese http://caml.inria.fr/pub/docs/manual-camlp4/manual007.html. Program může být zapsán dvěma různými syntaxemi při zachování stejné funkčnosti a záleží hlavně na subjektivním posouzení programátorem.

Velký počet programů napsaných v OCaml přispůsobuje syntaxi doplněním nových operátorů. Definici vlastních operátorů podporuje i jazyk C++.

Specializace jazyka

Jedna z neobvyklých vlastností jazyka Lisp je možnost použít makra k vytvoření vlastního minijazyka uvnitř projektu. Typicky ve velkých projektech bývají některé moduly napsány v minijazycích. Modul pro přístup k SQL databázi využívá dialekt se základem právě v SQL příkazech. Jiné moduly mohou využívat jiné minijazyky, například modul pro práci s GUI, tiskem, atd. Standardní knihovna Common Lisp obsahuje příklad, kdy se k využívá ke složitému iterování v cyklu minijazyk založený na jazyce Algol.

Univerzální preprocesory

Drtivá většina preprocesorů je zaměřena na jeden konkrétní jazyk, resp. spolupracuje s konkrétním kompilátorem. Ale existují také tzv. univerzální preprocesory, které nejsou svázány s konkrétním jazykem. V takových případech je možné preprocesor "programovat" vlastními pravidly pro konkrétní programovací jazyk.

Související články

Externí odkazy