Ecrire un traducteur brainfuck


18

Dans tout langage de programmation ou de script x , écrivez un programme qui prend un code source brainfuck valide de stdin et de sortie, vers stdout, le code source d'un programme, écrit en langage x , qui produirait exactement la même chose que le programme brainfuck.

Votre programme doit fonctionner pour tout programme brainfuck valide, y compris le fichier vide.

Votre score serait égal au nombre d'octets de votre code source, plus le nombre d'octets de votre sortie étant donné l'entrée suivante:

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

Par exemple, pour une entrée de [-], la sortie de *p=0;est beaucoup plus favorable quewhile(*p) *p--;

S'il vous arrive d'utiliser des caractères non ASCII, le nombre d'octets doit être calculé à l'aide du codage UTF-8.

Le score le plus bas l'emporte. Cependant, les solutions créatives qui tentent de minimiser la sortie doivent être encouragées par des votes positifs.


11
Vous voudrez peut-être ajouter une clause stipulant que la langue cible ne doit pas non plus être encerclée;)
Josh

@Josh bien, si quelqu'un a réussi à écrire un court programme de brainfuck qui supprime les codes inutiles inutiles, pourquoi ne pas les laisser le faire?
user12205

2
Eh bien tout simplement parce que la solution triviale de sortie de la source inchangée aura de toute façon un score très bas pour le brainfuck. Je serai surpris si une autre langue peut battre cela.
Tim Seguine

@Tim Seguine Je pourrais changer la question, mais est-ce injuste pour ceux qui ont déjà fourni une réponse? Et si je change la question, je pense à changer le calcul du score, ce byte count of source + (byte count of output)^2qui encouragerait les gens à se concentrer davantage sur la simplification de la sortie?
user12205

Généralement, changer une question comme celle-là après avoir déjà répondu est mal vu. Je montrais juste une raison pour laquelle je pense que Josh avait raison. Il est bon de publier des trucs comme celui-ci dans le bac à sable d'abord, afin que vous puissiez résoudre les problèmes potentiels tout en étant juste pour tout le monde.
Tim Seguine

Réponses:


12

Perl - 177 (source) + 172 (sortie) = 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'

Compter le shebang comme 2 octets, un pour chaque option. Tout d'abord, chacune des huit commandes est traduite dans la plage p-w, tout en supprimant tous les autres caractères. Cette chaîne est ensuite encodée en longueur et émise avec un décodeur / interprète minimal. Quelques choses sont optimisées: la chaîne ><ne fait évidemment rien, et une boucle for qui suit directement après une autre peut être supprimée complètement, car elle ne sera jamais entrée.

Sortie pour le programme de test:

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

Un exemple d'exécution:

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

Perl - 232 (source) + 21 (sortie) = 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\"")

Celui-ci est basé sur l'observation de la FIQ selon laquelle si le programme d'origine ne contient pas d'instruction d'entrée, la sortie sera statique et peut donc être réduite à une seule printinstruction. Si vous aimez celui-ci, assurez-vous de donner à sa réponse un +1.

Donc, ce que nous pouvons faire, c'est diriger stdoutvers une variable, evalle code que nous aurions en sortie, et encapsuler le résultat dans un print.

... mais ça ne marchera pas toujours. Chaque fois que le code à traduire aurait entraîné une boucle infinie, (par exemple +[.]), cela ne peut pas être réduit à une seule printinstruction, pour des raisons évidentes. Donc, à la place, nous lançons le evalprocessus dans un enfant avec un court délai d'expiration, et s'il ne termine pas son exécution dans ce délai, nous générons le programme traduit comme auparavant.

Structuré et commenté:

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\""
  }
}

Sortie pour exemple de programme:

print"Hello\ world\!"

Sortie pour ,[.]:

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

Sortie pour +[.](après 9 secondes):

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

1
Ceci est incroyable! Le cerveau fait mal :)
Timwi

Je pense que wv.*?(?=w)c'est faux. Je pense que cela ne supprimera que le code jusqu'au suivant ], mais vous en avez besoin pour trouver la correspondance ] ; vous devez prendre soin de la nidification ...
Timwi

