#include #include #include #include "syntree.h" #include "y.tab.h" /* funkcija za prijavljivanje greske */ int yyerror(char* s) { return fprintf(stderr, "%s", s); } /* alokacija cvora */ nodeType* allocNode() { nodeType *p; /* alokacija cvora */ if ((p = malloc(sizeof(nodeType))) == NULL) yyerror("out of memory"); return p; } /* Kreiranje cvora konstante sa datom vrednoscu */ nodeType* con(int value) { nodeType* p = allocNode(); p->type = typeCon; /* Tip cvora je tip konstante */ p->con.value = value; /* Vrednost konstante je prosledjena kao parametar */ return p; } /* Kreiranje cvora promenljive sa datim celobrojnim indeksom */ nodeType *id(char name[]) { nodeType *p = allocNode(); p->type = typeId; /* Tip cvora je cvor promenljive */ strcpy(p->id.name, name); /* naziv promenljive je dat kao parametar */ return p; } /* Kreiranje cvora unarnog operatora oper sa datim operandom */ nodeType* unOp(int oper, nodeType* op1) { nodeType* p = allocNode(); p->type = typeOpr; /* Tip cvora je cvor operanda */ p->opr.oper = oper; /* Operator je dat kao parametar */ p->opr.nops = 1; /* Operator je binaran */ /* Alokacija niza operanada */ if ((p->opr.op = malloc(sizeof(nodeType*))) == NULL) yyerror("out of memory"); /* Postavljanje operanada */ p->opr.op[0] = op1; return p; } /* Kreiranje cvora binarnog operatora oper sa data dva operanda */ nodeType* binOp(int oper, nodeType* op1, nodeType* op2) { nodeType* p = allocNode(); p->type = typeOpr; /* Tip cvora je cvor operanda */ p->opr.oper = oper; /* Operator je dat kao parametar */ p->opr.nops = 2; /* Operator je binaran */ /* Alokacija niza operanada */ if ((p->opr.op = malloc(2*sizeof(nodeType*))) == NULL) yyerror("out of memory"); /* Postavljanje operanada */ p->opr.op[0] = op1; p->opr.op[1] = op2; return p; } /* Kreiranje cvora n-arnog operatora oper sa datim operandima */ nodeType* naryOp(int oper, int nops, nodeType** op) { int i; nodeType* p = allocNode(); p->type = typeOpr; /* Tip cvora je cvor operanda */ p->opr.oper = oper; /* Operator je dat kao parametar */ p->opr.nops = nops; /* Operator je naran */ /* Alokacija niza operanada */ if ((p->opr.op = malloc(nops*sizeof(nodeType*))) == NULL) yyerror("out of memory"); /* Postavljanje operanada */ for (i = 0; i < nops; i++) p->opr.op[i] = op[i]; return p; } /* Ispis cvora stabla na datom nivou nazubljivanja */ void debugPrint_(nodeType* p, int level) { /* nazubljuemo do dubine level */ int k; for (k = 0; k < level; k++) putchar(' '); /* analiziramo tip cvora */ switch(p->type) { case typeCon: /* cvor konstante */ printf("Con: %d\n", p->con.value); break; case typeId: /* cvor promenljive */ printf("Id: %s\n", p->id.name); break; case typeOpr: /* cvor operatora */ if (p->opr.oper < 128) printf("Op %c\n", p->opr.oper); else printf("Op %d\n", p->opr.oper); /* rekurzivno ispisujemo operande na narednom nivou nazubljivanja */ for (k = 0; k < p->opr.nops; k++) debugPrint_(p->opr.op[k], level+1); break; } } /* Ispis sintaksnog stabla (korisno samo za debagovanje) */ void debugPrint(nodeType* p) { debugPrint_(p, 0); } /* brisanje drveta */ void freeNode(nodeType* n) { if (n != NULL) { if (n->type == typeOpr) { int i; for (i = 0; i < n->opr.nops; i++) freeNode(n->opr.op[i]); } free(n); } } /* stampanje cvora konstante ili promenljive (originalne ili privremene) */ void print(nodeType* p) { switch (p->type) { case typeCon: printf("%d", p->con.value); break; case typeId: printf("%s", p->id.name); break; } } /* kopiranje drveta */ nodeType* copy(nodeType* p) { switch (p->type) { case typeCon: return con(p->con.value); case typeId: return id(p->id.name); case typeOpr: { int i; nodeType* n = allocNode(); n->type = typeOpr; /* Tip cvora je cvor operanda */ n->opr.oper = p->opr.oper; /* Operator je dat kao parametar */ n->opr.nops = p->opr.nops; /* Operator je naran */ /* Alokacija niza operanada */ if ((n->opr.op = malloc(p->opr.nops*sizeof(nodeType*))) == NULL) yyerror("out of memory"); /* Kopiranje operanada */ for (i = 0; i < p->opr.nops; i++) n->opr.op[i] = copy(p->opr.op[i]); return n; } } return NULL; } /* Kompilacija u troadresni kod - ako se kompilira izraz, funkcija vraca novi cvor koji predstavlja konstantu ili promenljivu (originalnu ili privremenu) koja sadrzi rezultat izraza */ nodeType* compile3address_(nodeType* p) { /* brojac slobodnih labela */ static int label; /* brojac slobodnih privremenih promenljivih */ static int tempNum; switch (p->type) { case typeCon: /* konstanta predstavlja svoju vrednost */ return copy(p); case typeId: /* promenljiva predstavlja svoju vrednost */ return copy(p); case typeOpr: if (p->opr.oper == PRINT) { /* naredba stampanja */ /* kompiliramo argument funkcije print i kao rezultat dobijamo konstantu ili promenljivu koja ce sadrzati vrednost tog argumenta */ nodeType* res = compile3address_(p->opr.op[0]); /* generisemo instrunkciju stampanja te konstante tj. promenljive */ printf("print "); print(res); printf("\n"); /* oslobadjamo memoriju zauzetu privremenim cvorom */ freeNode(res); return NULL; } if (p->opr.oper == ';') { /* nadovezivanje dve naredbe */ /* kompiliramo prvu naredbu */ compile3address_(p->opr.op[0]); /* kompiliramo drugu naredbu */ compile3address_(p->opr.op[1]); /* naredbe nemaju vrednost, pa vracamo NULL */ return NULL; } else if (p->opr.oper == IF) { /* naredba grananja if */ /* rezervisemo jednu slobodnu labelu za kraj naredbe grananja */ int lblAfter = ++label; /* uslov i telo naredbe grananja */ nodeType* cond = p->opr.op[0]; nodeType* body = p->opr.op[1]; /* kompiliramo levu i desnu stranu uslova naredbe if */ nodeType* res0 = compile3address_(cond->opr.op[0]); nodeType* res1 = compile3address_(cond->opr.op[1]); /* res0 i res1 su konstante ili promenljive koje sadrze vrednosti leve i desne strane uslova naredbe if */ /* generisemo instrukciju koja preskace telo naredbe if ako uslov nije ispujen */ printf("ifFalse "); print(res0); printf(" %c ", cond->opr.oper); print(res1); printf(" goto labela%d\n", lblAfter); /* kompiliramo telo naredbe if - posto je to naredba, a ne izraz, povratna vrednost nije relevantna (ocekujemo da se vrati NULL) */ compile3address_(body); /* generisemo labelu na kraju naredbe if */ printf("labela%d:\n", lblAfter); /* if je naredba, a ne izraz, pa vracamo NULL */ return NULL; } else if (p->opr.oper == WHILE) { /* rezervisemo dve labele: jednu za pocetak i jednu za kraj naredbe while */ int lblBefore = ++label; int lblAfter = ++label; /* generisemo labelu na pocetku naredbe while */ printf("labela%d:\n", lblBefore); /* uslov i telo naredbe grananja */ nodeType* cond = p->opr.op[0]; nodeType* body = p->opr.op[1]; /* kompiliramo levu i desnu stranu uslova naredbe if */ nodeType* res0 = compile3address_(cond->opr.op[0]); nodeType* res1 = compile3address_(cond->opr.op[1]); /* res0 i res1 su konstante ili promenljive koje sadrze vrednosti leve i desne strane uslova naredbe if */ /* generisemo instrukciju koja preskace telo naredbe if ako uslov nije ispujen */ printf("ifFalse "); print(res0); printf(" %c ", cond->opr.oper); print(res1); printf(" goto labela%d\n", lblAfter); /* kompiliramo telo naredbe if - posto je to naredba, a ne izraz, povratna vrednost nije relevantna (ocekujemo da se vrati NULL) */ compile3address_(body); /* generisemo bezuslovni skok na pocetak petlje */ printf("goto labela%d\n", lblBefore); /* generisemo labelu na kraju naredbe if */ printf("labela%d:\n", lblAfter); /* if je naredba, a ne izraz, pa vracamo NULL */ return NULL; } else if (p->opr.oper == '=') { /* naredba dodele */ /* kompiliramo desnu stranu */ nodeType* res = compile3address_(p->opr.op[1]); /* rezultat na desnoj strani je smesten u konstantu ili promenljivu (originalnu ili privremenu) res */ /* generisemo instrukciju dodele koja promenljivoj sa leve strane originalne dodele dodeljuje res */ print(p->opr.op[0]); printf(" = "); print(res); printf("\n"); /* oslobadjamo memoriju zauzetu pomocnim cvorom vracenom iz rekurzivnog poziva */ freeNode(res); /* naredba dodel je naredba, a ne izraz, pa vracamo NULL */ return NULL; } else { if (p->opr.nops == 2) { /* binarni aritmeticki operatori */ /* rezervisemo novu privremenu promenljivu */ int temp = tempNum++; /* odredjujemo joj ime */ char tempName[MAX_ID + 1]; sprintf(tempName, "t%d", temp); /* kompiliramo levi i desni operand aritmetickog operatora */ nodeType* res1 = compile3address_(p->opr.op[0]); nodeType* res2 = compile3address_(p->opr.op[1]); /* res1 i res2 su konstante ili promenljive (originalne ili pomocne) koje sadrze rezultat levog i desnog operanda */ /* generisemo troadresnu dodelu */ printf("%s = ", tempName); print(res1); printf(" %c ", p->opr.oper); print(res2); printf("\n"); /* oslobadjamo memoriju zauzetu pomocnim cvorovima vracenim iz rekurzivnih poziva */ freeNode(res1); freeNode(res2); /* rezultat se nalazi u pomocnoj promenljivoj */ return id(tempName); } } break; } } /* Kompilacija u troadresni kod */ void compile3address(nodeType* p) { nodeType* res = compile3address_(p); freeNode(res); }