Add assembler
This commit is contained in:
parent
cc60532d74
commit
5429edd444
4
Makefile
4
Makefile
|
@ -1,7 +1,7 @@
|
|||
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}
|
||||
|
|
|
@ -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);
|
|
@ -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);
|
||||
}
|
|
@ -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
|
28
main.c
28
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) {
|
||||
mergeasmblks(asmlns, currunit->asmlns);
|
||||
currunit = currunit->next;
|
||||
}
|
||||
|
||||
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(currunit->asmlns, output);
|
||||
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;
|
||||
|
|
26
misc/io.c
26
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;
|
||||
}
|
||||
|
|
|
@ -11,4 +11,5 @@ typedef struct flist {
|
|||
|
||||
FILELIST* getfiles(char* input);
|
||||
void freefilelist(FILELIST* fs);
|
||||
char* getouthack(char* input);
|
||||
#endif
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ typedef struct unit {
|
|||
PARSER* parser;
|
||||
CLASS* parsed;
|
||||
COMPILER* compiler;
|
||||
STRINGLIST* asmlns;
|
||||
ASMBLK* asmlns;
|
||||
LINEBLOCK* compiled;
|
||||
VMTRANSLATOR* vmtranslator;
|
||||
struct unit* next;
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue