Add assembler

This commit is contained in:
Augusto Gunsch 2021-01-05 13:00:23 -03:00
parent cc60532d74
commit 5429edd444
No known key found for this signature in database
GPG Key ID: F7EEFE29825C72DC
12 changed files with 568 additions and 100 deletions

View File

@ -1,7 +1,7 @@
FILES = *.c */*.c FILES = *.c */*.c
LIBRARIES = -lpthread LIBRARIES = -lpthread
INCLUDES = -I. -I./parser/ -I./compiler/ -I./vm/ -I./tokenizer/ -I./misc/ INCLUDES = -I. -I./parser/ -I./compiler/ -I./vm/ -I./tokenizer/ -I./misc/ -I./assembler/
CFLAGS = -std=c99 -Wall CFLAGS = -std=c99 -Wall -o3
OUTFILE = jackc OUTFILE = jackc
main: ${FILES} main: ${FILES}

View File

@ -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);

368
assembler/assembler.c Normal file
View File

@ -0,0 +1,368 @@
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <stdbool.h>
#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);
}

37
assembler/assembler.h Normal file
View File

@ -0,0 +1,37 @@
#ifndef ASSEMBLER_H
#define ASSEMBLER_H
#include <stdio.h>
#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

36
main.c
View File

@ -7,6 +7,7 @@
#include "compiler.h" #include "compiler.h"
#include "io.h" #include "io.h"
#include "os.h" #include "os.h"
#include "assembler.h"
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
if(argc < 2) { if(argc < 2) {
@ -53,25 +54,42 @@ int main(int argc, char* argv[]) {
} }
actonunits(head, compileunit); actonunits(head, compileunit);
actonunits(head, vmtranslateunit); actonunits(head, vmtranslateunit);
currunit = head; ASMBLK* asmlns = head->asmlns;
FILE* output = fopen("out.asm", "w"); currunit = head->next;
while(currunit != NULL) { while(currunit != NULL) {
if(output == NULL) { mergeasmblks(asmlns, currunit->asmlns);
eprintf("%s", strerror(errno)); currunit = currunit->next;
exit(1); }
}
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; COMPILEUNIT* next = currunit->next;
freeunit(currunit); freeunit(currunit);
currunit = next; currunit = next;
} }
fclose(output);
freecompiler(compiler); freecompiler(compiler);
freeassembler(assembler);
freetree(headclass); freetree(headclass);
freefilelist(files); freefilelist(files);
return 0; return 0;

View File

