Напишите переводчик брейкфук


18

На любом языке программирования или сценариев x напишите программу, которая получает действительный исходный код brainfuck из stdin и выводит в stdout исходный код программы, написанный на языке x , который будет выводить то же самое, что и программа brainfuck.

Ваша программа должна работать для любой действительной программы brainfuck, включая пустой файл.

Ваша оценка будет равна количеству байтов вашего исходного кода плюс число байтов вашего вывода с учетом следующего ввода:

+++++ [-]
+++++ +++++ [
    > +++++ ++
    > ++ +++ ++++ +
    > +++
    <<< -
]
> ++ . H
> + . e
++ +++ ++. l
. l
+++ . o
> ++ . space
< +++++ +++ . w
----- --- . o
+++ . r
---- - - . l
----- --- . d
> + . exclamation mark
------lol; useless code :-)--------------------------[.............................................][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]<-<<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><

Например, для входа [-], выход *p=0;гораздо более благоприятный, чемwhile(*p) *p--;

Если вы используете символы не ASCII, количество байтов должно быть рассчитано с использованием кодировки UTF-8.

Самый низкий балл побеждает. Тем не менее, креативные решения, которые пытаются минимизировать результат, должны поощряться голосованием.


11
Возможно, вы захотите добавить предложение о том, что целевой язык также не будет придурком;)
Джош

@ Хорошо, если кому-то удалось написать короткую программу, которая удаляет ненужные ненужные коды, почему бы не позволить им это сделать?
user12205

2
Ну, довольно просто, потому что тривиальное решение вывода источника без изменений в любом случае будет иметь действительно низкую оценку для мозгового хуя. Я буду удивлен, если другой язык может победить это.
Тим Сегин

@ Тим Seguine Я мог бы изменить вопрос, но будет ли это несправедливо по отношению к тем, кто уже дал ответ? И если я изменю вопрос, я подумываю об изменении подсчета баллов, сделав это byte count of source + (byte count of output)^2, побудит ли людей больше сосредоточиться на упрощении результатов?
user12205

Как правило, изменение такого вопроса после того, как на него уже был дан ответ, осуждается. Я просто указывал причину, почему я думаю, что Джош был прав. Хорошо сначала публиковать подобные вещи в песочнице, чтобы вы могли решить потенциальные проблемы, будучи справедливыми для всех.
Тим Сегин

Ответы:


12

Perl - 177 (источник) + 172 (выход) = 349

#!perl -p0
y/-+><.,[]
-~/p-w/d;s/(.)\K\1+|rs|wv[^v]*(?=w)/$+&&length$&/ge;$_="eval'r$_'=~".'s/.(\d*)/(qw(--$ ++$ -- ++ print+chr$ $$i=ord+getc; while($$i){ })[$&&v63].q($i;))x($++1)/ger'

Считая Шебанг как 2 байта, по одному для каждого варианта. Сначала каждая из восьми команд транслируется в диапазон p-w, одновременно удаляя все остальные символы. Эта строка затем кодируется по длине прогона и выводится с минимальным декодером / интерпретатором. Некоторые вещи оптимизированы: строка, ><очевидно, ничего не делает, и цикл for, который следует непосредственно за другим, может быть полностью удален, так как он никогда не будет введен.

Выход для тестовой программы:

eval'rq4vpwq9vrq6rq9rq2s2pwrq1trqtq6t1q2trq1tsq7tp7tq2tp5tp7trqtp32vt44wsps1'=~s/.(\d*)/(qw(--$ ++$ -- ++ print+chr$ $$i=ord+getc; while($$i){ })[$&&v63].q($i;))x($++1)/ger

Пример прогона:

$ perl brainfusk.pl < in.bf | perl
Hello world!

Perl - 232 (источник) + 21 (выход) = 253

#!perl -p0
y/-+><.,[]
-~/0-7/d;$_="eval'2$_'=~".'s/./qw(--$ ++$ -- ++ print+chr$ $$i=ord+getc; while($$i){ })[$&].q($i;)/ger';
/5/||fork?(wait,$?||exit):($SIG{ALRM}=sub{exit 1},alarm 9,$S=select(open 1,'>',\$o),eval,print$S "print\"\Q$o\E\"")

Это основано на наблюдении FIQ о том, что если исходная программа не содержит оператора ввода, вывод будет статическим и, следовательно, может быть сведен к одному printоператору. Если вам нравится этот, обязательно дайте его ответ +1.

Итак, что мы можем сделать - это передать данные stdoutпеременной, evalкод, который мы бы получили, и обернуть результат в print.

