Skip to content

Instantly share code, notes, and snippets.

@vtols
Created May 4, 2013 09:07
Show Gist options
  • Select an option

  • Save vtols/5516901 to your computer and use it in GitHub Desktop.

Select an option

Save vtols/5516901 to your computer and use it in GitHub Desktop.
BrainFuck compiler for .NET
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Reflection;
using System.Reflection.Emit;
namespace Translator
{
class Translator
{
public static AssemblyBuilder asb;
public static ModuleBuilder mb;
public static MethodBuilder tb;
public static ILGenerator il;
public static LocalBuilder[] lcb;
public static FileStream fs = new FileStream("Hello.il", FileMode.Create, FileAccess.Write);
public static StreamWriter sw = new StreamWriter(fs);
public static int bropened = 0;
public static int brclosed = 1;
public static int memoryBlockSize = 30000;
public static List<Label> jumps = new List<Label>();
public static bool error = false;
public static Stack<int> brstack = new Stack<int>();
public static void Main(string[] args)
{
Console.WriteLine("brainfuck programming language compiler by Valery Tolstov ©2009\n");
StreamReader sr = new StreamReader("Hello.brfuck");
string source = sr.ReadToEnd();
EmitInit();
EmitText(source);
EmitEnd();
sw.Close();
if ((brstack.Count == 0) && (!error))
{
Console.WriteLine("Program successfully translated to CIL code.");
try
{
mb.CreateGlobalFunctions();
asb.SetEntryPoint(tb);
asb.Save("Hello.exe");
}
catch (Exception)
{
Console.WriteLine("\nError writing executable file.");
Console.WriteLine("\n***FAILED***");
}
}
else
{
int[] brarray = brstack.ToArray();
for (int i = 0; i < brarray.Length; i++)
{
Console.WriteLine("Source program have single opening bracket №" + (brarray[i] + 1).ToString());
}
Console.WriteLine("\n***FAILED***");
}
Console.Read();
}
public static void EmitText(string text)
{
for (int i = 0; i < text.Length; i++)
{
int c = 0;
switch (text[i])
{
case '>':
for (; ; ) { ++c; if ((text[i + 1] == '>') && (i < text.Length)) { ++i; } else break; }
EmitNext(c); break;
case '<':
for (; ; ) { ++c; if ((text[i + 1] == '<') && (i < text.Length)) { ++i; } else break; }
EmitPrev(c); break;
case '+':
for (; ; ) { ++c; if ((text[i + 1] == '+') && (i < text.Length)) { ++i; } else break; }
EmitPlus(c); break;
case '-':
for (; ; ) { ++c; if ((text[i + 1] == '-') && (i < text.Length)) { ++i; } else break; }
EmitMinus(c); break;
case '[': EmitLBracket(); break;
case ']': EmitRBracket(); break;
case '.': EmitDot(); break;
//case ',': ;
}
}
}
public static void EmitNext(int count)
{
StringBuilder sb = new StringBuilder();
sb.AppendLine("ldloc.1");
sb.AppendLine("ldc.i4.s " + count.ToString());
sb.AppendLine("add");
sb.AppendLine("stloc.1");
sw.WriteLine(sb.ToString());
il.Emit(OpCodes.Ldloc_1);
il.Emit(OpCodes.Ldc_I4_S, count);
il.Emit(OpCodes.Add);
il.Emit(OpCodes.Stloc_1);
}
public static void EmitPrev(int count)
{
StringBuilder sb = new StringBuilder();
sb.AppendLine("ldloc.1");
sb.AppendLine("ldc.i4.s " + count.ToString());
sb.AppendLine("sub");
sb.AppendLine("stloc.1");
sw.WriteLine(sb.ToString());
il.Emit(OpCodes.Ldloc_1);
il.Emit(OpCodes.Ldc_I4_S, count);
il.Emit(OpCodes.Sub);
il.Emit(OpCodes.Stloc_1);
}
public static void EmitPlus(int count)
{
StringBuilder sb = new StringBuilder();
sb.AppendLine("ldloc.0");
sb.AppendLine("ldloc.1");
sb.AppendLine("ldloc.0");
sb.AppendLine("ldloc.1");
sb.AppendLine("ldelem.i4");
sb.AppendLine("ldc.i4.s " + count.ToString());
sb.AppendLine("add");
sb.AppendLine("stelem.i4");
sw.WriteLine(sb.ToString());
il.Emit(OpCodes.Ldloc_0);
il.Emit(OpCodes.Ldloc_1);
il.Emit(OpCodes.Ldloc_0);
il.Emit(OpCodes.Ldloc_1);
il.Emit(OpCodes.Ldelem_I4);
il.Emit(OpCodes.Ldc_I4_S, count);
il.Emit(OpCodes.Add);
il.Emit(OpCodes.Stelem_I4);
}
public static void EmitDot()
{
StringBuilder sb = new StringBuilder();
sb.AppendLine("ldloc.3");
sb.AppendLine("ldloc.0");
sb.AppendLine("ldloc.1");
sb.AppendLine("ldelem.i4");
sb.AppendLine("conv.u2");
sb.AppendLine("callvirt instance void [mscorlib]System.IO.TextWriter::Write(char)");
sw.WriteLine(sb.ToString());
il.Emit(OpCodes.Ldloc_3);
il.Emit(OpCodes.Ldloc_0);
il.Emit(OpCodes.Ldloc_1);
il.Emit(OpCodes.Ldelem_I4);
il.Emit(OpCodes.Conv_U2);
il.Emit(OpCodes.Callvirt, typeof(TextWriter).GetMethod("Write", new Type[]{typeof(char)}));
}
public static void EmitLBracket()
{
StringBuilder sb = new StringBuilder();
sb.AppendLine("ldloc.0");
sb.AppendLine("ldloc.1");
sb.AppendLine("ldelem.i4");
sb.AppendLine("brfalse outEndLabel" + bropened.ToString());
sb.AppendLine("inStartLabel" + bropened.ToString() + ":");
sw.WriteLine(sb.ToString());
jumps.Add(il.DefineLabel()); jumps.Add(il.DefineLabel());
il.Emit(OpCodes.Ldloc_0);
il.Emit(OpCodes.Ldloc_1);
il.Emit(OpCodes.Ldelem_I4);
il.Emit(OpCodes.Brfalse, jumps[bropened * 2 + 1]);
il.MarkLabel(jumps[bropened * 2]);
brstack.Push(bropened);
++bropened;
}
public static void EmitRBracket()
{
if (brstack.Count > 0)
{
int br = brstack.Pop();
StringBuilder sb = new StringBuilder();
sb.AppendLine("ldloc.0");
sb.AppendLine("ldloc.1");
sb.AppendLine("ldelem.i4");
sb.AppendLine("brtrue inStartLabel" + br.ToString());
sb.AppendLine("outEndLabel" + br.ToString() + ":");
sw.WriteLine(sb.ToString());
il.Emit(OpCodes.Ldloc_0);
il.Emit(OpCodes.Ldloc_1);
il.Emit(OpCodes.Ldelem_I4);
il.Emit(OpCodes.Brtrue, jumps[br * 2]);
il.MarkLabel(jumps[br * 2 + 1]);
}
else
{
error = true;
Console.WriteLine("Source program have single closing bracket №" + (brclosed).ToString());
}
++brclosed;
}
public static void EmitMinus(int count)
{
StringBuilder sb = new StringBuilder();
sb.AppendLine("ldloc.0");
sb.AppendLine("ldloc.1");
sb.AppendLine("ldloc.0");
sb.AppendLine("ldloc.1");
sb.AppendLine("ldelem.i4");
sb.AppendLine("ldc.i4.s " + count.ToString());
sb.AppendLine("sub");
sb.AppendLine("stelem.i4");
sw.WriteLine(sb.ToString());
il.Emit(OpCodes.Ldloc_0);
il.Emit(OpCodes.Ldloc_1);
il.Emit(OpCodes.Ldloc_0);
il.Emit(OpCodes.Ldloc_1);
il.Emit(OpCodes.Ldelem_I4);
il.Emit(OpCodes.Ldc_I4_S, count);
il.Emit(OpCodes.Sub);
il.Emit(OpCodes.Stelem_I4);
}
public static void EmitInit()
{
StringBuilder sb = new StringBuilder();
Random rnd = new Random();
string iD = rnd.Next(0, 9).ToString() + rnd.Next(0, 9).ToString()
+ rnd.Next(0, 9).ToString() + rnd.Next(0, 9).ToString()
+ rnd.Next(0, 9).ToString() + rnd.Next(0, 9).ToString();
sb.AppendLine(".assembly extern mscorlib{}");
sb.AppendLine(".assembly brfck" + iD + "{}");
sb.AppendLine(".method public static void main() cil managed");
sb.AppendLine("{");
sb.AppendLine("InitBlock:");
sb.AppendLine(".locals init ([0] int32[] val, [1] int32 index, [2] class [mscorlib]System.IO.TextReader input,[3] class [mscorlib]System.IO.TextWriter output)");
sb.AppendLine(".entrypoint");
sb.AppendLine("ldc.i4 0x" + String.Format("{0:X}", memoryBlockSize));
sb.AppendLine("newarr [mscorlib]System.Int32");
sb.AppendLine("stloc.0");
sb.AppendLine("ldc.i4.0");
sb.AppendLine("stloc.1");
sb.AppendLine("call class [mscorlib]System.IO.TextReader [mscorlib]System.Console::get_In()");
sb.AppendLine("stloc.2");
sb.AppendLine("call class [mscorlib]System.IO.TextWriter [mscorlib]System.Console::get_Out()");
sb.AppendLine("stloc.3");
sb.AppendLine("");
sb.AppendLine("ProgramBlock:");
sw.Write(sb.ToString());
AssemblyName asn = new AssemblyName("brfck" + iD);
asb = AppDomain.CurrentDomain.DefineDynamicAssembly(asn, AssemblyBuilderAccess.Save);
mb = asb.DefineDynamicModule("Hello.exe");
tb = mb.DefineGlobalMethod("main",
MethodAttributes.Public | MethodAttributes.Static,
typeof(void), new Type[]{});
il = tb.GetILGenerator();
lcb = new LocalBuilder[]
{il.DeclareLocal(typeof(int[])),
il.DeclareLocal(typeof(int)),
il.DeclareLocal(typeof(System.IO.TextReader)),
il.DeclareLocal(typeof(System.IO.TextWriter))};
il.Emit(OpCodes.Ldc_I4, memoryBlockSize);
il.Emit(OpCodes.Newarr, typeof(int));
il.Emit(OpCodes.Stloc_0);
il.Emit(OpCodes.Ldc_I4_0);
il.Emit(OpCodes.Stloc_1);
il.Emit(OpCodes.Call, typeof(Console).GetMethod("get_In", new Type[] { }));
il.Emit(OpCodes.Stloc_2);
il.Emit(OpCodes.Call, typeof(Console).GetMethod("get_Out", new Type[] { }));
il.Emit(OpCodes.Stloc_3);
}
public static void EmitEnd()
{
StringBuilder sb = new StringBuilder();
sb.AppendLine("EndBlock:");
sb.AppendLine("call int32 [mscorlib]System.Console::Read()");
sb.AppendLine("pop");
sb.AppendLine("ret");
sb.AppendLine("}");
sw.Write(sb.ToString());
il.Emit(OpCodes.Call, typeof(Console).GetMethod("Read", new Type[]{}));
il.Emit(OpCodes.Pop);
il.Emit(OpCodes.Ret);
}
public static void T()
{
TextWriter ou = Console.Out;
int[] a = new int[30000];
int b = 0;
ou.Write((char)a[b]);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment