用C实现一个简单的BrainFuck解释器
Intro
本文包含以下内容
- BrainFuck解释器的实现
上一篇文章中,我们已经了解到了一门极简的语言-BrainFuck,并且还写了一个简单的BrainFuck程序.
但我们也只是在纸上脑测了这个程序,这并不能说明什么.想要验证一个程序是否正确,最简单的办法就是把它跑起来.
所以,我们需要一个BrainFuck的解释器.
解释器
示例
这是一个BrainFuck的解释器,源代码可以在github上拉取.
https://github.com/Ifuti/BrianFuck-Interpreter
或者在Gitee上拉取.
https://gitee.com/ifuti/BrianFuck-Interpreter
用法
将编译后的程序与bf代码文件放在同个文件夹下,打开终端输入
.\编译后的程序.exe 代码文件
如
解释
这个程序先是读取一个文本文件,然后将文件内容保存到一个字符串里.完成后重置字符串指针,并且调用解释函数interpret()
来开始执行BrainFuck程序.
interpret()
接受一个字符串指针,将BrainFuck代码分为由空字符分割的段落.
传入字符串指针后,当其指向的数据不是空字符时,程序便进入switch-case
代码块,执行brainfuck代码.
值得注意的是,我使用了一个长度为
100
的字符数组来当作纸带.如果你的程序使用的纸带长度长于这个数,你可能需要修改程序.
当进入switch-case
代码块时,指针将当前指向的字符传入,并前移一位,这有助于提前判断读写头是否超出纸带,以便适时结束程序.
><+-
的实现非常直观;.,
则分别用putchar()
与getchar()
来实现,值得注意的是,在Linux环境下stdout
属于行缓冲,这会使得.
无法立刻打印字符,所以必须使用fflush(stdout)
来强制输出.
接下来是[]
.想执行循环就得先找到循环的结尾,所以我们让传入的指针向后移动,寻找与之相应的]
为此,程序的开头声明了一个loop
变量,我们用它来表示循环的层数,将它初始化为1
,这表示目前有一层循环,当它找到一个[
时loop
就加一,遇到一个]
时loop
就减一.我们让指针向后移动,一个一个寻找,直到循环层数变为0,此时就找到了循环的结尾.如果直到代码最后都没找到循环的结尾,则打印错误信息并退出程序.
当找了循环的结尾,便进入循环.此时传入的指针已经指向循环的末尾,那要如何定位循环的开头呢?
在interpret()
的开头,我们定义了一个名为temp
的指针,开始寻找前,我们将它初始化为指向循环的开始.
此时传入的指针所指向的位置的上一位便是]
,我们将它替换成0
,这会截断循环的代码,使之成为一个独立的代码段.
我们将temp
指针传入interpret()
,进入递归.
while()
会不断执行这段BrainFuck代码,直到读写头指向的数为0.
使用递归来处理[]
可以直观的解决嵌套的问题,一层嵌套对应一层递归.
当循环结束后,第一层的interpret()
继续从传入的指针处执行,循环便被正确地处理了.
BrainFuck
现在有解释器了,我们可以检查上一篇中的代码是否正确了.
回忆一下,上一篇的代码是这样的
+>+>+>>+>+>+>+<<<<<<<
[>]+>[>]<-
这时发现了一个问题,那就是这个程序没有输出,所以我们还需要添加一段代码.
<<<<<<<
[++++++++++++++++++++++++++++++++++++++++++++++++.>]
这段代码使程序回到开头,并为每一位上的每一个数加上48,这会使得它变成ASCII中的数字,并当遇到零的时候程序就会停下来.
运行后发现结果是7个一,证明上一篇的代码没有问题.