Să se implementeze o funcție în limbaj de asamblare care efectuează parsarea unei expresii matematice în formă prefixată și construiește un AST (abstract syntax tree). Numerele ce apar în expresie sunt numere întregi cu semn, pe 32 de biți, iar operațiile ce se aplică lor sunt: +, -, /, *
. Expresia prefixată va fi primita sub forma unui șir de caractere ce este dat ca parametru funcției, rezultatul fiind un pointer către nodul rădăcină al arborelui, salvat in registrul EAX.
Arborii sintactici abstracți sunt o structură de date cu ajutorul căreia compilatoarele reprezintă structura unui program. În urma parcurgerii AST-ului, un compilator generează metadatele necesare transformării din cod de nivel înalt în cod assembly. Puteți găsi mai multe informații despre AST aici.
Reprezentarea sub forma unui AST a unui program/expresii are avantajul de a defini clar ordinea evaluarii operațiilor fară a fi necesare paranteze. Astfel expresia 4 / 64 - 2 * (3 + 1)
poate fi reprezentată sub forma:
Programul va folosi ca input un string în care se află parcurgerea preordine a arborelui, în ordinea, rădăcină, stânga, dreapta, ce poarta numele de Forma poloneza prefixată. Această expresie trebuie transformată în arbore de către functia create_tree(char* token)
din fișierul ast.asm
, funcție care este apelată de checker. De asemenea, de eliberarea memoriei utilizate pentru reținerea arborelui se ocupă checkerul.
Mai mult, veți avea de implementat funcția iocla_atoi
(in același fișier), care are o funționalitate similară funcției atoi din C.
int iocla_atoi(char* token)
Se garantează că inputul primit de iocla_atoi este valid (un număr ce poate fi reprezentat pe 4 octeți).
Astfel, ce vă revine de făcut este să implementați cele 2 funcții (create_tree și iocla_atoi). Urmăriți comentariile din schelet pentru detalii.
De asemenea, structura folosită pentru a stoca un nod din arbore arată astfel:
struct __attribute__((__packed__)) Node { char* data; struct Node* left; struct Node* right; };
Vă puteți folosi de funcțiile
int evaluate_tree(Node* root) // primește un arbore și întoarce rezultatul evaluării lui void print_tree_inorder(Node* root) // primește un arbore și afișează nodurile în urma parcurgerii inordine. void print_tree_preorder(Node* root) // primește un arbore și afișează nodurile în urma parcurgerii preordine. void check_atoi(char* str) // primește un șir de caractere și afișează 'Equal' sau 'Not equal', verificând dacă iocla_atoi întoarce același rezultat ca atoi.
Stringul data
conține fie un operator (+, -, *, /
), fie un operand (număr). În ambele cazuri, stringul se termină cu caracterul \0
.
După cum puteti afla si de pe acest link, urmatorul cod:
__attribute__((__packed__)
îi interzice compilatorului să adauge padding in cadrul unei structuri, distanțele față de începutul structurii la care se află campurile acesteia fiind astfel cele asteptate și nevariind de la o masină la alta.
Găsiți aici un fișier schelet de la care puteți începe implementarea.
O explicație a evaluării expresiei găsiți aici.
$ ./ast * - 5 6 7 -7 $ ./ast + + * 5 3 2 * 2 3 23 $ ./ast - * 4 + 3 2 5 15
Tema se poate testa pe platforma vmchecker sau local folosind checkerul check
de aici.
Temele vor trebui încărcate pe platforma vmchecker (în secțiunea IOCLA) și vor fi testate automat. Arhiva încărcată trebuie să fie o arhivă .zip
care să conțină:
ast.asm
README
ce conține descrierea implementăriiPunctajul final acordat pe o temă este compus din:
./check
după ce ați dat drepturi de execuție fișierului.stdout
.free_ast
trebuie sa se execute cu succes.$ ./ast - 2 1 1
* + 2 1 + 3 4
se va afișa 21
si nu 9
, operațiile executându-se în ordinea (2 + 1) * (3 + 4)
, și nu 2 + 1 * 3 + 4
.Arhiva ce conține checkerul, testele și fișierul de la care puteți începe implementarea este aici.