Brainfuck 是一门非常简单甚至可以说是最简单的编程语言,wikipedia。
它的语法由一个8个字符的字符集组成,即><+=.,[]
八个字符。brainfuck的模型还包括一个以字节为单位、被初始化为零的数组、一个指向该数组的指针(初始时指向数组的第一个字节)、以及用于输入输出的两个字节流。
这八个字符每一个都是一条指令:
> 指针加一
< 指针减一
+ 指针指向的字节的值加一
- 指针指向的字节的值减一
. 按ASCII码输出指针指向字节内容
, 按ASCII码输入内容到指针指向字节
[ 如果指针指向的单元值为零,向后跳转到对应的]指令的次一指令处
] 如果指针指向的单元值不为零,向前跳转到对应的[指令的次一指令处
brainfuck 是图灵完备的,你可以用它来实现你想实现的任何功能。
brainfuck的hello world程序:
++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]
>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.
而从上面的语法来看,我们可以将其完全地等效为对应的C语言。
基于上述语法等效我们可以来写一个brainfuck to C的解释器。其实就是读取字符处理就OK了,一个switch...case
不能更简单。再简单处理一下对齐,保持良好的可读性(然而这并不会使我们更容易理解brainfuck编译出来的c程序)。
实现:
// brianfuck to C
#include <fstream>
#include <string>
using namespace std;
const int max_box_size = 3000;
ifstream fin;
ofstream fout;
void translate_to_c(const char * file_name);
void retract(int n);
int main(int argc, char const *argv[])
{
for (int i = 0; i < argc; ++i)
{
translate_to_c(argv[i]);
}
return 0;
}
void translate_to_c(const char * file_name)
{
fin.open(file_name);
string target_file_name = file_name;
target_file_name += ".c";
fout.open(target_file_name);
fout << "// file_name : " << target_file_name << endl;
fout << "// This file is a c soucrce file interpreted from brainfuck souce file " << file_name << ".\n";
fout << "#include <stdio.h>\n" << "#define max_box_size " << max_box_size << endl;
fout << "char box[max_box_size];\n";
fout << "char *ptr = box;\n";
fout << "int main()\n{\n";
char ch;
int retract_num = 1;
while(fin.get(ch))
{
switch(ch)
{
case '>': retract(retract_num); fout << "++ptr;\n"; break;
case '<': retract(retract_num); fout << "--ptr;\n"; break;
case '+': retract(retract_num); fout << "++*ptr;\n"; break;
case '-': retract(retract_num); fout << "--*ptr;\n"; break;
case '.': retract(retract_num); fout << "putchar(*ptr);\n"; break;
case ',': retract(retract_num); fout << "*ptr=getchar();\n"; break;
case '[': retract(retract_num++); fout << "while (*ptr) {\n"; break;
case ']': retract(--retract_num); fout << "}\n"; break;
}
}
fout << "\n return 0;" << endl;
fout << "}\n";
fin.close();
fout.close();
}
void retract(int n)
{
for(int i=0;i<n;i++)
fout << ' ';
}
编译运行上述cpp程序,得到可执行文件,命令行环境下将待解释的brainfuck文件作为参数,执行命令便可得到对应的C程序。保存上述文件为bftoc.cpp
,helloworld存为hello.bf
。
g++ -o bftoc bftoc.cpp
./bftoc hello.bf
gcc -o hello.out hello.bf.c
./hello.out
hello world!
一个在线的brainfuck可视化执行工具:brainfuck-visualizer