Mendelova univerzita v Brně Provozně ekonomická fakulta Schopnosti překladačů vybraných objektově orientovaných jazyků Diplomová práce Vedoucí práce: Ing. Pavel Haluza Bc. Martin Ventruba Brno 2011
Tady je zadání práce
Rád bych poděkoval vedoucímu mé diplomové práce Ing. Pavlu Haluzovi za cenné rady a za podporu, kterou mi při tvorbě této práce poskytl. Dále bych chtěl poděkovat panu docentu Jiřímu Rybičkovi za tvorbu sazebního stylu pro diplomové a bakalářské práce.
Prohlašuji, že jsem tuto diplomovou práci vypracoval samostatně a že v ní uvádím veškerou použitou literaturu a jiné zdroje, ze kterých jsem čerpal. Brno 28. 11. 2011....................................................
5 Abstract Ventruba, M. The abilities of compilers of selected object oriented languages. Diploma thesis. Brno, 2011. This thesis deals with evaluation of compiler s abilities of selected object oriented languages according to 11 criteria. It focuses on next three languages C++, C# and Java. C++ is compiled language, C# and Java combine compilation with intrepretation. The work assesses just compilers of these languages, not interpreters. It introduces you to design of evaluation criteria and their testing methodologies. A lot of them require using suitable testing samples. Considerable attention is devoted to design, implementation and application of these testing samples. All testing is realized under two operating systems Windows and Linux. At the end of this diploma thesis gained results and outputs are interpreted and clearly expressed. Keywords Compiler, object oriented languages, evaluation criteria, testing methodologies, testing samples Abstrakt Ventruba, M. Schopnosti překladačů vybraných objektově orientovaných jazyků. Diplomová práce. Brno, 2011. Diplomová práce se zabývá posouzením schopností překladačů vybraných objektově orientovaných jazyků podle 11 hodnotících kritérií. Zaměřuje se na následující tři jazyky C++, C# a Java. C++ je kompilovaným jazykem, C# a Java kombinují kompilaci s interpretací. Dílo posuzuje pouze kompilátory daných jazyků. Obeznámí Vás s návrhem hodnotících kritérií a metodikou jejich testování. Řada hodnotících faktorů vyžaduje užití vhodných testovacích vzorků. Jejich návrhu, implementaci a následné aplikaci je též věnována nemalá pozornost. Veškeré testování pak probíhá pod 2 operačními systémy Windows a Linux. Dosažené výsledky a výstupy jsou na závěr interpretovány a přehledně vyjádřeny. Klíčová slova Kompilátor, objektově orientované jazyky, hodnotící kritéria, metodologie testování, testovací vzorky
OBSAH 6 Obsah 1 Úvod a cíl práce 8 1.1 Úvod.................................... 8 1.2 Cíl práce.................................. 9 2 Přehled literatury 10 3 Teoretická východiska práce 11 3.1 Programovací jazyky........................... 11 3.1.1 Klasifikace programovacích jazyků................ 11 3.1.2 Definice základních pojmů objektově orientovaného přístupu. 12 3.1.3 Současné trendy v objektově orientovaném programování... 13 3.1.4 Rozdělení objektově orientovaných jazyků........... 14 3.2 Překladače................................. 15 3.2.1 Historie překladačů........................ 16 3.2.2 Struktura překladače....................... 17 3.2.3 Typy překladačů......................... 20 3.2.4 Podrobná klasifikace překladačů................. 23 3.2.5 Zpracování chyb.......................... 24 3.3 Vybrané objektově orientované jazyky a jejich překladače....... 25 3.3.1 C++................................ 26 3.3.2 Java................................ 29 3.3.3 C#................................. 32 4 Testování 34 4.1 Testovací procedura............................ 34 4.2 Testovací technika............................ 35 4.3 Hodnotící kritéria............................. 35 4.3.1 Obtížnost instalace/odinstalace................. 36 4.3.2 Kompatibilita........................... 36 4.3.3 Schopnost odhalit anomálie................... 38 4.3.4 Srozumitelnost zpětné vazby................... 38 4.3.5 Počet nalezených chyb...................... 39 4.3.6 Odolnost.............................. 39 4.3.7 Doba kompilace.......................... 39 4.3.8 Paměťová náročnost....................... 40 4.3.9 Podpora oddělené kompilace................... 40 4.3.10 Dokumentace........................... 41 4.3.11 Akceptace nových prvků jazyka................. 42 4.4 Testovací prostředí............................ 42 4.5 Použité testovací nástroje a software.................. 43 4.6 Testovací vzorky............................. 44 4.6.1 Návrh testovacích vzorků..................... 44
OBSAH 7 4.6.2 Implementace testovacích vzorků................ 48 4.6.3 Aplikace testovacích vzorků................... 52 5 Interpretace výsledků testování 53 5.1 Obtížnost instalace/odinstalace..................... 53 5.2 Kompatibilita............................... 55 5.3 Doba kompilace a paměťová náročnost................. 56 5.4 Podpora oddělené kompilace....................... 57 5.5 Schopnost odhalit anomálie....................... 58 5.6 Dokumentace............................... 60 5.7 Srozumitelnost zpětné vazby....................... 63 5.8 Počet nalezených chyb.......................... 64 5.9 Odolnost.................................. 65 5.10 Akceptace nových prvků jazyka..................... 65 6 Diskuse 67 7 Závěr 70 8 Literatura 71 Přílohy 74 A Testovací vzorky 75
1 ÚVOD A CÍL PRÁCE 8 1 Úvod a cíl práce 1.1 Úvod Ač bychom si to přáli a díky mnoha science fiction pořadům bychom mohli nabýt dojmu, že lidé a počítače hovoří stejným jazykem, ve skutečnosti tomu tak ale není. Pro zápis algoritmů, jež mohou být provedeny na počítači, nám slouží programovací jazyky. Programovací jazyky jsou komunikačním nástrojem mezi programátorem, který v programovacím jazyce dává počítači instrukce, co má dělat, a počítačem, který program interpretuje technickými prostředky. Zápis programu se ukládá v člověku srozumitelném zdrojovém kódu. Na druhou stranu, program zapsaný v takovém jazyce počítač neumí přímo vykonat, a musí být proto speciálním programem tzv. překladačem přeložen do strojového kódu, který se teprve může provést. První programy na prvotních počítačích byly psány ve strojovém kódu. Avšak záhy se projevily nedostatky programování ve strojovém jazyce jako pro člověka nepohodlný číselný zápis instrukcí, závislost na konkrétním typu počítače a další. To mělo dopad na vznik prvních jazyků. Prvním krokem ve vývoji programovacích jazyků byla náhrada numericky kódované informace instrukcí strojového jazyka informací symbolickou. Vzniká tak důležitá třída programovacích jazyků jazyky symbolických instrukcí. Překladač jazyka symbolických instrukcí se nazývá assembler. Další vývoj směrem k vyšším programovacím jazykům nastal v 60. letech 20. století, kdy se objevily programovací jazyky 3. generace, které odstranily strojovou závislost jazyků a poskytly programátorům takové prostředky pro popis algoritmů, jenž odráží povahu řešených problémů. V této době se objevuje i nový pojem strukturované programování, které s sebou přineslo maximální přehlednost a srozumitelnost zdrojového kódu. Daný způsob programování měl i jednu nevýhodu v podobě obtížné práce se strukturami (například vytváření a manipulace s databázemi). Ze zmíněného důvodu vznikl směr objektového programování. Objektově orientované programování s sebou přináší změnu aktivity. Nositelem aktivity se stala data. Ve strukturovaném programování bychom pro práci se soubory volali příslušné funkce, naproti tomu v objektovém programování vytvoříme objekt soubor, který by měl metody definující, co vše je možné s ním provádět. Objektové programování s sebou přineslo také nové vlastnosti (zapouzdření, dědičnost a polymorfismus). Od té doby jsou služby, ve větší či menší míře podporující objektové programování, k dispozici ve většině programovacích jazyků.
1.2 Cíl práce 9 1.2 Cíl práce V poslední době začíná objektově orientované programování (OOP) převládat nad klasickými programovacími přístupy. Tato skutečnost se odráží ve velkém počtu programovacích jazyků podporujících zmiňovaný přístup. Pro každý programovací jazyk, který má být používán (implementován) na počítači, musí existovat překladač. Ke každému jazyku je k dispozici celá řada volně dostupných překladačů. Cílem této diplomové práce je posoudit schopnosti překladačů vybraných jazyků podle navržených kritérií. Dosažené výsledky pak poslouží jako metrika kvality produktu či jen zajímavé a unikátní srovnání jejich schopností. Text práce by měl rovněž poskytnout dobrý základ pro případné další testování překladačů. Z tohoto důvodu bude psán srozumitelnou formou a bude obsahovat všechny stěžejní informace, včetně ukázek použitých testovacích vzorků. V neposlední řadě práce poskytuje seznam volně dostupných kompilátorů daných jazyků společně s doplňujícími informacemi.
2 PŘEHLED LITERATURY 10 2 Přehled literatury Problematika jazyků a překladačů je velmi rozsáhlá, a proto není divu, že o ní byla napsána celá řada publikací. Snad nejznámější prací z dané oblasti je kniha Compilers: Principles, Techniques & Tools, Second edition (Aho a kol., 2007). Každá kapitola této knihy byla oproti původnímu vydání z roku 1986 přepracována tak, aby odrážela vývoj v oblasti softwarového inženýrství, programovacích jazyků a počítačové architektury. Dílo je určeno nejen počítačovým odborníkům a vývojářům, ale i začínajícím programátorům, kteří se chtějí něco dozvědět o stavbě, údržbě a chodu překladačů. Kniha je rovněž známá pod názvem Dračí kniha. Autoři knihy Engineering a compiler (Cooper a Torczon, 2003) si stanovili za cíl odhalit důležité problémy moderních překladačů a poskytnout řešení těchto problémů. Kniha je zaměřena na tzv. zadní část překladače, což odráží směr výzkumu a vývoje za poslední desetiletí. Zadní část překladače provádí optimalizaci mezikódu a generuje cílový program. Autoři věnují velkou pozornost i metodám generování kódu. V knize Automata and Languages (Meduna, 2000) nás autor provede krok po kroku teorií automatů, jazyků a potřebnou matematikou. Alexander Meduna užívá jasné definice, snadno pochopitelné důkazy a užitečné příklady k pochopení dříve nejasných pojmů. Spis také zahrnuje náročná cvičení spolu s programováním projektů ke zvýšení čtenářova pochopení problematiky, včetně spousty ilustrací a aplikace poznatků v praxi. Kniha Compiler Construction: Principles and Practice (Louden, 1997), vysloužilého profesora informatiky na San Jose State University, obsahuje jak teoretické studium kompilačních technik, spolu s mnoha příklady z praxe napsaných v jazyce C, tak úplný překladač spolu se strojovým simulátorem (též napsaným v C), který může být použit, aby provedl vygenerovaný kód. Jsou zde také kapitoly o metodách syntaktické analýzy shora dolů a zdola nahoru, sémantické analýze, běhových prostředí a generování kódu. Detailně jsou zde popsány i programy Lex a Yacc. V příloze pak nalezneme řadu doplňujících informací k vytvářenému překladači a strojovému simulátoru. Kromě výše zmíněných publikací existuje mnoho dalších kvalitních zdrojů řešících problematiku překladačů. Je možné vybírat z tištěných či elektronických médií. Za zmínku bezpochyby stojí například skripta Slezské univerzity v Opavě (Vavrečková, 2008). Nutno však podotknout, že tématem porovnání schopností překladačů se doposud v literatuře nikdo nezabýval. K dispozici je sice pár zdrojů (převážně elektronických), které částečně řeší dané téma. Při posuzování jejich kvality je však potřeba v nich pečlivě vybírat. O překladu a překladačích objektově orientovaných jazyků se tak nejvíce dozvídáme z knih věnovaných jednotlivým jazykům a na domovských stránkách konkrétních překladačů. Mezi takové knihy lze zařadit Mistrovství v C++ (Prata, 2001), Trustworthy Compilers (Sofanov, 2010) či C# pro zelenáče (Virius, 2002).
3 TEORETICKÁ VÝCHODISKA PRÁCE 11 3 Teoretická východiska práce 3.1 Programovací jazyky Existuje mnoho definic programovacího jazyka. Následující definice jsou hojně užívány a částečně z nich vyplývá, proč se vůbec programovací jazyky používají. Programovací jazyk je prostředník mezi běžnou řečí a posloupností typicky binárních číslic (Kolář, 2006). Notace pro popis výpočtů ve formě čitelné pro stroj i pro člověka (Louden, 2003). Z definic je zřejmé, že programovací jazyky stojí mezi programátorem a počítačem, tedy mezi člověkem a strojem. Lidé mezi sebou komunikují prostřednictvím přirozených jazyků, které se vyznačují velkou nepřesností. Binární jazyk, jenž využívají počítače, je náročný na zapamatování a zcela nevhodný pro rychlou tvorbu programů. Z tohoto důvodu se v něm programuje jen výjimečně a byla postupně vytvořena řada programovacích jazyků, které jsou pro člověka přeci jenom srozumitelnější. Aby mohl být zdrojový text programu zapsaný v některém z programovacích jazyků zpracován procesorem počítače, musí být přetransformován do takové podoby, kterou je procesor schopný zpracovat a vykonat, tj. do strojového kódu mající binární tvar. Takové transformaci se říká překlad. Nástroj, jenž se pak pro překládání používá, se označuje termínem překladač. 3.1.1 Klasifikace programovacích jazyků V současné době máme k dispozici velké množství programovacích jazyků a neustále se objevují nové. Tyto programovací jazyky lze rozdělit podle mnoha kritérií. Z hlediska míry abstrakce jakou dávají programátorovi lze rozlišit tyto kategorie jazyků: nižší neboli strojově orientované programovací jazyky vyšší (problémově orientované) programovací jazyky Vyšší programovací jazyky můžeme dále dělit podle paradigmat (v oblasti programování se jako paradigmata označují jednotlivé druhy, způsoby a přístupy k programování) na procedurální (imperativní) a neprocedurální (deklarativní). Procedurální programování popisuje přesný postup a posloupnost příkazu, jak požadovaný problém řešit. Dělí se na strukturované a objektově orientované programování. Strukturované programovaní rozdělí algoritmus na menší dílčí úlohy a objektově orientované programování vychází při tvorbě programů z opakovaného používání tzv. objektů, které tvoří základní stavební kameny vytvořeného programu. Neprocedurální programování je založeno na myšlence soustředit se co nejvíce na to, co se má řešit, a méně na to, jakým způsobem to má být řešeno. Dělí se na funkcionální a logické programování. Funkcionální programování se hlavně zaměřuje na programy,
3.1 Programovací jazyky 12 které jsou složeny z funkcí, a také nato co se má vypočítat. Logické programování používá matematickou logiku. Stejně jako funkcionální programovací jazyky jsou i logické programovací jazyky využívány především pro vědecké účely, v komerční sféře jsou využívány zřídkakdy (Dohnal, 2009). procedurální (imperativní) jazyky strukturované objektově orientované neprocedurální (deklarativní) jazyky logické funkcionální Podle způsobu překladu a spuštění můžeme vyšší programovací jazyky dělit na kompilované (před spuštěním přeloženy kompilátorem) a interpretované (překládají se do mezikódu a potom při spuštění do zdrojového kódu). Zmíněné postupy mohou být kombinovány. Dále můžeme jazyky klasifikovat podle účelu, zde je však velmi obtížné přesně vymezit jednotlivé skupiny, dle stáří na moderní a zastaralé. Toto dělení je však poněkud subjektivní. 3.1.2 Definice základních pojmů objektově orientovaného přístupu Historie objektově orientovaného programování začíná na přelomu 60. a 70. let 20. století. Jedná se o programovací styl, který se snaží řešit jeden ze základních problémů strukturovaného programování, kterým je separace datových objektů a funkcí (podprogramů), které s danými datovými objekty manipulují (Kraval, 1998). Základním prvkem OOP jsou struktury nazývané objekty. Objekt obsahuje vnitřní paměť, která se nazývá atribut objektu. Vnitřní paměť objektu je zvnějšku nepřístupná. Objekt dále obsahuje metody, které vykonávají nějakou činnost nad vnitřní pamětí objektu a pouze nad ní. Jedinou možností, jak spolupracovat s objektem, je zaslat mu zprávu. Objekty jsou struktury schopné nějakým mechanismem zaslat a přijmout zprávu zvnějšku. Mohou obsahovat i jiné objekty, kterým jsou schopni poslat zprávu a řídit tak jejich činnost. Prostředí resp. jazyk nebo technologie splňuje objektově orientovaný princip, pokud dovoluje vytvářet objekty s výše zapsanými vlastnostmi. Přesto poměrně značné množství literatury a zdrojů, věnovaných objektovému přístupu, uvádí jako zavádějící principy objektově orientovaného programování zapouzdření, polymorfismus a dědičnost. Tyto tři principy sice jsou objektovému systému většinou vlastní, ale nejsou zásadním principem objektového systému (snad vyjma polymorfismu, který s komunikací objektů úzce souvisí) (Čada, 2009). Nyní by bylo vhodné, abychom se na tyto tři pojmy podívali podrobněji a vysvětlili si jejich význam. Zapouzdření (encapsulation) je operace při které jsou skryty detaily implementace objektu a veřejně přístupné zůstávají jen vybrané metody
3.1 Programovací jazyky 13 a atributy, se kterými má mít uživatel právo manipulovat. Dědičnost je jeden z klíčových nástrojů OOP, který umožňuje vytváření nových tříd (nový programových modulů) jen naprogramováním změn oproti třídě jiné. Tento způsob vývoje aplikací bývá nazýván diferenciální programování (programming by extension) a zásadně přispívá ke zrychlení vývoje aplikací (Procházka, 2006). Polymorfismus úzce souvisí se zapouzdřením: zatímco zapouzdření požaduje, abychom s objektem komunikovali jako s černou skříňkou, do níž nevidíme, polymorfismus požaduje, abychom mohli jedním a týmž způsobem komunikovat s různými objekty. Každá ze zde uvedených předností vede k efektivnějšímu vývoji a spolehlivějšímu, robustnějšímu a snáze spravovatelnému kódu. Produktivita vývoje a kvalita výsledného kódu byly hlavními důvody, proč postupně téměř všichni programátoři přešli k OOP a proč jsou v současné době všechny opravdu velké projekty vyvíjeny téměř výhradně objektově. 3.1.3 Současné trendy v objektově orientovaném programování Objektové programování je přímým modelem reálného světa a zdá se proto celkem pravděpodobné, že nelze vymyslet nic principiálně lepšího (Čada, 2009). Objetkové jazyky se však samozřejmě zdokonalují a mění, i když jejich základní paradigma zůstávají bez principiálních změn. Zdokonalení jazyka C++ probíhá pomocí standardů, které činí jazyk snáze použitelným. To ovšem neznamená, že C++ je díky nim jednodušší, ale standardy poskytují mnoho funkcí usnadňujících programování v něm. Rovněž napsaný kód je pak kratším a čitelnějším. Jmenovitě se pro jazyk C++ jedná o standard C++0x. C++0x je pracovní označení tohoto nového standardu, který byl v září 2011 oficiálně zveřejněn pod názvem C++11 standard. V současnosti mnoho kompilátorů poskytuje podporu pro některé z jeho hlavních rysů. C++11 zahrnuje širokou škálu funkcí: zcela nová je podpora lambda funkce 1 a move semantics 2, zlepšení použitelnosti jako odvození typu pomocí klíčového slova auto, zjednodušené smyčky přes kontejnery a mnoho vylepšení, která umožní jednodušší použití a implementaci šablon. 28. července 2011, po pěti letech vývoje, vydala firma Oracle Javu 7 Standard Edition. Sedmá Java by měla být díky projektu Coin mnohem efektivnější pro vývoj. Jde o projekt, který měl za úkol udělat v jazyku malé změny, které výrazným způsobem ovlivní produktivitu programátorů. K takovým změnám patří použití řetězců v příkazu switch, multi-catch (multi-catch výjimky byly přidány do Java 1 Lambda-výrazy byly původně součástí tzv. λ-kalkulu, který zavedl A. Church ve 30. letech minulého století jako prostředek pro teoretický popis funkcí. V programování se používají jako nástroj, který umožňuje definovat funkci až v místě jejího použití. Donedávna jsme se s nimi setkávali pouze ve funkcionálně orientovaných programovacích jazycích, v posledních několika letech se ale objevují i v procedurálních jazycích (Virius, 2011). 2 Cílem move semantics je zabránit zbytečnému kopírování dat, která by stačilo jen přesunout. Tím můžeme z operace lineární vůči délce dat učinit operaci běžící v konstantním čase. Vždy potřebujeme naimplementovat move constructor (Move semantics a rvalue, 2011).
3.1 Programovací jazyky 14 SE 7 s cílem usnadnit a zestručnit práci s výjimkami), diamond (operátor, který redukuje některé výpisy Javy týkajících se generik tím, že kompilátor odvozuje typy u parametru pro konstruktory generických tříd), vylepšený try, nové API pro práci se souborovým systémem, rozšíření JVM, podporu pro dynamicky psané jazyky či framework pro efektivnější paralelizaci úloh a mnohé další novinky (Konda, 2011). C# je jazyk, který se vyvíjí docela dramaticky a každá nová verze s sebou přinese pár zajímavých novinek. V poslední verzi 5.0 se tvůrci C# zaměřili na asynchronní programování. Hlavní změny jsou v přidání dvou klíčových slov do jazyku C#: modifikátoru async (určuje, že metoda (nebo lambda výraz) je asynchronní) a operátoru await (určuje, že od tohoto místa může být metoda zpracovávána v jiném než hlavním vlákně) (Veith, 2011). 3.1.4 Rozdělení objektově orientovaných jazyků Dnes máme k dispozici velké množství programovacích jazyků umožňujících objektově orientované programování. Za jejich předchůdce je všeobecně považován jazyk Simula 67, který přinesl koncepci třídy jako zobecnění tehdejšího způsobu implementace datových typů. Následovníkem Simuly 67 byl systém Smalltalk, který přivedl na svět objekty a objektově orientované programování (program ve Smalltalku je tvořen objekty, které si navzájem posílají zprávy) (Pecinovský a Virius, 1996). Objektové programování se začalo výrazněji prosazovat v 80. letech s příchodem jazyka C++ a zcela ovládlo pole v 90. letech, zejména pak po příchodu jazyka Java. Za celou tu dobu se objevila řada OOJ, které dělíme na dvě skupiny: čistě objektové hybridní Čistě (ryze) objektově orientované jazyky nepřipouští jiné programovací modely, vše musí být objektem (čísla, písmena i samy třídy). Funkci nelze napsat samostatně, pokud není součástí třídy. Nemůžeme deklarovat globální proměnné. Program vytvořený v čistě objektově orientovaném jazyku není závislý na hlavní funkci, resp. metodě, která zahajuje zpracování programů vytvořených v hybridních programovací jazycích. V ryze objektově orientovaných programech jejich zpracování začíná zasláním zprávy z rozhraní programu vybraným objektům, které na tuto zprávu patřičným způsobem reagují (Kraval, 1998). Čistě objektové jazyky, ke kterým patří zejména dynamické jazyky, se používají v umělé inteligenci, simulacích, počítačové grafice atd. Do této skupiny patří Smalltalk, Eiffel či Ruby. Většina běžně rozšířených objektově orientovaných programovacích jazyků patří do kategorie hybridních jazyků. Kombinují v sobě možnosti strukturovaného a objektově orientovaného počítačového softwaru. To znamená, že hybridní jazyky porušují některý ze základních požadavků na OOP. Nejčastěji v nich bývá možnost využít základní datové typy, které nejsou objekty. Příkladem hybridních jazyků jsou C++, C#, Python, Java atd.
3.2 Překladače 15 Poněkud problematickým je pak zařazení jazyka Java. Mnozí autoři označují Javu za čistě objektový jazyk. V čistě objektově orientovaných jazycích je objektem opravdu všechno. Java však neuplatňuje objektovou orientaci naprosto důsledně a obsahuje tzv. primitivní datové typy, které nejsou objekty. Tvůrci Javy nadefinovali devět primitivních datových typů pro zvýšení efektivity programů. Pravdou zůstává, že ke každému primitivnímu datovému typu existuje třída implementující metody pro práci s daným datovým typem. Přesto díky možnosti použití primitivních datových typů, nesplňuje Java výše uvedený popis ryze objektových jazyků a je ji třeba zařadit mezi jazyky hybridní (Pecinovský, 2005). Dalším faktorem pro rozdělení objektově orientovaných jazyků může být jejich dynamika, resp. statika. Statické jazyky jsou založeny na znalosti datového typu a provádějí četné typové kontroly v době překladu. Dynamické jazyky mají slabší znalost typu, provádějí většinu kontroly za běhu a jsou obvykle interpretovány (např. Smalltalk). Naproti tomu statické jazyky jsou založeny na znalosti datového typu, provádějí četné typové kontroly v době překladu a jsou kompilovány (např. Object Pascal) (Kříž, 2002). 3.2 Překladače Až do tohoto okamžiku byl pro nás překladač jakousi černou skříňkou, která mapuje zdrojový program do sémanticky ekvivalentního cílového programu. Podíváme-li se na tuto skříňku podrobněji zjistíme, že celý postup mapování se skládá ze dvou částí: analytické a syntetické. Analýza spočívá v rozkladu zdrojového programu na jeho základní součásti, na základě kterých se během syntézy vybudují moduly cílového programu. Obě části překladače, analytická i syntetická, využívají ke své činnosti tabulku symbolů. Analytická část překladače je často nazývána přední část překladače (front end) a syntetická část zadní částí překladače (back end). Přední část zahrnuje lexikální, syntaktickou a sémantickou analýzu. Je do značné míry nezávislá na cílovém systému. Zadní část překladače provádí optimalizaci kódu a generuje cílový program. Tato část je již závislá na cílovém systému. Toto rozdělení zjednodušuje vytváření překladačů téhož jazyka pro různé operační systémy. Překladače mají stejnou přední část, liší se jen v zadní části, protože typ cílového kódu bude jiný, a také optimalizace mohou být určeny přímo pro danou platformu. Například pokud chceme vytvořit překladače pro tentýž programovací jazyk, které by běžely pod Windows, Linuxem i MacOS, vytvoříme jednu přední část zahrnující lexikální, syntaktickou a sémantickou analýzu a tři různé zadní části, které budou generovat spustitelné soubory pro tyto tři operační systémy (Vavrečková, 2008).
3.2 Překladače 16 3.2.1 Historie překladačů Software pro rané počítače byl primárně psán v jazyce symbolických instrukcí. Vyšší programovací jazyky se objevují až v době, kdy výhody znovupoužití softwaru na různých typech procesorů začaly výrazně převládat nad náklady na napsání překladače. Mnoho technických problémů při konstrukci překladače také zapříčinila značně omezená kapacita prvních počítačů. Na konci 50. let 20. století se poprvé objevily strojově nezávislé programovací jazyky. Následně bylo vyvinuto několik experimentálních překladačů. Prvním program, který je bylo možné označit jako překladač, byl A-0 System, který v roce 1952 vytvořila Grace Hopper pro počítač UNIVAC. Grace Murray Hopper také poprvé použila termín překladač. Na překlad se však tehdy dívalo jako na kompilaci posloupnosti podprogramů z knihovny. Kompilace v dnešním slova smyslu byla považována za nemožnou. Týmu vývojářů Fortranu, pracujícímu pro IBM, pod vedením Johna Backuse je obecně připisována prvenství za uvedení prvního kompletního překladače v roce 1957. S příchodem Fortranu nastal zlom v podstatě překladu. Zavedl tzv. problémově orientovaný přístup tj. důležitým faktorem bylo to, co je potřeba vyřešit, na rozdíl od přístupu stávajících překladačů, které spíše umožňovaly jen přehlednější zápis strojového kódu. Byla použita optimalizace k vytvoření efektivního strojového kódu, který byl zásadní pro první počítače s omezenými schopnostmi. Efektivní používání strojových zdrojů je koneckonců stále zásadním požadavkem moderních překladačů. Byla prokázána vhodnost kompilovaných jazyků vysoké úrovně a od té doby se jazyky strojem překládají do velmi efektivního cílového programu (Beneš, 2005). V roce 1960 se pak objevil první multiplatformní kompilátor pro jazyk Cobol. Myšlenka používání vyšších programovacích jazyků se rychle uchytila v mnoha aplikačních doménách. Kvůli rozšiřující se použitelnosti podporované novějšími programovacími jazyky a rostoucí složitosti počítačových architektur, se překladače stávali stále složitějšími (Historie překladačů, 2011). První tzv. self-hosting překladač (schopný kompilovat svůj vlastní zdrojový kód do vyššího programovacího jazyka) byl vytvořen pro LISP Timem Hartem a Mikem Levinem v MIT roku 1962. Ačkoliv jak Pascal, tak C byly oblíbenou volbou implementačního jazyka, od 70. let 20. století se stalo běžným implementovat překladač v jazyce jež kompiluje. Konstrukce self-hosting překladač s sebou přináší tzv. bootstrapping problém první takový překladač jazyka musí být zkompilován, buď překladačem napsaným v jiném jazyce nebo spuštěním onoho překladače v interpretu (Historie překladačů, 2011). Teorie překladačů a programovacích jazyků dnes umožňuje běžně používané jazyky překládat bez obtíží. Pro automatickou výstavbu překladačů je k dispozici mnoho specializovaných nástrojů. Zatímco na vývoj prvního překladače jazyka Fortran bylo potřeba 18 člověkoroků, nyní je vytvoření jednoduchého překladače libovolného jazyka zvládnutelné i pro méně zkušeného programátora.
3.2 Překladače 17 3.2.2 Struktura překladače Samotný překladač se skládá z několika části, z nichž každá má při překladu jiný úkol. Činnost jednotlivých částí nazýváme fáze překladu. V překladači mohou být tyto části: lexikální analyzátor syntaktický analyzátor sémantický analyzátor optimalizátor kódu generátor cílového kódu nebo interpretace Obr. 1: Struktura překladače (Aho a kol., 2007), upraveno autorem práce. Lexikální analyzátor První částí překladače, která se dostane do styku se zdrojovým programem je lexikální analyzátor (scanner). Úkolem lexikálního analyzátoru je převést zdrojový text
3.2 Překladače 18 do podoby, které rozumí ostatní části překladače (Vavrečková, 2008). Scanner čte proud znaků tvořících zdrojový program a rozdělí tyto vstupní znaky na významové sekvence nazývané lexémy (některý ze základních prvků příslušného jazyka, např. klíčové slovo function). Tyto lexémy jsou reprezentovány ve formě tokenů, majících svůj typ a obsah, které jsou dále poskytnuty ke zpracování syntaktickému analyzátoru. Předpokládejme, že zdrojový program obsahuje přiřazovací příkaz ve tvaru: pozice_x = 103,5. Pak pozice_x je lexém, který bude mapován do tokenu s typem identifikátor a obsahem pozice_x. Přiřazovací symbol = je lexém, který bude mapován do tokenu s typem přiřazovací příkaz. 103,5 je lexém, který bude namapován do tokenu s typem desetinné číslo a obsahem 103,5. Všechny možné lexémy jsou ve vstupním jazyce popsány pomocí regulárních výrazů. V překladači se pro jejich rozpoznávání používá konečný automat (Mužík, 2006). Během analýzy vynechává lexikální analyzátor ty části vstupu, které nemají význam pro další překlad. Jedná se o mezery, komentáře a konce řádků. Lexikální chyby zahrnují překlepy v identifikátorech, v klíčových slovech nebo v operátorech např. použití identifikátoru delkahran namísto delkahrany, rovněž chybějící uvozovky okolo textu jsou považovány za řetězec. Syntaktický analyzátor Syntaktický analyzátor (v angličtině označovaný jako parser) je nejdůležitější částí překladače. Úlohou tohoto analyzátoru je tvorba struktury překládaného programu (obvykle ve formě derivačního stromu ve vhodné reprezentaci) (Vavrečková, 2008). Syntaktický analyzátor dostává na vstup od lexikálního analyzátoru proud tokenů a je schopen posoudit, zda je správně syntakticky zapsán a zda posloupnost lexémů patří do daného zdrojového jazyka. Během své činnosti se parser snaží z lexému sestavit podle předem daných gramatických pravidel derivační strom. Pokud se jej podaří zkonstruovat je výsledný strom podstoupen sémantickému analyzátoru. Podle způsobu konstrukce derivačního stromu rozlišujeme 2 základní metody syntaktické analýzy: shora dolů, kdy derivační strom konstruujeme od kořene k listům, zdola nahoru, kdy postupujeme od listů ke kořeni (Vavrečková, 2008). Lexikální analyzátor je schopen odhalit pouze chyby, které nastanou v okamžiku, kdy konečný automat nemůže dále pokračovat a nenachází se v konečném stavu. Jedná se o chyby typu neznámý znak či neukončený řetězec do konce řádky. Naproti tomu parser nám odhalí chyby jako zapomenuté středníky, chybějící nebo přebývající závorky. Dalším příklad je z jazyka C nebo Java, kde výskyt bloku case mimo příkazový blok switch je syntaktickou chybou (nicméně tato situace je obvykle syntaktickým analyzátorem akceptována a odchycena až později při zpracování, konkrétně při generování kódu). Dokud nedojdeme na konec vstupního souboru, syntaktický analyzátor si opakovaně volá lexikální analyzátor, který mu vrací token po tokenu a posuzuje, zda je syntakticky přípustný nebo zda nikoliv.
3.2 Překladače 19 Sémantický analyzátor Sémantický analyzátor uzavírá analytickou část překladače. Popisuje význam jednotlivých částí programu. V této části překladu dochází ke zpracování informací uvedených v deklaracích, například při zpracování deklarace proměnné je třeba zkontrolovat, zda již není někde v programu deklarována a jestli je správně použita vzhledem k jejímu deklarovanému typu, u operátorů odčítání zkontroluje, zda jeho operandy jsou správného typu a případně provede přetypování atd (Vavrečková, 2008). Výstup sémantického analyzátoru je intermediální kód (mezikód), který lze snáze optimalizovat, a teprve optimalizovaný program se převádí do cílového jazyka. Tuto formu kódu lze také použít pro interpretaci. Hlavní rozdíl mezi intermediálním a cílovým kódem spočívá v tom, že v intermediálním kódu není ještě stanovena adresace operandů ani použití registrů pro výpočty. Nejčastěji se používají tyto formy intermediálního kódu (případně jejich modifikace nebo kombinace): 3-adresový kód, ohodnocený syntaktický strom (sémantický strom), postfixový tvar (polská notace) (Aho a kol., 2007). K sémantickým chybám patří nesoulad mezi operátory a operandy. Typickým příkladem je použití příkazu return u metod Javy či C++ s návratovým typem void. Pokud máme štěstí, může na ně překladač nepřímo upozornit pomocí varovných hlášení při překladu. Optimaliazace Strojově nezávislý optimalizátor kódu se pokouší vylepšit intermediální kód, tak aby jeho výsledkem byl lepší strojový kód. Co si však představit pod pojmem lepší strojový kód? Obvykle lepší znamená rychlejší, ale žádoucí mohou být i jiné cíle, jako například kratší strojový kód nebo cílový kód zabírající méně místa. Optimalizátor kódu zajišťuje, aby se používalo co nejméně pomocných proměnných pro mezivýpočty, aby se v cyklu zbytečně několikrát nevyhodnocoval tentýž výraz, jestliže hodnota jeho prvků zůstává beze změny a vyhodnocení stačí provést pouze jednou před cyklem, ve vygenerovaném kódu se může také vyskytovat tzv. mrtvý kód (kód, který se nikdy nevykoná), takový kód optimalizátor zcela zahodí, apod (Aho a kol., 2007). Použití optimalizace je charakteristické spíše pro kompilační překladače, u interpretů bývá tato fáze přeskočena (Vavrečková, 2008).
3.2 Překladače 20 Generování cílového programu nebo interpretace Tato část překladače, jak již samotný název kapitoly napovídá, generuje z optimalizovaného intermediálního kódu cílový program nebo jej interpretuje. Vytváří se kód buď v jazyce symbolických instrukcí, ve vlastním jazyce sestavujícího programu (interpretační překladač) nebo přímo v jazyce stroje (strojový kód, například EXE a DLL ve Windows) (Vavrečková, 2008). 3.2.3 Typy překladačů Rozmanitost typů překladačů používaných v současné době je ohromující. Pro účely této diplomové práce však zcela postačí následující rozdělení překladačů, které se také uvádí ve většině publikací. Podle typu cílového programu tedy rozlišujeme následující druhy překladačů: kompilátory (generační překladače), interprety (interpretační překladače, někdy též interpretery), hybridní překladače. Kompilátor Jedná se o překladač, jenž ze vstupního programu napsaného ve vyšším programovacím jazyce vytvoří cílový program ve strojovém jazyce nebo jazyce symbolických instrukcí. Z objektově orientovaných jazyků sem řadíme C++ či Delphi (Object Pascal). Obr. 2: Kompilační překladač (Aho a kol., 2007), upraveno autorem práce.
3.2 Překladače 21 Interpret Interpret, interpretační překladač, někdy též interpreter je označení pro program, který na rozdíl od kompilátoru, interpretuje příkazy zdrojového jazyka tak, jak jsou napsané, a přímo provádí odpovídající akce, bez toho aniž by vzniknul spustitelný soubor. Interpretace se provádí znovu při každém spuštění kódu, kdežto kompilace jen jednou a pak při každém dalším spuštění jsou přímo vykonávány strojové instrukce bez nutnosti překladu. Řadíme zde hybridní objektový jazyk Python či čistě objektové jazyky Smalltalk, Ruby. Obr. 3: Interpretační překladač (Aho a kol., 2007), upraveno autorem práce. Hybridní (kombinované) překladače Hybridní překladače kombinují kompilaci a interpretaci. Generují mezikód nezávislý na operačním systému, tento mezikód je pak interpretován interpretační částí překladače, která je nainstalována na počítači, kde mezikód spouštíme. Typickým příkladem je jazyk Java a C#. Obr. 4: Hybridní (kombinovaný) překladač (Aho a kol., 2007), upraveno autorem práce.
3.2 Překladače 22 Srovnání vlastností kompilačního a interpretačního překladače Mezi kompilátory a interprety existuje celá řada rozdílů a každý z těchto druhů se hodí pro jinou situaci. Asi zásadní rozdíl spočívá v rychlosti. Zatímco cílový program kompilátoru (obvykle soubor obsahující strojový kód, např. EXE pro Windows) se provádí relativně svižně, interpretovaný program je naopak pomalý a pro mnoho vyšších programovacích jazyků proto nevhodný, protože překlad je prováděn při každém spuštění programu. Interpret je v průměru 10krát až 100krát pomalejší. Vyskytují se však i výjimky, například interpret programovacího jazyka Perl je velmi rychlý. U kompilátorů samotný překlad probíhá jen jednou, nesouvisí se samotným prováděním programu, což umožňuje provádět i časově náročné optimalizace a kontroly (Vavrečková, 2008). Za další nedostatek interpretačních překladačů lze považovat jeho nezbytnost při spuštění interpretovaného programu a náročnost na paměť (při běhu musí být v paměti počítače nejen zdrojový program ale také celý překladač). Nutná přítomnost interpretu není žádným velkým problémem u snadno dostupných překladačů (třeba překladače jazyků Perl, Python či Ruby jsou běžně dostupné v linuxových překladačích) a ani nároky na paměťový prostor u současných počítačů nejsou žádnou velkou překážkou, nehledě na to, že nejsou až tak velké (Vavrečková, 2008). Na druhou stranu umožňují interpretační překladače provést pouze malé části zdrojového programu (např. jazyk Smalltalk), jsou snazší na konstrukci, programátor (autor překladače) obvykle nemusí ovládat assembler ani strojový jazyk a při výskytu chyby ji můžeme spolehlivěji lokalizovat (Vavrečková, 2008). Navíc v případě programu, který jeho uživatel uchovává, se jedná běžně o textový soubor zabírající výrazně méně místa než obdobný cílový program přeložený kompilátorem. K tomu všemu je zdrojový program snáze přenositelný (prakticky je spustitelný na libovolné platformě můžeme mít na strojích s rozličnými operačními systémy nainstalován interpretační překladač pro tentýž jazyk, všechny tyto překladače přijmou tentýž zdrojový program) (Vavrečková, 2008). V níže uvedené tabulce jsou shrnuty výsledky srovnání kompilačního a interpretačního překladače. Hybridní (kombinované) překladače svými vlastnostmi spadají na pomezí těchto dvou typů.
3.2 Překladače 23 Tab. 1: Srovnání vlastností kompilačního a interpretačního překladače. Zdroj: Programování překladačů, 2008 Vlastnost Kompilátor Interpret Rychlost běhu cílového programu lepší Rychlost spuštění cílového programu lepší Rychlost překladu lepší Spotřeba paměti operační (při běhu) lepší Spotřeba paměti cílový soubor na paměťovém médiu lepší Přenositelnost kódu mezi platformami lepší Možnosti optimalizace lepší Nezávislost na překladači lepší 3.2.4 Podrobná klasifikace překladačů Jak již kapitola 3.2.3 Typy překladačů naznačila, bylo by naivní myslet si, že existují jen překladače do nativního nebo virtuálního strojového kódu. Tato kapitola Vás obeznámí s nejpoužívanějšími typy překladačů současnosti. Rozdělení vychází z knihy Trustworthy Compilers (Sofanov, 2010) a nejrozšířenějšími typy překladačů jsou: kompilátory (generační překladače) interprety křížové překladače (cross-compilers) umožňují vytvořit spustitelný kód pro jinou platformu, než tu na které je překlad prováděn. Hlavně se využívá pro kompilaci kódu pro zařízení s pomalým procesorem, na kterých by kompilace trvala dlouho, inkrementální překladače oblíbené v 70. letech, umožňují po drobné opravě přeložit jen změněnou část. Drobné změny lze provádět během ladění programu, converters slouží pro překlad zdrojových kódů napsaných v jednom vyšším jazyce do jiného. Používají se při reengineeringu k portování 3 programů napsaných ve starších jazycích (např. COBOL) do novějších (např. Java nebo C#). Dalším důvodem pro použití tohoto přístupu je výzkum zaměřený na rozšíření programovacího jazyka o pokročilé prvky: v tomto případě rozšíření mohou být implementována přeměnou na základní jazykové konstrukce a specifickým voláním API, JIT překladače JIT představují hybridní přístup založený na skutečnosti, že tzv. mezikód je místo interpretování nejprve přeložen a ihned poté spuštěn. 3 S překladači úzce souvisí pojem portování. Jde o proces přenesení operačního systému nebo programu na jinou platformu, v případě operačních systémů hardwarovou jiný typ počítače (především procesoru, s jinou instrukční sadou), v případě ostatních programů spíše softwarovou (na jiný operační systém) nebo se změna musí týkat hardwarové i softwarové platformy (ovladače nebo jakékoliv programy psané v nižším programovacím jazyce). Může jít i o nutnost provedení změn přímo ve zdrojovém kódu, nejen samotný překlad (Vavrečková, 2008).
3.2 Překladače 24 K překladu přitom dochází až při prvním konkrétním požadavku na volání příslušné části mezikódu, odsud název just in time (ve smyslu: na poslední chvíli ). JIT překladače jsou neodmyslitelnou součástí Javy a.net technologií, předčasné překladače (ahead-of-time (AOT ) compilers nebo prekompilátory) tedy takové, které překládají program do nativního kódu ještě před jeho spuštěním a uchovávají ho pak v této přeložené podobě. Výhody jsou zřejmé lepší výkon než u JIT překladačů (k překladu nedochází při každém startu programu) a nezávislost na nutnosti instalovaného JIT interpreteru na vykonávajícím počítači. Nevýhodou je pak výrazné zvětšení velikosti programu, binární překladače jsou překladače přímo z binárního kódu jedné platformy do binárního kódu jiné platformy, a to bez použití zdrojového kódu. Binární kompilace se používá jako metoda portace aplikací ze starších hardwarových platforem do novějších, grafové překladače jedná se o překladače překládající některé grafům podobné reprezentace programů (spíše než jejich zdrojový kód) do jiných grafů nebo do kódů napsaném v některém z vyšších programovacích jazyků nebo strojového jazyka. Grafové kompilátory jsou nyní hojně užívány ve vědě a v průmyslu, obzvláště v elektronickém průmyslu pro návrh a vývoj very large scale integration (VLSI ) obvodů. 3.2.5 Zpracování chyb Kromě překladu jednoho jazyka na druhý musí překladače dál poskytovat informace pro ladění programu a vyhledávat chyby ve zdrojovém textu. Pokud překladač objeví během jakékoliv fáze překladu ve zdrojovém programu chybu, musí uživateli poskytnout chybové hlášení obsahující jasné a přesné informace o: umístění chyby v programu (např. jméno souboru, číslo řádku a pozice na něm), typu chyby (např. chybějící středník ), některé překladače mohou navrhnout i způsob opravy, nikdy se však nesmí pokusit chybu opravit samy, bez vědomí uživatele (Vavrečková, 2008). Překladač může na chybu reagovat dvojím způsobem: při prvním výskytu chyby se zastaví, provede diagnózu, informuje uživatele a čeká až bude chyba opravena (například jazyk Turbo Pascal), pokouší se nalézt co nejvíce chyb najednou, pozastaví se až při dosažení určitého počtu a informuje uživatele o všech objevených chybách (například C++) (Vavrečková, 2008). Druhý způsob využívá postup zvaný zotavení po chybě. Umožňuje opravit více chyb naráz bez nutnosti pokaždé spouštět překladač. Může však nastat situace, kdy výskyt jedné chyby ovlivní výskyt řady dalších. Typickým příkladem je překlep při
3.3 Vybrané objektově orientované jazyky a jejich překladače 25 deklaraci proměnné či procedury, potom všechna použití správného názvu jsou již považována za chybná. Zotavení po chybě obvykle probíhá následovně. Příslušný analyzátor načítá prvky ze vstupu naprázdno bez další reakce tak dlouho, dokud se nepodaří navázat na předchozí správný průběh překladu, pak pokračujeme běžným způsobem (Vavrečková, 2008). Běžné chyby v programování můžeme rozdělit do tří kategorií: chyby související se strukturou programu (většinou lexikální nebo syntaktické). Takové chyby lze obvykle odhalit již při překladu, chyby běhové (run-time), například dělení nulou popřípadě použití neinicializovaného indexu pole. Jedná se o chyby, které mohou nastat pouze za běhu programu. Souvisí obvykle s momentální hodnotou proměnných a lze je jen těžko identifikovat (některé překladače při zjištění možnosti run-time chyby generují varování warning), chyby logické touto chybou může být v podstatě cokoliv od chybné posloupnosti příkazů, přes záměnu operátorů a překlepy v číslech či operátorech až po nekonečnou smyčku, protože neaktualizujeme hodnotu proměnné použité v podmínce smyčky. Tyto chyby nelze při překladu prakticky odhalit, protože program může být sice dobře syntakticky zformován, nicméně nemusí odrážet programátorův záměr (Vavrečková, 2008). 3.3 Vybrané objektově orientované jazyky a jejich překladače Jednou z prvních otázek, která Vás v souvislosti s touto prací napadne, je bezesporu ta, jaké objektově orientované jazyky budou vybrány pro porovnání schopností jejich překladačů. Jen v současné době jsou používány téměř dva tucty objektově orientovaných jazyků a k nim samozřejmě existuje mnoho překladačů. Podle zadání diplomové práce bylo třeba rozdělit objektově orientované jazyky podle míry implementace objektového přístupu. Rozdělením jsme dostali 2 skupiny jazyků čistě objektové a hybridní (objektové). V souladu se zadáním bylo dále třeba z každé skupiny vybrat vhodné zástupce. Avšak nutno podotknout, že v běžné praxi se s čistě objektovými jazyky takřka nesetkáme, výjimkou je pouze Ruby. To je zapříčiněno jejich koncepcí, která není zdaleka tak univerzální, jako u hybridních jazyků. Navíc čistě objektové jazyky nejsou vhodné pro začínající programátory, jimž především by měly výsledky práce pomoci při výběru nejvhodnějšího překladače podle navolených kritérií. Díky zmíněným důvodům se práce zaměřila pouze na hybridní objektově orientované jazyky. I tak je hybridních jazyků mnoho, dále je lze rozlišit dle způsobu překladu a spuštění, statiky/dynamiky atd. Je zřejmé, že je velmi obtížné vymezit nějakou větší skupinu jazyků totožných vlastností a srovnat rysy jejich překladačů. Z tohoto důvodu byly vybrány pro daný účel sice poměrně nesourodé objektové (hybridní) jazyky, ale jedná se o jedny z nejpoužívanějších programovacích jazyků současnosti. Patří sem C++, Java a C#. Jedná se o přední komerční jazyky, z nichž
3.3 Vybrané objektově orientované jazyky a jejich překladače 26 lze za určitých podmínek hovořit o Javě a C#, jako o čistě objektových jazycích. Takže úmyslné odklonění od záměru není až tak výrazné. Před samotnou charakterizací překladačů vybraných OO jazyků je třeba zdůraznit, že pro účely posouzení jejich schopností byly vybrány pouze volně dostupné kompilátory daných jazyků. 3.3.1 C++ Programovací jazyk C++ vytvořil Bjarne Stroustrup tím, že do jazyka C přidal podporu objektově orientovaného programování. Stroustrup založil C++ na stručnosti C, jeho vhodnosti pro systémové programování, široce rozšířené dostupnosti a jeho úzké vazbě na operační systém UNIX. Hledisko OOP bylo inspirováno počítačovým simulačním jazykem Simula67 (C, C++, C#, 2004). C++ je hybridní OOJ, protože sice roubuje OOP na C, lze však ignorovat objektově orientované rysy jazyka C++. Jakmile dosáhl jazyk C++ jistého úspěchu, Stroustrup dodal šablony, umožňující programování pomocí šablon. Skutečnost, že C++ zahrnuje jak OOP, tak programování pomocí šablon, je jedním z důvodů úspěchu tohoto jazyka. C++ je kompilovaný jazyk. Přesné kroky vytváření programu závisí na prostředí počítače a použitém kompilátoru C++. Budou se však podobat následujícím krokům: 1. Máme k dispozici zdrojové kódy programy, příslušné hlavičkové soubory a rozhodneme se pro překlad. 2. Prvním z nástrojů podílejícím se na překladu je tzv. preprocesor. Preprocesor je speciální program používaný v jazycích C a C++ pro zpracování maker a symbolických konstant. Tento program se v podstatě stará jen o textovou náhradu definovaných symbolů v textu a umožňuje podmíněný překlad. Příkazy pro preprocessor začínají vždy znakem mřížky (#), například #define nebo #ifndef. Jedná se o program, který může existovat samostatně, ale většinou bývá součástí kompilátoru. 3. Kompilátor, též překladač, je program překládající zdrojový text programu do strojového jazyka. Výsledkem tohoto překladu obvykle není spustitelný program, protože v místech kde se volají podprogramy z jiných modulů a knihoven, nejsou konkrétní adresy těchto podprogramů, ale pouze značky, které se zpracují později při linkování, ale jsou jím objektové soubory. 4. Objektové soubory je třeba nějak spojit do funkčního celku. K tomu slouží program nazývaný linker. Proces linkování spočívá ve zjišťování, zda každá použitá funkce či proměnná existuje v některém z objektových souborů, k sestavení samostatně přeložených modulů, připojení inicializačního kódu a k vytvoření spustitelné verze programu (Prata, 2001).
3.3 Vybrané objektově orientované jazyky a jejich překladače 27 Vybrané překladače: GCC (G++) GCC představuje zkrácený zápis pro GNU Compiler Collection. Jak z názvu vyplývá, jedná se o kolekci překladačů pro následující programovací jazyky C, C++, Objective-C, Fortran, Java, Ada a Go. Současná verze GCC 4.6.1 byla uvolněna 27. června 2011 (K dispozici na adrese: http://gcc.gnu.org/gcc-4.6/). GCC překladače v současné době fungují na většině platforem. I ve Windows lze používat překladač GCC, jehož port do prostředí Windows se jmenuje MinGW. Dále existuje projekt Cygwin, jehož cílem je portovat všechny standardní GNU programy do systému Windows (http://www.fit.vutbr.cz/~martinek/clang/devwin.html). DJGPP pak představuje port GCC pro DOS. Jedná se o 32-bitový C /C++ vývojářský systém pro Intel 80386 (a vyšší) počítače se systémem DOS. Ten se však nepodařilo na 64 bitovém OS MS Windows 7 rozjet ani za využití DOSBoxu, a tudíž jeho schopnosti nebudou zanalyzovány. Tento problém nastal proto, že procesory x86-64 v tzv. long módu nepodporují virtuální 8086 mód používaný ke spuštění 16 bitového kódu v IA-32 procesorech (http://en.wikipedia.org/wiki/djgpp). GCC, respektive jeho port na Windows MinGW, je součástí řady vývojových prostředí jako Code::Blocks či Dev-C++. Microsoft Visual C++ 2010 Express Microsoft Visual C++ 2010 Express je k dispozici zdarma přímo od společnosti Microsoft. Software obsahuje integrované vývojové prostředí (IDE). Nová verze C++ kompilátoru, obsažená v balíčku programů Microsoft Visual Studio 2010 Express, obsahuje podporu pro některé vlastnosti jazyka C++ podle standardu C++0x jako jsou lambda výrazy, R-value reference (umožňují programátorům vyhnout se logicky zbytečnému kopírování a poskytnout perfektní směrování funkcí), klíčová slova auto (k deklaraci proměnných jejichž typ je odvozen od inicializace výrazu při deklaraci proměnné), static assert (slouží k ověření, zda jsou splněny určité podmínky), nullptr (pro ukazatel nikam je definována zvláštní hodnota vyjádřená právě tímto klíčovým slovem) a decltype (podobný staršímu operátoru typeof) (K dispozici na adrese: http://www.microsoft.com/visualstudio/en-us/products/2010-editions /visual-cpp-express). Borland C++ překladač verze 5.5 Borland C++ Compiler 5.5 (BCC ), uvolněný na trh v roce 2000, je základem a zásadní technologií C++ Builder 5. Jedná se o velmi rychlý 32- bitový překladač. Obsahuje nejnovější ANSI/ISO C++ jazykovou podporu včetně STL (Standard Template Library) rámce, C++ šablon a kompletní Borland C/C++ Runtime Library (RTL). Rovněž jsou volně dostupné ke stažení Borland C/C++ nástroje příkazového řádku, jako je vysoce výkonný Borland linker a kompilátor zdrojů. V červenci roku 2008 se vlastníkem Borland