#include "compiler.h" #include "interpreter.h" #include "types.h" #include "include/estr.h" #include #include 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 .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; APPEND_ESTR(start, " ; set\n") APPEND_ESTR(start, " mov rax, "); APPEND_ESTR(start, processValueString(gi.args.args[1])); APPEND_ESTR(start, "\n"); APPEND_ESTR(start, " mov ["); APPEND_ESTR(start, varName); APPEND_ESTR(start, "], rax\n"); break; } case ADD: { if (gi.args.length < 3) { runtimeError(TOO_FEW_ARGS, "Expecting 2 args for add instruction", &gi, i); } if (gi.args.length > 3) { runtimeError(TOO_MANY_ARGS, "Expecting 2 args for add instruction", &gi, i); } if (gi.args.args[0].type != VALUE && gi.args.args[0].type != VALREF) { runtimeError(ARG_TYPE_MISMATCH, "Expecting an Int for arg 1", &gi, i); } if (gi.args.args[1].type != VALUE && gi.args.args[1].type != VALREF) { runtimeError(ARG_TYPE_MISMATCH, "Expecting an Int for arg 2", &gi, i); } if (gi.args.args[2].type != DIRREF) { runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef for arg 3", &gi, i); } char* varName= gi.args.args[2].value.refName; APPEND_ESTR(start, " ; add\n"); APPEND_ESTR(start, " mov rax, "); APPEND_ESTR(start, processValueString(gi.args.args[0])); APPEND_ESTR(start, "\n"); APPEND_ESTR(start, " add rax, "); APPEND_ESTR(start, processValueString(gi.args.args[1])); APPEND_ESTR(start, "\n"); APPEND_ESTR(start, " mov ["); APPEND_ESTR(start, varName); APPEND_ESTR(start, "], rax\n"); break; } case SUBTRACT: { if (gi.args.length < 3) { runtimeError(TOO_FEW_ARGS, "Expecting 2 args for subtract instruction", &gi, i); } if (gi.args.length > 3) { runtimeError(TOO_MANY_ARGS, "Expecting 2 args for subtract instruction", &gi, i); } if (gi.args.args[0].type != VALUE && gi.args.args[0].type != VALREF) { runtimeError(ARG_TYPE_MISMATCH, "Expecting an Int for arg 1", &gi, i); } if (gi.args.args[1].type != VALUE && gi.args.args[1].type != VALREF) { runtimeError(ARG_TYPE_MISMATCH, "Expecting an Int for arg 2", &gi, i); } if (gi.args.args[2].type != DIRREF) { runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef for arg 3", &gi, i); } char* varName= gi.args.args[2].value.refName; APPEND_ESTR(start, " ; subtract\n"); APPEND_ESTR(start, " mov rax, "); APPEND_ESTR(start, processValueString(gi.args.args[0])); APPEND_ESTR(start, "\n"); APPEND_ESTR(start, " sub rax, "); APPEND_ESTR(start, processValueString(gi.args.args[1])); APPEND_ESTR(start, "\n"); APPEND_ESTR(start, " mov ["); APPEND_ESTR(start, varName); APPEND_ESTR(start, "], rax\n"); break; } case MULTIPLY: { if (gi.args.length < 3) { runtimeError(TOO_FEW_ARGS, "Expecting 2 args for multiply instruction", &gi, i); } if (gi.args.length > 3) { runtimeError(TOO_MANY_ARGS, "Expecting 2 args for multiply instruction", &gi, i); } if (gi.args.args[0].type != VALUE && gi.args.args[0].type != VALREF) { runtimeError(ARG_TYPE_MISMATCH, "Expecting an Int for arg 1", &gi, i); } if (gi.args.args[1].type != VALUE && gi.args.args[1].type != VALREF) { runtimeError(ARG_TYPE_MISMATCH, "Expecting an Int for arg 2", &gi, i); } if (gi.args.args[2].type != DIRREF) { runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef for arg 3", &gi, i); } char* varName= gi.args.args[2].value.refName; APPEND_ESTR(start, " ; multiply\n"); APPEND_ESTR(start, " mov rax, "); APPEND_ESTR(start, processValueString(gi.args.args[0])); APPEND_ESTR(start, "\n"); APPEND_ESTR(start, " imul rax, "); APPEND_ESTR(start, processValueString(gi.args.args[1])); APPEND_ESTR(start, "\n"); APPEND_ESTR(start, " mov ["); APPEND_ESTR(start, varName); APPEND_ESTR(start, "], rax\n"); break; } case EQUAL: { if (gi.args.length < 3) { runtimeError(TOO_FEW_ARGS, "Expecting 2 args for equal instruction", &gi, i); } if (gi.args.length > 3) { runtimeError(TOO_MANY_ARGS, "Expecting 2 args for equal instruction", &gi, i); } if (gi.args.args[0].type != VALUE && gi.args.args[0].type != VALREF) { runtimeError(ARG_TYPE_MISMATCH, "Expecting an Int for arg 1", &gi, i); } if (gi.args.args[1].type != VALUE && gi.args.args[1].type != VALREF) { runtimeError(ARG_TYPE_MISMATCH, "Expecting an Int for arg 2", &gi, i); } if (gi.args.args[2].type != DIRREF) { runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef for arg 3", &gi, i); } char* varName= gi.args.args[2].value.refName; APPEND_ESTR(start, " ; equal\n"); APPEND_ESTR(start, " mov rax, "); APPEND_ESTR(start, processValueString(gi.args.args[0])); APPEND_ESTR(start, "\n"); APPEND_ESTR(start, " cmp rax, "); APPEND_ESTR(start, processValueString(gi.args.args[1])); APPEND_ESTR(start, "\n"); APPEND_ESTR(start, " sete al\n"); APPEND_ESTR(start, " movzx rax, al\n"); APPEND_ESTR(start, " mov ["); APPEND_ESTR(start, varName); APPEND_ESTR(start, "], rax\n"); break; } case INEQUAL: { if (gi.args.length < 3) { runtimeError(TOO_FEW_ARGS, "Expecting 2 args for inequal instruction", &gi, i); } if (gi.args.length > 3) { runtimeError(TOO_MANY_ARGS, "Expecting 2 args for inequal instruction", &gi, i); } if (gi.args.args[0].type != VALUE && gi.args.args[0].type != VALREF) { runtimeError(ARG_TYPE_MISMATCH, "Expecting an Int for arg 1", &gi, i); } if (gi.args.args[1].type != VALUE && gi.args.args[1].type != VALREF) { runtimeError(ARG_TYPE_MISMATCH, "Expecting an Int for arg 2", &gi, i); } if (gi.args.args[2].type != DIRREF) { runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef for arg 3", &gi, i); } char* varName= gi.args.args[2].value.refName; APPEND_ESTR(start, " ; inequal\n"); APPEND_ESTR(start, " mov rax, "); APPEND_ESTR(start, processValueString(gi.args.args[0])); APPEND_ESTR(start, "\n"); APPEND_ESTR(start, " cmp rax, "); APPEND_ESTR(start, processValueString(gi.args.args[1])); APPEND_ESTR(start, "\n"); APPEND_ESTR(start, " setne al\n"); APPEND_ESTR(start, " movzx rax, al\n"); APPEND_ESTR(start, " mov ["); APPEND_ESTR(start, varName); APPEND_ESTR(start, "], rax\n"); break; } case GREATER: { if (gi.args.length < 3) { runtimeError(TOO_FEW_ARGS, "Expecting 2 args for greater instruction", &gi, i); } if (gi.args.length > 3) { runtimeError(TOO_MANY_ARGS, "Expecting 2 args for greater instruction", &gi, i); } if (gi.args.args[0].type != VALUE && gi.args.args[0].type != VALREF) { runtimeError(ARG_TYPE_MISMATCH, "Expecting an Int for arg 1", &gi, i); } if (gi.args.args[1].type != VALUE && gi.args.args[1].type != VALREF) { runtimeError(ARG_TYPE_MISMATCH, "Expecting an Int for arg 2", &gi, i); } if (gi.args.args[2].type != DIRREF) { runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef for arg 3", &gi, i); } char* varName= gi.args.args[2].value.refName; APPEND_ESTR(start, " ; greater\n"); APPEND_ESTR(start, " mov rax, "); APPEND_ESTR(start, processValueString(gi.args.args[0])); APPEND_ESTR(start, "\n"); APPEND_ESTR(start, " cmp rax, "); APPEND_ESTR(start, processValueString(gi.args.args[1])); APPEND_ESTR(start, "\n"); APPEND_ESTR(start, " setg al\n"); APPEND_ESTR(start, " movzx rax, al\n"); APPEND_ESTR(start, " mov ["); APPEND_ESTR(start, varName); APPEND_ESTR(start, "], rax\n"); break; } case LESSER: { if (gi.args.length < 3) { runtimeError(TOO_FEW_ARGS, "Expecting 2 args for lesser instruction", &gi, i); } if (gi.args.length > 3) { runtimeError(TOO_MANY_ARGS, "Expecting 2 args for lesser instruction", &gi, i); } if (gi.args.args[0].type != VALUE && gi.args.args[0].type != VALREF) { runtimeError(ARG_TYPE_MISMATCH, "Expecting an Int for arg 1", &gi, i); } if (gi.args.args[1].type != VALUE && gi.args.args[1].type != VALREF) { runtimeError(ARG_TYPE_MISMATCH, "Expecting an Int for arg 2", &gi, i); } if (gi.args.args[2].type != DIRREF) { runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef for arg 3", &gi, i); } char* varName= gi.args.args[2].value.refName; APPEND_ESTR(start, " ; lesser\n"); APPEND_ESTR(start, " mov rax, "); APPEND_ESTR(start, processValueString(gi.args.args[0])); APPEND_ESTR(start, "\n"); APPEND_ESTR(start, " cmp rax, "); APPEND_ESTR(start, processValueString(gi.args.args[1])); APPEND_ESTR(start, "\n"); APPEND_ESTR(start, " setl al\n"); APPEND_ESTR(start, " movzx rax, al\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); } if (gi.args.length > 1) { runtimeError(TOO_MANY_ARGS, "Expecting 1 arg for end instruction", &gi, i); } APPEND_ESTR(start, " ; end\n"); APPEND_ESTR(start, " mov rax, 60\n"); APPEND_ESTR(start, " mov rdi, "); APPEND_ESTR(start, processValueString(gi.args.args[0])); APPEND_ESTR(start, "\n"); APPEND_ESTR(start, " syscall\n"); break; } default: { printf("no\n"); exit(1); } } } 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; }