一个用C语言写的简单的脑操解释器。
首先 clone 这个仓库或直接点击这下载源码,然后使用下面命令编译安装。
make
make install
Brainfuck 运行在一组内存单元格上,每个格子的初始值为零,并只使用一个指针来操作这些单元格,具体语法如下表所示。
指令 | 作用 |
---|---|
> | 将指针右移一格 |
< | 将指针左移一格 |
+ | 将指针当前所指单元格的值加1 |
- | 将指针当前所指单元格的值减1 |
. | 打印指针当前所指单元格的值对应的ACSCII字符 |
, | 从键盘获取一个字符存入指针当前所指单元格 |
[ | 若指针当前所指单元格的值为0,则跳转到与之对应的] 处继续执行 |
] | 若指针当前所指单元格的值不为0,则跳回与之对应的[ 处继续执行 |
可以看出,brainfuck 只有一个指针、输入输出和循环功能,但它是图灵完备的,可以实现和图灵机等同的功能。esolangs.org 上还收集了许多基于 brainfuck 的另类编程语言。
老规矩,认识一门语言从打印 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 程序的作用是将键盘输入的内容直接打印出来,用 brainfuck 实现就很简单,如下。
,.
没错就两个字符,一个负责获取键盘输入,另一个负责打印。若想一直输入输出,加个循环就完事儿了。
+[,.]
最前面的
+
是为了触发第一次循环,因为所有单元格的初始值为 0.
另外,在esolangs.org上还有更多 brainfuck 程序示例和一些对 brainfuck 的扩展,如增加指令来将 ,
和 .
的输入输出指向一个文件或一个 socket 连接,实现简单的文件读写和网络功能,哈哈哈。
还有的将脑操解释器建立在 JIT (Just in Time) 机制上,如pablojorge/brainfuck,大大提升了 brainfuck 代码的运行效率。
总的来说,brainfuck 编程语言的优点是能玩儿,缺点是只能玩儿。但这对于学习来说已经够了。