一门“脑残”的编程语言

Published: 30 Sep 2014 Category: 其它

之前我写过一篇关于这个的文章,不过后来它被删掉了(和我的网站一起被删掉了)。下面我们来再温习一遍:

我知道,你肯定在想——“这家伙真能嚼舌根”。好吧,既然如此,我也承认。我刚研究了一下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时, 会导致无限循环。

现在你该明白了。你已经完成了第一个脑残程序,也学习到了循环以及如何将值从一个单元移动到下一个单元,还有一些可供你使用的基础算法。

英文原文链接