一门“脑残”的编程语言
之前我写过一篇关于这个的文章,不过后来它被删掉了(和我的网站一起被删掉了)。下面我们来再温习一遍:
我知道,你肯定在想——“这家伙真能嚼舌根”。好吧,既然如此,我也承认。我刚研究了一下brainfuck编程语言(脑残语言?),也说过我想要试一试。
下面是我的”脑残“语言的30分钟之旅
简介
这是从WIKI上摘录的:
brainfuck是一门深奥的编程语言,它以极简著称。这门语言只有8个简单的命令以及一个指令指针。它旨在挑战及取悦程序员,并不适合实际应用。它于1993年由Urban Müller所发明。
学习brainfuck的3个理由
- 你很无聊
- 你想向你的同事炫耀一下
- 你希望能吸引到辣妹
brainfuck的命令
它一共有8个命令。每个命令都是一个单字符,非命令的字符都会被解释器忽略掉。
脑残语言由一个初始化为0的拥有30000个单元的数组以及一个指向当前单元的数据指针(从第0个单元开始)所组成。
这8个命令是:
命令 | 说明 |
---|---|
+ | 将当前单元的值增加1 |
- | 将当前单元的值减1 |
> | 将数据指针移动到下一单元(右边的单元) |
< | 将数据指针移动到上一单元(左边的单元) |
. | 打印当前单元的ASCII值(65就是'A') |
, | 读取一个字符到当前单元 |
[ | 如果当前单元的值为0,跳到对应的]处。否则移动到下一条指令 |
] | 如果当前单元的值为0,移动到下一条指令。否则,回退到对应的[处。 |
我的脑残语言的处女作
这个程序花了我15到20分钟,这里面还包括了我研究这门语言的时间。我用的是一个在线的脑残语言的解释器来执行它,这个解释器是拿javascript写的,不过它工作得还可以。从这里能下载到它。我的这第一个程序非常简单,它只是将”ROBBIE“打印到了屏幕上。下面:
++++++++[>++++++++++<-]>++.>++++++++[>++++++++++<-]>-.>++++++
[>++++++++++<-]>++++++.>++++++[>++++++++++<-]>++++++.[>+<-]>+++++++.[>+<-]>----.
分析
为了讲清楚这是怎么回事,我将这个程序进行了分解,分别介绍里面的每一个命令,以便能让你明白它究竟在做什么。同时还请记住,每个非命令的字符,都会被解释器忽略掉,也就是说,任何的字母,数字以及空格。
小提示:如果你有纸笔的话,画个数组会有助于你理解每个单元里都有什么。
下面是打印每个字母的原始代码:
Print R
++++++++
[ > ++++++++++ < - ]
> ++ .
Print O
> ++++++++
[ > ++++++++++ < - ]
> - .
Print BB
> ++++++ [ > ++++++++++ < - ] > ++++++ .
> ++++++ [ > ++++++++++ < - ] > ++++++ .
Print I
[ > + < - ] > +++++++ .
Print E
[ > + < - ] > ---- .
打印字母R
我们想要打印出R,这意味着我们要把数组里的某个单元设置成82(R的ASCII值)。这听起来很简单,对吧?你只需插入82个+命令,然后使用.命令将其输出。
这没错,不过还有一种更简洁,更聪明的方法,就是使用循环。
我们把第0个单元当作循环的指针。当循环计数器到0的时候,这个循环会终止,在]命令之后我们会进入到下一条指令中去。
下面我给出了使用循环打印出字母R的这个算法:
将0单元初始化为8 当0单元 != 0的时候 移动到下一个单元(1单元) 将1单元自增到10 后退到前一单元(0单元) 将0单元减1
打印R的代码
++++++++ [ > ++++++++++ < - ] > ++ .
++++++++ 将0单元初始化为8
[ 循环开始,如果当前单元的值不为0时则继续
> 移动到1单元
++++++++++ 将1单元的值自增10
< 后退到0单元
- 将0单元的值减1
] 如果0单元的当前值为0,则移动到下一条指令,否则:
回到当前的左方括号(循环开始处)
> 移动到1单元
++ 将1单元增加2,现在1单元的最终值是82了。
. 打印1单元的ASCII值(R)
打印字母OBB
这和打印R非常类似。如果你能理解这个,那么打印OBB理解起来应该没有什么问题了。
打印I
这是打印字母的另一种方法。这里,我们将使用前一个赋值单元的值(也就是字母B)。
我们将从3单元的值(现在66,字母B)移动到4单元,然后将4单元的值修改73(也就是字母I)。
要实现这个我们得将66(B)移动到下一个单元,然后加7让它成为I。
下面是将当前单元移动到下一单元的代码:
[ > + < - ] > +++++++ .
下面来逐个命令地分析下代码:
[ 如果当前单元(3单元)的值不为0,则开始循环
> 移动到下一单元(4单元)
+ 将4单元的值加1
< 回到3单元
- 将3单元的值减1
] 如果3单元的当前值为0则到下一条指令,否则:
回到左方括号处
> 移动到下一单元(4单元)
+++++++ 将4单元的值增加7
. 打印出4单元的值(I)
打印字母E
刚才你已经打印出了I了。打印E也使用跟I一样的方法(将I的值移动到下一单元,然后将其修改为E)。
搞定!
基础算法
现在你已经掌握了循环的基本知识了,这里是一些关于脑残语言的一些有用的算法。
将值清零: {x} → {0}
[-]
移动值: {x, 0} → {0, x} (前面我们用过这一算法了)
[->+<]
拷贝值: {x, 0, 0} → {x, x, 0}
[->+>+<<]>>[-<<+>>]<<
加法: {x, y} → {0, x+y}
[->+<]
减法: {x, y} → {x-y, 0}
>[-<->]<
乘法: {x, y, 0, 0} → {0, y, x*y, 0}
[->[->+>+<<]>>[-<<+>>]<<<]
乘方: {x, y, 0, 0, 0} → {x, 0, pow(x, y), 0, 0}
>>+<[->[-<<[->>>+>+<<<<]>>>>[-<<<<+>>>>]<<]>[-<+>]<<]<
除法: {x, y, 0, 0, 0, 0} → {x/y, x%y, 0, 0, 0, 0}
[>[->+>+<<]>[-<<-[>]>>>[<[-<->]<[>]>>[[-]>>+<]>-<]<<]>>>+<<[-<<+>>]<<<]
>>>>>[-<<<<<+>>>>>]<<<<<
警告: 当 y=0时, 会导致无限循环。
现在你该明白了。你已经完成了第一个脑残程序,也学习到了循环以及如何将值从一个单元移动到下一个单元,还有一些可供你使用的基础算法。