#include "runner.h" #include #include #include #include #include #include const BuiltinFunction BUILTIN_FUNCTIONS[] = { print, }; const char *BUILTIN_FUNCTION_NAMES[] = { "print", }; const size_t BUILTIN_FUNCTIONS_SIZE = sizeof(BUILTIN_FUNCTIONS) / sizeof(BuiltinFunction); bool runner(SourceCode *sourceCode) { Instructions instructions = codeGenerator(sourceCode); if (instructions.size != ERROR_SIZE) { bool ranSuccess = _runner(instructions); deleteInstructions(instructions); return ranSuccess; } return false; } bool _runner(Instructions instructions) { size_t stack_size = 0; void **stack = a404m_malloc(stack_size * sizeof(void *)); size_t stack_inserted = 0; size_t variables_size = 0; RunnerVariable **variables = a404m_malloc(variables_size * sizeof(RunnerVariable *)); size_t variables_inserted = 0; for (size_t i = 0; i < instructions.size; ++i) { if (!runInstruction(instructions.instructions[i], &stack, &stack_size, &stack_inserted, &variables, &variables_size, &variables_inserted)) { goto RETURN_ERROR; } } for (size_t i = 0; i < variables_inserted; ++i) { free(variables[i]); } free(variables); free(stack); return true; RETURN_ERROR: free(stack); return false; } BuiltinFunction getBuiltinFunction(SizedString string) { for (size_t i = 0; i < BUILTIN_FUNCTIONS_SIZE; ++i) { const char *search = BUILTIN_FUNCTION_NAMES[i]; // faster than strlen+strncmp for (size_t j = 0;; ++j) { const char searchChar = search[j]; if (j == string.size) { if (searchChar == '\0') { return BUILTIN_FUNCTIONS[i]; } else { break; } } else if (searchChar == '\0') { break; } else if (searchChar != string.str[j]) { break; } } } return NULL; } bool runInstruction(Instruction instruction, void ***restrict stack, size_t *restrict stack_size, size_t *restrict stack_inserted, RunnerVariable ***restrict variables, size_t *restrict variables_size, size_t *restrict variables_inserted) { switch (instruction.command) { case COMMAND_PUSH_IDENTIFIER: { const CommandPushIdentifierOperand *operand = instruction.operand; pushToStack( getRunnerVariable(operand, variables, variables_inserted)->value, stack, stack_size, stack_inserted); return true; } case COMMAND_PUSH_STRING: { CommandPushStringOperand *operand = instruction.operand; pushToStack(operand, stack, stack_size, stack_inserted); return true; } case COMMAND_CALL_FUNCTION: { SizedString *functionName = instruction.operand; const BuiltinFunction function = getBuiltinFunction(*functionName); if (function == NULL) { fprintf(stderr, "function '%.*s' not found\n", (int)functionName->size, functionName->str); return false; } function(stack, stack_inserted); return true; } case COMMAND_POP_IDENTIFIER: { const CommandPopIdentifierOperand *operand = instruction.operand; setRunnerVariable(popFromStack(stack, stack_inserted), operand, variables, variables_size, variables_inserted); return true; } case COMMAND_NONE: } fprintf(stderr, "bad command '%d'\n", instruction.command); return false; } RunnerVariable *getRunnerVariable(const SizedString *varName, RunnerVariable ***restrict variables, size_t *restrict variables_inserted) { for (size_t i = *variables_inserted - 1; i != (typeof(i))-1; --i) { RunnerVariable *variable = (*variables)[i]; if (variable->name->size == varName->size && strncmp(varName->str, variable->name->str, varName->size) == 0) { return variable; } } return NULL; } void setRunnerVariable(void *value, const SizedString *varName, RunnerVariable ***restrict variables, size_t *restrict variables_size, size_t *restrict variables_inserted) { RunnerVariable *variable = getRunnerVariable(varName, variables, variables_inserted); if (variable != NULL) { variable->value = value; return; } variable = a404m_malloc(sizeof(*variable)); variable->name = varName; variable->value = value; if (*variables_inserted == *variables_size) { *variables_size += *variables_size / 2 + 1; *variables = a404m_realloc(*variables, *variables_size * sizeof(RunnerVariable *)); } (*variables)[*variables_inserted] = variable; *variables_inserted += 1; } void *popFromStack(void ***restrict stack, size_t *restrict stack_inserted) { if (*stack_inserted == 0) { fprintf(stderr, "stack underflow\n"); exit(1); } return (*stack)[--*stack_inserted]; } void pushToStack(void *value, void ***restrict stack, size_t *restrict stack_size, size_t *restrict stack_inserted) { if (*stack_inserted == *stack_size) { *stack_size += *stack_size / 2 + 1; *stack = a404m_realloc(*stack, *stack_size * sizeof(void *)); } (*stack)[*stack_inserted] = value; ++*stack_inserted; } void print(void ***restrict stack, size_t *restrict stack_inserted) { const SizedString *string = popFromStack(stack, stack_inserted); fwrite(string->str, string->size, 1, stdout); }