AyrA icon

Brainfuck.cs

AyrA | PRO | 04/29/16 09:31:35 AM UTC | 0 ⭐ | 616 👁️ | Never ⏰ | []
C# |

8.47 KB

|

None

|

0 👍

/

0 👎

using System.Collections.Generic;
using System.Text;
using System.CodeDom.Compiler;
using Microsoft.CSharp;
using System.IO;
using System;
 
namespace BrainfuckCompiler
{
    /// <summary>
    /// Brainfuck compiler and transpiler
    /// </summary>
    public class Brainfuck
    {
        /// <summary>
        /// Main frame for the output
        /// </summary>
        public const string MAIN = @"using System;
static class Program
{
static int Main(string[] Args)
{
int Index=0;
char[] Values=new char[/*MEMSIZE*/];
/*COMPILED*/
return (int)Values[Index];
}
 
static void Put(char C)
{
Console.Write(C);
}
 
static char Get()
{
Put('>');
char C=Console.ReadKey(true).KeyChar;
return C==27?'\0':C;
}
}
";
        /// <summary>
        /// Memory size in bytes
        /// </summary>
        public const int MEMSIZE = 32000;
 
        //no changes needed below
 
        public const string REPLACE = "/*COMPILED*/";
        public const string CODE = "/*SOURCE*/";
        public const string MEM = "/*MEMSIZE*/";
        private const string VALUE = "VAL";
        private Dictionary<char, string> Commands;
        private Dictionary<char, string> MultiCommands;
 
        /// <summary>
        /// Creates a new Brainfuck instance
        /// </summary>
        public Brainfuck()
        {
            Init();
        }
 
        /// <summary>
        /// Resets all codes
        /// </summary>
        private void Init()
        {
            Commands = new Dictionary<char, string>();
            MultiCommands = new Dictionary<char, string>();
            //add strings
            Commands.Add('>', "++Index;\r\n");
            Commands.Add('<', "--Index;\r\n");
            Commands.Add('+', "++Values[Index];\r\n");
            Commands.Add('-', "--Values[Index];\r\n");
            Commands.Add('[', "while(Values[Index]!=0)\r\n{\r\n");
            Commands.Add(']', "}\r\n");
            Commands.Add('.', "Put(Values[Index]);\r\n");
            Commands.Add(',', "Values[Index]=Get();\r\n");
            //add multi-commands
            MultiCommands.Add('>', "Index+=VAL;\r\n");
            MultiCommands.Add('<', "Index-=VAL;\r\n");
            MultiCommands.Add('+', "Values[Index]+=(char)VAL;\r\n");
            MultiCommands.Add('-', "Values[Index]-=(char)VAL;\r\n");
        }
 
        /// <summary>
        /// Removes all non-code data
        /// </summary>
        /// <param name="Source">Source code</param>
        /// <returns>Cleaned brainfuck</returns>
        public string Filter(string SourceCode)
        {
            Init();
            StringBuilder SB = new StringBuilder();
            foreach (char C in SourceCode)
            {
                if (Commands.ContainsKey(C))
                {
                    SB.Append(C);
                }
            }
            return SB.ToString();
        }
 
        /// <summary>
        /// Parses a brainfuck file and returns optimized C# code
        /// </summary>
        /// <param name="SourceCode">Source code</param>
        /// <returns>C# code</returns>
        public string Parse(string SourceCode)
        {
            return Parse(SourceCode, true);
        }
 
