From d6ba30b94a24607bce5db5e706eb20cc051a98f0 Mon Sep 17 00:00:00 2001 From: A404M Date: Wed, 18 Sep 2024 19:46:38 +0330 Subject: initial commit --- src/compiler/code_generator/code_generator.c | 199 +++++++++++++++++++++++++++ src/compiler/code_generator/code_generator.h | 41 ++++++ 2 files changed, 240 insertions(+) create mode 100644 src/compiler/code_generator/code_generator.c create mode 100644 src/compiler/code_generator/code_generator.h (limited to 'src/compiler/code_generator') 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 +#include +#include + +#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; +} diff --git a/src/compiler/code_generator/code_generator.h b/src/compiler/code_generator/code_generator.h new file mode 100644 index 0000000..1a9b4ff --- /dev/null +++ b/src/compiler/code_generator/code_generator.h @@ -0,0 +1,41 @@ +#pragma once + +#include + +#include "compiler/parser/parser.h" +typedef enum Command { + COMMAND_NONE = 0, + COMMAND_PRINT, + COMMAND_PUSH_STRING, +} Command; + +extern const char *COMMAND_STRINGS[]; + +typedef struct Instruction { + Command command; + void *operand; +} Instruction; + +typedef struct Instructions { + Instruction *restrict instructions; + size_t size; +} Instructions; + +extern void printInstruction(Instruction instruction); +extern void printInstructions(Instructions instructions); + +extern void deleteInstruction(Instruction instruction); +extern void deleteInstructions(Instructions instructions); + +extern Instructions codeGenerator(ParsedNode *root); + +extern bool nodeToInstruction(ParsedNode *node, Instruction **instructions, + size_t *instructions_size, + size_t *instructions_inserted); + +extern void insertInstruction(const Instruction instruction, + Instruction **restrict instructions, + size_t *restrict instructions_size, + size_t *restrict instructions_inserted); + +extern SizedString *nodeToString(ParsedNode const *node); -- cgit v1.2.3