From 2e454a5cdbc0b95fe5420e5222d80fb1be45b94e Mon Sep 17 00:00:00 2001 From: Rokas Puzonas Date: Sun, 14 Jul 2024 13:32:05 +0300 Subject: [PATCH] initial commit --- .gitignore | 2 + build.zig | 26 +++++++ src/bf_emulator.c | 169 ++++++++++++++++++++++++++++++++++++++++++++++ src/main.c | 57 ++++++++++++++++ 4 files changed, 254 insertions(+) create mode 100644 .gitignore create mode 100644 build.zig create mode 100644 src/bf_emulator.c create mode 100644 src/main.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4c82b07 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +zig-cache +zig-out diff --git a/build.zig b/build.zig new file mode 100644 index 0000000..2567c8f --- /dev/null +++ b/build.zig @@ -0,0 +1,26 @@ +const std = @import("std"); +const Build = std.Build; + +pub fn build(b: *Build) !void { + const target = b.standardTargetOptions(.{}); + const optimize = b.standardOptimizeOption(.{}); + + const exe = b.addExecutable(.{ + .name = "brainfuck", + .optimize = optimize, + .target = target + }); + exe.addIncludePath(.{ .path = "src" }); + exe.addCSourceFile(.{ .file = b.path("src/main.c") }); + exe.linkLibC(); + + b.installArtifact(exe); + + const run_exe = b.addRunArtifact(exe); + if (b.args) |args| { + run_exe.addArgs(args); + } + + const run_step = b.step("run", "Run program"); + run_step.dependOn(&run_exe.step); +} diff --git a/src/bf_emulator.c b/src/bf_emulator.c new file mode 100644 index 0000000..b15f54f --- /dev/null +++ b/src/bf_emulator.c @@ -0,0 +1,169 @@ +#include +#include +#include +#include +#include +#include + +enum bf_step_result { + BF_STEP_OK, + BF_STEP_FINISHED, + BF_STEP_ERROR, +}; + +struct bf_emulator { + uint32_t data_pointer; + + void *data; + uint32_t data_len; + uint32_t cell_size; + + const char *program; + size_t program_len; + size_t program_pointer; +}; + +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); +} diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..f659eab --- /dev/null +++ b/src/main.c @@ -0,0 +1,57 @@ +#include +#include +#include +#include +#include + +#include "bf_emulator.c" + +uint64_t get_file_size(const char *filename) { + struct stat result; + stat(filename, &result); + return result.st_size; +} + +int main(int argc, const char **argv) { + if (argc < 2) { + printf("Usage: %s \n", argv[0]); + return 1; + } + + const char *filename = argv[1]; + size_t program_len = get_file_size(filename); + char *program = calloc(program_len, sizeof(uint8_t)); + assert(program != NULL); + + { // Read program from file + FILE *f = fopen(filename, "r"); + if (f == NULL) { + printf("ERROR: Failed to open file\n"); + return 2; + } + + uint32_t read_amount = 0; + while (read_amount < program_len) { + int result = fread(program + read_amount, 1, program_len - read_amount, f); + if (result <= 0) { + printf("ERROR: Failed to read everything from file\n"); + return 3; + } + read_amount += result; + } + + fclose(f); + } + + struct bf_emulator emulator = { 0 }; + bf_emulator_init(&emulator, 16, 4096); + + enum bf_step_result result = bf_emulator_run(&emulator, program, program_len); + if (result == BF_STEP_ERROR) { + printf("Error occured while running program\n"); + return -1; + } + + bf_emulator_deinit(&emulator); + return 0; +}