diff --git a/.gitignore b/.gitignore index af20eaf..eb73685 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ assembler +tags diff --git a/Makefile b/Makefile index 9d01ef0..4173081 100644 --- a/Makefile +++ b/Makefile @@ -1,2 +1,7 @@ -main: assembler.c - ${CC} -std=c99 assembler.c -o assembler +FILES = assembler.c main.c util.c +INCLUDES = -I. +CFLAGS = -std=c99 +OUTFILE = assembler + +main: ${FILES} + ${CC} ${CFLAGS} ${FILES} -o ${OUTFILE} diff --git a/assembler.c b/assembler.c index 53ee997..3e53ba7 100644 --- a/assembler.c +++ b/assembler.c @@ -3,103 +3,61 @@ #include #include #include +#include +#include "tables.h" +#include "assembler.h" +#include "util.h" -#define RAM_LIMIT 24577 -#define TOP_VAR 16383 -#define BOT_VAR 16 -#define ADD_STR_SIZE 7 -#define INST_SIZE 17 -#define C_TOKEN_SIZE 4 -#define INST_LIMIT 32768 +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); +ASSEMBLER* mkassembler(FILE* input); +void populatevars(ASSEMBLER* a); +SYMBOL* readlabel(ASSEMBLER* a, int trueln); +void chop(ASSEMBLER* a); +void replacevar(SYMBOL* ln, int val); +void preprocess(ASSEMBLER* a); +void transa(SYMBOL* ln); +char* lookctable(TABLE* t, bool cond, char* token, const char* fieldname, int trueln); +void transb(SYMBOL* ln); +void translate(ASSEMBLER* a); +void gatherinfo(ASSEMBLER* a); +void freeassembler(ASSEMBLER* a); -#define CMP_SIZE 8 -#define CMP_TABLE_SIZE 37 -const char* cmptable[CMP_TABLE_SIZE] = -{ - "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" -}; - -#define DEST_SIZE 4 -#define DEST_TABLE_SIZE 7 -const char* desttable[] = -{ - "M", "001", - "D", "010", - "MD", "011", - "A", "100", - "AM", "101", - "AD", "110", - "AMD", "111" -}; - -#define JMP_SIZE 4 -#define JMP_TABLE_SIZE 7 -const char* jmptable[] = -{ - "JGT", "001", - "JEQ", "010", - "JGE", "011", - "JLT", "100", - "JNE", "101", - "JLE", "110", - "JMP", "111" -}; - -struct symbol { - char* name; - int value; -}; - -struct line { - char* ln; - int truen; -}; - -void freesymbols(struct symbol** symbols, int symbolsind) { - for(int i = 0; i < symbolsind; i++) { - free(symbols[i]->name); - free(symbols[i]); +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); } } -struct symbol* mksymb(char* name, int namesize, int val) { - struct symbol* s = (struct symbol*)malloc(sizeof(struct symbol)); +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; @@ -107,39 +65,39 @@ struct symbol* mksymb(char* name, int namesize, int val) { return s; } -int getsymb(char* symb, struct symbol** vars, int varscount, struct symbol** labels, int labelscount) { - for(int i = 0; i < varscount; i++) - if(strcmp(vars[i]->name, symb) == 0) - return vars[i]->value; +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 < labelscount; i++) - if(strcmp(labels[i]->name, symb) == 0) - return labels[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; } -void skipln(FILE* input) { +void skipln(ASSEMBLER* a) { char c; - while(c = fgetc(input), c != -1) + while(c = fgetc(a->input), c != -1) if(c == '\n') break; } -void readrest(FILE* input, int trueln) { +void readrest(ASSEMBLER* a, int trueln) { char c; - while(c = fgetc(input), c != -1) { + while(c = fgetc(a->input), c != -1) { if(c == '\n') break; if(isspace(c)) continue; if(c == '/') { - char nc = fgetc(input); + char nc = fgetc(a->input); if(nc == '/') { - skipln(input); + skipln(a); break; } - ungetc(nc, input); + ungetc(nc, a->input); } fprintf(stderr, "Unexpected '%c' at line '%i'\n", c, trueln); exit(1); @@ -158,96 +116,84 @@ int isvar(char* var) { return 0; } -void populatevars(struct symbol** vars, int* varscount) { - // First five +void initsymbols(SYMBOLARRAY* s) { + s->size = s->count * sizeof(SYMBOL*); + s->items = (SYMBOL**)malloc(s->size); + s->count = 0; +} + +ASSEMBLER* mkassembler(FILE* input) { + ASSEMBLER* a = (ASSEMBLER*)malloc(sizeof(ASSEMBLER)); + a->lns = (SYMBOLARRAY*)malloc(sizeof(SYMBOLARRAY)); + a->labels = (SYMBOLARRAY*)malloc(sizeof(SYMBOLARRAY)); + a->vars = (SYMBOLARRAY*)malloc(sizeof(SYMBOLARRAY)); + a->input = input; + + gatherinfo(a); + + initsymbols(a->lns); + initsymbols(a->labels); + a->vars->count = 80; // arbitrary number for initial size + initsymbols(a->vars); + + populatevars(a); + chop(a); + + 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++) { - vars[i] = mksymb(labels[i], strlen(labels[i])+1, i); + a->vars->items[i] = mksymbol(labels[i], strlen(labels[i])+1, i); } // RAM variables (R0-R15) - const int ramvamnt = 16; //max: 19 const int asciioff = 48; char ramvname[4]; ramvname[0] = 'R'; ramvname[2] = '\0'; - for(int i = 0; i < (ramvamnt/10)*10; i++) { + int tmptarg = (ramvamnt/10)*10; + for(int i = 0; i < tmptarg; i++) { ramvname[1] = (char)(i+asciioff); - vars[firstamnt+i] = mksymb(ramvname, 3, i); + 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); - vars[firstamnt+i] = mksymb(ramvname, 4, i); + a->vars->items[firstamnt+i] = mksymbol(ramvname, 4, i); } // SCREEN var - vars[firstamnt+ramvamnt] = mksymb("SCREEN", 7, 16384); + a->vars->items[firstamnt+ramvamnt] = mksymbol("SCREEN", 7, 16384); // KBD var - vars[firstamnt+ramvamnt+1] = mksymb("KBD", 4, 24576); - // update varscount to new index - *varscount = firstamnt+ramvamnt+2; + a->vars->items[firstamnt+ramvamnt+1] = mksymbol("KBD", 4, 24576); } -void gatherinfo(FILE* input, int* lnscount, int* labelscount, int* maxwidth) { - char c; - unsigned char readsmt = 0; - unsigned char comment = 0; - int truelnscount = 1; - int lnwidth = 1; - while(c = fgetc(input), c != -1) { - if(c == '\n') { - truelnscount++; - comment = 0; - if(lnwidth > *maxwidth) - *maxwidth = lnwidth; - if(readsmt) { - if(*lnscount == INST_LIMIT) { - fprintf(stderr, "Reached instruction limit (%i); line %i\n", INST_LIMIT, truelnscount); - exit(1); - } - (*lnscount)++; - } - readsmt = 0; - lnwidth = 1; - continue; - } - if(comment) - continue; - if(c == '(') { - (*labelscount)++; - comment = 1; - continue; - } - if(c == '/') { - char nc = fgetc(input); - if(nc == '/') { - comment = 1; - continue; - } - ungetc(nc, input); - } - if(isspace(c)) { - continue; - } - readsmt = 1; - lnwidth++; - } - rewind(input); -} - -struct symbol* readlabel(FILE* input, int ln, int trueln, int lnwidth) { - char* name = (char*)malloc(sizeof(char)*(lnwidth-1)); +SYMBOL* readlabel(ASSEMBLER* a, int trueln) { + char* name = (char*)malloc(sizeof(char)*(a->maxwidth-1)); int i = 0; char c; - while(c = fgetc(input), c != -1) { + int maxind = a->maxwidth-2; + while(c = fgetc(a->input), c != -1) { if(c == ')') break; - if(i == lnwidth-2) { + if(i == maxind) { fprintf(stderr, "Label width bigger than the maximum (%i characters); line %i\n", - lnwidth-2, trueln+1); + maxind, trueln+1); exit(1); } if(c == '\n') { @@ -262,28 +208,29 @@ struct symbol* readlabel(FILE* input, int ln, int trueln, int lnwidth) { i++; } name[i] = '\0'; - readrest(input, trueln); - struct symbol* l = (struct symbol*)malloc(sizeof(struct symbol)); + readrest(a, trueln); + SYMBOL* l = (SYMBOL*)malloc(sizeof(SYMBOL)); l->name = name; - l->value = ln; + l->value = a->lns->count; return l; } // Splits the stream into an array of strings, stripping comments, white spaces and labels // Requires vars array to check for duplicate symbols, but doesn't modify it -int chop(FILE* input, struct symbol** vars, int varscount, struct symbol** labels, int* labelscount, struct line** lns, int lnwidth) { +void chop(ASSEMBLER* a) { char c; - char tmpln[lnwidth]; + char tmpln[a->maxwidth]; + int lnind = 0; int lnscount = 0; int truelnscount = 1; - int lnind = 0; - int comment = 0; - int spacedln = 0; - while(c = fgetc(input), c != -1) { + + bool comment = false; + bool spacedln = false; + while(c = fgetc(a->input), c != -1) { if(c == '\n') { if(comment) { - comment = 0; - ungetc(c, input); + comment = false; + ungetc(c, a->input); continue; } truelnscount++; @@ -292,16 +239,11 @@ int chop(FILE* input, struct symbol** vars, int varscount, struct symbol** label tmpln[lnind] = '\0'; - char* newln = (char*)malloc(sizeof(char)*(lnind+1)); - strcpy(newln, tmpln); - struct line* s = (struct line*)malloc(sizeof(struct line)); - s->ln = newln; - s->truen = truelnscount; - lns[lnscount] = s; + pushsymbol(a->lns, mksymbol(tmpln, lnind+1, truelnscount)); - lnscount++; lnind = 0; - spacedln = 0; + spacedln = false; + lnscount++; continue; } @@ -310,35 +252,34 @@ int chop(FILE* input, struct symbol** vars, int varscount, struct symbol** label if(isspace(c)) { if(lnind) - spacedln = 1; + spacedln = true; continue; } if(c == '(') { - if(lnind != 0) { + if(lnind) { fprintf(stderr, "Unexpected char '%c'; line %i:%i\n", c, truelnscount, lnind+1); exit(1); } - struct symbol* l = readlabel(input, lnscount, truelnscount, lnwidth); - if(getsymb(l->name, vars, varscount, labels, *labelscount) != -1) { + SYMBOL* l = readlabel(a, truelnscount); + if(getsymbol(a, l->name) != -1) { fprintf(stderr, "Already defined symbol '%s'; line %i\n", l->name, truelnscount); exit(1); } - labels[*labelscount] = l; - (*labelscount)++; + pushsymbol(a->labels, l); truelnscount++; continue; } if(c == '/') { - char nc = fgetc(input); + char nc = fgetc(a->input); if(nc == '/') { - comment = 1; + comment = true; continue; } - ungetc(nc, input); + ungetc(nc, a->input); } if(spacedln) { @@ -346,91 +287,98 @@ int chop(FILE* input, struct symbol** vars, int varscount, struct symbol** label exit(1); } - if(lnwidth-1 == lnind) { - fprintf(stderr, "Reached line width limit (%i); line %i\n", lnwidth, lnscount+1); - exit(1); - } - tmpln[lnind] = c; lnind++; } - return lnscount; + fclose(a->input); } -void replacevar(struct line* ln, int val) { - free(ln->ln); - char* newln = (char *)malloc(sizeof(char)*ADD_STR_SIZE); - snprintf(newln, ADD_STR_SIZE, "@%i", val); - ln->ln = newln; +void replacevar(SYMBOL* ln, int val) { + free(ln->content); + int size = sizeof(char)*(countplaces(val) + 2); + char* newln = (char *)malloc(size); + snprintf(newln, size, "@%i", val); + ln->content = newln; } -void stripvars(struct symbol** vars, int* varscount, struct symbol** labels, int* labelscount, struct line** lns, int lnscount) { - int varsramind = BOT_VAR; - for(int i = 0; i < lnscount; i++) { - if(lns[i]->ln[0] == '@') { - char* afterat = lns[i]->ln+sizeof(char); +void preprocess(ASSEMBLER* a) { + int varsramind = BOTTOM_VAR; + for(int i = 0; i < a->lncount; i++) { + if(a->lns->items[i]->content[0] == '@') { + char* afterat = a->lns->items[i]->content+sizeof(char); if(isvar(afterat)) { - int val = getsymb(afterat, vars, *varscount, labels, *labelscount); + int val = getsymbol(a, afterat); if(val == -1) { if(varsramind == RAM_LIMIT) { - fprintf(stderr, "Variable amount reached RAM limit (%i); line %i\n", RAM_LIMIT, lns[i]->truen); + fprintf(stderr, "Variable amount reached RAM limit (%i); line %i\n", RAM_LIMIT, a->lns->items[i]->truen); exit(1); } - struct symbol* var = mksymb(afterat, strlen(afterat)+1, varsramind); - vars[*varscount] = var; - (*varscount)++; + SYMBOL* var = mksymbol(afterat, strlen(afterat)+1, varsramind); varsramind++; + pushsymbol(a->vars, var); val = var->value; } - replacevar(lns[i], val); + replacevar(a->lns->items[i], val); } } } } -void transa(char* in, char* out, int trueln) { - int add = atoi(in+sizeof(char)); +void transa(SYMBOL* ln) { + int add = atoi(ln->content+sizeof(char)); + if(add >= INST_LIMIT) { - fprintf(stderr, "'A' instruction cannot reference addresses bigger than %i; line %i\n", INST_LIMIT-1, trueln); + fprintf(stderr, "'A' instruction cannot reference addresses bigger than %i; line %i\n", INST_LIMIT-1, ln->truen); exit(1); } + + char* out = (char*)malloc(sizeof(char) * INST_SIZE); + int lastbit = 1 << 15; - for(int i = INST_SIZE-2;i > 0; i--) { + 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'; + + free(ln->content); + ln->content = out; } -void lookctable(char* out, int outsize, const char** table, int tablesize, int cond, char* token, const char* fieldname, int trueln) { +char* lookctable(TABLE* t, bool cond, char* token, const char* fieldname, int trueln) { + char* out = (char*)malloc(t->instsize); + if(!cond) { - for(int i = 0; i < outsize-1; i++) + int targsize = t->instsize - 1; + for(int i = 0; i < targsize; i++) out[i] = '0'; - out[outsize-1] = '\0'; - return; + out[t->instsize-1] = '\0'; + return out; } - for(int i = 0; i < tablesize; i++) - if(strcmp(table[2*i], token) == 0) { - strcpy(out, table[(2*i)+1]); - return; + 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; } + fprintf(stderr, "Unexpected token '%s' for %s field; line %i\n", token, fieldname, trueln); exit(1); } -void transb(char* in, char* out, int trueln) { - int hasjmp = 0; - int hasdest = 0; - int hascmp = 0; +void transb(SYMBOL* 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(1) { - if(in[i] == '\0') { + if(ln->content[i] == '\0') { tmp[tmpi] = '\0'; if(hasjmp) strcpy(jmp, tmp); @@ -440,22 +388,22 @@ void transb(char* in, char* out, int trueln) { } if(tmpi == C_TOKEN_SIZE-1) { - fprintf(stderr, "Unexpected char '%c'; line %i:%i;\n", in[i], trueln, i+1); + fprintf(stderr, "Unexpected char '%c'; line %i:%i;\n", ln->content[i], ln->truen, i+1); exit(1); } - if(in[i] == '=' && !hasdest && hascmp) { - hascmp = 0; - hasdest = 1; + if(ln->content[i] == '=' && !hasdest && hascmp) { + hascmp = false; + hasdest = true; tmp[tmpi] = '\0'; strcpy(dest, tmp); tmpi = 0; i++; continue; } - if(in[i] == ';' && !hasjmp && hascmp) { - hascmp = 0; - hasjmp = 1; + if(ln->content[i] == ';' && !hasjmp && hascmp) { + hascmp = false; + hasjmp = true; tmp[tmpi] = '\0'; strcpy(cmp, tmp); tmpi = 0; @@ -464,105 +412,90 @@ void transb(char* in, char* out, int trueln) { } hascmp = 1; - tmp[tmpi] = in[i]; + tmp[tmpi] = ln->content[i]; tmpi++; i++; } - char rawdest[DEST_SIZE]; - lookctable(rawdest, DEST_SIZE, desttable, DEST_TABLE_SIZE, hasdest, dest, "dest", trueln); - char rawjmp[JMP_SIZE]; - lookctable(rawjmp, JMP_SIZE, jmptable, JMP_TABLE_SIZE, hasjmp, jmp, "jump", trueln); - char rawcmp[CMP_SIZE]; - lookctable(rawcmp, CMP_SIZE, cmptable, CMP_TABLE_SIZE, 1, cmp, "comp", trueln); - sprintf(out, "111%s%s%s", rawcmp, rawdest, rawjmp); + char* rawdest = lookctable(&desttable, hasdest, dest, "dest", ln->truen); + char* rawjmp = lookctable(&jmptable, hasjmp, jmp, "jump", ln->truen); + char* rawcmp = lookctable(&cmptable, 1, cmp, "comp", ln->truen); + + int sz = sizeof(char) * INST_SIZE; + char* out = (char*)malloc(sz); + snprintf(out, sz, "111%s%s%s", rawcmp, rawdest, rawjmp); + + free(ln->content); + ln->content = out; + free(rawdest); + free(rawjmp); + free(rawcmp); } -char** translate(struct line** lns, int lnscount) { - char** assembled = (char**)malloc(sizeof(char*)*lnscount); - for(int i = 0; i < lnscount; i++) - assembled[i] = (char*)malloc(sizeof(char)*INST_SIZE); - - for(int i = 0; i < lnscount; i++) - if(lns[i]->ln[0] == '@') - transa(lns[i]->ln, assembled[i], lns[i]->truen); +void translate(ASSEMBLER* a) { + for(int i = 0; i < a->lns->count; i++) + if(a->lns->items[i]->content[0] == '@') + transa(a->lns->items[i]); else - transb(lns[i]->ln, assembled[i], lns[i]->truen); - return assembled; + transb(a->lns->items[i]); } -void getoutname(char* fname, int fnamelen, char* outf) { - strcpy(outf, fname); - strcpy(outf+(fnamelen*sizeof(char))-(3*sizeof(char)), "hack"); +void gatherinfo(ASSEMBLER* a) { + char c; + bool readsmt = false; + bool comment = false; + int lnwidth = 1; + + a->truelnscount = 1; + a->maxwidth = 0; + a->labels->count = 0; + a->lns->count = 0; + + while(c = fgetc(a->input), c != -1) { + if(c == '\n') { + a->truelnscount++; + comment = false; + if(lnwidth > a->maxwidth) + a->maxwidth = lnwidth; + if(readsmt) { + if(a->lns->count == INST_LIMIT) { + fprintf(stderr, "Reached instruction limit (%i); line %i\n", INST_LIMIT, a->truelnscount); + exit(1); + } + a->lns->count++; + } + readsmt = false; + lnwidth = 1; + continue; + } + if(comment) + continue; + if(c == '(') { + a->labels->count++; + comment = true; + continue; + } + if(c == '/') { + char nc = fgetc(a->input); + if(nc == '/') { + comment = true; + continue; + } + ungetc(nc, a->input); + } + if(isspace(c)) { + continue; + } + readsmt = true; + lnwidth++; + } + rewind(a->input); + a->lncount = a->lns->count; } -int main(int argc, char* argv[]) { - if(argc < 2) { - printf("Usage: %s {input}\n", argv[0]); - return 1; - } - - int fnamelen = strlen(argv[1]); - int invalidext = strcmp(argv[1]+(fnamelen*sizeof(char)-(4*sizeof(char))), ".asm"); - if(invalidext) { - fprintf(stderr, "Invalid extension (must be *.asm)\n"); - return 1; - } - FILE* input = fopen(argv[1], "r"); - - if(input == NULL) { - fprintf(stderr, "%s\n", strerror(errno)); - return errno; - } - - // info gathering - int lnscount = 0; - int labelscount = 0; - int lnwidth = 0; - gatherinfo(input, &lnscount, &labelscount, &lnwidth); - struct line** lns = (struct line**)malloc(sizeof(struct line*)*lnscount); // has to be on the heap; can be huge and cause a stack overflow - - // line chopping - struct symbol** labels = (struct symbol**)malloc(sizeof(struct symbol*)*labelscount); // same for this one - labelscount = 0; - - struct symbol* vars[TOP_VAR - BOT_VAR]; - int varscount = 0; - populatevars(vars, &varscount); - - lnscount = chop(input, vars, varscount, labels, &labelscount, lns, lnwidth); - fclose(input); - - // variable substitution - stripvars(vars, &varscount, labels, &labelscount, lns, lnscount); - freesymbols(vars, varscount); - freesymbols(labels, labelscount); - free(labels); - - // actual translation - char** bin = translate(lns, lnscount); - for(int i = 0; i < lnscount; i++) { - free(lns[i]->ln); - free(lns[i]); - } - free(lns); - - // file output - char outf[fnamelen+2]; - getoutname(argv[1], fnamelen, outf); - - FILE* output = fopen(outf, "w"); - - if(output == NULL) { - fprintf(stderr, "%s\n", strerror(errno)); - return errno; - } - - for(int i = 0; i < lnscount; i++) { - fprintf(output, "%s\n", bin[i]); - free(bin[i]); - } - free(bin); - fclose(output); - return 0; +void freeassembler(ASSEMBLER* a) { + freesymbols(a->lns); + freesymbols(a->vars); + freesymbols(a->labels); + free(a); } diff --git a/assembler.h b/assembler.h new file mode 100644 index 0000000..7779fed --- /dev/null +++ b/assembler.h @@ -0,0 +1,47 @@ +#ifndef ASSEMBLER_H +#define ASSEMBLER_H +#include + +#define RAM_LIMIT 24577 +#define TOP_VAR 16383 +#define BOTTOM_VAR 16 +#define INST_SIZE 17 +#define C_TOKEN_SIZE 4 +#define INST_LIMIT 1<<15 + +typedef struct { + union { + char* name; + char* content; + }; + union { + int value; + int truen; + }; +} SYMBOL; + +typedef struct { + SYMBOL** items; + int count; + int size; +} SYMBOLARRAY; + +typedef struct { + FILE* input; + + int maxwidth; + int truelnscount; + int lncount; + + SYMBOLARRAY* lns; + + SYMBOLARRAY* labels; + + SYMBOLARRAY* vars; +} ASSEMBLER; + +ASSEMBLER* mkassembler(FILE* input); +void preprocess(ASSEMBLER* a); +void translate(ASSEMBLER* a); +void freeassembler(ASSEMBLER* a); +#endif diff --git a/main.c b/main.c new file mode 100644 index 0000000..8b1ef1b --- /dev/null +++ b/main.c @@ -0,0 +1,59 @@ +#include +#include +#include +#include +#include "assembler.h" + +char* getoutname(char* fname, int fnamelen) { + char* outf = (char*)malloc(sizeof(char) * fnamelen + 2); + strcpy(outf, fname); + // .hack + strcpy( (outf + ((fnamelen * sizeof(char)) - (3 * sizeof(char)))), "hack"); + return outf; +} + +int main(int argc, char* argv[]) { + if(argc < 2) { + printf("Usage: %s {input}\n", argv[0]); + return 1; + } + + int fnamelen = strlen(argv[1]); + int invalidext = strcmp(argv[1]+(fnamelen*sizeof(char)-(4*sizeof(char))), ".asm"); + if(invalidext) { + fprintf(stderr, "Invalid extension (must be named lide Xxx.asm)\n"); + return 1; + } + FILE* input = fopen(argv[1], "r"); + + if(input == NULL) { + fprintf(stderr, "%s\n", strerror(errno)); + return errno; + } + + ASSEMBLER* a = mkassembler(input); + + // variable substitution + preprocess(a); + + // actual translation + translate(a); + + // file output + char* outf = getoutname(argv[1], fnamelen); + FILE* output = fopen(outf, "w"); + + if(output == NULL) { + fprintf(stderr, "%s\n", strerror(errno)); + return errno; + } + + for(int i = 0; i < a->lns->count; i++) { + fprintf(output, "%s\n", a->lns->items[i]->content); + } + + free(outf); + freeassembler(a); + fclose(output); + return 0; +} diff --git a/tables.h b/tables.h new file mode 100644 index 0000000..6be0780 --- /dev/null +++ b/tables.h @@ -0,0 +1,88 @@ +#ifndef TABLES +#define TABLES + +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" +}; +TABLE cmptable = +{ + .table = cmptablestrs, + .size = sizeof(cmptablestrs) / sizeof(char*) / 2, + .instsize = 8 * sizeof(char) +}; + +const char* desttablestrs[] = { + "M", "001", + "D", "010", + "MD", "011", + "A", "100", + "AM", "101", + "AD", "110", + "AMD", "111" +}; +TABLE desttable = +{ + .table = desttablestrs, + .size = sizeof(desttablestrs) / sizeof(char*) / 2, + .instsize = 4 * sizeof(char) +}; + +const char* jmptablestrs[] = { + "JGT", "001", + "JEQ", "010", + "JGE", "011", + "JLT", "100", + "JNE", "101", + "JLE", "110", + "JMP", "111" +}; +TABLE jmptable = +{ + .table = jmptablestrs, + .size = sizeof(jmptablestrs) / sizeof(char*) / 2, + .instsize = 4 * sizeof(char) +}; + +#endif diff --git a/util.c b/util.c new file mode 100644 index 0000000..5186e56 --- /dev/null +++ b/util.c @@ -0,0 +1,24 @@ +#include +#include +#include "util.h" + +char* heapstr(const char* str, int len) { + int sz = sizeof(char) * (len + 1); + char* outstr = (char*)malloc(sz); + strcpy(outstr, str); + return outstr; +} + +int countplaces(int n) { + int places = 1; + int divisor = 1; + if(n < 0) { + n = -n; + places++; + } + while(n / divisor >= 10) { + places++; + divisor *= 10; + } + return places; +} diff --git a/util.h b/util.h new file mode 100644 index 0000000..f6fde00 --- /dev/null +++ b/util.h @@ -0,0 +1,5 @@ +#ifndef UTIL_H +#define UTIL_H +char* heapstr(const char* str, int len); +int countplaces(int n); +#endif