From fafd290ed990aa2bef34b44fe373175eb6133093 Mon Sep 17 00:00:00 2001 From: Tyler Murphy Date: Thu, 13 Apr 2023 17:04:05 -0400 Subject: [PATCH] brainfucked --- .gitignore | 1 + LICENSE | 13 ++++ Makefile | 39 +++++++++++ src/interpreter.c | 136 +++++++++++++++++++++++++++++++++++++ src/interpreter.h | 5 ++ src/main.c | 39 +++++++++++ src/program.c | 166 ++++++++++++++++++++++++++++++++++++++++++++++ src/program.h | 50 ++++++++++++++ 8 files changed, 449 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 src/interpreter.c create mode 100644 src/interpreter.h create mode 100644 src/main.c create mode 100644 src/program.c create mode 100644 src/program.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ba077a4 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +bin diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..541f4f7 --- /dev/null +++ b/LICENSE @@ -0,0 +1,13 @@ + DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + Version 2, December 2004 + + Copyright (C) 2004 Sam Hocevar + + Everyone is permitted to copy and distribute verbatim or modified + copies of this license document, and changing it is allowed as long + as the name is changed. + + DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. You just DO WHAT THE FUCK YOU WANT TO. \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..0e0e8e8 --- /dev/null +++ b/Makefile @@ -0,0 +1,39 @@ +CC = gcc + +INCFLAGS = -Isrc + +CCFLAGS = -std=c99 -Wall -Wextra -pedantic -O2 +CCFLAGS += $(INCFLAGS) + +LDFLAGS += $(INCFLAGS) +LDFLAGS += -lpthread + +BIN = bin +APP = $(BIN)/app +SRC = $(shell find src -name "*.c") +OBJ = $(SRC:%.c=$(BIN)/%.o) + +.PHONY: clean build + +dirs: + mkdir -p ./$(BIN) + mkdir -p ./$(BIN)/src + +run: build + $(APP) + +build: dirs ${OBJ} + ${CC} -o $(APP) $(filter %.o,$^) $(LDFLAGS) + +$(BIN)/%.o: %.c + $(CC) -o $@ -c $< $(CCFLAGS) + +clean: + rm -rf $(APP) + rm -rf $(BIN) + +install: + cp $(APP) /usr/local/bin/brainfucked + +uninstall: + rm /usr/local/bin/brainfucked diff --git a/src/interpreter.c b/src/interpreter.c new file mode 100644 index 0000000..f14abcc --- /dev/null +++ b/src/interpreter.c @@ -0,0 +1,136 @@ +#include "interpreter.h" +#include "program.h" + +#include +#include +#include +#include +#include + +static void loop_end(Program* program) { + uint32_t count = 1; + Symbol s; + + while (true) { + program_next(program, &s); + if (s == StartLoop) { + count++; + } else if (s == EndLoop) { + count--; + } else if (s == Eof) { + return; + } + + if (count == 0) return; + } +} + +static void loop_start(Program* program) { + uint32_t count = 1; + Symbol s; + + program_last(program, &s); + while (true) { + program_last(program, &s); + if (s == StartLoop) { + count--; + } else if (s == EndLoop) { + count++; + } else if (s == Eof) { + return; + } + + if (count == 0) { + return; + }; + } +} + +static void recurse_program(Program* program, Tape* tape) { + Symbol s; + +next: + program_next(program, &s); + + switch (s) { + case MoveLeft: + tape_left(tape); + break; + case MoveRight: + tape_right(tape); + break; + case Increment: + tape_set(tape, tape_get(tape) + 1); + break; + case Decrement: + tape_set(tape, tape_get(tape) - 1); + break; + case StartLoop: + if (tape_get(tape) == 0) + loop_end(program); + break; + case EndLoop: + if (tape_get(tape) != 0) + loop_start(program); + break; + case PutChar: { + printf("%c", tape_get(tape)); + break; + } + case GetChar: { + uint8_t c = (uint8_t) getchar(); + tape_set(tape, c); + break; + } + case Allocate: { + uint8_t len = tape_get(tape); + Tape* new = malloc(sizeof(Tape)); + tape_init(len, tape); + void* ptr = (void*) tape_ptr(tape); + memcpy(ptr, &new, sizeof(Tape*)); + break; + } + case Free: { + Tape* old; + void* ptr = (void*) tape_ptr(tape); + memcpy(&old, ptr, sizeof(Tape*)); + memset(ptr, 0, sizeof(Tape*)); + free(old); + break; + } + case EnterTape: { + Tape* cur; + void* ptr = (void*) tape_ptr(tape); + memcpy(&cur, ptr, sizeof(Tape*)); + recurse_program(program, cur); + break; + } + case GetString: { + uint8_t len = tape_get(tape); + void* ptr = (void*) tape_ptr(tape); + fgets(ptr, len, stdin); + break; + } + case PutString: { + char* ptr = (char*) tape_ptr(tape); + printf("%s", ptr); + break; + } + case Clear: + printf("\033c"); + break; + case LeaveTape: + case Eof: + case Invalid: + return; + } + + goto next; +} + +void run_program(Program* program) { + Tape tape; + tape_init(sizeof(void*), &tape); + recurse_program(program, &tape); + tape_free(&tape); +} diff --git a/src/interpreter.h b/src/interpreter.h new file mode 100644 index 0000000..b7c3e2a --- /dev/null +++ b/src/interpreter.h @@ -0,0 +1,5 @@ +#pragma once + +#include "program.h" + +void run_program(Program* program); diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..ac5e0f7 --- /dev/null +++ b/src/main.c @@ -0,0 +1,39 @@ +#include "program.h" +#include "interpreter.h" + +#include +#include +#include +#include +#include +#include + +/// < Move pointer left +/// > Move pointer right +/// + Increment cell by one +/// - Decrement cell by one +/// [ Jump past the matching ] if the cell at the pointer is 0 +/// ] Jump back to the matching [ if the cell at the pointer is nonzero +/// . Output ascii at current cell +/// , Input ascii into current cell +/// * Allocate new tape size of current cell and replace with pointer +/// ! Free allocated pointer in current cell +/// ( Go to tape at pointer in current cell +/// ) Leave tape last entered +/// ` Output null terminated string at current cell +/// ~ Input string into current cells with max length in current cell +/// % Clear screen + +int main(int argc, char** argv) { + if (argc != 2) { + printf("usage: brainfucked infile\n"); + return EXIT_FAILURE; + } + + Program program; + program_init(argv[1], &program); + run_program(&program); + program_free(&program); + + return EXIT_SUCCESS; +} diff --git a/src/program.c b/src/program.c new file mode 100644 index 0000000..43f6ee9 --- /dev/null +++ b/src/program.c @@ -0,0 +1,166 @@ +#include "program.h" + +#include +#include +#include +#include +#include + +static FILE* f; +static uint32_t count; + +static char next_char() { + char c; + if (fread(&c, 1, 1, f) != 1) { + return EOF; + } else { + count++; + return c; + } +} + +static Symbol next_symbol() { + char c = next_char(); +retest: + switch (c) { + case '<': + return MoveLeft; + case '>': + return MoveRight; + case '+': + return Increment; + case '-': + return Decrement; + case '[': + return StartLoop; + case ']': + return EndLoop; + case '.': + return PutChar; + case ',': + return GetChar; + case '*': + return Allocate; + case '!': + return Free; + case '(': + return EnterTape; + case ')': + return LeaveTape; + case '`': + return PutString; + case '~': + return GetString; + case '%': + return Clear; + case '\n': + case ' ': + while(c = next_char(), c == '\n' || c == ' '); + goto retest; + case '/': + while(c = next_char(), c != '\n' && c != EOF); + goto retest; + case EOF: + return Eof; + default: + return Invalid; + } +} + +void program_init(char* file_path, Program* program) { + f = fopen (file_path, "r"); + if (f == NULL) { + printf("error: failed to open %s (%s)\n", file_path, strerror(errno)); + exit(EXIT_FAILURE); + } + + uint32_t capacity = 8; + count = 0; + + program->data = malloc(capacity * sizeof(Symbol)); + program->len = 0; + + Symbol s; + while(true) { + s = next_symbol(); + + if (s == Invalid) { + printf("error: invalid symbol at character %d\n", count); + exit(EXIT_FAILURE); + } + + if (program->len == capacity) { + capacity *= 2; + program->data = realloc(program->data, capacity * sizeof(Symbol)); + } + + program->data[program->len] = s; + program->len++; + + if (s == Eof) break; + } + + fclose(f); +} + +void program_peek(Program* program, Symbol* symbol) { + *symbol = program->data[program->index]; +} + +void program_next(Program* program, Symbol* symbol) { + if (program->index >= program->len) { + *symbol = Eof; + return; + } + program_peek(program, symbol); + program->index++; +} + +void program_last(Program* program, Symbol* symbol) { + if (program->index == 0) { + *symbol = Eof; + return; + } + program->index--; + program_peek(program, symbol); +} + +void program_free(Program* program) { + free(program->data); +} + +void tape_init(uint32_t len, Tape* tape) { + tape->len = len; + tape->data = malloc(len); + tape->index = 0; + memset(tape->data, 0, len); +} + +void tape_left(Tape* tape) { + if (tape->index == 0) { + tape->index = tape->len - 1; + } else { + tape->index--; + } +} + +void tape_right(Tape* tape) { + tape->index++; + tape->index %= tape->len; +} + +uint8_t tape_get(Tape* tape) { + return tape->data[tape->index]; +} + +void tape_set(Tape* tape, uint8_t value) { + tape->data[tape->index] = value; +} + +uint8_t* tape_ptr(Tape* tape) { + return tape->data; +} + +void tape_free(Tape* tape) { + free(tape->data); +} diff --git a/src/program.h b/src/program.h new file mode 100644 index 0000000..7b40712 --- /dev/null +++ b/src/program.h @@ -0,0 +1,50 @@ +#pragma once + +#include +#include + +typedef enum { + MoveLeft, + MoveRight, + Increment, + Decrement, + StartLoop, + EndLoop, + PutChar, + GetChar, + Allocate, + Free, + EnterTape, + LeaveTape, + PutString, + GetString, + Clear, + Eof, + Invalid +} Symbol; + +typedef struct { + uint32_t len; + uint32_t index; + Symbol* data; +} Program; + +void program_init(char* file_path, Program* program); +void program_peek(Program* program, Symbol* symbol); +void program_next(Program* program, Symbol* symbol); +void program_last(Program* program, Symbol* symbol); +void program_free(Program* program); + +typedef struct { + uint32_t len; + uint32_t index; + uint8_t* data; +} Tape; + +void tape_init(uint32_t len, Tape* tape); +void tape_left(Tape* tape); +void tape_right(Tape* tape); +uint8_t tape_get(Tape* tape); +void tape_set(Tape* tape, uint8_t value); +uint8_t* tape_ptr(Tape* tape); +void tape_free(Tape* tape);