bfck

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

commit: 36fae0a9fab3e39356f26cd136b3874f98ac56bf
parent: 
author: Chris Noxz <chris@noxz.tech>
date:   Sat, 14 Sep 2019 19:41:40 +0200
Initial commit of bfck (brainfuck interpreter with break support)
Abfck.c189++++++++++++++++++++
1 file changed, 189 insertions(+)
diff --git a/bfck.c b/bfck.c
@@ -0,0 +1,189 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ncurses.h>
+
+#define ALLOCATION_SIZE 1024
+#define BETWEEN(x, a, b)  (((x) >= (a)) && ((x) <= (b)))
+
+static unsigned char *cols;
+static char *bf;
+
+void
+allocate(int alc)
+{
+    size_t s = ALLOCATION_SIZE * (alc + 1);
+    char *new;
+
+    if ((new = calloc(s, sizeof(char))) == NULL)
+    memset(new, 0, s * sizeof(char));
+    memmove(new, cols, (ALLOCATION_SIZE * alc));
+
+    free(cols);
+    cols = new;
+}
+
+void
+run()
+{
+    int i, j, l, x;
+    int idx = 0,    /* index of column */
+        pos = 0,    /* possitiong in debug */
+        beg = 0,    /* begining in debug */
+        alc = 1,    /* allocation count */
+        lix = 0;    /* loop index */
+    char ch = 0;
+
+    cols = calloc(ALLOCATION_SIZE, sizeof(char));
+    memset(cols, 0, ALLOCATION_SIZE * sizeof(char));
+
+    /* remove non-brainfuck */
+    for (i = j = 0, l = strlen(bf); i < l; i++)
+        if (strchr("[]<>+-,.!", bf[i]))
+            bf[j++] = bf[i];
+    bf[(l = j)] = 0;
+
+    for (i = 0; i < l; i++) {
+        switch (bf[i]) {
+        case '>':
+            /* check if more columns are needed */
+            if (idx++ >= (ALLOCATION_SIZE * alc) - 1)
+                allocate(alc++);
+            break;
+        case '<':
+            if (idx <= 0)
+                break;
+            idx--;
+            break;
+        case '[':
+            /* skip if zero */
+            if (cols[idx] == 0) {
+                for (x = 0, i++; i < l; i++) {
+                    if (bf[i] == '[')
+                        x++;
+                    else if (bf[i] == ']' && x > 0)
+                        x--;
+                    else if (bf[i] == ']')
+                        break;
+                }
+                break;
+            }
+            lix++;
+            break;
+        case ']':
+            /* go back if not zero */
+            if (cols[idx] != 0) {
+                for (x = 0, j = i - 1; j > 0; j--) {
+                    if (bf[j] == ']')
+                        x++;
+                    else if (bf[j] == '[' && x > 0)
+                        x--;
+                    else if (bf[j] == '[')
+                        break;
+                }
+                i = j;  /* jump to beginning */
+                break;
+            }
+            lix--;      /* leave loop */
+            break;
+        case '+':
+            if (cols[idx] < 255)
+                cols[idx]++;
+            break;
+        case '-':
+            if (cols[idx] > 0)
+                cols[idx]--;
+            break;
+        case '.':
+            putchar(cols[idx]);
+            break;
+        case ',':
+            cols[idx] = getchar();
+            break;
+        case '!':
+            initscr();
+            cbreak();
+            noecho();
+
+            for (pos = idx;;) {
+                clear();
+
+                if (ch == 0x1B)
+                    break;
+                else if (ch == 0x68 && pos > 0)
+                    pos--;
+                else if (ch == 0x6C && pos < alc * ALLOCATION_SIZE)
+                    pos++;
+                else if (ch == 0x6A && cols[pos] > 0)
+                    cols[pos]--;
+                else if (ch == 0x6B && cols[pos] < 255)
+                    cols[pos]++;
+
+                beg = pos < 5 ? 0 : pos - 5;
+                if (beg > (alc * ALLOCATION_SIZE - 10))
+                    beg = alc * ALLOCATION_SIZE - 10;
+
+                printw("breakpoint: %d\n\n\n", i);
+
+                if ((beg - idx) < 0)
+                    printw("%*s!\n", (beg - idx) * 4 - 1, " ");
+                else
+                    printw("\n");
+
+                for (int p = beg; p < beg + 11; p++)
+                    cols[p] < 10 \
+                    ? printw(" %-2d ", cols[p]) \
+                    : printw("%-3d ", cols[p]);
+                printw("\n");
+
+                for (int p = beg; p < beg + 11; p++)
+                    printw("[%c] ",
+                        BETWEEN(cols[p], 32, 126) ? cols[p] : ' ');
+                printw("\n");
+
+                printw("%*s^\n",
+                    (pos - beg != 5 ? (pos - beg) : 5) * 4 + 1, " ");
+                pos < 10 \
+                ? printw("%*s%d\n",
+                    (pos - beg != 5 ? (pos - beg) : 5) * 4 + 1, " ", pos) \
+                : printw("%*s%d\n",
+                    (pos - beg != 5 ? (pos - beg) : 5) * 4 + 0, " ", pos);
+
+                printw("\n         press [ESC] to continue...\n");
+                ch = getch();
+            }
+
+            refresh();
+            endwin();
+            break;
+        }
+    }
+}
+
+void
+load(const char *fn)
+{
+    int b, n = 0;
+    char buf[1024], *p = 0;
+    FILE *f = NULL;
+
+    if (!(f = fopen(fn, "r")))
+        exit(0);
+
+    while (!feof(f)) {
+        b = fread(buf, 1, sizeof buf, f);
+        if (!(p = (char *)realloc(p, (n += b) + 1)))
+            exit(1);
+        memcpy(p + n - b, buf, b);
+    }
+    fclose(f);
+    bf = p;
+}
+
+int
+main(int argc, char *argv[])
+{
+    load(argv[1]);
+    run();
+    free(cols);
+}