/* cflags: */
/* linker: debug.o */
-#include <assert.h>
+#include <errno.h>
#include <getopt.h>
#include <malloc.h>
#include <stdio.h>
/* macros */
#define BUFSIZE 256
+#define MAXJUMP 4
#define MEMSIZE 10
/* type definition */
char *progname = NULL;
int p = 0;
char mem[MEMSIZE] = {0};
+int j = 0;
+int jump[MAXJUMP] = {0};
/* help function */
int usage (int ret)
{
FILE *fd = ret ? stderr : stdout;
- fprintf (fd, "usage: %s [-i file] [-h] [-m k&r|ansi|c99] [-o file] [-v]\n", progname);
+ fprintf (fd, "usage: %s [-i file] [-h] [-m memory] [-o file] [-v]\n", progname);
fprintf (fd, " -i : input file\n");
fprintf (fd, " -h : help message\n");
- fprintf (fd, " -m : indent mode\n");
+ fprintf (fd, " -m : memory [0..0]\n");
fprintf (fd, " -o : output file\n");
fprintf (fd, " -v : verbose level (%d)\n", verbose);
return ret;
}
+/* main process */
+
+int process (char *buffer, int nb, FILE *out) {
+ int 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"));
+
+ switch (buffer[i]) {
+ case '>': /* increase pointer */
+ p++;
+ break;
+ case '<': /* decrease pointer */
+ p--;
+ break;
+ case '+': /* increase pointer value */
+ if ((p >= 0) && (p < MEMSIZE)) {
+ mem[p]++;
+ } else {
+ VERBOSE (ERROR, fprintf (stderr, "%s: invalid address (%d)\n", progname, p));
+ return 1;
+ }
+ break;
+ case '-': /* decrease pointer value */
+ if ((p >= 0) && (p < MEMSIZE)) {
+ mem[p]--;
+ } else {
+ VERBOSE (ERROR, fprintf (stderr, "%s: invalid address (%d)\n", progname, p));
+ return 1;
+ }
+ break;
+ case '.': /* output pointer value */
+ if ((p >= 0) && (p < MEMSIZE)) {
+ fprintf (out, "%c", mem[p]);
+ } else {
+ VERBOSE (ERROR, fprintf (stderr, "%s: invalid address (%d)\n", progname, p));
+ return 1;
+ }
+ break;
+ case ',': /* read a byte and store it in memory */
+ if ((p >= 0) && (p < MEMSIZE)) {
+ 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)) {
+ bracket += (buffer[i] == '[') ? +1 : (buffer[i] == ']') ? -1 :0;
+ }
+ if (bracket) {
+ VERBOSE (ERROR, fprintf (stderr, "%s: brace not closed\n", progname));
+ return 1;
+ }
+ i--;
+ } else {
+ 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 (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;
+ default:
+ VERBOSE (WARNING, fprintf (stderr, "%s: can't understand '%c'\n", progname, buffer[i]));
+ }
+
+ //VERBOSE (DEBUG, int _i; fprintf (stderr, "%s: p: %d mem:", progname, p); for (_i = 0; _i < MEMSIZE; _i++) fprintf (stderr, " %d", mem[_i]); fprintf (stderr, "\n"));
+
+ }
+
+ return 0;
+}
+
/* main function */
int main (int argc, char *argv[])
char *input = NULL;
char *output = NULL;
char *buffer = NULL;
+ int i;
int n = 0;
int size = 0;
FILE *fid = NULL;
}
int c;
- while ((c = getopt(argc, argv, "i: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;
+ case 'm':
+ for (i = 0; i < MEMSIZE; i++) {
+ if (optarg) {
+ mem[i] = strtol (optarg, &optarg, 10);
+ VERBOSE (DEBUG, fprintf (stderr, "%s: mem[%d] = %d\n", progname, i, mem[i]));
+ }
+ }
+ if (*optarg != 0) {
+ VERBOSE (WARNING, fprintf (stderr, "%s: too many memory values or incorrect value\n", progname));
+ return 1;
+ }
+ break;
case 'o':
output = optarg;
break;
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");
if (fid == NULL) {
VERBOSE (ERROR, fprintf (stderr, "%s: can't open file '%s' for writing\n", progname, output));
+ if (buffer) free (buffer);
return 1;
}
} else {
int rc = process (buffer, size, fid);
/* close output file */
- fclose (fid);
-
- return rc;
-}
-
-/* main process */
-int process (char *buffer, int nb, FILE *out) {
- int i;
-
- for (i = 0; (i < nb) && (buffer[i] != 0); i++) {
-
- VERBOSE (DEBUG, fprintf (stderr, "%s: read '%c' (%u)\n", progname, buffer[i], buffer[i]));
- switch (buffer[i]) {
- case '>': /* increase pointer */
- p++;
- break;
- case '<': /* decrease pointer */
- p--;
- break;
- case '+': /* increase pointer value */
- if ((p >= 0) && (p < MEMSIZE)) {
- mem[p]++;
- } else {
- VERBOSE (ERROR, fprintf (stderr, "%s: invalid address (%d)\n", progname, p));
- return 1;
- }
- break;
- case '-': /* decrease pointer value */
- if ((p >= 0) && (p < MEMSIZE)) {
- mem[p]--;
- } else {
- VERBOSE (ERROR, fprintf (stderr, "%s: invalid address (%d)\n", progname, p));
- return 1;
- }
- break;
- case '.': /* output pointer value */
- if ((p >= 0) && (p < MEMSIZE)) {
- fprintf (out, "%c", mem[p]);
- } else {
- VERBOSE (ERROR, fprintf (stderr, "%s: invalid address (%d)\n", progname, p));
- return 1;
- }
- break;
- case ',': /* read a byte and store it in memory */
- if ((p >= 0) && (p < MEMSIZE)) {
- mem[p] = buffer[++i];
- } 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 (mem[p] == 0) {
- int bracket = 1;
- while ((++i < nb) && (bracket > 0)) {
- bracket += (buffer[i] == '[') ? +1 : (buffer[i] == ']') ? -1 :0;
- }
- if (bracket) {
- VERBOSE (ERROR, fprintf (stderr, "%s: brace not closed\n", progname));
- return 1;
- }
- } else {
- return process (buffer + i + 1, nb - i - 1, out);
- }
- break;
- case ']': /* jump to left bracket if pointer is different to 0 */
- if (mem[p] != 0) {
- i = -1;
- }
- break;
- case '\n':
- case '\r':
- break;
- default:
- VERBOSE (WARNING, fprintf (stderr, "%s: can't understand '%c'\n", progname, buffer[i]));
- }
-
- //VERBOSE (DEBUG, int _i; fprintf (stderr, "%s: p: %d mem:", progname, p); for (_i = 0; _i < MEMSIZE; _i++) fprintf (stderr, " %d", mem[_i]); fprintf (stderr, "\n"));
+ if (fid != stdout) {
+ fclose (fid);
+ }
+ /* free buffer */
+ if (buffer) {
+ free (buffer);
}
- return 0;
+ VERBOSE (INFO, fprintf (stdout, "\nmemory:"); int _i; for (_i = 0; _i < MEMSIZE; _i++) fprintf (stdout," %d", mem[_i]); fprintf (stdout,"\n"));
+
+ return rc;
}
// test: bf.exe -h
// 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: echo '++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.' | bf.exe
-// test: echo '++++++++++[>+>+++>+++++++>++++++++++<<<<-]>>>++++++++++++++.>+++++++++++++++++.<<++.>+++++++++++++.>--.<<.>+++.+.--.>----.++++++.+.<++.>----.++.<<.>>+.-------.<<.>>++.<.>+++++.<<.>-.+.<.>---.>---.<-.++++++++.>----.<---.>+++++++.<---.++++++++.' | bf.exe
-// test: echo ',3>,2>>++++++++++++++++[-<+++<---<--->>>]<<[<[>>+>+<<<-]>>>[<<<+>>>-]<<-]>.' | bf.exe
+// test: bf.exe error 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 "error" | bf.exe -v1 2>&1 | grep -q "can't understand"
+// test: echo "<+" | bf.exe -v1 2>&1 | grep -q "invalid address"
+// test: echo "<-" | bf.exe -v1 2>&1 | grep -q "invalid address"
+// test: echo "<." | bf.exe -v1 2>&1 | grep -q "invalid address"
+// test: echo "<," | bf.exe -v1 2>&1 | grep -q "invalid address"
+// test: echo "<[" | bf.exe -v1 2>&1 | grep -q "invalid address"
+// test: echo "[" | bf.exe -v1 2>&1 | grep -q "brace not closed"
+// test: echo "+[[[[[]]]]]" | bf.exe -v1 2>&1 | grep -q "too many jump"
+// test: bf.exe -m "0 1 2 3 4 5 6 7 8 9 10" -e '.' -v1 2>&1 | grep -q "too many memory values"
+// test: bf.exe -m "0 error" -e '.' -v1 2>&1 | grep -q "incorrect value"
+// test: echo "]" | bf.exe -v1 2>&1 | grep -q "can't jump back"
+
+// test: echo '+++>++>>-<--' | bf.exe -v2 | grep -q "memory: 3 2 -2 -1 0"
+// test: bf.exe -e '+++' -e '+++>++>>-<--' -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: bf.exe -m "51 50 49" -e '.>.>.' -o test.log && grep -q "321" test.log; rc=$?; rm test.log; test $rc -eq 0
+// test: echo '+++>++>>-<--' > test.b | bf.exe -i test.b | grep -q "memory: 3 2 -2 -1 0"; rc=$?; rm test.b; test $rc -eq 0
+
+// 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 -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: */