Advertisement
NPSF3000

NPSF3000 Simple Brainfuck Interpreter V0.01

Jun 27th, 2011
248
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 7.20 KB | None | 0 0
  1. #define USE_INSTRUCTION_COMPRESSION
  2.  
  3. //  NPSF3000 Simple Brainfuck Interpreter V0.01
  4. //  Free for Educational/Personal Use, Attribution required.
  5. //  Work In progress. Meant to be simple learning experiment hence lack of comments.
  6. //  Tested and works with non-trivial BF.
  7.  
  8. //  Contact, NPSF3001 Gmail.com
  9.  
  10. using System;
  11. using System.Collections.Generic;
  12. using System.Linq;
  13. using System.Text;
  14. using System.Diagnostics;
  15. using System.Windows.Forms;
  16.  
  17. class Program
  18. {
  19.     const byte END_OF_LINE = 10;
  20.     enum COMMANDS : byte { Left, Right, Add, Subtract, Input, Output, LoopStart, LoopEnd };
  21.  
  22.     [STAThread]
  23.     static void Main(string[] args)
  24.     {
  25.  
  26.         byte[] program;
  27.  
  28.         print("Use clipboard y/n?");
  29.  
  30.         if (Console.ReadKey(true).KeyChar.ToString().ToLower() == "y")
  31.         {
  32.             print(Clipboard.GetText());
  33.             program = CleanProgram(Clipboard.GetText());
  34.         }
  35.         else
  36.         {
  37.             print("Enter line of code");
  38.             program = CleanProgram(Console.ReadLine());
  39.         }
  40.  
  41. #if USE_INSTRUCTION_COMPRESSION
  42.         program = CompressProgram(program);
  43. #endif
  44.  
  45.         ushort[] LLU = new ushort[program.Length];
  46.  
  47.         foreach (var keyPair in ParseLoops(program))
  48.         {
  49.             LLU[keyPair.Value] = keyPair.Key;
  50.             LLU[keyPair.Key] = keyPair.Value;
  51.         }
  52.  
  53.  
  54.         while (true)
  55.         {
  56.  
  57.             ushort sPointer = 0, pPointer = 0;
  58.  
  59.             byte[] stack = new byte[ushort.MaxValue + 1];
  60.  
  61.             print("Starting Program");
  62.             Stopwatch sw = new Stopwatch();
  63.  
  64.             sw.Start();
  65.  
  66.             while (pPointer < program.Length)
  67.             {
  68.                 switch (program[pPointer])
  69.                 {
  70. #if USE_INSTRUCTION_COMPRESSION
  71.                     case (byte)COMMANDS.Right: pPointer++; sPointer += program[pPointer]; break;
  72.                     case (byte)COMMANDS.Left: pPointer++; sPointer -= program[pPointer]; break;
  73.                     case (byte)COMMANDS.Add: pPointer++; stack[sPointer] += (byte)program[pPointer]; break;
  74.                     case (byte)COMMANDS.Subtract: pPointer++; stack[sPointer] -= (byte)program[pPointer]; break;
  75. #else
  76.                     case (byte)COMMANDS.Right: sPointer++; break;
  77.                     case (byte)COMMANDS.Left: sPointer--; break;
  78.                     case (byte)COMMANDS.Add: stack[sPointer]++; break;
  79.                     case (byte)COMMANDS.Subtract: stack[sPointer]--; break;
  80. #endif
  81.                     case (byte)COMMANDS.Output: Output(stack[sPointer]); break;
  82.                     case (byte)COMMANDS.Input: stack[sPointer] = Input(); break;
  83.                     case (byte)COMMANDS.LoopStart:
  84.  
  85.                         if (stack[sPointer] == 0)
  86.                         {
  87.                             pPointer = LLU[pPointer];//FindLoopEnd[pPointer];
  88.                         } break;
  89.  
  90.  
  91.                     case (byte)COMMANDS.LoopEnd:
  92.  
  93.                         if (stack[sPointer] == 0) break;
  94.                         pPointer = LLU[pPointer]; //FindLoopStart[pPointer];
  95.  
  96.                         break;
  97.  
  98.                 }
  99.                 pPointer++;
  100.             }
  101.  
  102.             sw.Stop();
  103.  
  104.             stack = null;
  105.             GC.Collect();
  106.  
  107.             while (Console.KeyAvailable) Console.ReadKey();
  108.            
  109.             print("");
  110.             print("Program finished in " + sw.ElapsedMilliseconds.ToString() + "ms");
  111.             Console.ReadKey();
  112.         }
  113.     }
  114.  
  115.     static Dictionary<ushort, ushort> ParseLoops(byte[] program)
  116.     {
  117.         var result = new Dictionary<ushort, ushort>();
  118.  
  119.         for (ushort i = 0; i < program.Length; i++)
  120.         {
  121.             var command = program[i];
  122.  
  123.             if (IsCompressedCommand(command))
  124.             {
  125.                 i++; //Skip next instruction (which is part of the command);
  126.                 continue;
  127.             }
  128.  
  129.             if (command != (byte)(COMMANDS.LoopStart)) continue;
  130.  
  131.             ushort searchPos = i;
  132.  
  133.             byte brackets = 1;
  134.  
  135.             while (brackets != 0)
  136.             {
  137.                 // Skip to matching ']'
  138.  
  139.                 searchPos++;
  140.  
  141.                 byte searchCommand = program[searchPos];
  142.  
  143.                 if (IsCompressedCommand(searchCommand))
  144.                 {
  145.                     searchPos++; //Skip next instruction (which is part of the command);
  146.                     continue;
  147.                 }
  148.  
  149.                 switch (searchCommand)
  150.                 {
  151.                     case (byte)(COMMANDS.LoopStart): brackets++; break;
  152.                     case (byte)(COMMANDS.LoopEnd): brackets--; break;
  153.                 }
  154.             }
  155.  
  156.             result.Add(i, searchPos);
  157.         }
  158.         return result;
  159.     }
  160.  
  161.     static bool IsCompressedCommand(byte command)
  162.     {
  163. #if USE_INSTRUCTION_COMPRESSION
  164.         return ((command == (byte)COMMANDS.Add) || (command == (byte)COMMANDS.Subtract) || (command == (byte)COMMANDS.Left) || (command == (byte)COMMANDS.Right));
  165. #endif
  166.     }
  167.  
  168.     static void print(string line)
  169.     {
  170.         Console.WriteLine(line);
  171.     }
  172.  
  173.     static byte Input()
  174.     {
  175.  
  176.         //var input = (byte)Console.ReadKey(false).KeyChar.;
  177.         var input = Encoding.ASCII.GetBytes(Console.ReadKey(false).KeyChar.ToString())[0];
  178.  
  179.         if (input == 13) input = END_OF_LINE;
  180.  
  181.         return input;
  182.     }
  183.  
  184.     static void Output(byte value)
  185.     {
  186.  
  187.         if (value == END_OF_LINE) Console.WriteLine("");
  188.         else Console.Write(Encoding.ASCII.GetString(new[] { value }));
  189.     }
  190.  
  191.     static byte[] CompressProgram(byte[] wastefulProgram)
  192.     {
  193.         List<byte> program = new List<byte>(wastefulProgram.Count());
  194.  
  195.         for (int i = 0; i < wastefulProgram.Count(); i++)
  196.         {
  197.             byte command = wastefulProgram[i];
  198.  
  199.             if (IsCompressedCommand(command))
  200.             {
  201.                 program.Add(command);
  202.                 byte compressedValue = 1;
  203.  
  204.                 while (i+1 < wastefulProgram.Count() && command == wastefulProgram[i + 1])
  205.                 {
  206.                     i++;
  207.                     compressedValue++;
  208.  
  209.                     if (compressedValue == byte.MaxValue) break;
  210.                 }
  211.                 program.Add(compressedValue);
  212.  
  213.             }
  214.             else
  215.             {
  216.                 program.Add(command);
  217.             }
  218.         }
  219.         return program.ToArray();
  220.     }
  221.    
  222.     static byte[] CleanProgram(string dirtyProgram)
  223.     {
  224.         List<byte> program = new List<byte>(short.MaxValue);
  225.  
  226.         foreach (var command in dirtyProgram)
  227.         {
  228.             switch (command)
  229.             {
  230.                 case '>': program.Add((byte)COMMANDS.Right); break;
  231.                 case '<': program.Add((byte)COMMANDS.Left); break;
  232.                 case '+': program.Add((byte)COMMANDS.Add); break;
  233.                 case '-': program.Add((byte)COMMANDS.Subtract); break;
  234.                 case '.': program.Add((byte)COMMANDS.Output); break;
  235.                 case ',': program.Add((byte)COMMANDS.Input); break;
  236.                 case '[': program.Add((byte)COMMANDS.LoopStart); break;
  237.                 case ']': program.Add((byte)COMMANDS.LoopEnd); break;
  238.             }
  239.         }
  240.         return program.ToArray();
  241.     }
  242. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement