correct jump management
[brainfuck.git] / bf.c
diff --git a/bf.c b/bf.c
index 0e331d9c4d594c38371698cbf92100b5cf9b81c9..c71b46785fcc047d10da40120bcf3c91b7db1917 100644 (file)
--- a/bf.c
+++ b/bf.c
@@ -14,7 +14,8 @@
 /* macros */
 
 #define BUFSIZE 256
-#define MEMSIZE 8
+#define MAXJUMP 4
+#define MEMSIZE 10
 
 /* type definition */
 
@@ -23,6 +24,8 @@
 char *progname = NULL;
 int p = 0;
 char mem[MEMSIZE] = {0};
+int j = 0;
+int jump[MAXJUMP] = {0};
 
 /* help function */
 
@@ -44,9 +47,13 @@ int usage (int ret)
 int process (char *buffer, int nb, FILE *out) {
     int i;
 
-    for (i = 0; (i < nb) && (buffer[i] != 0); i++) {
+    for (i = 0; i < nb; i++) {
+        if (buffer[i] == 0) {
+            break;
+        }
+
+        VERBOSE (DEBUG, fprintf (stderr, "%s: p=%d, buffer='%s', memory=[ ", progname, p, buffer + i); int _i; for (_i = 0; _i < MEMSIZE; _i++) fprintf (stderr," %d", mem[_i]); fprintf (stderr," ]\n"));
 
-        VERBOSE (DEBUG, fprintf (stderr, "%s: read '%c' (%u)\n", progname, buffer[i], buffer[i]));
         switch (buffer[i]) {
             case '>': /* increase pointer */
                 p++;
@@ -80,13 +87,18 @@ int process (char *buffer, int nb, FILE *out) {
                 break;
             case ',': /* read a byte and store it in memory */
                 if ((p >= 0) && (p < MEMSIZE)) {
-                    mem[p] = buffer[++i];
+                    int c = getchar ();
+                    mem[p] = (c > 0) ? c : 0;
                 } else {
                     VERBOSE (ERROR, fprintf (stderr, "%s: invalid address (%d)\n", progname, p));
                     return 1;
                 }
                 break;
             case '[': /* jump to right bracket if pointer is set to 0 */
+                if ((p < 0) || (p >= MEMSIZE)) {
+                    VERBOSE (ERROR, fprintf (stderr, "%s: invalid address (%d)\n", progname, p));
+                    return 1;
+                }
                 if (mem[p] == 0) {
                     int bracket = 1;
                     while ((++i < nb) && (bracket > 0)) {
@@ -96,15 +108,24 @@ int process (char *buffer, int nb, FILE *out) {
                         VERBOSE (ERROR, fprintf (stderr, "%s: brace not closed\n", progname));
                         return 1;
                     }
+                    i--;
                 } else {
-                    return process (buffer + i + 1, nb - i - 1, out);
+                    if (j >= MAXJUMP) {
+                        VERBOSE (ERROR, fprintf (stderr, "%s: too many jump\n", progname));
+                        return 1;
+                    }
+                    jump[j++] = i;
                 }
                 break;
             case ']': /* jump to left bracket if pointer is different to 0 */
-                if (mem[p] != 0) {
-                    i = -1;
+                if (j <= 0) {
+                    VERBOSE (ERROR, fprintf (stderr, "%s: can't jump back\n", progname));
+                    return 1;
                 }
+                i = jump[--j] - 1;
                 break;
+            case ' ':
+            case '\t':
             case '\n':
             case '\r':
                 break;
@@ -141,8 +162,19 @@ int main (int argc, char *argv[])
     }
 
     int c;
-    while ((c = getopt(argc, argv, "i:m:o:hv:")) != EOF) {
+    while ((c = getopt(argc, argv, "e:i:m:o:hv:")) != EOF) {
         switch (c) {
+        case 'e':
+            if (buffer) {
+                free (buffer);
+            }
+            buffer = strdup (optarg);
+            if (buffer == NULL) {
+                VERBOSE (ERROR, fprintf (stderr, "%s: can't allocate memory\n", progname));
+                return 1;
+            }
+            size = strlen (buffer) + 1;
+            break;
         case 'i':
             input = optarg;
             break;
@@ -181,30 +213,36 @@ int main (int argc, char *argv[])
             VERBOSE (ERROR, fprintf (stderr, "%s: can't open file '%s' for reading\n", progname, input));
             return 1;
         }
-    } else {
+    } else if (buffer == NULL) {
         fid = stdin;
     }
 
     /* read input file */
-    while (!feof (fid)) {
-        buffer = (char *) realloc (buffer, size + BUFSIZE);
-        if (buffer == NULL) {
-            VERBOSE (ERROR, fprintf (stderr, "%s: can't allocate memory\n", progname));
-            return 1;
+    if (fid) {
+        while (!feof (fid)) {
+            buffer = (char *) realloc (buffer, size + BUFSIZE);
+            if (buffer == NULL) {
+                VERBOSE (ERROR, fprintf (stderr, "%s: can't allocate memory\n", progname));
+                return 1;
+            }
+            memset (buffer + size, 0, BUFSIZE);
+            n = fread (buffer + size, 1, BUFSIZE, fid);
+            if (errno != 0) {
+                VERBOSE (ERROR, fprintf (stderr, "%s: can't read data from file '%s'\n", progname, input));
+                return 1;
+            }
+            size += BUFSIZE;
         }
-        memset (buffer + size, 0, BUFSIZE);
-        n = fread (buffer + size, 1, BUFSIZE, fid);
-        if (errno != 0) {
-            VERBOSE (ERROR, fprintf (stderr, "%s: can't read data from file '%s'\n", progname, input));
-            return 1;
+
+        /* close input file */
+        if (fid != stdin) {
+            fclose (fid);
         }
-        size += BUFSIZE;
+        VERBOSE (DEBUG, fprintf (stderr, "%s: read %d bytes\n", progname, size + n - BUFSIZE));
+    } else {
+        VERBOSE (DEBUG, fprintf (stderr, "%s: prog %d bytes\n", progname, size -1));
     }
 
-    /* close input file */
-    fclose (fid);
-    VERBOSE (DEBUG, fprintf (stderr, "%s: read %d bytes\n", progname, size + n - BUFSIZE));
-
     /* check output file */
     if (output) {
         fid = fopen (output, "w");
@@ -218,10 +256,13 @@ int main (int argc, char *argv[])
 
     /* main process */
     int rc = process (buffer, size, fid);
-    VERBOSE (INFO, fprintf (stdout, "\nmemory:"); int _i; for (_i = 0; _i < MEMSIZE; _i++) fprintf (stdout," %d", mem[_i]); fprintf (stdout,"\n"));
 
     /* close output file */
-    fclose (fid);
+    if (fid != stdout) {
+        fclose (fid);
+    }
+
+    VERBOSE (INFO, fprintf (stdout, "\nmemory:"); int _i; for (_i = 0; _i < MEMSIZE; _i++) fprintf (stdout," %d", mem[_i]); fprintf (stdout,"\n"));
 
     return rc;
 }
@@ -230,11 +271,17 @@ int main (int argc, char *argv[])
 // test: bf.exe -h | awk '/usage:/ { rc=1 } END { exit (1-rc) }'
 // test: bf.exe -_ 2> /dev/null | awk 'END { if (NR == 0) { exit(0) } else exit (1) }'
 // test: bf.exe -_ 2>&1 | awk '/usage:/ { rc=1 } END { exit (1-rc) }'
+// test: bf.exe -i error.b 2>&1 | grep "can't open" | grep -q "reading"
+// test: echo ">>." | bf.exe -o error/error.b 2>&1 | grep "can't open" | grep -q "writing"
+// test: echo '+++>++>>-<--' | bf.exe -v2 | grep -q "memory: 3 2 -2 -1 0"
+// test: bf.exe -e '+++>++>>-<--' -v2 | grep -q "memory: 3 2 -2 -1 0"
+// test: bf.exe -m "51 50 49" -e '.>.>.' |grep -q "321"
 // test: echo '++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.' | bf.exe -v1 | grep -q "Hello World!"
 // test: echo '++++++++++[>+>+++>+++++++>++++++++++<<<<-]>>>++++++++++++++.>+++++++++++++++++.<<++.>+++++++++++++.>--.<<.>+++.+.--.>----.++++++.+.<++.>----.++.<<.>>+.-------.<<.>>++.<.>+++++.<<.>-.+.<.>---.>---.<-.++++++++.>----.<---.>+++++++.<---.++++++++.' | bf.exe -v1 | grep -q "Tu as decouvert un peu de brainfuck"
-// test: echo ',4>++++++[<-------->-],3[<+>-]<.' | bf.exe -v1 | grep -q 7
-
-// test: echo ',3>,2>>++++++++++++++++[-<+++<---<--->>>]<<[<[>>+>+<<<-]>>>[<<<+>>>-]<<-]>.' | bf.exe -v1 | grep -q 6
-// test: echo ',3>,2[->>+<<]+<[->>>[>>>>>+<<<<<->+<<]<[>]>>>>>[-<<->>>>>>>]<[>]<<<<<<]>[>>>>->]<<<<<<[-]>[-]>>[-]>.' | bf.exe -v1 | grep -q 3
+// test: echo -e "123\0" | bf.exe -e ',[>,]' -v2 | grep -q "memory: 49 50 51 0"
+// test: echo -e "4+3\0" | bf.exe -e ',>++++++[<-------->-],,[<+>-]<.' -v1 | grep -q 7
+// test: echo -e "1+7\0" | bf.exe -e ',>++++++[<-------->-],,[<+>-]<.' -v1 | grep -q 8
+// test: echo -e "3*2\0" | bf.exe -e ',>,,>++++++++[<------<------>>-]<<[>[>+>+<<-]>>[<<+>>-]<<<-]>>>++++++[<++++++++>-]<.' -v1 | grep -q 6
+// test: echo -e "1*7\0" | bf.exe -e ',>,,>++++++++[<------<------>>-]<<[>[>+>+<<-]>>[<<+>>-]<<<-]>>>++++++[<++++++++>-]<.' -v1 | grep -q 7
 
 /* vim: set ts=4 sw=4 et: */