Add compiler #14

Merged
max merged 13 commits from unstable into master 2026-01-21 15:53:20 +11:00
2 changed files with 124 additions and 23 deletions
Showing only changes of commit 31577fcc62 - Show all commits

View File

@@ -3,20 +3,126 @@
#include "types.h" #include "types.h"
#include "include/estr.h" #include "include/estr.h"
#include <stdint.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) { char* compileGroundProgram(GroundProgram* program) {
Estr start = CREATE_ESTR("global _start\nsection .text\n_start:\n"); 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 // Create data section
for (size_t i = 0; i < program->size; i++) { 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 // Generate assembly
for (size_t i = 0; i < program->size; i++) { for (size_t i = 0; i < program->size; i++) {
GroundInstruction gi = program->instructions[i]; GroundInstruction gi = program->instructions[i];
switch (gi.type) { 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: { case END: {
if (gi.args.length < 1) { if (gi.args.length < 1) {
runtimeError(TOO_FEW_ARGS, "Expecting 1 arg for end instruction", &gi, i); 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) { if (gi.args.length > 1) {
runtimeError(TOO_MANY_ARGS, "Expecting 1 arg for end instruction", &gi, i); runtimeError(TOO_MANY_ARGS, "Expecting 1 arg for end instruction", &gi, i);
} }
if (gi.args.args[0].type != VALUE) { APPEND_ESTR(start, " ; end\n");
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, " mov rax, 60\n"); APPEND_ESTR(start, " mov rax, 60\n");
APPEND_ESTR(start, " mov rdi, "); APPEND_ESTR(start, " mov rdi, ");
APPEND_ESTR(start, retstr); APPEND_ESTR(start, processValueString(gi.args.args[0]));
APPEND_ESTR(start, "\n"); APPEND_ESTR(start, "\n");
APPEND_ESTR(start, " syscall\n"); APPEND_ESTR(start, " syscall\n");
break; break;
@@ -60,6 +147,7 @@ char* compileGroundProgram(GroundProgram* program) {
Estr complete = CREATE_ESTR(""); Estr complete = CREATE_ESTR("");
APPEND_ESTR(complete, start.str); 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) APPEND_ESTR(complete, data.str)
return complete.str; return complete.str;

View File

@@ -3,3 +3,16 @@
char* compileGroundProgram(GroundProgram* program); char* compileGroundProgram(GroundProgram* program);
[[noreturn]] void runtimeError(GroundRuntimeError error, char* what, GroundInstruction* where, int whereLine); [[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;