... это не всегда работает, хотя. Всякий раз, когда переводимый код приводил бы к бесконечному циклу (например +[.]), это не может быть сведено к одному printвыражению по очевидным причинам. Поэтому вместо этого мы запускаем evalдочерний процесс с коротким тайм-аутом, и если он не завершается в течение этого времени, мы выводим переведенную программу, как и раньше.

Структурировано и прокомментировано:

if(!/5/) { # no `,` in program

  if(fork) { # parent process

    # wait for child
    wait;
    # no child error, terminate without output
    $?||exit

  } else { # child process

    # alarm handler, exit with error
    $SIG{ALRM}=sub{exit 1};
    # set an alarm in 9 seconds
    alarm 9;
    # redirect STDOUT to variable $o
    $S=select open 1,'>',\$o;
    # execute translated code
    eval;
    # wrap the result in a print statement
    print$S "print\"\Q$o\E\""
  }
}

Выход для примера программы:

print"Hello\ world\!"

Выход для ,[.]:

eval'25647'=~s/./qw(--$ ++$ -- ++ print+chr$ $$i=ord+getc; while($$i){ })[$&].q($i;)/ger

Выход за +[.](через 9 секунд):

eval'21647'=~s/./qw(--$ ++$ -- ++ print+chr$ $$i=ord+getc; while($$i){ })[$&].q($i;)/ger

1
Это потрясающе! Мозг болит :)
Тимви

Я думаю, что wv.*?(?=w)это неправильно. Я думаю, что это только удалит код до следующего ], но вам нужно, чтобы найти соответствующий ] ; вам нужно позаботиться о вложенности ...
Тимви

@Timwi Исправлено, игнорируя вложенные случаи wv[^v]*(?=w), которые значительно короче альтернативы.
Примо

14

Brainfuck, 5 + 540 = 545 байт

5 байт кода, 540 из выходных данных данного тестового файла (при условии правильного подсчета из моей вставки этого кода).

,[.,]

Предполагая, что EOF равно 0.


@primo, поскольку он не сбрасывается перед чтением интерпретатора, который не изменяет значение в EOF, сделает эту программу бесконечным циклом для всех входных данных, превышающих 0 байтов.
Сильвестр

Не могу не задуматься, какое программное обеспечение используется для запуска этого материала? xD
Теун Пронк

@TeunPronk Есть переводчик брейкфак, который называется bfi ( github.com/susam/bfi ). Просто скомпилируйте и установите его, и запустите его так: bfi input.bfгде input.bfнаходится файл brainfuck для интерпретации.
Брэден Бест

5

PHP, 553 + 27 = 580 байт

(553 байта со всеми пропущенными пробелами, т.е. символами новой строки и пробелами)

Я плохо сосуюсь в игре в гольф на PHP, поэтому этот подход может быть сильно оптимизирован. В основном я хотел показать свой подход к решению проблемы не BF.

<?php
echo "<?php ";
$x = 'if (!$b) $c = $_GET[c];
$x=$y=$n[0]=$p=0;$o[0]=1;$d="";
while($a=$c[$x++]){
    if($o[$p]){
        if($a=="-")$m[$y]--;
        if($a=="+")$m[$y]++;
        $m[$y]=$m[$y]%256;
        if($a=="<")$y--;
        if($a==">")$y++;
        if($a=="."){
            $e=chr($m[$y]);
            if ($b) echo $e;
            else $d.=addslashes($e);
        }
        if($a==",")$m[$y]=($b=$_GET[i])?ord($b):0;
    }if($a=="["){
        $p++;
        $n[$p]=$x-1;
        $o[$p]=$o[$p-1]?$m[$y]:0;
    }
    if($a=="]"){
        if($o[$p])$x=$n[$p];
        $p--;
        if($p=-1)$p=0;
    }
}
if (!$b) echo "echo \'$d\';";';
if (strstr($_GET['c'],",")) {
    $x = '$b=1;'.$x;
    echo '$c="'.addslashes($_GET[c]).'";'.$x;
    return;
}
eval($x);

Сообщения об ошибках должны быть отключены, иначе PHP будет вас ненавидеть. Использование: выбросить это как страницу и запустить с помощью script.php? C = CODE (если результирующий скрипт требует ввода, вы запускаете его как out.php? I = INPUT). Не забудьте URL избежать входа!

В основном это происходит так: если скрипт BF содержит «,», он в значительной степени внедряется как результирующий скрипт с прикрепленным $ b = 1; наверху. Если он НЕ содержит «,», он оптимизирует его до «echo '<BF output>'». Удобно, что тестовый скрипт в OP НЕ требует ввода. Addlashes () только для экранирования 'и \.


