Return Styles: Pseud0ch, Terminal, Valhalla, NES, Geocities, Blue Moon. Entire thread

My first Brainfuck

Name: The Amazing Anus !Anus3nMVO2 2009-08-31 1:43

I was bored as fuck so I decided to implement a Brainfuck interpreter in C.

/* brainfuck.c ... version 0.9
 *
 * usage: brainfuck <file>
 *
 */

 
#include <stdio.h>

/* 64kb -1b each
 *
 * The Brainfuck spec says that memory should be 30000 bytes, but I prefer to
 * use a whole 64kb for both code and memory.
 *
 */
#define BRAINF_CODESIZE   65535
#define BRAINF_MEMSIZE   65535


FILE* fp;

unsigned char* code, *memory;
short unsigned int codeptr, memptr;


int main(int argc, char* argv[])
{
     if (argc != 2)
          exit(1);

     if ((fp = fopen(argv[1], "r")) == NULL)
          exit(1);

     code = malloc(BRAINF_CODESIZE);
     memory = malloc(BRAINF_MEMSIZE);

     memset(code, 0, BRAINF_CODESIZE);
     memset(memory, 0, BRAINF_MEMSIZE);

     codeptr = 0;
     memptr = 0;

     while (!feof(fp))
     {
          fread(code, BRAINF_CODESIZE -1, 1, fp);
     }


     /*** Interpreting begins ***/
     while (code[codeptr])
     {
          switch (code[codeptr])
          {
               case '>':
                    ++memptr;
                    ++codeptr;
                    break;

               case '<':
                    --memptr;
                    ++codeptr;
                    break;

               case '+':
                    ++memory[memptr];
                    ++codeptr;
                    break;

               case '-':
                    --memory[memptr];
                    ++codeptr;
                    break;

               case '.':
                    putchar(memory[memptr]);
                    ++codeptr;
                    break;

               case ',':
                    memory[memptr] = getchar();
                    ++codeptr;
                    break;

               /* :NOTE: Some kind of error handling should take
                * place if no ']' is found.
                */
               case '[':
                    if (!memory[memptr])
                    {
                         while ((code[codeptr] != ']') && (code[codeptr]))
                         {
                              ++codeptr;
                         }
                    }
                    else
                         ++codeptr;
                    break;


               /* :NOTE: Some kind of error handling should take
                * place if no '[' is found.
                */
               case ']':
                    if (memory[memptr])
                    {
                         while ((code[codeptr] != '[') && (codeptr))
                              --codeptr;
                    }
                    else
                         ++codeptr;
                    break;

               /* invalid instruction
                * For now we will just continue executing when this happens.
                * It should ignore characters 10, 13, & 32 anyways.
                */
               default:
                    ++codeptr;
                    break;
          }
     }

     free(code);
}

Name: Anonymous 2009-11-16 17:32

>>77 Why thank you, Dear! I'm very fond of you too.

Here's a version that should compile w/o any trickery.

#include <iostream>

using std::cin;
using std::cout;
using std::cerr;
using std::endl;
#define MS (65536)
struct state {
        unsigned char * tape;
        size_t head;
        static state s;
private:
        state() : tape(new unsigned char[MS]), head() {}
};
state state::s;
state & s = state::s;

template <char c, int times = 1>
struct insn {
        enum { C = c };
        enum { T = 0 };
        void operator () () const {}
};

template <typename B, typename I>
struct block : B {
        typedef B base;
        typedef I insn_;

        block() {}
        block(B const &, I const &) {}

        void operator () () const { B::operator () (); I()(); }

        block<B, insn<I::C, I::T + 1> > operator , (insn<I::C, 1> const &)
        { return block<B, insn<I::C, I::T + 1> >(); }

        template <char c>
        block<block<B, I>, insn<c> > operator , (insn<c> const & i2)
        { return block<block<B, I>, insn<c> >(*this, i2); }
};

template <>
struct block<void, void> {
        typedef void insn_;

        void operator () () const { }

        template <char c>
        block<block, insn<c> > operator , (insn<c> const & i) { return block<block, insn<c> >(*this, i); }
        static block BF;
        block(block const &) {}
        block() {}
};
block<void, void> block<void, void>::BF;
block<void, void> & BF = block<void, void>::BF;

