![]() |
![]() |
![]() |
![]() |
Programmi
täitmine (execution) toimub alati mingis konkreetses
operatsioonisüsteemis ja konkreetses protsessoris. Kuna protsessorid ja
operatsioonisüsteemid on erinevad, vajatakse klassikalise
transleerimissüsteemi järgi transleeritavate keelte (C, C++
jne) iga keskkonna (protsessor+operatsioonisüsteem) jaoks oma
translaatorit, mis teisendab talle esitatud programmi teksti just selle
protsessor+operatsioonisüsteemi jaoks: Windows-PC jaoks oma (ja
erinevate Windows-i versioonide - 16-bitise, 32-bitise ja 64-bitise
jaoks samuti erinevat), Linux-PC jaoks oma, Unix-tööjaamade jaoks oma
jne. On arusaadav, et sellise tehnoloogia kasutamisel vajatakse
programmeerimiskeele jaoks palju translaatoreid ja on väga raske
tagada, et programm esinevates keskkondades annaks alati täpselt sama
tulemuse. Olukorda muudab veel keerulisemaks see, et translaatoreid
valmistavad erinevad firmad (Microsoft, Borland, IBM jt), kes sageli
tõlgendavad programmeerimiskeele kirjeldust/standardit veidi erinevalt;
tulemuseks on olukord, kus peaaegu alati mingi suurema programmi
täitmise tulemustest rääkides mainitakse kindlasti ka see, millise
translaatoriga programm transleeriti ja millises keskkonnas see
käivitati, sest erinevate translaatorite ja keskkondade puhul on
tulemused sageli (veidi) erinevad.
Erinevat
lähenemist kasutati Java keele loomisel - programm transleeritakse
kahes etapis, esimeses etapis on tulemuseks konkreetsest keskkonnast
sõltumatu, s.t. kõigi arvutite/opsüsteemide jaoks ühesugune vahekuju
(Java baitkood, bytecode), mis alles teises etapis tõlgendatakse
konkreetse protsessori/opsüsteemi jaoks sobivale kujule. Kuna vahekuju
on väga madala tasemega, on teine etapp suhteliselt lihtne ja seda
sooritav programm VM (Virtual
Machine, virtuaalarvuti) suhteliselt väike, see võimaldabki Javat
kasutada väga piiratud võimalustega keskkondades, näiteks
mobiiltelefonides. Java puhul oli see "leiutis" tegelikult
poolsunnitud, sest Java-t ei planeeritud esialgselt üldse
üldkasutatavaks programmeerimiskeeleks, vaid interaktiivse televisiooni
jaoks (Javat hakati arendama 1991, kui Intenet-i praegusel kujul polnud
üldse veel olemaski) ja Java oli planeeritud televiisorite
lisaseadmete, nn "set-top" seadmete programmeerimiseks; kuna need oleks
olnud samuti piiratud võimalustega ja väga erinevad, pidi
transleerimise kavandama nii, et see viimane etapp oleks võimalikult
lihtne. Kuid mitmesuguseid vahekeeli oli kasutatud ka varem, paljudes
programmeerimiskeeltes ja -süsteemides kasutatav täitmissüsteem
(run-time system) on samuti sisuliselt virtuaalmasin, kuid kuid
tavaliselt vaid mingi konkreetse protsessori+opsüsteemi jaoks.
Sama vahekeelt kasutatakse sageli mitme erineva programmeerimiskeele translaatori jaoks, näiteks GNU gcc translaatorite süsteemis kasutatakse vaheleelt RTL (Register Transfer Language) nii C, Ada, Fortrani kui ka teiste gcc translaatorite süsteemis realiseeritud keelte transleerimisel; sama vahevormi kasutamine lihtsustab ka nn rist-translaatorite (cross-translators) loomist, mis transleerivad ühest kõrgkeelest (näiteks Pascal-ist) teise (näiteks Ada-sse).
Java eeskujul võttis ka Microsoft oma .net programmeerimissüsteemis kasutusele vahekeele MSIL (Microsoft Intermediate Language), esimesena kasutatati seda programmeerimiskeele C#
transleerimisel. MSIL-i virtuaalmasinat/täitmissüsteemi nimetatakse
.net-ümbruses CLR (Common Language Runtime) ja see on projekteeritud
nii, et seda saaks kasutada paljude programmeerimiskeelte
transleerimisel: APL, C, C++, C#, COBOL, Eiffel, Forth, Fortran, Hasell
jne - selle omadused (sisseehitatud andmetüübid ja käsud) peaks sobima
rohkem kui kahekümnele programmeerimiskeelele.
Translaatorite teoorias on kõige tuntumaid vahekeeli nn kolmeaadressiline kood. Kolmeaadressilise koodi versioone on mitmesuguseid, erinevate operatsioonide ja andmestruktuuridega, kuid neis kõigis kasutatakse vaid järgmise kujuga arvutuskäske:
x = y op z
x = op y
x = y
"Kõrgema taseme" kolmeaadressilises koodis võivad olla lubatud ka alamprotseduurid; nende argumentide tähistamiseks kasutatakse võtmesõnu param, call ja koodilõik
param x1
param x2
...
param xn
call p, n
Kolmeaadressilise koodi töö juhtimiseks kasutatakse vaid suunamiskäske kujul
goto M
if x relop y goto M
Sellised suunamiskäsud on realiseeritud ka enamuses protsessoritest, sellepärast on kolmeaadressilise koodi teisendamine masinkoodiks või assembleriks väga lihtne, kui näiteks x,y on 32-bitised täisarvud, vastab kolmeaadressilise koodi käsule
x = y + z
järgnev kõrgtaseme assembleri HLA koodilõik
mov(y, eax)
mov(z, ebx)
add(eax, ebx)
mov(ebx, x)
Vahekeelena võib kasutada ka Java baitkoodi tekstilisi kujusid; Java virtuaalarvuti VM jaoks on juba loodud üle kahesaja mitmesuguse keele.