Alexei Snastin. dezvoltator de software independent, consultant
Alexei Snastin este un dezvoltator de software independent, consultant și traducător din limba engleză a literaturii tehnice și educaționale despre IT. A participat la dezvoltarea de aplicații de birou de rețea, cum ar fi client / server în limba C într-un mediu Linux.
Descriere: Primul articol al ciclului descrie caracteristicile și principiile generale ale mașinii virtuale Parrot, precum și exemple de cod sursă. Următorul articol va detalia mecanismul de compilare și instrumentele; În plus, vom vorbi despre interacțiunea dintre Parrot și diferite limbi de programare.
Utilizarea oricărui limbaj de programare implică prezența unui mecanism care convertește comenzile și instrucțiunile unei limbi în cod binar pentru sistemul țintă pe care va rula programul. Compiliatorii generează coduri de mașină corespunzătoare arhitecturii date. În cazul limbilor interpretate sau scripturi, situația este mai complicată. Acestea necesită un anumit timp de execuție, numit un interpret sau o mașină virtuală.
Până de curând, fiecare limbă interpretată "purta de-a lungul" propria sa mașină virtuală. Numele Perl, Python, Ruby nu sunt doar numele de limbi de scripting, ci și notarea interpreților, mașinile virtuale necesare funcționării lor. Nu cu mult timp în urmă, a apărut o idee, urmată de implementarea unei mașini virtualizate generalizate, care vă permite să executați în mod eficient programe în diferite limbi de programare. Numit acest papagal "poliglot". O serie de articole despre această mașină virtuală vor fi utile pentru programarea dezvoltatorilor în limbi interpretate, precum și pentru administratorii unix-sistemelor.
Deci, Parrot este o mașină virtuală. Sarcina sa principală este de a efectua instrucțiuni specializate care nu depind de o anumită platformă hardware. Codul sursă în limbile de scripting este mai întâi convertit într-un set de instrucțiuni specializate, denumite de obicei bytecode, și apoi executate în mediul de lucru al mașinii virtuale.
În prezent, Parrot poate accepta instrucțiuni de execuție în patru formate. În formatul PIR (Parrot Intermediate Representation), instrucțiunile pot fi scrise de programatori sau generate de compilatoare din diferite limbi. Acest format vă permite să ascundeți unele aspecte ale unui nivel inferior, de exemplu, modul în care sunt transmise parametrii unei funcții. Un nivel inferior PIR vă permite să renunțați la formatul PASM (Parrot Assembly), ale cărui instrucțiuni rămân accesibile citirii umane și pot fi generate de compilator. Cu toate acestea, dezvoltatorul este pe deplin responsabil pentru toate detaliile implementării: coordonarea acordurilor privind solicitările de funcții și proceduri, alocarea registrelor unei mașini virtuale și multe altele. În general, asamblorul este asamblorul - necesită o calificare înaltă a programatorului.
Formatul PAST (Tree Syntax Tree Parrot) vă permite să acceptați ca date de intrare o structură abstractă a arborelui sintactic - foarte utilă pentru cei care sunt implicați în dezvoltarea compilatoarelor.
Toate formatele descrise mai sus sunt, în orice caz, transferate automat în cel de-al patrulea format PBC (Parrot Bytecode). Bytecode este un cod binar compilat destinat exclusiv interpretului Parrot. Este puțin probabil ca o persoană să fie capabilă să citească orice, și chiar mai puțin probabil să poată scrie ceva direct pe bytecode. Codul de cod Parrot este absolut independent de orice platformă. Desigur, octetul este mult mai rapid decât codul sursă al scriptului, care nu a fost precompilat.
Setul de instrucțiuni pentru mașină virtuală Parrot include operatori aritmetici și logici, construcții de comparație și control al debitului, cicluri, dacă-apoi de construcție, și așa mai departe. Sunt sprijinite variabilele locale și globale, lucrează cu clase și obiecte, mecanisme de apelare subrutine și metode cu parametri, intrări / ieșiri, multithreading și multe altele.
Mașina virtuală Parrot este înregistrată, adică ca un procesor hardware, are seturi de elemente care oferă acces ultra-rapid la datele stocate în ele. Astfel de elemente sunt numite registre. Registrele Parrot ofera patru tipuri: integer (I), pentru virgulă flotantă (N), pentru linii (S) pentru PMC-containere (P), care vor fi discutate mai târziu. Pot exista mai multe registre de fiecare tip, iar o anumită sumă trebuie definită pentru fiecare subprogram la timpul de compilare.
Acum vom dezvălui abrevierea misterioasă PMC - este Container PolyMorphic, container polimorfic. Un container PMC poate reprezenta orice tip de structură complexă sau complexă: un tablou, o tabelă hash, un dicționar, o listă etc. Pentru orice container PMC, puteți implementa propriile operații de aritmetică, logică și șir specializate, adică simula comportamentul dorit al obiectului. Containerele PMC pot fi construite în programe Parrot sau încărcate dinamic numai când este necesar.
Parrot implementează mecanismul de colectare a gunoiului, astfel încât programatorul nu trebuie să-și facă griji pentru eliberarea explicită a memoriei capturate - Parrot va avea grijă de asta.
Pentru a trece la "testarea pe teren" a mașinii virtuale Parrot, este necesar să o instalați. Cea mai bună cale este să utilizați managerul de pachete obișnuit al distribuției dvs. și nici o problemă de instalare.
Ușurința de a stăpâni un nou instrument software este de obicei evaluată în funcție de următorul criteriu: cât de repede puteți scrie un program elementar pentru ieșirea unui șir arbitrar, așa-numitul "test HelloWorld". Să evaluăm acest criteriu.
În fișierul hello.pir (nu ați uitat că formatul PIR are cel mai înalt nivel de reprezentare a codului?) Vom scrie următorul cod:
Instrucțiunea de ieșire a liniei este practic aceeași ca instrucțiunea Perl sau Python. Acesta este un moment pozitiv, un mic argument în favoarea Parrot. Dar lumea noastră nu este perfectă și tot ceea ce există în ea, din păcate, este imperfectă. Pe fiecare "plus" există cel puțin un "minus". Aici și cu Parrot. După efectuarea testului, în loc de rezultatul așteptat, vedem următorul mesaj:
Aceasta înseamnă că șirul de ieșire nu este formatat corect. Consultați documentația, constatăm că implicit în principal Parrot este un ASCII pe 8 biți, în timp ce marea majoritate a distribuțiile moderne primite de standardul de facto UTF-8.
Problema este rezolvată prin indicarea explicită a codificării necesare sub forma unui prefix înainte de șirul de ieșire. Se pare ca aceasta:
Acum, testul nostru se efectuează conform așteptărilor. Trebuie remarcat faptul că suporturile Parrot seturi de caractere ASCII, iso-8859-1 (Latin 1), unicode (cu variante fixed_8, UCS2, utf8 și UTF16), și în plus un tip special de binar, care permite să interpreteze șirul ca respectivul tampon binar neformatate date.
În căldura luptei cu problema, am uitat să discutăm structura și sintaxa programului în sine. Și totuși, ce este acolo pentru a discuta - și tot atât de clar: Prima linie definește o subrutină numit principal, al doilea - o componentă de instruire a corpului subrutina (constantele șir de ieșire), a treia - completarea rutine de instruire. Mai multe instrucțiuni PIR pentru a determina începutul și sfârșitul unui început de subrutină cu un caracter "punct". Aceasta este întreaga descriere.
Corzile, ca și alte tipuri de variabile, pot fi stocate în registrele specializate, despre care am vorbit deja. Luați în considerare următorul exemplu:
Prima parte a șirului este scrisă în registrul de șir S0. Un alt rezultat al înregistrării șirului S1 este rezultatul concatenării conținutului registrului S0 și a contracției string-specific specificate. Punctul reprezintă operația de concatenare sau combinare a șirurilor. Apoi se transmite conținutul registrului S1.
Este important să rețineți că în formatul PIR nu puteți scrie direct în registre. În schimb, se utilizează referiri la registre, notate cu simbolul dolarului: $ S0, $ S1. Compilatorul, întâlnit cu referința $ S0, îl asociază cu unul dintre registrele de șir disponibile ale mașinii virtuale și atribuie acestui registru o valoare specificată.
O altă modalitate de utilizare a registrelor este posibilă - sunt "registre numite" originale, care sporesc lizibilitatea codului sursă. Registrele numite sunt de asemenea afișate de compilator în registrele interne ale mașinii virtuale:
A doua linie de subrutină principală Directiva .local specifică faptul că registrul numit urmează a fi utilizat (sau rutina de curent este numit Scoped acest caz) în rutina curentă. Următorul este tipul șirului denumit, adică. acesta este un registru de șir (S). De asemenea, pot fi menționate tipuri de registre pentru int întreg (I), registre float pentru numere în virgulă flotantă (N), PMC containere registre polimorfi (P), și, în plus, pot fi scrise aici nume de tip PMC.
Pentru a continua studiul sintaxei și a structurilor de control ale mașinii virtuale Parrot, aveți nevoie de un program care nu face decât o simplă ieșire de linii, dar fără o complexitate excesivă. În acest scop, suma de pătrate, de exemplu, primele zece numere naturale, este destul de potrivită.
În acest program au apărut noi elemente: operații aritmetice cu numere întregi, etichetă de buclă. verificați dacă este cazul. În plus, am constatat că operația de atribuire generalizată sum + + tmp este acceptată, dar creșterea incrementului se face cu comanda inc i și nu cu i ++, ca în Perl.
Din motive de justiție, trebuie remarcat faptul că formularea mai multor instrucțiuni PIR este așa-numitul "zahăr sintactic" (zahăr sintactic); mai echilibrat și mai natural, echivalent cu instrucțiunile asamblorului "misterios". De exemplu, fragmentul
pot fi scrise într-o formă mai "asamblată":
O regulă importantă atunci când se utilizează un astfel de stil de asamblare: dacă instrucțiunea modifică conținutul registrului, acest registru trebuie să fie scris în primul rând, de fapt, la fel ca în cele mai multe dintre asamblorii „reale“.
Cel mai bun exemplu pentru demonstrarea apelurilor funcțiilor recursive în orice limbaj de programare este calculul factorial al unui număr. Pentru mașina virtuală Parrot, programul arată astfel:
După subrutină factorial scris .return directivă (res), pentru a copia valoarea conținută în res registrului numit, în cazul în care programul de asteptare este rezervat pentru valoarea de returnare a subrutina.
Titlul subrutinei principale este scris în formular
Faptul este că implicit în formatul PIR se presupune că execuția începe cu prima subrutină din fișierul sursă. Ordinea de execuție poate fi modificată prin adăugarea modificatorului: principal în antetul subrutinei necesare. Apropo, nu este necesar să dai subrutina de start numele principal, principalul lucru fiind modificatorul.
Pentru a îmbunătăți performanțele și viteza programelor Parrot, le puteți precompila la octeți (format PBC). Numele fișierului în care este salvat rezultatul compilației este specificat în linia de comandă după flagul -o, iar acest fișier trebuie să aibă extensia .pbc.
De exemplu, dacă decidem să ne compilam programul factorial în bytecode, atunci trebuie să executăm următoarea comandă:
Acum puteți executa atât fctr_calc.pir cât și fctr_calc.pbc. fișier fctr_calc.pbc precompiled va fi mai rapid, dar este puțin probabil va fi capabil de a evalua vizual diferența de viteză atunci când executați aceste programe și pe moderne super-rapid calculatoare.
În acest articol am examinat caracteristicile și principiile generale ale mașinii virtuale Parrot și am examinat exemplele codului sursă. Acesta este primul pas pentru a evalua funcționalitatea și eficiența Parrot. Următorul articol va descrie mecanismul de compilare și instrumentele; În plus, vom vorbi despre interacțiunea dintre Parrot și diferite limbi de programare.
Alexei Snastin este un dezvoltator de software independent, consultant și traducător din limba engleză a literaturii tehnice și educaționale despre IT. A participat la dezvoltarea de aplicații de birou de rețea, cum ar fi client / server în limba C într-un mediu Linux.