@ -75,9 +75,9 @@ bool isdotjack(char* f, int len) {
return strcmp(strtail(f, len, strlen(ext)), ext) == 0; return strcmp(strtail(f, len, strlen(ext)), ext) == 0;
} }
bool isdir(char* f, int len) { bool isdir(char* f) {
bool readsmt = false; bool readsmt = false;
for(int i = len-1; i >= 0; i--) { for(int i = strlen(f)-1; i >= 0; i--) {
if(f[i] == '.') { if(f[i] == '.') {
if(readsmt) if(readsmt)
return false; return false;
@ -160,10 +160,7 @@ FILELIST* getsinglefile(char* file) {
} }
FILELIST* getfiles(char* input) { FILELIST* getfiles(char* input) {
int inplen = strlen(input); if(isdir(input))
bool isitdir = isdir(input, inplen);
if(isitdir)
return getfilesfromdir(input); return getfilesfromdir(input);
else else
return getsinglefile(input); return getsinglefile(input);
@ -178,3 +175,20 @@ void freefilelist(FILELIST* fs) {
if(next != NULL) if(next != NULL)
freefilelist(next); 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;
}

View File

@ -11,4 +11,5 @@ typedef struct flist {
FILELIST* getfiles(char* input); FILELIST* getfiles(char* input);
void freefilelist(FILELIST* fs); void freefilelist(FILELIST* fs);
char* getouthack(char* input);
#endif #endif

View File

@ -93,7 +93,6 @@ void actonunits(COMPILEUNIT* units, void*(*fun)(void*)) {
void freeunit(COMPILEUNIT* u) { void freeunit(COMPILEUNIT* u) {
freeparser(u->parser); freeparser(u->parser);
freelnblk(u->compiled); freelnblk(u->compiled);
freestrlist(u->asmlns);
freevmtranslator(u->vmtranslator); freevmtranslator(u->vmtranslator);
free(u); free(u);
} }

View File

@ -14,7 +14,7 @@ typedef struct unit {
PARSER* parser; PARSER* parser;
CLASS* parsed; CLASS* parsed;
COMPILER* compiler; COMPILER* compiler;
STRINGLIST* asmlns; ASMBLK* asmlns;
LINEBLOCK* compiled; LINEBLOCK* compiled;
VMTRANSLATOR* vmtranslator; VMTRANSLATOR* vmtranslator;
struct unit* next; struct unit* next;

View File

@ -17,7 +17,6 @@ char* tpushlns[] = {
"", "",
"", "",
"", "",
"",
"A=D+A", "A=D+A",
"D=M", "D=M",
"@SP", "@SP",
@ -29,7 +28,6 @@ char* tpushlns[] = {
mktemplate(tpush, tpushlns); mktemplate(tpush, tpushlns);
char* tpushconslns[] = { char* tpushconslns[] = {
"",
"", "",
"D=A", "D=A",
"@SP", "@SP",
@ -41,7 +39,6 @@ char* tpushconslns[] = {
mktemplate(tpushcons, tpushconslns); mktemplate(tpushcons, tpushconslns);
char* tpushstatlns[] = { char* tpushstatlns[] = {
"",
"", "",
"D=M", "D=M",
"@SP", "@SP",
@ -60,7 +57,6 @@ char* tpoplns[] = {
"", "",
"", "",
"", "",
"",
"D=D+A", "D=D+A",
"@R13", "@R13",
"M=D", "M=D",
@ -74,7 +70,6 @@ char* tpoplns[] = {
mktemplate(tpop, tpoplns); mktemplate(tpop, tpoplns);
char* tpopstatlns[] = { char* tpopstatlns[] = {
"",
"@SP", "@SP",
"AM=M-1", "AM=M-1",
"D=M", "D=M",
@ -88,7 +83,6 @@ mktemplate(tpoptemp, tpopstatlns);
mktemplate(tpoppointer, tpopstatlns); mktemplate(tpoppointer, tpopstatlns);
char* tarithlns[] = { char* tarithlns[] = {
"",
"@SP", "@SP",
"AM=M-1", "AM=M-1",
"D=M", "D=M",
@ -98,7 +92,6 @@ char* tarithlns[] = {
mktemplate(tarith, tarithlns); mktemplate(tarith, tarithlns);
char* tneglns[] = { char* tneglns[] = {
"",
"@SP", "@SP",
"A=M-1", "A=M-1",
"M=-M", "M=-M",
@ -106,7 +99,6 @@ char* tneglns[] = {
mktemplate(tneg, tneglns); mktemplate(tneg, tneglns);
char* tnotlns[] = { char* tnotlns[] = {
"",
"@SP", "@SP",
"A=M-1", "A=M-1",
"M=!M", "M=!M",
@ -114,7 +106,6 @@ char* tnotlns[] = {
mktemplate(tnot, tnotlns); mktemplate(tnot, tnotlns);
char* tcomplns[] = { char* tcomplns[] = {
"",
"@SP", "@SP",
"AM=M-1", "AM=M-1",
"D=M", "D=M",
@ -131,20 +122,17 @@ char* tcomplns[] = {
mktemplate(tcomp, tcomplns); mktemplate(tcomp, tcomplns);
char* tlabellns[] = { char* tlabellns[] = {
"",
"" ""
}; };
mktemplate(tlabel, tlabellns); mktemplate(tlabel, tlabellns);
char* tgotolns[] = { char* tgotolns[] = {
"",
"", "",
"0;JMP" "0;JMP"
}; };
mktemplate(tgoto, tgotolns); mktemplate(tgoto, tgotolns);
char* tifgotolns[] = { char* tifgotolns[] = {
"",
"@SP", "@SP",
"AM=M-1", "AM=M-1",
"D=M", "D=M",
@ -154,8 +142,6 @@ char* tifgotolns[] = {
mktemplate(tifgoto, tifgotolns); mktemplate(tifgoto, tifgotolns);
char* tcallstartlns[] = { char* tcallstartlns[] = {
"",
"",
"D=A", "D=A",
"@SP", "@SP",
"A=M", "A=M",
@ -204,7 +190,6 @@ char* tframevarslns[] = {
mktemplate(tframevars, tframevarslns); mktemplate(tframevars, tframevarslns);
char* tfunctionlns[] = { char* tfunctionlns[] = {
"",
"" ""
}; };
mktemplate(tfunction, tfunctionlns); mktemplate(tfunction, tfunctionlns);
@ -219,7 +204,6 @@ char* tfunctionpushlns[] = {
mktemplate(tfunctionpush, tfunctionpushlns); mktemplate(tfunctionpush, tfunctionpushlns);
char* tstartreturnlns[] = { char* tstartreturnlns[] = {
"",
"@LCL", "@LCL",
"D=M", "D=M",
"@5", "@5",

View File

@ -5,11 +5,6 @@
#include "util.h" #include "util.h"
#define eq(translator, index, str) !strcmp(translator->currln->tokens[index], str) #define eq(translator, index, str) !strcmp(translator->currln->tokens[index], str)
typedef struct {
STRINGLIST* head;
STRINGLIST* tail;
} ASMBLK;
STRINGLIST* asmln(char* content) { STRINGLIST* asmln(char* content) {
STRINGLIST* ln = (STRINGLIST*)malloc(sizeof(STRINGLIST)); STRINGLIST* ln = (STRINGLIST*)malloc(sizeof(STRINGLIST));
ln->content = content; ln->content = content;
@ -68,26 +63,6 @@ char* dotat(VMTRANSLATOR* t, char* name, char* n) {
return atstr; 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) { char* switchsegment(VMTRANSLATOR* t) {
if(eq(t, 1, "local")) if(eq(t, 1, "local"))
return mkstr(t, "@LCL"); return mkstr(t, "@LCL");
@ -154,13 +129,6 @@ ASMBLK* copytemplate(TEMPLATE* t) {
return blk; return blk;
} }
ASMBLK* mkasmlns(VMTRANSLATOR* t, TEMPLATE* tp) {
// instruction comment
tp->items[0] = comment(t);
return copytemplate(tp);
}
void mergeasmblks(ASMBLK* a, ASMBLK* b) { void mergeasmblks(ASMBLK* a, ASMBLK* b) {
a->tail->next = b->head; a->tail->next = b->head;
a->tail = b->tail; a->tail = b->tail;
@ -173,47 +141,47 @@ void mergeasmblks(ASMBLK* a, ASMBLK* b) {
ASMBLK* translatepushconst(VMTRANSLATOR* t) { ASMBLK* translatepushconst(VMTRANSLATOR* t) {
// @i // @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) { ASMBLK* translatepushstatic(VMTRANSLATOR* t) {
// @classname.i // @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) { ASMBLK* translatepushpointer(VMTRANSLATOR* t) {
// @THIS/@THAT // @THIS/@THAT
tpushpointer.items[1] = mkpointerind(t); tpushpointer.items[0] = mkpointerind(t);
return mkasmlns(t, &tpushpointer); return copytemplate(&tpushpointer);
} }
ASMBLK* translatepushtemp(VMTRANSLATOR* t) { ASMBLK* translatepushtemp(VMTRANSLATOR* t) {
// @5+i // @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) { void pushpopcommon(VMTRANSLATOR* t, TEMPLATE* tp) {
// @segment // @segment
tp->items[1] = switchsegment(t); tp->items[0] = switchsegment(t);
// D=M // D=M
tp->items[2] = mkstr(t, "D=M"); tp->items[1] = mkstr(t, "D=M");
// @i // @i
tp->items[3] = at(t, t->currln->tokens[2]); tp->items[2] = at(t, t->currln->tokens[2]);
} }
ASMBLK* translatepushgeneric(VMTRANSLATOR* t) { ASMBLK* translatepushgeneric(VMTRANSLATOR* t) {
pushpopcommon(t, &tpush); pushpopcommon(t, &tpush);
return mkasmlns(t, &tpush); return copytemplate(&tpush);
} }
ASMBLK* translatepush(VMTRANSLATOR* t) { ASMBLK* translatepush(VMTRANSLATOR* t) {
@ -235,7 +203,7 @@ ASMBLK* translatepopstatic(VMTRANSLATOR* t) {
// M=D // M=D
tpopstat.items[tpopstat.count-1] = mkstr(t, "M=D"); tpopstat.items[tpopstat.count-1] = mkstr(t, "M=D");
return mkasmlns(t, &tpopstat); return copytemplate(&tpopstat);
} }
ASMBLK* translatepoppointer(VMTRANSLATOR* t) { ASMBLK* translatepoppointer(VMTRANSLATOR* t) {
@ -245,7 +213,7 @@ ASMBLK* translatepoppointer(VMTRANSLATOR* t) {
// M=D // M=D
tpoppointer.items[tpoppointer.count-1] = mkstr(t, "M=D"); tpoppointer.items[tpoppointer.count-1] = mkstr(t, "M=D");
return mkasmlns(t, &tpoppointer); return copytemplate(&tpoppointer);
} }
ASMBLK* translatepoptemp(VMTRANSLATOR* t) { ASMBLK* translatepoptemp(VMTRANSLATOR* t) {
@ -254,13 +222,13 @@ ASMBLK* translatepoptemp(VMTRANSLATOR* t) {
tpoptemp.items[tpoptemp.count-1] = mkstr(t, "M=D"); tpoptemp.items[tpoptemp.count-1] = mkstr(t, "M=D");
return mkasmlns(t, &tpoptemp); return copytemplate(&tpoptemp);
} }
ASMBLK* translatepopgeneric(VMTRANSLATOR* t) { ASMBLK* translatepopgeneric(VMTRANSLATOR* t) {
pushpopcommon(t, &tpop); pushpopcommon(t, &tpop);
return mkasmlns(t, &tpop); return copytemplate(&tpop);
} }
ASMBLK* translatepop(VMTRANSLATOR* t) { ASMBLK* translatepop(VMTRANSLATOR* t) {
@ -281,7 +249,7 @@ ASMBLK* translatepop(VMTRANSLATOR* t) {
ASMBLK* translatearith(VMTRANSLATOR* t, char* op) { ASMBLK* translatearith(VMTRANSLATOR* t, char* op) {
tarith.items[tarith.count-1] = mkstr(t, op); tarith.items[tarith.count-1] = mkstr(t, op);
return mkasmlns(t, &tarith); return copytemplate(&tarith);
} }
ASMBLK* translatecomp(VMTRANSLATOR* t, char* op) { ASMBLK* translatecomp(VMTRANSLATOR* t, char* op) {
@ -301,7 +269,7 @@ ASMBLK* translatecomp(VMTRANSLATOR* t, char* op) {
// (label) // (label)
tcomp.items[tcomp.count-1] = enclosingparenthesis(t, label, labellen); tcomp.items[tcomp.count-1] = enclosingparenthesis(t, label, labellen);
return mkasmlns(t, &tcomp); return copytemplate(&tcomp);
} }
/* END OPERATIONS */ /* END OPERATIONS */
@ -310,25 +278,25 @@ ASMBLK* translatelabel(VMTRANSLATOR* t) {
// (classname$label) // (classname$label)
tlabel.items[tlabel.count-1] = mklab(t); tlabel.items[tlabel.count-1] = mklab(t);
return mkasmlns(t, &tlabel); return copytemplate(&tlabel);
} }
ASMBLK* translategoto(VMTRANSLATOR* t) { ASMBLK* translategoto(VMTRANSLATOR* t) {
// @label // @label
tgoto.items[tgoto.count-2] = mkgotolab(t); tgoto.items[tgoto.count-2] = mkgotolab(t);
return mkasmlns(t, &tgoto); return copytemplate(&tgoto);
} }
ASMBLK* translateifgoto(VMTRANSLATOR* t) { ASMBLK* translateifgoto(VMTRANSLATOR* t) {
// @label // @label
tifgoto.items[tifgoto.count-2] = mkgotolab(t); tifgoto.items[tifgoto.count-2] = mkgotolab(t);
return mkasmlns(t, &tifgoto); return copytemplate(&tifgoto);
} }
ASMBLK* translatereturn(VMTRANSLATOR* t) { ASMBLK* translatereturn(VMTRANSLATOR* t) {
ASMBLK* blk = mkasmlns(t, &tstartreturn); ASMBLK* blk = copytemplate(&tstartreturn);
for(int i = tframevars.count-1; i >= 0; i--) { for(int i = tframevars.count-1; i >= 0; i--) {
tretpop.items[tretpop.count-2] = tframevars.items[i]; tretpop.items[tretpop.count-2] = tframevars.items[i];
@ -344,8 +312,8 @@ ASMBLK* translatefunction(VMTRANSLATOR* t) {
t->cmpind = 0; t->cmpind = 0;
// (funcname) // (funcname)
tfunction.items[1] = mklab(t); tfunction.items[0] = mklab(t);
ASMBLK* blk = mkasmlns(t, &tfunction); ASMBLK* blk = copytemplate(&tfunction);
// repeat nVars times: // repeat nVars times:
int nlocals = atoi(t->currln->tokens[2]); 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) { ASMBLK* pushframe(VMTRANSLATOR* t, char* retlab, int retlablen, int* framesize) {
tcallstart.items[1] = atraw(t, retlab, retlablen); tcallstart.items[1] = atraw(t, retlab, retlablen);
ASMBLK* blk = mkasmlns(t, &tcallstart); ASMBLK* blk = copytemplate(&tcallstart);
for(int i = 0; i < tframevars.count; i++) { for(int i = 0; i < tframevars.count; i++) {
tcallpush.items[0] = tframevars.items[i]; tcallpush.items[0] = tframevars.items[i];
@ -408,9 +376,9 @@ ASMBLK* translateln(VMTRANSLATOR* t) {
return translatearith(t, "M=D|M"); return translatearith(t, "M=D|M");
if(eq(t, 0, "neg")) if(eq(t, 0, "neg"))
return mkasmlns(t, &tneg); return copytemplate(&tneg);
if(eq(t, 0, "not")) if(eq(t, 0, "not"))
return mkasmlns(t, &tnot); return copytemplate(&tnot);
if(eq(t, 0, "eq")) if(eq(t, 0, "eq"))
return translatecomp(t, "EQ"); return translatecomp(t, "EQ");
@ -433,15 +401,13 @@ ASMBLK* translateln(VMTRANSLATOR* t) {
return translatecall(t); return translatecall(t);
} }
STRINGLIST* translatevm(VMTRANSLATOR* t) { ASMBLK* translatevm(VMTRANSLATOR* t) {
ASMBLK* blk = copytemplate(&tbootstrap); ASMBLK* blk = copytemplate(&tbootstrap);
while(t->currln != NULL) { while(t->currln != NULL) {
mergeasmblks(blk, translateln(t)); mergeasmblks(blk, translateln(t));
t->currln = t->currln->next; t->currln = t->currln->next;
} }
STRINGLIST* output = blk->head; return blk;
free(blk);
return output;
} }
VMTRANSLATOR* mkvmtranslator(char* classname, LINEBLOCK* vmlines) { VMTRANSLATOR* mkvmtranslator(char* classname, LINEBLOCK* vmlines) {

View File

@ -12,9 +12,14 @@ typedef struct {
int retind; int retind;
} VMTRANSLATOR; } VMTRANSLATOR;
typedef struct {
STRINGLIST* head;
STRINGLIST* tail;
} ASMBLK;
STRINGLIST* translatevm(VMTRANSLATOR* t); ASMBLK* translatevm(VMTRANSLATOR* t);
VMTRANSLATOR* mkvmtranslator(char* classname, LINEBLOCK* vmlines); VMTRANSLATOR* mkvmtranslator(char* classname, LINEBLOCK* vmlines);
void freevmtranslator(VMTRANSLATOR* t); void freevmtranslator(VMTRANSLATOR* t);
void mergeasmblks(ASMBLK* a, ASMBLK* b);
#endif #endif