challenge BFコンパイラー

「どう書く?」でまだ出ていないのが不思議なお題。それがBF処理系。 ここでは、BFで書かれたソースを、同じ言語に変換するコンパイラーを募集します。

私自身、すでにPerlとJavaScriptに関しては http://blog.livedoor.jp/dankogai/archives/50545151.html でやっているのですが、他の言語バージョンも是非見たいので。

Dan the Brainf.ucker

以下のようにonelinerで可能です。 ただしLanguage::BF 0.03が必要です。 CodeRepos経由 で、

  • svn co svn.coderepos.org/share/lang/perl/Language-BF
  • cd Language-BF/trunk
  • perl Makefile.PL
  • make install

するか、CPANにVersion 0.03が現れるのをお待ち下さい。

Dan the Brainf.cker

1
2
3
4
perl -MLanguage::BF \
  -e 'print Language::BF->new_from_file(shift)->as_perl' t/hello.bf \
  | perl
Hello World!

Posted feedbacks - C

簡単の為、標準出力を使用。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <stdio.h>
#include <stdlib.h>

int main(int arg_c, char **arg_v) {
    FILE *fp;
    int c;

    if (*++arg_v == NULL) {
        fprintf(stderr, "usage: bfc [source file]\n");
        exit(EXIT_FAILURE);
    }
    if ((fp = fopen(*arg_v, "r")) == NULL) {
        fprintf(stderr, "file open error.\n");
        exit(EXIT_FAILURE);
    }
    
    puts("#include <stdio.h>");
    puts("#include <stdlib.h>");
    puts("int main(void) {");
    puts(" char *s, *p;");
    puts(" p = s = (char *)calloc(1024, 1);");
    
    while ((c = getc(fp)) != EOF) {
        switch (c) {
            case '>': puts(" ++p;"); break;
            case '<': puts(" --p;"); break;
            case '+': puts(" ++*p;"); break;
            case '-': puts(" --*p;"); break;
            case '.': puts(" putchar(*p);"); break;
            case ',': puts(" *p = getchar();"); break;
            case '[': puts(" while (*p) {"); break;
            case ']': puts(" }"); break;
            default: break;
        }
    }
    
    puts(" free(s);");
    puts("}");
    
    fclose(fp);
}

出力のインデント処理と配列の長さを引数で調整できるようにしてみました。
./bf2c hello.bf > hello.c
または
./bf2c hello.bf 128 > hello.c
のように使います。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include <stdio.h>
#include <stdlib.h>

char *code[] = { "sp++;", "sp--;", "(*sp)++;", "(*sp)--;", "putchar(*sp);",
                 "*sp = getchar();", "while(*sp){", "}" };

int main( int argc, char *argv[] ){
   int c,i,j,n=0;
   int indent = 1;
   int length;
   FILE *fp;

   if( argc < 2 ){
      fprintf(stderr,"Usage: %s sourcefile\n", argv[0] );
      return EXIT_FAILURE;
   }
   if( (fp = fopen( argv[1], "r" )) == NULL ){
      fprintf(stderr,"Error: %s cannot opened\n", argv[1] );
      return EXIT_FAILURE;
   }
   if( !argv[2] || (length = atoi( argv[2] )) <= 0 ){
      length = 256;
   }

   puts("#include <stdio.h>");
   puts("#include <stdlib.h>");
   printf("#define DATA_LEN %d\n", length);
   puts("char code[DATA_LEN];");
   puts("int main (void){");
   puts("   char *sp = code;");
   while( (c=fgetc( fp )) != EOF ){
      switch(c){
      case '>': i = 0; break;
      case '<': i = 1; break;
      case '+': i = 2; break;
      case '-': i = 3; break;
      case '.': i = 4; break;
      case ',': i = 5; break;
      case '[': i = 6; indent++; break;
      case ']': i = 7; indent--; break;
      default:
         /* skip other characters */
         continue;
      }
      for( j = 0; j < (indent+(i==6?-1:0)); j++ ){
         printf("   ");
      }
      printf("%s\n", code[i] );
   }
   puts("   return EXIT_SUCCESS;");
   puts("}");
   fclose(fp);
   return EXIT_SUCCESS;
}

ケースが嫌いな私は、以下のように書き換えてしまいました。機能的には#3955と互換ですが、出力されたCコードのコンパイルには差し支えないのでインデントは省略しました。

Dan the Brainf.cker

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <stdio.h>
#include <stdlib.h>

int main( int argc, char *argv[] ){
    int c;
    char *code[256];
    int length;
    FILE *fp;

    if( argc < 2 ){
        fprintf(stderr,"Usage: %s sourcefile\n", argv[0] );
        return EXIT_FAILURE;
    }
    if( (fp = fopen( argv[1], "r" )) == NULL ){
        fprintf(stderr,"Error: %s cannot opened\n", argv[1] );
        return EXIT_FAILURE;
    }
    if( !argv[2] || (length = atoi( argv[2] )) <= 0 ){
        length = 256;
    }

    for (c = 0; c < 256; c++) code[c] = NULL;
    code['>'] = "sp++;";
    code['<'] = "sp--;";
    code['+'] = "(*sp)++;";
    code['-'] = "(*sp)--;";
    code['.'] = "putchar(*sp);";
    code[','] = "*sp = getchar();";
    code['['] = "while(*sp){";
    code[']'] = "}";

    puts("#include <stdio.h>");
    puts("#include <stdlib.h>");
    printf("#define DATA_LEN %d\n", length);
    puts("char code[DATA_LEN];");
    puts("int main (void){");
    puts("   char *sp = code;");
    while( (c=fgetc( fp )) != EOF ) if (code[c]) printf("%s\n", code[c]); 
    puts("   return EXIT_SUCCESS;");
    puts("}");
    fclose(fp);
    return EXIT_SUCCESS;
}

