Add compiler #14
134
src/compiler.c
134
src/compiler.c
@@ -3,20 +3,126 @@
|
||||
#include "types.h"
|
||||
#include "include/estr.h"
|
||||
#include <stdint.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
VariableTable createVariableTable() {
|
||||
VariableTable vt;
|
||||
vt.capacity = 16;
|
||||
vt.count = 0;
|
||||
vt.vars = malloc(sizeof(VariableInfo) * vt.capacity);
|
||||
return vt;
|
||||
}
|
||||
|
||||
void addVtVariable(VariableTable* vt, const char* name) {
|
||||
// check if it already exists
|
||||
for (size_t i = 0; i < vt->count; i++) {
|
||||
if (strcmp(vt->vars[i].name, name) == 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// increase capacity
|
||||
if (vt->count >= vt->capacity) {
|
||||
vt->capacity *= 2;
|
||||
vt->vars = realloc(vt->vars, sizeof(VariableInfo) * vt->capacity);
|
||||
}
|
||||
|
||||
// add the variable
|
||||
strcpy(vt->vars[vt->count].name, name);
|
||||
vt->vars[vt->count].offset = vt->count * 8;
|
||||
vt->count++;
|
||||
}
|
||||
|
||||
int getVariablePos(VariableTable* vt, const char* name) {
|
||||
for (size_t i = 0; i < vt->count; i++) {
|
||||
if (strcmp(vt->vars[i].name, name) == 0) {
|
||||
return vt->vars[i].offset;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
char* processValueString(GroundArg arg) {
|
||||
if (arg.type == VALREF) {
|
||||
char* buf = malloc(sizeof(char) * 260);
|
||||
snprintf(buf, sizeof(char) * 260, "[%s]", arg.value.refName);
|
||||
return buf;
|
||||
}
|
||||
if (arg.type == VALUE) {
|
||||
if (arg.value.value.type != INT) {
|
||||
printf("Only int is supported right now");
|
||||
exit(1);
|
||||
}
|
||||
char* buf = malloc(sizeof(char) * 64);
|
||||
snprintf(buf, sizeof(char) * 260, "%" PRId64, arg.value.value.data.intVal);
|
||||
return buf;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char* compileGroundProgram(GroundProgram* program) {
|
||||
Estr start = CREATE_ESTR("global _start\nsection .text\n_start:\n");
|
||||
Estr data = CREATE_ESTR("section .rodata\n");
|
||||
Estr data = CREATE_ESTR("section .bss\n");
|
||||
|
||||
VariableTable varTable = createVariableTable();
|
||||
|
||||
// Allocate a spot for all direct references
|
||||
for (size_t i = 0; i < program->size; i++) {
|
||||
GroundInstruction gi = program->instructions[i];
|
||||
for (size_t j = 0; j < gi.args.length; j++) {
|
||||
if (gi.args.args[j].type == DIRREF) {
|
||||
addVtVariable(&varTable, gi.args.args[j].value.refName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create data section
|
||||
for (size_t i = 0; i < program->size; i++) {
|
||||
|
||||
if (strcmp(varTable.vars[i].name, "") == 0) {
|
||||
continue;
|
||||
}
|
||||
APPEND_ESTR(data, " ");
|
||||
APPEND_ESTR(data, varTable.vars[i].name);
|
||||
APPEND_ESTR(data, " resq 1\n");
|
||||
}
|
||||
|
||||
// Generate assembly
|
||||
for (size_t i = 0; i < program->size; i++) {
|
||||
GroundInstruction gi = program->instructions[i];
|
||||
switch (gi.type) {
|
||||
case SET: {
|
||||
if (gi.args.length < 2) {
|
||||
runtimeError(TOO_FEW_ARGS, "Expecting 2 args", &gi, i);
|
||||
}
|
||||
if (gi.args.length > 2) {
|
||||
runtimeError(TOO_MANY_ARGS, "Expecting 2 args", &gi, i);
|
||||
}
|
||||
if (gi.args.args[0].type != DIRREF) {
|
||||
runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef for arg 1", &gi, i);
|
||||
}
|
||||
if (gi.args.args[1].type != VALUE) {
|
||||
runtimeError(ARG_TYPE_MISMATCH, "Expecting a Value for arg 2", &gi, i);
|
||||
}
|
||||
|
||||
char* varName= gi.args.args[0].value.refName;
|
||||
GroundValue val = gi.args.args[1].value.value;
|
||||
|
||||
if (val.type != INT) {
|
||||
runtimeError(ARG_TYPE_MISMATCH, "For now only ints are supported", &gi, i);
|
||||
}
|
||||
|
||||
char valueStr[32];
|
||||
snprintf(valueStr, sizeof(valueStr), "%" PRId64, val.data.intVal);
|
||||
APPEND_ESTR(start, " ; set\n")
|
||||
APPEND_ESTR(start, " mov rax, ");
|
||||
APPEND_ESTR(start, valueStr);
|
||||
APPEND_ESTR(start, "\n");
|
||||
APPEND_ESTR(start, " mov [");
|
||||
APPEND_ESTR(start, varName);
|
||||
APPEND_ESTR(start, "], rax\n");
|
||||
|
||||
break;
|
||||
}
|
||||
case END: {
|
||||
if (gi.args.length < 1) {
|
||||
runtimeError(TOO_FEW_ARGS, "Expecting 1 arg for end instruction", &gi, i);
|
||||
@@ -24,29 +130,10 @@ char* compileGroundProgram(GroundProgram* program) {
|
||||
if (gi.args.length > 1) {
|
||||
runtimeError(TOO_MANY_ARGS, "Expecting 1 arg for end instruction", &gi, i);
|
||||
}
|
||||
if (gi.args.args[0].type != VALUE) {
|
||||
runtimeError(ARG_TYPE_MISMATCH, "Expecting an Int for end instruction", &gi, i);
|
||||
}
|
||||
if (gi.args.args[0].value.value.type != INT) {
|
||||
runtimeError(ARG_TYPE_MISMATCH, "Expecting an Int for end instruction", &gi, i);
|
||||
}
|
||||
|
||||
int64_t bigretint = gi.args.args[0].value.value.data.intVal;
|
||||
int retint;
|
||||
if (bigretint > 255) {
|
||||
retint = 255;
|
||||
}
|
||||
else if (bigretint < 0) {
|
||||
retint = 0;
|
||||
}
|
||||
else {
|
||||
retint = bigretint;
|
||||
}
|
||||
char retstr[8];
|
||||
snprintf(retstr, sizeof(retstr), "%d", retint);
|
||||
APPEND_ESTR(start, " ; end\n");
|
||||
APPEND_ESTR(start, " mov rax, 60\n");
|
||||
APPEND_ESTR(start, " mov rdi, ");
|
||||
APPEND_ESTR(start, retstr);
|
||||
APPEND_ESTR(start, processValueString(gi.args.args[0]));
|
||||
APPEND_ESTR(start, "\n");
|
||||
APPEND_ESTR(start, " syscall\n");
|
||||
break;
|
||||
@@ -60,6 +147,7 @@ char* compileGroundProgram(GroundProgram* program) {
|
||||
|
||||
Estr complete = CREATE_ESTR("");
|
||||
APPEND_ESTR(complete, start.str);
|
||||
APPEND_ESTR(complete, " ; End of program\n mov rax, 60\n mov rdi, 0\n syscall\n");
|
||||
APPEND_ESTR(complete, data.str)
|
||||
|
||||
return complete.str;
|
||||
|
||||
@@ -3,3 +3,16 @@
|
||||
|
||||
char* compileGroundProgram(GroundProgram* program);
|
||||
[[noreturn]] void runtimeError(GroundRuntimeError error, char* what, GroundInstruction* where, int whereLine);
|
||||
|
||||
typedef struct VariableInfo {
|
||||
char name[256];
|
||||
int offset;
|
||||
} VariableInfo;
|
||||
|
||||
typedef struct VariableTable {
|
||||
VariableInfo* vars;
|
||||
size_t count;
|
||||
size_t capacity;
|
||||
} VariableTable;
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user