#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; } /* Ispis cvora stabla na datom nivou nazubljivanja */ void print_(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++) print_(p->opr.op[k], level+1); break; } } /* Ispis sintaksnog stabla (korisno samo za debagovanje) */ void print(nodeType* p) { print_(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); } } /* Komilacija za stek masinu sa sledecim instrukcijama: - push x - stavlja navedeni broj x na stek - add - skida dve vrednosti sa vrha steka i na stek stavlja njihov zbir - sub - skida dve vrednosti sa vrha steka i na stek stavlja njihovu razliku - mul - skida dve vrednosti sa vrha steka i na stek stavlja njihov proizvod - Pretpostavljamo da izraz sadrzi samo konstante i binarne operatore. - Kada kompiliramo cvor p dobijamo kod koji na stek dodaje jedan broj koji predstavlja vrednost cvora p . - Kompilacija se u ovom slucaju svodi na postfiksni obilazak drveta. */ void compileStackMachine(nodeType* p) { /* brojac slobodnih labela (za uslovne i bezuslovne skokove i kontrolu toka programa) */ static int lbl; switch(p->type) { case typeCon: /* konstante postavljamo na stek */ printf("\tpush %d\n", p->con.value); break; case typeId: /* promenljive postavljamo na stek */ printf("\tpush [%s]\n", p->id.name); case typeOpr: if (p->opr.oper == PRINT) { /* naredba stampanja */ /* vrsimo kompilaciju operanda i generisemo kod koji izracunava argument naredbe - nakon njegovog izracunavanja rezultat je na vrhu steka */ compileStackMachine(p->opr.op[0]); /* generisemo (asemblersku) instrukciju stampanja */ printf("\tprint\n"); } else if (p->opr.oper == IF) { /* naredba if */ /* rezervisemo labelu za kraj naredbe */ int lblAfter = lbl++; /* generisemo kod koji izracunava uslov - rezultat je na vrhu steka */ compileStackMachine(p->opr.op[0]); /* generisemo instrukciju koja proverava da li je na vrhu steka nula i ako jeste, skace na kraj tj. preskace telo naredbe grananja */ printf("\tjz LBL%d\n", lblAfter); /* generisemo kod za telo naredbe grananja */ compileStackMachine(p->opr.op[1]); /* generisemo labelu na kraju naredbe grananja */ printf("LBL%d:\n", lblAfter); } else if (p->opr.oper == WHILE) { /* petlja while */ /* rezervisemo dve labele: jednu za pocetak i jednu za kraj petlje */ int lblBefore = lbl++; int lblAfter = lbl++; /* generisemo labelu na pocetku petlje */ printf("LBL%d:\n", lblBefore); /* generisemo kod koji izracunava uslov petlje - rezultat je na vrhu steka */ compileStackMachine(p->opr.op[0]); /* generisemo instrukciju koja proverava da li je na vrhu steka nula i ako jeste, skace na kraj petlje */ printf("\tjz LBL%d\n", lblAfter); /* generisemo kod za telo petlje */ compileStackMachine(p->opr.op[1]); /* generisemo bezuslovni skok na pocetak petlje */ printf("\tjmp LBL%d\n", lblBefore); /* generisemo labelu na kraju petlje */ printf("LBL%d:\n", lblAfter); } else if (p->opr.oper == '=') { /* naredba dodele */ /* generisemo kod koji izracunava desnu stranu - rezultat je na vrhu steka */ compileStackMachine(p->opr.op[1]); /* generisemo kod koji vrednost sa steka prebacuje u memoriju, na mesto promenljive sa leve strane */ printf("\tpop [%s]\n", p->opr.op[0]->id.name); } else { if (p->opr.nops == 2) { /* aritmeticki binarni operator */ /* vrsimo kompilaciju levog operanda */ /* nakon izvrsavanja dobijenog koda na vrh steka ce biti dodata vrednost prvog operanda */ compileStackMachine(p->opr.op[0]); /* vrsimo kompilaciju desnog operanda */ /* nakon izvrsavanja dobijenog koda na vrh steka ce biti dodata vrednost drugog operanda */ compileStackMachine(p->opr.op[1]); /* primenjujemo operator koji sa steka skida dve vrednosti (a to su vrednosti operanada) i na stek stavlja rezultat primene odgovarajuceg operatora na te dve vrednosti (a to ce biti vrednosti cvora p) */ switch(p->opr.oper) { case '+': printf("\tadd\n"); break; case '-': printf("\tsub\n"); break; case '*': printf("\tmul\n"); break; case '<': printf("\tcmpLT\n"); break; case '>': printf("\tcmpGT\n"); break; } } } } }