4

C ++, 695 + 510 = 1205 байт

Код:

#include<iostream>
#include<utility>
#include<vector>
#define D "\n#define "
using namespace std;using S=string;int main(){vector<pair<S,S>>m={{"--------","(*p)-=8;"},{"<>",""},{"[]","F;"},{"+","A;"},{"-","B;"},{">","C;"},{"<","D;"},{"[","F{"},{"]","}"},{".","E;"},{",","std::cin>>*p;"}};S s;char c;while(cin>>c)if(S("+-><[].,").find(c)<8)s+=c;for(int i=0;i<s.length();i++)if(s.substr(i,4)=="[][]")s=s.replace(i--,4,"[]");cout<<"#include<iostream>" D"A ++*p" D"B --*p" D"C p++" D"D p--" D"E std::cout<<*p" D"F while(*p)\nint main(){char*p=new char[1<<19]();";while(s.size())for(auto p:m)if(s.substr(0,p.first.length())==p.first){s=s.substr(p.first.length());cout<<p.second;break;}cout<<"}";}

Выход:

#include<iostream>
#define A ++*p
#define B --*p
#define C p++
#define D p--
#define E std::cout<<*p
#define F while(*p)
int main(){char*p=new char[1<<19]();A;A;A;A;A;F{B;}A;A;A;A;A;A;A;A;A;A;F{C;A;A;A;A;A;A;A;C;A;A;A;A;A;A;A;A;A;A;C;A;A;A;D;D;D;B;}C;A;A;E;C;A;E;A;A;A;A;A;A;A;E;E;A;A;A;E;C;A;A;E;D;A;A;A;A;A;A;A;A;E;(*p)-=8;E;A;A;A;E;B;B;B;B;B;B;E;(*p)-=8;E;C;A;E;(*p)-=8;(*p)-=8;(*p)-=8;(*p)-=8;B;F{E;E;E;E;E;E;E;E;E;E;E;E;E;E;E;E;E;E;E;E;E;E;E;E;E;E;E;E;E;E;E;E;E;E;E;E;E;E;E;E;E;E;E;E;E;}F;D;B;D;D;}

Оригинальный код:

#include <iostream>
#include <utility>
#include <vector>
using namespace std;
int main() {
    vector<pair<string, string>> m={
    {"--------","(*p)-=8;"},
    {"<>",""},
    {"[]","F;"},
    {"+","A;"},
    {"-","B;"},
    {">","C;"},
    {"<","D;"},
    {"[","F{"},
    {"]","}"},
    {".","E;"},
    {",","std::cin>>*p;"}};
    string s;
    char c;
    while (cin >> c)
        if (string("+-><[].,").find(c) < 8)
            s += c;
    for(int i = 0; i < s.length(); i++)
        if(s.substr(i, 4) == "[][]")
            s = s.replace(i--, 4, "[]");
    cout << "#include<iostream>\n"
            "#define A ++*p\n"
            "#define B --*p\n"
            "#define C p++\n"
            "#define D p--\n"
            "#define E std::cout<<*p\n"
            "#define F while(*p)\n"
            "int main(){char*p=new char[1<<19]();";
    while (s.size())
        for (auto p : m)
            if (s.substr(0, p.first.length()) == p.first) {
                s = s.substr(p.first.length());
                cout << p.second;
                break;
            }
    cout << "}";
}

2

Python - 514 + 352 = 866

Код:

import sys,zlib,base64
s,i="import sys\na,i=[0]*300000,0\n",0
for c in sys.stdin.read():
 if c in"+-><,.[]":
  s+=" "*i+{'+':"a[i]+=1\n",'-':"a[i]-=1\n",'>':"i+=1\n",'<':"i-=1\n",',':"a[i]=(lambda x:0if x==''else ord(x))(sys.stdin.read(1))\n",".":"sys.stdout.write(chr(a[i]))\n","[":"while a[i]!=0:\n","]":"pass\n"}[c]
  i+={'[':1,']':-1}.get(c,0)
print('import zlib,base64\nexec(zlib.decompress(base64.b64decode("'+base64.b64encode(zlib.compress(bytes(s,"utf8"),9)).decode("utf8")+'")).decode("utf8"))')

Выход:

