Escribe un traductor de brainfuck

18

En cualquier lenguaje de programación o scripting x , escriba un programa que tome un código fuente válido de brainfuck de stdin y envíe, a stdout, el código fuente de un programa, escrito en lenguaje x , que generaría exactamente lo mismo que haría el programa brainfuck.

Su programa debe funcionar para cualquier programa válido de brainfuck, incluido el archivo vacío.

Su puntaje sería igual al recuento de bytes de su código fuente, más el recuento de bytes de su salida dada la siguiente entrada:

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

Por ejemplo, para una entrada de [-], la salida de *p=0;es mucho más favorable quewhile(*p) *p--;

Si utiliza caracteres no ASCII, el recuento de bytes debe calcularse utilizando la codificación UTF-8.

La puntuación más baja gana. Sin embargo, las soluciones creativas que intentan minimizar el resultado serán alentadas por los votos positivos.

usuario12205
fuente
11
Es posible que desee agregar una cláusula de que el idioma de destino no sea también una mierda mental;)
Josh
@Josh, bueno, si alguien logró escribir un breve programa de brainfuck que elimina códigos inútiles innecesarios, ¿por qué no dejar que lo hagan?
usuario12205
2
Bueno, simplemente porque la solución trivial de generar la fuente sin cambios va a tener un puntaje muy bajo de todos modos para el brainfuck. Me sorprendería si otro idioma puede superar eso.
Tim Seguine
@Tim Seguine Podría cambiar la pregunta, pero ¿sería injusto para quienes ya han proporcionado una respuesta? Y si cambio la pregunta, estoy pensando en cambiar el cálculo del puntaje, haciéndolo byte count of source + (byte count of output)^2, ¿eso animaría a las personas a centrarse más en simplificar el resultado?
usuario12205
Generalmente, cambiar una pregunta como esa después de que ya ha sido respondida está mal visto. Solo estaba señalando una razón por la que creo que Josh tenía razón. Es bueno publicar cosas como esta en el sandbox primero, para que pueda resolver posibles problemas y ser justo con todos.
Tim Seguine

Respuestas:

12

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

Contando el shebang como 2 bytes, uno para cada opción. Primero, cada uno de los ocho comandos se traduce al rango p-w, mientras que al mismo tiempo elimina todos los demás caracteres. Esta cadena se codifica en longitud de ejecución y se emite con un decodificador / intérprete mínimo. Algunas cosas están optimizadas: la cadena ><obviamente no hace nada, y un bucle for que sigue directamente después de otro puede eliminarse por completo, ya que nunca se ingresará.

Salida para el programa de prueba:

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

Una muestra de ejecución:

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

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

Este se basa en la observación de FIQ de que si el programa original no contiene una declaración de entrada, la salida será estática y, por lo tanto, puede reducirse a una sola printdeclaración. Si te gusta este, asegúrate de darle a su respuesta un +1.

Entonces, lo que podemos hacer es canalizar stdouta una variable, evalel código que obtendríamos, y envolver el resultado en a print.

... aunque eso no siempre funcionará. Siempre que el código a traducir hubiera resultado en un bucle infinito, (por ejemplo +[.]), esto no se puede reducir a una sola printdeclaración, por razones obvias. Entonces, en su lugar, iniciamos el evalproceso en un hijo con un breve tiempo de espera, y si no termina de ejecutarse dentro de ese tiempo, mostraremos el programa traducido como antes.

Estructurado y comentado:

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

Salida para el programa de muestra:

print"Hello\ world\!"

Salida para ,[.]:

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

Salida para +[.](después de 9 segundos):

eval'21647'=~s/./qw(--$ ++$ -- ++ print+chr$ $$i=ord+getc; while($$i){ })[$&].q($i;)/ger
primo
fuente
1
¡Esto es increíble! El cerebro duele :)
Timwi
Creo que wv.*?(?=w)esta mal. Creo que solo eliminará el código hasta el siguiente ], pero lo necesita para encontrar la coincidencia ] ; debes cuidar de anidar ...
Timwi 03 de
@Timwi fijo, al ignorar los casos anidados wv[^v]*(?=w), que es significativamente más corto que la alternativa.
primo
14

Brainfuck, 5 + 540 = 545 bytes

5 bytes de código, 540 de la salida del archivo de prueba dado (suponiendo que obtuve el recuento correcto de mi pegado de ese código).

,[.,]

Suponiendo que EOF es 0.

FIQ
fuente
@primo ya que no se reinicia antes de leer un intérprete que no cambia el valor en EOF hará de este programa un bucle sin fin para todas las entradas de más de 0 bytes.
Sylwester
No puedo evitar preguntarme, ¿qué software se utiliza para ejecutar estas cosas? xD
Teun Pronk
@TeunPronk Hay un intérprete llamado Brainfuckbfi ( github.com/susam/bfi ). Simplemente compílelo e instálelo, y ejecútelo así: ¿ bfi input.bfdónde input.bfse interpretará el archivo brainfuck?
Braden Best
5

PHP, 553 + 27 = 580 bytes

(553 bytes con todos los espacios en blanco, es decir, nuevas líneas y espacios, eliminados)

Soy muy malo en jugar golf en PHP, por lo que este enfoque puede optimizarse en gran medida. Sobre todo quería mostrar mi enfoque de la solución en algo que no sea 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);

El informe de errores debe estar desactivado, de lo contrario, PHP lo odiará. Uso: tire esto como una página y ejecútelo con script.php? C = CODE (si el script resultante requiere entrada, lo ejecuta como out.php? I = INPUT). Recuerde url escapar de la entrada!

Lo que esto hace es básicamente esto: si el script BF contiene ",", se incrusta prácticamente como el script resultante con un $ b = 1 adjunto; en la cima. Si NO contiene ",", lo optimiza a "echo '<BF output>'". Convenientemente, el script de prueba en el OP NO requiere ninguna entrada. El addlashes () está ahí para escapar 'y \.

FIQ
fuente
4

C ++, 695 + 510 = 1205 bytes

Código:

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

Salida:

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

Código original:

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

Python - 514 + 352 = 866

Código:

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

Salida:

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

io

659 + 553 = 1212

Cosas como File standardInput readBufferOfLength(1)realmente matar el conteo de bytes, pero no puedo evitarlo. No hice optimizaciones para símbolos repetidos o falta de entrada en el programa BF, pero continuaré trabajando en ello, también trabajando en uno haciendo uso de las capacidades de metaprogramación de 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))

Pruebas

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

Rendimientos

Hello world!
659  +  553  = 1212
Jordon Biondo
fuente
1

Brainfuck , 109 + 407 = 516

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

Pruébalo en línea!

Solo elimina operaciones que no son BF y no mira otras optimizaciones.

Sylwester
fuente
0

Lua - 328 + 2256 = 2584

(Oh, me acabo de dar cuenta de que también necesitas agregar la longitud del resultado, puntaje pobre, parece)

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

Tomado de esta respuesta mía.

mniip
fuente
0

Lua - 319 + 21 = 340

Este es probablemente el código más corto de todos, pero no acepta entradas, por lo que es un poco engañoso. Tengo una idea para otra versión con entrada, vea el final de este comentario.

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

Esta versión es para demostrar que Lua puede hacerlo mejor 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;"}))()')

Ambas versiones agregan 30000 bytes de datos. Mi segunda versión se basa en entrada / salida: todo después de un '.' o ',' será eliminado. Mi segunda versión no permite bucles infinitos ([.,], [], Etc.)

Mi idea es conseguir:

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

De su entrada, con un ', +' adicional.

YoYoYonnY
fuente