8400309140f4b205cce4101099a1c679a45e4913
22 #define CHECKALLOC(ptr) \
24 if ((ptr) == NULL) { \
25 VERBOSE (ERROR, fprintf (stderr, "can't get enough memory for '%s'\n", #ptr)); \
34 char *progname
= NULL
;
36 signed char mem
[MEMSIZE
] = {0};
38 int jump
[MAXJUMP
] = {0};
44 FILE *fd
= ret
? stderr
: stdout
;
45 fprintf (fd
, "usage: %s [-i file] [-h] [-m memory] [-o file] [-v]\n", progname
);
46 fprintf (fd
, " -i : input file\n");
47 fprintf (fd
, " -h : help message\n");
48 fprintf (fd
, " -m : memory [0..0]\n");
49 fprintf (fd
, " -o : output file\n");
50 fprintf (fd
, " -v : verbose level (%d)\n", verbose
);
57 int process (char *buffer
, int nb
, FILE *out
) {
59 for (int i
= 0; i
< nb
; i
++) {
64 VERBOSE (DEBUG
, fprintf (stderr
, "%s: p=%d, buffer='%s', memory=[ ", progname
, p
, buffer
+ i
); for (int _i
= 0; _i
< MEMSIZE
; _i
++) fprintf (stderr
," %d", mem
[_i
]); fprintf (stderr
," ]\n"));
67 case '>': /* increase pointer */
70 case '<': /* decrease pointer */
73 case '+': /* increase pointer value */
74 if ((p
>= 0) && (p
< MEMSIZE
)) {
77 VERBOSE (ERROR
, fprintf (stderr
, "%s: invalid address (%d)\n", progname
, p
));
81 case '-': /* decrease pointer value */
82 if ((p
>= 0) && (p
< MEMSIZE
)) {
85 VERBOSE (ERROR
, fprintf (stderr
, "%s: invalid address (%d)\n", progname
, p
));
89 case '.': /* output pointer value */
90 if ((p
>= 0) && (p
< MEMSIZE
)) {
91 fprintf (out
, "%c", mem
[p
]);
93 VERBOSE (ERROR
, fprintf (stderr
, "%s: invalid address (%d)\n", progname
, p
));
97 case ',': /* read a byte and store it in memory */
98 if ((p
>= 0) && (p
< MEMSIZE
)) {
100 mem
[p
] = (c
> 0) ? c
: 0;
102 VERBOSE (ERROR
, fprintf (stderr
, "%s: invalid address (%d)\n", progname
, p
));
106 case '[': /* jump to right bracket if pointer is set to 0 */
107 if ((p
< 0) || (p
>= MEMSIZE
)) {
108 VERBOSE (ERROR
, fprintf (stderr
, "%s: invalid address (%d)\n", progname
, p
));
113 while ((++i
< nb
) && (bracket
> 0)) {
114 bracket
+= (buffer
[i
] == '[') ? +1 : (buffer
[i
] == ']') ? -1 :0;
117 VERBOSE (ERROR
, fprintf (stderr
, "%s: brace not closed\n", progname
));
123 VERBOSE (ERROR
, fprintf (stderr
, "%s: too many jump\n", progname
));
129 case ']': /* jump to left bracket if pointer is different to 0 */
131 VERBOSE (ERROR
, fprintf (stderr
, "%s: can't jump back\n", progname
));
142 VERBOSE (WARNING
, fprintf (stderr
, "%s: can't understand '%c'\n", progname
, buffer
[i
]));
145 //VERBOSE (DEBUG, fprintf (stderr, "%s: p: %d mem:", progname, p); for (int _i = 0; _i < MEMSIZE; _i++) fprintf (stderr, " %d", mem[_i]); fprintf (stderr, "\n"));
154 int main (int argc
, char *argv
[])
164 char *pt
= progname
= argv
[0];
166 if ((*pt
== '/') || (*pt
== '\\')) {
173 while ((c
= getopt(argc
, argv
, "e:i:m:o:hv:")) != EOF
) {
177 buffer
= strdup (optarg
);
179 size
= strlen (buffer
) + 1;
185 for (int i
= 0; i
< MEMSIZE
; i
++) {
187 mem
[i
] = strtol (optarg
, &optarg
, 10);
188 VERBOSE (DEBUG
, fprintf (stderr
, "%s: mem[%d] = %d\n", progname
, i
, mem
[i
]));
192 VERBOSE (WARNING
, fprintf (stderr
, "%s: too many memory values or incorrect value\n", progname
));
201 verbose
= atoi (optarg
);
206 return usage (c
!= 'h');
209 if (argc
- optind
!= 0) {
210 VERBOSE (ERROR
, fprintf (stderr
, "%s: invalid option -- %s\n", progname
, argv
[optind
]));
215 /* check input file */
217 fid
= fopen (input
, "r");
219 VERBOSE (ERROR
, fprintf (stderr
, "%s: can't open file '%s' for reading\n", progname
, input
));
223 } else if (buffer
== NULL
) {
227 /* read input file */
229 while (!feof (fid
)) {
230 buffer
= (char *) realloc (buffer
, size
+ BUFSIZE
);
232 memset (buffer
+ size
, 0, BUFSIZE
);
233 n
= fread (buffer
+ size
, 1, BUFSIZE
, fid
);
235 VERBOSE (ERROR
, fprintf (stderr
, "%s: can't read data from file '%s'\n", progname
, input
));
248 VERBOSE (DEBUG
, fprintf (stderr
, "%s: read %d bytes\n", progname
, size
+ n
- BUFSIZE
));
250 VERBOSE (DEBUG
, fprintf (stderr
, "%s: prog %d bytes\n", progname
, size
-1));
253 /* check output file */
255 fid
= fopen (output
, "w");
257 VERBOSE (ERROR
, fprintf (stderr
, "%s: can't open file '%s' for writing\n", progname
, output
));
266 int rc
= process (buffer
, size
, fid
);
268 /* close output file */
274 VERBOSE (INFO
, fprintf (stdout
, "\nmemory:"); for (int _i
= 0; _i
< MEMSIZE
; _i
++) fprintf (stdout
," %d", (int)mem
[_i
]); fprintf (stdout
,"\n"));
281 // test: bf.exe -h | awk '/usage:/ { rc=1 } END { exit (1-rc) }'
283 // test: bf.exe -_ 2> /dev/null | awk 'END { if (NR == 0) { exit(0) } else exit (1) }'
284 // test: bf.exe -_ 2>&1 | awk '/usage:/ { rc=1 } END { exit (1-rc) }'
285 // test: bf.exe error 2>&1 | awk '/usage:/ { rc=1 } END { exit (1-rc) }'
287 // test: bf.exe -i error.b 2>&1 | grep "can't open" | grep -q "reading"
288 // test: echo ">>." | bf.exe -o error/error.b 2>&1 | grep "can't open" | grep -q "writing"
289 // test: echo "error" | bf.exe -v1 2>&1 | grep -q "can't understand"
290 // test: echo "<+" | bf.exe -v1 2>&1 | grep -q "invalid address"
291 // test: echo "<-" | bf.exe -v1 2>&1 | grep -q "invalid address"
292 // test: echo "<." | bf.exe -v1 2>&1 | grep -q "invalid address"
293 // test: echo "<," | bf.exe -v1 2>&1 | grep -q "invalid address"
294 // test: echo "<[" | bf.exe -v1 2>&1 | grep -q "invalid address"
295 // test: echo "[" | bf.exe -v1 2>&1 | grep -q "brace not closed"
296 // test: echo "+[[[[[]]]]]" | bf.exe -v1 2>&1 | grep -q "too many jump"
297 // 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"
298 // test: bf.exe -m "0 error" -e '.' -v1 2>&1 | grep -q "incorrect value"
299 // test: echo "]" | bf.exe -v1 2>&1 | grep -q "can't jump back"
301 // test: echo '+++>++>>-<--' | bf.exe -v2 | grep -q "memory: 3 2 -2 -1 0"
302 // test: bf.exe -e '+++' -e '+++>++>>-<--' -v2 | grep -q "memory: 3 2 -2 -1 0"
303 // test: bf.exe -e '+++>++>>-<--' -v2 | grep -q "memory: 3 2 -2 -1 0"
304 // test: bf.exe -m "51 50 49" -e '.>.>.' |grep -q "321"
305 // test: bf.exe -m "51 50 49" -e '.>.>.' -o test.log && grep -q "321" test.log; rc=$?; rm test.log; test $rc -eq 0
306 // 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
308 // test: echo '++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.' | bf.exe -v1 | grep -q "Hello World!"
309 // test: echo '++++++++++[>+>+++>+++++++>++++++++++<<<<-]>>>++++++++++++++.>+++++++++++++++++.<<++.>+++++++++++++.>--.<<.>+++.+.--.>----.++++++.+.<++.>----.++.<<.>>+.-------.<<.>>++.<.>+++++.<<.>-.+.<.>---.>---.<-.++++++++.>----.<---.>+++++++.<---.++++++++.' | bf.exe -v1 | grep -q "Tu as decouvert un peu de brainfuck"
311 // test: echo -e "123\0" | bf.exe -e ',[>,]' -v2 | grep -q "memory: 49 50 51 0"
312 // test: echo -e "4+3\0" | bf.exe -e ',>++++++[<-------->-],,[<+>-]<.' -v1 | grep -q 7
313 // test: echo -e "1+7\0" | bf.exe -e ',>++++++[<-------->-],,[<+>-]<.' -v1 | grep -q 8
314 // test: echo -e "3*2\0" | bf.exe -e ',>,,>++++++++[<------<------>>-]<<[>[>+>+<<-]>>[<<+>>-]<<<-]>>>++++++[<++++++++>-]<.' -v1 | grep -q 6
315 // test: echo -e "1*7\0" | bf.exe -e ',>,,>++++++++[<------<------>>-]<<[>[>+>+<<-]>>[<<+>>-]<<<-]>>>++++++[<++++++++>-]<.' -v1 | grep -q 7
317 /* vim: set ts=4 sw=4 et: */