Kompilátor

Aktuální verze stránky ještě nebyla zkontrolována zkušenými přispěvateli a může se výrazně lišit od verze recenzované 6. prosince 2021; kontroly vyžadují 6 úprav .

Kompilátor je program, který překládá text napsaný v programovacím jazyce do sady strojových kódů [1] [2] [3] .

Základní funkce a terminologie

Kompilace  - sestavení programu, včetně:

  1. překlad všech programových modulů napsaných v jednom nebo více zdrojových vysokoúrovňových programovacích jazycích a/nebo assembleru do ekvivalentních programových modulů v nízkoúrovňovém jazyce blízkém strojovému kódu ( absolutní kód , objektový modul , někdy assembler ) [2 ] [3] [4] nebo přímo ve strojovém jazyce nebo jiném binárním nízkoúrovňovém příkazovém jazyce;
  2. následné sestavení programu spustitelného stroje, včetně vložení kódu všech funkcí importovaných ze statických knihoven do programu a/nebo vygenerování kódu požadavku do OS na načtení dynamických knihoven, ze kterých bude program volat funkcí.

Pokud kompilátor generuje spustitelný program strojového jazyka, pak je takový program přímo vykonáván fyzickým programovatelným strojem (např. počítačem). V ostatních případech je program spustitelného stroje spuštěn odpovídajícím virtuálním strojem .

Vstup kompilátoru je:

  1. ve fázi překladu: zdrojový kód programu, který je popisem algoritmu nebo programu v doménově specifickém programovacím jazyce ;
  2. ve fázi linkování: soubory objektových kódů programových modulů generovaných ve fázi překladu, dále soubory objektových kódů statických knihoven a data o použitých dynamických knihovnách.

Výstupem kompilátoru je ekvivalentní popis algoritmu ve strojově orientovaném jazyce (objektový kód [5] , bytecode ).

Kompilace  - sestavení strojového programu, včetně:

  1. překlad z jazyka specifického pro doménu do jazyka specifického pro stroj [3] ,
  2. propojení spustitelného strojově orientovaného programu z objektových modulů generovaných ve fázi překladu - modulů obsahujících části programového kódu na strojově orientovaném programovém kódu.

Docela často kompilátory z jazyků na vysoké úrovni provádějí pouze překlad zdrojového kódu, přičemž propojení svěří externímu linkeru, linkeru, který představuje nezávislý program nazývaný kompilátorem jako externí podprogram. V důsledku toho je kompilátor mnohými považován za druh překladatele, což je nesprávné ...

Typy překladačů

Všechny kompilátory lze také podmíněně rozdělit do dvou skupin:

Typy kompilací

Typy kompilace [2] :

Struktura kompilátoru

Proces kompilace se skládá z následujících kroků:

  1. Překlad programu - překlad všech nebo pouze upravených modulů zdrojového programu.
  2. Propojení strojově orientovaného programu.

Implementace strukturálního kompilátoru mohou být následující:

  1. Kompilátor i linker mohou být zahrnuty do kompilátoru jako spustitelné programy.
  2. Kompilátor sám provádí pouze překlad zkompilovaného programu, přičemž linkování programu provádí samostatný linker program volaný kompilátorem. Téměř všechny moderní kompilátory jsou sestaveny podle tohoto schématu.
  3. Softwarový balíček, který obsahuje překladače z různých programovacích jazyků a linkery.

Podle prvního schématu byly postaveny úplně první kompilátory - pro moderní kompilátory je takové konstrukční schéma necharakteristické.

