jack-compiler/compiler/compiler.c

312 lines
8.1 KiB
C
Raw Normal View History

2020-12-20 13:58:10 -05:00
#include <stdlib.h>
#include <string.h>
#include "compiler.h"
#include "compiler-util.h"
#include "compiler-expressions.h"
2020-12-20 13:58:10 -05:00
2020-12-31 08:00:21 -05:00
LINEBLOCK* compilestatements(COMPILER* c, SCOPE* s, STATEMENT* sts);
2020-12-27 16:52:28 -05:00
LINEBLOCK* compileexpression(SCOPE* s, TERM* e);
2020-12-22 13:45:12 -05:00
2020-12-27 16:52:28 -05:00
int countparameters(PARAMETER* params) {
2020-12-20 13:58:10 -05:00
int i = 0;
while(params != NULL) {
i++;
params = params->next;
}
return i;
}
int countlocalvars(VARDEC* decs) {
int i = 0;
while(decs != NULL) {
2020-12-27 16:52:28 -05:00
STRINGLIST* curr = decs->names;
while(curr != NULL) {
i++;
curr = curr->next;
}
2020-12-20 13:58:10 -05:00
decs = decs->next;
}
return i;
}
2020-12-27 16:52:28 -05:00
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;
2020-12-20 13:58:10 -05:00
}
2020-12-31 14:49:38 -05:00
LINE* pushthatadd() {
char* pushthatadd[] = { "push", "pointer", "1" };
return mkln(pushthatadd);
2020-12-31 14:49:38 -05:00
}
LINE* popthat() {
char* popthat[] = { "pop", "that", "0" };
return mkln(popthat);
2020-12-31 14:49:38 -05:00
}
LINE* pushtemp() {
char* pushtemp[] = { "push", "temp", "0" };
return mkln(pushtemp);
2020-12-20 13:58:10 -05:00
}
2020-12-21 13:05:49 -05:00
LINEBLOCK* compileret(SCOPE* s, TERM* e) {
LINE* ret = onetoken("return");
2020-12-27 16:52:28 -05:00
LINEBLOCK* blk = mklnblk(ret);
2020-12-21 13:05:49 -05:00
2020-12-21 18:35:41 -05:00
// void subroutdecs return 0
2020-12-20 13:58:10 -05:00
if(e == NULL) {
2020-12-21 13:05:49 -05:00
char* tokens[] = { "push", "constant", "0" };
appendlnbefore(blk, mkln(tokens));
2020-12-21 13:05:49 -05:00
} else
2020-12-27 16:52:28 -05:00
blk = mergelnblks(compileexpression(s, e), blk);
2020-12-21 13:05:49 -05:00
2020-12-27 16:52:28 -05:00
return blk;
2020-12-20 13:58:10 -05:00
}
2020-12-31 08:00:21 -05:00
LINEBLOCK* compileif(COMPILER* c, SCOPE* s, IFSTATEMENT* st) {
2020-12-27 16:52:28 -05:00
LINEBLOCK* blk = compileexpression(s, st->base->expression);
2020-12-31 08:00:21 -05:00
pthread_mutex_lock(&(c->ifmutex));
2020-12-27 16:52:28 -05:00
static int ifcount = 0;
int mycount = ifcount;
ifcount++;
2020-12-31 08:00:21 -05:00
pthread_mutex_unlock(&(c->ifmutex));
2020-12-22 13:45:12 -05:00
2020-12-27 16:52:28 -05:00
char* truelabel = mkcondlabel("IF_TRUE", mycount);
char* ifgoto[] = { "if-goto", truelabel };
appendln(blk, mkln(ifgoto));
2020-12-27 16:52:28 -05:00
char* falselabel = mkcondlabel("IF_FALSE", mycount);
char* gotofalse[] = { "goto", falselabel };
appendln(blk, mkln(gotofalse));
2020-12-27 16:52:28 -05:00
char* truelabelln[] = { "label", truelabel };
appendln(blk, mkln(truelabelln));
2020-12-22 13:45:12 -05:00
2020-12-31 08:00:21 -05:00
blk = mergelnblks(blk, compilestatements(c, s, st->base->statements));
2020-12-22 13:45:12 -05:00
2020-12-27 16:52:28 -05:00
char* endlabel;
2020-12-22 13:45:12 -05:00
bool haselse = st->elsestatements != NULL;
if(haselse) {
2020-12-27 16:52:28 -05:00
endlabel = mkcondlabel("IF_END", mycount);
char* endgoto[] = { "goto", endlabel };
appendln(blk, mkln(endgoto));
2020-12-20 13:58:10 -05:00
}
2020-12-22 13:45:12 -05:00
2020-12-27 16:52:28 -05:00
char* falselabelln[] = { "label", falselabel};
appendln(blk, mkln(falselabelln));
2020-12-22 13:45:12 -05:00
if(haselse) {
2020-12-31 08:00:21 -05:00
blk = mergelnblks(blk, compilestatements(c, s, st->elsestatements));
2020-12-27 16:52:28 -05:00
char* endlabelln[] = { "label", endlabel };
appendln(blk, mkln(endlabelln));
2020-12-22 13:45:12 -05:00
}
2020-12-27 16:52:28 -05:00
return blk;
2020-12-22 13:45:12 -05:00
}
2020-12-31 08:00:21 -05:00
LINEBLOCK* compilewhile(COMPILER* c, SCOPE* s, CONDSTATEMENT* w) {
2020-12-27 16:52:28 -05:00
LINEBLOCK* blk = compileexpression(s, w->expression);
2020-12-22 13:45:12 -05:00
2020-12-31 08:00:21 -05:00
pthread_mutex_lock(&(c->whilemutex));
2020-12-27 16:52:28 -05:00
static int whilecount = 0;
int mycount = whilecount;
whilecount++;
2020-12-31 08:00:21 -05:00
pthread_mutex_unlock(&(c->whilemutex));
2020-12-22 13:45:12 -05:00
2020-12-27 16:52:28 -05:00
char* explabel = mkcondlabel("WHILE_EXP", mycount);
char* explabelln[] = { "label", explabel };
appendlnbefore(blk, mkln(explabelln));
2020-12-22 13:45:12 -05:00
2020-12-27 16:52:28 -05:00
appendln(blk, onetoken("not"));
2020-12-22 13:45:12 -05:00
2020-12-27 16:52:28 -05:00
char* endlabel = mkcondlabel("WHILE_END", mycount);
char* ifgoto[] = { "if-goto", endlabel };
appendln(blk, mkln(ifgoto));
2020-12-22 13:45:12 -05:00
2020-12-31 08:00:21 -05:00
blk = mergelnblks(blk, compilestatements(c, s, w->statements));
2020-12-22 13:45:12 -05:00
2020-12-27 16:52:28 -05:00
char* gotoln[] = { "goto", explabel };
appendln(blk, mkln(gotoln));
2020-12-22 13:45:12 -05:00
2020-12-27 16:52:28 -05:00
char* endlabelln[] = { "label", endlabel };
appendln(blk, mkln(endlabelln));
2020-12-27 16:52:28 -05:00
return blk;
2020-12-22 13:45:12 -05:00
}
2020-12-27 16:52:28 -05:00
LINEBLOCK* compilelet(SCOPE* s, LETSTATEMENT* l) {
LINEBLOCK* blk = compileexpression(s, l->expression);
2020-12-31 14:49:38 -05:00
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));
2020-12-27 16:52:28 -05:00
return blk;
2020-12-22 13:45:12 -05:00
}
2020-12-31 08:00:21 -05:00
LINEBLOCK* compilestatement(COMPILER* c, SCOPE* s, STATEMENT* st) {
2020-12-27 16:52:28 -05:00
s->currdebug = st->debug;
if(st->type == dostatement) return compilesubroutcall(s, st->dostatement);
2020-12-22 13:45:12 -05:00
if(st->type == returnstatement) return compileret(s, st->retstatement);
2020-12-31 08:00:21 -05:00
if(st->type == ifstatement) return compileif(c, s, st->ifstatement);
if(st->type == whilestatement) return compilewhile(c, s, st->whilestatement);
2020-12-27 16:52:28 -05:00
if(st->type == letstatement) return compilelet(s, st->letstatement);
2020-12-22 13:45:12 -05:00
eprintf("UNSUPPORTED type %i\n", st->type);
exit(1);
2020-12-20 13:58:10 -05:00
}
2020-12-31 08:00:21 -05:00
LINEBLOCK* compilestatements(COMPILER* c, SCOPE* s, STATEMENT* sts) {
2020-12-21 13:05:49 -05:00
LINEBLOCK* head = NULL;
while(sts != NULL) {
2020-12-31 08:00:21 -05:00
head = mergelnblks(head, compilestatement(c, s, sts));
2020-12-20 13:58:10 -05:00
sts = sts->next;
}
return head;
}
2020-12-31 08:00:21 -05:00
LINEBLOCK* compilefunbody(COMPILER* c, SCOPE* s, CLASS* cl, SUBROUTBODY* b) {
2020-12-24 14:22:22 -05:00
SCOPE* myscope = mkscope(s);
2020-12-31 08:00:21 -05:00
myscope->currclass = cl;
2020-12-24 14:22:22 -05:00
if(b->vardecs != NULL)
2020-12-27 16:52:28 -05:00
addlocalvars(s, b->vardecs);
2020-12-31 08:00:21 -05:00
LINEBLOCK* head = compilestatements(c, myscope, b->statements);
2020-12-20 13:58:10 -05:00
return head;
}
2020-12-30 18:47:11 -05:00
LINE* mksubdeclabel(CLASS* c, SUBROUTDEC* sd) {
char* labelstrs[] = { "function", dotlabel(c->name, sd->name), itoa(countlocalvars(sd->body->vardecs)) };
LINE* label = mkln(labelstrs);
2020-12-30 18:47:11 -05:00
free(labelstrs[1]);
free(labelstrs[2]);
2020-12-21 13:05:49 -05:00
label->next = NULL;
2020-12-30 18:47:11 -05:00
return label;
}
2020-12-31 08:00:21 -05:00
LINEBLOCK* compilefundec(COMPILER* c, SCOPE* s, CLASS* cl, SUBROUTDEC* f) {
LINE* label = mksubdeclabel(cl, f);
2020-12-20 13:58:10 -05:00
2020-12-21 13:05:49 -05:00
if(f->body->statements != NULL) {
2020-12-31 08:00:21 -05:00
LINEBLOCK* body = compilefunbody(c, s, cl, f->body);
2020-12-21 13:05:49 -05:00
appendlnbefore(body, label);
return body;
}
else
return mklnblk(label);
2020-12-20 13:58:10 -05:00
}
2020-12-30 18:47:11 -05:00
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;
}
2020-12-31 08:00:21 -05:00
LINEBLOCK* compileconstructor(COMPILER* c, SCOPE* s, CLASS* cl, SUBROUTDEC* con) {
LINE* label = mksubdeclabel(cl, con);
2020-12-30 18:47:11 -05:00
LINEBLOCK* blk = mklnblk(label);
char* size[] = { "push", "constant", itoa(getobjsize(cl)) };
2020-12-30 18:47:11 -05:00
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]);
2020-12-30 18:47:11 -05:00
if(con->body != NULL)
2020-12-31 08:00:21 -05:00
return mergelnblks(blk, compilefunbody(c, s, cl, con->body));
2020-12-30 18:47:11 -05:00
else
return blk;
}
2020-12-31 08:00:21 -05:00
LINEBLOCK* compilemethod(COMPILER* c, SCOPE* s, CLASS* cl, SUBROUTDEC* m) {
LINE* label = mksubdeclabel(cl, m);
2020-12-30 18:47:11 -05:00
LINEBLOCK* blk = mklnblk(label);
char* pusharg0[] = { "push", "argument", "0" };
2020-12-30 18:47:11 -05:00
char* poppointer[] = { "pop", "pointer", "0" };
appendln(blk, mkln(pusharg0));
appendln(blk, mkln(poppointer));
2020-12-30 18:47:11 -05:00
if(m->body != NULL)
2020-12-31 08:00:21 -05:00
return mergelnblks(blk, compilefunbody(c, s, cl, m->body));
2020-12-30 18:47:11 -05:00
else
return blk;
}
2020-12-31 08:00:21 -05:00
LINEBLOCK* compilesubroutdec(COMPILER* c, SCOPE* s, CLASS* cl, SUBROUTDEC* sd) {
2020-12-20 13:58:10 -05:00
// '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
2020-12-27 16:52:28 -05:00
SCOPE* myscope = mkscope(s);
if(sd->parameters != NULL)
2020-12-31 15:38:41 -05:00
addparameters(myscope, sd->subroutclass == method, sd->parameters);
2020-12-20 13:58:10 -05:00
if(sd->subroutclass == function)
2020-12-31 08:00:21 -05:00
return compilefundec(c, myscope, cl, sd);
2020-12-30 18:47:11 -05:00
if(sd->subroutclass == constructor)
2020-12-31 08:00:21 -05:00
return compileconstructor(c, myscope, cl, sd);
return compilemethod(c, myscope, cl, sd);
2020-12-20 13:58:10 -05:00
}
2020-12-21 13:05:49 -05:00
LINEBLOCK* compileclass(COMPILER* c, CLASS* class) {
2020-12-20 13:58:10 -05:00
SCOPE* topscope = mkscope(c->globalscope);
2020-12-24 14:22:22 -05:00
if(class->vardecs != NULL)
2020-12-31 11:39:07 -05:00
addclassvardecs(c, topscope, class->vardecs);
2020-12-24 14:22:22 -05:00
if(class->subroutdecs != NULL)
2020-12-27 16:52:28 -05:00
topscope->subroutines = class->subroutdecs;
2020-12-20 13:58:10 -05:00
2020-12-21 13:05:49 -05:00
LINEBLOCK* output = NULL;
2020-12-21 18:35:41 -05:00
SUBROUTDEC* curr = class->subroutdecs;
2020-12-21 13:05:49 -05:00
while(curr != NULL) {
2020-12-31 08:00:21 -05:00
output = mergelnblks(output, compilesubroutdec(c, topscope, class, curr));
2020-12-21 13:05:49 -05:00
curr = curr->next;
2020-12-20 13:58:10 -05:00
}
2020-12-21 13:05:49 -05:00
return output;
2020-12-20 13:58:10 -05:00
}
COMPILER* mkcompiler(CLASS* classes) {
COMPILER* c = (COMPILER*)malloc(sizeof(COMPILER));
c->globalscope = mkscope(NULL);
2020-12-27 16:52:28 -05:00
c->globalscope->classes = classes;
2020-12-24 14:22:22 -05:00
c->classes = classes;
2020-12-31 08:00:21 -05:00
pthread_mutex_init(&(c->ifmutex), NULL);
pthread_mutex_init(&(c->whilemutex), NULL);
2020-12-31 11:39:07 -05:00
pthread_mutex_init(&(c->staticmutex), NULL);
2020-12-20 13:58:10 -05:00
return c;
}
2020-12-31 08:00:21 -05:00
void freecompiler(COMPILER* c) {
pthread_mutex_destroy(&(c->ifmutex));
pthread_mutex_destroy(&(c->whilemutex));
2020-12-31 11:39:07 -05:00
pthread_mutex_destroy(&(c->staticmutex));
2020-12-31 08:00:21 -05:00
// to be continued
free(c);
}