diff --git a/bf.c b/bf.c new file mode 100644 index 0000000..77d0c72 --- /dev/null +++ b/bf.c @@ -0,0 +1,162 @@ +#include +#include +#include + +#define EXIT_NO_INPUT 4 + +#define TAPE_SIZE 30000 +#define MAX_LOOPS 1024 + +static unsigned char tape[TAPE_SIZE]; /* BF memory cells. */ +static long loop_stack[MAX_LOOPS]; /* Loop stack. */ +static unsigned int tape_ptr = 0; /* Current tape position. */ +static unsigned int loop_ptr = 0; /* Loop stack top. */ + +int +main (int argc, char **argv) { + FILE * f; /* The input file. */ + unsigned int i; /* The current file being processed. */ + unsigned int l; /* A counter for looping. */ + unsigned int done; /* Boolean for looping. */ + char c; /* Current BF instruction. */ + + if (argc == 1) { + /* There must be at leas one input file. */ + fprintf (stderr, "%s: fatal error: no input files\n", argv[0]); + return EXIT_NO_INPUT; + + } else { + + /* Process all input files. */ + for (i = 1; i < argc; i++) { + /* Reset everything. */ + memset (tape, 0, TAPE_SIZE * sizeof (unsigned char)); + memset (loop_stack, 0, MAX_LOOPS * sizeof (long)); + l = 0; + c = 'a'; + + /* Try to open the input file. */ + f = fopen (argv[i], "r"); + + if (f == NULL) { + fprintf (stderr, "Failed to open %s\n", argv[1]); + continue; + + } else { + + /* If the file opened, then read characters from it one by one. */ + while ((c = fgetc (f)) != EOF) { + + /* Proccess the character. */ + switch (c) { + + case '.': + /* BF output instruction. */ + putchar (tape[tape_ptr]); + fflush (stdout); + break; + + case ',': + /* BF input instruction. */ + tape[tape_ptr] = (unsigned char) getchar (); + break; + + case '+': + /* BF tape increment instruction. */ + tape[tape_ptr]++; + break; + + case '-': + /* BF Tape decrement instruction. */ + tape[tape_ptr]--; + break; + + case '>': + /* BF move to next cell instruction. */ + tape_ptr = (tape_ptr + 1) % TAPE_SIZE; + break; + + case '<': + /* BF move to previous cell instruction. */ + tape_ptr = (tape_ptr == 0) ? TAPE_SIZE - 1 : tape_ptr - 1; + break; + + case '[': + /* BF open loop instruction. */ + /* Check if the program has reached the max supported number of open loops. */ + if (loop_ptr == MAX_LOOPS) { + /* Fail if it has. */ + fprintf (stderr, + "%s: Fatal error in %s: max number of nested loops reached\n", + argv[0], argv[i]); + goto skip; + + } else { + + /* Check if there is something on the tape. */ + if (tape[tape_ptr] != 0) { + /* If there is, then store the instruction's position on the file + so that the program car return to it at the loop's end. */ + loop_stack[loop_ptr] = ftell (f); + loop_ptr++; + + } else { + + /* If there is nothing on the tape, then search for the corresponding loop + end instruction. */ + done = 0; + while (!done) { + /* Read characters from the file until a [, ] or EOF, whichever happens + first. */ + c = fgetc (f); + + switch(c) { + case EOF: + /* Skip the file on EOF. */ + fprintf (stderr, "%s: Fatal error in %s: premature EOF\n", argv[0], argv[1]); + goto skip; + break; + + case '[': + /* If a loop opens, then increase the nested loops counter. */ + l++; + break; + + case ']': + /* If a ] instruction is found, */ + if (l > 0) + l--; + else + done = 1; + break; + } /* switch(c) */ + } /* while(!done) */ + } /* else (tape[tape_ptr] == 0) */ + } /* else (loop_ptr < MAX_LOOPS) */ + break; + + case ']': + /* BF close loop instruction. */ + /* Check if there is something on the tape. */ + if (tape[tape_ptr] != 0) + /* If there is, then jump back to the corresponding ] instruction. */ + fseek (f, loop_stack[loop_ptr - 1], SEEK_SET); + else + /* If there is nothing, then remove the loop from the stack and continue. */ + loop_ptr--; + break; + + default: + continue; + } /* switch(c) */ + } /* while(c = fgetc(f)) */ + + skip: + /* Done with this file. */ + fclose (f); + } /* else (f != NULL) */ + } /* for(i = 1 to argc - 1) */ + } /* else (argc > 1) */ + + return EXIT_SUCCESS; +} diff --git a/bf.s b/bf.s index b54c06c..98328fd 100644 --- a/bf.s +++ b/bf.s @@ -112,6 +112,34 @@ eif1: /* Loop through all arguments */ movl $0, %edi loop_start: + /* Reset everything. */ + pushl %eax + pushl %ecx + pushl %edx + pushl $30000 + pushl $0 + pushl $tape + call memset + addl $12, %esp + popl %edx + popl %ecx + popl %eax + + pushl %eax + pushl %ecx + pushl %edx + pushl $4100 + pushl $0 + pushl $jmp_stack + call memset + addl $12, %esp + popl %edx + popl %ecx + popl %eax + + movl $0, ptr + movl $0, loop_ptr + /* Process current input file */ pushl %eax pushl %ecx @@ -126,9 +154,11 @@ loop_start: /* Get current argument length */ pushl %ecx pushl %edx + pushl %edi pushl %edx call strlen add $4, %esp + popl %edi popl %edx popl %ecx