diff options
-rw-r--r-- | README | 9 | ||||
-rw-r--r-- | brainfuck.c | 204 | ||||
-rw-r--r-- | makefile | 25 | ||||
-rw-r--r-- | numwarp.bf | 1 |
4 files changed, 239 insertions, 0 deletions
@@ -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 @@ +>>>>+>+++>+++>>>>>+++[>,+>++++[>++++<-]>[<<[-[->]]>[<]>-]<<[>+>+>>+>+[<<<<]<+>>[+<]<[>]>+[[>>>]>>+[<<<<]>-]+<+>>>-[<<+[>]>>+<<<+<+<--------[<<-<<+[>]>+<<-<<-[<<<+<-[>>]<-<-<<<-<----[<<<->>>>+<-[<<<+[>]>+<<+<-<-[<<+<-<+[>>]<+<<<<+<-[<<-[>]>>-<<<-<-<-[<<<+<-[>>]<+<<<+<+<-[<<<<+[>]<-<<-[<<+[>]>>-<<<<-<-[>>>>>+<-<<<+<-[>>+<<-[<<-<-[>]>+<<-<-<-[<<+<+[>]<+<+<-[>>-<-<-[<<-[>]<+<++++[<-------->-]++<[<<+[>]>>-<-<<<<-[<<-<<->>>>-[<<<<+[>]>+<<<<-[<<+<<-[>>]<+<<<<<-[>>>>-<<<-<-]]]]]]]]]]]]]]]]]]]]]]>[>[[[<<<<]>+>>[>>>>>]<-]<]>>>+>>>>>>>+>]<]<[-]<<<<<<<++<+++<+++[[>]>>>>>>++++++++[<<++++>++++++>-]<-<<[-[<+>>.<-]]<<<<[-[-[>+<-]>]>>>>>[.[>]]<<[<+>-]>>>[<<++[<+>--]>>-]<<[->+<[<++>-]]<<<[<+>-]<<<<]>>+>>>--[<+>---]<.>>[[-]<<]<] |