#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); 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; } 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; } case PARSED_TOKEN_NONE: case PARSED_TOKEN_ROOT: } 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; }