User:Rdebath/deadbeef

From Esolang
Jump to navigation Jump to search

Small and fast Brainfuck interpreter

This interpreter uses byte cells and Ansi-C89. It does use the POSIX limits.h header but this can be easily substituted. It currently out performs all but four or five pure interpreters, however, C and assembler/JIT generators should be a lot faster. (But some of them aren't!)

This means that it's performance is still an order of magnitude below a really fast brainfuck interpreter.

/* This is the deadbeef brainfuck interpreter.
 *
 * Robert de Bath (2014/2015).
 * Released into the public domain.
 * Alternatively you may consider it released under the CC0
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>

void run(void);
struct bfi { int mov; int cmd; int arg; } *pgm = 0;
int pgmlen = 0, on_eof = 1, debug = 0;

int main(int argc, char **argv)
{
   FILE * ifd;
   int ch;
   int p= -1, n= -1, j= -1;
   for (;;) {
      if (argc < 2 || argv[1][0] != '-' || argv[1][1] == '\0') {
         break;
      } else if (!strcmp(argv[1], "-e")) { argc--; argv++; on_eof = -1;
      } else if (!strcmp(argv[1], "-z")) { argc--; argv++; on_eof = 0;
      } else if (!strcmp(argv[1], "-n")) { argc--; argv++; on_eof = 1;
      } else if (!strcmp(argv[1], "-d")) { argc--; argv++; debug = 1;
      } else if (argv[1][0] == '-') {
         fprintf(stderr, "Unknown option '%s'\n", argv[1]);
         exit(1);
      } else break;
   }
   ifd = argc>1&&strcmp(argv[1],"-")?fopen(argv[1],"r"):stdin;
   if(!ifd) perror(argv[1]); else {
      while((ch = getc(ifd)) != EOF && (ifd!=stdin || ch != '!' || j>=0)) {
         int r = (ch == '<' || ch == '>' || ch == '+' || ch == '-');
         if (r || (debug && ch == '#') || (ch == ']' && j>=0) ||
               ch == '[' || ch == ',' || ch == '.') {
            if (ch == '<') {ch = '>'; r = -r;}
            if (ch == '-') {ch = '+'; r = -r;}
            if (r && p>=0 && pgm[p].cmd == ch) { pgm[p].arg += r; continue; }
            if (p>=0 && pgm[p].cmd == '=' && ch == '+')
                { pgm[p].arg += r; continue; }
            if (p>=0 && pgm[p].cmd == '>') { pgm[p].mov = pgm[p].arg; }
            else {
               n++;
               if (n>= pgmlen-2) pgm = realloc(pgm, (pgmlen=n+99)*sizeof*pgm);
               if (!pgm) { perror("realloc"); exit(1); }
               pgm[n].mov = 0;
            }
            pgm[n].cmd = ch; pgm[n].arg = r; p = n;
            if (pgm[n].cmd == '[') { pgm[n].arg=j; j = n; }
            else if (pgm[n].cmd == ']') {
               pgm[n].arg = j; j = pgm[j].arg; pgm[pgm[n].arg].arg = n;
               if (  pgm[n].mov == 0 && pgm[n-1].mov == 0 &&
                     pgm[n-1].cmd == '+' && (pgm[n-1].arg&1) == 1 &&
                     pgm[n-2].cmd == '[') {
                  n -= 2; pgm[p=n].cmd = '='; pgm[n].arg = 0;
               } else if (pgm[n-1].cmd == '[') {
                  n--; pgm[p=n].cmd = '?'; pgm[n].arg = pgm[n+1].mov;
               }
            }
         }
      }
      while(j>=0) { p=j; j=pgm[j].arg; pgm[p].arg=0; pgm[p].cmd = '+'; }
      if (ifd!=stdin) fclose(ifd);
      setbuf(stdout, NULL);
      if (pgm) { pgm[n+1].cmd = 0; run(); }
   }
   return !ifd;
}

void run(void)
{
static unsigned char t[(sizeof(int)>sizeof(short))+USHRT_MAX];
   unsigned short m = 0;
   int n, ch;
   for(n=0; ; n++) {
      m += pgm[n].mov;
      switch(pgm[n].cmd)
      {
         case 0:    return;
         case '=':  t[m] = pgm[n].arg; break;
         case '+':  t[m] += pgm[n].arg; break;
         case '[':  if (t[m] == 0) n=pgm[n].arg; break;
         case ']':  if (t[m] != 0) n=pgm[n].arg; break;
         case '?':  while(t[m]) m += pgm[n].arg; break;
         case '>':  m += pgm[n].arg; break;
         case '.':  putchar(t[m]); break;
         case ',':  if((ch=getchar())!=EOF) t[m]=ch;
                    else if (on_eof != 1) t[m]=on_eof;
                    break;
         case '#':
            fprintf(stderr, "\n%3d %3d %3d %3d %3d %3d %3d %3d %3d %3d\n%*s\n",
               t[0],t[1],t[2],t[3],t[4],t[5],t[6],t[7],t[8],t[9],4*m+3,"^");
            break;
      }
   }
}