#include #include #include #include #include #include #include "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, LINELIST* ln, int count); void replacevar(LINELIST* ln, int val); void preprocess(ASSEMBLER* a); void transa(LINELIST* ln); char* lookctable(TABLE* t, bool cond, char* token, const char* fieldname, int trueln); void transb(LINELIST* ln); void translate(ASSEMBLER* a); void freeassembler(ASSEMBLER* a); 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(LINELIST* input) { ASSEMBLER* a = (ASSEMBLER*)malloc(sizeof(ASSEMBLER)); a->labels = (SYMBOLARRAY*)malloc(sizeof(SYMBOLARRAY)); a->vars = (SYMBOLARRAY*)malloc(sizeof(SYMBOLARRAY)); 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, LINELIST* ln, int count) { int i = 1; char c; while(true) { c = ln->content[i]; if(c == ')') break; if(c == '\0') { fprintf(stderr, "Unexpected end of line; line %i\n", ln->truen+1); exit(1); } if(isspace(c) || c == '(') { fprintf(stderr, "Unexpected '%c'; line %i\n", c, ln->truen+1); exit(1); } i++; } if (i == 1) { fprintf(stderr, "Label has no content; line %i\n", ln->truen+1); exit(1); } 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(LINELIST* 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 handlevarsymbol(ASSEMBLER* a, LINELIST* ln) { char* afterat = ln->content+sizeof(char); if(isvar(afterat)) { int val = getsymbol(a, afterat); if(val == -1) { if(a->varsramind == RAM_LIMIT) { fprintf(stderr, "Variable amount reached RAM limit (%i); line %i\n", RAM_LIMIT, ln->truen); exit(1); } SYMBOL* var = mksymbol(afterat, strlen(afterat)+1, a->varsramind); a->varsramind++; pushsymbol(a->vars, var); val = var->value; } replacevar(ln, val); } } void handlelabelsymbol(ASSEMBLER* a, LINELIST* ln, int count) { SYMBOL* l = readlabel(a, ln, count); if(getsymbol(a, l->name) != -1) { fprintf(stderr, "Already defined symbol '%s'; line %i\n", l->name, ln->truen); exit(1); } pushsymbol(a->labels, l); } void stripvars(ASSEMBLER* a) { LINELIST* curln = a->lns; while(curln != NULL) { if(curln->content[0] == '@') handlevarsymbol(a, curln); curln = curln->next; } } void striplabels(ASSEMBLER* a) { LINELIST* curln = a->lns; LINELIST* 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; LINELIST* tmp = curln; curln = curln->next; free(tmp->content); free(tmp); } else { lastln = curln; curln = curln->next; count++; } } } void preprocess(ASSEMBLER* a) { striplabels(a); stripvars(a); } void transa(LINELIST* 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, 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--) { 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; } char* lookctable(TABLE* t, bool cond, char* token, const char* fieldname, int trueln) { 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; } fprintf(stderr, "Unexpected token '%s' for %s field; line %i\n", token, fieldname, trueln); exit(1); } void transb(LINELIST* 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(tmpi == C_TOKEN_SIZE-1) { fprintf(stderr, "Unexpected char '%c'; line %i:%i;\n", ln->content[i], ln->truen, i+1); exit(1); } 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", 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); } void translate(ASSEMBLER* a) { LINELIST* curln = a->lns; while(curln != NULL) { if(curln->content[0] == '@') transa(curln); else transb(curln); curln = curln->next; } } void freelns(LINELIST* lns) { LINELIST* next = lns->next; free(lns->content); free(lns); if(next != NULL) freelns(next); } void freeassembler(ASSEMBLER* a) { freesymbols(a->vars); freesymbols(a->labels); freelns(a->lns); free(a); }