Sunteți pe pagina 1din 7

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:

comenzile virtuale sa fie suficiente pentru a permite transpunerea corecta a instructiunilor limbajului sursa; functionarea masinii virtuale sa poata fi cat mai usor de simulat cu ajutorul executivelor, pentru fiecare limbaj obiect.

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:

SP: indicatorul varfului stivei de lucru (STIVA); VBAZA: indicatorul varfului stivei BAZA; NI: registrul adresei program (numaratorul de instructiuni). Contine indicele intrarii curente din tabela de cod (TAB_COD); ST: registrul de stare. Poate sa contina una din valorile: o 'activ' = program n curs de executie o 'stop' = oprire normala a programului o 'err' = oprire a programului la detectarea unei erori de executie; RX: registru index, utilizat pentru lucrul cu elemente de tablou sau cu campuri de structura; IE: registru indicator de eroare. Contine un indice in tabela mesajelor de eroare, pozitionat in momentul detectarii unei erori de executie.

Fig.10.1.Configuratia masinii virtuale Memoria operativa cuprinde urma toarele structuri:

Stiva de lucru (STIVA): contine valorile variabilelor si ale parametrilor din blocurile de program active la un moment dat, rezultate intermediare ale calculelor si adrese. Un nod al stivei este format din doua campuri: o TIP_NOD: indicator al tipului informatiei din nod. Poate lua una din valorile: 'ntreg', 'real', 'caracter' sau 'adresa'; o INFO: informatia propriu-zisa din nod. Obs: practic, campul TIP_NOD este important pentru a distinge nodurile care contin adrese, de restul nodurilor. Acest lucru este necesar daca limbajul sursa permite si transmiterea prin adresa a parametrilor subprogramelor.

Stiva pentru apeluri de subprograme (BAZA): are cate o intrare pentru fiecare bloc de program activ la un moment dat. Un nod al acestei stive contine urmatoarele informatii: o BLOC = un indice spre inceputul zonei alocate pentru blocul respectiv in stiva de lucru;

LEVEL = nivelul de incuibare al blocului.

Tabela de cod (TAB_COD): o secventa de numere intregi reprezentand codul virtual rezultat prin compilarea programului sursa. Un numar prestabilit de intrari de la inceputul tabelei sunt rezervate pentru valori utilizate de executiv la initializari, inainte de lansarea in executie a unui program. Tabela de constante (TAB_CONST): contine valorile constantelor intalnite in textul sursa (v. Lucrarea nr.1).

Obs: tabela de constante este de fapt o structura optionala, utilizata cu scopul simplificarii modului de reprezentare a tabelei de cod. De exemplu, instructiunea LODI - incarcare imediata (v. Anexa C) are ca argument chiar valoarea care urmeaza a fi depusa in varful stivei de lucru. Cum aceasta valoare poate fi de diferite tipuri, ar insemna ca locatiile tabelei de cod sa fie de tip articol cu variante ( sauunion). Utilizand tabela de constante, argumentul instructiunii LODI va fi totdeauna un numar intreg (indice spre TAB_CONST).

Tabela mesajelor de eroare (TAB_ERR): contine mesaje corespunzatoare erorilor de executie.

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. TabelaTAB_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:

detectate in cursul unor secvente de verificare generate de compilator (de exemplu verificarea nedepasirii limitelor indicilor de tablouri), caz in care secventele respective contin instructiuni speciale de oprire fortata a executiei (v. Anexa C, instructiunea ERR). Argumentul unei asemenea instructiuni este indicele in tabela TAB_ERR al unui mesaj de eroare. Pentru aceasta categorie de erori mesajele sunt completate de compilator; detectate de executiv (de exemplu tentativele de impartire cu 0 sau depasirile limitelor de reprezentare a numerelor). Mesajele corespunzatoare acestor situatii sunt completate de executiv.

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.

S-ar putea să vă placă și