FLYING

/* TODO: 気の利いた説明を書く */

Brainfuck in C-Language

これで、プログラミング言語インタプリタを実装したことがあるって胸を張って言える……かも。

#include <stdio.h>

int main(int argc, char *argv[])
{
	char array[1024] = { 0 };
	int stack[32], ptr = 0, stk = 0;
	int nest, c;
	FILE *fp;
	
	if (argc < 2) {
		fprintf(stderr, "Usage: brainfxck filename\n");
		return 0;
	}
	
	if ((fp = fopen(argv[1], "r")) == NULL) {
		fprintf(stderr, "can't open file\n");
		return 1;
	}
	
	while ((c = getc(fp)) != EOF) {
		switch (c) {
		case '>':
			ptr++;
			break;
		case '<':
			ptr--;
			break;
		case '+':
			array[ptr]++;
			break;
		case '-':
			array[ptr]--;
			break;
		case '.':
			putchar(array[ptr]);
			break;
		case ',':
			array[ptr] = getchar();
			break;
		case '[':
			if (array[ptr]) {
				// '['の場所をスタックにpush
				stack[stk++] = ftell(fp) - 1;
			} else {
				// 対応する']'にジャンプする
				nest = 1;
				while (nest) {
					c = getc(fp);
					if      (c == '[') nest++;
					else if (c == ']') nest--;
				}
			}
			break;
		case ']':
			// スタックをpopし、対応する'['に戻る
			fseek(fp, stack[--stk], SEEK_SET);
			break;
		}
	}
	
	fclose(fp);
	return 0;
}

バッファを使うのも面倒なので、愚直にファイルを1バイトずつ読み込んでダイレクトに実行してる。構文エラーとかデータ領域を越えたアクセスには対応してないけど、常識的なソースを放り込む分には問題ないだろう。ループしまくってるソースを実行すると遅いのは、いちいちIOにアクセスしてファイルポインタを移動させているからか?

$ cat neko
>++++++[<+++++++++++>-]<.
>++++[<++++>-]<.
>++++[<---->-]<-.
++++++++.
+++++.
--------.
+++++++++++++++.
>+++[<------>-]<.
++++++++.
>++++++[<------->-]<.

$ ./brainfxck neko
BRAINFUCK!

うん、ちゃんと動いた。