読者です 読者をやめる 読者になる 読者になる

FLYING

〈全日本・紀文豆乳飲料シリーズ「麦芽コーヒー」の500ミリリットルパックを扱う小売店が少ないことに遺憾の意を表明する会〉活動記録

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!

うん、ちゃんと動いた。