diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..295dee9 --- /dev/null +++ b/Makefile @@ -0,0 +1,8 @@ +CFLAGS=-O2 -Wall +SRC=main.c interactive.c +HEADER=interactive.h +OUT=bfuck + +$(OUT): $(SRC) $(HEADER) + $(CC) $(SRC) $(CFLAGS) -o $(OUT) + diff --git a/README.md b/README.md new file mode 100644 index 0000000..c4212db --- /dev/null +++ b/README.md @@ -0,0 +1,19 @@ +# Brainfuck Interpreter +Written in C. Nothing really interesting. Only distinct feature is interactive mode + +`hw.bf` and `hw_2.bf` are hello world code examples in brainfuck. + +Build: +``` +make +``` + +Interpret file: +``` +./bfuck +``` + +Interactive mode: +``` +./bfuck +``` diff --git a/hw.bf b/hw.bf new file mode 100644 index 0000000..2d1725c --- /dev/null +++ b/hw.bf @@ -0,0 +1,2 @@ +>+++++++++[<++++++++>-]<.>+++++++[<++++>-]<+.+++++++..+++.>>>++++++++[<++++>-] +<.>>>++++++++++[<+++++++++>-]<---.<<<<.+++.------.--------.>>+.>++++++++++. diff --git a/hw_2.bf b/hw_2.bf new file mode 100644 index 0000000..fc0d0f7 --- /dev/null +++ b/hw_2.bf @@ -0,0 +1,3 @@ + ++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++ + .>+.+++++++..+++.>++.<<+++++++++++++++.>.+++. + ------.--------.>+.>. diff --git a/interactive.c b/interactive.c new file mode 100644 index 0000000..02779d6 --- /dev/null +++ b/interactive.c @@ -0,0 +1,51 @@ +// interactive.c + +#include +#include +#include +#include + +#include "interactive.h" + +void start_interactive() +{ + char* code = NULL; + _Bool exit = false; + + printf("Type 'q' to quit from interactive mode\n"); + + while (!exit) { + printf(">>> "); + + code = read_code(); + size_t code_len = strlen(code); + + if (code[0] == 'q') { + exit = true; + } else { + run_code(code, code_len); + printf("\n"); + } + + free(code); + } +} + +char* read_code() +{ + char* code_buffer = NULL; + size_t buf_size; + + if (getline(&code_buffer, &buf_size, stdin) == -1) { + if (feof(stdin)) { + printf("\n"); + exit(EXIT_SUCCESS); + } else { + perror("Error: Cannot getline()"); + exit(EXIT_FAILURE); + } + } + + return code_buffer; +} + diff --git a/interactive.h b/interactive.h new file mode 100644 index 0000000..c3864ac --- /dev/null +++ b/interactive.h @@ -0,0 +1,10 @@ +// interative.h + +#include + +#define CELL_COUNT 30000 +#define START_BUFFER_SIZE 2048 + +char* read_code(); +void run_code(char* code, int code_len); +void start_interactive(); diff --git a/main.c b/main.c new file mode 100644 index 0000000..d2c0a2c --- /dev/null +++ b/main.c @@ -0,0 +1,98 @@ +// main.c + +#include +#include +#include + +#include "interactive.h" + +int main(int argc, char* argv[]) +{ + if (argc < 2) { + start_interactive(); + exit(EXIT_SUCCESS); + } + + char* input = argv[1]; + FILE* input_file = fopen(input, "r"); + + if (!input_file) { + fprintf(stderr, "Error: File \"%s\" doesn't exist\n", input); + exit(EXIT_FAILURE); + } + + // Get size of file + fseek(input_file, 0L, SEEK_END); + int code_len = ftell(input_file); + fseek(input_file, 0L, SEEK_SET); + + char* code_buffer = malloc(code_len); + + fread(code_buffer, sizeof(char), code_len, input_file); + fclose(input_file); + + run_code(code_buffer, code_len); + + free(code_buffer); + return 0; +} + +void run_code(char* code, int code_len) +{ + // Create cell array and set every cell to 0 + char cells[CELL_COUNT]; + memset(cells, 0, sizeof(cells)); + + int cell_i = 0; // current cell index + int b = 0; // bracket counter + + // Start interpreting code + for (int i = 0; i < code_len; i++) { + switch (code[i]) { + case '>': cell_i++; break; + case '<': cell_i--; break; + case '+': cells[cell_i]++; break; + case '-': cells[cell_i]--; break; + case '.': putchar(cells[cell_i]); break; + case ',': + cells[cell_i] = getchar(); + getchar(); // remove '\n' from stdin + break; + case '[': + if (cells[cell_i] != 0) continue; + b++; + + while (b > 0) { + switch (code[i]) { + case '[': b++; break; + case ']': b--; break; + } + + // In case if matching brace wasnt found and we + // got past the code_len + if (++i > code_len) { + break; + } + } + break; + case ']': + if (cells[cell_i] == 0) continue; + b++; + + while (b > 0) { + switch (code[i]) { + case ']': b++; break; + case '[': b--; break; + } + + if (--i < 0) { + break; + } + } + break; + default: + break; + } + } +} +