jackc/vm/vm-translator.c

438 lines
9.7 KiB
C
Raw Permalink Normal View History

2021-01-04 15:00:48 -05:00
#include <stdlib.h>
#include <string.h>
#include "vm-templates.h"
#include "vm-translator.h"
#include "util.h"
#define eq(translator, index, str) !strcmp(translator->currln->tokens[index], str)
STRINGLIST* asmln(char* content) {
STRINGLIST* ln = (STRINGLIST*)malloc(sizeof(STRINGLIST));
ln->content = content;
return ln;
}
void togarbage(VMTRANSLATOR* t, char* str) {
STRINGLIST* garb = asmln(str);
garb->next = t->garbage;
t->garbage = garb;
}
char* atraw(VMTRANSLATOR* t, char* n, int len) {
int sz = sizeof(char) * (len + 2);
char* atstr = (char*)malloc(sz);
sprintf(atstr, "@%s", n);
togarbage(t, atstr);
return atstr;
}
char* at(VMTRANSLATOR* t, char* n) {
return atraw(t, n, strlen(n));
}
char* atn(VMTRANSLATOR* t, int n) {
char* str = itoa(n);
togarbage(t, str);
return at(t, str);
}
char* mkstr(VMTRANSLATOR* t, char* str) {
char* heapstr = ezheapstr(str);
togarbage(t, heapstr);
return heapstr;
}
char* mkpointerind(VMTRANSLATOR* t) {
if(t->currln->tokens[2][0] == 0)
return mkstr(t, "@THIS");
else
return mkstr(t, "@THAT");
}
char* mktempind(VMTRANSLATOR* t) {
int index = atoi(t->currln->tokens[2]);
char* actualind = itoa(index+5);
togarbage(t, actualind);
return at(t, actualind);
}
char* dotat(VMTRANSLATOR* t, char* name, char* n) {
int sz = sizeof(char) * (strlen(name) + strlen(n) + 3);
char* atstr = (char*)malloc(sz);
sprintf(atstr, "@%s.%s", name, n);
togarbage(t, atstr);
return atstr;
}
char* switchsegment(VMTRANSLATOR* t) {
if(eq(t, 1, "local"))
return mkstr(t, "@LCL");
if(eq(t, 1, "argument"))
return mkstr(t, "@ARG");
if(eq(t, 1, "this"))
return mkstr(t, "@THIS");
return mkstr(t, "@THAT");
}
char* mkspeciallab(VMTRANSLATOR* t, char* suffix, int* ind, int* len) {
(*ind)++;
*len = t->classnamelen + countplaces(*ind) + strlen(suffix) + 2;
int sz = ((*len)+1) * sizeof(char);
char* lab = (char*)malloc(sz);
sprintf(lab, "%s$%s.%i", t->classname, suffix, (*ind));
togarbage(t, lab);
return lab;
}
char* mkcmplab(VMTRANSLATOR* t, int* len) {
return mkspeciallab(t, "cmp", &(t->cmpind), len);
}
char* mkretlab(VMTRANSLATOR* t, int* len) {
return mkspeciallab(t, "ret", &(t->retind), len);
}
char* enclosingparenthesis(VMTRANSLATOR* t, char* content, int len) {
int sz = sizeof(char) * (len + 3);
char* str = (char*)malloc(sz);
sprintf(str, "(%s)", content);
togarbage(t, str);
return str;
}
char* mklab(VMTRANSLATOR* t) {
int sz = (t->classnamelen + strlen(t->currln->tokens[1]) + 4) * sizeof(char);
char* lab = (char*)malloc(sz);
sprintf(lab, "(%s$%s)", t->classname, t->currln->tokens[1]);
togarbage(t, lab);
return lab;
}
char* mkgotolab(VMTRANSLATOR* t) {
int sz = sizeof(char) * (t->classnamelen + strlen(t->currln->tokens[1]) + 3);
char* lab = (char*)malloc(sz);
sprintf(lab, "@%s$%s", t->classname, t->currln->tokens[1]);
togarbage(t, lab);
return lab;
}
ASMBLK* copytemplate(TEMPLATE* t) {
ASMBLK* blk = (ASMBLK*)malloc(sizeof(ASMBLK));
blk->head = asmln(t->items[0]);
STRINGLIST* curr = blk->head;
for(int i = 1; i < t->count; i++) {
STRINGLIST* newln = asmln(t->items[i]);
curr->next = newln;
curr = newln;
}
curr->next = NULL;
blk->tail = curr;
return blk;
}
void mergeasmblks(ASMBLK* a, ASMBLK* b) {
a->tail->next = b->head;
a->tail = b->tail;
free(b);
}
/* START STACK MANIPULATION */
ASMBLK* translatepushconst(VMTRANSLATOR* t) {
// @i
2021-01-05 11:00:23 -05:00
tpushcons.items[0] = at(t, t->currln->tokens[2]);
2021-01-04 15:00:48 -05:00
2021-01-05 11:00:23 -05:00
return copytemplate(&tpushcons);
2021-01-04 15:00:48 -05:00
}
ASMBLK* translatepushstatic(VMTRANSLATOR* t) {
// @classname.i
2021-01-05 11:00:23 -05:00
tpushstat.items[0] = dotat(t, t->classname, t->currln->tokens[2]);
2021-01-04 15:00:48 -05:00
2021-01-05 11:00:23 -05:00
return copytemplate(&tpushstat);
2021-01-04 15:00:48 -05:00
}
ASMBLK* translatepushpointer(VMTRANSLATOR* t) {
// @THIS/@THAT
2021-01-05 11:00:23 -05:00
tpushpointer.items[0] = mkpointerind(t);
2021-01-04 15:00:48 -05:00
2021-01-05 11:00:23 -05:00
return copytemplate(&tpushpointer);
2021-01-04 15:00:48 -05:00
}
ASMBLK* translatepushtemp(VMTRANSLATOR* t) {
// @5+i
2021-01-05 11:00:23 -05:00
tpushtemp.items[0] = mktempind(t);
2021-01-04 15:00:48 -05:00
2021-01-05 11:00:23 -05:00
return copytemplate(&tpushtemp);
2021-01-04 15:00:48 -05:00
}
void pushpopcommon(VMTRANSLATOR* t, TEMPLATE* tp) {
// @segment
2021-01-05 11:00:23 -05:00
tp->items[0] = switchsegment(t);
2021-01-04 15:00:48 -05:00
// D=M
2021-01-05 11:00:23 -05:00
tp->items[1] = mkstr(t, "D=M");
2021-01-04 15:00:48 -05:00
// @i
2021-01-05 11:00:23 -05:00
tp->items[2] = at(t, t->currln->tokens[2]);
2021-01-04 15:00:48 -05:00
}
ASMBLK* translatepushgeneric(VMTRANSLATOR* t) {
pushpopcommon(t, &tpush);
2021-01-05 11:00:23 -05:00
return copytemplate(&tpush);
2021-01-04 15:00:48 -05:00
}
ASMBLK* translatepush(VMTRANSLATOR* t) {
if(eq(t, 1, "constant"))
return translatepushconst(t);
if(eq(t, 1, "static"))
return translatepushstatic(t);
if(eq(t, 1, "pointer"))
return translatepushpointer(t);
if(eq(t, 1, "temp"))
return translatepushtemp(t);
return translatepushgeneric(t);
}
ASMBLK* translatepopstatic(VMTRANSLATOR* t) {
// @classname.i
tpopstat.items[tpopstat.count-2] = dotat(t, t->classname, t->currln->tokens[2]);
// M=D
tpopstat.items[tpopstat.count-1] = mkstr(t, "M=D");
2021-01-05 11:00:23 -05:00
return copytemplate(&tpopstat);
2021-01-04 15:00:48 -05:00
}
ASMBLK* translatepoppointer(VMTRANSLATOR* t) {
// @THIS/@THAT
tpoppointer.items[tpoppointer.count-2] = mkpointerind(t);
// M=D
tpoppointer.items[tpoppointer.count-1] = mkstr(t, "M=D");
2021-01-05 11:00:23 -05:00
return copytemplate(&tpoppointer);
2021-01-04 15:00:48 -05:00
}
ASMBLK* translatepoptemp(VMTRANSLATOR* t) {
// @5+i
tpoptemp.items[tpoptemp.count-2] = mktempind(t);
tpoptemp.items[tpoptemp.count-1] = mkstr(t, "M=D");
2021-01-05 11:00:23 -05:00
return copytemplate(&tpoptemp);
2021-01-04 15:00:48 -05:00
}
ASMBLK* translatepopgeneric(VMTRANSLATOR* t) {
pushpopcommon(t, &tpop);
2021-01-05 11:00:23 -05:00
return copytemplate(&tpop);
2021-01-04 15:00:48 -05:00
}
ASMBLK* translatepop(VMTRANSLATOR* t) {
if(eq(t, 1, "static"))
return translatepopstatic(t);
if(eq(t, 1, "pointer"))
return translatepoppointer(t);
if(eq(t, 1, "temp"))
return translatepoptemp(t);
return translatepopgeneric(t);
}
/* END STACK MANIPULATION */
/* BEGIN OPERATIONS */
ASMBLK* translatearith(VMTRANSLATOR* t, char* op) {
tarith.items[tarith.count-1] = mkstr(t, op);
2021-01-05 11:00:23 -05:00
return copytemplate(&tarith);
2021-01-04 15:00:48 -05:00
}
ASMBLK* translatecomp(VMTRANSLATOR* t, char* op) {
int labellen;
char* label = mkcmplab(t, &labellen);
// @label
tcomp.items[tcomp.count-6] = atraw(t, label, labellen);
// D;J(op)
int sz = sizeof(char) * 6;
char* trueop = (char*)malloc(sz);
sprintf(trueop, "D;J%s", op);
tcomp.items[tcomp.count-5] = trueop;
togarbage(t, trueop);
// (label)
tcomp.items[tcomp.count-1] = enclosingparenthesis(t, label, labellen);
2021-01-05 11:00:23 -05:00
return copytemplate(&tcomp);
2021-01-04 15:00:48 -05:00
}
/* END OPERATIONS */
ASMBLK* translatelabel(VMTRANSLATOR* t) {
// (classname$label)
tlabel.items[tlabel.count-1] = mklab(t);
2021-01-05 11:00:23 -05:00
return copytemplate(&tlabel);
2021-01-04 15:00:48 -05:00
}
ASMBLK* translategoto(VMTRANSLATOR* t) {
// @label
tgoto.items[tgoto.count-2] = mkgotolab(t);
2021-01-05 11:00:23 -05:00
return copytemplate(&tgoto);
2021-01-04 15:00:48 -05:00
}
ASMBLK* translateifgoto(VMTRANSLATOR* t) {
// @label
tifgoto.items[tifgoto.count-2] = mkgotolab(t);
2021-01-05 11:00:23 -05:00
return copytemplate(&tifgoto);
2021-01-04 15:00:48 -05:00
}
ASMBLK* translatereturn(VMTRANSLATOR* t) {
2021-01-05 11:00:23 -05:00
ASMBLK* blk = copytemplate(&tstartreturn);
2021-01-04 15:00:48 -05:00
for(int i = tframevars.count-1; i >= 0; i--) {
tretpop.items[tretpop.count-2] = tframevars.items[i];
mergeasmblks(blk, copytemplate(&tretpop));
}
mergeasmblks(blk, copytemplate(&tendreturn));
return blk;
}
ASMBLK* translatefunction(VMTRANSLATOR* t) {
t->retind = 0;
t->cmpind = 0;
// (funcname)
2021-01-05 11:00:23 -05:00
tfunction.items[0] = mklab(t);
ASMBLK* blk = copytemplate(&tfunction);
2021-01-04 15:00:48 -05:00
// repeat nVars times:
int nlocals = atoi(t->currln->tokens[2]);
for(int i = 0; i < nlocals; i++)
mergeasmblks(blk, copytemplate(&tfunctionpush));
return blk;
}
ASMBLK* pushframe(VMTRANSLATOR* t, char* retlab, int retlablen, int* framesize) {
tcallstart.items[1] = atraw(t, retlab, retlablen);
2021-01-05 11:00:23 -05:00
ASMBLK* blk = copytemplate(&tcallstart);
2021-01-04 15:00:48 -05:00
for(int i = 0; i < tframevars.count; i++) {
tcallpush.items[0] = tframevars.items[i];
mergeasmblks(blk, copytemplate((&tcallpush)));
}
*framesize = tframevars.count + 1;
return blk;
}
ASMBLK* translatecall(VMTRANSLATOR* t) {
// return label
int retlablen;
char* retlab = mkretlab(t, &retlablen);
// push frame
int framesize;
ASMBLK* blk = pushframe(t, retlab, retlablen, &framesize);
// setting ARG
int nargs = atoi(t->currln->tokens[2]);
tcallsetarg.items[tcallsetarg.count-4] = atn(t, nargs + framesize);
mergeasmblks(blk, copytemplate(&tcallsetarg));
// jmp
tcalljmp.items[tcalljmp.count-3] = at(t, t->currln->tokens[1]);
tcalljmp.items[tcalljmp.count-1] = enclosingparenthesis(t, retlab, retlablen);
mergeasmblks(blk, copytemplate(&tcalljmp));
return blk;
}
ASMBLK* translateln(VMTRANSLATOR* t) {
if(eq(t, 0, "push"))
return translatepush(t);
if(eq(t, 0, "pop"))
return translatepop(t);
if(eq(t, 0, "add"))
return translatearith(t, "M=D+M");
if(eq(t, 0, "sub"))
return translatearith(t, "M=M-D");
if(eq(t, 0, "and"))
return translatearith(t, "M=D&M");
if(eq(t, 0, "or"))
return translatearith(t, "M=D|M");
if(eq(t, 0, "neg"))
2021-01-05 11:00:23 -05:00
return copytemplate(&tneg);
2021-01-04 15:00:48 -05:00
if(eq(t, 0, "not"))
2021-01-05 11:00:23 -05:00
return copytemplate(&tnot);
2021-01-04 15:00:48 -05:00
if(eq(t, 0, "eq"))
return translatecomp(t, "EQ");
if(eq(t, 0, "gt"))
return translatecomp(t, "LT");
if(eq(t, 0, "lt"))
return translatecomp(t, "GT");
if(eq(t, 0, "label"))
return translatelabel(t);
if(eq(t, 0, "goto"))
return translategoto(t);
if(eq(t, 0, "if-goto"))
return translateifgoto(t);
if(eq(t, 0, "return"))
return translatereturn(t);
if(eq(t, 0, "function"))
return translatefunction(t);
return translatecall(t);
}
2021-01-05 11:00:23 -05:00
ASMBLK* translatevm(VMTRANSLATOR* t) {
2021-01-04 15:00:48 -05:00
ASMBLK* blk = copytemplate(&tbootstrap);
while(t->currln != NULL) {
mergeasmblks(blk, translateln(t));
t->currln = t->currln->next;
}
2021-01-05 11:00:23 -05:00
return blk;
2021-01-04 15:00:48 -05:00
}
VMTRANSLATOR* mkvmtranslator(char* classname, LINEBLOCK* vmlines) {
VMTRANSLATOR* transl = (VMTRANSLATOR*)malloc(sizeof(VMTRANSLATOR));
transl->currln = vmlines->head;
transl->start = vmlines->head;
transl->garbage = NULL;
transl->retind = 0;
transl->cmpind = 0;
transl->classname = classname;
transl->classnamelen = strlen(classname);
return transl;
}
void freegarbage(STRINGLIST* garbage) {
if(garbage != NULL) {
free(garbage->content);
STRINGLIST* next = garbage->next;
free(garbage);
freegarbage(next);
}
}
void freevmtranslator(VMTRANSLATOR* t) {
freegarbage(t->garbage);
free(t);
}