summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Jones <admin@danieljon.es>2020-11-19 23:49:25 +1030
committerDaniel Jones <admin@danieljon.es>2020-11-19 23:49:25 +1030
commit8cabdb9b7bc682949bcad2e90055a485aafad7a3 (patch)
treea755a2bbc138e4fd826858fb4cc8059040ecd722
interpreter works
-rw-r--r--README9
-rw-r--r--brainfuck.c204
-rw-r--r--makefile25
-rw-r--r--numwarp.bf1
4 files changed, 239 insertions, 0 deletions
diff --git a/README b/README
new file mode 100644
index 0000000..843ec8f
--- /dev/null
+++ b/README
@@ -0,0 +1,9 @@
+a simple brainfuck interpreter
+
+```
+make
+./brainfuck numwarp.bf
+```
+type a number then press enter
+
+
diff --git a/brainfuck.c b/brainfuck.c
new file mode 100644
index 0000000..3cddd02
--- /dev/null
+++ b/brainfuck.c
@@ -0,0 +1,204 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <assert.h>
+
+#define MEMORY_SIZE 30000
+#define MAX_PROGRAM_SIZE 4096
+#define STACK_SIZE 512
+
+#define STACK_PUSH(x) (stack[sp++] = x)
+#define STACK_POP() (sp--)
+#define STACK_EMPTY() (sp == 0)
+#define STACK_FULL() (sp == STACK_SIZE)
+#define STACK_PEEK() (stack[sp-1])
+
+void die(const char *msg) { perror(msg); exit(EXIT_FAILURE); }
+
+void usage (char *argv[]) { printf("usage: %s script\n", argv[0]); exit(EXIT_SUCCESS); }
+
+uint8_t memory[MEMORY_SIZE] = {0};
+uint8_t program[MAX_PROGRAM_SIZE] = {0};
+uint32_t stack[STACK_SIZE] = {0};
+uint32_t sp = 0; // stack pointer
+
+char *bf_file;
+int bf_fd;
+
+void
+load(void)
+{
+ size_t i = 0;
+ char c;
+ while ((read(bf_fd, &c, 1)) > 0)
+ {
+ switch (c)
+ {
+ case '>':
+ case '<':
+ case '+':
+ case '-':
+ case '.':
+ case ',':
+ case '[':
+ case ']':
+ program[i] = c;
+ i++;
+ break;
+
+ default: break;
+ }
+ }
+}
+
+ssize_t
+find_closing_bracket(size_t pos)
+{
+ /*
+ * find closing ] for opening [ at location pos in program, return its position
+ * -1 on not found
+ *
+ * count each opening [ and closing ] until the numbers match, that will be our closing bracket
+ */
+ ssize_t close_pos = -1;
+ size_t open_count = 0;
+ size_t close_count = 0;
+
+ if (pos > MAX_PROGRAM_SIZE)
+ {
+ return -1;
+ }
+ if (program[pos] != '[')
+ {
+ fprintf(stderr, "instruction not [ at %zu\n", pos);
+ exit(EXIT_FAILURE);
+ }
+
+ uint8_t c;
+ while ((c = program[pos]) != 0)
+ {
+ switch (c)
+ {
+ case '[':
+
+ open_count++;
+ break;
+ case ']':
+ close_count++;
+ break;
+ default: break;
+ }
+ if (open_count == close_count)
+ {
+ close_pos = pos;
+ break;
+ }
+ pos++;
+ if (pos > MAX_PROGRAM_SIZE)
+ break;
+ }
+
+ assert(close_pos != -1);
+ return close_pos;
+}
+
+void
+run(void)
+{
+ int pc = 0; // program counter
+ size_t datap = 0; // data pointer into memory
+ uint8_t i; // current instruction
+ while ((i = program[pc]) != 0)
+ {
+ /*
+ size_t in;
+ int x = 0;
+ printf("PC = %d\n", pc);
+ while ((in = program[x]) != 0)
+ {
+ if (x == pc)
+ putchar('A');
+ putchar(in);
+ if (x == pc)
+ putchar('A');
+ x++;
+ }
+ getchar();
+ */
+ switch (i)
+ {
+ case '>':
+ datap++;
+ pc++;
+ break;
+ case '<':
+ datap--;
+ pc++;
+ break;
+ case '+':
+ memory[datap]++;
+ pc++;
+ break;
+ case '-':memory[datap]--;
+ pc++;
+ break;
+
+ case '.':
+ putchar(memory[datap]);
+ fflush(stdout);
+ pc++;
+ break;
+ case ',':
+ memory[datap] = (char)getchar();
+ pc++;
+ break;
+ case '[':
+ {
+ if (memory[datap] == 0)
+ {
+ uint32_t end = find_closing_bracket(pc);
+ pc = end+1;
+ }
+ else
+ {
+ STACK_PUSH(pc+1);
+ pc++;
+ }
+ break;
+ }
+ case ']':
+ if (memory[datap] != 0)
+ {
+ pc = STACK_PEEK();
+ }
+ else
+ {
+ STACK_POP();
+ pc++;
+ }
+ break;
+
+ default: die("unknown instruction"); break;
+ }
+ }
+}
+
+int
+main(int argc, char *argv[])
+{
+ if (argc < 2)
+ usage(argv);
+
+ bf_file = argv[1];
+ if ((bf_fd = open(bf_file, O_RDONLY)) < 0)
+ die("open");
+
+ load();
+
+ run();
+
+ close(bf_fd);
+ return EXIT_SUCCESS;
+}
diff --git a/makefile b/makefile
new file mode 100644
index 0000000..7b21de5
--- /dev/null
+++ b/makefile
@@ -0,0 +1,25 @@
+TARGET = brainfuck
+LIBS =
+CC = gcc
+CFLAGS = -std=c99 -g -Wextra -Wall -Werror -Wno-unused-variable -Wimplicit-fallthrough
+
+.PHONY: default all
+
+default: $(TARGET)
+all: default
+
+OBJECTS = $(patsubst %.c, %.o, $(wildcard *.c))
+HEADERS = $(wildcard *.h)
+
+%.o: %.c $(HEADERS)
+ $(CC) $(CFLAGS) -c $< -o $@
+
+.PRECIOUS: $(TARGET) $(OBJECTS)
+
+$(TARGET): $(OBJECTS)
+ $(CC) $(OBJECTS) -Wall $(CFLAGS) $(LIBS) -o $@
+
+clean:
+ -rm -f *.o
+ -rm -f *.tmp
+ -rm -f $(TARGET)
diff --git a/numwarp.bf b/numwarp.bf
new file mode 100644
index 0000000..3118ccd
--- /dev/null
+++ b/numwarp.bf
@@ -0,0 +1 @@
+>>>>+>+++>+++>>>>>+++[>,+>++++[>++++<-]>[<<[-[->]]>[<]>-]<<[>+>+>>+>+[<<<<]<+>>[+<]<[>]>+[[>>>]>>+[<<<<]>-]+<+>>>-[<<+[>]>>+<<<+<+<--------[<<-<<+[>]>+<<-<<-[<<<+<-[>>]<-<-<<<-<----[<<<->>>>+<-[<<<+[>]>+<<+<-<-[<<+<-<+[>>]<+<<<<+<-[<<-[>]>>-<<<-<-<-[<<<+<-[>>]<+<<<+<+<-[<<<<+[>]<-<<-[<<+[>]>>-<<<<-<-[>>>>>+<-<<<+<-[>>+<<-[<<-<-[>]>+<<-<-<-[<<+<+[>]<+<+<-[>>-<-<-[<<-[>]<+<++++[<-------->-]++<[<<+[>]>>-<-<<<<-[<<-<<->>>>-[<<<<+[>]>+<<<<-[<<+<<-[>>]<+<<<<<-[>>>>-<<<-<-]]]]]]]]]]]]]]]]]]]]]]>[>[[[<<<<]>+>>[>>>>>]<-]<]>>>+>>>>>>>+>]<]<[-]<<<<<<<++<+++<+++[[>]>>>>>>++++++++[<<++++>++++++>-]<-<<[-[<+>>.<-]]<<<<[-[-[>+<-]>]>>>>>[.[>]]<<[<+>-]>>>[<<++[<+>--]>>-]<<[->+<[<++>-]]<<<[<+>-]<<<<]>>+>>>--[<+>---]<.>>[[-]<<]<]