Skip to content

mivinci/bf

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

><+-.,[]

一个用C语言写的简单的脑操解释器。

安装

首先 clone 这个仓库或直接点击这下载源码,然后使用下面命令编译安装。

make
make install

语法

Brainfuck 运行在一组内存单元格上,每个格子的初始值为零,并只使用一个指针来操作这些单元格,具体语法如下表所示。

指令 作用
> 将指针右移一格
< 将指针左移一格
+ 将指针当前所指单元格的值加1
- 将指针当前所指单元格的值减1
. 打印指针当前所指单元格的值对应的ACSCII字符
, 从键盘获取一个字符存入指针当前所指单元格
[ 若指针当前所指单元格的值为0,则跳转到与之对应的]处继续执行
] 若指针当前所指单元格的值不为0,则跳回与之对应的[处继续执行

可以看出,brainfuck 只有一个指针、输入输出和循环功能,但它是图灵完备的,可以实现和图灵机等同的功能。esolangs.org 上还收集了许多基于 brainfuck 的另类编程语言。

Hello world

老规矩,认识一门语言从打印 Hello World! 开始。如其名,实现简单的打印功能的代码就很操脑。创建一个 hello.bf 文件其内容如下。

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

使用刚刚编译安装的 brainfuck 解释器来运行该文件

bf hello.bf

得到运行结果

Hello World!

没懂?换个更简单的例子:只打印一个 A 。我们知道 A 的 ASCII 码值为 65,根据上表中的语法,我们要先用 65 个 + 让某个单元格的值变为 65,再使用 . 将该单元格的值打印出来,像这样:

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.

但这样一点也不酷,我们知道 65 可以拆成 8×8+1,也就是说可以使用 [] 循环来缩短代码,像这样:

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

这样,我们使用了 2 个单元格,第一个单元格负责记录循环的次数,相当于某些编程语言里面 for 循环中的 i,然后在每次循环中,先使用 > 将指针移动到第二个格子再使用 8 个 + 将第二个格子里的值加 8,然后使用 < 回到第一个格子,再使用 - 将第一个格子的值减一,当第一个格子的值为 0 时 ] 不再让程序跳回到 [ 处执行,像这样进行 8 次循环后,第二个格子的值就被累加到了 64,最后再对第二个格子使用一次 + 使之变为 65 后通过 . 打印出来。

还没明白?这儿有一个 brainfuck 执行过程的可视化工具可以看看。

Cat

Cat 程序的作用是将键盘输入的内容直接打印出来,用 brainfuck 实现就很简单,如下。

,.

没错就两个字符,一个负责获取键盘输入,另一个负责打印。若想一直输入输出,加个循环就完事儿了。

+[,.]

最前面的 + 是为了触发第一次循环,因为所有单元格的初始值为 0.

另外,在esolangs.org上还有更多 brainfuck 程序示例和一些对 brainfuck 的扩展,如增加指令来将 . 的输入输出指向一个文件或一个 socket 连接,实现简单的文件读写和网络功能,哈哈哈。

还有的将脑操解释器建立在 JIT (Just in Time) 机制上,如pablojorge/brainfuck,大大提升了 brainfuck 代码的运行效率。

总结

总的来说,brainfuck 编程语言的优点是能玩儿,缺点是只能玩儿。但这对于学习来说已经够了。