继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

BrainFuck——C实现BrainFuck解释器

九日王朝
关注TA
已关注
手记 180
粉丝 41
获赞 185

首先介绍一下吊炸天的语言——BrainFuck


Brainfuck是一种极小化的计算机语言,它是由Urban Müller在1993年创建的。由于fuck在英语中是脏话,这种语言有时被称为brainf*ck或brainf**k,甚至被简称为BF

这种语言基于一个简单的机器模型,除了指令,这个机器还包括:一个以字节为单位、被初始化为零的数组、一个指向该数组的指针(初始时指向数组的第一个字节)、以及用于输入输出的两个字节流。
这种语言,是一种按照“Turing complete(完整图灵机)”思想设计的语言,它的主要设计思路是:用最小的概念实现一种“简单”的语言,BrainF**k 语言只有八种符号,所有的操作都由这八种符号的组合来完成


https://img3.mukewang.com/5b4f0ce80001a35c04470211.jpg


(按照更节省时间的简单说法,"]"也可以说成“向后跳转到对应的"["状态”。这两解释是一样的。)
(第三种同价的说法,"["意思是"向前跳转到对应的"]"",]意思是"向后跳转到对应的[指令的次一指令处,如果指针指向的字节非零。")
Brainfuck程序可以用下面的替换方法翻译成C语言(假设ptr是char*类型):


https://img2.mukewang.com/5b4f0cf000015c5d01830197.jpg


当前位置清零
[-] 将当前指针的值归零
之前位置清零
[[-]<] 将当前指针以及之前的指针归零
字符I/O
,. 从键盘读取一个字符并输出到屏幕上。
简单的循环
,[.,] 这是一个连续从键盘读取字符并回显到屏幕上的循环。注意,这里假定0表示输入结束,事实上有些系统并非如此。以-1和"未改变"作为判断依据的程序代码分别是",+[-.,+]"和",[.[-],]"。
指针维护
>,[.>,] 通过移动指针保存所有的输入,供后面的程序使用。
加法
[->+<]
把当前位置的值加到后面的单元中(破坏性的加,它导致左边的单元被归零)。



为了方便我们理解BrainFuck语言,大家可以下载一个很好的编译器,里面还有很多demo

http://download.csdn.net/detail/sm9sun/9721483

下面给出两个示例:


一、程序输出hello word!


BF代码:++++++++++[>+>+++>+++++++>++++++++++<<<<-]>>>++.>+.+++++++..+++.<<++.>+++++++++++++++.>.+++.------.--------.<<+.<.

https://img2.mukewang.com/5b4f0cf700016e4b04270370.jpg


程序输出小于输入数字的所有质数

BF代码:>++++++++[<++++++++>-]<++++++++++++++++.[-]>++++++++++[<++++++++++>-]<++++++++++++++.[-]>++++++++++[<++++++++++>-]<+++++.[-]>++++++++++[<++++++++++>-]<+++++++++.[-]>++++++++++[<++++++++++>-]<+.[-]>++++++++++[<++++++++++>-]<+++++++++++++++.[-]>+++++[<+++++>-]<+++++++.[-]>++++++++++[<++++++++++>-]<+++++++++++++++++.[-]>++++++++++[<++++++++++>-]<++++++++++++.[-]>+++++[<+++++>-]<+++++++.[-]>++++++++++[<++++++++++>-]<++++++++++++++++.[-]>++++++++++[<++++++++++>-]<+++++++++++.[-]>+++++++[<+++++++>-]<+++++++++.[-]>+++++[<+++++>-]<+++++++.[-]+[->,----------[<+>-------------------------------------->[>+>+<<-]>>[<<+>>-]<>>>+++++++++[<<<[>+>+<<-]>>[<<+>>-]<[<<+>>-]>>-]<<<[-]<<[>+<-]]<]>>[<<+>>-]<<>+<-[>+[>+>+<<-]>>[<<+>>-]<>+<-->>>>>>>>+<<<<<<<<[>+<-<[>>>+>+<<<<-]>>>>[<<<<+>>>>-]<<<>[>>+>+<<<-]>>>[<<<+>>>-]<<<<>>>[>+>+<<-]>>[<<+>>-]<<<[>>>>>+<<<[>+>+<<-]>>[<<+>>-]<[>>[-]<<-]>>[<<<<[>+>+<<-]>>[<<+>>-]<>>>-]<<<-<<-]+>>[<<[-]>>-]<<>[-]<[>>>>>>[-]<<<<<<-]<<>>[-]>[-]<<<]>>>>>>>>[-<<<<<<<[-]<<[>>+>+<<<-]>>>[<<<+>>>-]<<<>>[>+<-]>[[>+>+<<-]>>[<<+>>-]<>+++++++++<[>>>+<<[>+>[-]<<-]>[<+>-]>[<<++++++++++>>-]<<-<-]+++++++++>[<->-]<[>+<-]<[>+<-]<[>+<-]>>>[<<<+>>>-]<>+++++++++<[>>>+<<[>+>[-]<<-]>[<+>-]>[<<++++++++++>>>+<-]<<-<-]>>>>[<<<<+>>>>-]<<<<>[-]<<+>]<[[>+<-]+++++++[<+++++++>-]<-><.[-]>>[<<+>>-]<<-]>++++[<++++++++>-]<.[-]>>>>>>>]<<<<<<<<>[-]<[-]<<-]++++++++++.[-]



