介绍两个比较好玩的编程语言

  BF语言介绍

  Brainfuck,是一种极小化的计算机语言,这种 语言,是一种按照"Turing complete(完整图灵机)"思想设计的语言,它的主要设计思路是:用最小的概念实现一种"简单"的语言,BrainFuck 语言只有八种符号,所有的操作都由这八种符号的组合来完成。BF基于一个简单的机器模型,除了八个指令,这个机器还包括:一个以字节为单位、被初始化为零的数组、一个指向该数组的指针(初始时指向数组的第一个字节)、以及用于输入输出的两个字节流。

  下面是这八种指令的描述,其中每个指令由一个字符标识:

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

   提供一个简单的HelloWord程序

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

  下面提供一个BF的解析器,用C语言模拟的。

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <stdlib.h>
 4 
 5 int main(int argc,char *argv[])
 6 {
 7     FILE * rfp;
 8     FILE * wfp;
 9     char filename[64];
10     char exec[128];
11     char ch;
12     if(argc!=2)
13     {
14         printf("请输入brainfuck源文件:");
15         scanf("%s",filename);
16     }
17     else
18     {
19         strcpy(filename,argv[1]);
20     }
21     rfp=fopen(filename,"r");
22     strcat(filename,".c");
23     wfp=fopen(filename,"w");
24     if(rfp==NULL || wfp==NULL)
25     {
26         printf("Can't open the file!\n");
27         return -1;
28     }
29     fputs("#include <stdio.h>\n#include <string.h>\n int main(int argc,char *argv[])\n{",wfp);
30     fputs("char *ptr; \n char memory_tmp[0xffff];\n",wfp);
31     fputs("memset(memory_tmp,0,sizeof(memory_tmp));\nptr=memory_tmp;\n ",wfp);
32 
33     while((ch=fgetc(rfp))!=EOF)
34     {
35         //printf("%c",ch);
36         switch(ch)
37         {
38             case '>':
39                 fputs("++ptr;\n",wfp);
40                 break;
41             case '<':
42                 fputs("--ptr;\n",wfp);
43                 break;
44             case '+':
45                 fputs("++*ptr;\n",wfp);
46                 break;
47             case '-':
48                 fputs("--*ptr;\n",wfp);
49                 break;
50             case '.':
51                 fputs("putchar(*ptr);\n",wfp);
52                 break;
53             case ',':
54                 fputs("*ptr=getchar();\n",wfp);
55                 break;
56             case '[':
57                 fputs("while(*ptr)\n{\n",wfp);
58                 break;
59             case ']':
60                 fputs("}\n",wfp);
61                 break;
62             default:
63                 break;
64         }
65     }
66     fputs("\n return 0; \n }",wfp);
67     fclose(rfp);
68     fclose(wfp);
69     memset(exec,0,sizeof(exec));
70     strcpy(exec,"gcc ");
71     strcat(exec,filename);
72     strcat(exec," -o tmp.tmp; rm ");
73     strcat(exec,filename);
74     strcat(exec,"; chmod 777 tmp.tmp;./tmp.tmp ; rm tmp.tmp;");
75     //printf("运行的命令是:%s\n",exec);
76     printf("===============brainfuck运行结果=================\n");
77     system(exec);
78     printf("=================================================\n");
79     return 0;
80 }

  下面对那个Hello World进行解释

 1 +++ +++ +++ +           initialize counter (cell #0) to 10
 2 [                       use loop to set the next four cells to 70/100/30/10
 3     > +++ +++ +             add  7 to cell #1
 4     > +++ +++ +++ +         add 10 to cell #2
 5     > +++                   add  3 to cell #3
 6     > +                     add  1 to cell #4
 7     <<< < -                 decrement counter (cell #0)
 8 ]
 9 >++ .                   print 'H'
10 >+.                     print 'e'
11 +++ +++ +.              print 'l'
12 .                       print 'l'
13 +++ .                   print 'o'
14 >++ .                   print ' '
15 <<+ +++ +++ +++ +++ ++. print 'W'
16 >.                      print 'o'
17 +++ .                   print 'r'
18 --- --- .               print 'l'
19 --- --- --.             print 'd'
20 >+.                     print '!'
21 >.                      print '\n'

  下面提供一个小程序用于把玩

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

 

  Piet语言

  Piet 是一种非常深奥的编程语言,使用颜色编写代码。由David Morgan-Mar,其方案是位图,看起来像抽象艺术设计。编译指导图像周围移动,从一个连续颜色的区域下的一个“指针”。通过一个地区的指针退出时的程序进行。

  由于原本的Piet语法比较复杂,我对其修改如下,使其比较简单和容易实现。

编号 指令 含义 颜色Red 颜色Green 颜色Blue
1 start 表示一个代码段的开始 0 0 0
2 end 表示一个代码段的结束 2 2 2
3 ++(plusplus) 将寄存器中的数加1 0 0 1
4 --(minusminus) 将寄存器中的数减1 0 0 2
5 push 将寄存器中的数写入栈中 0 1 1
6 pop 将栈中的数读弹出并不存入寄存器中 0 1 2
7 in 控制台输入一个字符到寄存器 0 2 1
8 out 将寄存器的字符打印到控制台 0 2 2
9 turn

栈顶元素与寄存器比较,如果相等则代码方向指针向前

如果大于则代码方向指针向左,如果小于则代码方向指针向右

1 0 1
10 zero 将寄存器中的数置零 1 0 0
11 call 跳转指令,以寄存器为x,以栈顶数为y,跳到图像的(x,y)位置开始执行 1 1 1
12 add 栈顶元素与寄存器相加,并保存在寄存器中 2 0 0
13 sub 栈顶元素减去寄存器,差保存在寄存器中 2 0 1
14 mul 栈顶元素与寄存器相乘,并保存在寄存器中 2 1 0
15 div 栈顶元素除以寄存器,商保存在寄存器中 2 1 1

  这个语言包含一个栈,还有一个寄存器,包含IO操作。十五个颜色的对应如下

   我给出的程序是使用PPM格式的图片,彩色255颜色,以左上角为(0,0)右下角(sx,xy).

  下面这个是用于编译的代码

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <string.h>
  4 
  5 #define START       1
  6 #define END         2
  7 #define PLUSPLUS    3
  8 #define MINUSMINUS  4
  9 #define PUSH        5
 10 #define POP         6
 11 #define IN          7
 12 #define OUT         8
 13 #define TURN        9
 14 #define ZERO        10
 15 #define CALL        11
 16 #define ADD         12
 17 #define SUB         13
 18 #define MUL         14
 19 #define DIV         15
 20 
 21 struct IMG
 22 {
 23     int channel;
 24     int sx,sy;
 25     int maxv;
 26     unsigned char * img;
 27 };
 28 
 29 int ReadPPM(char * fname,struct IMG * img)
 30 {
 31     FILE * fp=NULL;
 32     char ch;
 33     fp=fopen(fname,"rb");
 34     if(fp==NULL)
 35     {
 36         perror("Can't open the file");
 37         exit(-1);
 38     }
 39     fscanf(fp,"%c%d%d%d%d%*c",&ch,&img->channel,&img->sx,&img->sy,&img->maxv);
 40     if(img->channel==6)
 41     {
 42         img->img=(unsigned char *)malloc(img->sx*img->sy*3);
 43         if(img->img==NULL)
 44         {
 45             perror("Can't malloc memory");
 46             exit(-1);
 47         }
 48         fread(img->img,img->sx*img->sy*3,1,fp);
 49     }
 50     fclose(fp);
 51     return 0;
 52 }
 53 
 54 struct Dir
 55 {
 56     int x;
 57     int y;
 58 };
 59 
 60 int to3(int a)
 61 {
 62     if(a<=50)
 63         return 0;
 64     if(a>50&&a<150)
 65         return 1;
 66     if(a>=200)
 67         return 2;
 68     perror("图片格式模糊不便执行");
 69 }
 70 
 71 int toinc(int r,int g,int b)
 72 {
 73     int i;
 74     if(to3(r)==0 && to3(g)==0 &&to3(b)==0)
 75         return START;
 76     if(to3(r)==2 && to3(g)==2 &&to3(b)==2)
 77         return END;
 78 
 79     if(to3(r)==0 && to3(g)==0 &&to3(b)==1)
 80         return PLUSPLUS;
 81     if(to3(r)==0 && to3(g)==0 &&to3(b)==2)
 82         return MINUSMINUS;
 83 
 84     if(to3(r)==0 && to3(g)==1 &&to3(b)==1)
 85         return PUSH;
 86     if(to3(r)==0 && to3(g)==1 &&to3(b)==2)
 87         return POP;
 88 
 89     if(to3(r)==0 && to3(g)==2 &&to3(b)==1)
 90         return IN;
 91     if(to3(r)==0 && to3(g)==2 &&to3(b)==2)
 92         return OUT;
 93 
 94     if(to3(r)==1 && to3(g)==0 &&to3(b)==1)
 95         return TURN;
 96     if(to3(r)==1 && to3(g)==0 &&to3(b)==0)
 97         return ZERO;
 98     if(to3(r)==1 && to3(g)==1 &&to3(b)==1)
 99         return CALL;
100 
101     if(to3(r)==2 && to3(g)==0 &&to3(b)==0)
102         return ADD;
103     if(to3(r)==2 && to3(g)==0 &&to3(b)==1)
104         return SUB;
105     if(to3(r)==2 && to3(g)==1 &&to3(b)==0)
106         return MUL;
107     if(to3(r)==2 && to3(g)==1 &&to3(b)==1)
108         return DIV;
109 }
110 
111 int decode(struct IMG * img)
112 {
113     struct Dir dir;//代码方向向量
114     struct Dir now;//表示当前代码指针
115     int stack[1024];
116     char ch;
117     int inc;//保存指令
118     int ptr;//栈指针
119     int reg;//这个是寄存器
120     int tmp;
121     memset(stack,0,sizeof(stack));
122     ptr=0;reg=0;
123     dir.x=1;
124     dir.y=0;//表示向前
125     now.x=0;
126     now.y=0;
127     inc=toinc(img->img[0],img->img[1],img->img[2]);
128     while(1)
129     {
130         tmp=now.y*img->sx*3+now.x*3;
131         inc=toinc(img->img[tmp],img->img[tmp+1],img->img[tmp+2]);
132         //printf("%d x=%d y=%d\n",inc,now.x,now.y);
133         //printf("此时reg=%d stack=%d\n",reg,stack[ptr-1]);
134         //getchar();
135         switch(inc)
136         {
137             case START:
138                 {
139                     break;
140                 }
141             case END:
142                 {
143                     return 0;
144                 }
145             case PLUSPLUS:
146                 {
147                     reg++;
148                     break;
149                 }
150             case MINUSMINUS:
151                 {
152                     reg--;
153                     break;
154                 }
155             case PUSH:
156                 {
157                     stack[ptr]=reg;
158                     ptr++;
159                     break;
160                 }
161             case POP:
162                 {
163                     ptr--;
164                     break;
165                 }
166             case IN:
167                 {
168                     fflush(stdin);
169                     ch=getchar();
170                     reg=ch;
171                     break;
172                 }
173             case OUT:
174                 {
175                     printf("%c",reg);
176                     break;
177                 }
178             case TURN:
179                 {
180                     if(stack[ptr-1]>reg)//左转
181                     {
182                         //printf("左转\n");
183                         if(dir.x==1&&dir.y==0)//
184                         {
185                             dir.x=0;dir.y=-1;
186                         }
187                         else if(dir.x==-1&&dir.y==0)//西
188                         {
189                             dir.x=0;dir.y=1;
190                         }
191                         else if(dir.x==0&&dir.y==1)//
192                         {
193                             dir.x=1;dir.y=0;
194                         }
195                         else if(dir.x==0&&dir.y==-1)//
196                         {
197                             dir.x=-1;dir.y=0;
198                         }
199                     }
200                     else if(stack[ptr-1]<reg)//右转
201                     {
202                         //printf("右转\n");
203                         if(dir.x==1&&dir.y==0)//
204                         {
205                             dir.x=0;dir.y=1;
206                         }
207                         else if(dir.x==-1&&dir.y==0)//西
208                         {
209                             dir.x=0;dir.y=-1;
210                         }
211                         else if(dir.x==0&&dir.y==1)//
212                         {
213                             dir.x=-1;dir.y=0;
214                         }
215                         else if(dir.x==0&&dir.y==-1)//
216                         {
217                             dir.x=1;dir.y=0;
218                         }
219                     }
220                     else
221                     {
222                         ;//不变
223                     }
224                     break;
225                 }
226             case ZERO:
227                 {
228                     reg=0;
229                     break;
230                 }
231             case CALL:
232                 {
233                     now.x=reg;
234                     now.y=stack[ptr-1];
235                     continue;
236                     break;
237                 }
238             case ADD:
239                 {
240                     reg=reg+stack[ptr-1];
241                     break;
242                 }
243             case SUB:
244                 {
245                     reg=stack[ptr-1]-reg;
246                     break;
247                 }
248             case MUL:
249                 {
250                     reg=reg*stack[ptr-1];
251                     break;
252                 }
253             case DIV:
254                 {
255                     reg=stack[ptr-1]/reg;
256                     break;
257                 }
258         }
259         now.x=now.x+dir.x;
260         now.y=now.y+dir.y;
261     }
262 
263     return 0;
264 }
265 
266 int main(int argc,char *argv[])
267 {
268     int i,j;
269     struct IMG image;
270     struct IMG *pimg=&image;
271     char filename[64];
272     if(argc!=2)
273     {
274         printf("请输入要编译的文件:");
275         scanf("%s",filename);
276     }
277     else
278     {
279         strcpy(filename,argv[1]);
280     }
281     ReadPPM(filename,pimg);
282     decode(pimg);
283     return 0;
284 }
View Code

  运行这个程序: ./ppm file.ppm

  例如下面这个图片将会输出"He"这两个字符,本来是要输出Helloworld的,但是发现画起来有点麻烦,所以就没有画了。

  

  上面的指令表示如下:

  start;++;++;push;mul;mul;mul;mul;mul;
  push;zero;++;++;push;++turn;--;
  mul;mul;pop;add;out;++;turn;--;
  push;zero;++;++;push;mul;mul;
  mul;mul;pop;add;--;--;--;out;end;

  看起来很神奇的样子呢!画了几个图,下面有点小经验,(如果有人真的去画的话。)关于转弯的问题,转弯是紫色,要让当前是左转还是右转,就取决于前一个颜色块是++块还是--块,然后为了恢复,后面就接着用--块或++块,这就实现转弯了。如果有强迫症的想每一行都用上像个已字一样那么就只需同时使用两个转弯就可以了。注意两次右转就实现向后了,而且还是只隔一行。好方便的说。

  如果有兴趣还可以根据指令生成一张ppm的图片呢,然后再用程序去执行它。

 

  参考资料: http://coolshell.cn/articles/1142.html

        http://www.dangermouse.net/esoteric/piet/samples.html

  本文地址: http://www.cnblogs.com/wunaozai/p/3888481.html

  用到的程序和图片: https://files.cnblogs.com/wunaozai/BF%26Piet.zip

posted @ 2014-08-04 00:32  无脑仔的小明  阅读(8079)  评论(7编辑  收藏  举报