简介

Brainfuck语言,可以简单的理解为一个双向的纸带,我们根据纸带上的指令,进行操作,和图灵机类似,就是说Brainfuck 是一种极简的图灵完备语言,8 个字符模拟图灵机操作,通过指针移动、单元加减与循环控制,实现一切逻辑——只要你愿意写。

八条核心指令

指令 含义 说明
> 指针向右移动一格 相当于 ptr++,指向下一个单元
< 指针向左移动一格 相当于 ptr--,指向上一个单元
+ 当前单元值加一 buf[ptr]++,溢出则回绕到 0
- 当前单元值减一 buf[ptr]--,负数时回绕到 255
. 输出当前单元的 ASCII 字符 使用 putchar(buf[ptr])cout << char(buf[ptr])
, 读取一个字符存入当前单元 使用 getchar()cin >> ch(注意处理换行)
[ 如果当前值为 0,跳到匹配的 ] 否则进入循环
] 如果当前值不为 0,跳回对应的 [ 否则退出循环

内存模型

  • 一条 双向纸带(tape):可以无限向左、向右移动(理论上)。

  • 每个单元为一个 8-bit 无符号整数(unsigned char,即:
    0 ~ 255,加法超过 255 会回到 0,减法低于 0 会回到 255。

  • 默认初始化为 0。

image.png

实现

code

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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#include <iostream>
#include <vector>
#include <cstdio>
#include <string>
using namespace std;

#define LOG(X, Y) cout << " [ "<< #X << " ] " << Y << '\n'
#define MAX_SIZE (int)1024

char buf[MAX_SIZE] = {0};
size_t ptr = MAX_SIZE / 2;


void run(const string& code) {
    vector<size_t> loop_stack;
    for (size_t pc = 0; pc < code.size(); ++pc) {
        char cmd = code[pc];
        switch (cmd) {
            case '>':
                if (ptr + 1 < MAX_SIZE) ptr++; break;
            case '<':
                if (ptr > 0) ptr--; break;
            case '+':
                buf[ptr]++; break;
            case '-':
                buf[ptr]--; break;
            case '.':
                putchar(buf[ptr]); break;
            case ',':
                buf[ptr] = getchar(); break;
            case '[':
                if (buf[ptr] == 0) {
                    int level = 1;
                    while (level && ++pc < code.size()) {
                        if (code[pc] == '[') level++;
                        else if (code[pc] == ']') level--;
                    }
                } else {
                    loop_stack.push_back(pc);
                }
                break;
            case ']':
                if (buf[ptr] != 0) {
                    pc = loop_stack.back();  // 跳回对应 [
                } else {
                    loop_stack.pop_back();   // 退出循环
                }
                break;
        }

    }

}



int main() {
    string code;
    getline(cin, code);
    run(code);
    return 0;
}

解析

通过 string 也就是 char数组模拟纸带,其他没什么好说的,就是简单的把逻辑翻译成cpp的语言,最主要的就是实现循环逻辑,循环需要控制括号嵌套层级,这里采用简单的level进行深度记录,保证每个深度的左括号都能匹配到对应深度的右括号。

编译/运行

手动编译cpp文件

1
g++ bf.cpp -o bf.exe 

然后运行文件,输入标准 hello world 代码

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

观察输出:
image.png
成功输出hello world!