initial commit

This commit is contained in:
Rokas Puzonas 2024-07-14 13:32:05 +03:00
commit 2e454a5cdb
4 changed files with 254 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
zig-cache
zig-out

26
build.zig Normal file
View File

@ -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);
}

169
src/bf_emulator.c Normal file
View File

@ -0,0 +1,169 @@
#include <inttypes.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
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);
}

57
src/main.c Normal file
View File

@ -0,0 +1,57 @@
#include <assert.h>
#include <stdio.h>
#include <inttypes.h>
#include <stdlib.h>
#include <sys/stat.h>
#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 <filename>\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;
}