Brainfuck 编程语言

本文详细介绍了Brainfuck编程语言的基本概念、设计思想、指令集及其应用实例,并通过两个不同版本的解释器代码展示了其运行原理。文章还探讨了Brainfuck作为图灵完备语言的独特之处,以及它在计算机科学领域的地位。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

很偶然的机会认识到这个语言,当时在纸上对着它的 "hello world" 程序一个字符一个字符的解释了一遍,惊讶于它的设计思想。到网上查了下,记录下来。

以下是正文 :

-------------------------------- 

Brainfuck,是一种极小化的计算机语言,它是由Urban Müller在1993年创建的。由于fuck在英语中是脏话,这种语言有时被称为brainf*ck或brainf***,甚至被简称为BF。 

Müller的目标是创建一种简单的、可以用最小的编译器来实现的、符合图灵完全思想的编程语言。这种语言由八种运算符构成,为Amiga机器编写的编译器(第二版)只有240个字节大小。 

就象它的名字所暗示的,brainfuck程序很难读懂。尽管如此,brainfuck图灵机一样可以完成任何计算任务。虽然brainfuck的计算方式如此与众不同,但它确实能够正确运行。 

这种语言基于一个简单的机器模型,除了指令,这个机器还包括:一个以字节为单位、被初始化为零的数组、一个指向该数组的指针(初始时指向数组的第一个字节)、以及用于输入输出的两个字节流。 

