af9f00118aba6a74c3ea0332fa26105e4cd6475b
[bf.git] / bf.c
1 #include <stdlib.h>
2 #include <string.h>
3 #include <stdio.h>
4 #include <errno.h>
5
6 #define die(s, as...) {fprintf(stderr, s, ## as); return EXIT_FAILURE;}
7 #define check_fail(v, s, f) if((v) == f) die("%s(): %s\n", s, strerror(errno))
8 #define check_null(v, s) check_fail(v, s, NULL)
9
10 #define INITIALBUFSIZE 2
11
12 struct nest {
13 long pos;
14 struct nest *next;
15 };
16
17 int main(int argc, char *argv[])
18 {
19 size_t offset, stacksize, depth;
20 char *buf, *ptr;
21 struct nest *temp, *stack;
22 FILE *in;
23
24 if(argc != 2){
25 die("Usage: %s PROGRAM\n", argv[0]);
26 }
27
28 check_null(in = fopen(argv[1], "r"), "fopen");
29 check_null(buf = calloc(stacksize = INITIALBUFSIZE, 1), "calloc");
30 ptr = buf;
31
32 while(1){
33 switch(fgetc(in)){
34 case EOF:
35 free(buf);
36 check_fail(fclose(in), "fclose", -1);
37 return EXIT_SUCCESS;
38 case '>':
39 if(++ptr >= buf+stacksize){
40 offset = ptr-buf;
41 check_null(buf = realloc(buf, stacksize *=2), "realloc");
42 ptr = buf+offset;
43 memset(ptr, 0, stacksize/2);
44 }
45 break;
46 case '<':
47 if(ptr-- == buf){
48 die("There is no stack position -1\n");
49 }
50 break;
51 case '+':
52 ++*ptr;
53 break;
54 case '-':
55 --*ptr;
56 break;
57 case '.':
58 putchar(*ptr);
59 break;
60 case ',':
61 *ptr = getchar();
62 break;
63 case '[':
64 if(*ptr){
65 temp = stack;
66 check_null(stack = malloc(sizeof(struct nest)), "malloc");
67 stack->next = temp;
68 check_fail(stack->pos = ftell(in), "ftell", -1);
69 } else {
70 depth = 1;
71 while(depth > 0){
72 switch(fgetc(in)){
73 case ']':
74 depth--;
75 break;
76 case '[':
77 depth++;
78 }
79 }
80 }
81 break;
82 case ']':
83 check_fail(fseek(in, stack->pos-1, SEEK_SET), "fseek", -1);
84 temp = stack;
85 stack = stack->next;
86 free(temp);
87 }
88 }
89 }