少しだけ最適化を行います。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#include <stdio.h>

void putnest(FILE* fout,int n){
    while(n--){
        fprintf(fout,"\t");
    };
}

int main(){
    char filename[]="test.bf";
    FILE *fin;
    FILE *fout;
    int cmd=' ',lastcmd;
    int count=0;
    int nest=1;
    fin =fopen(filename,"r");
    fout=fopen("bf.c","w");
    
    fprintf(fout,"#include<stdio.h>\n");
    fprintf(fout,"\n");
    fprintf(fout,"int main(){\n");
    fprintf(fout,"\tint  buf[256];\n");
    fprintf(fout,"\tint *ptr;\n");
    fprintf(fout,"\tint i;");
    fprintf(fout,"\n");
    fprintf(fout,"\tfor(i=0;i<256;i++) buf[i]=0;\n");
    fprintf(fout,"\tptr=buf;\n");
    fprintf(fout,"\n");
    
    do{
        lastcmd=cmd;
        cmd=fgetc(fin);
        if(lastcmd!=cmd){
            switch(lastcmd){
            case '+':
            case '-':
            case '>':
            case '<':
                putnest(fout,nest);
                fprintf(fout,"%s%c",lastcmd&0x10?"ptr":"(*ptr)",lastcmd&0x02?'+':'-');
                if(count==1)
                    fprintf(fout,"%c;\n",lastcmd&0x02?'+':'-');
                else
                    fprintf(fout,"=%d;\n",count);
                count=0;
                break;
            }
        }
        switch(cmd){
            case '+':
            case '-':
            case '>':
            case '<':
                count++;
                break;
            case '[':
                putnest(fout,nest);
                fprintf(fout,"while(*ptr){\n");
                nest++;
                break;
            case ']':
                nest--;
                putnest(fout,nest);
                fprintf(fout,"}\n");
                break;
            case '.':
                putnest(fout,nest);
                fprintf(fout,"putchar(*ptr);\n");
                break;
            case ',':
                putnest(fout,nest);
                fprintf(fout,"*ptr=getchar();\n");
                break;
        }
    }while(cmd!=EOF);
    fprintf(fout,"    return 0;\n");
    fprintf(fout,"}\n");
    fprintf(fout,"\n");
    return 0;
}

にしおさんのlex/yacc見てなるほど思ったので、本家lexのお勉強。 下のコードをbf.lとすると % lex bf.l % cc lex.yy.c -ll -o bfc としてコンパイル。 % ./bfc <hello.bf >hello.c % cc hello.c % ./a.out Hello World! のように使います。

一応 ++++++ → *pt = 6 みたいなことするようにしてみました。

System Message: WARNING/2 (<string>, line 12); backlink

Inline emphasis start-string without end-string.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
%{
#include <stdio.h>
#include <string.h>
%}
%option noyywrap
%%
\++ printf("*pt+=%d;\n", strlen(yytext));
\-+ printf("*pt-=%d;\n", strlen(yytext));
\>+ printf("pt+=%d;\n", strlen(yytext));
\<+ printf("pt-=%d;\n", strlen(yytext));
\, puts("*pt=getchar();");
\. puts("putchar(*pt);");
\[ puts("while(*pt){");
\] puts("}");
. ;
%%
int main(int argc, char **argv)
{
  puts("#include <stdio.h>\n"
  "int mem[30000];\n"
  "int *pt = mem;\n"
  "int main(){");
  yylex();
  puts("return 0;\n}");
  return 0;
}

昔七行スレに投下したのを投稿してみる。
要gcc、出力はa.outで固定です。
$ gcc bfc.c -o bfc #コンパイラのコンパイル
$ ./bfc hoge.bf #コンパイル
$ ./a.out #実行
1
2
3
4
5
6
7
#include <stdio.h>
int system(),i;int main(int c,char**v){FILE*f=fopen(*++v,"r"),*g=fopen("!.c","w"
);char s[99],*o[]={"putchar(*p);","*p=getchar();","while(*p){","}","++p;","--p;"
,"++*p;","--*p;"};fputs("#include<stdio.h>\nint main(void){static int b[30000],"
"*p=b;",g);for(;f&&(c=fgetc(f))-EOF;)for(i=8;0<i--;)fputs(".,[]><+-"[i]-c?"":o[i
],g);fputs("return 0;}",g);fclose(f);fclose(g);sprintf(s,"gcc !.c -o%s",*++v);
return system(s);}

Index

Feed

Other

Link

Pathtraq

loading...