https://img2.mukewang.com/5b4f0cff0001487004220376.jpg

https://img4.mukewang.com/5b4f0d070001932704250377.jpg


是不是很神奇?


下面我们具体说一下思路:

假设我们要打印一个'A'  A对应的ascii码为65,当然我们也可以用65个+,不过这样比较LOW

我们先用++++++表示把第一个空间增加到6,然后以此为循环进入第二个空间

每次循环让其加10,即++++++ [ > ++++++++++ < - ] > 

此时我们在后面加一个.   运行一下++++++ [ > ++++++++++ < - ] > .输出的应该是一个<,即ascii为60

https://img2.mukewang.com/5b4f0d0f0001b8eb04260372.jpg


然后我们再在后面加5个+就能输出A了

https://img2.mukewang.com/5b4f0d15000142c904270372.jpg


好了下面我们输出一个I LOVE YOU试试

还是根据上面的原理,首先I(73),我们把他当作8*9+1来处理,即:++++++++ [ > +++++++++ < - ] > +.

之后我们可以将其变成空格(32),除了直接减去差值以外我们也可以将其归零然后重新赋值,用[-]归零,再加32

即:++++++++ [ > +++++++++ < - ] > +.[-]++++ [ > ++++++++ < - ] > .

然后写L(76),注意,当前值为32,我们可以使其加到38再*2,即:++++++++ [ > +++++++++ < - ] > +.[-]++++ [ > ++++++++ < - ] >.++++++[>++<-]>.

此时你应该输出的I L,看看是不是~~

https://img.mukewang.com/5b4f0d1c000165f204200373.jpg

所以~BrainFuck语言实现起来非常的自由,具体怎样写最简洁最大气就要看你的智商啦~~

接着我们再完成下面的字符输出

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

https://img3.mukewang.com/5b4f0d220001b36004190372.jpg



C语言实现解释器代码:


#define  _CRT_SECURE_NO_WARNINGS#include <stdio.h>#include <stdlib.h>char s[30000]={0};char code[100000];int len = 0;int stack[100];int stack_len=0;int main(int argc,char**argv){char c;int i=0,j,k,x=0;FILE* f;char* p=s+10000;f=fopen(argv[1],"r");while(fread(&code[len],1,1,f)==1)	{len++;}setbuf(stdout,NULL);while(i<len) {switch(code[i]) {case '+':(*p)++;break;case '-':(*p)--;break;case '>':p++;break;case '<':p--;break;case '.':putchar((int)(*p));//printf("put:%hdn",*p);break;case ',':*p=getchar();break;case '[':if(*p) {stack[stack_len++]=i;} else {for(k=i,j=0;k<len;k++) {code[k]=='['&&j++;code[k]==']'&&j--;if(j==0)break;}if(j==0)i=k;else {fprintf(stderr,"%s:%dn",__FILE__,__LINE__);return 3;}}break;case ']':i=stack[stack_len-- - 1]-1;break;default:break;}i++;//x++;//printf("%d : i=%dn",x,i);}printf("\n");	system("pause");return 0;}


注:网上相关代码很多,但是大多数都有一个BUG,就是对于嵌套循环即[[]]这样的处理有误。


大家也可以测试输出质数的这个源码,其正好有一个嵌套循环。

https://img4.mukewang.com/5b4f0d2a0001826605070322.jpg






然后我们也可以把BF代码保存为二进制文本,后缀名为bf(随便你啦)

再将我们的程序关联上


https://img.mukewang.com/5b4f0d300001abf204310327.jpg


最后再让我们输出一下I LOVE YOU


https://img2.mukewang.com/5b4f0d37000192dc04880334.jpg



好啦~大家现在又学会了一种语言说“我爱你”,还不赶紧去跟妹子表(zhuang)白(bi)~科科

https://img.mukewang.com/5b4f0d570001150b01130106.jpg



打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP