Preprocesor: Porovnání verzí

Z Wikipedie, otevřené encyklopedie
Smazaný obsah Přidaný obsah
Doplnění textu převážně z anglické verze
Doplnění některých informací. Správné nastavení odkazů.
Řádek 17: Řádek 17:
Avšak takovýto 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 takovýto přístup pomalý, neboť je nutné před každou kompilací připojovat hlavičkové soubory, ikdyž se v nich nic nezměnilo.
Avšak takovýto 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 takovýto přístup pomalý, neboť je nutné před každou kompilací připojovat hlavičkové soubory, ikdyž se v nich nic nezměnilo.


Od roku 1970, bylo vymyšleno mnoho alternativ hlavičkových souborů používaných v jazyce C/C++. Tyto alternativy jsou mnohdy efektivnější, rychlejší a použití je přehlednější. Vybrané implementace zdílených souborů: [[Java (programming language)|Java]] a [[Common Lisp]] používají balíčky, [[Pascal (programming language)|Pascal]] má unity, [[Modula]], [[OCaml]], [[Haskell (programming language)|Haskell]] a [[Python (programming language)|Python]] mají moduly a C# podobně jako Java využívá importy balíčků.
Od roku 1970, bylo vymyšleno mnoho alternativ hlavičkových souborů používaných v jazyce 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#]] podobně jako Java využívá importy balíčků.


====Makra====
====Makra====
Řádek 64: Řádek 64:


==Syntaktické preprocesory==
==Syntaktické preprocesory==
Syntaktické preprocesory byly poprvé představeny v jazyce [[Lisp programming language|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 programming language|Lisp]] a [[OCaml]]. Ostatní jazyky mají tyto pravidla definovaná v jiných jazycích jako například [[XSLT]] preprocesor pro [[XML]] nebo statické [[CD]].
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 definovaná v jiných jazycích jako například [[XSLT]] preprocesor pro [[XML]] nebo statické [[CD]].


Syntaktické preprocesory jsou typicky použity ke custimizaci jazyka, doplnění nových primitiv, atd. Takto je možné dosáhnout všeobecně použitelného jazyka.
Syntaktické preprocesory jsou typicky použity ke custimizaci jazyka, doplnění nových primitiv, atd. Takto je možné dosáhnout všeobecně použitelného jazyka.


===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 syntaxemy při zachování stejné funkčnosti a záleží hlavně na subjektivním posouzení programátora.
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átora.


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


===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 takovýchto 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 tohoto typu, kdy se k využívá ke složitému iterování v cyklu minijazyk založený na jazyce [[Algol]].
===Extending a language===
The best examples of language extension through macros are found in the [[Lisp programming language|Lisp]] family of languages. While the languages, by themselves, are simple dynamically-typed functional cores, the standard distributions of [[Scheme (programming language)|Scheme]] or [[Common Lisp]] permit imperative or object-oriented programming, as well as static typing. Almost all of these features are implemented by syntactic preprocessing, although it bears noting that the "macro expansion" phase of compilation is handled by the compiler in Lisp. This can still be considered a form of preprocessing, since it takes place before other phases of compilation.


==Všeobecně použitelné preprocesory==
Similarly, statically-checked, type-safe [[regular expressions]] or [[code generation]] may be added to the syntax and semantics of [[OCaml]] through macros, as well as micro-threads (also known as [[coroutines]] or [[fiber (computer science)|fibers]]), [[Monads in functional programming|monads]] or transparent XML manipulation.
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ýchto případech je možné preprocesor "programovat" vlastními pravidly pro každý konkrétní jazyk.

===Specializing a language===
One of the unusual features of the [[Lisp programming language|Lisp]] family of languages is the possibility of using macros to create an internal
[[Domain-specific programming language|Domain-Specific Programming Language]]. Typically, in a large [[Lisp programming language|Lisp]]-based project, a module may be written in a variety of such minilanguages, one perhaps using a [[SQL]]-based dialect of [[Lisp programming language|Lisp]], another written in a dialect specialized for GUIs or pretty-printing, etc. [[Common Lisp]]'s standard library contains an example of this level of syntactic abstraction in the form of the LOOP macro, which implements an Algol-like minilanguage to describe complex iteration, while still enabling the use of standard Lisp operators.

The [[MetaOCaml]] preprocessor/language provides similar features for external [[Domain-specific programming language|Domain-Specific Programming Languages]]. This preprocessor takes the description of the semantics of a language (i.e. an interpreter) and, by combining compile-time interpretation and code generation, turns that definition into a compiler to the [[OCaml]] programming language -- and from that language, either to bytecode or to native code.`

==General purpose preprocessor==
Most preprocessors are specific to a particular data processing task (e.g., [[compilers|compiling]] the [[C (programming language)|C]] language). A preprocessor may be promoted as being ''general purpose'', meaning that it is not aimed at a specific usage or programming language, and is intended to be used for a wide variety of text processing tasks.
-->


===Externí zdroje===
===Externí zdroje===

Verze z 30. 4. 2009, 08:50

Preprocesor je počítačový program, který zpracovává svá vstupní data tak, aby výstup mohl dále zpracovávat jiný program. Častým příkladem, kdy se používá preprocesor, je předzpracování zdrojového kódu před dalším krokem, kterým je kompilace. Druh a míra předzpracování závisí primárně na požadavcích kompilátoru. Většina preprocesorů je relativně jednoduchá, zvládá nahrazování textu a jednoduchá makra. Malé procento preprocesorů disponuje silnými prostředky na zpracování programovacího jazyka. V takových případech není zpravidla nutné používat složité kompilátory.

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 pouze jako s 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 pouze v umístění, kde bude preprocesor zadaný soubor hledat. "..." značí lokalní 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.

Avšak takovýto 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 takovýto přístup pomalý, neboť je nutné před každou kompilací připojovat hlavičkové soubory, ikdyž se v nich nic nezměnilo.

Od roku 1970, bylo vymyšleno mnoho alternativ hlavičkových souborů používaných v jazyce 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# podobně jako Java využívá importy balíčků.

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.

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 debugingu, 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 i 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á kompilace

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í a podobně. Takto je možné do jednoho zdrojového kódu napsat program kompilovatelný na více platforem, či různé jazykové mutace, ...

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

#ifndef FOO_H
#define FOO_H
...(header file code)...
#endif

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

Podmínky preprocesuru 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á ale za následek pomalejší běh programu, neboť tato 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 definovaná v jiných jazycích jako například XSLT preprocesor pro XML nebo statické CD.

Syntaktické preprocesory jsou typicky použity ke custimizaci jazyka, doplnění nových primitiv, atd. Takto je možné dosáhnout všeobecně použitelného jazyka.

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átora.

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 takovýchto 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 tohoto typu, kdy se k využívá ke složitému iterování v cyklu minijazyk založený na jazyce Algol.

Všeobecně použitelné 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ýchto případech je možné preprocesor "programovat" vlastními pravidly pro každý konkrétní jazyk.

Externí zdroje

Související články