Brainfuck
Brainfuck
Brainfuck是一种极小化的计算机语言,它是由Urban Müller在1993年创建的。由于fuck在英语中是脏话,这种语言有时被称为brainf*ck或brainf**k,甚至被简称为BF。
简介
Müller的目标是建立一种简单的、可以用最小的编译器来实现的、符合艾伦·麦席森·图灵完全思想的编程语言。这种语言由八种状态构成,为Amiga机器编写的编译器(第二版)只有240个字节大小!
就象它的名字所暗示的,brainfuck程序很难读懂。尽管如此,brainfuck图灵机一样可以完成任何计算任务。虽然brainfuck的计算方式如此与众不同,但它确实能够正确运行。
这种语言基于一个简单的机器模型,除了指令,这个机器还包括:一个以字节为单位、被初始化为零的数组、一个指向该数组的指针(初始时指向数组的第一个字节)、以及用于输入输出的两个字节流。
这种语言,是一种按照“Turing complete(艾伦·图灵完备)”思想设计的语言,它的主要设计思路是:用最小的概念实现一种“简单”的语言,BrainF**k 语言只有八种符号,所有的操作都由这八种符号的组合来完成。
字符标识
下面是这八种状态的描述,其中每个状态由一个字符标识:
(按照更节省时间的简单说法,"]"也可以说成“向后跳转到对应的"["状态”。这两解释是一样的。)
(第三种同价的说法,"["意思是"向前跳转到对应的"]"",]意思是"向后跳转到对应的[指令的次一指令处,如果指针指向的字节非零。")
Brainfuck程序可以用下面的替换方法翻译成c语言(假设ptr是char*类型):
当前位置清零
[-] 将当前指针的值归零
之前位置清零
[[-]\u003c] 将当前指针以及之前的指针归零
字符i/o
,. 从键盘读取一个字符并输出到屏幕上。
简单的循环
,[.,] 这是一个连续从键盘读取字符并回显到屏幕上的循环。注意,这里假定0表示输入结束,事实上有些系统并非如此。以-1和"未改变"作为判断依据的程序代码分别是",+[-.,+]"和",[.[-],]"。
指针维护
\u003e,[.\u003e,] 通过移动指针保存所有的输入,供后面的程序使用。
加法
[-\u003e+\u003c]
把当前位置的值加到后面的单元中(破坏性的加,它导致左边的单元被归零)。
条件指令
,----------[----------------------.,----------]
这个程序会把从键盘读来的小写字符转换成大写。按回车键退出程序。
首先,我们通过,读入第一个字符并把它减10(大多数情况下,brainfuck使用10作为换行符的值)。如果用户按的是回车键,循环命令([)就会直接跳转到程序的结尾:因为这时第一个字节已经被减到了零。如果输入的字符不是换行符(假设它是一个小写字符),程序进入循环。在这里我们再减去剩下的22,这样总共减掉32:这是ASCⅡ码中小写字符和大写字符的差值。
下面我们把它输出到屏幕。然后接收下一个输入字符,并减去10。如果它是换行符,退出循环;否则,再回到循环的开始,减去22并输出……当循环退出时,因为后面已经没有其他的指令,程序也随之终止。
加法
,\u003e++++++[\u003c--------\u003e-],,[\u003c+\u003e-],\u003c.\u003e.
这个程序对两个一位数做加法,并输出结果(如果结果也只有一位数的话):4+3
7 (现在程序开始有点复杂了。我们要涉及到数组中单元的内容了,比如、、之类。)
第一个输入的数字被放在在中,从中减去48来把它从ASCⅡ码值48到57转换为数值0到9:这是通过在中放入6,然后按照中的次数让一个循环从中多次减去8来完成的(当加上或减去一个大的数值时,这是常用的办法)。下一步,加号被读入中;然后,第二个数字被输入,覆盖掉加号。
下面的循环[\u003c+\u003e-]执行最重要的工作:通过把第二个数字移动到第一个里面让它们相加,并把清空。这里的每次循环都把增一并从中减一;最终,在被置零的多次循环中,中的值就被转移到了中。现在,中是我们输入的换行符(这个程序里,我们没有设置对输入错误的检查机制)。
然后,指针被移回到指向,并输出它的内容(里面现在是 a + (b + 48)的值,因为我们没有修改b的值,这等于 (a + b) + 48,也就是我们想要输出的ASCⅡ值)。然后,把指针指向,里面保存着前面输入的换行符;输出换行符,程序结束。
乘法
,\u003e,,\u003e++++++++[\u003c------\u003c------\u003e\u003e-]\u003c\u003c[\u003e[\u003e+\u003e+\u003c\u003c-]\u003e\u003e[\u003c\u003c+\u003e\u003e-]\u003c\u003c\u003c-]\u003e\u003e\u003e++++++[\u003c++++++++\u003e-],\u003c.\u003e.
和前一个程序类似,不过这次是乘法而不是加法。
第一个输入的数字被放入,星号和第二个数字被放入,然后两个数值都被校正:减去48。
现在,程序进入了主循环。我们的基本思想是:每次从中减去一,同时把的值加入到保存乘积的中。在实际操作中,第一个内层循环把的值同时转移到和中,同时清零(这是我们复制数字的基该方法)。下一个内层循环把中的值重新放回到,并清零。然后从中减一,结束外层循环。在退出这个循环时,中为零,仍然是输入的第二个数值,则是这两个数值的和。(要是想保存第一个数,我们可以在外层循环中每次给加一,最后把移回。)在结果中加48,并把换行符读入,输出ASCII码的乘积,然后输出刚才保存的换行符。
除法
,\u003e,\u003e++++++[-\u003c--------\u003c--------\u003e\u003e]
从简单储存2个数字符到和,并各自减去48
\u003c\u003c[ 这是一个主循环,在被除数,也就是的值为0后循环跳出
\u003e[-\u003e+\u003e+\u003c\u003c] 从单元1中复制除数的值到和,设为0
\u003e[-\u003c\u003c- 被除数减去除数,结果将储存在,并且将归0
[\u003e]\u003e\u003e\u003e[\u003c[\u003e\u003e\u003e-\u003c\u003c\u003c[-]]\u003e\u003e]\u003c\u003c] 如果被除数为0,跳出循环
\u003e\u003e\u003e+ 加1值商到
\u003c\u003c[-\u003c\u003c+\u003e\u003e] 从复制除数到
\u003c\u003c\u003c] 移动指针到
\u003e[-]\u003e\u003e\u003e\u003e[-\u003c\u003c\u003c\u003c\u003c+\u003e\u003e\u003e\u003e\u003e] 从复制商到 (这步不是必须的,但会更清楚)
\u003c\u003c\u003c\u003c++++++[-\u003c++++++++\u003e]\u003c.
参考资料

Warning: Invalid argument supplied for foreach() in /www/wwwroot/newbaike1.com/id.php on line 362
目录
概述
简介
字符标识
条件指令
加法
乘法
除法
参考资料