Viết một dịch giả Brainfuck


18

Trong bất kỳ ngôn ngữ lập trình hoặc kịch bản x nào , hãy viết một chương trình lấy mã nguồn gốc hợp lệ từ stdin và đầu ra, đến stdout, mã nguồn của chương trình, được viết bằng ngôn ngữ x , sẽ tạo ra chính xác như chương trình brainfuck sẽ làm.

Chương trình của bạn phải hoạt động cho bất kỳ chương trình brainfuck hợp lệ nào, bao gồm cả tệp trống.

Điểm của bạn sẽ bằng với số byte của mã nguồn của bạn, cộng với số byte của đầu ra của bạn cho đầu vào sau:

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

Ví dụ, đối với đầu vào của [-], đầu ra của *p=0;thuận lợi hơn nhiều so với đầu vàowhile(*p) *p--;

Nếu bạn tình cờ sử dụng các ký tự không phải ASCII, số byte phải được tính bằng mã hóa UTF-8.

Điểm số thấp nhất chiến thắng. Tuy nhiên, các giải pháp sáng tạo cố gắng giảm thiểu đầu ra sẽ được khuyến khích bởi các upvote.


11
Bạn có thể muốn thêm một mệnh đề rằng ngôn ngữ đích cũng không phải là brainfuck;)
Josh

@Josh tốt, nếu ai đó quản lý để viết một chương trình brainfuck ngắn loại bỏ các mã vô dụng không cần thiết, tại sao không để họ làm điều đó?
dùng12205

2
Cũng khá đơn giản bởi vì giải pháp tầm thường của việc xuất nguồn không thay đổi sẽ có điểm thực sự thấp cho dù sao đi nữa. Tôi sẽ ngạc nhiên nếu một ngôn ngữ khác có thể đánh bại điều đó.
Tim Seguine

@Tim Seguine Tôi có thể thay đổi câu hỏi, nhưng điều đó có bất công với những người đã cung cấp câu trả lời không? Và nếu tôi thay đổi câu hỏi, tôi đang nghĩ về việc thay đổi cách tính điểm, làm cho nó byte count of source + (byte count of output)^2, điều đó có khuyến khích mọi người tập trung hơn vào việc đơn giản hóa đầu ra không?
dùng12205

Nói chung thay đổi một câu hỏi như vậy sau khi nó đã được trả lời là nhăn mặt. Tôi chỉ nêu ra một lý do tại sao tôi nghĩ Josh đã đúng. Thật tốt khi đăng những thứ như thế này vào hộp cát trước, vì vậy bạn có thể giải quyết các vấn đề tiềm ẩn trong khi công bằng với mọi người.
Tim Seguine

Câu trả lời:


12

Perl - 177 (nguồn) + 172 (đầu ra) = 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'

Đếm shebang là 2 byte, mỗi byte cho một tùy chọn. Đầu tiên, mỗi trong số tám lệnh được dịch lên phạm vi p-w, đồng thời loại bỏ tất cả các ký tự khác. Chuỗi này sau đó được mã hóa chiều dài chạy và đầu ra với bộ giải mã / trình thông dịch tối thiểu. Một vài điều được tối ưu hóa đi: chuỗi ><rõ ràng không làm gì cả và một vòng lặp for ngay sau chuỗi khác có thể bị xóa hoàn toàn, vì nó sẽ không bao giờ được nhập.

Đầu ra cho chương trình thử nghiệm:

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

Một mẫu chạy:

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

Perl - 232 (nguồn) + 21 (đầu ra) = 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\"")

Điều này dựa trên quan sát của FIQ rằng nếu chương trình ban đầu không chứa câu lệnh đầu vào, đầu ra sẽ ở trạng thái tĩnh và do đó có thể được giảm xuống thành một printcâu lệnh. Nếu bạn thích câu hỏi này, hãy chắc chắn đưa ra câu trả lời của anh ấy +1.

Vì vậy, những gì chúng ta có thể làm là dẫn stdoutđến một biến, evalmã chúng ta sẽ có đầu ra và bọc kết quả trong a print.

... điều đó sẽ không luôn luôn làm việc, mặc dù. Bất cứ khi nào mã được dịch sẽ dẫn đến một vòng lặp vô hạn, (ví dụ +[.]), điều này không thể được giảm xuống thành một printcâu lệnh, vì những lý do rõ ràng. Vì vậy, thay vào đó, chúng tôi khởi chạy evaltiến trình con với thời gian chờ ngắn và nếu nó không hoàn thành thực thi trong thời gian đó, chúng tôi sẽ xuất chương trình dịch như trước.

Cấu trúc và nhận xét:

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

Đầu ra cho chương trình mẫu:

print"Hello\ world\!"

Đầu ra cho ,[.]:

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

Đầu ra cho +[.](sau 9 giây):

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

