BrainFuck 解释器(C语言实现)

码农的业余休闲活动就是去学习一门冷门的语言或者研究一项非主流的技术。BrainFuck 是一门小巧的编程语言,顾名思义,阅读这门语言的代码就像在强奸你的大脑一样。事实证明开发它的解释器比读懂它的 Hello World 要快。

BrainFuck只有八条指令:

指令 含义 等价的C代码
> 指针加一 ++ptr;
< 指针减一 --ptr;
+ 指针指向的字节的值加一 ++*ptr;
- 指针指向的字节的值减一 --*ptr;
. 输出指针指向的单元内容(ASCII码) putchar(*ptr);
, 输入内容到指针指向的单元(ASCII码) *ptr = getchar();
[ 如果指针指向的单元值为零,向后跳转到对应的]指令的次一指令处 while (*ptr) {
] 如果指针指向的单元值不为零,向前跳转到对应的[指令的次一指令处 }

解释器代码如下:

#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;
}

Hello world:

brainfuc$ cat helloword.bf
++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.
brainfuc$ ./bf helloword.bf
Hello World!
brainfuc$
时间: 2024-10-27 06:04:38

BrainFuck 解释器(C语言实现)的相关文章

用Python编写一个简单的Lisp解释器的教程_python

本文有两个目的: 一是讲述实现计算机语言解释器的通用方法,另外一点,着重展示如何使用Python来实现Lisp方言Scheme的一个子集.我将我的解释器称之为Lispy (lis.py).几年前,我介绍过如何使用Java编写一个Scheme解释器,同时我还使用Common Lisp语言编写过一个版本.这一次,我的目的是尽可能简单明了地演示一下Alan Kay所说的"软件的麦克斯韦方程组" (Maxwell's Equations of Software). Lispy支持的Scheme

90分钟实现一门编程语言(极简解释器教程)_C#教程

本文介绍了如何使用 C# 实现一个简化 Scheme--iScheme 及其解释器. 如果你对下面的内容感兴趣: 实现基本的词法分析,语法分析并生成抽象语法树. 实现嵌套作用域和函数调用. 解释器的基本原理. 以及一些 C# 编程技巧. 那么请继续阅读. 如果你对以下内容感兴趣: 高级的词法/语法分析技术. 类型推导/分析. 目标代码优化. 本文则过于初级,你可以跳过本文,但欢迎指出本文的错误 :-) 代码样例 public static int Add(int a, int b) { retu

JavaScript中this关键字使用方法详解

javascript|关键字|详解 在面向对象编程语言中,对于this关键字我们是非常熟悉的.比如C++.C#和Java等都提供了这个关键字,虽然在开始学习的时候觉得比较难,但只要理解了,用起来是非常方便和意义确定的.JavaScript也提供了这个this关键字,不过用起来就比经典OO语言中要"混乱"的多了.     下面就来看看,在JavaScript中各种this的使用方法有什么混乱之处?     1.在HTML元素事件属性中inline方式使用this关键字:  <div

开源大数据周刊-第35期

阿里云E-MapReduce实践 如何在E-MapReduce上使用引导操作安装kafka组件 当前E-MapReduce中没有kafka组件,需要额外安装.本文介绍如何用E-MapReduce引导操作来安装kafka_2.10-0.10.0.0版本. 资讯 大数据行业成资本市场新宠 数据源或成大数据公司核心竞争力 日前,大数据发展浪潮正在席卷全球,资本也敏锐追逐着高增长市场.大数据是我国的战略性新兴产业,而投资界持续看好大数据产业的发展未来,这种趋势明显增强. LinkedSee灵犀获5000

《C++入门经典(第6版)》——第2章 程序的组成部分2.1 使用C++的原因

第2章 程序的组成部分 C++入门经典(第6版) 本章介绍如下内容: 为何使用C++: C++程序的组织结构: 注释如何让程序更容易理解: 函数的作用. 虽然已面世37年,但是C++编程语言的地位比20世纪70年代末出现的其他东西高得多.当前C++仍在风行,还是一种世界级编程语言. 造就它令人惊讶的生命力的原因在于,通过使用C++,只需编写少量的代码,就可创建快速执行的程序,且可在各种计算环境下运行.当今的C++编程功能让您能够生成功能强大的复杂应用程序,适用于商业.商务和开源开发. 2.1 使

JavaScript中的this指针详细实例

网页特效中的this指针详细实例javascript中this的用法,其实this最根本的特性还是和oo语言中的定义相吻合的.之所以有这么多看似混乱的使用方式,是因为javascript语言(解释器和语言本身的内容)本身在实现上是遵循oo的(object-based),连它的所有数据类型都是对象,也有object这样一个super object.但是这个语言在运行上(runtime),就没有遵循完备的oo特点 <script language="javascript" type=

3个步骤实现简单语言解释器(自制简易编程语言)

本文讲的是3个步骤实现简单语言解释器(自制简易编程语言), 前段时间,我用javascript重新编写了一个16位的虚拟机,用它实现了一个定制的CPU架构和汇编语言,汇编器和调试器.虽然从头编一个语言可以完全实现自己的自定义目标,但过程却及其复杂.为了使自己的编程过程更有效率,我决定使用Lel(布局表达式语言,Layout Expression Language,LEL). 本文将深入研究怎样用一个简单的方法来编写一个编程语言解释器,由于所有Lel的代码都是开放的,可以在github上使用. 解

零基础构建语言解释器

在编写Interpreter之前,我们需要先了解Lexer(词法分析器),Parser(语法解析器),AST(抽象语法树). 一般情况下,Interpreter在解释执行程序时,一般会经过如下步骤. Lexer读入程序代码,把代码转换token序列. Parser把读到的token序列转换为AST(大部分情况下,Lexer内嵌为Parser的一部分). 对AST进行Lowering(化简AST)或者desugar(把语法糖的AST节点转换为标准等价AST节点)处理. Interpreter递归执

用C语言写解释器(四)——语句分析

声明 为提高教学质量,我所在的学院正在筹划编写C语言教材.<用C语言写解释器>系列文章经整理后将收入书中"综合实验"一章.因此该系列的文章主要阅读对象定为刚学完C语言的学生(不要求有数据结构等其他知识),所以行文比较罗嗦,请勿见怪.本人水平有限,如有描述不恰当或错误之处请不吝赐教!特此声明. 语句 在前面的章节中已经成功实现了内存管理和表达式求值模块.之所以称表达式求值是解释器的核心部分,是因为几乎所有语句的操作都伴随着表达式求值.也许你已经迫不及待地给 eval 传值让它