#define _GNU_SOURCE #include <errno.h> #include <stdarg.h> #include <stdio.h> #include <stdlib.h> #include <string.h> void pasm(const char *s, ...); void syscall(const char *ncall, const char *a, const char *b, const char *c); int push(int n); int pop(void); void print_long(const char *name); void print_data(void); void print_getchar(void); void print_putchar(void); void init_bf(void); void out_sub(int val, char c, const char *to); void out_add(int val, char c, const char *to); void char_to_code(int c, int times, int circular); int get_next_char() { int c; while (((c = getchar()) != -1) && (!strchr("+-<>,.[]", c))) ; return (c); } void get_n_char(int *buf, int pos, int n) { int i; i = 0; while (i < n) { buf[(pos + i) % 4] = get_next_char(); i++; } } int get_bf_char() { static int buf[4]; static int pos = -1; int tmp; if (pos == -1) get_n_char(buf, pos = 0, 4); if ((buf[pos % 4] == '[') && (buf[(pos + 1) % 4] == '-') && (buf[(pos + 2) % 4] == ']')) { get_n_char(buf, pos, 3); pos += 3; return (0); } tmp = buf[pos % 4]; buf[pos++ % 4] = get_next_char(); return (tmp); } void pasm(const char *s, ...) { va_list args; printf("\t"); va_start(args, s); vprintf(s, args); va_end(args); printf("\n"); } #if defined(linux) || defined(__linux) void syscall(const char *ncall, const char *a, const char *b, const char *c) { if (strcmp("%eax", ncall)) // Here to avoid redundant movs pasm("movl %s, %%eax", ncall); if (strcmp("%ebx", a)) pasm("movl %s, %%ebx", a); if (strcmp("%ecx", b)) pasm("movl %s, %%ecx", b); if (strcmp("%edx", c)) pasm("movl %s, %%edx", c); pasm("int $0x80"); } #elif defined(BSD) // the BSD style syscall isn't tested void syscall(const char *ncall, const char *a, const char *b, const char *c) { pasm("movl %s, %%eax", ncall); pasm("pushl %s", c); pasm("pushl %s", b); pasm("pushl %s", a); pasm("subl $4, %%esp"); pasm("int $0x80"); pasm("addl $16, %%esp"); } #else # error only handles linux and bsd systems #endif typedef struct s_llst t_llst; struct s_llst { int n; t_llst *next; }; // The labels stack t_llst *stack = NULL; int label_max = 0; int push(int n) { t_llst *p; p = malloc(sizeof(*p)); p->n = n; p->next = stack; stack = p; return (n); } int pop() { int tmp_n; t_llst *p; if (stack == NULL) return (-1); tmp_n = stack->n; p = stack; stack = p->next; free(p); return (tmp_n); } void print_long(const char *name) { printf(".align 4\n"); printf("%s:\n", name); pasm(".long 0"); } void print_data() { printf(".data\n"); print_long("pos_read"); print_long("len_read"); print_long("pos_write"); puts(""); pasm(".comm buf_read, 512, 32"); pasm(".comm buf_write, 512, 32"); puts(""); } void print_getchar() { printf("getchar:\n"); pasm("movl pos_read, %%eax"); pasm("cmpl len_read, %%eax"); pasm("jl retchar"); syscall("$3", "$0", "$buf_read", "$512"); // The read syscall pasm("cmpl $0, %%eax"); // Note: that doesn't handle errors properly on bsd pasm("jg read_ok"); pasm("movl $0, (%%ebp, %%esi)"); // EOF is handled as returning 0 pasm("ret"); printf("read_ok:\n"); pasm("movl %%eax, len_read"); pasm("movl $0, pos_read"); printf("retchar:\n"); pasm("movl pos_read, %%eax"); pasm("movb buf_read(%%eax), %%bh"); pasm("movb %%bh, (%%ebp, %%esi)"); pasm("incl %%eax"); pasm("movl %%eax, pos_read"); pasm("ret"); } void print_putchar() { printf("putchar:\n"); pasm("movl pos_write, %%eax"); pasm("incl %%eax"); pasm("movb (%%ebp, %%esi), %%bh"); pasm("movb %%bh, buf_write(%%eax)"); pasm("movl %%eax, pos_write"); pasm("cmpl $512, %%eax"); pasm("jge flush"); pasm("cmpb $%d, %%bh", '\n'); pasm("je flush"); pasm("ret"); printf("flush:\n"); pasm("movl pos_write, %%edx"); pasm("incl %%edx"); syscall("$4", "$1", "$buf_write", "%edx"); pasm("movl $0, pos_write"); pasm("ret"); } void init_bf() { print_data(); printf(".text\n"); print_getchar(); print_putchar(); printf(".globl _start\n"); printf("_start:\n"); pasm("movl %%esp, %%ebp"); // base pointer pasm("subl $30000, %%esp"); // allocate space pasm("xorl %%eax, %%eax"); printf("memzero:\n"); // initialize space pasm("movl $0, (%%ebp, %%eax, 0x4)"); pasm("decl %%eax"); pasm("cmpl $-7500, %%eax"); pasm("jg memzero"); pasm("xorl %%esi, %%esi"); // initialize counter } void out_sub(int val, char c, const char *to) { if (val < 0) out_add(-val, c, to); else if (val == 1) pasm("dec%c %s", c, to); else if (val > 1) pasm("sub%c $%d, %s", c, val, to); } void out_add(int val, char c, const char *to) { if (val < 0) out_sub(-val, c, to); else if (val == 1) pasm("inc%c %s", c, to); else if (val > 1) pasm("add%c $%d, %s", c, val, to); } void char_to_code(int c, int times, int circular) { if (c == '>') { out_sub(times, 'l', "%esi"); if (circular) { pasm("cmpl $-30000, %%esi"); pasm("jg wrapped%d", label_max); pasm("addl $30000, %%esi"); printf("wrapped%d:\n", label_max++); } } else if (c == '<') { out_add(times, 'l', "%esi"); if (circular) { pasm("cmpl $0, %%esi"); pasm("jle wrapped%d", label_max); pasm("subl $30000, %%esi"); printf("wrapped%d:\n", label_max++); } } else if (c == 0) pasm("movb $0, (%%ebp, %%esi)"); else if (c == '+') out_add(times, 'b', "(%ebp, %esi)"); else if (c == '-') out_sub(times, 'b', "(%ebp, %esi)"); else if (c == '.') while (times--) pasm("call putchar"); else if (c == ',') while (times--) pasm("call getchar"); else if (c == '[') while (times--) { printf("start%d:\n", push(label_max++)); pasm("movb (%%ebp, %%esi), %%al"); pasm("testb %%al, %%al"); pasm("jz end%d", stack->n); } else if (c == ']') while (times--) { pasm("jmp start%d", stack->n); printf("end%d:\n", pop()); } } int main(int ac, char **av) { int cur_char; int last_char; int times_char; int circular; circular = 0; while (ac > 1) { if (!strcmp(av[1], "-c") || !strcmp(av[1], "--circular")) circular = 1; else if (!strcmp(av[1], "-h") || !strcmp(av[1], "--help")) { printf("Usage:\n%s < infile > outfile\n\t-c\t--circular\t" "activates circular memory\n\t-h\t--help\t this help", program_invocation_name); return (0); } av++; ac--; } init_bf(); times_char = 0; last_char = cur_char = get_bf_char(); do { if (cur_char == last_char) times_char++; else { char_to_code(last_char, times_char, circular); last_char = cur_char; times_char = 1; } } while ((cur_char = get_bf_char()) != -1); char_to_code(last_char, times_char, circular); pasm("call flush"); pasm("movzbl (%%ebp, %%esi), %%ebx"); pasm("movl $1, %%eax"); pasm("int $0x80"); return (0); }