1
Thật đáng kinh ngạc! Đau não :)
Timwi

Tôi nghĩ wv.*?(?=w)là sai. Tôi nghĩ rằng nó sẽ chỉ loại bỏ mã cho đến tiếp theo ], nhưng bạn cần nó để tìm sự phù hợp ] ; bạn cần phải chăm sóc làm tổ ...
Timwi

@Timwi Đã sửa, bằng cách bỏ qua các trường hợp lồng nhau wv[^v]*(?=w), ngắn hơn đáng kể so với phương án.
primo

14

Brainfuck, 5 + 540 = 545 byte

5 byte mã, 540 từ đầu ra của tệp thử nghiệm đã cho (giả sử có số đếm ngay từ lần dán mã đó của tôi).

,[.,]

Giả sử EOF là 0.


@primo vì nó không được thiết lập lại trước khi đọc trình thông dịch không có giá trị chaneg tại EOF sẽ làm cho chương trình này trở thành một vòng lặp vô tận cho tất cả đầu vào lớn hơn 0 byte.
Sylwester

Tôi không thể giúp tự hỏi, phần mềm nào được sử dụng để chạy công cụ này? xD
Teun Pronk

@TeunPronk Có một trình thông dịch Brainfuck được gọi là bfi ( github.com/susam/bfi ). Chỉ cần biên dịch và cài đặt nó, và chạy nó như vậy: bfi input.bfnơi input.bfđược file Brainfuck để được giải thích.
Braden hay nhất

5

PHP, 553 + 27 = 580 byte

(553 byte với tất cả các khoảng trắng, tức là dòng mới và dấu cách, đã bị xóa)

Tôi rất tệ trong việc chơi golf PHP, vì vậy cách tiếp cận này có thể được tối ưu hóa mạnh mẽ. Tôi chủ yếu muốn thể hiện cách tiếp cận của tôi với giải pháp trong một cái gì đó không phải là 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);

Báo cáo lỗi phải được tắt, nếu không PHP sẽ ghét bạn. Cách sử dụng: ném nó lên như một trang và chạy nó với script.php? C = CODE (nếu tập lệnh kết quả yêu cầu đầu vào, bạn chạy nó dưới dạng out.php? I = INPUT). Nhớ url thoát khỏi đầu vào!

Về cơ bản, đây là cái gì - nếu tập lệnh BF chứa ",", nó sẽ tự nhúng vào đó như tập lệnh kết quả với $ b = 1 đính kèm; ở trên cùng Nếu nó KHÔNG chứa ",", nó sẽ tối ưu hóa thành "echo '<đầu ra BF>'". Thuận tiện, tập lệnh thử nghiệm trong OP KHÔNG yêu cầu bất kỳ đầu vào. Các addlash () chỉ ở đó để thoát 'và \.


4

C ++, 695 + 510 = 1205 byte

Mã số:

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

Đầu ra:

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

Mã gốc:

#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

Con trăn - 514 + 352 = 866

Mã số:

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

Đầu ra:

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

1

io

659 + 553 = 1212

Những thứ như File standardInput readBufferOfLength(1)thực sự giết chết số byte nhưng tôi không thể vượt qua nó. Tôi đã không thực hiện tối ưu hóa cho các biểu tượng lặp đi lặp lại hoặc thiếu đầu vào trong chương trình BF, nhưng sẽ tiếp tục làm việc với nó, cũng làm việc với việc sử dụng các khả năng siêu lập trình của 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))

Kiểm tra

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

Sản lượng

Hello world!
659  +  553  = 1212

1

Brainfuck , 109 + 407 = 516

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

Hãy thử trực tuyến!

Nó chỉ loại bỏ các op không BF và không nhìn vào các tối ưu hóa khác.


0

Lua - 328 + 2256 = 2584

(Ồ tôi mới nhận ra bạn cũng cần thêm độ dài của kết quả, điểm kém, có vẻ như vậy)

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

Lấy từ câu trả lời này của tôi.


0

Lua - 319 + 21 = 340

Đây rất có thể là mã ngắn nhất trong tất cả, nhưng nó không chấp nhận đầu vào, vì vậy nó hơi gian lận. Tôi có một ý tưởng cho một phiên bản khác với đầu vào, xem phần cuối của bình luận này.

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

Phiên bản này là để chứng minh rằng lua có thể làm tốt hơn 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;"}))()')

Cả hai phiên bản đều thêm vào 30000 byte dữ liệu. Phiên bản thứ hai của tôi dựa trên đầu vào / đầu ra: mọi thứ sau một '.' hoặc ',' sẽ bị xóa. Phiên bản thứ hai của tôi không cho phép các vòng lặp vô hạn ([.,], [], V.v.)

Ý tưởng của tôi là có được:

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

Từ đầu vào của bạn, có thêm ', +.'

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.