        /// <summary>
        /// Parses a brainfuck file and returns C# code
        /// </summary>
        /// <param name="SourceCode">Source code</param>
        /// <param name="optimize">true, to optimize commands</param>
        /// <returns>C# code</returns>
        public string Parse(string SourceCode, bool optimize)
        {
            Init();
            //CurrentIndent = 2;
            List<string> Parts = new List<string>();
            //add dummy item
            Parts.Add("YAY");
            SourceCode = Filter(SourceCode);
            //add optimizations here
            if (optimize)
            {
                //[-] sets the current value to 0 ([+] does too)
                Commands.Add('!', "Values[Index]='\\0';\r\n");
                SourceCode = SourceCode
                    .Replace("[-]", "!")
                    .Replace("[+]", "!");
            }
 
            foreach (char c in SourceCode)
            {
                if (Commands.ContainsKey(c))
                {
                    if (optimize && Parts[Parts.Count - 1][0] == c)
                    {
                        Parts[Parts.Count - 1] += c;
                    }
                    else
                    {
                        Parts.Add(c.ToString());
                    }
                }
            }
            //remove dummy item
            Parts.RemoveAt(0);
            StringBuilder SB = new StringBuilder();
            foreach (string s in Parts)
            {
                SB.Append(MultiCommand(s));
            }
            return MAIN
                .Replace(REPLACE, SB.ToString())
                .Replace(CODE, SourceCode)
                .Replace(MEM, MEMSIZE.ToString());
        }
 
        /// <summary>
        /// Compresses code using simple Replacements (still valid C#)
        /// </summary>
        /// <param name="Code">Code</param>
        /// <returns>Compressed code</returns>
        public string Compress(string SourceCode)
        {
            return SourceCode
                .Replace("Put", "W")
                .Replace("Get", "R")
                //.Replace("32000", "1<<15") //not actually shorter, just obfuscated
                .Replace("Values", "V")
                .Replace("Index", "I")
                .Replace('\t', '\n')
                .Replace('\r', '\n')
                .Replace("\n", "");
        }
 
        /// <summary>
        /// gets the shortest version of a multicommand
        /// </summary>
        /// <param name="Command">Command</param>
        /// <returns>multicommand</returns>
        private string MultiCommand(string Command)
        {
            return MultiCommand(Command[0], Command.Length);
        }
 
        /// <summary>
        /// gets the shortest version of a multicommand
        /// </summary>
        /// <param name="Command">Command</param>
        /// <param name="Count">How often it is repeated</param>
        /// <returns>multicommand</returns>
        public string MultiCommand(char Command, int Count)
        {
            if (Count == 1)
            {
                return Commands[Command];
            }
            if (MultiCommands.ContainsKey(Command))
            {
                return MultiCommands[Command].Replace(VALUE, Count.ToString());
            }
            else
            {
                StringBuilder SB = new StringBuilder(Commands[Command].Length * Count);
                for (int i = 0; i < Count; i++)
                {
                    SB.Append(Commands[Command]);
                }
                return SB.ToString();
            }
        }
 
        /// <summary>
        /// Compiles C# source code
        /// </summary>
        /// <param name="SourceCode">Source code (not the file name)</param>
        /// <param name="TargetFile">Target file</param>
        /// <returns>true, if successful</returns>
        public bool Compile(string SourceCode,string TargetFile)
        {
            using (CodeDomProvider codeProvider = new CSharpCodeProvider())
            {
                CompilerParameters compilerParams = new CompilerParameters();
                compilerParams.MainClass = "Program";
                compilerParams.OutputAssembly = TargetFile;
                compilerParams.CompilerOptions = " /optimize";
                compilerParams.GenerateExecutable = true;
                compilerParams.IncludeDebugInformation = false;
                compilerParams.ReferencedAssemblies.Add("mscorlib.dll");
                compilerParams.ReferencedAssemblies.Add("System.dll");
 
                CompilerResults results = codeProvider.CompileAssemblyFromSource(compilerParams, new string[] { SourceCode });
 
                if (results.Errors.Count > 0)
                {
                    Console.ForegroundColor = ConsoleColor.Red;
                    foreach (CompilerError E in results.Errors)
                    {
                        Console.ForegroundColor = E.IsWarning ? ConsoleColor.Yellow : ConsoleColor.Red;
                        Console.WriteLine("<{0}:{1}> [{2}]: {3}", E.Line, E.Column, E.ErrorNumber, E.ErrorText);
                    }
                }
                return results.Errors.Count > 0;
            }
        }
    }
}

Comments

  •  icon
    01/01/70 12:00:00 AM UTC
    Plain Text |

    0 B

    |

    👍

    /

    👎