aboutsummaryrefslogtreecommitdiff
path: root/src/compiler/code_generator/code_generator.c
diff options
context:
space:
mode:
authorA404M <ahmadmahmoudiprogrammer@gmail.com>2024-09-18 19:46:38 +0330
committerA404M <ahmadmahmoudiprogrammer@gmail.com>2024-09-18 19:57:20 +0330
commitd6ba30b94a24607bce5db5e706eb20cc051a98f0 (patch)
tree146e74b0bc2e1636451257015210e3c7d1a0ecab /src/compiler/code_generator/code_generator.c
initial commit
Diffstat (limited to 'src/compiler/code_generator/code_generator.c')
-rw-r--r--src/compiler/code_generator/code_generator.c199
1 files changed, 199 insertions, 0 deletions
diff --git a/src/compiler/code_generator/code_generator.c b/src/compiler/code_generator/code_generator.c
new file mode 100644
index 0000000..0beca33
--- /dev/null
+++ b/src/compiler/code_generator/code_generator.c
@@ -0,0 +1,199 @@
+#include "code_generator.h"
+
+#include <compiler/parser/parser.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "utils/memory/memory.h"
+#include "utils/types.h"
+
+const char *COMMAND_STRINGS[] = {
+ "COMMAND_NONE",
+ "COMMAND_PRINT",
+ "COMMAND_PUSH_STRING",
+};
+
+void printInstruction(Instruction instruction) {
+ printf("%s", COMMAND_STRINGS[instruction.command]);
+ switch (instruction.command) {
+ case COMMAND_NONE:
+ case COMMAND_PRINT:
+ break;
+ case COMMAND_PUSH_STRING:
+ SizedString *sizedString = instruction.operand;
+ printf(" '%.*s'", (int)sizedString->size, sizedString->str);
+ break;
+ default:
+ fprintf(stderr, "bad instruction %d\n", instruction.command);
+ }
+ printf("\n");
+}
+
+void printInstructions(Instructions instructions) {
+ for (size_t i = 0; i < instructions.size; ++i) {
+ printInstruction(instructions.instructions[i]);
+ }
+}
+
+void deleteInstruction(Instruction instruction) {
+ switch (instruction.command) {
+ case COMMAND_NONE:
+ case COMMAND_PRINT:
+ break;
+ case COMMAND_PUSH_STRING:
+ SizedString *sizedString = instruction.operand;
+ free(sizedString->str);
+ free(sizedString);
+ break;
+ default:
+ fprintf(stderr, "bad instruction %d\n", instruction.command);
+ }
+}
+
+void deleteInstructions(Instructions instructions) {
+ for (size_t i = 0; i < instructions.size; ++i) {
+ deleteInstruction(instructions.instructions[i]);
+ }
+ free(instructions.instructions);
+}
+
+Instructions codeGenerator(ParsedNode *root) {
+ const ScopeMetadata *metadata = root->metadata;
+
+ size_t instructions_size = 10;
+ Instruction *instructions =
+ a404m_malloc(instructions_size * sizeof(Instruction));
+ size_t instructions_inserted = 0;
+
+ for (size_t i = 0; i < metadata->operands_size; ++i) {
+ ParsedNode *node = metadata->operands[i];
+ if (!nodeToInstruction(node, &instructions, &instructions_size,
+ &instructions_inserted)) {
+ goto RETURN_ERROR;
+ }
+ }
+
+ Instructions result = {
+ .instructions = a404m_realloc(
+ instructions, instructions_inserted * sizeof(Instruction)),
+ .size = instructions_inserted,
+ };
+ return result;
+
+RETURN_ERROR:
+ const Instructions error = {
+ .instructions = NULL,
+ .size = ERROR_SIZE,
+ };
+ return error;
+}
+
+bool nodeToInstruction(ParsedNode *node, Instruction **instructions,
+ size_t *instructions_size,
+ size_t *instructions_inserted) {
+ switch (node->token) {
+ // TODO: this is wrong when you want functions
+ case PARSED_TOKEN_PARENTHESIS: {
+ const ScopeMetadata *metadata = node->metadata;
+ for (size_t i = 0; i < metadata->operands_size; ++i) {
+ if (!nodeToInstruction(metadata->operands[i], instructions,
+ instructions_size, instructions_inserted)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ case PARSED_TOKEN_EOL:
+ return nodeToInstruction(node->metadata, instructions, instructions_size,
+ instructions_inserted);
+ break;
+ case PARSED_TOKEN_PRINT:
+ if (nodeToInstruction(node->metadata, instructions, instructions_size,
+ instructions_inserted)) {
+ const Instruction instruction = {
+ .command = COMMAND_PRINT,
+ .operand = NULL,
+ };
+ insertInstruction(instruction, instructions, instructions_size,
+ instructions_inserted);
+ return true;
+ } else {
+ return false;
+ }
+ break;
+ case PARSED_TOKEN_VALUE_STRING: {
+ SizedString *string = nodeToString(node);
+ if (string == NULL) {
+ return false;
+ }
+ const Instruction instruction = {
+ .command = COMMAND_PUSH_STRING,
+ .operand = string,
+ };
+ insertInstruction(instruction, instructions, instructions_size,
+ instructions_inserted);
+ return true;
+ }
+ default:
+ fprintf(stderr, "unexpected token %s\n",
+ PARSED_TOKEN_STRINGS[node->token]);
+ return false;
+ }
+}
+
+void insertInstruction(const Instruction instruction,
+ Instruction **restrict instructions,
+ size_t *restrict instructions_size,
+ size_t *restrict instructions_inserted) {
+ if (*instructions_inserted == *instructions_size) {
+ *instructions_size += *instructions_size / 2 + 1;
+ *instructions =
+ a404m_realloc(*instructions, *instructions_size * sizeof(Instruction));
+ }
+ (*instructions)[*instructions_inserted] = instruction;
+ ++*instructions_inserted;
+}
+
+SizedString *nodeToString(ParsedNode const *node) {
+ const char *strBegin = node->strBegin + 1;
+ const char *strEnd = node->strEnd - 1;
+
+ char *str = a404m_malloc((strEnd - strBegin + 1) * sizeof(char));
+ size_t inserted = 0;
+
+ for (char const *iter = strBegin; iter < strEnd; ++iter) {
+ char c = *iter;
+ if (c == '\\') {
+ if (++iter < strEnd) {
+ switch (*iter) {
+ case '\'':
+ c = '\'';
+ break;
+ case '\"':
+ c = '\"';
+ break;
+ case 'n':
+ c = '\n';
+ break;
+ default:
+ fprintf(stderr, "bad string, bad '\\'\n");
+ goto RETURN_ERROR;
+ }
+ } else {
+ fprintf(stderr, "bad string, bad '\\'\n");
+ goto RETURN_ERROR;
+ }
+ }
+ str[inserted] = c;
+ ++inserted;
+ }
+
+ str[inserted] = '\0';
+ SizedString *string = a404m_malloc(sizeof(SizedString));
+ string->str = a404m_realloc(str, (inserted + 1) * sizeof(char));
+ string->size = inserted;
+ return string;
+RETURN_ERROR:
+ free(str);
+ return NULL;
+}