用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个一,证明上一篇的代码没有问题.

posted @ 2024-08-13 16:42  iFuti  阅读(14)  评论(0编辑  收藏  举报