diff --git a/templates.h b/templates.h index b7b6280..e9e25e8 100644 --- a/templates.h +++ b/templates.h @@ -94,4 +94,51 @@ char* tpoppointer[TPOPPOINTERN] = { "M=D" }; +#define TARITHN 7 +char* tarith[TARITHN] = { + "", + "@SP", + "M=M-1", + "A=M", + "D=M", + "A=A-1", + "" +}; + +#define TNEGN 5 +char* tneg[TNEGN] = { + "", + "@SP", + "M=M-1", + "A=M", + "M=-M", +}; + +#define TNOTN 5 +char* tnot[TNOTN] = { + "", + "@SP", + "M=M-1", + "A=M", + "M=!M", +}; + +#define TCOMPN 15 +char* tcomp[TCOMPN] = { + "", + "M=D", + "@SP", + "M=M-1", + "A=M", + "D=M", + "A=A-1", + "D=D-M", + "M=1", + "", + "", + "@SP", + "A=M-1", + "M=0", + "" +}; #endif diff --git a/translator.c b/translator.c index a8290e1..ec9b4da 100644 --- a/translator.c +++ b/translator.c @@ -4,6 +4,8 @@ #include #include "translator.h" #include "templates.h" +#define CMPLIMIT 1000 +#define CMPLEN 4 void pushtoclean(struct Translator* t, char* topush) { int nextsz = sizeof(char*)*(t->tocleanind+1); @@ -105,6 +107,19 @@ void checkind(struct line* ln, int indlen) { } } +char* mkcmplab(struct Translator* t, struct line* ln) { + t->compcount++; + if(t->compcount > CMPLIMIT) { + fprintf(stderr, "Reached comparison limit (%i); line %i\n", CMPLIMIT, ln->truen); + exit(1); + } + int newsz = (CMPLEN+13)*sizeof(char); + char* label = (char*)malloc(newsz); + snprintf(label, newsz, "COMPARISON-%i", t->compcount); + pushtoclean(t, label); + return label; +} + char* mkind(struct Translator* t, struct line* ln, int indlen) { checkind(ln, indlen); int newsz = sizeof(char) * (indlen + 2); @@ -114,6 +129,22 @@ char* mkind(struct Translator* t, struct line* ln, int indlen) { return newind; } +char* atlab(struct Translator* t, char* label, int labellen) { + int newsz = sizeof(char) * (labellen + 2); + char* newind = (char*)malloc(newsz); + snprintf(newind, newsz, "@%s", label); + pushtoclean(t, newind); + return newind; +} + +char* mklab(struct Translator* t, char* label, int labellen) { + int newsz = sizeof(char) * (labellen + 3); + char* newind = (char*)malloc(newsz); + snprintf(newind, newsz, "(%s)", label); + pushtoclean(t, newind); + return newind; +} + char* mkstatind(struct Translator* t, struct line* ln, int indlen) { checkind(ln, indlen); int fnamelen = strlen(t->fname); @@ -275,6 +306,32 @@ void pop(struct Translator* t, struct line* ln, int indlen) { addasmlns(t, ln, tpop, TPOPN); } +void arith(struct Translator* t, struct line* ln, char* op) { + tarith[TARITHN-1] = heapstr(t, op); + + addasmlns(t, ln, tarith, TARITHN); +} + +void comp(struct Translator* t, struct line* ln, char* op) { + char* label = mkcmplab(t, ln); + int labellen = strlen(label); + + // @label + tcomp[TCOMPN-6] = atlab(t, label, labellen); + + // D;J(op) + int opsz = sizeof(char)*6; + char* trueop = (char*)malloc(opsz); + snprintf(trueop, opsz, "D;J%s", op); + tcomp[TCOMPN-5] = trueop; + + // (label) + tcomp[TCOMPN-1] = mklab(t, label, labellen); + free(label); + + addasmlns(t, ln, tcomp, TCOMPN); +}; + void switchpush(struct Translator* t, struct line* ln) { checkopamnt(3, ln); char* seg = ln->tokens[1]; @@ -314,6 +371,24 @@ void switchop(struct Translator* t, struct line* ln) { switchpush(t, ln); else if(!strcmp(op, "pop")) switchpop(t, ln); + else if(!strcmp(op, "add")) + arith(t, ln, "M=M+D"); + else if(!strcmp(op, "sub")) + arith(t, ln, "M=M-D"); + else if(!strcmp(op, "neg")) + addasmlns(t, ln, tneg, TNEGN); + else if(!strcmp(op, "eq")) + comp(t, ln, "EQ"); + else if(!strcmp(op, "gt")) + comp(t, ln, "GT"); + else if(!strcmp(op, "lt")) + comp(t, ln, "LT"); + else if(!strcmp(op, "and")) + arith(t, ln, "M=M&D"); + else if(!strcmp(op, "or")) + arith(t, ln, "M=M|D"); + else if(!strcmp(op, "not")) + addasmlns(t, ln, tnot, TNOTN); else { fprintf(stderr, "Unrecognized operation '%s'; line %i\n", op, ln->truen); exit(1); diff --git a/translator.h b/translator.h index 41ba43a..6e38dcd 100644 --- a/translator.h +++ b/translator.h @@ -16,6 +16,7 @@ struct Translator { int tocleanind; struct lnarray* lns; char* fname; + int compcount; }; void freetranslator(struct Translator* t);