Podle druhého schématu jsou sestaveny všechny kompilátory z jazyků na vysoké úrovni bez výjimky. Každý takový kompilátor sám provádí pouze překlad a poté volá linker jako externí podprogram, který spojuje strojově orientovaný program. Takové konstrukční schéma snadno umožňuje kompilátoru pracovat v režimu překladače z odpovídajícího programovacího jazyka. Tato okolnost často slouží jako důvod považovat kompilátor za jakýsi překladač, což je přirozeně špatně - všechny moderní kompilátory tohoto typu stále provádějí linkování, i když pomocí externího linkeru volaného kompilátorem, zatímco kompilátor sám nikdy nevolá externí linker. Stejná okolnost však umožňuje kompilátoru z jednoho programovacího jazyka ve fázi spojování zahrnout do programu napsaného v jednom programovacím jazyce funkce-podprogramy z těch, které již přeložil odpovídající kompilátor/překladač, napsané v jiném programovacím jazyce. Takže můžete vložit funkce napsané v Pascalu nebo Fortranu do programu C/C++ . Podobně a naopak lze funkce napsané v C/C++ vložit do programu Pascal nebo Fortran. To by nebylo možné bez podpory mnoha moderních kompilátorů pro generování kódu pro volání procedur (funkcí) v souladu s konvencemi jiných programovacích jazyků. Například moderní kompilátory z jazyka Pascal kromě organizace volání procedur/funkcí v samotném standardu Pascal podporují organizaci volání procedur/funkcí v souladu s konvencemi jazyka C/C++. (Například k tomu, aby procedura/funkce napsaná v Pascalu pracovala se vstupními parametry na úrovni strojového kódu v souladu s konvencemi jazyka C/C++, musí deklarační příkaz takové procedury/funkce Pascal obsahovat klíčové slovo cdecl .)


Konečně, podle třetího schématu jsou sestaveny kompilátory, což jsou celé systémy, které zahrnují překladače z různých programovacích jazyků a linkery. Jakýkoli takový kompilátor může také použít jako překladatel jakýkoli překladač schopný kompilátor z určitého jazyka na vysoké úrovni. Takový kompilátor samozřejmě dokáže přeložit program, jehož různé části zdrojového textu jsou napsány v různých programovacích jazycích. Často jsou takové kompilátory řízeny vestavěným interpretem jednoho nebo druhého příkazového jazyka. Pozoruhodným příkladem takových kompilátorů je zpřístupnění kompilátoru na všech systémech UNIX (zejména na Linuxu) .

Překlad programu jako nedílná součást kompilace zahrnuje:

  1. Lexikální analýza . V této fázi je sekvence znaků ve zdrojovém souboru převedena na sekvenci tokenů.
  2. Syntaktická (gramatická) analýza . Posloupnost tokenů se převede do stromu analýzy.
  3. Sémantická analýza . V této fázi je strom analýzy zpracován za účelem stanovení jeho sémantiky (významu) – například vazby identifikátorů na jejich deklarace, datové typy, kontroly kompatibility, typy výrazů atd. Výsledek se obvykle nazývá „mezilehlá reprezentace / kód“, a může být rozšířený strom analýzy, nový strom, abstraktní sada instrukcí nebo něco jiného vhodného pro další zpracování.
  4. Optimalizace . Jsou odstraněny nadbytečné konstrukce a kód je zjednodušen při zachování jeho významu. Optimalizace může být na různých úrovních a fázích – například přes mezikód nebo přes konečný strojový kód.
  5. Generování kódu . Ze střední reprezentace je generován kód v cílovém strojově orientovaném jazyce.

Generování kódu

Generování strojového kódu

Většina kompilátorů překládá program z nějakého vysokoúrovňového programovacího jazyka do strojového kódu , který může být přímo spuštěn fyzickým procesorem . Tento kód je zpravidla také zaměřen na spouštění v prostředí konkrétního operačního systému , protože využívá schopností, které poskytuje ( systémová volání , knihovny funkcí). Architektura (soubor softwaru a hardwaru), pro kterou je strojově orientovaný program zkompilován (sestaven), se nazývá cílový stroj .

Výsledek kompilace – spustitelný programový modul – má nejvyšší možný výkon, ale je vázán na konkrétní operační systém (rodinu nebo podrodinu OS) a procesor (rodinu procesorů) a na jiných nebude fungovat.

Každý cílový stroj ( IBM , Apple , Sun , Elbrus atd.) a každý operační systém nebo rodina operačních systémů běžících na cílovém stroji vyžaduje napsání vlastního kompilátoru. Existují také tzv. křížové kompilátory , které umožňují na jednom stroji a v prostředí jednoho OS generovat kód určený ke spuštění na jiném cílovém stroji a/nebo v prostředí jiného OS. Kromě toho mohou kompilátory optimalizovat kód pro různé modely ze stejné rodiny procesorů (podporou funkcí specifických pro daný model nebo rozšířením instrukční sady). Například kód kompilovaný pro procesory rodiny Pentium může zohledňovat vlastnosti paralelizace instrukcí a využívat jejich specifická rozšíření - MMX , SSE atd.