下面是这八种状态的描述,其中每个状态由一个字符标识: 
字符 含义 
>    指针加一 
<    指针减一 
+    指针指向的字节的值加一 
-     指针指向的字节的值减一 
.     输出指针指向的单元内容(ASCII码) 
,     输入内容到指针指向的单元(ASCII码) 
[     如果指针指向的单元值为零,向后跳转到对应的]指令的次一指令处 
]     如果指针指向的单元值不为零,向前跳转到对应的[指令的次一指令处 

(按照更节省时间的简单说法,]也可以说成“向前跳转到对应的[状态”。这两解释是一样的。) 

(第三种同价的说法,[意思是"向后跳转到对应的]",]意思是"向前跳转到对应的[指令的次一指令处,如果指针指向的字节非零。") 

Brainfuck程序可以用下面的替换方法翻译成C语言(假设ptr是char*类型): 
Brainfuck C 
>    ++ptr; 
<    --ptr; 
+    ++*ptr; 
-     --*ptr; 
.     putchar(*ptr); 
,     *ptr =getchar(); 
[     while (*ptr) { 
]     } 

(以上内容源自维基百科:http://zh.wikipedia.org/wiki/Brainfuck)


下面是它的一个解释器: 
-------------------------------- 

#include <stdio.h>
int p, r, q;
char a[5000], f[5000], b, o, *s=f;
void interpret(char *c)
{
    char *d;
    r++;
    while( *c ) {
        //if(strchr("<>;+-,.[]\n",*c))printf("%c",*c);
        switch(o=1,*c++) {
            case '<': p--; break;
            case '>': p++; break;
            case '+': a[p]++; break;
            case '-': a[p]--; break;
            case '.': putchar(a[p]); fflush(stdout); break;
            case ',': a[p]=getchar();fflush(stdout); break;
            case '[':
                for( b=1,d=c; b && *c; c++ )
                b+=*c=='[', b-=*c==']';
                if(!b) {
                    c[-1]=0;
                    while( a[p] )
                    interpret(d);
                    c[-1]=']';
                    break;
                }
            case ']':
                puts("UNBALANCED BRACKETS"), exit(0);
            case '#':
                if(q>2)
                printf("%2d %2d %2d %2d %2d %2d %2d %2d %2d %2d\n%*s\n",
                *a,a[1],a[2],a[3],a[4],a[5],a[6],a[7],a[8],a[9],3*p+2,"^");
                break;
            default: o=0;
        }
        if( p<0 || p>100)
            puts("RANGE ERROR"), exit(0);
    }
    r--;
    // chkabort();
}
 
main(int argc,char *argv[])
{
    FILE *z;
 
    q=argc;
 
    if(z=fopen(argv[1],"r")) {
        while( (b=getc(z))>0 )
            *s++=b;
        *s=0;
        interpret(f);
    }
}

-------------------------------- 
代码比较直接,不做解释了。


一个 BF 的 hello world ( 注意,这里成行的减号是起分割线作用的,不是 BF 代码。)
-------------------------------- 
++++++++++[>+++++++>++++++++++>+++>+<<<<-] 
>++.>+.+++++++..+++.>++.<<+++++++++++++++. 
>.+++.------.--------.>+.>. 
-------------------------------- 

解释 
-------------------------------- 
+++ +++ +++ +                    initialize counter (cell #0) to 10 
[                                               use loop to set the next four cells to 70/100/30/10 
> +++ +++ +                         add 7 to cell #1 
> +++ +++ +++ +                add 10 to cell #2 
> +++                                    add 3 to cell #3 
> +                                         add 1 to cell #4 
<<< < -                                 decrement counter (cell #0) 

>++ .                                     print 'H' 
>+.                                         print 'e' 
+++ +++ +.                          print 'l' 
.                                             print 'l' 
+++ .                                     print 'o' 
>++ .                                     print ' ' 
<<+ +++ +++ +++ +++ ++.  print 'W' 
>.                                               print 'o' 
+++ .                                         print 'r' 
--- --- .                                       print 'l' 
--- --- --.                                    print 'd' 
>+.                                             print '!' 
>.                                               print '\n' 
-------------------------------- 

(以上内容来自 coolshell : http://coolshell.cn/articles/1142.html,作者: 陈皓)


在网上又查到了一个代码写得很好的解释器,代码如下: 
-------------------------------- 

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#define TOKENS "><+-.,[]"
#define CODE_SEGMENT_SIZE 30000
#define STACK_SEGMENT_SIZE 1000
#define DATA_SEGMENT_SIZE 30000
typedef void (*Callback)(void);
struct {
  char cs[CODE_SEGMENT_SIZE]; /* Code Segment */
  long ip; /* Instruction Pointer */
 
  char ss[STACK_SEGMENT_SIZE]; /* Stack Segment */
  long sp; /* Stack Pointer */
 
  char ds[DATA_SEGMENT_SIZE]; /* Data Segment */
  long bp; /* Base Pointer */
 
  Callback fn[128];
} vm;
void vm_forward() {
  vm.bp = (vm.bp + 1) % DATA_SEGMENT_SIZE;
}
void vm_backward() {
  vm.bp = (vm.bp + DATA_SEGMENT_SIZE - 1) % DATA_SEGMENT_SIZE;
}
void vm_increment() {
  vm.ds[vm.bp]++;
}
void vm_decrement() {
  vm.ds[vm.bp]--;
}
void vm_input() {
  vm.ds[vm.bp] = getchar();
}
 
void vm_output() {
  putchar(vm.ds[vm.bp]);
}
void vm_while_entry() {
  if (vm.ds[vm.bp]) {
    vm.ss[vm.sp] = vm.ip - 1;
    vm.sp++;
  } else {
    int c = 1;
    for (vm.ip++; vm.cs[vm.ip] && c; vm.ip++) {
      if (vm.cs[vm.ip] == '[') {
        c++;
      } else if (vm.cs[vm.ip] == ']') {
        c--;
      }
    }
  }
}
void vm_while_exit() {
  if (vm.ds[vm.bp]) {
    vm.sp--;
    vm.ip = vm.ss[vm.sp];
  }
}
void setup() {
  int c;
  int i;
 
  memset(&vm, 0, sizeof(vm));
  vm.fn['>'] = vm_forward;
  vm.fn['<'] = vm_backward;
  vm.fn['+'] = vm_increment;
  vm.fn['-'] = vm_decrement;
  vm.fn['.'] = vm_output;
  vm.fn[','] = vm_input;
  vm.fn['['] = vm_while_entry;
  vm.fn[']'] = vm_while_exit;
 
  for (i = 0; (c = getchar()) != EOF;) {
    if (strchr(TOKENS, c)) {
      vm.cs[i] = c;
      i++;
    }
  }
}
void run() {
  while (vm.cs[vm.ip]) {
    vm.fn[vm.cs[vm.ip]]();
    vm.ip++;
  }
}
 
int main(int argc, char* argv[]) {
  if (argc > 1) {
    freopen(argv[1], "r", stdin);
  }
 
  setup();
  run();
 
  return 0;
}

-------------------------------- 

(以上内容来自 http://blog.youkuaiyun.com/redraiment/article/details/7483062,作者:redraiment)

代码清晰易懂,不再解释了。


上面提到的图灵完备之类的概念是计算机科学(CS)中的内容,有兴趣的可以自行参考维基百科介绍,然后再决定是否要进一步的了解。不过,先提个醒,CS 是个很大很引人入胜的领域,小心“沉迷”。

转载于:https://my.oschina.net/xhan/blog/317343

Brainfuck,是一种极小化的计算机语言,它是由Urban Müller在1993年创建的。由于fuck在英语中是脏话,这种语言有时被称为brainf*ck或brainf***,甚至被简称为BF。 【内含:BF解释器,BF解释器源码,BF写的几个小程序】 ReadMe: Brainfuck 编程语言 [图灵完全] [8条指令] 语法: > 指针加一 < 指针减一 + 指针指向的字节的值加一 - 指针指向的字节的值减一 . 输出指针指向的单元内容(ASCII码) , 输入内容到指针指向的单元(ASCII码) [ 如果指针指向的单元值为零,向后跳转到对应的]指令的次一指令处 ] 如果指针指向的单元值不为零,向前跳转到对应的[指令的次一指令处 特性: 8KB 环状内存(初始化为0) <>操作不会越界 加减操作环状 +-操作不会溢出(0xFF + 为 0x00) 文件说明: bf.exe 解释器 Usage: bf [-options] source where options include: -b buffered input (default mode) 缓冲输入(按回车才输入,默认) -i not buffered input 无缓冲输入 -e not buffered input without echo 无缓冲输入且不回显 bf.cpp 解释器的源代码(纯C实现) hello.txt HelloWorld程序 up.txt 这个程序将你的输入(小写字母)转换为大写(回车结束) add.txt 这个程序对两个一位数做加法,并输出结果(如果结果也只有一位数的话)(例如:输入2+3) mul.txt 这个程序对两个一位数做乘法,并输出结果(如果结果也只有一位数的话)(例如:输入2*3) factor.txt 这个程序分解多位数的因子,并输出结果(例如:输入1000) numwarp.txt 这个程序输入 ()-./0123456789abcdef 和空格的字符串,显示很有趣的排列结果(例如:输入520 1314) prime.txt 这个程序输入一个多位整数,输出从1到这个整数间的所有素数(例如:输入100) quine.txt 这个程序输出源代码本身 [以上程序,基本上依靠回车确认]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值