import zlib,base64
exec(zlib.decompress(base64.b64decode("eNrLzC3ILypRKK4s5krUybSNNojVMjYAAR0DrsTozFhtW0OCdHlGZk6qAoinaGtgxQVm6QLFFQoSi4uJNoVc2zJBggowWTIZVDGEEvMzddFJ1FDMxBYUwFjTKy5JyS8t0SsvyixJ1UjOKNIASWpqomrAp5DceMBnJjn2Ee0ZojToUiGlEfIFzA5yaGqHELXtp5XfMukVwMOFRi/u8IXZqOSo5KjkqOSIlAQ3k9BLy1HBUcFRwVFBOgpmIrfeMhGE9ihrpLEAudg3NA==")).decode("utf8"))

1

И.О.

659 + 553 = 1212

Такие вещи, как File standardInput readBufferOfLength(1)действительно убивают количество байтов, но я не могу обойти это. Я не проводил оптимизацию для повторяющихся символов или отсутствия ввода в программе BF, но продолжу работать над этим, также работая над одним, используя возможности метапрограммирования io.

"v :=Vector clone setSize(30000)
p :=0
z :=getSlot(\"method\")
j :=z(p=p+1)
k :=z(p=p-1)
a :=z(v at(p))
l :=z(v atPut(p,a+1))
m :=z(v atPut(p,a-1))
n :=z(a asCharacter print)
u :=getSlot(\"while\")
o :=z(v atPut(p,File standardInput readBufferOfLength(1)))"println
z :=getSlot("method")
g :=z(a,b,if(a,a,b))
v :=z(e,f,if((x :=s)==e,nil,f .. g(w(x),"")))
s :=z(File standardInput readBufferOfLength(1))
w :=z(c,c switch(">",v("<","j"),"<","k","+","l","-","m",".","n",",","o","[",v("]","u(a>0,"),"]",")"))
while((c :=s)!=nil,if((t :=w(c))!=nil,t println))

тестирование

cat test.bf | io bftrans.io > out.io && io out.io && echo && echo  $(cat out.io | wc -c) " + " $(cat bftrans.io | wc -c) " = "$(($(cat bftrans.io | wc -c) + $(cat out.io | wc -c)))

Урожайность

Hello world!
659  +  553  = 1212


0

Луа - 328 + 2256 = 2584

(О, я только что понял, что вам нужно добавить длину результата тоже, плохой результат, похоже)

print((("l,m,p=loadstring,{0},1 z,y,x,w,v,u=l'io.write(string.char(@))',l'@=io.read(1):byte()',l'p=p-1',l'p=p+1 @=@or 0',l'@=(@+1)%256',l'@=(@-1)%256'"..io.read"*a":gsub("[^.,<>[%]+-]",""):gsub(".",{["."]="z()",[","]="y()",["<"]="x()",[">"]="w()",["["]="while @~=0 do ",["]"]="end ",["+"]="v()",["-"]="u()"})):gsub("@","m[p]")))

Взято из этого моего ответа.


0

Луа - 319 + 21 = 340

Скорее всего, это самый короткий код из всех, но он не принимает ввод, поэтому он довольно обманчив. У меня есть идея для другой версии с вводом, см. Конец этого комментария.

loadstring("o=\"\";d={"..string.rep("0,",30000).."}p=1;"..io.read():gsub("[^%+%-<>%.,%[%]]+",""):gsub(".",{["+"]="d[p]=d[p]+1;",["-"]="d[p]=d[p]-1;",[">"]="p=p+1;",["<"]="p=p-1;",["."]="o=o..string.char(d[p])",[","]="d[p]=io.read()",["["]="while d[p]~=0 do ",["]"]="end;"}))()print("print("..string.format("%q",o)..")")

Луа - 376 + 366 = 742

Эта версия, чтобы доказать, что Луа может сделать лучше, чем 2584: D

print('loadstring("d={"..string.rep("0,",30000).."}p=1;"..('..string.format("%q",io.read():gsub("[^%+%-<>%.,%[%]]+",""):gsub("%[[^%+%-<>%,%[%]]*%]",""):match("(.*[.,]).-"))..'):gsub(".",{["+"]="d[p]=d[p]+1;",["-"]="d[p]=d[p]-1;",[">"]="p=p+1;",["<"]="p=p-1;",["."]="io.write(string.char(d[p]))",[","]="d[p]=string.byte(io.read())",["["]="while d[p]~=0 do ",["]"]="end;"}))()')

Обе версии добавляют в 30000 байтов данных. Моя вторая версия основана на вводе / выводе: все после «.» или ',' будет удален. Моя вторая версия не допускает бесконечных циклов ([.,], [] И т. Д.)

Моя идея состоит в том, чтобы получить:

print("Hello world!"..string.char(string.byte(io.read())+1)

Из вашего ввода, с дополнительным ', +.'

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.