Add assembler
This commit is contained in:
76
assembler/assembler-tables.h
Normal file
76
assembler/assembler-tables.h
Normal 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
368
assembler/assembler.c
Normal 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
37
assembler/assembler.h
Normal 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
|
Reference in New Issue
Block a user