#include "code_generator.h" #include #include #include #include #include #include #include "compiler/tree_parser/tree_parser.h" const char *COMMAND_STRINGS[] = { "COMMAND_NONE", "COMMAND_CALL_FUNCTION", "COMMAND_PUSH_STRING", }; void printInstruction(Instruction instruction) { printf("%s", COMMAND_STRINGS[instruction.command]); switch (instruction.command) { case COMMAND_NONE: printf("\n"); return; case COMMAND_CALL_FUNCTION: case COMMAND_PUSH_STRING: case COMMAND_POP_IDENTIFIER: case COMMAND_PUSH_IDENTIFIER: SizedString *sizedString = instruction.operand; printf(" '%.*s'\n", (int)sizedString->size, sizedString->str); return; } fprintf(stderr, "bad instruction %d\n", instruction.command); } 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: return; case COMMAND_PUSH_STRING: case COMMAND_CALL_FUNCTION: case COMMAND_PUSH_IDENTIFIER: case COMMAND_POP_IDENTIFIER: SizedString *sizedString = instruction.operand; free(sizedString->str); free(sizedString); return; } 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(SourceCode *code) { ParsedTree *root = treeParser(code); if (root != NULL) { Instructions instructions = _codeGenerator(root, code); deleteParsedTree(root); return instructions; } const Instructions error = { .instructions = NULL, .size = ERROR_SIZE, }; return error; } Instructions codeGeneratorWithPrint(SourceCode *code) { ParsedTree *root = treeParserWithPrint(code); if (root != NULL) { printf("----tree parsed:\n"); printParsedTreeNode(root); Instructions instructions = _codeGenerator(root, code); deleteParsedTree(root); return instructions; } fprintf(stderr, "error in tree parser\n"); const Instructions error = { .instructions = NULL, .size = ERROR_SIZE, }; return error; } Instructions _codeGenerator(ParsedTree *root, SourceCode *code) { const TreeScopeMetadata *metadata = root->metadata; size_t instructions_size = 10; Instruction *instructions = a404m_malloc(instructions_size * sizeof(*instructions)); size_t instructions_inserted = 0; for (size_t i = 0; i < metadata->lines_size; ++i) { ParsedTree *node = metadata->lines[i]; if (!nodeToInstruction(node, &instructions, &instructions_size, &instructions_inserted, code)) { goto RETURN_ERROR; } } Instructions result = { .instructions = a404m_realloc( instructions, instructions_inserted * sizeof(*instructions)), .size = instructions_inserted, }; return result; RETURN_ERROR: free(instructions); const Instructions error = { .instructions = NULL, .size = ERROR_SIZE, }; return error; } bool nodeToInstruction(ParsedTree *tree, Instruction **instructions, size_t *instructions_size, size_t *instructions_inserted, SourceCode *code) { /*printf("Parsing token = %s\n", TREE_TOKEN_STRINGS[tree->token]);*/ switch (tree->token) { case TREE_TOKEN_FUNCTION_CALL: { const TreeFunctionCallMetadata *tree_metadata = tree->metadata; for (size_t i = 0; i < tree_metadata->values_size; ++i) { if (!nodeToInstruction(tree_metadata->values[i], instructions, instructions_size, instructions_inserted, code)) { return false; } } CommandCallFunctionOperand *operand = a404m_malloc(sizeof(*operand)); operand->size = tree_metadata->function->nameEnd - tree_metadata->function->nameBegin; operand->str = a404m_malloc((operand->size + 1) * sizeof(char)); strncpy(operand->str, tree_metadata->function->nameBegin, operand->size); const Instruction instruction = { .command = COMMAND_CALL_FUNCTION, .operand = operand, }; insertInstruction(instruction, instructions, instructions_size, instructions_inserted); return true; } case TREE_TOKEN_IDENTIFIER: { const TreeIdentifierMetadata *tree_metadata = tree->metadata; CommandPushIdentifierOperand *operand = a404m_malloc(sizeof(*operand)); operand->size = tree_metadata->variable->nameEnd - tree_metadata->variable->nameBegin; operand->str = a404m_malloc((operand->size + 1) * sizeof(char)); strncpy(operand->str, tree_metadata->variable->nameBegin, operand->size * sizeof(char)); const Instruction instruction = { .command = COMMAND_PUSH_IDENTIFIER, .operand = operand, }; insertInstruction(instruction, instructions, instructions_size, instructions_inserted); return true; } case TREE_TOKEN_VALUE_STRING: { const TreeStringValueMetadata *tree_metadata = tree->metadata; CommandPushStringOperand *operand = a404m_malloc(sizeof(*operand)); operand->size = tree_metadata->size; operand->str = a404m_malloc((operand->size + 1) * sizeof(char)); memcpy(operand->str, tree_metadata->str, (operand->size + 1) * sizeof(char)); const Instruction instruction = { .command = COMMAND_PUSH_STRING, .operand = operand, }; insertInstruction(instruction, instructions, instructions_size, instructions_inserted); return true; } case TREE_TOKEN_DEFINE_VARIABLE: { const TreeDefineVariableMetadata *tree_metadata = tree->metadata; if (tree_metadata->value == NULL) { return true; } else if (!nodeToInstruction(tree_metadata->value, instructions, instructions_size, instructions_inserted, code)) { return false; } CommandPopIdentifierOperand *operand = a404m_malloc(sizeof(*operand)); operand->size = tree_metadata->nameEnd - tree_metadata->nameBegin; operand->str = a404m_malloc((operand->size + 1) * sizeof(char)); strncpy(operand->str, tree_metadata->nameBegin, operand->size); const Instruction instruction = { .command = COMMAND_POP_IDENTIFIER, .operand = operand, }; insertInstruction(instruction, instructions, instructions_size, instructions_inserted); return true; } case TREE_TOKEN_DEFINE_CONSTANT: return true; case TREE_TOKEN_GLOBAL_SCOPE: case TREE_TOKEN_LOCAL_SCOPE: case TREE_TOKEN_STRUCT: case TREE_TOKEN_FUNCTION: case TREE_TOKEN_NONE: case TREE_TOKEN_ROOT: } printError("Unhandled token %s\n", code, tree->strBegin, tree->strEnd, TREE_TOKEN_STRINGS[tree->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; }