jack-compiler/compiler.c

258 lines
6.0 KiB
C
Raw Normal View History

2020-12-20 13:58:10 -05:00
#include <stdlib.h>
#include <string.h>
#include "compiler.h"
int countparameters(EXPRESSIONLIST* params) {
int i = 0;
while(params != NULL) {
i++;
params = params->next;
}
return i;
}
int countlocalvars(VARDEC* decs) {
int i = 0;
while(decs != NULL) {
i++;
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;
}
char* subdecname(CLASS* c, SUBDEC* sd) {
return dotlabel(c->name, sd->name);
}
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 13:05:49 -05:00
return mksimpleln(tokens, sizeof(tokens) / sizeof(char*));
2020-12-20 13:58:10 -05:00
}
if(op == '*') {
char* tokens[] = { "call", "Math.multiply", "2" };
2020-12-21 13:05:49 -05:00
return mksimpleln(tokens, sizeof(tokens) / sizeof(char*));
2020-12-20 13:58:10 -05:00
}
}
2020-12-21 13:05:49 -05:00
LINEBLOCK* compileexpression(SCOPE* s, TERM* e) {
LINEBLOCK* myblk;
LINEBLOCK* next = NULL;
2020-12-20 13:58:10 -05:00
if(e->type == intconstant) {
2020-12-21 13:21:37 -05:00
char* tokens[] = { "push", "constant", itoa(e->integer) };
myblk = mklnblk(mksimpleln(tokens, sizeof(tokens) / sizeof(char*)));
2020-12-20 13:58:10 -05:00
}
else if(e->type == unaryopterm) {
2020-12-21 13:05:49 -05:00
myblk = compileexpression(s, e->expression);
LINE* neg = onetoken("neg");
appendln(myblk, neg);
2020-12-20 13:58:10 -05:00
}
else if(e->type == innerexpression) {
2020-12-21 13:05:49 -05:00
myblk = compileexpression(s, e->expression);
2020-12-20 13:58:10 -05:00
}
else {
2020-12-21 13:05:49 -05:00
fprintf(stderr, "Unsupported term yet %i\n", e->type);
2020-12-20 13:58:10 -05:00
exit(1);
}
2020-12-21 13:05:49 -05:00
if(e->next != NULL) {
next = compileexpression(s, e->next);
2020-12-21 13:21:37 -05:00
appendln(next, mathopln(e->op));
2020-12-21 13:05:49 -05:00
myblk = mergelnblks(myblk, next);
2020-12-20 13:58:10 -05:00
}
2020-12-21 13:05:49 -05:00
return myblk;
2020-12-20 13:58:10 -05:00
}
2020-12-21 13:05:49 -05:00
LINEBLOCK* compileparameters(SCOPE* s, EXPRESSIONLIST* params) {
LINEBLOCK* head = NULL;
while(params != NULL) {
head = mergelnblks(head, compileexpression(s, params->expression));
params = params->next;
2020-12-20 13:58:10 -05:00
}
return head;
}
2020-12-21 13:05:49 -05:00
LINEBLOCK* compilecallln(CLASS* c, SUBROUTCALL* call) {
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
if(call->parentname != NULL)
2020-12-21 13:05:49 -05:00
addtoken(ln, dotlabel(call->parentname, call->name));
2020-12-20 13:58:10 -05:00
else
2020-12-21 13:05:49 -05:00
addtoken(ln, dotlabel(c->name, call->name));
2020-12-20 13:58:10 -05:00
2020-12-21 13:05:49 -05:00
addtoken(ln, itoa(countparameters(call->parameters)));
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-21 13:05:49 -05:00
// temporary ignore list for OS functions
char* ignoresubdecs[] = {
"printInt", "void"
};
int ignorecount = sizeof(ignoresubdecs) / sizeof(char*);
LINEBLOCK* compilesubroutcall(SCOPE* s, CLASS* c, SUBROUTCALL* call) {
LINEBLOCK* block = compilecallln(c, call);
if(call->parameters != NULL)
block = mergelnblks(compileparameters(s, call->parameters), block);
// void functions always return 0
// therefore must be thrown away
// gambiarra
char* type = NULL;
for(int i = 0; i < ignorecount; i += 2) {
if(!strcmp(call->name, ignoresubdecs[i])) {
type = ignoresubdecs[i+1];
break;
}
}
if(type == NULL)
type = getsubdecfromcall(s, call)->type;
if(!strcmp(type, "void")) {
char* tokens[] = { "pop", "temp", "0" };
appendln(block, mksimpleln(tokens, sizeof(tokens) / sizeof(char*)));
}
return block;
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");
LINEBLOCK* block = mklnblk(ret);
// void subdecs 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(block, mksimpleln(tokens, sizeof(tokens) / sizeof(char*)));
} else
block = mergelnblks(compileexpression(s, e), block);
return block;
2020-12-20 13:58:10 -05:00
}
2020-12-21 13:05:49 -05:00
LINEBLOCK* compilestatement(SCOPE* s, CLASS* c, STATEMENT* st) {
2020-12-20 13:58:10 -05:00
if(st->type == dostatement)
return compilesubroutcall(s, c, st->dost);
else if(st->type == returnstatement)
return compileret(s, st->retst);
else {
fprintf(stderr, "UNSUPPORTED\n");
exit(1);
}
}
2020-12-21 13:05:49 -05:00
LINEBLOCK* compilestatements(SCOPE* s, CLASS* c, STATEMENT* sts) {
LINEBLOCK* head = NULL;
while(sts != NULL) {
head = mergelnblks(head, compilestatement(s, c, sts));
2020-12-20 13:58:10 -05:00
sts = sts->next;
}
return head;
}
2020-12-21 13:05:49 -05:00
LINEBLOCK* compilefunbody(SCOPE* s, CLASS* c, SUBROUTBODY* b) {
2020-12-20 13:58:10 -05:00
// missing scope and vardecs handling
2020-12-21 13:05:49 -05:00
LINEBLOCK* head = compilestatements(s, c, b->statements);
2020-12-20 13:58:10 -05:00
return head;
}
2020-12-21 13:05:49 -05:00
LINEBLOCK* compilefundec(SCOPE* s, CLASS* c, SUBDEC* f) {
LINE* label = mkline(3);
addtoken(label, ezheapstr("function"));
addtoken(label, subdecname(c, f));
addtoken(label, itoa(countlocalvars(f->body->vardecs)));
label->next = NULL;
2020-12-20 13:58:10 -05:00
2020-12-21 13:05:49 -05:00
if(f->body->statements != NULL) {
LINEBLOCK* body = compilefunbody(s, c, f->body);
appendlnbefore(body, label);
return body;
}
else
return mklnblk(label);
2020-12-20 13:58:10 -05:00
}
2020-12-21 13:05:49 -05:00
LINEBLOCK* compilesubdec(SCOPE* s, CLASS* c, SUBDEC* 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
if(sd->subroutclass == function)
return compilefundec(s, c, sd);
}
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);
addclassvardecs(topscope, class->vardecs);
addsubdecs(topscope, class->subdecs);
2020-12-21 13:05:49 -05:00
LINEBLOCK* output = NULL;
SUBDEC* curr = class->subdecs;
while(curr != NULL) {
output = mergelnblks(output, compilesubdec(topscope, class, curr));
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
}
void compile(COMPILER* c) {
2020-12-21 13:05:49 -05:00
LINEBLOCK* output = NULL;
CLASS* curr = c->globalscope->classes;
while(curr != NULL) {
output = mergelnblks(output, compileclass(c, curr));
curr = curr->next;
2020-12-20 13:58:10 -05:00
}
2020-12-21 13:05:49 -05:00
c->output = output;
2020-12-20 13:58:10 -05:00
}
COMPILER* mkcompiler(CLASS* classes) {
COMPILER* c = (COMPILER*)malloc(sizeof(COMPILER));
c->globalscope = mkscope(NULL);
addclasses(c->globalscope, classes);
return c;
}