[杂记]BrainFuck语言及编译器(c++实现)
BrainFuck语言
极简的一种图灵完备的语言,由Urban Müller在1993年创造,由八个指令组成(如下表)。工作机制与图灵机非常相似,有一条足够长的纸带,初始时纸带上的每一格都是0,有一个数据读写头指向纸带的初始位置,读写头的行为由指令指示。
指令 | 含义 |
> | 指针向右移动一位 |
< | 指针向左移动一位 |
+ | 指针所指位置的值增加1字节 |
- | 指针所指位置的值减少1字节 |
. | 将指针所指位置的值按ASCII表输出 |
, | 接受1字节的输入,存储在当前指针所指位置 |
[ | 当指针当前处的值为0时,跳转到对应]之后;否则,顺序执行 |
] | 跳转回对应[处 |
用经典的Hello World!来举例说明BrainFuck语言的画风。
++++++++ [ >++++ [ >++ >+++ >+++ >+ <<<<- ] >+ >+ >- >>+ [<] <- ] >>. >---. +++++++..+++. >>. <-. <. +++.------.--------. >>+. >++.
其中的空格、缩进、换行都不影响程序,只是为了看起来可读性更强而已。事实上,上述程序完全可以写成这样:
++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.
编译器实现(c++)
写了两个版本,都差不多。第一个直接开始执行,会在从[跳转到]时向后遍历,时间稍长;第二个先做一次括号匹配,标记对应的括号位置,内存稍大(事实上,如果括号并不多,可以用STL的map来动态管理内存)。
第一个:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 5 using namespace std; 6 #define MaxCodeLen 1000 //代码最大长度 7 #define MaxTapeLen 3000 //纸带最大长度 8 9 char Code[MaxCodeLen]; //代码 10 char Tape[MaxTapeLen]; //纸带 11 int St[MaxCodeLen / 2]; //用来匹配括号的栈 12 int top = 0; //栈顶 13 14 int isLegalInstruction(char ch) 15 { 16 int Ret = 0; 17 switch(ch) 18 { 19 case '>' : 20 case '<' : 21 case '+' : 22 case '-' : 23 case '.' : 24 case ',' : 25 case '[' : 26 case ']' : Ret = 1; break; 27 case '\n' : 28 case ' ' : 29 case '\t' : Ret = 2; break; 30 default : break; 31 } 32 return Ret; 33 } 34 35 int main() 36 { 37 freopen("Pro.txt", "r", stdin); 38 char ch; 39 int len = 0; 40 int cur = 0; 41 int i, cnt; 42 char* p = Tape + MaxTapeLen / 2; //为了方便左右移动,让纸带从中间开始 43 while((ch = getchar()) != EOF) 44 { 45 //printf("ch = %c\n", ch); 46 switch(isLegalInstruction(ch)) 47 { 48 case 0 : 49 printf("illegal instruction\n"); 50 return 0; 51 case 1 : 52 Code[len++] = ch; 53 break; 54 default: 55 break; 56 } 57 } 58 //Code[len] = '\0'; 59 //printf("%s\n", Code); 60 freopen("CON", "r", stdin); 61 while(cur < len) 62 { 63 switch(Code[cur]) 64 { 65 case '>' : 66 p++; 67 break; 68 case '<' : 69 p--; 70 break; 71 case '+' : 72 (*p)++; 73 break; 74 case '-' : 75 (*p)--; 76 break; 77 case '.' : 78 printf("%c", *p); 79 break; 80 case ',' : 81 *p = getchar(); 82 break; 83 case '[' : 84 if(*p) 85 { 86 St[top++] = cur; 87 } 88 else 89 { 90 cnt = 0; 91 for(i = cur; i < len; i++) 92 { 93 if(Code[i] == '[') 94 cnt++; 95 if(Code[i] == ']') 96 cnt--; 97 if(!cnt) 98 break; 99 } 100 if(!cnt) 101 { 102 cur = i; 103 } 104 else 105 { 106 printf("parentheses do not match\n"); //左括号比右括号多 107 return 0; 108 } 109 } 110 break; 111 case ']' : 112 cur = St[top - 1] - 1; 113 top--; 114 break; 115 default: 116 break; 117 } 118 cur++; 119 if(top < 0) 120 { 121 printf("parentheses do not match\n"); //右括号比左括号多 122 return 0; 123 } 124 } 125 printf("\n"); 126 return 0; 127 }
第二个:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 5 using namespace std; 6 #define MaxCodeLen 1000 //代码最大长度 7 #define MaxTapeLen 3000 //纸带最大长度 8 9 char Code[MaxCodeLen]; //代码 10 char Tape[MaxTapeLen]; //纸带 11 int St[MaxCodeLen / 2]; //用来匹配括号的栈 12 int top = 0; //栈顶 13 int Match[MaxCodeLen]; //括号匹配 14 15 int isLegalInstruction(char ch) 16 { 17 int Ret = 0; 18 switch(ch) 19 { 20 case '>' : 21 case '<' : 22 case '+' : 23 case '-' : 24 case '.' : 25 case ',' : 26 case '[' : 27 case ']' : Ret = 1; break; 28 case '\n' : 29 case ' ' : 30 case '\t' : Ret = 2; break; 31 default : break; 32 } 33 return Ret; 34 } 35 36 int main() 37 { 38 freopen("Pro.txt", "r", stdin); 39 char ch; 40 int len = 0; 41 int cur, i, cnt; 42 char* p = Tape + MaxTapeLen / 2; //为了方便左右移动,让纸带从中间开始 43 while((ch = getchar()) != EOF) 44 { 45 //printf("ch = %c\n", ch); 46 switch(isLegalInstruction(ch)) 47 { 48 case 0 : 49 printf("illegal instruction\n"); 50 return 0; 51 case 1 : 52 Code[len++] = ch; 53 break; 54 default: 55 break; 56 } 57 } 58 //Code[len] = '\0'; 59 //printf("%s\n", Code); 60 for(i = 0; i < len; i++) 61 { 62 if(Code[i] == '[') 63 { 64 St[top++] = i; 65 } 66 else if(Code[i] == ']') 67 { 68 if(top <= 0) 69 { 70 printf("parentheses do not match\n"); //右括号比左括号多 71 return 0; 72 } 73 Match[i] = St[top - 1]; 74 Match[St[top - 1]] = i; 75 top--; 76 } 77 } 78 if(top > 0) 79 { 80 printf("parentheses do not match\n"); //左括号比右括号多 81 return 0; 82 } 83 freopen("CON", "r", stdin); 84 cur = 0; 85 while(cur < len) 86 { 87 switch(Code[cur]) 88 { 89 case '>' : 90 p++; 91 break; 92 case '<' : 93 p--; 94 break; 95 case '+' : 96 (*p)++; 97 break; 98 case '-' : 99 (*p)--; 100 break; 101 case '.' : 102 printf("%c", *p); 103 break; 104 case ',' : 105 *p = getchar(); 106 break; 107 case '[' : 108 if(!(*p)) 109 { 110 cur = Match[cur]; 111 } 112 break; 113 case ']' : 114 cur = Match[cur] - 1; 115 break; 116 default: 117 break; 118 } 119 cur++; 120 } 121 printf("\n"); 122 return 0; 123 }
【也许有空了可以琢磨一下写个界面hhh】