Některé kompilátory překládají program z vysokoúrovňového jazyka ne přímo do strojového kódu, ale do assembleru . (Příklad: PureBasic , překládání kódu BASIC do assembleru FASM .) To se provádí za účelem zjednodušení části kompilátoru pro generování kódu a zvýšení jeho přenositelnosti (úkol konečného generování kódu a jeho propojení s požadovanou cílovou platformou se přesouvá na assembler ), nebo mít možnost kontrolovat a korigovat výsledek kompilace (včetně ruční optimalizace) programátorem.

Generování bytekódu

Výsledkem práce kompilátoru může být program ve speciálně vytvořeném nízkoúrovňovém jazyce příkazů v binárním kódu prováděný virtuálním strojem . Takový jazyk se nazývá pseudokód nebo bytecode . Zpravidla se nejedná o strojový kód žádného počítače a programy na něm lze spouštět na různých architekturách, kde existuje odpovídající virtuální stroj, ale v některých případech jsou vytvořeny hardwarové platformy, které přímo spouštějí pseudokód jakéhokoli jazyka. . Například pseudokód jazyka Java se nazývá bajtový kód Java a běží v Java Virtual Machine a pro jeho přímé provádění byla vytvořena specifikace procesoru picoJava . Pro rozhraní .NET Framework se pseudokód nazývá Common Intermediate Language (CIL) a modul runtime se nazývá Common Language Runtime (CLR).

Některé implementace interpretovaných jazyků na vysoké úrovni (jako je Perl) používají bajtový kód k optimalizaci provádění: nákladné kroky analýzy a převodu programového textu na bajtový kód se provádějí po načtení, poté lze odpovídající kód znovu použít bez rekompilace.

Dynamická kompilace

Vzhledem k nutnosti interpretace běží bytekód mnohem pomaleji než strojový kód srovnatelné funkčnosti, ale je přenosnější (nezávisí na operačním systému a modelu procesoru). Pro urychlení provádění bajtkódu se používá dynamická kompilace , kdy virtuální stroj převede pseudokód do strojového kódu bezprostředně před jeho prvním spuštěním (a při opakovaném přístupu ke kódu se provede již zkompilovaná verze).

Nejoblíbenějším typem dynamické kompilace je JIT . Další variantou je inkrementální kompilace .

Kód CIL je také kompilován do cílového strojového kódu kompilátorem JIT, zatímco knihovny .NET Framework jsou předkompilovány.

Překlad bajtkódu do strojového kódu

Překlad bajtového kódu do strojového kódu speciálním překladačem bajtového kódu, jak je uvedeno výše, je integrální fází dynamické kompilace. Překlad bajtkódu je však také užitečný pro jednoduchou konverzi programu bajtového kódu na program ekvivalentního strojového jazyka. Lze jej přeložit do strojového kódu jako předkompilovaný bytekód. Ale také překlad bajtového kódu do strojového kódu může být proveden kompilátorem bajtového kódu ihned po kompilaci bajtového kódu. Téměř vždy v druhém případě je překlad bajtkódu prováděn externím překladačem volaným kompilátorem bajtového kódu.

Dekompilace

Existují programy, které řeší inverzní problém – překlad programu z nízkoúrovňového jazyka do vysokoúrovňového. Tento proces se nazývá dekompilace a takové programy se nazývají dekompilátory . Ale protože kompilace je ztrátový proces, obecně není možné přesně obnovit zdrojový kód například v C++. Programy v bajtkódech se dekompilují efektivněji – například pro Flash existuje celkem spolehlivý dekompilátor . Variantou dekompilace je rozložení strojového kódu do kódu assembleru, který se téměř vždy provádí bezpečně (v tomto případě může být složitost samo-modifikující se kód nebo kód, ve kterém skutečný kód a data nejsou odděleny). To je způsobeno skutečností, že mezi kódy strojových instrukcí a instrukcemi assembleru existuje téměř přímá shoda.

Samostatná kompilace

Samostatná kompilace ( angl.  samostatná kompilace ) - překlad částí programu samostatně s jejich následnou kombinací linkerem do jediného zaváděcího modulu [2] .

