Backend Coder Logo

Brainfuck Interpreter in C Sharp

Published: 14th Nov 2016

I will assume that you know what the Brainfuck esoteric programming language is so I won't explain the basics. I am new to it but learned it very quickly and found it fun to play around with.

As an excuse to code something in C# again, I thought that it would be fun to code an Interpreter  for Brainfuck, so here it is. On the Wikipedia page it suggests that it is trivial to code but I think that the bracketed looping feature presents some challenge. This needs to search for the ending bracket, and take into account depths of nesting.

I also added error checking and exception throwing into the mix. This program runs in the command console. The code is entered on a line, and the enter key pressed to run the program. Entering a blank line exits.


using System;
using System.Collections.Generic;

namespace Brainfuck
{
    class Program
    {
        const int MEM_SIZE = 1024;

        static void Main()
        {
            ConsoleKeyInfo userInput;

            try
            {
                do
                {
                    byte[] memory = new byte[MEM_SIZE];
                    int instructionPointer = 0;
                    int dataPointer = 0;
                    int depth = 0;

                    Console.WriteLine("Enter your Brainfuck code: <>+-,.[]?");
                    string program = Console.ReadLine();
                    int numCmds = program.Length;
                    if (numCmds < 1) break;
                    for (instructionPointer = 0; instructionPointer < numCmds; instructionPointer++)
                    {
                        switch (program[instructionPointer])
                        {
                            case '<':
                                if (dataPointer > 0)
                                    dataPointer--;
                                else
                                    throw new SystemException("Data pointer underflow error!");
                                break;

                            case '>':
                                dataPointer++;
                                if (dataPointer >= MEM_SIZE)
                                    throw new SystemException("Data pointer memory size overflow error!");
                                break;

                            case '+':
                                memory[dataPointer]++;
                                break;

                            case '-':
                                memory[dataPointer]--;
                                break;

                            case '.':
                                char c = (char)memory[dataPointer];
                                Console.Write(c);
                                break;

                            case ',':
                                userInput = Console.ReadKey(true);
                                memory[dataPointer] = (byte)userInput.KeyChar;
                                break;

                            case '[':
                                depth++; // Move the loop nesting depth up

                                if (memory[dataPointer] == 0)
                                {
                                    // Move to closing bracket
                                    int searchDepth = depth;
                                    do
                                    {
                                        instructionPointer++;
                                        if (instructionPointer == numCmds)
                                            throw new SystemException("Missing closing ] at depth: " + depth);

                                        if (program[instructionPointer] == '[')
                                            searchDepth++;

                                        if (program[instructionPointer] == ']')
                                            searchDepth--;                                      
                                    }
                                    while (searchDepth >= depth);

                                    depth--; // Move the loop nesting depth down
                                }
                                break;

                            case ']':
                                if (memory[dataPointer] != 0)
                                {
                                    // Move to opening bracket
                                    int searchDepth = depth;
                                    do
                                    {
                                        instructionPointer--;
                                        if (instructionPointer < 0)
                                            throw new SystemException("Missing open [ at depth: " + depth);

                                        if (program[instructionPointer] == '[')
                                            searchDepth--;

                                        if (program[instructionPointer] == ']')
                                            searchDepth++;
                                    }
                                    while (searchDepth >= depth);
                                }
                                else
                                    depth--; // Move the loop nesting depth down
                                break;

                            case '?':
                                Console.WriteLine("wtf is bf: https://en.wikipedia.org/wiki/Brainfuck");
                                break;

                            default:
                                //throw new SystemException("Error: Unknown command: " + Convert.ToChar(program[instructionPointer]));
                                // Write unknown command value to memory - non-standard implementation
                                memory[dataPointer] = (byte)program[instructionPointer];
                                break;
                        }
                    }
                    Console.WriteLine("");
                } while (true);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
                Console.ReadKey();
            }
        }   
    }
}

Code Example

Enter 0 to count from 1 to 9 +++>>,<<[>+++[>+.<-]<-] This code demonstrates nested looping. The value entered is incremented on each iteration of a 3x3 loop.

Simple Improvement

With the standard implementation, it is annoying to enter ASCII character codes in the alpha numeric range since many plus commands are needed. For example, 32 are needed to get to the space character.

A simple mod is to replace the exception throw on unknown command with a write of the value to the pointer location as follows:

memory[dataPointer] = (byte)program[instructionPointer];

So to enter the code for the letter "a", simply type "a" and for the digit "1" enter "1" etc.

Similar to the above code example but with zero hard coded: +++>>0<<[>+++[>+.<-]<-]