Analiza tipurilor Generarea codului
Definirea unei masini virtuale.
Interpretorul de cod virtual



Notiuni generale

Masina virtuala este un calculator imaginar, dotat cu un set de instructiuni ce constituie limbajul (codul) virtual.

Lucrul cu cod virtual decurge astfel: textul sursa este tradus de catre compilator in limbaj virtual; programul rezultat constituie intrare pentru o procedura numita executiv, care este de fapt un interpreter al limbajului virtual. Executivul este scris intr-un limbaj recunoscut de calculatorul tinta (cel pe care urmeaza sa ruleze programul compilat). Rolul executivului este acela de a parcurge codul virtual obtinut de la compilator si de a executa fiecare instructiune, in termenii limbajului masina al calculatorului tinta .

Avantajul acestui mod de lucru este acela ca daca un limbaj sursa trebuie tradus in mai multe limbaje obiect, compilatorul propriu-zis se scrie o singura data (el genereaza doar cod virtual), iar pentru fiecare limbaj obiect se construieste cate un executiv. A scrie un executiv este un lucru mult mai usor decat a scrie un compilator. Pe de alta parte, programul generat in cod virtual poate fi transportat pe orice masina dotata cu interpreterul codului respectiv, deci programul are o portabilitate crescuta.
Compilatoarele de Java, spre exemplu, genereaza cod virtual (numit byte-code). Astfel, un applet, care este de fapt un program Java compilat poate fi incarcat si executat de catre un browser de web dotat cu interpreter de byte-code, chiar in conditiile in care applet-ul si browser-ul se afla pe calculatoare care functioneaza sub sisteme de operare diferite.
Un dezavantaj al lucrului cu cod virtual este acela ca viteza de executie a programelor respective este mai mica, deoarece ele sunt executate "software" (prin intermediul interpreterului) si nu "hardware" (direct de catre procesor).

Limbajul virtual si structura masinii virtuale sunt stabilite in principiu de catre proiectantul compilatorului, dupa urmatoarele criterii:

In general, limbajul virtual este inspirat din limbajele de asamblare existente la un moment dat, avand insa un grad ceva mai mare de abstractizare.
 

Arhitectura masinii virtuale

In cele ce urmeaza vom descrie o masina virtuala simpla (fig.10.1) la a carei conceptie s-a tinut cont de specificul limbajului sursa prezentat in Anexa B. Pentru aceasta masina se propune un limbaj virtual prezentat in Anexa C.

Masina este compusa dintr-o unitate centrala si o memorie operativa.
Unitatea centrala este dotata cu urmatorii registri:

Fig.10.1.Configuratia masinii virtuale

Memoria operativa cuprinde urma toarele structuri:


Trebuie mentionat faptul ca cele trei tabele enumerate mai sus reprezinta practic interfata dintre compilator si executiv. Aceste tabele sunt completate de catre compilator si apoi utilizate de executiv. Tabela TAB_ERR este completata partial de compilator (prima parte a tabelei) si partial de executiv. Acest lucru se intampla deoarece erorile la executie pot fi de doua feluri:

Numarul mesajelor completate de compilator apare ca parametru intr-una din locatiile rezervate la inceputul tabelei de cod.

Se poate spune ca cele trei tabele formeaza impreuna programul obiect.
 
 

Functionarea masinii virtuale

Este simulata prin intermediul executivului care este descris mai jos in pseudocod:

procedure EXECUTIV is
*completeaza tabela TAB_ERR  incepand cu prima intrare libera
NI = *adresa de start a programului principal
SP = *dimensiunea spatiului variabilelor din programul principal
ST = 'activ'
VBAZA = 0, BAZA[0].LEVEL = 1, BAZA[0].BLOC = 0
repeat
selectTAB_COD[NI] of
LOD: *interpreteaza LOD
LODI: *interpreteaza LODI

. . . *se insira toate codurile

default: *eroare la executie 'instructiune nerecunoscuta '

endselect
until ST <> 'activ'
if ST = 'err' then
*afiseaza mesajul din TAB_ERR [ IE ]
endif
end EXECUTIV
Valorile cu care se initializeaza registrii NI si SP, respectiv indicele primei intrari libere din TAB_ERR se afla memorate la inceputul tabelei de cod, ele fiind depuse acolo de catre compilator (v. Lucrarea nr.11).
Executarea instructiunii curente (indicata de NI) presupune interpretarea acelei instructiuni in termenii limbajului masina pe care ruleaza executivul. In Anexa C fiecare instructiune este insotita de o descriere in pseudocod a efectului ei. Instructiunile sunt codificate cu ajutorul mnemonicelor, carora le corespund coduri numerice alese de proiectantul masinii virtuale. Daca se utilizeaza limbaje ca Pascal sau C pentru scrierea compilatorului si/sau a executivului, codurile instructiunilor virtuale se pot reprezenta cu ajutorul unui tip enumerare.
Obs: eroarea de tip 'instructiune nerecunoscuta' face parte din categoria celor detectate de executiv. Ea ar putea sa apara fie din cauza unei functionari incorecte a compilatorului, care ajunge sa completeze TAB_COD in mod necorespunzator, fie ca urmare a coruperii zonei de memorie in care se afla TAB_COD. La detectarea unei erori de executie de catre executiv, se va pozitiona registrul IE astfel incat sa indice un mesaj adecvat, iar registrul ST pe valoarea err, determinandu-se astfel parasirea buclei din procedura EXECUTIV.
Pentru a se ilustra modul de implementare in cadrul executivului a executiei unei instructiuni virtuale, se iau ca exemplu instructiunile EQU si CALL:
 
selectTAB_COD[NI] of
. . .
EQU:
SP = SP - 1
if STIVA[SP + 1] = STIVA[SP] then
STIVA[SP].INFO = 1
else
STIVA[SP].INFO = 0
endif
STIVA[SP].TIP_NOD = 'intreg'
NI = NI + 1
CALL:
VBAZA = VBAZA + 1
BAZA[VBAZA].LEVEL = TAB_COD[NI + 3]
BAZA[VBAZA].BLOC = SP - TAB_COD[NI + 2] + 1
SP = SP + STIVA[BAZA[VBAZA].BLOC -1].INFO
STIVA[BAZA[VBAZA].BLOC - 1].INFO = NI + 4
NI = TAB_COD[NI + 1]
. . .
endselect
Obs: in secventa corespunzatoare instructiunii CALL, elementele de forma TAB_COD[NI + ...] reprezinta argumentele instructiunii.
 

Desfasurarea lucrarii

Se va proiecta un executiv pentru limbajul virtual propus in Anexa C. Testarea executivului se va realiza astfel: se completeaza manual, intr-un fisier, o tabela de constante si o tabela de cod. In aceasta din urma se pun instructiuni virtuale intr-o ordine oarecare, avand insa grija la instructiunile de salt, deoarece se poate ajunge in situatii de buclare infinita .
Executivul va incarca tabela de constante si pe cea de cod din fisier, apoi va prelucra fiecare instructiune afisand totodata informatii de control care sa permita urmarirea continutului stivelor (STIVA si BAZA) si al registrilor masinii.
Se recomanda ca, pentru instructiunile care implica adaugari de noduri in stivele masinii virtuale sa se prevada verificari privind depasirea spatiului alocat stivelor. Situatiile de depasire vor constitui erori de executie.

Analiza tipurilor Generarea codului