Back to projects

BrainSharp

A brainfuck to C# transpiler and runner.
LucaScorpion/BrainSharp
C# C#

This was a fun little project which started because I was playing around with the brainfuck programming language. BrainSharp is a CLI tool which can interpret brainfuck code and transpile it to C#. It can also output the generated source code or executable, or run it directly.

Brainfuck is a very minimalistic language which contains just a pointer, memory, in-, and output. The complete syntax consists of these following symbols:

  • + and - increment and decrement the cell value.
  • > and < increment and decrement the pointer value.
  • . prints the cell value as a character.
  • , reads a byte from the input.
  • [ and ] denote a loop which runs while the cell value is not zero.

All other characters are also valid, and are simply interpreted as comments. A simple hello world brainfuck program looks like this:

++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>
->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.
+++.------.--------.>>+.>++.

The way BrainSharp interprets this is by converting each character to an abstract instruction, and keeping a list with those instructions. After it built the complete list, it will go through it to merge instructions where possible. For example: >>>> means “increment the pointer by 4”, which can be represented by a single instruction (pointer += 4;).

From here generating the C# code is fairly simple. First there is some boilerplate which is necessary for any valid C# program, and there are some extra functions which handle I/O to make generating the code for that a bit simpler. The ${code} placeholder is where the generated code will be put.

using System;

namespace brainfuck
{
	public class Program
	{
		private static byte[] stack = new byte[256];
		private static byte pointer = 0;
		private static string input = String.Empty;
		private static int inputPointer = 0;

		private static void Main(string[] args)
		{
			for (int i = 0; i < args.Length; i++)
			{
				input += args[i];
				if (i < args.Length - 1)
					input += ' ';
			}

${code}

			Console.Read();
		}

		private static byte ReadByte()
		{
			return (byte)(inputPointer < input.Length
                ? input[inputPointer++]
                : 0);
		}

		private static void PrintChar()
		{
			Console.Write((char)stack[pointer]);
		}
	}
}

Now the code for each instruction can be generated. Most of the instructions have very simple C# equivalents, from PrintChar() for . to pointer += 4 for >>>>. To make sure the code stays properly indented it also keeps a counter for the number of tabs, which increases when a loop starts and decreases when it ends. After this is done we have successfully generated a C# program from brainfuck!