一篇文章搞懂Brainf**k

本文章整合了很多个网站的内容和数据,篇幅较长,请根据目录跳转。

Brainfuck

简介

Brainfuck是一种极小化的计算机语言,它是由Urban Müller在1993年创建的。由于fuck在英语中是脏话,这种语言有时被称为brainf*ck或brainfxxk,甚至被简称为BF。
Müller的目标是建立一种简单的、可以用最小的编译器来实现的、符合图灵完备思想的编程语言。这种语言由八种状态构成,为Amiga机器编写的编译器(第二版)只有240个字节大小。
就象它的名字所暗示的 (强奸你的脑子:) ,brainfuck程序很难读懂。尽管如此,brainfuck图灵机一样可以完成任何计算任务。虽然brainfuck的计算方式如此与众不同,但它确实能够正确运行。
这种语言基于一个简单的机器模型,除了指令,这个机器还包括:一个以字节为单位、被初始化为零的数组、一个指向该数组的指针(初始时指向数组的第一个字节)、以及用于输入输出的两个字节流。
这种语言,是一种按照“Turing complete(图灵完备)”思想设计的语言,它的主要设计思路是:用最小的概念实现一种“简单”的语言,BrainF**k 语言只有八种符号,所有的操作都由这八种符号的组合来完成。

字符标识(指令)

下面是这八种状态的描述,其中每个状态由一个字符标识:

