CによるBrainfuckインタプリタ
難解プログラミング言語のひとつBrainfuckのインタプリタをCで書いてみた.
環境はVC2008ProSP1とWindowsVistaSP2.
BrainfuckとはUrban Dominik Müllerが考案した言語でコンパイラを小さくすることを
目的として開発された.
機能は8つしか持たないがチューリング完全性を備えており,Cなどと同等の表現力があるらしい.
名前があまりにもアレなのでBrainf*ckやBFと表記するようだ.
これをきっかけに難解プログラミング言語という分野が生まれたとか…
どんなものかというと…
http://ja.wikipedia.org/wiki/Brainfuck
処理系内部には30000バイトのbyte型の配列があり,配列の要素は0で初期化される.また、その配列の要素のひとつを指す暗黙のポインタがあり、ポインタは最初配列の先頭を指している。
ほうほう
Cにはbyte型はないのでtypedefする.
windef.hには
typedef unsigned char BYTE;
と書いてあるのでこれを参考にさせてもらうことにした.
暗黙のポインタということは外部から直接操作できるものではないんだろう.
とりあえずポインタはC/C++のポインタという意味ではなさそう.
byte buff[30000];
int buff_ptr;
でいいかな
命令はわずか8つ
'>' ポインタをインクリメントする
'<' ポインタをデクリメントする
'+' ポインタが指す値をインクリメントする
'-' ポインタが指す値をデクリメントする
'.' ポインタの指す値を出力する
',' 1バイトを入力してポインタが指す値に代入する
'[' ポインタが指す値が0なら、対応する ] の直後までジャンプする
']' ポインタが指す値が0でないなら、対応する [ にジャンプする
これだけ
うーんシンプル
#include<stdio.h> #define CODE_SIZE 30000 #define BUFF_SIZE 30000 typedef unsigned char byte; int main(int argc, char *argv[]) { FILE *fp; char code[CODE_SIZE]; byte buff[BUFF_SIZE]; int code_ptr = 0, code_len = 0, buff_ptr = 0, loop = 0; int i; if(argc != 2){ printf("error\n"); return -1; } if((fp = fopen(argv[1], "r")) == NULL){ printf("file open error\n"); return -1; } for(code_len = 0; (code[code_len] = fgetc(fp)) != EOF && code_len < CODE_SIZE; code_len++) ; for(i = 0; i < BUFF_SIZE; i++) buff[i] = 0; for(; code_ptr < code_len; code_ptr++){ switch(code[code_ptr]){ case '>': buff_ptr++; break; case '<': buff_ptr--; break; case '+': buff[buff_ptr]++; break; case '-': buff[buff_ptr]--; break; case '.': putchar(buff[buff_ptr]); break; case ',': buff[buff_ptr] = getchar(); break; case '[': if(buff[buff_ptr] == 0){ for(code_ptr++; loop > 0 || code[code_ptr] != ']'; code_ptr++){ if(code[code_ptr] == '[') loop++; if(code[code_ptr] == ']') loop--; } } break; case ']': if(buff[buff_ptr] != 0){ for(code_ptr--; loop > 0 || code[code_ptr] != '['; code_ptr--){ if(code[code_ptr] == ']') loop++; if(code[code_ptr] == '[') loop--; } code_ptr--; } break; } } fclose(fp); return 0; }