🌝
Table of Contents

实现了个 brainfuck 解释器

Posted at — Jul 02, 2021

用 C 语言写了个的简单的 brainfuck 解释器,下面简单介绍一下这门脑操语言和解释器的使用方法。

安装

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

1
2
make
make install

原理

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

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

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

Hello world

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

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

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

1
bf hello.bf

得到运行结果

1
Hello World!

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

1
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.

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

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

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

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

Cat

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

1
,.

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

1
+[,.]

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

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

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

总结

总的来说,brainfuck 编程语言的优点是能玩儿,缺点是只能玩儿。

评论插件加载中 OvO