#include #include #include "syntree.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(int i) { nodeType *p = allocNode(); p->type = typeId; /* Tip cvora je cvor promenljive */ p->id.i = i; /* indeks promenljive je dat kao parametar */ 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: %c\n", 'a' + p->id.i); break; case typeOpr: /* cvor operatora */ printf("Op %c\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->type == typeOpr) { freeNode(n->opr.op[0]); freeNode(n->opr.op[1]); } 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 compile(nodeType* p) { switch(p->type) { case typeCon: /* konstante postavljamo na stek */ printf("push %d\n", p->con.value); break; case typeOpr: /* izrvsavamo kompilaciju levog operanda */ /* nakon izvrsavanja dobijenog koda na vrh steka ce biti dodata vrednost prvog operanda */ compile(p->opr.op[0]); /* izvrsavamo kompilaciju desnog operanda */ /* nakon izvrsavanja dobijenog koda na vrh steka ce biti dodata vrednost drugog operanda */ compile(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("add\n"); break; case '-': printf("sub\n"); break; case '*': printf("mul\n"); break; } } }