Historicky bylo rysem kompilátoru, který se odrážel v jeho názvu ( angl.  kompilovat  - dát dohromady, skládat), to, že produkoval jak překlad , tak propojení, zatímco kompilátor mohl okamžitě generovat strojový kód . Avšak později, s rostoucí složitostí a velikostí programů (a rostoucím časem stráveným rekompilací), bylo nutné oddělit programy na části a izolovat knihovny , které lze kompilovat nezávisle na sobě. V procesu překladu programu samotný kompilátor nebo kompilátor povolaný kompilátorem vygeneruje objektový modul obsahující další informace, které se pak – v procesu spojování částí do spustitelného modulu – používají k propojení a rozlišení odkazů mezi části programu. Samostatná kompilace také umožňuje psát různé části zdrojového kódu programu v různých programovacích jazycích.

Objevení samostatné kompilace a přiřazení linkování jako samostatné fáze nastalo mnohem později než vytvoření kompilátorů. V tomto ohledu se místo výrazu „překladač“ někdy používá jako jeho synonymum výraz „překladač“: buď ve staré literatuře, nebo když chtějí zdůraznit jeho schopnost přeložit program do strojového kódu (a naopak, používají termín "kompilátor", aby zdůraznili schopnost sestavit z mnoha souborů jeden). To je jen použití výrazů "překladač" a "překladač" v tomto kontextu je nesprávné. I když kompilátor provádí překlad programu sám, deleguje linkování na vyvolaný program externího linkeru, nelze takový kompilátor považovat za jakýsi překladač - překladač provádí překlad zdrojového programu a nic víc. A rozhodně ne překladači jsou kompilátory, jako je obslužný program kompilátoru make system, který se nachází na všech systémech UNIX.

Samotný nástroj make  je ukázkovým příkladem poměrně úspěšné implementace samostatné kompilace. Činnost nástroje make je řízena skriptem ve vstupním jazyce interpretovaném nástrojem, známým jako makefile , obsaženým ve vstupním textovém souboru zadaném při spuštění nástroje. Obslužný program sám o sobě neprovádí žádný překlad ani propojení – obslužný program make de facto funguje jako správce procesů kompilátoru, který organizuje kompilaci programu v souladu se zadaným skriptem. Zejména během kompilace cílového programu nástroj make volá kompilátory z programovacích jazyků, které překládají různé části zdrojového programu do objektového kódu, a poté je volán jeden nebo jiný linker, který spojuje konečný spustitelný program nebo knihovnu. programový modul. Současně lze různé části programu, uspořádané jako samostatné zdrojové textové soubory, psát jak ve stejném programovacím jazyce, tak v různých programovacích jazycích. Při rekompilaci programu se překládají pouze změněné části-soubory zdrojového kódu programu, v důsledku čehož se výrazně (někdy až řádově) zkracuje doba trvání rekompilace programu.

Historie

Na úsvitu rozvoje počítačů se první kompilátory (překladače) nazývaly „programovací programy“ [6] (protože v té době byl za program považován pouze strojový kód a „programovací program“ byl schopen vytvořit strojový kód z lidský text, tedy programování počítače ).

Poznámky

  1. GOST 19781-83 // Počítačová věda. Terminologie: Referenční příručka. Číslo 1 / Recenzent Ph.D. tech. vědy Yu. P. Selivanov. - M . : Nakladatelství norem, 1989. - 168 s. - 55 000 výtisků.  — ISBN 5-7050-0155-X . ; viz také GOST 19781-90
  2. 1 2 3 4 Pershikov, 1991 .
  3. 1 2 3 Počítání .
  4. Borkovsky A. B. Anglicko-ruský slovník programování a informatiky (s výklady). - M . : ruský jazyk, 1990. - 335 s. - 50 050 (dalších) výtisků.  — ISBN 5-200-01169-3 .
  5. Dictionary of Computing Systems = Dictionary of Computing / Ed. V. Illingworth a další: Per. z angličtiny. A. K. Belotsky a další; Ed. E. K. Maslovského. - M .: Mashinostroenie, 1990. - 560 s. - 70 000 (dalších) výtisků.  - ISBN 5-217-00617-X (SSSR), ISBN 0-19-853913-4 (VB).
  6. N. A. Krinitsky, G. A. Mironov, G. D. Frolov. Programování / Ed. M. R. Shura-Bura . - M . : Státní nakladatelství fyzikální a matematické literatury, 1963.

Literatura

Odkazy