bfck

Brainfuck interpreter with breakpoint support
git clone https://noxz.tech/git/bfck.git
Log | Files

bfck.c
1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4#include <ncurses.h>
5
6#define ALLOCATION_SIZE 1024
7#define BETWEEN(x, a, b)  (((x) >= (a)) && ((x) <= (b)))
8
9static unsigned char *cols;
10static char *bf;
11
12void
13allocate(int alc)
14{
15    size_t s = ALLOCATION_SIZE * (alc + 1);
16    char *new;
17
18    if ((new = calloc(s, sizeof(char))) == NULL)
19    memset(new, 0, s * sizeof(char));
20    memmove(new, cols, (ALLOCATION_SIZE * alc));
21
22    free(cols);
23    cols = new;
24}
25
26void
27run()
28{
29    int i, j, l, x;
30    int idx = 0,    /* index of column */
31        pos = 0,    /* possitiong in debug */
32        beg = 0,    /* begining in debug */
33        alc = 1,    /* allocation count */
34        lix = 0;    /* loop index */
35    char ch = 0;
36
37    cols = calloc(ALLOCATION_SIZE, sizeof(char));
38    memset(cols, 0, ALLOCATION_SIZE * sizeof(char));
39
40    /* remove non-brainfuck */
41    for (i = j = 0, l = strlen(bf); i < l; i++)
42        if (strchr("[]<>+-,.!", bf[i]))
43            bf[j++] = bf[i];
44    bf[(l = j)] = 0;
45
46    for (i = 0; i < l; i++) {
47        switch (bf[i]) {
48        case '>':
49            /* check if more columns are needed */
50            if (idx++ >= (ALLOCATION_SIZE * alc) - 1)
51                allocate(alc++);
52            break;
53        case '<':
54            if (idx <= 0)
55                break;
56            idx--;
57            break;
58        case '[':
59            /* skip if zero */
60            if (cols[idx] == 0) {
61                for (x = 0, i++; i < l; i++) {
62                    if (bf[i] == '[')
63                        x++;
64                    else if (bf[i] == ']' && x > 0)
65                        x--;
66                    else if (bf[i] == ']')
67                        break;
68                }
69                break;
70            }
71            lix++;
72            break;
73        case ']':
74            /* go back if not zero */
75            if (cols[idx] != 0) {
76                for (x = 0, j = i - 1; j > 0; j--) {
77                    if (bf[j] == ']')
78                        x++;
79                    else if (bf[j] == '[' && x > 0)
80                        x--;
81                    else if (bf[j] == '[')
82                        break;
83                }
84                i = j;  /* jump to beginning */
85                break;
86            }
87            lix--;      /* leave loop */
88            break;
89        case '+':
90            if (cols[idx] < 255)
91                cols[idx]++;
92            break;
93        case '-':
94            if (cols[idx] > 0)
95                cols[idx]--;
96            break;
97        case '.':
98            putchar(cols[idx]);
99            break;
100        case ',':
101            cols[idx] = getchar();
102            break;
103        case '!':
104            initscr();
105            cbreak();
106            noecho();
107
108            for (pos = idx;;) {
109                clear();
110
111                if (ch == 0x1B)
112                    break;
113                else if (ch == 0x68 && pos > 0)
114                    pos--;
115                else if (ch == 0x6C && pos < alc * ALLOCATION_SIZE)
116                    pos++;
117                else if (ch == 0x6A && cols[pos] > 0)
118                    cols[pos]--;
119                else if (ch == 0x6B && cols[pos] < 255)
120                    cols[pos]++;
121
122                beg = pos < 5 ? 0 : pos - 5;
123                if (beg > (alc * ALLOCATION_SIZE - 10))
124                    beg = alc * ALLOCATION_SIZE - 10;
125
126                printw("breakpoint: %d\n\n\n", i);
127
128                if ((beg - idx) < 0)
129                    printw("%*s!\n", (beg - idx) * 4 - 1, " ");
130                else
131                    printw("\n");
132
133                for (int p = beg; p < beg + 11; p++)
134                    cols[p] < 10 \
135                    ? printw(" %-2d ", cols[p]) \
136                    : printw("%-3d ", cols[p]);
137                printw("\n");
138
139                for (int p = beg; p < beg + 11; p++)
140                    printw("[%c] ",
141                        BETWEEN(cols[p], 32, 126) ? cols[p] : ' ');
142                printw("\n");
143
144                printw("%*s^\n",
145                    (pos - beg != 5 ? (pos - beg) : 5) * 4 + 1, " ");
146                pos < 10 \
147                ? printw("%*s%d\n",
148                    (pos - beg != 5 ? (pos - beg) : 5) * 4 + 1, " ", pos) \
149                : printw("%*s%d\n",
150                    (pos - beg != 5 ? (pos - beg) : 5) * 4 + 0, " ", pos);
151
152                printw("\n         press [ESC] to continue...\n");
153                ch = getch();
154            }
155
156            refresh();
157            endwin();
158            break;
159        }
160    }
161    free(cols);
162    free(bf);
163}
164
165void
166load(const char *fn)
167{
168    int b, n = 0;
169    char buf[1024];
170    FILE *f = NULL;
171
172    if (!(f = fopen(fn, "r")))
173        exit(0);
174
175    while (!feof(f)) {
176        b = fread(buf, 1, sizeof buf, f);
177        if (!(bf = (char *)realloc(bf, (n += b) + 1)))
178            exit(1);
179        memcpy(bf + n - b, buf, b);
180    }
181    fclose(f);
182}
183
184int
185main(int argc, char *argv[])
186{
187    load(argv[1]);
188    run();
189}