#include "bf_emulator.h" #include #include #include #include void bf_emulator_init(struct bf_emulator *emulator, uint32_t cell_size, uint32_t data_len) { assert(cell_size == 8 || cell_size == 16 || cell_size == 32); emulator->cell_size = cell_size; emulator->data = calloc(data_len, cell_size / 8); emulator->data_len = data_len; } void bf_emulator_deinit(struct bf_emulator *emulator) { free(emulator->data); emulator->data = NULL; emulator->data_len = 0; } static void bf_emulator_set(struct bf_emulator *emulator, uint32_t index, uint32_t value) { if (emulator->cell_size == 8) { ((uint8_t*)emulator->data)[index] = value; } else if (emulator->cell_size == 16) { ((uint16_t*)emulator->data)[index] = value; } else if (emulator->cell_size == 32) { ((uint32_t*)emulator->data)[index] = value; } } static uint32_t bf_emulator_get(struct bf_emulator *emulator, uint32_t index) { if (emulator->cell_size == 8) { return ((uint8_t*)emulator->data)[index]; } else if (emulator->cell_size == 16) { return ((uint16_t*)emulator->data)[index]; } else if (emulator->cell_size == 32) { return ((uint32_t*)emulator->data)[index]; } return 0; } static void bf_emulator_inc(struct bf_emulator *emulator, uint32_t index) { bf_emulator_set(emulator, index, bf_emulator_get(emulator, index) + 1); } static void bf_emulator_dec(struct bf_emulator *emulator, uint32_t index) { bf_emulator_set(emulator, index, bf_emulator_get(emulator, index) - 1); } enum bf_step_result bf_emulator_step(struct bf_emulator *emulator) { if (emulator->program_pointer == emulator->program_len) { return BF_STEP_FINISHED; } char inst = emulator->program[emulator->program_pointer]; switch (inst) { case '>': emulator->data_pointer = (emulator->data_pointer + 1) % emulator->data_len; break; case '<': emulator->data_pointer = (emulator->data_pointer - 1 + emulator->data_len) % emulator->data_len; break; case '-': bf_emulator_dec(emulator, emulator->data_pointer); break; case '+': bf_emulator_inc(emulator, emulator->data_pointer); break; case '.': putchar(bf_emulator_get(emulator, emulator->data_pointer)); break; case ',': bf_emulator_set(emulator, emulator->data_pointer, getchar()); break; case '[': if (bf_emulator_get(emulator, emulator->data_pointer) == 0) { uint32_t open_blocks = 0; while (true) { emulator->program_pointer++; if (emulator->program_pointer == emulator->program_len) { return BF_STEP_ERROR; } if (emulator->program[emulator->program_pointer] == '[') { open_blocks++; } if (emulator->program[emulator->program_pointer] == ']') { if (open_blocks == 0) break; open_blocks--; } } } break; case ']': if (bf_emulator_get(emulator, emulator->data_pointer) != 0) { uint32_t closing_blocks = 0; while (true) { if (emulator->program_pointer == 0) { return BF_STEP_ERROR; } emulator->program_pointer--; if (emulator->program[emulator->program_pointer] == ']') { closing_blocks++; } if (emulator->program[emulator->program_pointer] == '[') { if (closing_blocks == 0) break; closing_blocks--; } } } break; default: break; }; emulator->program_pointer++; return BF_STEP_OK; } enum bf_step_result bf_emulator_continue(struct bf_emulator *emulator) { while (true) { enum bf_step_result result = bf_emulator_step(emulator); if (result != BF_STEP_OK) { return result; } } } enum bf_step_result bf_emulator_run(struct bf_emulator *emulator, const char *program, size_t program_len) { emulator->data_pointer = 0; memset(emulator->data, 0, emulator->data_len); emulator->program = program; emulator->program_len = program_len; emulator->program_pointer = 0; return bf_emulator_continue(emulator); }