template <typename B>
struct block<B, insn<'['> > : block<void, void> {
        typedef insn<'['> insn_;

        typedef B prev_block;

        block() {}
        block(B const &, insn<'['> const &) {}

        void operator () () const { }

        template <char c>
        block<block<B, insn<'['> >, insn<c> > operator , (insn<c> const & i2)
        { return block<block<B, insn<'['> >, insn<c> >(*this, i2); }
};

template <typename B>
struct block<B, insn<']'> > : B::prev_block {
        typedef insn<']'> insn_;

        block() {}
        block(B const &, insn<']'> const &) {}

        void operator () () const {
                B::prev_block::operator () ();
                while (s.tape[s.head])
                { B()(); }
        }

        template <char c>
        block<block<B, insn<']'> >, insn<c> > operator , (insn<c> const & i2)
        { return block<block<B, insn<']'> >, insn<c> >(*this, i2); }
};

template <int times>
struct insn<'<', times> {
        enum { C = '<' };
        enum { T = times };
        void operator () () const {
                if (s.head >= times) s.head -= times;
                else s.head = 0;
        }
};

template <int times>
struct insn<'>', times> {
        enum { C = '>' };
        enum { T = times };
        void operator () () const {
                if (s.head + times < MS) s.head += times;
                else s.head = MS - 1;
        }
};

template <int times>
struct insn<'-', times> {
        enum { C = '-' };
        enum { T = times };
        void operator () () const {
                s.tape[s.head] -= times;
        }
};

template <int times>
struct insn<'+', times> {
        enum { C = '+' };
        enum { T = times };
        void operator () () const {
                s.tape[s.head] += times;
        }
};

template <int times>
struct insn<'.', times> {
        enum { C = '.' };
        enum { T = times };
void dump(unsigned char c) const
{
        static int dotc = 155;

        if (dotc-- == 0) { cerr << "too much output" << endl; *((int*)0)=1; }

        if (c == ' ' || c == '\n' || (c >= 'A' && c <= 'z')) cout << c;
        //else cout << "ip: " << ip << " head: " << head << " depth: " << depth << ' ' << (int)c << endl;
        else cout << (int)c;
}

        void operator () () const {
                for (int i = 0; i < times; i++) dump(s.tape[s.head]);
        }
};

template <int times>
struct insn<',', times> {
        enum { C = ',' };
        enum { T = times };
        void operator () () const {
                for (int i = 0; i < times; i++) cin >> s.tape[s.head];
        }
};

template <int times>
struct insn<'[', times> {
        enum { C = '[' };
        enum { T = times };
        void operator () () const {
        }
};

template <int times>
struct insn<']', times> {
        enum { C = ']' };
        enum { T = times };
        void operator () () const {
        }
};

        insn<'<'> l;
        insn<'>'> r;
        insn<'+'> p;
        insn<'-'> m;
        insn<'.'> d;
        insn<','> c;
        insn<'['> b;
        insn<']'> e;
int main()
{
        (BF
                        BFCODE
        )();
}


Compile w/ this to get the benchmark previously mentioned:
g++ -O2 -DBFCODE=,r,p,p,b,l,p,p,p,p,p,p,p,p,p,p,p,p,p,r,m,e,l,b,b,r,p,r,p,l,l,m,e,r,b,l,p,r,m,e,p,p,p,p,p,p,p,p,b,r,p,p,p,p,p,p,p,p,l,m,e,r,d,b,m,e,l,l,r,p,p,p,p,p,p,p,p,p,p,b,r,p,p,p,p,p,p,p,p,p,p,b,r,p,p,p,p,p,p,p,p,p,p,b,r,p,p,p,p,p,p,p,p,p,p,b,r,p,p,p,p,p,p,p,p,p,p,b,r,p,p,p,p,p,p,p,p,p,p,b,r,p,p,p,p,p,p,p,p,p,p,b,m,e,l,m,e,l,m,e,l,m,e,l,m,e,l,m,e,l,m,e,l,m,e,p,p,p,p,p,p,p,p,p,p,d

I reckon there's a bug hiding somewhere in there, as it emits a different/wrong result when compiled with cl.exe, than it does when compiled with g++. (I used the 20091112 snapshot of g++-4.5.)

Newer Posts
Don't change these.
Name: Email:
Entire Thread Thread List