From b9f016f82a8c9e6dde6738eb4b8c365a54b7105c Mon Sep 17 00:00:00 2001 From: Augusto Gunsch Date: Thu, 31 Dec 2020 20:02:04 -0300 Subject: [PATCH] Organize compiler --- compiler/compiler-expressions.h | 2 +- compiler/compiler-statements.c | 166 +++++++++++++++++++ compiler/compiler-statements.h | 9 ++ compiler/compiler-structure.c | 130 +++++++++++++++ compiler/compiler-structure.h | 9 ++ compiler/compiler-util.h | 3 + compiler/compiler.c | 277 +------------------------------- compiler/compiler.h | 5 +- 8 files changed, 325 insertions(+), 276 deletions(-) create mode 100644 compiler/compiler-statements.c create mode 100644 compiler/compiler-statements.h create mode 100644 compiler/compiler-structure.c create mode 100644 compiler/compiler-structure.h diff --git a/compiler/compiler-expressions.h b/compiler/compiler-expressions.h index f84da31..01eccbf 100644 --- a/compiler/compiler-expressions.h +++ b/compiler/compiler-expressions.h @@ -4,7 +4,7 @@ #include "compiler.h" /* compiler-expressions - * Subroutines for dealing and compiling expressions and singular terms. */ + * Functions for dealing and compiling expressions and singular terms. */ // Dealing with singular terms LINEBLOCK* compilesubroutcall(SCOPE* s, SUBROUTCALL* call); diff --git a/compiler/compiler-statements.c b/compiler/compiler-statements.c new file mode 100644 index 0000000..3af3bce --- /dev/null +++ b/compiler/compiler-statements.c @@ -0,0 +1,166 @@ +#include +#include +#include "compiler-expressions.h" +#include "compiler-statements.h" +#include "compiler-util.h" + +/* BEGIN FORWARD DECLARATIONS */ + +// Miscelaneous +LINE* popthat(); +LINE* pushtemp(); +char* mkcondlabel(char* name, int count); + +// Handling individual statements +LINEBLOCK* compileret(SCOPE* s, TERM* e); +LINEBLOCK* compileif(COMPILER* c, SCOPE* s, IFSTATEMENT* st); +LINEBLOCK* compilewhile(COMPILER* c, SCOPE* s, CONDSTATEMENT* w); +LINEBLOCK* compilelet(SCOPE* s, LETSTATEMENT* l); +LINEBLOCK* compilestatement(COMPILER* c, SCOPE* s, STATEMENT* st); + +/* END FORWARD DECLARATIONS */ + + + +// Miscelaneous +LINE* popthat() { + char* popthat[] = { "pop", "that", "0" }; + return mkln(popthat); +} + +LINE* pushtemp() { + char* pushtemp[] = { "push", "temp", "0" }; + return mkln(pushtemp); +} + +char* mkcondlabel(char* name, int count) { + int sz = (strlen(name) + countplaces(count) + 1) * sizeof(char); + char* result = (char*)malloc(sz); + sprintf(result, "%s%i", name, count); + return result; +} + +// Handling individual statements +LINEBLOCK* compileret(SCOPE* s, TERM* e) { + LINE* ret = onetoken("return"); + LINEBLOCK* blk = mklnblk(ret); + + // void subroutdecs return 0 + if(e == NULL) { + char* tokens[] = { "push", "constant", "0" }; + appendlnbefore(blk, mkln(tokens)); + } else + blk = mergelnblks(compileexpression(s, e), blk); + + return blk; +} + +LINEBLOCK* compileif(COMPILER* c, SCOPE* s, IFSTATEMENT* st) { + LINEBLOCK* blk = compileexpression(s, st->base->expression); + + pthread_mutex_lock(&(c->ifmutex)); + static int ifcount = 0; + int mycount = ifcount; + ifcount++; + pthread_mutex_unlock(&(c->ifmutex)); + + char* truelabel = mkcondlabel("IF_TRUE", mycount); + char* ifgoto[] = { "if-goto", truelabel }; + appendln(blk, mkln(ifgoto)); + + char* falselabel = mkcondlabel("IF_FALSE", mycount); + char* gotofalse[] = { "goto", falselabel }; + appendln(blk, mkln(gotofalse)); + + char* truelabelln[] = { "label", truelabel }; + appendln(blk, mkln(truelabelln)); + + blk = mergelnblks(blk, compilestatements(c, s, st->base->statements)); + + char* endlabel; + bool haselse = st->elsestatements != NULL; + if(haselse) { + endlabel = mkcondlabel("IF_END", mycount); + char* endgoto[] = { "goto", endlabel }; + appendln(blk, mkln(endgoto)); + } + + char* falselabelln[] = { "label", falselabel}; + appendln(blk, mkln(falselabelln)); + + if(haselse) { + blk = mergelnblks(blk, compilestatements(c, s, st->elsestatements)); + char* endlabelln[] = { "label", endlabel }; + appendln(blk, mkln(endlabelln)); + } + + return blk; +} + +LINEBLOCK* compilewhile(COMPILER* c, SCOPE* s, CONDSTATEMENT* w) { + LINEBLOCK* blk = compileexpression(s, w->expression); + + pthread_mutex_lock(&(c->whilemutex)); + static int whilecount = 0; + int mycount = whilecount; + whilecount++; + pthread_mutex_unlock(&(c->whilemutex)); + + char* explabel = mkcondlabel("WHILE_EXP", mycount); + char* explabelln[] = { "label", explabel }; + appendlnbefore(blk, mkln(explabelln)); + + appendln(blk, onetoken("not")); + + char* endlabel = mkcondlabel("WHILE_END", mycount); + char* ifgoto[] = { "if-goto", endlabel }; + appendln(blk, mkln(ifgoto)); + + blk = mergelnblks(blk, compilestatements(c, s, w->statements)); + + char* gotoln[] = { "goto", explabel }; + appendln(blk, mkln(gotoln)); + + char* endlabelln[] = { "label", endlabel }; + appendln(blk, mkln(endlabelln)); + + return blk; +} + +LINEBLOCK* compilelet(SCOPE* s, LETSTATEMENT* l) { + LINEBLOCK* blk = compileexpression(s, l->expression); + + if(l->arrayind != NULL) { + appendlnbefore(blk, onetoken("add")); + appendlnbefore(blk, pushvar(s, l->varname)); + blk = mergelnblks(compileexpression(s, l->arrayind), blk); + + appendln(blk, poptemp()); + appendln(blk, popthatadd()); + appendln(blk, pushtemp()); + appendln(blk, popthat()); + } + else + appendln(blk, popvar(s, l->varname)); + return blk; +} + +LINEBLOCK* compilestatement(COMPILER* c, SCOPE* s, STATEMENT* st) { + s->currdebug = st->debug; + if(st->type == dostatement) return compilesubroutcall(s, st->dostatement); + if(st->type == returnstatement) return compileret(s, st->retstatement); + if(st->type == ifstatement) return compileif(c, s, st->ifstatement); + if(st->type == whilestatement) return compilewhile(c, s, st->whilestatement); + if(st->type == letstatement) return compilelet(s, st->letstatement); + eprintf("UNSUPPORTED type %i\n", st->type); + exit(1); +} + +LINEBLOCK* compilestatements(COMPILER* c, SCOPE* s, STATEMENT* sts) { + LINEBLOCK* head = NULL; + while(sts != NULL) { + head = mergelnblks(head, compilestatement(c, s, sts)); + sts = sts->next; + } + return head; +} diff --git a/compiler/compiler-statements.h b/compiler/compiler-statements.h new file mode 100644 index 0000000..ab347ec --- /dev/null +++ b/compiler/compiler-statements.h @@ -0,0 +1,9 @@ +#ifndef COMPILER_STATEMENTS_H +#define COMPILER_STATEMENTS_H +#include "compiler.h" + +/* compiler-statements + * Single function for compiling statements */ + +LINEBLOCK* compilestatements(COMPILER* c, SCOPE* s, STATEMENT* sts); +#endif diff --git a/compiler/compiler-structure.c b/compiler/compiler-structure.c new file mode 100644 index 0000000..87a9a40 --- /dev/null +++ b/compiler/compiler-structure.c @@ -0,0 +1,130 @@ +#include +#include "compiler-statements.h" +#include "compiler-structure.h" +#include "compiler-util.h" + +/* BEGIN FORWARD DECLARATIONS */ + +// Miscelaneous +int countlocalvars(VARDEC* decs); +int countstrs(STRINGLIST* ls); +int getobjsize(CLASS* c); +LINE* mksubdeclabel(CLASS* c, SUBROUTDEC* sd); + +// Compiling methods +LINEBLOCK* compilefunbody(COMPILER* c, SCOPE* s, CLASS* cl, SUBROUTBODY* b); +LINEBLOCK* compilefundec(COMPILER* c, SCOPE* s, CLASS* cl, SUBROUTDEC* f); +LINEBLOCK* compileconstructor(COMPILER* c, SCOPE* s, CLASS* cl, SUBROUTDEC* con); +LINEBLOCK* compilemethod(COMPILER* c, SCOPE* s, CLASS* cl, SUBROUTDEC* m); + +/* END FORWARD DECLARATIONS */ + + +// Miscelaneous +int countlocalvars(VARDEC* decs) { + int i = 0; + while(decs != NULL) { + STRINGLIST* curr = decs->names; + while(curr != NULL) { + i++; + curr = curr->next; + } + decs = decs->next; + } + return i; +} + +int countstrs(STRINGLIST* ls) { + int count = 0; + while(ls != NULL) { + count++; + ls = ls->next; + } + return count; +} + +int getobjsize(CLASS* c) { + CLASSVARDEC* curr = c->vardecs; + int count = 0; + while(curr != NULL) { + if(curr->type == field) + count += countstrs(curr->base->names); + curr = curr->next; + } + return count; +} + +LINE* mksubdeclabel(CLASS* c, SUBROUTDEC* sd) { + char* labelstrs[] = { "function", dotlabel(c->name, sd->name), itoa(countlocalvars(sd->body->vardecs)) }; + LINE* label = mkln(labelstrs); + free(labelstrs[1]); + free(labelstrs[2]); + label->next = NULL; + return label; +} + +// Compiling methods +LINEBLOCK* compilefunbody(COMPILER* c, SCOPE* s, CLASS* cl, SUBROUTBODY* b) { + SCOPE* myscope = mkscope(s); + myscope->currclass = cl; + if(b->vardecs != NULL) + addlocalvars(s, b->vardecs); + LINEBLOCK* head = compilestatements(c, myscope, b->statements); + return head; +} + +LINEBLOCK* compilefundec(COMPILER* c, SCOPE* s, CLASS* cl, SUBROUTDEC* f) { + LINE* label = mksubdeclabel(cl, f); + + if(f->body->statements != NULL) { + LINEBLOCK* body = compilefunbody(c, s, cl, f->body); + appendlnbefore(body, label); + return body; + } + else + return mklnblk(label); +} + +LINEBLOCK* compileconstructor(COMPILER* c, SCOPE* s, CLASS* cl, SUBROUTDEC* con) { + LINE* label = mksubdeclabel(cl, con); + LINEBLOCK* blk = mklnblk(label); + + char* size[] = { "push", "constant", itoa(getobjsize(cl)) }; + char* memalloc[] = { "call", "Memory.alloc", "1" }; + char* poppointer[] = { "pop", "pointer", "0" }; + appendln(blk, mkln(size)); + appendln(blk, mkln(memalloc)); + appendln(blk, mkln(poppointer)); + free(size[2]); + + if(con->body != NULL) + return mergelnblks(blk, compilefunbody(c, s, cl, con->body)); + else + return blk; +} + +LINEBLOCK* compilemethod(COMPILER* c, SCOPE* s, CLASS* cl, SUBROUTDEC* m) { + LINE* label = mksubdeclabel(cl, m); + LINEBLOCK* blk = mklnblk(label); + + char* pusharg0[] = { "push", "argument", "0" }; + char* poppointer[] = { "pop", "pointer", "0" }; + appendln(blk, mkln(pusharg0)); + appendln(blk, mkln(poppointer)); + + if(m->body != NULL) + return mergelnblks(blk, compilefunbody(c, s, cl, m->body)); + else + return blk; +} + +LINEBLOCK* compilesubroutdec(COMPILER* c, SCOPE* s, CLASS* cl, SUBROUTDEC* sd) { + SCOPE* myscope = mkscope(s); + if(sd->parameters != NULL) + addparameters(myscope, sd->subroutclass == method, sd->parameters); + if(sd->subroutclass == function) + return compilefundec(c, myscope, cl, sd); + if(sd->subroutclass == constructor) + return compileconstructor(c, myscope, cl, sd); + return compilemethod(c, myscope, cl, sd); +} diff --git a/compiler/compiler-structure.h b/compiler/compiler-structure.h new file mode 100644 index 0000000..36ae94a --- /dev/null +++ b/compiler/compiler-structure.h @@ -0,0 +1,9 @@ +#ifndef COMPILER_STRUCTURE_H +#define COMPILER_STRUCTURE_H +#include "compiler.h" + +/* compiler-structure + * Module for dealing with and compiling general program structure. */ + +LINEBLOCK* compilesubroutdec(COMPILER* c, SCOPE* s, CLASS* cl, SUBROUTDEC* sd); +#endif diff --git a/compiler/compiler-util.h b/compiler/compiler-util.h index 07d79ac..176d18a 100644 --- a/compiler/compiler-util.h +++ b/compiler/compiler-util.h @@ -4,6 +4,9 @@ #include "compiler-scopes.h" #include "compiler.h" +/* compiler-util + * Random utilities for the compiler. */ + #define mkln(id) mksimpleln(id, strcount(id)) LINE* onetoken(char* str); diff --git a/compiler/compiler.c b/compiler/compiler.c index 380050f..76a87a2 100644 --- a/compiler/compiler.c +++ b/compiler/compiler.c @@ -1,280 +1,9 @@ #include -#include +#include "compiler-structure.h" #include "compiler.h" -#include "compiler-util.h" -#include "compiler-expressions.h" - -LINEBLOCK* compilestatements(COMPILER* c, SCOPE* s, STATEMENT* sts); -LINEBLOCK* compileexpression(SCOPE* s, TERM* e); - -int countparameters(PARAMETER* params) { - int i = 0; - while(params != NULL) { - i++; - params = params->next; - } - return i; -} - -int countlocalvars(VARDEC* decs) { - int i = 0; - while(decs != NULL) { - STRINGLIST* curr = decs->names; - while(curr != NULL) { - i++; - curr = curr->next; - } - decs = decs->next; - } - return i; -} - -char* mkcondlabel(char* name, int count) { - int sz = (strlen(name) + countplaces(count) + 1) * sizeof(char); - char* result = (char*)malloc(sz); - sprintf(result, "%s%i", name, count); - return result; -} - -LINE* pushthatadd() { - char* pushthatadd[] = { "push", "pointer", "1" }; - return mkln(pushthatadd); -} - -LINE* popthat() { - char* popthat[] = { "pop", "that", "0" }; - return mkln(popthat); -} - -LINE* pushtemp() { - char* pushtemp[] = { "push", "temp", "0" }; - return mkln(pushtemp); -} - -LINEBLOCK* compileret(SCOPE* s, TERM* e) { - LINE* ret = onetoken("return"); - LINEBLOCK* blk = mklnblk(ret); - - // void subroutdecs return 0 - if(e == NULL) { - char* tokens[] = { "push", "constant", "0" }; - appendlnbefore(blk, mkln(tokens)); - } else - blk = mergelnblks(compileexpression(s, e), blk); - - return blk; -} - -LINEBLOCK* compileif(COMPILER* c, SCOPE* s, IFSTATEMENT* st) { - LINEBLOCK* blk = compileexpression(s, st->base->expression); - - pthread_mutex_lock(&(c->ifmutex)); - static int ifcount = 0; - int mycount = ifcount; - ifcount++; - pthread_mutex_unlock(&(c->ifmutex)); - - char* truelabel = mkcondlabel("IF_TRUE", mycount); - char* ifgoto[] = { "if-goto", truelabel }; - appendln(blk, mkln(ifgoto)); - - char* falselabel = mkcondlabel("IF_FALSE", mycount); - char* gotofalse[] = { "goto", falselabel }; - appendln(blk, mkln(gotofalse)); - - char* truelabelln[] = { "label", truelabel }; - appendln(blk, mkln(truelabelln)); - - blk = mergelnblks(blk, compilestatements(c, s, st->base->statements)); - - char* endlabel; - bool haselse = st->elsestatements != NULL; - if(haselse) { - endlabel = mkcondlabel("IF_END", mycount); - char* endgoto[] = { "goto", endlabel }; - appendln(blk, mkln(endgoto)); - } - - char* falselabelln[] = { "label", falselabel}; - appendln(blk, mkln(falselabelln)); - - if(haselse) { - blk = mergelnblks(blk, compilestatements(c, s, st->elsestatements)); - char* endlabelln[] = { "label", endlabel }; - appendln(blk, mkln(endlabelln)); - } - - return blk; -} - -LINEBLOCK* compilewhile(COMPILER* c, SCOPE* s, CONDSTATEMENT* w) { - LINEBLOCK* blk = compileexpression(s, w->expression); - - pthread_mutex_lock(&(c->whilemutex)); - static int whilecount = 0; - int mycount = whilecount; - whilecount++; - pthread_mutex_unlock(&(c->whilemutex)); - - char* explabel = mkcondlabel("WHILE_EXP", mycount); - char* explabelln[] = { "label", explabel }; - appendlnbefore(blk, mkln(explabelln)); - - appendln(blk, onetoken("not")); - - char* endlabel = mkcondlabel("WHILE_END", mycount); - char* ifgoto[] = { "if-goto", endlabel }; - appendln(blk, mkln(ifgoto)); - - blk = mergelnblks(blk, compilestatements(c, s, w->statements)); - - char* gotoln[] = { "goto", explabel }; - appendln(blk, mkln(gotoln)); - - char* endlabelln[] = { "label", endlabel }; - appendln(blk, mkln(endlabelln)); - - return blk; -} - -LINEBLOCK* compilelet(SCOPE* s, LETSTATEMENT* l) { - LINEBLOCK* blk = compileexpression(s, l->expression); - - if(l->arrayind != NULL) { - appendlnbefore(blk, onetoken("add")); - appendlnbefore(blk, pushvar(s, l->varname)); - blk = mergelnblks(compileexpression(s, l->arrayind), blk); - - appendln(blk, poptemp()); - appendln(blk, popthatadd()); - appendln(blk, pushtemp()); - appendln(blk, popthat()); - } - else - appendln(blk, popvar(s, l->varname)); - return blk; -} - -LINEBLOCK* compilestatement(COMPILER* c, SCOPE* s, STATEMENT* st) { - s->currdebug = st->debug; - if(st->type == dostatement) return compilesubroutcall(s, st->dostatement); - if(st->type == returnstatement) return compileret(s, st->retstatement); - if(st->type == ifstatement) return compileif(c, s, st->ifstatement); - if(st->type == whilestatement) return compilewhile(c, s, st->whilestatement); - if(st->type == letstatement) return compilelet(s, st->letstatement); - eprintf("UNSUPPORTED type %i\n", st->type); - exit(1); -} - -LINEBLOCK* compilestatements(COMPILER* c, SCOPE* s, STATEMENT* sts) { - LINEBLOCK* head = NULL; - while(sts != NULL) { - head = mergelnblks(head, compilestatement(c, s, sts)); - sts = sts->next; - } - return head; -} - -LINEBLOCK* compilefunbody(COMPILER* c, SCOPE* s, CLASS* cl, SUBROUTBODY* b) { - SCOPE* myscope = mkscope(s); - myscope->currclass = cl; - if(b->vardecs != NULL) - addlocalvars(s, b->vardecs); - LINEBLOCK* head = compilestatements(c, myscope, b->statements); - return head; -} - -LINE* mksubdeclabel(CLASS* c, SUBROUTDEC* sd) { - char* labelstrs[] = { "function", dotlabel(c->name, sd->name), itoa(countlocalvars(sd->body->vardecs)) }; - LINE* label = mkln(labelstrs); - free(labelstrs[1]); - free(labelstrs[2]); - label->next = NULL; - return label; -} - -LINEBLOCK* compilefundec(COMPILER* c, SCOPE* s, CLASS* cl, SUBROUTDEC* f) { - LINE* label = mksubdeclabel(cl, f); - - if(f->body->statements != NULL) { - LINEBLOCK* body = compilefunbody(c, s, cl, f->body); - appendlnbefore(body, label); - return body; - } - else - return mklnblk(label); -} - -int countstrs(STRINGLIST* ls) { - int count = 0; - while(ls != NULL) { - count++; - ls = ls->next; - } - return count; -} - -int getobjsize(CLASS* c) { - CLASSVARDEC* curr = c->vardecs; - int count = 0; - while(curr != NULL) { - if(curr->type == field) - count += countstrs(curr->base->names); - curr = curr->next; - } - return count; -} - -LINEBLOCK* compileconstructor(COMPILER* c, SCOPE* s, CLASS* cl, SUBROUTDEC* con) { - LINE* label = mksubdeclabel(cl, con); - LINEBLOCK* blk = mklnblk(label); - - char* size[] = { "push", "constant", itoa(getobjsize(cl)) }; - char* memalloc[] = { "call", "Memory.alloc", "1" }; - char* poppointer[] = { "pop", "pointer", "0" }; - appendln(blk, mkln(size)); - appendln(blk, mkln(memalloc)); - appendln(blk, mkln(poppointer)); - free(size[2]); - - if(con->body != NULL) - return mergelnblks(blk, compilefunbody(c, s, cl, con->body)); - else - return blk; -} - -LINEBLOCK* compilemethod(COMPILER* c, SCOPE* s, CLASS* cl, SUBROUTDEC* m) { - LINE* label = mksubdeclabel(cl, m); - LINEBLOCK* blk = mklnblk(label); - - char* pusharg0[] = { "push", "argument", "0" }; - char* poppointer[] = { "pop", "pointer", "0" }; - appendln(blk, mkln(pusharg0)); - appendln(blk, mkln(poppointer)); - - if(m->body != NULL) - return mergelnblks(blk, compilefunbody(c, s, cl, m->body)); - else - return blk; -} - -LINEBLOCK* compilesubroutdec(COMPILER* c, SCOPE* s, CLASS* cl, SUBROUTDEC* sd) { - // 'this' and arguments are pushed by caller - // Must have a 'return' at the end - // Label names must have class name too (see mapping) - - // types: method, function, constructor - // must switch all of these - SCOPE* myscope = mkscope(s); - if(sd->parameters != NULL) - addparameters(myscope, sd->subroutclass == method, sd->parameters); - if(sd->subroutclass == function) - return compilefundec(c, myscope, cl, sd); - if(sd->subroutclass == constructor) - return compileconstructor(c, myscope, cl, sd); - return compilemethod(c, myscope, cl, sd); -} +/* This should be part of compiler-structure, but since it is used by other modules, + * it will stay here for convenience */ LINEBLOCK* compileclass(COMPILER* c, CLASS* class) { SCOPE* topscope = mkscope(c->globalscope); if(class->vardecs != NULL) diff --git a/compiler/compiler.h b/compiler/compiler.h index 11d6ae7..1ecc1e0 100644 --- a/compiler/compiler.h +++ b/compiler/compiler.h @@ -5,8 +5,11 @@ #include "vm-lines.h" #include "compiler-scopes.h" -struct scope; +/* compiler + * This is the file that should be included in other modules + * that want to compile a class/program. */ +struct scope; typedef struct compiler { pthread_mutex_t ifmutex; pthread_mutex_t whilemutex;