@Timwi Fixed, en ignorant les cas imbriqués wv[^v]*(?=w), ce qui est nettement plus court que l'alternative.
primo

14

Brainfuck, 5 + 540 = 545 octets

5 octets de code, 540 à partir de la sortie du fichier de test donné (en supposant que le décompte soit correct à partir de ma pâte de ce code).

,[.,]

En supposant que EOF est 0.


@primo car il ne se réinitialise pas avant de lire un interpréteur qui ne modifie pas la valeur à EOF fera de ce programme une boucle sans fin pour toutes les entrées supérieures à 0 octet.
Sylwester

Je ne peux pas m'empêcher de me demander quel logiciel est utilisé pour exécuter ce genre de choses? xD
Teun Pronk

@TeunPronk Il y a un interprète de brainfuck appelé bfi ( github.com/susam/bfi ). Compilez-le et installez-le, puis exécutez-le comme ceci: bfi input.bfinput.bfest le fichier brainfuck à interpréter.
Braden Best

5

PHP, 553 + 27 = 580 octets

(553 octets avec tous les espaces blancs, c'est-à-dire les nouvelles lignes et les espaces, supprimés)

Je crains mal au golf PHP, donc cette approche peut être fortement optimisée. Je voulais surtout montrer mon approche de la solution dans quelque chose qui n'était pas 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);

Le signalement des erreurs doit être désactivé, sinon PHP vous détestera. Utilisation: lancez cela comme une page et exécutez-le avec script.php? C = CODE (si le script résultant nécessite une entrée, vous l'exécutez comme out.php? I = INPUT). N'oubliez pas d'url échapper à l'entrée!

Ce que cela fait est fondamentalement ceci - si le script BF contient ",", il s'incorpore à peu près comme le script résultant avec un $ b = 1 attaché; au sommet. S'il ne contient PAS ",", il l'optimise jusqu'à "echo '<sortie BF>'". Idéalement, le script de test dans l'OP ne nécessite aucune entrée. L'addlashs () est juste là pour échapper 'et \.


4

C ++, 695 + 510 = 1205 octets

Code:

#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<<"}";}

Production:

#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;}

Code d'origine:

#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

Code:

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"))')

Production:

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

1

io

659 + 553 = 1212

Des choses comme File standardInput readBufferOfLength(1)vraiment tuer le nombre d'octets mais je ne peux pas le contourner. Je n'ai pas fait d'optimisations pour les symboles répétés ou le manque d'entrée dans le programme BF, mais je continuerai à y travailler, en travaillant également sur celui utilisant les capacités de métaprogrammation d'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))

Essai

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)))

Rendements

Hello world!
659  +  553  = 1212

1

Brainfuck , 109 + 407 = 516

>+[>+++++++[-<------>]<-[-[-[-[--------------[--[>+++++[-<------>]<+[--[[-]<[-]>]]]]]]]]<[.[-]]>>,[-<+<+>>]<]

Essayez-le en ligne!

Il supprime uniquement les opérations non BF et ne regarde pas les autres optimisations.


0

Lua - 328 + 2256 = 2584

(Oh, je viens de réaliser que vous devez aussi ajouter la longueur du résultat, mauvais score, on dirait)

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]")))

Tiré de cette réponse à moi.


0

Lua - 319 + 21 = 340

C'est probablement le code le plus court de tous, mais il n'accepte pas d'entrée, il est donc un peu tricheur. J'ai eu une idée pour une autre version avec entrée, voir la fin de ce commentaire.

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)..")")

Lua - 376 + 366 = 742

Cette version doit prouver que lua peut faire mieux que 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;"}))()')

Les deux versions ajoutent 30000 octets de données. Ma deuxième version est basée sur les entrées / sorties: tout après un '.' ou ',' sera supprimé. Ma deuxième version ne permet pas les boucles infinies ([.,], [], Etc.)

Mon idée est d'obtenir:

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

De votre entrée, avec un supplément «, +».

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.