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.