Scrivi un traduttore brainfuck


18

In qualsiasi linguaggio di programmazione o di scripting x , scrivere un programma che prende un codice sorgente brainfuck valido da stdin e output, a stdout, il codice sorgente del programma, scritto in linguaggio x , che produrrebbe esattamente la stessa cosa che farebbe il programma brainfuck.

Il programma deve funzionare per qualsiasi programma brainfuck valido, incluso il file vuoto.

Il tuo punteggio sarebbe uguale al conteggio dei byte del tuo codice sorgente, più il conteggio dei byte dell'output dato il seguente input:

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

Ad esempio, per un input di [-], l'output di *p=0;è molto più favorevole diwhile(*p) *p--;

Se ti capita di usare caratteri non ASCII, il conteggio dei byte deve essere calcolato usando la codifica UTF-8.

Il punteggio più basso vince. Tuttavia, le soluzioni creative che tentano di ridurre al minimo l'output devono essere incoraggiate dai voti positivi.


11
Potresti voler aggiungere una clausola secondo cui anche la lingua di destinazione non deve essere brainfuck;)
Josh,

@Josh bene, se qualcuno è riuscito a scrivere un breve programma brainfuck che rimuove codici inutili inutili, perché non lasciarlo fare?
user12205,

2
Bene semplicemente perché la banale soluzione di emettere la fonte invariata avrà comunque un punteggio davvero basso per il brainfuck. Sarò sorpreso se un'altra lingua riuscirà a batterlo.
Tim Seguine,

@Tim Seguine Potrei cambiare la domanda, ma sarebbe ingiusto per coloro che hanno già fornito una risposta? E se cambio la domanda, sto pensando di cambiare il calcolo del punteggio, rendendolo byte count of source + (byte count of output)^2, ciò incoraggerebbe le persone a concentrarsi maggiormente sulla semplificazione dell'output?
user12205

Generalmente cambiare una domanda del genere dopo che è già stata data una risposta è disapprovato. Stavo solo indicando un motivo per cui penso che Josh avesse ragione. È bene pubblicare prima cose come questa nella sandbox, in modo da poter risolvere potenziali problemi pur essendo onesti con tutti.
Tim Seguine,

Risposte:


12

Perl - 177 (fonte) + 172 (uscita) = 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 lo shebang come 2 byte, uno per ogni opzione. Innanzitutto, ciascuno degli otto comandi viene tradotto nell'intervallo p-w, rimuovendo allo stesso tempo tutti gli altri caratteri. Questa stringa viene quindi codificata per la lunghezza e viene emessa con un decodificatore / interprete minimo. Alcune cose sono ottimizzate: la stringa ><ovviamente non fa nulla e un ciclo for che segue direttamente un altro può essere rimosso del tutto, poiché non verrà mai inserito.

Uscita per il programma di test:

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

Un'esecuzione di esempio:

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

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

Questo si basa sull'osservazione di FIQ secondo cui se il programma originale non contiene un'istruzione input, l'output sarà statico e quindi può essere ridotto a una singola printistruzione. Se ti piace questo, assicurati di dare alla sua risposta un +1.

Quindi quello che possiamo fare è reindirizzare stdouta una variabile, evalil codice che avremmo prodotto e racchiudere il risultato in a print.

... non sempre funzionerà, comunque. Ogni volta che il codice da tradurre avrebbe comportato un ciclo infinito, (ad esempio +[.]), questo non può essere ridotto a una singola printistruzione, per ovvi motivi. Quindi, invece, lanciamo il evalprocesso in un figlio con un breve timeout e se non termina l'esecuzione entro quel tempo, produciamo il programma tradotto come prima.

Strutturato e commentato:

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

Uscita per programma di esempio:

print"Hello\ world\!"

Uscita per ,[.]:

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

Uscita per +[.](dopo 9 secondi):

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

1
Questo è fantastico! Il cervello fa male :)
Timwi,

Penso che wv.*?(?=w)sia sbagliato Penso che rimuoverà solo il codice fino al prossimo ], ma è necessario per trovare la corrispondenza ] ; devi occuparti della nidificazione ...
Timwi,

@Timwi Risolto, ignorando i casi nidificati wv[^v]*(?=w), che è significativamente più breve dell'alternativa.
primo

14

Brainfuck, 5 + 540 = 545 byte

5 byte di codice, 540 dall'output di un determinato file di test (supponendo che abbia ottenuto il conteggio proprio dal mio incolla di quel codice).

,[.,]

Supponendo che EOF sia 0.


@primo poiché non si reimposta prima di leggere un interprete che non modifica il valore su EOF renderà questo programma un ciclo infinito per tutti gli input superiori a 0 byte.
Sylwester,

Non posso fare a meno di chiedermi, quale software viene utilizzato per eseguire queste cose? xD
Teun Pronk,

@TeunPronk C'è un interprete brainfuck chiamato bfi ( github.com/susam/bfi ). Basta compilarlo e installarlo, ed eseguirlo in questo modo: bfi input.bfdov'è input.bfil file brainfuck da interpretare.
Braden Best

5

PHP, 553 + 27 = 580 byte

(553 byte con tutti gli spazi bianchi, ovvero newline e spazi, rimossi)

Faccio schifo al golf PHP, quindi questo approccio può essere fortemente ottimizzato. Volevo principalmente mostrare il mio approccio alla soluzione in qualcosa di non 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);

La segnalazione degli errori deve essere disattivata, altrimenti PHP ti odierà. Uso: lancialo come una pagina ed eseguilo con script.php? C = CODE (se lo script risultante richiede input, lo esegui come out.php? I = INPUT). Ricorda di urlare per evitare l'ingresso!

Ciò che fa sostanzialmente è questo: se lo script BF contiene ",", praticamente si incorpora come lo script risultante con $ b = 1 allegato; in cima. Se NON contiene ",", lo ottimizza fino a "echo '<BF output>'". Convenientemente, lo script di test nell'OP NON richiede alcun input. L'addlash () è lì solo per l'escape 'e \.


4

C ++, 695 + 510 = 1205 byte

Codice:

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

Produzione:

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

Codice originale:

#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

Codice:

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

Produzione:

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

1

io

659 + 553 = 1212

Cose come File standardInput readBufferOfLength(1)uccidere davvero il conteggio dei byte, ma non riesco a evitarlo. Non ho fatto ottimizzazioni per simboli ripetuti o mancanza di input nel programma BF, ma continuerò a lavorarci su, lavorando anche su uno sfruttando le capacità di metaprogrammazione di 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))

analisi

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

I rendimenti

Hello world!
659  +  553  = 1212

1

Brainfuck , 109 + 407 = 516

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

Provalo online!

Rimuove solo operazioni non BF e non esamina altre ottimizzazioni.


0

Lua - 328 + 2256 = 2584

(Oh, ho appena realizzato che è necessario aggiungere anche la lunghezza del risultato, punteggio scarso, sembra)

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

Tratto da questa mia risposta.


0

Lua - 319 + 21 = 340

Questo è probabilmente il codice più breve di tutti, ma non accetta input, quindi è un po 'economico. Ho avuto un'idea per un'altra versione con input, vedere la fine di questo commento.

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

Questa versione dimostra che lua può fare meglio di 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;"}))()')

Entrambe le versioni aggiungono 30000 byte di dati. La mia seconda versione si basa su input / output: tutto dopo un '.' o "," verranno rimossi. La mia seconda versione non consente loop infiniti ([.,], [], Ecc.)

La mia idea è di ottenere:

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

Dal tuo input, con un ulteriore ", +".

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.