summaryrefslogtreecommitdiff
path: root/skullfuck.c
diff options
context:
space:
mode:
Diffstat (limited to 'skullfuck.c')
-rw-r--r--skullfuck.c49
1 files changed, 41 insertions, 8 deletions
diff --git a/skullfuck.c b/skullfuck.c
index 47cb772..a8de668 100644
--- a/skullfuck.c
+++ b/skullfuck.c
@@ -25,7 +25,7 @@
#include <getopt.h>
-#if defined(x86_64)
+#if defined(__x86_64__)
#define ARCH "x86_64"
#define OS "Linux"
#define INC_DATA_PTR "\tincq %rsi\n"
@@ -36,6 +36,7 @@
#define ADD_DATA "\taddb $0x%x, (%%rsi)\n"
#define DEC_DATA "\tdecb (%rsi)\n"
#define SUB_DATA "\tsubb $0x%x, (%%rsi)\n"
+#define ZERO_DATA "\tmovb $0x00, (%rsi)\n"
#define PRINT_DATA "\tmovq $0x01, %rax\n" \
"\tmovq $0x01, %rdi\n" \
"\tsyscall\n"
@@ -58,7 +59,7 @@
#define EXIT "\tmovq $0x3c, %rax\n" \
"\tmovq $0x00, %rdi\n" \
"\tsyscall\n"
-#elif defined(i686)
+#elif defined(__i686__)
#define ARCH "i686"
#define OS "Linux"
#define INC_DATA_PTR "\tincl %ecx\n"
@@ -69,6 +70,7 @@
#define ADD_DATA "\taddb $0x%x, (%%ecx)\n"
#define DEC_DATA "\tdecb (%ecx)\n"
#define SUB_DATA "\tsubb $0x%x, (%%ecx)\n"
+#define ZERO_DATA "\tmovb $0x00, (%ecx)\n"
#define PRINT_DATA "\tmovl $0x04, %eax\n" \
"\tmovl $0x01, %ebx\n" \
"\tint $0x80\n"
@@ -116,12 +118,14 @@ struct loop_stack {
int _stack_index;
};
+
/* Pushes `n` onto the stack specified by `s`. */
static void push_loop_index(struct loop_stack *s, int n) {
s->_mem[s->_stack_index] = n;
s->_stack_index++;
}
+
/* Pops the top of `s` off and returns it. */
static int pop_loop_index(struct loop_stack *s) {
s->_stack_index--;
@@ -129,6 +133,30 @@ static int pop_loop_index(struct loop_stack *s) {
}
+/* Loop optimizations. */
+enum {
+ NONE,
+ LOOP_EMPTY,
+ LOOP_ZERO,
+};
+
+
+/* Optimization subroutine which detects common loop patterns, such as
+ `[-]`, increments the `in` pointer to beyond them, and returns the
+ identity of the pattern. */
+static int optimize_loops(char **in) {
+ if (*(*in + 1) == '-' && *(*in + 2) == ']') {
+ *in += 2;
+ return LOOP_ZERO;
+ }
+ if (*(*in + 1) == ']') {
+ *in += 1;
+ return LOOP_EMPTY;
+ }
+ return NONE;
+}
+
+
/* Minor optimization subroutine. Increments the `in` pointer to beyond
the collection of adjacent `op` characters, and returns the number
of operations counted. */
@@ -144,7 +172,7 @@ static int reduce(char **in, char op) {
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, op_count;
+ int next_loop = 0, cur_loop = 0, op_count, optimization;
struct loop_stack *loops = calloc(sizeof(struct loop_stack), 1);
for (char *cur = in; *cur != '\0'; cur++) {
@@ -188,11 +216,16 @@ static void write_instructions(FILE *out, char *in) {
fputs(READ_DATA, out);
break;
case '[':
- cur_loop = next_loop;
- push_loop_index(loops, next_loop++);
- fprintf(out, "S%d:\n", cur_loop);
- fputs(DATA_IS_ZERO, out);
- fprintf(out, JMP_END, cur_loop);
+ optimization = optimize_loops(&cur);
+ if (optimization == LOOP_ZERO) {
+ fputs(ZERO_DATA, out);
+ } else if (optimization == NONE) {
+ cur_loop = next_loop;
+ push_loop_index(loops, next_loop++);
+ fprintf(out, "S%d:\n", cur_loop);
+ fputs(DATA_IS_ZERO, out);
+ fprintf(out, JMP_END, cur_loop);
+ }
break;
case ']':
cur_loop = pop_loop_index(loops);