initial commit
This commit is contained in:
commit
2e454a5cdb
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
zig-cache
|
||||
zig-out
|
26
build.zig
Normal file
26
build.zig
Normal 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
169
src/bf_emulator.c
Normal 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
57
src/main.c
Normal 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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user