fork(1) download
  1. // This is in the public domain
  2. //#define DEBUG
  3.  
  4. using System;
  5. using System.CodeDom.Compiler;
  6. using System.Collections;
  7. using System.Collections.Generic;
  8. using System.Collections.ObjectModel;
  9. using System.Diagnostics;
  10. using System.IO;
  11. using System.Linq;
  12. using System.Linq.Expressions;
  13. using System.Reflection;
  14. using System.Threading;
  15. using System.Threading.Tasks;
  16. using static System.Environment;
  17. using static System.Linq.Expressions.Expression;
  18.  
  19. public static class Test
  20. {
  21. [Conditional("DEBUG")]
  22. private static void DebugSetup()
  23. {
  24. var listeners = Debug.Listeners;
  25. listeners.Clear();
  26. listeners.Add(new ConsoleTraceListener());
  27. }
  28.  
  29. private static readonly string Rod = new string('─', 77);
  30.  
  31. private static T Ask<T>() => (T)Convert.ChangeType(Console.ReadLine(), typeof(T));
  32.  
  33. static Test()
  34. {
  35. DebugSetup();
  36. }
  37.  
  38. public static int Main()
  39. {
  40. try
  41. {
  42. switch (char.ToLower(Ask<char>()))
  43. {
  44. case 'b':
  45. using (var @out = Console.OpenStandardOutput())
  46. {
  47. var bf = Brainfuck(Console.ReadLine(), typeof(ushort),
  48. @out.WriteByte, ReadByteInternal);
  49. Debug.WriteLine(bf.Type);
  50. Debug.WriteLine(bf);
  51. Console.Out.Flush();
  52. bf.Compile()(new byte[MemorySize]);
  53. break;
  54. }
  55.  
  56. case 'c':
  57. {
  58. var bf = Brainfuck(Console.ReadLine(), typeof(ushort),
  59. Console.Write, ReadCharInternal);
  60. Debug.WriteLine(bf.Type);
  61. Debug.WriteLine(bf);
  62. bf.Compile()(new char[MemorySize]);
  63. break;
  64. }
  65.  
  66. default:
  67. Console.Error.WriteLine("Input error.");
  68. return 1;
  69. }
  70. }
  71. catch (ArgumentException e)
  72. {
  73. Debug.WriteLine(e);
  74. Console.Error.WriteLine(e.Message);
  75. return 1;
  76. }
  77. return 0;
  78. }
  79.  
  80. private const int MemorySize = 1 << 12;
  81.  
  82. private static byte ReadByteInternal()
  83. {
  84. var value = Console.Read();
  85. switch (value)
  86. {
  87. case (int)'\n':
  88. case -1:
  89. return 0;
  90.  
  91. default:
  92. return (byte)value;
  93. }
  94. }
  95.  
  96. private static char ReadCharInternal()
  97. {
  98. var value = Console.Read();
  99. switch (value)
  100. {
  101. case (int)'\n':
  102. case -1:
  103. return '\0';
  104.  
  105. default:
  106. return (char)value;
  107. }
  108. }
  109.  
  110. private static Expression OperateInteger(Expression expression, Type integerType, bool decrement)
  111. {
  112. if (integerType != null)
  113. {
  114. var converted = Convert(expression, integerType);
  115. return Assign(expression,
  116. Convert(decrement ? Decrement(converted) : Increment(converted),
  117. expression.Type));
  118. }
  119. else
  120. {
  121. return decrement ? PreDecrementAssign(expression) : PreIncrementAssign(expression);
  122. }
  123. }
  124.  
  125. private static MethodCallExpression DelegateCall(Delegate @delegate, params Expression[] arguments)
  126. {
  127. var method = @delegate.Method;
  128. var target = @delegate.Target;
  129. var eArguments = arguments.AsEnumerable();
  130. if (method.IsStatic)
  131. {
  132. if (target != null)
  133. {
  134. eArguments = eArguments.Prepend(Constant(target));
  135. }
  136. target = null;
  137. }
  138. return Call(target?.ConstantInternal(), method, eArguments);
  139. }
  140.  
  141. private static ConstantExpression ConstantInternal(this object value) => Constant(value);
  142.  
  143. private static Expression<Action<T[]>> Brainfuck<T>(string code, Type integerType, Action<T> writeMethod, Func<T> readMethod)
  144. {
  145. var array = Parameter(typeof(T[]), "array");
  146. var index = Variable(typeof(int));
  147. var variables = new[] { index };
  148. var current = ArrayAccess(array, index);
  149. var write = DelegateCall(writeMethod, current);
  150. var read = Assign(current, DelegateCall(readMethod));
  151. var cInc = OperateInteger(current, integerType, false);
  152. var cDec = OperateInteger(current, integerType, true);
  153. var xInc = PostIncrementAssign(index);
  154. var xDec = PostDecrementAssign(index);
  155. var test = Equal(current, Default(typeof(T)));
  156. var eStack = new Stack<List<Expression>>();
  157. eStack.Push(new List<Expression> { Assign(index, Divide(ArrayLength(array), Constant(2))) });
  158. try
  159. {
  160. foreach (var element in code)
  161. {
  162. var eList = eStack.Peek();
  163. switch (element)
  164. {
  165. case '+':
  166. eList.Add(cInc);
  167. break;
  168.  
  169. case '-':
  170. eList.Add(cDec);
  171. break;
  172.  
  173. case '>':
  174. eList.Add(xInc);
  175. break;
  176.  
  177. case '<':
  178. eList.Add(xDec);
  179. break;
  180.  
  181. case '.':
  182. eList.Add(write);
  183. break;
  184.  
  185. case ',':
  186. eList.Add(read);
  187. break;
  188.  
  189. case '[':
  190. eStack.Push(new List<Expression>());
  191. break;
  192.  
  193. case ']':
  194. {
  195. var label = Label();
  196. var @break = IfThen(test, Break(label));
  197. var pop = eStack.Pop();
  198. eStack.Peek().Add(Loop(Block(pop.Prepend(@break)), label));
  199. break;
  200. }
  201. }
  202. }
  203. Debug.WriteLine(eStack.Count);
  204. return Lambda<Action<T[]>>(Block(variables, eStack.Pop()), array);
  205. }
  206. catch (InvalidOperationException)
  207. {
  208. throw new ArgumentException("Compile error.", nameof(code));
  209. }
  210. }
  211. }
Success #stdin #stdout 0.15s 33228KB
stdin
B
+[>,]<[.[-]++++++++++.<]
Brainfuck
stdout
k
c
u
f
n
i
a
r
B