2020-12-20 13:58:10 -05:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
2020-12-31 08:00:21 -05:00
|
|
|
#include <pthread.h>
|
2020-12-20 13:58:10 -05:00
|
|
|
#include "compiler.h"
|
|
|
|
|
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* compilesubroutcall(SCOPE* s, SUBROUTCALL* call);
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2020-12-27 16:52:28 -05:00
|
|
|
int countexpressions(EXPRESSIONLIST* explist) {
|
|
|
|
int i = 0;
|
|
|
|
while(explist != NULL) {
|
|
|
|
i++;
|
|
|
|
explist = explist->next;
|
|
|
|
}
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
2020-12-20 13:58:10 -05:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
char* dotlabel(char* n1, char* n2) {
|
|
|
|
int sz = (strlen(n1) + strlen(n2) + 2) * sizeof(char);
|
|
|
|
char* result = (char*)malloc(sz);
|
2020-12-21 13:05:49 -05:00
|
|
|
sprintf(result, "%s.%s", n1, n2);
|
2020-12-20 13:58:10 -05:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
LINE* onetoken(char* str) {
|
|
|
|
LINE* ln = mkline(1);
|
|
|
|
addtoken(ln, ezheapstr(str));
|
2020-12-21 13:05:49 -05:00
|
|
|
ln->next = NULL;
|
2020-12-20 13:58:10 -05:00
|
|
|
return ln;
|
|
|
|
}
|
|
|
|
|
2020-12-21 13:05:49 -05:00
|
|
|
LINE* mksimpleln(char** tokens, int count) {
|
2020-12-20 13:58:10 -05:00
|
|
|
LINE* ln = mkline(count);
|
|
|
|
for(int i = 0; i < count; i++)
|
|
|
|
addtoken(ln, ezheapstr(tokens[i]));
|
2020-12-21 13:21:37 -05:00
|
|
|
ln->next = NULL;
|
2020-12-20 13:58:10 -05:00
|
|
|
return ln;
|
|
|
|
}
|
|
|
|
|
|
|
|
LINE* mathopln(char op) {
|
|
|
|
if(op == '+')
|
|
|
|
return onetoken("add");
|
|
|
|
if(op == '-')
|
|
|
|
return onetoken("sub");
|
|
|
|
if(op == '=')
|
|
|
|
return onetoken("eq");
|
|
|
|
if(op == '>')
|
|
|
|
return onetoken("gt");
|
|
|
|
if(op == '<')
|
|
|
|
return onetoken("lt");
|
|
|
|
if(op == '|')
|
|
|
|
return onetoken("or");
|
|
|
|
if(op == '&')
|
|
|
|
return onetoken("and");
|
|
|
|
if(op == '/') {
|
|
|
|
char* tokens[] = { "call", "Math.divide", "2" };
|
2020-12-21 16:11:23 -05:00
|
|
|
return mksimpleln(tokens, strcount(tokens));
|
2020-12-20 13:58:10 -05:00
|
|
|
}
|
|
|
|
if(op == '*') {
|
|
|
|
char* tokens[] = { "call", "Math.multiply", "2" };
|
2020-12-21 16:11:23 -05:00
|
|
|
return mksimpleln(tokens, strcount(tokens));
|
2020-12-20 13:58:10 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-27 16:52:28 -05:00
|
|
|
LINEBLOCK* pushconstant(int n) {
|
|
|
|
char* tokens[] = { "push", "constant", itoa(n) };
|
|
|
|
return mklnblk(mksimpleln(tokens, strcount(tokens)));
|
|
|
|
}
|
2020-12-20 13:58:10 -05:00
|
|
|
|
2020-12-27 16:52:28 -05:00
|
|
|
LINEBLOCK* pushunaryopterm(SCOPE* s, TERM* t) {
|
|
|
|
LINEBLOCK* blk = compileexpression(s, t->expression);
|
|
|
|
LINE* neg;
|
|
|
|
if(t->unaryop == '-')
|
|
|
|
neg = onetoken("neg");
|
|
|
|
else
|
|
|
|
neg = onetoken("not");
|
|
|
|
appendln(blk, neg);
|
|
|
|
return blk;
|
|
|
|
}
|
|
|
|
|
2020-12-31 11:07:26 -05:00
|
|
|
LINEBLOCK* opvarraw(SCOPE* s, char* op, VAR* v) {
|
2020-12-27 16:52:28 -05:00
|
|
|
char* tokens[] = { op, v->memsegment, itoa(v->index) };
|
|
|
|
return mklnblk(mksimpleln(tokens, strcount(tokens)));
|
2020-12-31 11:07:26 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
LINEBLOCK* opvar(SCOPE* s, char* op, const char* name) {
|
|
|
|
VAR* v = getvar(s, name);
|
|
|
|
return opvarraw(s, op, v);
|
|
|
|
}
|
2020-12-27 16:52:28 -05:00
|
|
|
|
2020-12-31 11:07:26 -05:00
|
|
|
LINEBLOCK* pushvarraw(SCOPE*s, VAR* v) {
|
|
|
|
return opvarraw(s, "push", v);
|
2020-12-27 16:52:28 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
LINEBLOCK* pushvar(SCOPE* s, const char* name) {
|
|
|
|
return opvar(s, "push", name);
|
|
|
|
}
|
|
|
|
|
|
|
|
LINEBLOCK* popvar(SCOPE* s, const char* name) {
|
|
|
|
return opvar(s, "pop", name);
|
|
|
|
}
|
|
|
|
|
|
|
|
LINEBLOCK* pushfalse() {
|
|
|
|
return pushconstant(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
LINEBLOCK* pushtrue() {
|
|
|
|
LINEBLOCK* blk = pushfalse();
|
|
|
|
appendln(blk, onetoken("not"));
|
|
|
|
return blk;
|
|
|
|
}
|
|
|
|
|
2020-12-30 18:47:11 -05:00
|
|
|
LINEBLOCK* pushthis() {
|
|
|
|
char* pushthis[] = { "push", "pointer", "0" };
|
|
|
|
return mklnblk(mksimpleln(pushthis, strcount(pushthis)));
|
|
|
|
}
|
|
|
|
|
2020-12-27 16:52:28 -05:00
|
|
|
LINEBLOCK* compilekeywordconst(SCOPE* s, TERM* t) {
|
|
|
|
if(!strcmp(t->string, "true")) return pushtrue();
|
|
|
|
if(!strcmp(t->string, "false")) return pushfalse();
|
2020-12-30 18:47:11 -05:00
|
|
|
if(!strcmp(t->string, "this")) return pushthis();
|
2020-12-27 16:52:28 -05:00
|
|
|
eprintf("Unsupported keyword '%s'\n", t->string);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
LINEBLOCK* compileterm(SCOPE* s, TERM* t) {
|
|
|
|
if(t->type == intconstant) return pushconstant(t->integer);
|
|
|
|
if(t->type == unaryopterm) return pushunaryopterm(s, t);
|
|
|
|
if(t->type == innerexpression) return compileexpression(s, t->expression);
|
|
|
|
if(t->type == varname) return pushvar(s, t->string);
|
|
|
|
if(t->type == subroutcall) return compilesubroutcall(s, t->call);
|
|
|
|
if(t->type == keywordconstant) return compilekeywordconst(s, t);
|
2020-12-20 13:58:10 -05:00
|
|
|
else {
|
2020-12-27 16:52:28 -05:00
|
|
|
eprintf("Unsupported term yet %i\n", t->type);
|
2020-12-20 13:58:10 -05:00
|
|
|
exit(1);
|
|
|
|
}
|
2020-12-27 16:52:28 -05:00
|
|
|
}
|
2020-12-20 13:58:10 -05:00
|
|
|
|
2020-12-27 16:52:28 -05:00
|
|
|
LINEBLOCK* compileexpression(SCOPE* s, TERM* e) {
|
|
|
|
LINEBLOCK* blk = compileterm(s, e);
|
|
|
|
TERM* curr = e->next;
|
|
|
|
if(curr != NULL) {
|
|
|
|
while(true) {
|
|
|
|
blk = mergelnblks(blk, compileterm(s, curr));
|
|
|
|
if(curr->next != NULL) {
|
|
|
|
appendln(blk, mathopln(curr->op));
|
|
|
|
curr = curr->next;
|
|
|
|
}
|
|
|
|
else break;
|
|
|
|
}
|
|
|
|
appendln(blk, mathopln(e->op));
|
2020-12-20 13:58:10 -05:00
|
|
|
}
|
2020-12-27 16:52:28 -05:00
|
|
|
return blk;
|
2020-12-20 13:58:10 -05:00
|
|
|
}
|
|
|
|
|
2020-12-27 16:52:28 -05:00
|
|
|
LINEBLOCK* compileexplist(SCOPE* s, EXPRESSIONLIST* explist) {
|
2020-12-21 13:05:49 -05:00
|
|
|
LINEBLOCK* head = NULL;
|
2020-12-27 16:52:28 -05:00
|
|
|
while(explist != NULL) {
|
|
|
|
head = mergelnblks(head, compileexpression(s, explist->expression));
|
|
|
|
explist = explist->next;
|
2020-12-20 13:58:10 -05:00
|
|
|
}
|
|
|
|
return head;
|
|
|
|
}
|
|
|
|
|
2020-12-31 11:07:26 -05:00
|
|
|
LINEBLOCK* compilecallln(SCOPE* s, SUBROUTDEC* d, SUBROUTCALL* call) {
|
2020-12-21 13:05:49 -05:00
|
|
|
LINE* ln = mkline(3);
|
2020-12-20 13:58:10 -05:00
|
|
|
|
2020-12-21 13:05:49 -05:00
|
|
|
addtoken(ln, ezheapstr("call"));
|
2020-12-20 13:58:10 -05:00
|
|
|
|
2020-12-31 11:07:26 -05:00
|
|
|
addtoken(ln, dotlabel(d->class->name, call->name));
|
2020-12-20 13:58:10 -05:00
|
|
|
|
2020-12-31 11:07:26 -05:00
|
|
|
int count = countexpressions(call->parameters);
|
|
|
|
if(d->subroutclass == method)
|
|
|
|
count++;
|
|
|
|
addtoken(ln, itoa(count));
|
2020-12-20 13:58:10 -05:00
|
|
|
|
2020-12-21 13:05:49 -05:00
|
|
|
return mklnblk(ln);
|
|
|
|
}
|
2020-12-20 13:58:10 -05:00
|
|
|
|
2020-12-27 16:52:28 -05:00
|
|
|
LINEBLOCK* compilesubroutcall(SCOPE* s, SUBROUTCALL* call) {
|
2020-12-31 11:07:26 -05:00
|
|
|
VAR* v;
|
|
|
|
SUBROUTDEC* d = getsubroutdecfromcall(s, call, &v);
|
|
|
|
LINEBLOCK* blk = compilecallln(s, d, call);
|
2020-12-21 13:05:49 -05:00
|
|
|
|
|
|
|
if(call->parameters != NULL)
|
2020-12-27 16:52:28 -05:00
|
|
|
blk = mergelnblks(compileexplist(s, call->parameters), blk);
|
2020-12-21 13:05:49 -05:00
|
|
|
|
2020-12-31 11:07:26 -05:00
|
|
|
if(d->subroutclass == method) {
|
2020-12-30 18:47:11 -05:00
|
|
|
if(call->parentname == NULL)
|
|
|
|
blk = mergelnblks(pushthis(), blk);
|
|
|
|
else
|
2020-12-31 11:07:26 -05:00
|
|
|
blk = mergelnblks(pushvarraw(s, v), blk);
|
2020-12-30 18:47:11 -05:00
|
|
|
}
|
2020-12-31 11:07:26 -05:00
|
|
|
|
|
|
|
// void functions always return 0
|
|
|
|
// therefore must be thrown away
|
|
|
|
if(!strcmp(d->type, "void")) {
|
2020-12-21 13:05:49 -05:00
|
|
|
char* tokens[] = { "pop", "temp", "0" };
|
2020-12-27 16:52:28 -05:00
|
|
|
appendln(blk, mksimpleln(tokens, sizeof(tokens) / sizeof(char*)));
|
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-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" };
|
2020-12-27 16:52:28 -05:00
|
|
|
appendlnbefore(blk, mksimpleln(tokens, strcount(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, mksimpleln(ifgoto, strcount(ifgoto)));
|
|
|
|
|
|
|
|
char* falselabel = mkcondlabel("IF_FALSE", mycount);
|
|
|
|
char* gotofalse[] = { "goto", falselabel };
|
|
|
|
appendln(blk, mksimpleln(gotofalse, strcount(gotofalse)));
|
|
|
|
|
|
|
|
char* truelabelln[] = { "label", truelabel };
|
|
|
|
appendln(blk, mksimpleln(truelabelln, strcount(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, mksimpleln(endgoto, strcount(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, mksimpleln(falselabelln, strcount(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, mksimpleln(endlabelln, strcount(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, mksimpleln(explabelln, strcount(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, mksimpleln(ifgoto, strcount(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, mksimpleln(gotoln, strcount(gotoln)));
|
2020-12-22 13:45:12 -05:00
|
|
|
|
2020-12-27 16:52:28 -05:00
|
|
|
char* endlabelln[] = { "label", endlabel };
|
|
|
|
appendln(blk, mksimpleln(endlabelln, strcount(endlabelln)));
|
|
|
|
|
|
|
|
return blk;
|
2020-12-22 13:45:12 -05:00
|
|
|
}
|
|
|
|
|
2020-12-27 16:52:28 -05:00
|
|
|
LINEBLOCK* compilelet(SCOPE* s, LETSTATEMENT* l) {
|
|
|
|
// missing array ind
|
|
|
|
LINEBLOCK* blk = compileexpression(s, l->expression);
|
|
|
|
blk = mergelnblks(blk, popvar(s, l->varname));
|
|
|
|
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 = mksimpleln(labelstrs, strcount(labelstrs));
|
|
|
|
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);
|
|
|
|
|
2020-12-31 11:07:26 -05:00
|
|
|
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, mksimpleln(size, strcount(size)));
|
|
|
|
appendln(blk, mksimpleln(memalloc, strcount(memalloc)));
|
|
|
|
appendln(blk, mksimpleln(poppointer, strcount(poppointer)));
|
2020-12-31 11:07:26 -05:00
|
|
|
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);
|
|
|
|
|
2020-12-31 11:07:26 -05:00
|
|
|
char* pusharg0[] = { "push", "argument", "0" };
|
2020-12-30 18:47:11 -05:00
|
|
|
char* poppointer[] = { "pop", "pointer", "0" };
|
|
|
|
appendln(blk, mksimpleln(pusharg0, strcount(pusharg0)));
|
|
|
|
appendln(blk, mksimpleln(poppointer, strcount(poppointer)));
|
|
|
|
|
|
|
|
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)
|
|
|
|
addparameters(myscope, 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)
|
|
|
|
addclassvardecs(topscope, class->vardecs);
|
|
|
|
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-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));
|
|
|
|
// to be continued
|
|
|
|
free(c);
|
|
|
|
}
|