1. Post #1
    Gold Member
    Jallen's Avatar
    December 2007
    7,532 Posts
    Jallen's Brainfuck Interpreter
    I recently saw someone explain in a post how simple brainfuck actually was, so I wrote an interpreter for it.
    There is infinite array space as it is written in C++ and uses std::vector, so for crying out loud do not make an infinite loop which continues increasing the current index unless you want it to start using memory like mad.

    The Exe is about 17kb, and actually weiged in at about 110 lines of C++ including all the debug message stuff.
    Just drag and drop your brainfuck source files onto either executeable, the debug one has debug messages to make it a little easier to make your programs.
    http://www.mediafire.com/?23ymeeztznm

    And now a simple brainfuck introduction
    You have an array.
    You start at element 0.
    All elements are initialised to 0.
    > goes to the next element in the array (index--;).
    < goes to the previous index in the array (index++;).
    + adds one to the item you are currently on (items[index]++;)
    - subtracts one from the item you are currently on (items[index]--;)
    , takes a character from the keyboard and puts it in your currently pointed at item.
    . outputs the currently pointed at item by casting it to a char (so 65 is A).
    [ indicates the start of a loop.
    ] indicates the end of a loop.
    A loop will continue to run while the currently pointed at object is not 0.
    For more information: http://en.wikipedia.org/wiki/Brainfuck

    The test program in the archive shows how to output ABCDE using both repeated +'s and a loop.

    So yeah, enjoy programming in brainfuck, be sure to post any cool stuff you make in it, and if you are sure of a problem with the interpreter, it would be nice if you would post that also.
    Thanks for reading, and hopefully trying out my interpreter :D
    Tell me what you think :)

    NEW BUG FREE VERSION - ALLOWS LOOPS IN LOOPS AND STUFF
    http://www.mediafire.com/?zg3othmmfyj

    Includes sources :D

  2. Post #2
    Gold Member
    gparent's Avatar
    January 2005
    3,949 Posts
    Funnily enough, I wanted to write my own one in either C or C++ to practice a bit. I'll try working on it today and see how it compares.

    Good job!

  3. Post #3
    Gold Member
    BrokenGlass's Avatar
    June 2007
    189 Posts
    Haha, good job :P

  4. Post #4
    Gold Member
    Jallen's Avatar
    December 2007
    7,532 Posts
    Thanks guys.

  5. Post #5
    I survived Camp FP 2010
    Mattz333's Avatar
    June 2007
    1,658 Posts
    Any chance of getting the source so I can try this out on linux?

  6. Post #6
    Gold Member
    Xeon06's Avatar
    September 2005
    1,222 Posts
    Nice job, I wanna try making one in C#. Maybe even a pseudo-compiler for it. Oh and you're missing a right bracket in your OP at the '-' operator's definition.

  7. Post #7
    I survived Camp FP 2010
    Mattz333's Avatar
    June 2007
    1,658 Posts
    -snip-

  8. Post #8
    Gold Member
    Jallen's Avatar
    December 2007
    7,532 Posts
    Oh and you're missing a right bracket in your OP at the '-' operator's definition.
    Thanks.

  9. Post #9
    Gold Member
    gilly_54's Avatar
    June 2006
    260 Posts
    Hehe this is sweet.
    I basically ignored brainfuck because of its name...

    I want to make one too, maybe a "whitespace" interpreter

  10. Post #10
    Gold Member
    BrokenGlass's Avatar
    June 2007
    189 Posts
    Hehe this is sweet.
    I basically ignored brainfuck because of its name...

    I want to make one too, maybe a "whitespace" interpreter
    make an LOLcode one please

  11. Post #11
    Gold Member
    Sporbie's Avatar
    August 2006
    671 Posts
    Holy shit this is actually so simple, it looked so fucking complicated when I first saw it, now I'm gonna try to make one too, maybe even add some of my own shit to it.

    Also this may pick up to be like that raytracer fad.

  12. Post #12
    Gold Member
    noctune9's Avatar
    April 2008
    1,515 Posts
    I did this crime against c++ for fun some time ago:
    char* _bf_data = new char[30000]; 
    char* _bf_ptr = _bf_data;
    
    #define > ++_bf_ptr;
    #define < --_bf_ptr;
    #define + ++*_bf_ptr;
    #define - --*_bf_ptr;
    #define . _bf_out(*_bf_ptr);
    #define , *_bf_ptr = _bf_in();
    #define [ while (*_bf_ptr) {
    #define ] }
    
    #define input(x) char (*_bf_in )() = x
    #define output(x) void (*_bf_out)(char) = x

    Unfortunately (or fortunately :P), it doesn't compile since MSVC doesn't allow me to define symbols such as + - * etc.

  13. Post #13
    Gold Member
    danharibo's Avatar
    July 2006
    4,459 Posts
    I did this crime against c++ for fun some time ago:
    char* _bf_data = new char[30000]; 
    char* _bf_ptr = _bf_data;
    
    #define > ++_bf_ptr;
    #define < --_bf_ptr;
    #define + ++*_bf_ptr;
    #define - --*_bf_ptr;
    #define . _bf_out(*_bf_ptr);
    #define , *_bf_ptr = _bf_in();
    #define [ while (*_bf_ptr) {
    #define ] }
    
    #define input(x) char (*_bf_in )() = x
    #define output(x) void (*_bf_out)(char) = x

    Unfortunately (or fortunately :P), it doesn't compile since MSVC doesn't allow me to define symbols such as + - * etc.
    Of course it won't, You kind of need them.

  14. Post #14
    Gold Member
    noctune9's Avatar
    April 2008
    1,515 Posts
    Of course it won't, You kind of need them.
    Yeah, I see why, but that was more of a test for fun. Anyways, I've made a interpreter while being bored yesterday:
    #include <stack>
    #include <iostream>
    #include <vector>
    #include <string>
    
    void brainfuck(std::string code, std::istream& in, std::ostream& out)
    {
    	std::stack<unsigned int> func;
    	std::vector<char> memory(30000,0);
    
    	unsigned int memory_index = 0;
    	unsigned int code_index = 0;
    	bool jump = false;
    
    	while (code_index <= code.size())
    	{
    		if (!jump)
    		{
    			switch(code[code_index])
    			{
    			case '>':
    				memory_index++; break;
    			case '<':
    				memory_index--; break;
    			case '+':
    				memory[memory_index]++; break;
    			case '-':
    				memory[memory_index]--; break;
    			case '.':
    				out << memory[memory_index]; break;
    			case ',':
    				in >> memory[memory_index]; break;
    			case '[':
    				func.push(code_index);
    				if(memory[memory_index] == 0) jump = true; break;
    			case ']':
    				if(memory[memory_index] != 0) code_index = func.top();
    				else func.pop(); break;
    			}
    		}
    		else if(memory[memory_index] == ']')
    			jump = false;
    
    		code_index++;
    	}
    }
    It's much more difficult to write brainfuck than writing the interpreter.

  15. Post #15
    Gold Member
    Jallen's Avatar
    December 2007
    7,532 Posts
    Yeah, I see why, but that was more of a test for fun. Anyways, I've made a interpreter while being bored yesterday:
    #include <stack>
    #include <iostream>
    #include <vector>
    #include <string>
    
    void brainfuck(std::string code, std::istream& in, std::ostream& out)
    {
    	std::stack<unsigned int> func;
    	std::vector<char> memory(30000,0);
    
    	unsigned int memory_index = 0;
    	unsigned int code_index = 0;
    	bool jump = false;
    
    	while (code_index <= code.size())
    	{
    		if (!jump)
    		{
    			switch(code[code_index])
    			{
    			case '>':
    				memory_index++; break;
    			case '<':
    				memory_index--; break;
    			case '+':
    				memory[memory_index]++; break;
    			case '-':
    				memory[memory_index]--; break;
    			case '.':
    				out << memory[memory_index]; break;
    			case ',':
    				in >> memory[memory_index]; break;
    			case '[':
    				func.push(code_index);
    				if(memory[memory_index] == 0) jump = true; break;
    			case ']':
    				if(memory[memory_index] != 0) code_index = func.top();
    				else func.pop(); break;
    			}
    		}
    		else if(memory[memory_index] == ']')
    			jump = false;
    
    		code_index++;
    	}
    }
    It's much more difficult to write brainfuck than writing the interpreter.
    That's pretty much identical to mine, except I handled loops a little differently and I have alot of lines taken up by the debug helping code (it's just a preprocessor definition which decides whether debug messages are shown).
    And mine goes through a file rather than just reading it from a string.
    And pushes back elements initialised to 0 when they move forward and the element doesn't yet exist.

    Actually, I'll clean up my code a bit, and then I'll post it.

  16. Post #16
    Gold Member
    Jallen's Avatar
    December 2007
    7,532 Posts
    Ok, here's my solution which doesn't use a stack, and has optional debug messages. And it's now OOP.
    Main.cpp
    #include "BrainFuck.h"
    
    int main(int argc, char *argv[])
    {
    	BrainFuck brainfuck;
    
    	if(argc != 2)
    	{
    		std::cout<< "The file could not be opened - did you not open a file with the executable?\n";
    		getchar();
    		return 0;
    	}
    
    	brainfuck.RunFile(argv[1]);
    
    	return 0;
    }
    BrainFuck.h
    #ifndef BrainFuck_h
    #define BrainFuck_h
    
    #include <iostream>
    #include <fstream>
    #include <vector>
    #include <string>
    #include <sstream>
    
    //#define DEBUGHELP
    
    class BrainFuck
    {
    public:
    	void RunFile(std::string filename);
    protected:
    	void RunCommand(char cmd);
    	void OutputDebug(std::string message);
    
    	std::ifstream file;
    	std::vector<char> vector;
    	int currentIndex;
    	char command;
    
    	std::string loopCode;
    	unsigned int loopLength;
    	bool inloop;
    };
    
    std::string IntToString(int number);
    
    #endif
    BrainFuck.cpp
    #include "BrainFuck.h"
    
    void BrainFuck::RunFile(std::string filename)
    {
    	inloop = false;
    	vector.push_back(0);
    	currentIndex = 0;
    	command = 'a';
    
    	file.open(filename.c_str());
    
    	if(!file.is_open())
    	{
    		std::cout<< "The file could not be opened - did you not to open a file with the executable?\n";
    		getchar();
    		return;
    	}
    
    	while(!file.eof())
    	{
    		file>> command;
    		if(!file.eof())
    		{
    			if(!inloop)
    				RunCommand(command);
    			else 
    			{
    				while(command != ']')
    				{
    					loopCode += command;
    					if(!file.eof())
    						file>> command;
    				}
    				while(vector[currentIndex])
    				{
    					for(int i = 0; i < loopCode.size(); i++)
    					{
    						RunCommand(loopCode[i]);
    					}
    				}
    				inloop = false;
    				OutputDebug("Exiting loop.");
    			}
    		}
    	}
    	OutputDebug("Program finished.");
    	file.close();
    
    	getchar();
    }
    
    void BrainFuck::RunCommand(char cmd)
    {
    	switch(cmd)
    	{
    	case '>':
    		currentIndex += 1;
    		OutputDebug("Now on index " + IntToString(currentIndex) + ".");
    		if(currentIndex >= vector.size()-1)
    			vector.push_back(0);
    		break;
    	case '<':
    		currentIndex -= 1;
    		OutputDebug("Now on index " + IntToString(currentIndex) + ".");
    		break;
    	case '+':
    		if(vector[currentIndex] < 255)
    			vector[currentIndex]++;
    		else OutputDebug("Could not add to current item - max value reached (255).");
    		break;
    	case '-':
    		if(vector[currentIndex] > 0)
    			vector[currentIndex]--;
    		else OutputDebug("Could not decrease current item - item is already null.");
    		break;
    	case '.':
    		std::cout<< vector[currentIndex];
    		OutputDebug("Outputted character at index " + IntToString(currentIndex) + ".");
    		break;
    	case ',':
    		std::cin>> vector[currentIndex];
    		OutputDebug("Read character to index " + IntToString(currentIndex) + ".");
    		break;
    	case '[':
    		inloop = true;
    		OutputDebug("Entering loop.");
    		break;
    	default:
    		break;
    	}
    }
    
    void BrainFuck::OutputDebug(std::string message)
    {
    #ifdef DEBUGHELP
    	std::cout<< "\nDEBUG>>\t" << message << "\n";
    #endif
    	return;
    }
    
    std::string IntToString(int number)
    {
    	std::stringstream stringstream;
    	stringstream<< number;
    	return stringstream.str();
    }

    So yeah, it's not really what you call minimalistic like noctune's is because I made it all OOP and use debug and things, but yeah, it works, and it doesn't use a stack :D

  17. Post #17
    Gold Member
    raccoon12's Avatar
    November 2008
    3,175 Posts
    Code:
    ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.>
    +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.>
    ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.>
    +++++++
    [>++++++++++<-]>-.
    Do it

  18. Post #18
    Gold Member
    Jallen's Avatar
    December 2007
    7,532 Posts
    Hmm, I've found a bug... attempting to fix it.

  19. Post #19
    Gold Member
    noctune9's Avatar
    April 2008
    1,515 Posts
    According to the different sites where I looked, the chars are supposed to 'wrap'. Ie. go to 0 when you increment 255 and go to 255 when you decrement 0.

    Edit: Whoops, just noticed I forgot to make the vector endless.

    Edit:
    Play that funky music, console.
    Code:
    +++++++[.]

  20. Post #20
    Gold Member
    Jallen's Avatar
    December 2007
    7,532 Posts
    According to the different sites where I looked, the chars are supposed to 'wrap'. Ie. go to 0 when you increment 255 and go to 255 when you decrement 0.
    Ah ok cool, I'll add that too.

  21. Post #21
    high6's Avatar
    September 2008
    197 Posts
    That should be automatic because the vector is a vector of chars.

  22. Post #22
    Gold Member
    Sporbie's Avatar
    August 2006
    671 Posts
    I made my own implementation, and it's pretty much the same as yours except the loops code, is your code capable of doing loops in loops?

    Well anyway here's mine: http://www.speedyshare.com/678677514.html

    Here's the code for the lazy:
    #include <iostream>
    #include <string>
    #include <fstream>
    
    #define START_MEMORY 30000
    
    void runProgram(std::string *program, std::string *memory, int index)
    {
        for (int i=0; i<program->size(); i++)
            switch(program->at(i))
            {
                case '>':
                    index++;
                    if (index>=memory->size()-1) memory->push_back((char)0);
                    break;
                case '<':
                    index--;
                    break;
                case '+':
                    memory->at(index)++;
                    break;
                case '-':
                    memory->at(index)--;
                    break;
                case '.':
                    std::cout<<memory->at(index);
                    break;
                case ',':
                    std::cin>>memory->at(index);
                    break;
                case '[':
                    std::string loop;
                    i++;
                    while (program->at(i)!=']')
                    {
                        loop.push_back(program->at(i));
                        i++;
                    }
                    while (memory->at(index))
                    {
                        runProgram(&loop, memory, index);
                    }
                    break;
            }
    }
    
    int main(int argc, char *argv[])
    {
        std::string memory(START_MEMORY,(char)0);
        std::string program,temp;
        std::ifstream file(argv[1]);
        if (argc!=2)
            std::cin>>program; else
        while (!file.eof())
        {
            file>>temp;
            program+=temp;
        }
        runProgram (&program,&memory,0);
        std::cout<<"\n\nYeah I'm using system(\"PAUSE\") whatcha gonna do you dick?\n";
        system("PAUSE");
        return 0;
    }
    

    Oh yeah just drag and drop a file like with Jallens or run the program and type the program as a single line.

    Ah crud just figured out why my code doesn't do loops in loops, I'll sort it out tomorrow.

  23. Post #23
    Gold Member
    noctune9's Avatar
    April 2008
    1,515 Posts
    That should be automatic because the vector is a vector of chars.
    It doesn't seem to be. My unfixed program throws an debug assertion when incrementing memory_index to a value larger than the size of the vector and I read/write to it.

  24. Post #24
    high6's Avatar
    September 2008
    197 Posts
    O ya, that's cause of MSVC.

  25. Post #25
    Gold Member
    gparent's Avatar
    January 2005
    3,949 Posts
    Sporbie, you really should rework how you indent some of your code.
    if (argc!=2)  
        std::cin>>program; else  
    while (!file.eof()) 
    

    ... really makes people want to kill babies.

    Also, don't just use pointers because you can. Go with references whenever possible, it simplifies the typing as well.

    Here's everything I changed, fixing every warning I could find. Checking the diff of your code and mine should show the obvious differences, you'll be able to figure out why I changed it easily:

    #include <iostream>
    #include <string>
    #include <fstream>
    
    const size_t START_MEMORY = 30000;
    
    void runProgram(std::string& program, std::string& memory, size_t index)
    {
        for (size_t i = 0; i < program.size(); i++)
        {
            switch(program[i])
            {
                default:
                    break;
                case '>':
                    index++;
                    if (index >= memory.size() - 1)
                        memory.push_back(0);
                    break;
                case '<':
                    index--;
                    break;
                case '+':
                    memory[index]++;
                    break;
                case '-':
                    memory[index]--;
                    break;
                case '.':
                    std::cout << memory[index];
                    break;
                case ',':
                    std::cin >> memory[index];
                    break;
                case '[':
                    std::string loop;
                    i++;
    
                    while (program[i] != ']')
                    {
                        loop.push_back(program[i]);
                        i++;
                    }
    
                    while (memory[index])
                    {
                        runProgram(loop, memory, index);
                    }
                    break;
            }
        }
    }
    
    int main(int argc, char *argv[])
    {
        std::string memory(START_MEMORY, 0);
        std::string program, temp;
        std::ifstream file(argv[1]);
    
        if (argc != 2 )
        {
            std::cin >> program;
        }
        else
        {
            //while (!file.eof())
            while (std::getline(file, temp))
            {
                program += temp;
            }
        }
    
        runProgram (program, memory, 0);
    
        cin.ignore(cin.rdbuf()->in_avail() + 1);
    
        return 0;
    }
    

    I didn't test everything so there might be minor errors - If you have any questions regarding the changes, let me know.

  26. Post #26
    Gold Member
    Jallen's Avatar
    December 2007
    7,532 Posts
    Hmm, I'm going to rewrite mine using a stack.

    Get the new version in the OP, it works even with loops in loops, and it includes the source files.
    For the lazy:
    Main.cpp
    // Written by James Allen. Use this code as you like, but do not claim it as your own
    #include "BrainFuckInterpreter.h"
    
    int main(int argc, char *argv[])
    {
    	BrainFuckInterpreter bf;
    	if(argc != 2)
    	{
    		std::cout<<"The file could not be opened.";
    		return 0;
    	}
    	bf.RunFile(argv[1]);
    	getchar();
    	return 0;
    }
    BrainFuckInterpreter.h
    // Written by James Allen. Use this code as you like, but do not claim it as your own
    #ifndef BrainFuckInterpreter_h
    #define BrainFuckInterpreter_h
    
    #include <iostream>
    #include <fstream>
    #include <string>
    #include <vector>
    
    class BrainFuckInterpreter
    {
    public:
    	void RunFile(std::string filename);
    protected:
    	void RunLoop(std::string code);
    	void RunChar(char command);
    
    	std::vector<char> memory;
    	int currentIndex;
    	std::ifstream file;
    };
    
    #endif
    BrainFuckInterpreter.cpp
    // Written by James Allen. Use this code as you like, but do not claim it as your own
    #include "BrainFuckInterpreter.h"
    
    void BrainFuckInterpreter::RunFile(std::string filename)
    {
    	file.open(filename.c_str());
    	if(!file.is_open())
    	{
    		std::cout<<"The file could not be opened.";
    		return;
    	}
    	memory.push_back(0);
    	currentIndex = 0;
    	char cmd;
    	while(!file.eof())
    	{
    		file>> cmd;
    		if(!file.eof()) RunChar(cmd);
    	}
    }
    
    void BrainFuckInterpreter::RunLoop(std::string code)
    {
    	while(memory[currentIndex] != 0)
    	{
    		for(int i = 0; i < code.size(); i++)
    		{
    			RunChar(code[i]);
    		}
    	}
    }
    
    void BrainFuckInterpreter::RunChar(char command)
    {
    	switch(command)
    	{
    	case '+':
    		if(memory[currentIndex] == 255) memory[currentIndex] = 0;
    		else memory[currentIndex] += 1;
    		break;
    	case '-':
    		if(memory[currentIndex] == 0) memory[currentIndex] = 255;
    		else memory[currentIndex] -= 1;
    		break;
    	case '>':
    		if(currentIndex == memory.size()-1)
    			memory.push_back(0);
    		currentIndex += 1;
    		break;
    	case '<':
    		if(currentIndex != 0)
    			currentIndex -= 1;
    		break;
    	case '.':
    		std::cout<< memory[currentIndex];
    		break;
    	case ',':
    		std::cin>> memory[currentIndex];
    		break;
    	case '[':
    		std::string loopcode;
    		char nextcmd = 'a';
    		bool makingLoop = true;
    		while(makingLoop)
    		{
    			file>> nextcmd;
    			if(nextcmd != ']' && nextcmd != '[') loopcode += nextcmd;
    			if(nextcmd == '[') continue;
    			else if( nextcmd == ']') makingLoop = false;
    		}
    		RunLoop(loopcode);
    		break;
    	}
    }

  27. Post #27
    Gold Member
    Sporbie's Avatar
    August 2006
    671 Posts
    Thanks gparent, that does look prettier, but why use size_t? What exactly is it?

    Oh and what's the difference between reference and pointer? When do you use pointers and when references?

  28. Post #28
    Gold Member
    Sporbie's Avatar
    August 2006
    671 Posts
    It doesn't seem to be. My unfixed program throws an debug assertion when incrementing memory_index to a value larger than the size of the vector and I read/write to it.
    Nope it's automatic with mine.

  29. Post #29
    Gold Member
    ZeekyHBomb's Avatar
    June 2006
    3,577 Posts
    Well, noctune9 is using operator[], which doesn't do boundary checks I think.

    size_t is an unsigned int.

  30. Post #30
    Gold Member
    Sporbie's Avatar
    August 2006
    671 Posts
    That shouldn't matter, try subtracting 1 from an unsigned integer set to 0, you'll just get a huge number, same with chars, don't know he's program doesn't do it.

  31. Post #31
    Gold Member
    ZeekyHBomb's Avatar
    June 2006
    3,577 Posts
    Using size_t doesn't fix it. gparent didn't intend to fix it with that.
    You just use size_t for array- and container-indices.

  32. Post #32
    Gold Member
    Sporbie's Avatar
    August 2006
    671 Posts
    I know I was just trying to demonstrate what you get when you subtract 1 from an unsigned type, don't know why your compiler doesn't like that.

  33. Post #33
    raccoon121's Avatar
    March 2009
    18 Posts
    Code:
    +.>
    ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.>
    +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.>
    +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.>
    +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.>
    +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.>
    +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.>
    ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.>
    +.>
    This is fun.

  34. Post #34
    high6's Avatar
    September 2008
    197 Posts
    I am not happy about it but here goes.

    http://i43.tinypic.com/5pef0m.jpg

    C#

    Program.cs
    using System;
    using System.Collections.Generic;
    using System.Text;
    
    namespace BrainfuckInterpreter
    {
        class Program
        {
            static void Main(string[] args)
            {
                BrainFuck.BFParser p = new BrainFuck.BFParser();
                BrainFuck.Instruction[] ins = p.Parse(
    @"++++++++++        initialises cell zero to 10
    [
       >+++++++>++++++++++>+++>+<<<<-
    ]                 this loop sets the next four cells to 70/100/30/10 
    >++.              print   'H'
    >+.               print   'e'
    +++++++.                  'l'
    .                         'l'
    +++.                      'o'
    >++.                      space
    <<+++++++++++++++.        'W'
    >.                        'o'
    +++.                      'r'
    ------.                   'l'
    --------.                 'd'
    >+.                       '!'
    >.                        newline
    ");
                BrainFuck.BFSystem bfs = new BrainFuck.BFSystem();
                bfs.Execute(ins);
                Console.ReadKey();
            }
        }
    }
    

    BrainFuck.cs
    using System;
    using System.Collections.Generic;
    using System.Text;
    
    
    namespace BrainFuck
    {
        public class BFParser
        {
            int Idx;
            public List<Instruction> Instructions;
            public BFParser()
            {
                Idx = 0;
            }
            public Instruction[] Parse(string str)
            {
                Instructions = new List<Instruction>();
                Parse(str, false);
                if (Instructions.Count > 1)
                {
                    Instructions[0].Next = Instructions[1];
                    for (int i = 1; i < Instructions.Count - 1; i++)
                    {
                        Instructions[i].Prev = Instructions[i - 1];
                        Instructions[i].Next = Instructions[i + 1];
                    }
                }
                return Instructions.ToArray();
            }
            void Parse(string str, bool IsLoop)
            {
                for (; Idx < str.Length; Idx++)
                {
                    if (str[Idx] == '[')
                    {
                        Instruction ins = Instruction.WhileStart.Clone() as Instruction;
                        Instructions.Add(ins);
                        Idx++;
                        Parse(str, true);
                        ins.Data = Instructions[Instructions.Count - 1];
                        Instructions[Instructions.Count - 1].Data = ins;
                    }
                    else if (str[Idx] == ']')
                    {
                        if (IsLoop)
                        {
                            Instructions.Add(Instruction.WhileEnd.Clone() as Instruction);
                            return;
                        }
                        else
                        {
                            throw new Exception(string.Format("Missing [ before ({0})", Idx));
                        }
                    }
                    for (int i = 0; i < BFSystem.Instructions.Length; i++)
                    {
                        if (BFSystem.Instructions[i].Symbol == str[Idx].ToString())
                        {
                            Instructions.Add(BFSystem.Instructions[i].Clone() as Instruction);
                        }
                    }
                }
                if (IsLoop)
                {
                    throw new Exception(string.Format("Missing ] before (EOF)"));
                }
            }
        }
        public class BFSystem
        {
            public Dictionary<uint, byte> Data;
            public uint Pointer;
            public Instruction Current;
            public void Execute(Instruction[] instructs)
            {
                if (instructs.Length < 1)
                    return;
                Data = new Dictionary<uint, byte>();
                Pointer = 0;
                Current = instructs[0];
                for (; Current != null; Current = Current.Next)
                {
                    Current.Execute(this, Current);
                }
            }
    
            public static readonly Instruction[] Instructions = 
            {
                Instruction.AddDataPtr,
                Instruction.SubDataPtr,
                Instruction.Increment,
                Instruction.Decrement,
                Instruction.PutChar,
                Instruction.GetChar,
                Instruction.WhileStart,
                Instruction.WhileEnd,
            };
        }
        public class Instruction : ICloneable
        {
            public object Clone()
            {
                Instruction ins = new Instruction(Symbol, Data, Execute);
                ins.Next = this.Next;
                ins.Prev = this.Prev;
                return ins;
            }
    
            public override string ToString()
            {
                return Symbol;
            }
    
            public Instruction(string symbol, ExecuteD exe)
                : this(symbol, null, exe)
            {
    
            }
            public Instruction(string symbol, object data, ExecuteD exe)
            {
                Symbol = symbol;
                Data = data;
                Execute = exe;
            }
            public Instruction Prev;
            public Instruction Next;
    
            public object Data;
            public string Symbol;
            public ExecuteD Execute;
            public delegate void ExecuteD(BFSystem sys, Instruction self);
    
    
    
            public static readonly Instruction AddDataPtr = new Instruction(">",
            delegate(BFSystem sys, Instruction self)
            {
                sys.Pointer++;
            });
            public static readonly Instruction SubDataPtr = new Instruction("<",
                delegate(BFSystem sys, Instruction self)
                {
                    sys.Pointer--;
                });
            public static readonly Instruction Increment = new Instruction("+",
                delegate(BFSystem sys, Instruction self)
                {
                    if (!sys.Data.ContainsKey(sys.Pointer))
                    {
                        sys.Data.Add(sys.Pointer, 0);
                    }
                    sys.Data[sys.Pointer]++;
                });
            public static readonly Instruction Decrement = new Instruction("-",
                delegate(BFSystem sys, Instruction self)
                {
                    if (!sys.Data.ContainsKey(sys.Pointer))
                    {
                        sys.Data.Add(sys.Pointer, 0);
                    }
                    sys.Data[sys.Pointer]--;
                });
            public static readonly Instruction PutChar = new Instruction(".",
                delegate(BFSystem sys, Instruction self)
                {
                    if (!sys.Data.ContainsKey(sys.Pointer))
                    {
                        Console.Write(0);
                    }
                    else
                    {
                        Console.Write((char)sys.Data[sys.Pointer]);
                    }
                });
            public static readonly Instruction GetChar = new Instruction(",",
                delegate(BFSystem sys, Instruction self)
                {
                    if (!sys.Data.ContainsKey(sys.Pointer))
                    {
                        sys.Data.Add(sys.Pointer, 0);
                    }
                    sys.Data[sys.Pointer] = (byte)Console.Read();
                });
            public static readonly Instruction WhileStart = new Instruction("[",
                delegate(BFSystem sys, Instruction self)
                {
                    if (!sys.Data.ContainsKey(sys.Pointer) || sys.Data[sys.Pointer] == 0)
                    {
                        sys.Current = (self.Data as Instruction);
                    }
                });
            public static readonly Instruction WhileEnd = new Instruction("]",
                delegate(BFSystem sys, Instruction self)
                {
                    if (sys.Data.ContainsKey(sys.Pointer) && sys.Data[sys.Pointer] != 0)
                    {
                        sys.Current = (self.Data as Instruction);
                    }
                    else
                    {
                    }
                });
    
        }
    }
    
    

    If I was to rewrite it or put more effort into it I would...
    -Take the methods out of the Instruction class and give them their own class
    -Include a method that can be provided for special parsing
    -etc

    Really was just messing around applying the concept. Never tried it before.

  35. Post #35
    Gold Member
    gparent's Avatar
    January 2005
    3,949 Posts
    Thanks gparent, that does look prettier, but why use size_t? What exactly is it?

    Oh and what's the difference between reference and pointer? When do you use pointers and when references?
    size_t is a type that can hold the largest size of an array, if I remember correctly.

    So vector indices, malloc()'s 2nd parameter, the return value of str.size(), everything that deep-down is handled by an array, will return size_t.

    As for references and pointers, I know the difference between them, however I'm not a great teacher.

    However, the basic is:
    A reference is similar to a pointer in that you are accessing an object that is not copied by value.
    A reference is different to a pointer in that you cannot assign a reference after it is initialized
    A reference cannot be NULL (Unless you try fairly hard IIRC)
    You don't need to use the -> operator with a reference, you use . instead.

    You use references whenever you can, and pointers whenever you can't. Start with a reference, if you can't do what you want with one (or if it requires a lot of extra code), use a pointer.

    As for the other few things I've changed:

    -Always use a const variable before using a #define if you can. const variables provide type safety, and they have a scope.
    -Added default case to the switch to fix a compiler warning
    -Changed every .at() to [] (Although I missed some, I edited my post to remove some more). The difference between .at() and [] is that .at() will throw an exception if you access an invalid indice. If you're not using try catch, it's pointless to use it.
    -Changed !file.eof() condition to the state of the stream. More explanation here: http://www.parashift.com/c++-faq-lit....html#faq-15.5

    Let me know if you have more questions.

  36. Post #36
    im gay
    _Kilburn's Avatar
    July 2007
    3,619 Posts
    Haha, reminds me that I've made a Brainfuck compiler for my graphical calculator a long time ago. Compiles directly into executable machine code. It's way easier to do than an interpreter because most tokens are simple CPU instructions (increment, decrement), and loops in loops appear naturally when you make use of labels and jumps. On the other hand, console input and output were a pain in the ass to do because the CPU didn't have instructions to call a C function from assembly.

  37. Post #37
    Gold Member
    Sporbie's Avatar
    August 2006
    671 Posts
    -snip-, nevermind.

  38. Post #38
    Gold Member
    ZeekyHBomb's Avatar
    June 2006
    3,577 Posts
    I know I was just trying to demonstrate what you get when you subtract 1 from an unsigned type, don't know why your compiler doesn't like that.
    It's not weired. If sizeof(unsigned int) is x, then you get the number 2^x-1.

  39. Post #39
    Gold Member
    gparent's Avatar
    January 2005
    3,949 Posts
    sizeof() returns bytes, not bits.

  40. Post #40
    Gold Member
    ZeekyHBomb's Avatar
    June 2006
    3,577 Posts
    Right. >.<
    If sizeof(unsigned int)*8 is x, then you get the number 2^x-1.