字符含义
>指针加一
<指针减一
+指针指向的字节的值加一
-指针指向的字节的值减一
.输出指针指向的单元内容(ASCⅡ码)
,输入内容到指针指向的单元(ASCⅡ码)
[如果指针指向的单元值为零,向后跳转到对应的]指令的次一指令处
]如果指针指向的单元值不为零,向前跳转到对应的[指令的次一指令处

当前位置清零

[-] 将当前指针的值归零

之前位置清零

[[-]<] 将当前指针以及之前的指针归零

字符I/O

,. 从键盘读取一个字符并输出到屏幕上。

简单的循环

,[.,] 这是一个连续从键盘读取字符并回显到屏幕上的循环。注意,这里假定0表示输入结束,事实上有些系统并非如此。以-1和"未改变"作为判断依据的程序代码分别是,+[-.,+],[.[-],]

指针维护

>,[.>,] 通过移动指针保存所有的输入,供后面的程序使用。

加法

[->+<]
把当前位置的值加到后面的单元中(破坏性的加,它导致左边的单元被归零)。

条件指令

,----------[----------------------.,----------]

这个程序会把从键盘读来的小写字符转换成大写。按回车键退出程序。
首先,我们通过读入第一个字符并把它减10(大多数情况下,brainfuck使用10作为换行符的值)。如果用户按的是回车键,循环命令([)就会直接跳转到程序的结尾:因为这时第一个字节已经被减到了零。如果输入的字符不是换行符(假设它是一个小写字符),程序进入循环。在这里我们再减去剩下的22,这样总共减掉32:这是ASCⅡ码中小写字符和大写字符的差值。
下面我们把它输出到屏幕。然后接收下一个输入字符,并减去10。如果它是换行符,退出循环;否则,再回到循环的开始,减去22并输出……当循环退出时,因为后面已经没有其他的指令,程序也随之终止。

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

这个程序对两个一位数做加法,并输出结果(如果结果也只有一位数的话):4+3
7 (现在程序开始有点复杂了。我们要涉及到数组中单元的内容了,比如[0]、[1]、[2]之类。)
第一个输入的数字被放在在[0]中,从中减去48来把它从ASCII码值48到57转换为数值0到9:这是通过在[1]中放入6,然后按照[1]中的次数让一个循环从[0]中多次减去8来完成的(当加上或减去一个大的数值时,这是常用的办法)。下一步,加号被读入[1]中;然后,第二个数字被输入,覆盖掉加号。
下面的循环[<+>-]执行最重要的工作:通过把第二个数字移动到第一个里面让它们相加,并把[1]清空。这里的每次循环都把[0]增一并从[1]中减一;最终,在[1]被置零的多次循环中,[1]中的值就被转移到了[0]中。现在,[1]中是我们输入的换行符(这个程序里,我们没有设置对输入错误的检查机制)。
然后,指针被移回到指向[0],并输出它的内容([0]里面现在是 a + (b + 48) 的值,因为我们没有修改b的值,这等于 (a + b) + 48,也就是我们想要输出的ASCⅡ值。然后,把指针指向[1],里面保存着前面输入的换行符;输出换行符,程序结束。
乘法

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

和前一个程序类似,不过这次是乘法而不是加法。
第一个输入的数字被放入[0],星号和第二个数字被放入[1],然后两个数值都被校正:减去48。
现在,程序进入了主循环。我们的基本思想是:每次从[0]中减去一,同时把[1]的值加入到保存乘积的[2]中。在实际操作中,第一个内层循环把[1]的值同时转移到[2]和[3]中,同时[1]清零(这是我们复制数字的基该方法)。下一个内层循环把[3]中的值重新放回到[1],并清零[3]。然后从[0]中减一,结束外层循环。在退出这个循环时,[0]中为零,[1]仍然是输入的第二个数值,[2]则是这两个数值的和。(要是想保存第一个数,我们可以在外层循环中每次给[4]加一,最后把[4]移回[0]。)在结果中加48,并把换行符读入[3],输出ASCII码的乘积,然后输出刚才保存的换行符。
除法

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

从简单储存2个数字符到[0]和[1],并各自减去48
<<[ 这是一个主循环,在被除数,也就是[0]的值为0后循环跳出
>[->+>+<<] 从单元1中复制除数的值到[2]和[3],设[1]为0
>[-<<- 被除数[1]减去除数[2],结果将储存在[0],并且[2]将归0
[>]>>>[<[>>>-<<<[-]]>>]<<] 如果被除数[0]为0,跳出循环
>>>+ 加1值商到[5]
<<[-<<+>>] 从[3]复制除数到[1]
<<<] 移动指针到[0]
>[-]>>>>[-<<<<<+>>>>>] 从[5]复制商到[0] (这步不是必须的,但会更清楚)
<<<<++++++[-<++++++++>]<.

代码实例

Hello world

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

输出brainfuck

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

滴!

+++++++.

它的作用是输出一个07HBEL响铃

打印ascii-ext表

-[>.+<-]>.

你没看错,就这么几个字节

输出输入的字符串

,[.[-],]

将输入倒过来

>,[>,]<[.<]

清屏

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

按ascii码降序排列字符

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

计算黄金分割比(1.618)

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

这个程序会无限运行下去,你需要在你满足时终止掉它

计算常数e

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

跟上面一样,这个程序也需要手动终止

伪随机数生成器

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

这个程序基于元胞自动机(规则30),输出x字节需要32x+4个细胞。
当然这玩意也不会自动终止

谢尔宾斯基三角形

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

用brainfuck写的brainfuck解释器

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

输入你的bf程序,然后输入一个!,也就是英文感叹号,然后继续运行下去就可以了

打印代码本身

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

程序列表持续更新

C语言解释器(自己写的)

char C[9999],*n[99],*r=C,*p=C+5000,**s=n,d,c,l;main(){for(read(0,r,4e3);c=*r;r++)c-93||(d>1||(r=*p?*s:(--s,r)),!d||d--),c-91||d++||(*++s=r),d||(*p+=c==43,*p-=c==45,p+=c==62,p-=c==60,c-46||write(2,p,1),c-44||read(2,p,1));}/* brainfxxker */

将代码赋值给变量C即可运行。

网站推荐

https://www.iwriteiam.nl/Ha_BF.html
http://brainfuck.org
https://ashupk.github.io/Brainfuck/brainfuck-visualizer-master/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值