diff options
Diffstat (limited to 'src/compiler/code-generator.c')
-rw-r--r-- | src/compiler/code-generator.c | 192 |
1 files changed, 192 insertions, 0 deletions
diff --git a/src/compiler/code-generator.c b/src/compiler/code-generator.c new file mode 100644 index 0000000..0de098c --- /dev/null +++ b/src/compiler/code-generator.c @@ -0,0 +1,192 @@ +#include "code-generator.h" +#include "compiler/ast-tree.h" +#include "utils/log.h" +#include "utils/memory.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +CodeGeneratorCode createGenerateCode(char *label_begin, char *label_end, + CodeGeneratorInstruction instruction) { + CodeGeneratorCode code = { + .label_begin = label_begin, + .label_end = label_end, + .instruction = instruction, + }; + return code; +} + +CodeGeneratorCode *newGenerateCode(char *label_begin, char *label_end, + CodeGeneratorInstruction instruction) { + CodeGeneratorCode *result = a404m_malloc(sizeof(*result)); + result->label_begin = label_begin; + result->label_end = label_end; + result->instruction = instruction; + return result; +} + +void generateCodePushCode(CodeGeneratorCodes *codes, CodeGeneratorCode code) { + size_t codes_size = + a404m_malloc_usable_size(codes->codes) / sizeof(*codes->codes); + if (codes_size == codes->codes_size) { + codes_size += codes_size / 2 + 1; + codes->codes = + a404m_realloc(codes->codes, codes_size * sizeof(*codes->codes)); + } + codes->codes[codes->codes_size] = code; + codes->codes_size += 1; +} + +CodeGeneratorCodes *codeGenerator(AstTreeRoot *astTreeRoot) { + CodeGeneratorCodes *codes = a404m_malloc(sizeof(*codes)); + + codes->codes = a404m_malloc(0); + codes->codes_size = 0; + + for (size_t i = 0; i < astTreeRoot->variables.size; ++i) { + AstTreeVariable *variable = astTreeRoot->variables.data[i]; + switch (variable->value->token) { + case AST_TREE_TOKEN_FUNCTION: + codeGeneratorAstTreeFunction(variable->name_begin, variable->name_end, + *variable->value, codes); + continue; + case AST_TREE_TOKEN_KEYWORD_PRINT: + generateCodePushCode( + codes, + createGenerateCode(NULL, NULL, CODE_GENERATOR_INSTRUCTION_PRINT)); + continue; + case AST_TREE_TOKEN_NONE: + } + printLog("Bad token %d", variable->value->token); + } + + return codes; +} + +bool codeGeneratorAstTreeFunction(char *label_begin, char *label_end, + AstTree astTree, CodeGeneratorCodes *codes) { + AstTreeScope *scope = astTree.metadata; + + for (size_t i = 0; i < scope->expressions_size; ++i) { + AstTree tree = scope->expressions[i]; + switch (tree.token) { + case AST_TREE_TOKEN_KEYWORD_PRINT: + generateCodePushCode( + codes, createGenerateCode(label_begin, label_end, + CODE_GENERATOR_INSTRUCTION_PRINT)); + goto OK; + case AST_TREE_TOKEN_FUNCTION: + case AST_TREE_TOKEN_NONE: + } + printLog("Bad token %d", tree.token); + return false; + OK: + label_begin = NULL; + label_end = NULL; + } + + generateCodePushCode(codes, + createGenerateCode(label_begin, label_end, + CODE_GENERATOR_INSTRUCTION_RET)); + + return true; +} + +static const char TEMPLATE[] = + "format ELF64 executable 3\nSYS_exit = 60\nSYS_write = 1\nSTDOUT = " + "1\nsegment readable writable\nhello: db \"Hello, " + "World!\",0xa\nhello_len = $-hello\nsegment readable executable\nentry " + "_start\nprint:\nmov rax, SYS_write\nmov rdi, STDOUT\nmov rsi, " + "hello\nmov rdx, hello_len\nsyscall\nret\n_start:\ncall main\nmov rax, " + "SYS_exit\nxor " + "rdi,rdi\nsyscall\n"; +static const size_t TEMPLATE_LEN = + sizeof(TEMPLATE) / sizeof(*TEMPLATE) - sizeof(*TEMPLATE); + +static void codeGeneratorAppendFlatASMCommand(char **fasm, size_t *fasm_size, + size_t *fasm_inserted, + const char *str, size_t str_len) { + size_t inserted_last = *fasm_inserted; + *fasm_inserted += str_len; + if (*fasm_inserted + 1 >= *fasm_size) { + *fasm_size = *fasm_inserted + *fasm_inserted / 2 + 1; + *fasm = a404m_realloc(*fasm, *fasm_size * sizeof(*fasm)); + } + strncpy(*fasm + inserted_last, str, str_len); +} + +char *codeGeneratorToFlatASM(const CodeGeneratorCodes *codes) { + size_t fasm_size = TEMPLATE_LEN + 1; + char *fasm = a404m_malloc(fasm_size * sizeof(*fasm)); + size_t fasm_inserted = 0; + fasm[0] = '\0'; + + codeGeneratorAppendFlatASMCommand(&fasm, &fasm_size, &fasm_inserted, TEMPLATE, + TEMPLATE_LEN); + + for (size_t i = 0; i < codes->codes_size; ++i) { + const CodeGeneratorCode code = codes->codes[i]; + if (code.label_begin != code.label_end) { + codeGeneratorAppendFlatASMCommand(&fasm, &fasm_size, &fasm_inserted, + code.label_begin, + code.label_end - code.label_begin); + + codeGeneratorAppendFlatASMCommand(&fasm, &fasm_size, &fasm_inserted, + ":\n", 2); + } + + switch (code.instruction) { + case CODE_GENERATOR_INSTRUCTION_PRINT: { + constexpr char INST[] = "call print\n"; + codeGeneratorAppendFlatASMCommand(&fasm, &fasm_size, &fasm_inserted, INST, + strlen(INST)); + } + continue; + case CODE_GENERATOR_INSTRUCTION_RET: { + constexpr char INST[] = "ret\n"; + codeGeneratorAppendFlatASMCommand(&fasm, &fasm_size, &fasm_inserted, INST, + strlen(INST)); + } + continue; + } + printLog("Bad instruction %d", code.instruction); + } + + fasm[fasm_inserted] = '\0'; + return fasm; +} + +bool codeGeneratorFlatASMExec(const char *filePath, const char *fasm) { + const size_t filePathLen = strlen(filePath); + char *asmFilePath = a404m_malloc((filePathLen + 4 + 1) * sizeof(char)); + strncpy(asmFilePath, filePath, filePathLen); + strcpy(asmFilePath + filePathLen, ".asm"); + + FILE *file = fopen(asmFilePath, "w"); + + if (file == NULL) { + return false; + } + + fwrite(fasm, sizeof(*fasm), strlen(fasm), file); + + fclose(file); + + char *command; + asprintf(&command, "fasm -m 102400 \"%s\" \"%s\"", asmFilePath, filePath); + + if (system(command) != 0) { + free(command); + return false; + } + free(command); + + asprintf(&command, "chmod + \"%s\"", filePath); + + if (system(command) != 0) { + free(command); + return false; + } + + return true; +} |