JavaScript1.6でBrainf**kもどきを実装

2008/09/10追記

gistに置いた
9713’s gists · GitHub

動機

1000speakersとかで言語の処理系を実装した人をたくさん目にしたが、
自分はまだ一つも実装していない。
これでプログラマを名乗ってていいのか?

言い訳とか

やっつけ仕事のためにArray.prototype.indexOfが使いたかったのでJavaScript1.6。
とりあえずHelloWorldだけでも動かしたかったので、
,での入力、ネストした[]でのループは未実装。

実装

メモリセル
function Cell(memory){
	this._memory = memory || [];
	if(!this._memory.length){
		this._memory.push(this);
	}
};
Cell.prototype._memory;
Cell.prototype._num = 0;
Cell.prototype.incr = function(){
	if(this._num < 255){
		this._num++;
	}
	return this;
};
Cell.prototype.decr = function(){
	if(this._num > 0){
		this._num--;
	}
	return this;
};
Cell.prototype.ptrIncr = function(){
	var mem = this._memory;
	var idx = mem.indexOf(this);
	if(idx < 0){
		throw new Error();
	}else if(idx < mem.length - 1){
		return mem[idx + 1];
	}else{
		var cell = new Cell(mem);
		mem.push(cell);
		return cell;
	}
};
Cell.prototype.ptrDecr = function(){
	var mem = this._memory;
	var idx = this._memory.indexOf(this);
	if(idx < 0){
		throw new Error();
	}else if(idx == 0){
		var cell = new Cell(mem);
		mem.unshift(cell);
		return cell;
	}else{
		return mem[idx - 1];
	}
};
Cell.prototype.put = function(){
	console.log(String.fromCharCode(this._num));
}
Cell.prototype.getNum = function(){
	return this._num;
}

値と自分が属するメモリへの参照を持ってるクラス。
ポインタのインクリメント・デクリメント=配列の後・前への移動に
Array.prototype.indexOfを利用した。
前後それぞれの端まで行ってしまったら新しいCellインスタンスをくっつけていく。
なので、メモリが許す限り無限に続くメモリセルの連なりになってるはず。

ソースを読んで処理する側
function fuck(source){
	var idx = 0;
	var curr = new Cell();
	while(idx < source.length){
		switch(source.charAt(idx)){
			case '>':
				curr = curr.ptrIncr();
				idx++;
				break;
			case '<':
				curr = curr.ptrDecr();
				idx++;
				break;
			case '+':
				curr.incr();
				idx++;
				break;
			case '-':
				curr.decr();
				idx++;
				break;
			case ',':
				idx++;
				break;
			case '.':
				curr.put();
				idx++;
				break;
			case '[':
				if(curr.getNum() == 0){
					var end = source.indexOf(']',idx);
					if(end < 0){
						throw new Error();
					}
					idx = end;
				}else{
					idx++;
				}
				break;
			case ']':
				if(curr.getNum() != 0){
					var start = source.lastIndexOf('[',idx);
					if(start < 0){
						throw new Error();
					}
					idx = start;
				}else{
					idx++;
				}
				break;
			default:
				throw new Error();
		}
	}
}

ちょーやっつけ。
文字列上を右に行ったり左に行ったりしてるだけ。
ブラケットの片割れを探すのをString.prototype.indexOfと
String.prototype.lastIndexOfでやってるのでネストしてると駄目。

HelloWorld
fuck('+++++++++[>++++++++>+++++++++++>+++++<<<-]>.>++.+++++++..+++.>-.------------.<++++++++.--------.+++.------.--------.>+.');

上の関数を呼んでやるだけ。