首先介绍一下brainfuck的语法:

该语言定义在这样一个环境之上:
你有一列无限长的小火车,每个车厢里装了一个数字,初始为0。
还有一个列车员,初始在最头上那节车厢上。
好了,你把你写的BrainFK程序交给列车员,列车员会做如下的事情:
从左向右、由上自下一个字符一个字符地读取你的程序
当读到+的时候,将所在车厢里的数字加一
当读到-的时候,将所在的车厢里的数字减一
当读到>的时候,跑到后一个车厢去
当读到<的时候,跑到前一个车厢去
当读到[的时候,如果该车厢里面的数字为0,则跳去执行下一个]之后的程序内容
当读到]的时候,如果该车想里面的数字不为0,则跳去执行上一个[之后的程序内容
当读到.的时候,将所在车厢里面的数字翻译成ASCII字符,显示在你的屏幕上 当读到, 的时候,从等待使用者输入一个ASCII字符,转码成数字写进所在车厢里

可以把火车想象成一个纸带,那么解释器需要有一个纸带类。纸带里面需要记录列车员的位置。那么代码如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Tape(object):
    """
    纸带
    """
    def __init__(self):
        self.tape = [0]
        self.position = 0

    def get(self):
        return self.tape[self.position]

    def set(self, val):
        self.tape[self.position] = val

    def inc(self):
        self.tape[self.position] += 1

    def dec(self):
        self.tape[self.position] -= 1

    def forward(self):
        self.position += 1
        if len(self.tape) <= self.position:
            self.tape.append(0)

    def backward(self):
        self.position -= 1

然后我们需要循环读取程序的每个字符的意思

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
class BrainFuck(object):
    def __init__(self,program,tape_obj):
        self.program = program # program that you're going to interpret
        self.pairs = {}
        self.record()
        self.tape = tape_obj

    def record(self):
        """遍历一次代码,记录'['和']'的相对位置"""
        left_stack = []
        for i,p in enumerate(self.program):
            if p == '[':
                left_stack.append(i)
            if p == ']':
                left = left_stack.pop()
                right = i
                self.pairs[left] = right
                self.pairs[right] = left

    def parse(self):
        values = []
        pc = 0
        while pc < len(self.program):
            p = self.program[pc]
            if p == '+':
                self.tape.inc()
            elif p == '-':
                self.tape.dec()
            elif p == '>':
                self.tape.forward()
            elif p == '<':
                self.tape.backward()
            elif p == '[':
                if self.tape.get() == 0:
                    pc = self.pairs[pc]  # 到下一个]所在的地方
            elif p == ']':
                if self.tape.get() != 0:
                    pc = self.pairs[pc]
            elif p == '.':
                values.append(chr(self.tape.get()))
            elif p == ',':
                self.tape.set(input())
            pc += 1
        return ''.join(values)

那么它的Hello world!该怎么写呢?为了可读性和程序的长度可控,我们可以这样,用四个车厢来分别控制输出大写字母,小写字母,特殊符号和控制符号。(如果需要输出数字的话,我们可以增加输出数字的车厢。) 由Ascii码表可得知,A的十进制表示为65,a的十进制表示为97,空格和感叹号分别为32,33,换行键是10.为了便于循环,可把四个车厢设置为70,100,30,10。那么尝试写程序如下: ++++++++++[>+++++++>++++++++++>+++>+]++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.-------.--------.>+.>.

假设有个注释符是这个//,那么把程序展开并注释如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
++++++++++              //第0个车厢加到10,次车厢用于定位以及定义循环长度
[
>+++++++                //第1个车厢加到7
>++++++++++             //第2个车厢加到10
>+++                    //第3个车厢加到3
>+                      //第4个车厢加到1
]
                        //循环结束时,第1个到第4个车厢数字分别为70,100,30,10
++.                     //输出H
>+.                     //输出e
+++++++.                //输出l
.                       //输出l
+++.                    //输出o
>++.                    //输出空格
<<+++++++++++++++.      //输出W
>.                      //输出o
+++.                    //输出r
-------.                //输出l
--------.               //输出d
>+.                     //输出!
>.                      //输出换行键

可以看到,这门语言的语法十分简单而且优雅,而且这是一门图灵完备语言,这意味着任何用其他语言写出的程序都可以用它来实现一遍。例如上面用python写成的brainfuck解释器,就可以用brainfuck再写一遍:即用brainfuck写的brainfuck解释器。但是这里纸张太短,写不下了。