Just another brainfuck interpreter
Why?
Honestly, why not?
The entry point
Not much to tell:
```csharp
static void Main(string[] args)
{
var parser = new Parser("++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------
.\>+.\>.");
var instructions = parser.Instructions;
var interpreter = new Interpreter(instructions);
interpreter.Interpret();
}
```
## The container classes
Some data classes and enums:
```csharp
public enum Tokens
{
MoveFwd,
MoveBack,
Incr,
Decr,
While,
Print,
Input,
WhileEnd,
WhileStart,
Unknown
}
public class Instruction
{
public Tokens Token { get; set; }
public override string ToString()
{
return Token.ToString();
}
}
class While : Instruction
{
public While()
{
Token = Tokens.While;
}
public List\<Instruction\> Instructions { get; set; }
}
```
## A helper function
A function to translate a character token into a known token
```csharp
private Tokens GetToken(char input)
{
switch (input)
{
case '+':
return Tokens.Incr;
case '-':
return Tokens.Decr;;
case '\<':
return Tokens.MoveBack;
case '\>':
return Tokens.MoveFwd;
case '.':
return Tokens.Print;
case ',':
return Tokens.Input;
case '[':
return Tokens.WhileStart;
case ']':
return Tokens.WhileEnd;
}
return Tokens.Unknown;
}
```
## The parser
And the entire parser:
```csharp
public List\<Instruction\> Instructions { get; private set; }
public Parser(string source)
{
Instructions = Tokenize(source.Select(GetToken)
.Where(token =\> token != Tokens.Unknown)
.ToList()).ToList();
}
IEnumerable\<Instruction\> Tokenize(IEnumerable\<Tokens\> input)
{
var stack = new Stack\<While\>();
foreach (var t in input)
{
switch (t)
{
case Tokens.WhileStart:
stack.Push(new While {Instructions = new List\<Instruction\>()});
break;
case Tokens.WhileEnd:
if (stack.Count == 0)
{
throw new Exception("Found a ] without a matching [");
}
if (stack.Count \> 1)
{
var top = stack.Pop();
stack.Peek().Instructions.Add(top);
}
else
{
yield return stack.Pop();
}
break;
default:
var instruction = new Instruction {Token = t};
if (stack.Count \> 0)
{
stack.Peek().Instructions.Add(instruction);
}
else
{
yield return instruction;
}
break;
}
}
if (stack.Count \> 0)
{
throw new Exception("Unmatched [found. Expecting]");
}
}
```
I took a different approach to parsing this time than usual. I didn't feel like having to deal with a consumable stream, so I linearly went through the token source. Each time I encountered a while loop start I pushed it onto the while loop stack. Anytime I had instructions, if I had stuff in the stack, I added it to the instruction list at the top of stack. As I hit while loop end tokens (]), I popped off the stack and yielded the aggregate instruction.
## The interpreter
The interpreter is dirt simple too. We have a 30,000 byte array of memory (per spec from wikipedia). The rest I think is self explanatory:
```csharp
public class Interpreter
{
private readonly byte[] \_space = new byte[30000];
private int \_dataPointer;
private List\<Instruction\> Instructions { get; set; }
public Interpreter (List\<Instruction\> instructions)
{
Instructions = instructions;
}
public void Interpret()
{
InterpretImpl(Instructions);
}
private void InterpretImpl(IEnumerable\<Instruction\> instructions)
{
foreach(var instruction in instructions){
switch (instruction.Token)
{
case Tokens.Input:
\_space[\_dataPointer] = Convert.ToByte(Console.Read());
break;
case Tokens.Incr:
\_space[\_dataPointer]++;
break;
case Tokens.Decr:
\_space[\_dataPointer]--;
break;
case Tokens.Print:
Console.Write(Encoding.ASCII.GetString(new[] { \_space[\_dataPointer] }));
break;
case Tokens.MoveFwd:
\_dataPointer++;
break;
case Tokens.MoveBack:
\_dataPointer--;
break;
case Tokens.While:
while (\_space[\_dataPointer] != 0)
{
InterpretImpl((instruction as While).Instructions);
}
break;
}
}
}
}
```
## The source
Read the [source](https://github.com/devshorts/BrainFuckSharp), Luke