From 5429edd44410d3e3523713d02199db20ae23522b Mon Sep 17 00:00:00 2001 From: Augusto Gunsch Date: Tue, 5 Jan 2021 13:00:23 -0300 Subject: [PATCH] Add assembler --- Makefile | 6 +- assembler/assembler-tables.h | 76 ++++++++ assembler/assembler.c | 368 +++++++++++++++++++++++++++++++++++ assembler/assembler.h | 37 ++++ main.c | 36 +++- misc/io.c | 26 ++- misc/io.h | 1 + misc/threads.c | 1 - misc/threads.h | 2 +- vm/vm-templates.h | 16 -- vm/vm-translator.c | 92 +++------ vm/vm-translator.h | 7 +- 12 files changed, 568 insertions(+), 100 deletions(-) create mode 100644 assembler/assembler-tables.h create mode 100644 assembler/assembler.c create mode 100644 assembler/assembler.h diff --git a/Makefile b/Makefile index 52b51a6..2d11fde 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ -FILES = *.c */*.c + FILES = *.c */*.c LIBRARIES = -lpthread -INCLUDES = -I. -I./parser/ -I./compiler/ -I./vm/ -I./tokenizer/ -I./misc/ -CFLAGS = -std=c99 -Wall +INCLUDES = -I. -I./parser/ -I./compiler/ -I./vm/ -I./tokenizer/ -I./misc/ -I./assembler/ +CFLAGS = -std=c99 -Wall -o3 OUTFILE = jackc main: ${FILES} diff --git a/assembler/assembler-tables.h b/assembler/assembler-tables.h new file mode 100644 index 0000000..78b9b74 --- /dev/null +++ b/assembler/assembler-tables.h @@ -0,0 +1,76 @@ +#ifndef TABLES +#define TABLES +#else +#error assembler-tables.h may only be included once +#endif + +#define mktable(name, strs, instructionsize) TABLE name = { .table = strs, .size = sizeof(strs) / sizeof(char*) / 2, .instsize = instructionsize * sizeof(char) } + +typedef struct { + const char** table; + const int size; + const int instsize; +} TABLE; + +const char* cmptablestrs[] = { + "0", "0101010", + "1", "0111111", + "-1", "0111010", + "D", "0001100", + "A", "0110000", + "!D", "0001101", + "!A", "0110001", + "-D", "0001111", + "-A", "0110011", + "D+1", "0011111", + "1+D", "0011111", + "A+1", "0110111", + "1+A", "0110111", + "D-1", "0001110", + "A-1", "0110010", + "D+A", "0000010", + "A+D", "0000010", + "D-A", "0010011", + "A-D", "0000111", + "D&A", "0000000", + "A&D", "0000000", + "D|A", "0010101", + "A|D", "0010101", + "M", "1110000", + "!M", "1110001", + "-M", "1110011", + "M+1", "1110111", + "1+M", "1110111", + "M-1", "1110010", + "D+M", "1000010", + "M+D", "1000010", + "D-M", "1010011", + "M-D", "1000111", + "D&M", "1000000", + "M&D", "1000000", + "D|M", "1010101", + "M|D", "1010101" +}; +mktable(cmptable, cmptablestrs, 8); + +const char* desttablestrs[] = { + "M", "001", + "D", "010", + "MD", "011", + "A", "100", + "AM", "101", + "AD", "110", + "AMD", "111" +}; +mktable(desttable, desttablestrs, 4); + +const char* jmptablestrs[] = { + "JGT", "001", + "JEQ", "010", + "JGE", "011", + "JLT", "100", + "JNE", "101", + "JLE", "110", + "JMP", "111" +}; +mktable(jmptable, jmptablestrs, 4); diff --git a/assembler/assembler.c b/assembler/assembler.c new file mode 100644 index 0000000..3a1febe --- /dev/null +++ b/assembler/assembler.c @@ -0,0 +1,368 @@ +#include +#include +#include +#include +#include +#include +#include "assembler-tables.h" +#include "assembler.h" +#include "util.h" + +void expandsymbols(SYMBOLARRAY* a, int toaddn); +void pushsymbol(SYMBOLARRAY* a, SYMBOL* s); +void freesymbol(SYMBOL* s); +SYMBOL* mksymbol(char* name, int namesize, int val); +int getsymbol(ASSEMBLER* a, char* name); +void skipln(ASSEMBLER* a); +void readrest(ASSEMBLER* a, int trueln); +int isvar(char* var); +void initsymbols(SYMBOLARRAY* s); +void populatevars(ASSEMBLER* a); +SYMBOL* readlabel(ASSEMBLER* a, STRINGLIST* ln, int count); +void replacevar(ASSEMBLER* a, STRINGLIST* ln, int val); +void preprocess(ASSEMBLER* a); +void transa(STRINGLIST* ln); +char* lookctable(TABLE* t, bool cond, char* token, const char* fieldname); +void transb(STRINGLIST* ln); +void assemble(ASSEMBLER* a); +void freeassembler(ASSEMBLER* a); +void strtogarbage(ASSEMBLER* a, char* str); + +void strtogarbage(ASSEMBLER* a, char* str) { + STRINGLIST* newstr = (STRINGLIST*)malloc(sizeof(STRINGLIST)); + newstr->content = str; + newstr->next = a->garbage; + a->garbage = newstr; +} + +void expandsymbols(SYMBOLARRAY* a, int toaddn) { + int sum = a->count + toaddn; + if(sizeof(SYMBOL*) * sum > a->size) { + a->size = sizeof(SYMBOL*) * sum * 3; + a->items = (SYMBOL**)realloc(a->items, a->size); + } +} + +void pushsymbol(SYMBOLARRAY* a, SYMBOL* s) { + expandsymbols(a, 1); + a->items[a->count] = s; + a->count++; +} + +void freesymbol(SYMBOL* s) { + free(s->name); + free(s); +} + +void freesymbols(SYMBOLARRAY* a) { + for(int i = 0; i < a->count; i++) + freesymbol(a->items[i]); + free(a->items); + free(a); +} + +SYMBOL* mksymbol(char* name, int namesize, int val) { + SYMBOL* s = (SYMBOL*)malloc(sizeof(SYMBOL)); + char* heapname = (char*)malloc(namesize); + strcpy(heapname, name); + s->name = heapname; + s->value = val; + return s; +} + +int getsymbol(ASSEMBLER* a, char* name) { + for(int i = 0; i < a->vars->count; i++) + if(strcmp(a->vars->items[i]->name, name) == 0) + return a->vars->items[i]->value; + + for(int i = 0; i < a->labels->count; i++) + if(strcmp(a->labels->items[i]->name, name) == 0) + return a->labels->items[i]->value; + + return -1; +} + +int isvar(char* var) { + int i = 0; + while(1) { + if(var[i] == '\0') + break; + if(!isdigit(var[i])) + return 1; + i++; + } + return 0; +} + +void initsymbols(SYMBOLARRAY* s) { + s->size = 150 * sizeof(SYMBOL*); + s->items = (SYMBOL**)malloc(s->size); + s->count = 0; +} + +ASSEMBLER* mkassembler(STRINGLIST* input) { + ASSEMBLER* a = (ASSEMBLER*)malloc(sizeof(ASSEMBLER)); + a->labels = (SYMBOLARRAY*)malloc(sizeof(SYMBOLARRAY)); + a->vars = (SYMBOLARRAY*)malloc(sizeof(SYMBOLARRAY)); + a->garbage = NULL; + a->lns = input; + + initsymbols(a->labels); + initsymbols(a->vars); + + populatevars(a); + a->varsramind = BOTTOM_VAR; + + return a; +} + +void populatevars(ASSEMBLER* a) { + const int firstamnt = 5; + const int ramvamnt = 16; //max: 19 + const int specialamt = 2; + const int sum = firstamnt + ramvamnt + specialamt; + + // realloc if necessary + expandsymbols(a->vars, sum); + + // update varscount to new index + a->vars->count = sum; + + // first five + char* labels[] = { "SP", "LCL", "ARG", "THIS", "THAT" }; + for(int i = 0; i < firstamnt; i++) { + a->vars->items[i] = mksymbol(labels[i], strlen(labels[i])+1, i); + } + + // RAM variables (R0-R15) + const int asciioff = 48; + char ramvname[4]; + ramvname[0] = 'R'; + ramvname[2] = '\0'; + int tmptarg = (ramvamnt/10)*10; + for(int i = 0; i < tmptarg; i++) { + ramvname[1] = (char)(i+asciioff); + a->vars->items[firstamnt+i] = mksymbol(ramvname, 3, i); + } + ramvname[1] = '1'; + ramvname[3] = '\0'; + for(int i = 10; i < ramvamnt; i++) { + ramvname[2] = (char)((i%10)+asciioff); + a->vars->items[firstamnt+i] = mksymbol(ramvname, 4, i); + } + + // SCREEN var + a->vars->items[firstamnt+ramvamnt] = mksymbol("SCREEN", 7, 16384); + // KBD var + a->vars->items[firstamnt+ramvamnt+1] = mksymbol("KBD", 4, 24576); +} + +SYMBOL* readlabel(ASSEMBLER* a, STRINGLIST* ln, int count) { + int i = 1; + char c; + while(true) { + c = ln->content[i]; + if(c == ')') + break; + i++; + } + + int size = i * sizeof(char); + char* name = (char*)malloc(size); + snprintf(name, size, "%s", ln->content+sizeof(char)); + SYMBOL* l = (SYMBOL*)malloc(sizeof(SYMBOL)); + l->name = name; + l->value = count; + return l; +} + +void replacevar(ASSEMBLER* a, STRINGLIST* ln, int val) { + int size = sizeof(char)*(countplaces(val) + 2); + char* newln = (char *)malloc(size); + snprintf(newln, size, "@%i", val); + ln->content = newln; + strtogarbage(a, newln); +} + +void handlevarsymbol(ASSEMBLER* a, STRINGLIST* ln) { + char* afterat = ln->content+sizeof(char); + if(isvar(afterat)) { + int val = getsymbol(a, afterat); + if(val == -1) { + if(a->varsramind == RAM_LIMIT) { + eprintf("Variable amount reached RAM limit (%i)\n", RAM_LIMIT); + exit(1); + } + SYMBOL* var = mksymbol(afterat, strlen(afterat)+1, a->varsramind); + a->varsramind++; + pushsymbol(a->vars, var); + val = var->value; + } + replacevar(a, ln, val); + } +} + +void handlelabelsymbol(ASSEMBLER* a, STRINGLIST* ln, int count) { + SYMBOL* l = readlabel(a, ln, count); + + pushsymbol(a->labels, l); +} + +void stripvars(ASSEMBLER* a) { + STRINGLIST* curln = a->lns; + while(curln != NULL) { + if(curln->content[0] == '@') + handlevarsymbol(a, curln); + curln = curln->next; + } +} + +void striplabels(ASSEMBLER* a) { + STRINGLIST* curln = a->lns; + STRINGLIST* lastln; + int count = 0; + while(curln != NULL) { + if(curln->content[0] == '(') { + handlelabelsymbol(a, curln, count); + if(count > 0) + lastln->next = curln->next; + else + a->lns = curln->next; + STRINGLIST* tmp = curln; + curln = curln->next; + free(tmp); + } + else { + lastln = curln; + curln = curln->next; + count++; + } + } +} + +void preprocess(ASSEMBLER* a) { + striplabels(a); + stripvars(a); +} + +void transa(STRINGLIST* ln) { + int add = atoi(ln->content+sizeof(char)); + + char* out = (char*)malloc(sizeof(char) * INST_SIZE); + + int lastbit = 1 << 15; + for(int i = INST_SIZE-2; i > 0; i--) { + if(add & (lastbit >> i)) + out[i] = '1'; + else + out[i] = '0'; + } + + out[INST_SIZE-1] = '\0'; + out[0] = '0'; + + ln->content = out; +} + +char* lookctable(TABLE* t, bool cond, char* token, const char* fieldname) { + char* out = (char*)malloc(t->instsize); + + if(!cond) { + int targsize = t->instsize - 1; + for(int i = 0; i < targsize; i++) + out[i] = '0'; + out[t->instsize-1] = '\0'; + return out; + } + for(int i = 0; i < t->size; i++) + if(strcmp(t->table[2*i], token) == 0) { + strcpy(out, t->table[(2*i)+1]); + return out; + } + return NULL; +} + +void transb(STRINGLIST* ln) { + bool hasjmp = false; + bool hasdest = false; + bool hascmp = false; + int i = 0; + int tmpi = 0; + char tmp[C_TOKEN_SIZE], dest[C_TOKEN_SIZE], cmp[C_TOKEN_SIZE], jmp[C_TOKEN_SIZE]; + + while(true) { + if(ln->content[i] == '\0') { + tmp[tmpi] = '\0'; + if(hasjmp) + strcpy(jmp, tmp); + else + strcpy(cmp, tmp); + break; + } + + if(ln->content[i] == '=' && !hasdest && hascmp) { + hascmp = false; + hasdest = true; + tmp[tmpi] = '\0'; + strcpy(dest, tmp); + tmpi = 0; + i++; + continue; + } + if(ln->content[i] == ';' && !hasjmp && hascmp) { + hascmp = false; + hasjmp = true; + tmp[tmpi] = '\0'; + strcpy(cmp, tmp); + tmpi = 0; + i++; + continue; + } + + hascmp = 1; + tmp[tmpi] = ln->content[i]; + tmpi++; + i++; + } + + char* rawdest = lookctable(&desttable, hasdest, dest, "dest"); + char* rawjmp = lookctable(&jmptable, hasjmp, jmp, "jump"); + char* rawcmp = lookctable(&cmptable, 1, cmp, "comp"); + + int sz = sizeof(char) * INST_SIZE; + char* out = (char*)malloc(sz); + snprintf(out, sz, "111%s%s%s", rawcmp, rawdest, rawjmp); + + ln->content = out; + free(rawdest); + free(rawjmp); + free(rawcmp); +} + +void assemble(ASSEMBLER* a) { + STRINGLIST* currln = a->lns; + while(currln != NULL) { + if(currln->content[0] == '@') + transa(currln); + else + transb(currln); + currln = currln->next; + } +} + +void freeasmlns(STRINGLIST* lns) { + if(lns != NULL) { + free(lns->content); + STRINGLIST* next = lns->next; + free(lns); + freeasmlns(next); + } +} + +void freeassembler(ASSEMBLER* a) { + freesymbols(a->vars); + freesymbols(a->labels); + freeasmlns(a->lns); + freeasmlns(a->garbage); + free(a); +} diff --git a/assembler/assembler.h b/assembler/assembler.h new file mode 100644 index 0000000..ff29b49 --- /dev/null +++ b/assembler/assembler.h @@ -0,0 +1,37 @@ +#ifndef ASSEMBLER_H +#define ASSEMBLER_H +#include +#include "parser.h" + +#define RAM_LIMIT 24577 +#define TOP_VAR 16383 +#define BOTTOM_VAR 16 +#define INST_SIZE 17 +#define C_TOKEN_SIZE 4 + +typedef struct { + char* name; + int value; +} SYMBOL; + +typedef struct { + SYMBOL** items; + int count; + int size; +} SYMBOLARRAY; + +typedef struct { + STRINGLIST* lns; + STRINGLIST* garbage; + + SYMBOLARRAY* labels; + + SYMBOLARRAY* vars; + int varsramind; +} ASSEMBLER; + +ASSEMBLER* mkassembler(STRINGLIST* input); +void preprocess(ASSEMBLER* a); +void assemble(ASSEMBLER* a); +void freeassembler(ASSEMBLER* a); +#endif diff --git a/main.c b/main.c index 0bdaa53..7ea9edf 100644 --- a/main.c +++ b/main.c @@ -7,6 +7,7 @@ #include "compiler.h" #include "io.h" #include "os.h" +#include "assembler.h" int main(int argc, char* argv[]) { if(argc < 2) { @@ -53,25 +54,42 @@ int main(int argc, char* argv[]) { } actonunits(head, compileunit); - actonunits(head, vmtranslateunit); - currunit = head; - FILE* output = fopen("out.asm", "w"); + ASMBLK* asmlns = head->asmlns; + currunit = head->next; while(currunit != NULL) { - if(output == NULL) { - eprintf("%s", strerror(errno)); - exit(1); - } + mergeasmblks(asmlns, currunit->asmlns); + currunit = currunit->next; + } - printstrlist(currunit->asmlns, output); + ASSEMBLER* assembler = mkassembler(asmlns->head); + preprocess(assembler); + assemble(assembler); + + + char* outname = getouthack(argv[1]); + FILE* output = fopen(outname, "w"); + if(output == NULL) { + eprintf("%s", strerror(errno)); + exit(1); + } + + printstrlist(asmlns->head, output); + free(asmlns); + + fclose(output); + free(outname); + + currunit = head; + while(currunit != NULL) { COMPILEUNIT* next = currunit->next; freeunit(currunit); currunit = next; } - fclose(output); freecompiler(compiler); + freeassembler(assembler); freetree(headclass); freefilelist(files); return 0; diff --git a/misc/io.c b/misc/io.c index 04a576e..eb241a2 100644 --- a/misc/io.c +++ b/misc/io.c @@ -75,9 +75,9 @@ bool isdotjack(char* f, int len) { return strcmp(strtail(f, len, strlen(ext)), ext) == 0; } -bool isdir(char* f, int len) { +bool isdir(char* f) { bool readsmt = false; - for(int i = len-1; i >= 0; i--) { + for(int i = strlen(f)-1; i >= 0; i--) { if(f[i] == '.') { if(readsmt) return false; @@ -160,10 +160,7 @@ FILELIST* getsinglefile(char* file) { } FILELIST* getfiles(char* input) { - int inplen = strlen(input); - bool isitdir = isdir(input, inplen); - - if(isitdir) + if(isdir(input)) return getfilesfromdir(input); else return getsinglefile(input); @@ -178,3 +175,20 @@ void freefilelist(FILELIST* fs) { if(next != NULL) freefilelist(next); } + +char* getouthack(char* input) { + char* out; + int inplen = strlen(input); + if(isdir(input)) { + char* name = getname(input, inplen); + int sz = (inplen + strlen(name) + 7) * sizeof(char); + out = (char*)malloc(sz); + sprintf(out, "%s/%s.hack", input, name); + free(name); + } + else { + out = heapstr(input, inplen); + out[inplen-4] = 'h'; + } + return out; +} diff --git a/misc/io.h b/misc/io.h index 1e493b3..a8d4f7e 100644 --- a/misc/io.h +++ b/misc/io.h @@ -11,4 +11,5 @@ typedef struct flist { FILELIST* getfiles(char* input); void freefilelist(FILELIST* fs); +char* getouthack(char* input); #endif diff --git a/misc/threads.c b/misc/threads.c index 9a1a481..473affb 100644 --- a/misc/threads.c +++ b/misc/threads.c @@ -93,7 +93,6 @@ void actonunits(COMPILEUNIT* units, void*(*fun)(void*)) { void freeunit(COMPILEUNIT* u) { freeparser(u->parser); freelnblk(u->compiled); - freestrlist(u->asmlns); freevmtranslator(u->vmtranslator); free(u); } diff --git a/misc/threads.h b/misc/threads.h index f85bbe9..9f223ba 100644 --- a/misc/threads.h +++ b/misc/threads.h @@ -14,7 +14,7 @@ typedef struct unit { PARSER* parser; CLASS* parsed; COMPILER* compiler; - STRINGLIST* asmlns; + ASMBLK* asmlns; LINEBLOCK* compiled; VMTRANSLATOR* vmtranslator; struct unit* next; diff --git a/vm/vm-templates.h b/vm/vm-templates.h index d3df959..0a47c31 100644 --- a/vm/vm-templates.h +++ b/vm/vm-templates.h @@ -17,7 +17,6 @@ char* tpushlns[] = { "", "", "", - "", "A=D+A", "D=M", "@SP", @@ -29,7 +28,6 @@ char* tpushlns[] = { mktemplate(tpush, tpushlns); char* tpushconslns[] = { - "", "", "D=A", "@SP", @@ -41,7 +39,6 @@ char* tpushconslns[] = { mktemplate(tpushcons, tpushconslns); char* tpushstatlns[] = { - "", "", "D=M", "@SP", @@ -60,7 +57,6 @@ char* tpoplns[] = { "", "", "", - "", "D=D+A", "@R13", "M=D", @@ -74,7 +70,6 @@ char* tpoplns[] = { mktemplate(tpop, tpoplns); char* tpopstatlns[] = { - "", "@SP", "AM=M-1", "D=M", @@ -88,7 +83,6 @@ mktemplate(tpoptemp, tpopstatlns); mktemplate(tpoppointer, tpopstatlns); char* tarithlns[] = { - "", "@SP", "AM=M-1", "D=M", @@ -98,7 +92,6 @@ char* tarithlns[] = { mktemplate(tarith, tarithlns); char* tneglns[] = { - "", "@SP", "A=M-1", "M=-M", @@ -106,7 +99,6 @@ char* tneglns[] = { mktemplate(tneg, tneglns); char* tnotlns[] = { - "", "@SP", "A=M-1", "M=!M", @@ -114,7 +106,6 @@ char* tnotlns[] = { mktemplate(tnot, tnotlns); char* tcomplns[] = { - "", "@SP", "AM=M-1", "D=M", @@ -131,20 +122,17 @@ char* tcomplns[] = { mktemplate(tcomp, tcomplns); char* tlabellns[] = { - "", "" }; mktemplate(tlabel, tlabellns); char* tgotolns[] = { - "", "", "0;JMP" }; mktemplate(tgoto, tgotolns); char* tifgotolns[] = { - "", "@SP", "AM=M-1", "D=M", @@ -154,8 +142,6 @@ char* tifgotolns[] = { mktemplate(tifgoto, tifgotolns); char* tcallstartlns[] = { - "", - "", "D=A", "@SP", "A=M", @@ -204,7 +190,6 @@ char* tframevarslns[] = { mktemplate(tframevars, tframevarslns); char* tfunctionlns[] = { - "", "" }; mktemplate(tfunction, tfunctionlns); @@ -219,7 +204,6 @@ char* tfunctionpushlns[] = { mktemplate(tfunctionpush, tfunctionpushlns); char* tstartreturnlns[] = { - "", "@LCL", "D=M", "@5", diff --git a/vm/vm-translator.c b/vm/vm-translator.c index 20a1b16..de4313a 100644 --- a/vm/vm-translator.c +++ b/vm/vm-translator.c @@ -5,11 +5,6 @@ #include "util.h" #define eq(translator, index, str) !strcmp(translator->currln->tokens[index], str) -typedef struct { - STRINGLIST* head; - STRINGLIST* tail; -} ASMBLK; - STRINGLIST* asmln(char* content) { STRINGLIST* ln = (STRINGLIST*)malloc(sizeof(STRINGLIST)); ln->content = content; @@ -68,26 +63,6 @@ char* dotat(VMTRANSLATOR* t, char* name, char* n) { return atstr; } -char* comment(VMTRANSLATOR* t) { - int sz = (4 + strlen(t->currln->tokens[0])) * sizeof(char); - for(int i = 1; i < t->currln->count; i++) - sz += (1 + strlen(t->currln->tokens[i])) * sizeof(char); - - char* com = (char*)malloc(sz); - if(t->currln->count == 1) - sprintf(com, "// %s", t->currln->tokens[0]); - else if(t->currln->count == 2) - sprintf(com, "// %s %s", t->currln->tokens[0], - t->currln->tokens[1]); - else if(t->currln->count == 3) - sprintf(com, "// %s %s %s", t->currln->tokens[0], - t->currln->tokens[1], - t->currln->tokens[2]); - - togarbage(t, com); - return com; -} - char* switchsegment(VMTRANSLATOR* t) { if(eq(t, 1, "local")) return mkstr(t, "@LCL"); @@ -154,13 +129,6 @@ ASMBLK* copytemplate(TEMPLATE* t) { return blk; } -ASMBLK* mkasmlns(VMTRANSLATOR* t, TEMPLATE* tp) { - // instruction comment - tp->items[0] = comment(t); - - return copytemplate(tp); -} - void mergeasmblks(ASMBLK* a, ASMBLK* b) { a->tail->next = b->head; a->tail = b->tail; @@ -173,47 +141,47 @@ void mergeasmblks(ASMBLK* a, ASMBLK* b) { ASMBLK* translatepushconst(VMTRANSLATOR* t) { // @i - tpushcons.items[1] = at(t, t->currln->tokens[2]); + tpushcons.items[0] = at(t, t->currln->tokens[2]); - return mkasmlns(t, &tpushcons); + return copytemplate(&tpushcons); } ASMBLK* translatepushstatic(VMTRANSLATOR* t) { // @classname.i - tpushstat.items[1] = dotat(t, t->classname, t->currln->tokens[2]); + tpushstat.items[0] = dotat(t, t->classname, t->currln->tokens[2]); - return mkasmlns(t, &tpushstat); + return copytemplate(&tpushstat); } ASMBLK* translatepushpointer(VMTRANSLATOR* t) { // @THIS/@THAT - tpushpointer.items[1] = mkpointerind(t); + tpushpointer.items[0] = mkpointerind(t); - return mkasmlns(t, &tpushpointer); + return copytemplate(&tpushpointer); } ASMBLK* translatepushtemp(VMTRANSLATOR* t) { // @5+i - tpushtemp.items[1] = mktempind(t); + tpushtemp.items[0] = mktempind(t); - return mkasmlns(t, &tpushtemp); + return copytemplate(&tpushtemp); } void pushpopcommon(VMTRANSLATOR* t, TEMPLATE* tp) { // @segment - tp->items[1] = switchsegment(t); + tp->items[0] = switchsegment(t); // D=M - tp->items[2] = mkstr(t, "D=M"); + tp->items[1] = mkstr(t, "D=M"); // @i - tp->items[3] = at(t, t->currln->tokens[2]); + tp->items[2] = at(t, t->currln->tokens[2]); } ASMBLK* translatepushgeneric(VMTRANSLATOR* t) { pushpopcommon(t, &tpush); - return mkasmlns(t, &tpush); + return copytemplate(&tpush); } ASMBLK* translatepush(VMTRANSLATOR* t) { @@ -235,7 +203,7 @@ ASMBLK* translatepopstatic(VMTRANSLATOR* t) { // M=D tpopstat.items[tpopstat.count-1] = mkstr(t, "M=D"); - return mkasmlns(t, &tpopstat); + return copytemplate(&tpopstat); } ASMBLK* translatepoppointer(VMTRANSLATOR* t) { @@ -245,7 +213,7 @@ ASMBLK* translatepoppointer(VMTRANSLATOR* t) { // M=D tpoppointer.items[tpoppointer.count-1] = mkstr(t, "M=D"); - return mkasmlns(t, &tpoppointer); + return copytemplate(&tpoppointer); } ASMBLK* translatepoptemp(VMTRANSLATOR* t) { @@ -254,13 +222,13 @@ ASMBLK* translatepoptemp(VMTRANSLATOR* t) { tpoptemp.items[tpoptemp.count-1] = mkstr(t, "M=D"); - return mkasmlns(t, &tpoptemp); + return copytemplate(&tpoptemp); } ASMBLK* translatepopgeneric(VMTRANSLATOR* t) { pushpopcommon(t, &tpop); - return mkasmlns(t, &tpop); + return copytemplate(&tpop); } ASMBLK* translatepop(VMTRANSLATOR* t) { @@ -281,7 +249,7 @@ ASMBLK* translatepop(VMTRANSLATOR* t) { ASMBLK* translatearith(VMTRANSLATOR* t, char* op) { tarith.items[tarith.count-1] = mkstr(t, op); - return mkasmlns(t, &tarith); + return copytemplate(&tarith); } ASMBLK* translatecomp(VMTRANSLATOR* t, char* op) { @@ -301,7 +269,7 @@ ASMBLK* translatecomp(VMTRANSLATOR* t, char* op) { // (label) tcomp.items[tcomp.count-1] = enclosingparenthesis(t, label, labellen); - return mkasmlns(t, &tcomp); + return copytemplate(&tcomp); } /* END OPERATIONS */ @@ -310,25 +278,25 @@ ASMBLK* translatelabel(VMTRANSLATOR* t) { // (classname$label) tlabel.items[tlabel.count-1] = mklab(t); - return mkasmlns(t, &tlabel); + return copytemplate(&tlabel); } ASMBLK* translategoto(VMTRANSLATOR* t) { // @label tgoto.items[tgoto.count-2] = mkgotolab(t); - return mkasmlns(t, &tgoto); + return copytemplate(&tgoto); } ASMBLK* translateifgoto(VMTRANSLATOR* t) { // @label tifgoto.items[tifgoto.count-2] = mkgotolab(t); - return mkasmlns(t, &tifgoto); + return copytemplate(&tifgoto); } ASMBLK* translatereturn(VMTRANSLATOR* t) { - ASMBLK* blk = mkasmlns(t, &tstartreturn); + ASMBLK* blk = copytemplate(&tstartreturn); for(int i = tframevars.count-1; i >= 0; i--) { tretpop.items[tretpop.count-2] = tframevars.items[i]; @@ -344,8 +312,8 @@ ASMBLK* translatefunction(VMTRANSLATOR* t) { t->cmpind = 0; // (funcname) - tfunction.items[1] = mklab(t); - ASMBLK* blk = mkasmlns(t, &tfunction); + tfunction.items[0] = mklab(t); + ASMBLK* blk = copytemplate(&tfunction); // repeat nVars times: int nlocals = atoi(t->currln->tokens[2]); @@ -359,7 +327,7 @@ ASMBLK* translatefunction(VMTRANSLATOR* t) { ASMBLK* pushframe(VMTRANSLATOR* t, char* retlab, int retlablen, int* framesize) { tcallstart.items[1] = atraw(t, retlab, retlablen); - ASMBLK* blk = mkasmlns(t, &tcallstart); + ASMBLK* blk = copytemplate(&tcallstart); for(int i = 0; i < tframevars.count; i++) { tcallpush.items[0] = tframevars.items[i]; @@ -408,9 +376,9 @@ ASMBLK* translateln(VMTRANSLATOR* t) { return translatearith(t, "M=D|M"); if(eq(t, 0, "neg")) - return mkasmlns(t, &tneg); + return copytemplate(&tneg); if(eq(t, 0, "not")) - return mkasmlns(t, &tnot); + return copytemplate(&tnot); if(eq(t, 0, "eq")) return translatecomp(t, "EQ"); @@ -433,15 +401,13 @@ ASMBLK* translateln(VMTRANSLATOR* t) { return translatecall(t); } -STRINGLIST* translatevm(VMTRANSLATOR* t) { +ASMBLK* translatevm(VMTRANSLATOR* t) { ASMBLK* blk = copytemplate(&tbootstrap); while(t->currln != NULL) { mergeasmblks(blk, translateln(t)); t->currln = t->currln->next; } - STRINGLIST* output = blk->head; - free(blk); - return output; + return blk; } VMTRANSLATOR* mkvmtranslator(char* classname, LINEBLOCK* vmlines) { diff --git a/vm/vm-translator.h b/vm/vm-translator.h index 9ee994a..bc8f57e 100644 --- a/vm/vm-translator.h +++ b/vm/vm-translator.h @@ -12,9 +12,14 @@ typedef struct { int retind; } VMTRANSLATOR; +typedef struct { + STRINGLIST* head; + STRINGLIST* tail; +} ASMBLK; -STRINGLIST* translatevm(VMTRANSLATOR* t); +ASMBLK* translatevm(VMTRANSLATOR* t); VMTRANSLATOR* mkvmtranslator(char* classname, LINEBLOCK* vmlines); void freevmtranslator(VMTRANSLATOR* t); +void mergeasmblks(ASMBLK* a, ASMBLK* b); #endif