A fordító olyan program, amely egy programozási nyelven írt szöveget gépi kódok halmazává fordítja [1] [2] [3] .
Összeállítás - a program összeállítása, beleértve:
Ha a fordító végrehajtható gépi nyelvű programot állít elő, akkor az ilyen programot közvetlenül egy fizikai programozható gép (pl. számítógép) hajtja végre. Más esetekben a végrehajtható gépi programot a megfelelő virtuális gép hajtja végre .
A fordító bemenete:
A fordító kimenete az algoritmus egyenértékű leírása géporientált nyelven (objektumkód [5] , bájtkód ).
Fordítás - gépi program összeállítása, beleértve:
A magas szintű nyelvek fordítói gyakran csak a forráskód fordítását végzik el, miközben a hivatkozást egy külső linkerre bízzák, egy linkerre, amely egy független programot képvisel, amelyet a fordító külső szubrutinként hív meg. Ennek eredményeként a fordítót sokan egyfajta fordítónak tartják, ami helytelen ...
Ezenkívül az összes fordító feltételesen két csoportra osztható:
Összeállítás típusai [2] :
Az összeállítási folyamat a következő lépésekből áll:
A strukturális fordítói megvalósítások a következők lehetnek:
Az első séma szerint a legelső fordítók épültek - a modern fordítók számára egy ilyen konstrukciós séma nem jellemző.
A második séma szerint kivétel nélkül az összes fordítóprogram magas szintű nyelvekből épül fel. Bármely ilyen fordító maga csak fordítást hajt végre, majd külső szubrutinként meghívja a linkert, amely összekapcsolja a géporientált programot. Egy ilyen felépítési séma könnyen lehetővé teszi a fordító számára, hogy a megfelelő programozási nyelvből fordító módban dolgozzon. Ez a körülmény gyakran arra ad okot, hogy a fordítót egyfajta fordítónak tekintsük, ami természetesen téves – minden ilyen típusú modern fordító még mindig végez linkelést, igaz, a fordító által meghívott külső linker segítségével, miközben maga a fordító soha nem hív a külső linker. Ugyanez a körülmény azonban lehetővé teszi, hogy az egyik programozási nyelv fordítója a linkelési fázisban az egyik programozási nyelven írt programba olyan függvényeket-szubrutinokat vegyen fel, amelyeket a megfelelő fordító/fordító már lefordított, és egy másik programnyelven íródott. Így Pascal vagy Fortran nyelven írt függvényeket illeszthet be egy C/C++ programba . Hasonlóképpen, és fordítva, a C/C++ nyelven írt függvények beilleszthetők egy Pascal vagy Fortran programba. Ez lehetetlen lenne számos modern fordító támogatása nélkül, amelyek más programozási nyelvek konvencióinak megfelelően kódokat generálnak az eljárások (függvények) meghívásához . Például a modern Pascal nyelvű fordítók azon túl, hogy magában a Pascal-szabványban szervezik az eljárás-/függvényhívásokat, támogatják az eljárás/függvényhívások C/C++ nyelvi konvencióknak megfelelő megszervezését. (Például ahhoz, hogy egy Pascal nyelven írt eljárás/függvény a C/C++ nyelv konvencióinak megfelelően gépi kód szintű bemeneti paraméterekkel működjön, egy ilyen Pascal eljárás/Pascal függvény deklarációs utasításának tartalmaznia kell a cdecl kulcsszó .)
Végül a harmadik séma szerint fordítókat építenek, amelyek teljes rendszerek, amelyek különböző programozási nyelvekből származó fordítókat és linkereket tartalmaznak. Ezenkívül bármely ilyen fordító fordítóként használhat bármely fordítóképes fordítót egy adott magas szintű nyelvből. Természetesen egy ilyen fordító képes olyan programot fordítani, amelynek a forrásszöveg különböző részei különböző programozási nyelveken vannak megírva. Az ilyen fordítókat gyakran egyik vagy másik parancsnyelv beépített értelmezője vezérli. Az ilyen fordítók szembetűnő példája a fordító elérhetővé tétele minden UNIX rendszeren (különösen Linuxon) .
A program fordítása, mint az összeállítás szerves része, a következőket tartalmazza:
A legtöbb fordítóprogram lefordítja a programot valamilyen magas szintű programozási nyelvről gépi kódra , amelyet egy fizikai processzor közvetlenül végrehajthat . Általában ez a kód is egy adott operációs rendszer környezetében való végrehajtásra összpontosít , mivel az általa biztosított képességeket használja ( rendszerhívások , függvénykönyvtárak). Azt az architektúrát (szoftver- és hardverkészletet), amelyre egy géporientált programot fordítanak (összeállítanak), célgépnek nevezzük .
A fordítás eredménye - egy végrehajtható programmodul - a lehető legnagyobb teljesítményt nyújtja, de egy adott operációs rendszerhez (OS család vagy alcsalád) és processzorhoz (processzorcsalád) van kötve, és nem működik másokon.
Minden célgép ( IBM , Apple , Sun , Elbrus stb.) és a célgépen futó minden operációs rendszer vagy operációs rendszercsalád saját fordítóprogramot igényel. Léteznek úgynevezett keresztfordítók is, amelyek lehetővé teszik egy gépen és egy operációs rendszer környezetében, hogy egy másik célgépen és/vagy egy másik operációs rendszer környezetében végrehajtható kódot generáljanak. Ezenkívül a fordítók optimalizálhatják a kódot ugyanazon processzorcsalád különböző modelljeihez (a modellspecifikus funkciók vagy az utasításkészlet-kiterjesztések támogatásával). Például a Pentium család processzorai számára összeállított kód figyelembe veheti az utasítások párhuzamosításának jellemzőit, és használhatja azok speciális kiterjesztését - MMX , SSE stb.
Egyes fordítók magas szintű nyelvről nem közvetlenül gépi kódra, hanem assembly nyelvre fordítanak le egy programot . (Példa: PureBasic , a BASIC kód lefordítása FASM assemblerre .) Ez a fordító kódgeneráló részének egyszerűsítése és a hordozhatóság növelése érdekében történik (a végső kódgenerálás és a szükséges célplatformhoz való kapcsolódás feladata az assemblerre hárul ), vagy hogy az összeállítási eredményt (beleértve a kézi optimalizálást is) a programozó ellenőrizhesse és korrigálni tudja.
A fordító munkájának eredménye egy speciálisan létrehozott , bináris kódú parancsokból álló alacsony szintű nyelvű program lehet, amelyet egy virtuális gép hajt végre . Az ilyen nyelvet pszeudokódnak vagy bájtkódnak nevezik . Ez általában nem egy számítógép gépi kódja, és a rajta lévő programok különböző architektúrákon futtathatók, ahol van egy megfelelő virtuális gép, de bizonyos esetekben hardverplatformok jönnek létre, amelyek közvetlenül végrehajtják bármely nyelv pszeudokódját. . Például a Java nyelvi pszeudokódot Java bájtkódnak hívják, és a Java virtuális gépen fut , és a picoJava processzorspecifikációt annak közvetlen végrehajtására hozták létre . A .NET-keretrendszer esetében a pszeudokód neve Common Intermediate Language (CIL), a futási környezet pedig Common Language Runtime (CLR).
A magas szintű értelmezett nyelvek egyes implementációi (például a Perl) bájtkódot használnak a végrehajtás optimalizálására: a programszöveg elemzésének és bájtkóddá alakításának költséges lépései betöltéskor megtörténik, majd a megfelelő kód újrafordítás nélkül újra felhasználható.
Az értelmezési igény miatt a bájtkód sokkal lassabban fut, mint a hasonló funkcionalitású gépi kód, de hordozhatóbb (nem függ operációs rendszertől és processzormodelltől). A bájtkód végrehajtásának felgyorsítása érdekében dinamikus fordítást alkalmaznak , amikor a virtuális gép közvetlenül az első végrehajtás előtt lefordítja a pszeudokódot gépi kódra (és a kód ismételt elérésekor a már lefordított verzió kerül végrehajtásra).
A dinamikus fordítások legnépszerűbb típusa a JIT . Egy másik változat az inkrementális fordítás .
A CIL-kódot a célgépi kódhoz is a JIT-fordító fordítja, míg a .NET-keretrendszer -könyvtárakat előre lefordítják.
A bájtkód gépi kódra fordítása egy speciális bájtkód-fordító által, amint azt fentebb említettük, a dinamikus fordítás szerves fázisa. De a bájtkód fordítása akkor is hasznos, ha egy bájtkódos programot egyenértékű gépi nyelvű programmá konvertál. Előre lefordított bájtkódként gépi kódra fordítható. De a bájtkód gépi kódra fordítását is végrehajthatja a bájtkód fordító közvetlenül a bájtkód fordítása után. Ez utóbbi esetben szinte mindig a bájtkód fordítást egy külső fordító hajtja végre, amelyet a bytecode fordító hív meg.
Vannak programok, amelyek megoldják az inverz problémát - egy program lefordítása alacsony szintű nyelvről magas szintű nyelvre. Ezt a folyamatot dekompilációnak, az ilyen programokat pedig dekompilátoroknak nevezik . De mivel a fordítás veszteséges folyamat, általában nem lehet pontosan visszaállítani a forráskódot mondjuk C++ nyelven. A bájtkódokban lévő programok hatékonyabban dekompilálhatók - például van egy meglehetősen megbízható visszafejtő a Flash számára . A dekompiláció egyik változata a gépi kód összeszerelési nyelvi kódra való szétbontása , amely szinte mindig biztonságosan fut le (ebben az esetben a bonyolultság lehet önmódosító kód vagy olyan kód, amelyben a tényleges kód és az adatok nincsenek elválasztva). Ez annak a ténynek köszönhető, hogy a gépi utasításkódok és az assembler utasítások között szinte egy-egy megfelelés van.
Külön fordítás ( eng. külön fordítás ) - a program részeinek külön fordítása, majd a linker által egyetlen betöltési modulba való kombinálása [2] .
Történelmileg a fordító jellemzője, ami a nevében is tükröződik ( eng. compile - tedd össze, compose) az volt, hogy fordítást és linkelést is készített, miközben a fordító azonnal gépi kódot tudott generálni . Később azonban a programok egyre bonyolultabbá és méretesebbé válásával (és az újrafordításra fordított idő növekedésével) szükségessé vált a programok részekre bontása és az egymástól függetlenül fordítható könyvtárak elkülönítése . A program fordítása során a fordító maga, vagy a fordító által meghívott fordító létrehoz egy további információkat tartalmazó objektummodult , amelyet azután - a részek végrehajtható modullá való összekapcsolása során - a hivatkozások összekapcsolására és feloldására használnak. a program részeit. A külön fordítás azt is lehetővé teszi, hogy egy program forráskódjának különböző részeit különböző programozási nyelveken írjuk.
A külön fordítás megjelenése és a linkelés külön szakaszként való kiosztása jóval később következett be, mint a fordítók létrehozása. Ebben a vonatkozásban a "fordító" kifejezés helyett néha a "fordító" kifejezést használják szinonimájaként: vagy a régi irodalomban, vagy amikor hangsúlyozni akarják, hogy képes egy programot gépi kódra fordítani (és fordítva, a "fordító" kifejezést használják annak hangsúlyozására, hogy sok fájlból össze lehet állítani egy). Csak a "fordító" és a "fordító" kifejezések használata ebben az összefüggésben helytelen. Még ha a fordító maga hajtja végre a program fordítását, delegálva a hivatkozást a meghívott külső linker programra, egy ilyen fordító nem tekinthető egyfajta fordítónak - a fordító végzi el a forrásprogram fordítását, és semmi több. És természetesen nem a fordítók olyan fordítók, mint a make system compiler segédprogram , amely minden UNIX rendszeren megtalálható.
Maga a make segédprogram kiváló példa a külön fordítás meglehetősen sikeres megvalósítására. A make segédprogram működését a segédprogram által értelmezett beviteli nyelven lévő szkript, az úgynevezett makefile vezérli, amely a segédprogram futtatásakor megadott bemeneti szövegfájlban található. Maga a segédprogram nem végez fordítást vagy linkelést – de facto a make segédprogram fordítói folyamatkezelőként működik, a program fordítását a megadott szkriptnek megfelelően szervezve. Konkrétan a célprogram fordítása során a make segédprogram olyan fordítókat hív meg programozási nyelvekből, amelyek a forrásprogram különböző részeit objektumkódba fordítják, majd ezt követően egy-egy linkert hívnak meg, amely összekapcsolja a végső végrehajtható programot vagy könyvtárat. programmodul. Ugyanakkor a program különböző részei, külön forrásszöveg állományokba rendezve, mind ugyanazon a programozási nyelven, mind különböző programozási nyelveken írhatók. A program újrafordítása során csak a program forráskódjának megváltozott részei-fájljai kerülnek fordításra, aminek következtében a program újrafordításának időtartama jelentősen (esetenként nagyságrenddel) lecsökken.
A számítógépek fejlődésének hajnalán az első fordítókat (fordítókat) „programozóprogramoknak” [6] nevezték (mivel akkoriban csak a gépi kód számított programnak, a „programozóprogram” pedig képes volt gépi kódot készíteni belőle. emberi szöveg, azaz számítógép programozása ).
Szótárak és enciklopédiák | ||||
---|---|---|---|---|
|