diff options
| author | jakob <jakob@memeware.net> | 2017-03-18 18:07:39 -0400 |
|---|---|---|
| committer | jakob <jakob@memeware.net> | 2017-03-18 18:07:39 -0400 |
| commit | d45dbeb48a9da2ccfc1dd3fc0f3baea4c365e086 (patch) | |
| tree | d1107185a1b722ee65b2c8f9b5f70376dd39057a | |
| parent | 9b5abf3e3859e54d4bc48db0792b2686eb7bd16a (diff) | |
The compilation process now includes *very* minimal code optimization.
| -rw-r--r-- | .gitignore | 4 | ||||
| -rw-r--r-- | README.md | 7 | ||||
| -rw-r--r-- | skullfuck.c | 53 | ||||
| -rw-r--r-- | test/hello_world.bf (renamed from examples/hello_world.bf) | 0 | ||||
| -rw-r--r-- | test/hello_world_commented.bf (renamed from examples/hello_world_commented.bf) | 0 | ||||
| -rw-r--r-- | test/rot13.bf (renamed from examples/rot13.bf) | 0 | ||||
| -rw-r--r-- | test/rot13_commented.bf (renamed from examples/rot13_commented.bf) | 0 |
7 files changed, 51 insertions, 13 deletions
@@ -1,3 +1,3 @@ skullfuck -test -test.c +run_tests +run_tests.c @@ -1,17 +1,12 @@ Skullfuck ========= -Skullfuck is a dead simple, non-optimizing compiler for Brainfuck, contained in a single C source file. It outputs binaries targeting amd64 Linux. +Skullfuck is a dead simple, non-optimizing compiler for Brainfuck, contained in a single C source file. It outputs binaries targeting x86_64 and i686 Linux. It depends on GNU Binutils, or any compatible implementation of `as` and `ld`. A good explanation of the history and design behind the language can be found in [the Wikipedia article.](https://en.wikipedia.org/wiki/Brainfuck) -Undefined Behavior ------------------- -The Brainfuck programming language is extremely limited in its specification, and some operations don't have a defined behavior - specifically, operations on an out-of-bounds data pointer are undefined. UB is allowed, but do not expect it to work equally on all platforms. - - TODO ---- * *BSD targeted binaries. diff --git a/skullfuck.c b/skullfuck.c index 7d9e0a8..b40e903 100644 --- a/skullfuck.c +++ b/skullfuck.c @@ -29,9 +29,13 @@ #define ARCH "x86_64" #define OS "Linux" #define INC_DATA_PTR "\tincq %rsi\n" +#define ADD_DATA_PTR "\taddq $0x%x, %%rsi\n" #define DEC_DATA_PTR "\tdecq %rsi\n" +#define SUB_DATA_PTR "\tsubq $0x%x, %%rsi\n" #define INC_DATA "\tincb (%rsi)\n" +#define ADD_DATA "\taddb $0x%x, (%%rsi)\n" #define DEC_DATA "\tdecb (%rsi)\n" +#define SUB_DATA "\tsubb $0x%x, (%%rsi)\n" #define PRINT_DATA "\tmovq $0x01, %rax\n" \ "\tmovq $0x01, %rdi\n" \ "\tsyscall\n" @@ -58,9 +62,13 @@ #define ARCH "i686" #define OS "Linux" #define INC_DATA_PTR "\tincl %ecx\n" +#define ADD_DATA_PTR "\taddl $0x%x, %%ecx\n" #define DEC_DATA_PTR "\tdecl %ecx\n" +#define SUB_DATA_PTR "\tsubl $0x%x, %%ecx\n" #define INC_DATA "\tincb (%ecx)\n" +#define ADD_DATA "\taddb $0x%x, (%%ecx)\n" #define DEC_DATA "\tdecb (%ecx)\n" +#define SUB_DATA "\tsubb $0x%x, (%%ecx)\n" #define PRINT_DATA "\tmovl $0x04, %eax\n" \ "\tmovl $0x01, %ebx\n" \ "\tint $0x80\n" @@ -121,26 +129,57 @@ static int pop_loop_index(struct loop_stack *s) { } +/* Minor optimization subroutine. Increments the `in` pointer to beyond + the collection of adjacent `op` characters, and returns the number + of operations counted. */ +static int reduce(char **in, char op) { + int i; + for (i = 0; (*in)[i] == op; i++); + *in += i - 1; + return i; +} + + /* Converts the brainfuck instructions read from `in` to assembly instructions and writes them to `out`. `in` is expected to be null-terminated. */ static void write_instructions(FILE *out, char *in) { - int next_loop = 0, cur_loop = 0; + int next_loop = 0, cur_loop = 0, op_count; struct loop_stack *loops = calloc(sizeof(struct loop_stack), 1); for (char *cur = in; *cur != '\0'; cur++) { switch(*cur) { case '>': - fputs(INC_DATA_PTR, out); + op_count = reduce(&cur, '>'); + if (op_count > 1) { + fprintf(out, ADD_DATA_PTR, op_count); + } else { + fputs(INC_DATA_PTR, out); + } break; case '<': - fputs(DEC_DATA_PTR, out); + op_count = reduce(&cur, '<'); + if (op_count > 1) { + fprintf(out, SUB_DATA_PTR, op_count); + } else { + fputs(DEC_DATA_PTR, out); + } break; case '+': - fputs(INC_DATA, out); + op_count = reduce(&cur, '+'); + if (op_count > 1) { + fprintf(out, ADD_DATA, op_count); + } else { + fputs(INC_DATA, out); + } break; case '-': - fputs(DEC_DATA, out); + op_count = reduce(&cur, '-'); + if (op_count > 1) { + fprintf(out, SUB_DATA, op_count); + } else { + fputs(DEC_DATA, out); + } break; case '.': fputs(PRINT_DATA, out); @@ -223,6 +262,10 @@ static void create_binary(struct params p) { wait(NULL); } } + + if (!p.compile_only) + remove("/tmp/skullfuck_tmp.s"); + remove("/tmp/skullfuck_tmp.o"); } diff --git a/examples/hello_world.bf b/test/hello_world.bf index ea2b641..ea2b641 100644 --- a/examples/hello_world.bf +++ b/test/hello_world.bf diff --git a/examples/hello_world_commented.bf b/test/hello_world_commented.bf index fff532c..fff532c 100644 --- a/examples/hello_world_commented.bf +++ b/test/hello_world_commented.bf diff --git a/examples/rot13.bf b/test/rot13.bf index e9e82be..e9e82be 100644 --- a/examples/rot13.bf +++ b/test/rot13.bf diff --git a/examples/rot13_commented.bf b/test/rot13_commented.bf index 85a97fa..85a97fa 100644 --- a/examples/rot13_commented.bf +++ b/test/rot13_commented.bf |