forked from ground/cground
Add set to compiler
This commit is contained in:
134
src/compiler.c
134
src/compiler.c
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user