summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTyler Murphy <tylerm@tylerm.dev>2023-04-13 17:04:05 -0400
committerTyler Murphy <tylerm@tylerm.dev>2023-04-13 17:04:05 -0400
commitfafd290ed990aa2bef34b44fe373175eb6133093 (patch)
tree5d4848b3006bc4eec5d5f49d6372516e1a2a0ba3
downloadbrainfucked-fafd290ed990aa2bef34b44fe373175eb6133093.tar.gz
brainfucked-fafd290ed990aa2bef34b44fe373175eb6133093.tar.bz2
brainfucked-fafd290ed990aa2bef34b44fe373175eb6133093.zip
brainfucked
-rw-r--r--.gitignore1
-rw-r--r--LICENSE13
-rw-r--r--Makefile39
-rw-r--r--src/interpreter.c136
-rw-r--r--src/interpreter.h5
-rw-r--r--src/main.c39
-rw-r--r--src/program.c166
-rw-r--r--src/program.h50
8 files changed, 449 insertions, 0 deletions
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 <sam@hocevar.net>
+
+ 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 <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+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 <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+
+/// < 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 <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+
+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 <stdbool.h>
+#include <stdint.h>
+
+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);