Транслятор brainfuck в C#

3 Янв
2012

В рамках попытки вспомнить C# написал транслятор из Brainfuck в C#, с возможностью дальнейшей компиляции программы в Mono.


Используется замена операторов brainfuck соответствующей конструкцией на C#.
Операции + — > <. , определяются внутри шаблона (как функции)
Внутри основного файла только задаётся метод их вызова (т.е. то, чем будет заменена каждая из этих инструкций). Также внутри него определены реакции на [ ] (циклом while)
Написан с использованием Visual Studio 2010, но успешно компилируется в Mono.
Использование:
bf.exe <файл brainfuck-кода (с расширением .bf)> -c
Ключ -c — опциональный, скармливает полученный C# файл Mono

Вот код транслятора:
  1.  
  2. using System;
  3. using System.Collections;
  4. using System.Linq;
  5. using System.Text;
  6. using System.IO;
  7. using System.Diagnostics;
  8.  
  9. namespace ConsoleApplication1
  10. {
  11.     class Program
  12.     {
  13.         static void WriteLine(string message)
  14.         {
  15.             Console.WriteLine(message);
  16.         }
  17.  
  18.         static void WriteError(string message)
  19.         {
  20.             WriteLine(message);
  21.             Process.GetCurrentProcess().Kill();
  22.         }
  23.  
  24.         //Получаем C# код по коду brainfuck
  25.         static string translateBrainFuck(string bf_code)
  26.         {
  27.             string res = «»;
  28.  
  29.             //Функции, которые должны быть описаны в шаблоне :
  30.             // changeElement(value) — изменение значения элемента в текущей ячейке на value
  31.             // memoryIndex — индекс текущей ячейки памяти
  32.             // outputElement — вывод символа, соответствующего текущему значению ячейки памяти
  33.             // inputElement — запись в ячейку кода введённого символа
  34.  
  35.             //Заменыв формате
  36.             //<brainfuck> <C#> <cycle>
  37.             //где :
  38.             // cycle == 0 если конструкция не задаёт цикла
  39.             // cycle == 1 если конструкция открывает цикл
  40.             // cycle == 2 если конструкция закрывает цикл
  41.             object[] replaces ={new string[]{«+»,«changeElement(+1);»,«0»},
  42.                                 new string[]{«-«,«changeElement(-1);»,«0»},
  43.                                 new string[]{«>»,«memoryIndex++;»,«0»},
  44.                                 new string[]{«<«,«memoryIndex—;»,«0»},
  45.                                 new string[]{«.»,«outputElement();»,«0»},
  46.                                 new string[]{«,»,«inputElement();»,«0»},
  47.                                 new string[]{«[«,«while(getElement()!=0){«,«1»},
  48.                                 new string[]{«]»,«}»,«2»}};
  49.  
  50.             //Количество отступов
  51.             int tabcount = 3;
  52.             foreach (char chr in bf_code)
  53.             {
  54.                 int i = 0;
  55.                 string[] obj;
  56.  
  57.                 //Поиск соответствующей символу замены
  58.                 int replaceNum = 1;
  59.                 while(replaceNum==1){
  60.                     obj=(string[])replaces[i];
  61.                     if(obj[0]==chr.ToString()){
  62.                         replaceNum=i;
  63.                     }
  64.                     i++;
  65.                     if (> replaces.Length)
  66.                     {
  67.                         WriteError(«Fatal error: illegal character ‘» + chr.ToString() + «‘»);
  68.                     }
  69.                 }
  70.  
  71.                 obj=(string[])replaces[replaceNum];
  72.                 string c_sharp = obj[1];
  73.                 string cycle = obj[2];
  74.                 string tabs = «»;
  75.                 int tabchange = 0;
  76.  
  77.                 //Изменение отступа
  78.                 if (cycle == «1») {
  79.                     //Для начала цикла отступ поменяем уже после дописывания в код цикла
  80.                     tabchange = 1;
  81.                 }
  82.                 else
  83.                 if (cycle == «2») {
  84.                     tabcount;
  85.                 }
  86.  
  87.                 //Формируем табуляции
  88.                 for (= 1; i <= tabcount; i++)
  89.                 {tabs += «t»;}
  90.  
  91.                 tabcount += tabchange;
  92.  
  93.                 res += tabs + c_sharp+«\n«;
  94.             }
  95.  
  96.             return res;
  97.         }
  98.  
  99.         static void Main(string[] args)
  100.         {
  101.  
  102.             try
  103.             {
  104.                 if (args[0].IndexOf(«help») != 1)
  105.                 {
  106.                     WriteError(«this is translator from brainfuck to c#.\n Written by Pozharckey Alexander in 2011.\n May use Mono for compilation created C# code»);
  107.                 }
  108.             }
  109.             catch { }
  110.  
  111.  
  112.  
  113.             //Загрузка настроек из конфига
  114.             StreamReader config = new StreamReader(AppDomain.CurrentDomain.BaseDirectory + «brainfuck.conf»);
  115.             string pattern = config.ReadLine().Replace(«THIS.»,AppDomain.CurrentDomain.BaseDirectory);
  116.             string monoPath = config.ReadLine();
  117.             config.Close();
  118.  
  119.  
  120.  
  121.             string code = «»; 
  122.             string bf_code=«»;
  123.             string line = «»;
  124.  
  125.             string brainfuckFile = «»;
  126.             string outFName = «»;
  127.             try
  128.             {
  129.                 brainfuckFile = args[0];
  130.                 outFName = brainfuckFile.Replace(«.bf»«.cs»);
  131.                 Environment.CurrentDirectory = Path.GetDirectoryName(brainfuckFile);
  132.             }
  133.             catch
  134.             {
  135.                 WriteError(«Error in parameters.\n Use :\n bf.exe «brainfuckFileName» -c(if need to compile file)»);
  136.             }
  137.             StreamReader file;
  138.  
  139.  
  140.  
  141.             try
  142.             {
  143.                 WriteLine(«Reading BRAINFUCK code file : ‘» + brainfuckFile + «‘»);
  144.                 file = new StreamReader(brainfuckFile);
  145.                 bf_code = file.ReadToEnd();
  146.                 file.Close();
  147.             }
  148.             catch
  149.             {
  150.                 WriteError(«Error while reading : ‘» + brainfuckFile + «‘»);
  151.             }
  152.             WriteLine(«File ‘» + brainfuckFile + «‘ readed succesfully»);
  153.  
  154.  
  155.  
  156.  
  157.             try
  158.             {
  159.                 WriteLine(«Reading template : ‘»+pattern+«‘»);
  160.                 file = new StreamReader(pattern);
  161.                 while ((line = file.ReadLine()) != null)
  162.                 {
  163.                     if (line.IndexOf(«//body») == 1)
  164.                     {
  165.                         code += line + «\n«;
  166.                     }
  167.                     else
  168.                     {
  169.                         code += translateBrainFuck(bf_code) + «\n«;
  170.                     }
  171.                 }
  172.                 file.Close();
  173.             }
  174.             catch
  175.             {
  176.                 WriteError(«Error while reading template ‘» + pattern + «‘»);
  177.             }
  178.             WriteLine(«File ‘» + pattern + «‘ readed sucessfully»);
  179.  
  180.  
  181.  
  182.             try
  183.             {
  184.                 WriteLine(«Writing C# result to : ‘» + outFName + «‘»);
  185.                 StreamWriter outFile = new StreamWriter(outFName);
  186.                 outFile.Write(code);
  187.                 outFile.Close();
  188.             }
  189.             catch
  190.             {
  191.                 WriteError(«Error while writing C# result to : ‘» + outFName + «‘»);
  192.             }
  193.             WriteLine(«C# result succesfully writed to : ‘» + outFName + «‘»);
  194.  
  195.  
  196.  
  197.             try
  198.             {
  199.                 if (args[1] == «-c»)
  200.                 {
  201.  
  202.                     Process monoProc = new Process();
  203.                     monoProc.StartInfo.UseShellExecute = false;
  204.                     monoProc.StartInfo.FileName = monoPath;
  205.                     monoProc.StartInfo.Arguments = «»» + outFName + ««»;
  206.                     monoProc.StartInfo.WorkingDirectory = Path.GetDirectoryName(outFName);
  207.                     monoProc.StartInfo.RedirectStandardOutput = true;
  208.                     monoProc.StartInfo.RedirectStandardError = true;
  209.                     monoProc.Start();
  210.                     monoProc.WaitForExit();
  211.  
  212.                     WriteLine(«Mono standart output : \n«+monoProc.StandardOutput.ReadToEnd());
  213.                     WriteLine(«Mono error output : \n« + monoProc.StandardError.ReadToEnd());
  214.                 }
  215.             }
  216.             catch { }
  217.         }
  218.     }
  219. }


Код шаблона:
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Collections;
  6.  
  7. namespace CnsoleApp
  8. {
  9.     class Program
  10.     {
  11. static ArrayList memory = new ArrayList();
  12.         static int memoryIndex = 0;
  13.  
  14.         static void changeElement(int value)
  15.         {
  16.             try
  17.             {
  18.                 memory[memoryIndex] = (int)memory[memoryIndex] + value;
  19.             }
  20.             catch
  21.             {
  22.                 memory.Add(value);
  23.             }
  24.         }
  25.  
  26.         static int getElement()
  27.         {
  28.             try
  29.             {
  30.                 return (int)memory[memoryIndex];
  31.             }
  32.             catch
  33.             {
  34.                 return 0;
  35.             }
  36.         }
  37.  
  38. static void inputElement()
  39. {
  40.             ConsoleKeyInfo k = Console.ReadKey();
  41.             int code=(int)(Encoding.ASCII.GetBytes(new char[]{k.KeyChar})[0]);
  42. try
  43. {
  44. memory[memoryIndex]=code;
  45. }
  46. catch
  47. {
  48. memory.Add(code);
  49. }
  50. }
  51.  
  52.         static void outputElement()
  53.         {
  54.             int iEL=(int)memory[memoryIndex];
  55.             byte[] el = { (byte)iEL };
  56.             char chr = Encoding.ASCII.GetChars(el)[0];
  57.             Console.Write(chr);
  58.         }
  59.  
  60.         static void Main(string[] args)
  61.         {
  62. int memoryIndex=0;
  63.  
  64. //body
  65.  
  66. Console.Write(«\n«);
  67.         }
  68.     }
  69. }


Конфиг (файл brainfuck.conf) должен находиться в той же директории, что и исполняемый файл транслятора и иметь такой вид
<путь к шаблону> (если он находится в той же папке, что и файл приложения, или расположение задано относительно неё, то вместо директории приложения можно указать THIS.)
<путь к компилятору mono>

Например, запустим такую прогу:
,[-.]

(для сборки и запуска я юзал такой bat-файл:
@echo off
echo «Compiling»
ConsoleApplication1.exe «C:\Users\alex\Documents\Visual Studio 2010\Projects\ConsoleApplication1\ConsoleApplication1\bin\Debug\bf.bf» -c
pause
echo «»
echo «»
bf.exe
pause
)
Результат скармливания:
"Compiling"
Reading BRAINFUCK code file : 'C:\Users\alex\Documents\Visual Studio 2010\Projects\ConsoleApplication1\ConsoleApplication1\bin\Debug\bf.bf'
File 'C:\Users\alex\Documents\Visual Studio 2010\Projects\ConsoleApplication1\ConsoleApplication1\bin\Debug\bf.bf' readed succesfully
Reading template : 'C:\Users\alex\Documents\Visual Studio 2010\Projects\ConsoleApplication1\ConsoleApplication1\bin\Debug\base.cs'
File 'C:\Users\alex\Documents\Visual Studio 2010\Projects\ConsoleApplication1\ConsoleApplication1\bin\Debug\base.cs' readed sucessfully
Writing C# result to : 'C:\Users\alex\Documents\Visual Studio 2010\Projects\ConsoleApplication1\ConsoleApplication1\bin\Debug\bf.cs'
C# result succesfully writed to : 'C:\Users\alex\Documents\Visual Studio 2010\Projects\ConsoleApplication1\ConsoleApplication1\bin\Debug\bf.cs'
Mono standart output :
Compilation succeeded - 1 warning(s)

Mono error output :
C:\Users\alex\Documents\Visual Studio 2010\Projects\ConsoleApplication1\ConsoleApplication1\bin\Debug\bf.cs(62,17): warning CS0219: The variable `memoryIndex' is assigned but
its value is never used

Для продолжения нажмите любую клавишу . . .
""
""
♀♂3210/.-,+*)('&%$#"! ▼▲↔∟←→↓↑↨▬§¶‼↕◄►☼♫
♠♣♦♥☻☺
Для продолжения нажмите любую клавишу . . .
По материалам Хабрахабр.



загрузка...

Комментарии:

Наверх