JS_RandezvousでBrainfuckインタプリタ
サンプルとして作ってみた。ロジックはほぼJSDeferredのサンプルと同じ。
せっかくなので実行中に停止する機能とステップ実行も付けておいた。
Task.define();
$(function() {
var brf = new Task(
function() {
this.jRun = $("#run").click(brf.run).text("Run");
this.jPause = $("#pause").click(brf.pause).text("Pause");
this.jStep = $("#step").click(brf.step).text("Step");
this.jSource = $("#source");
this.jSourceView = $("#source_view");
},
loop(
true,
accept(
"run",
function() {
this.source = $("#source").val();
this.pos = 0;
this.memory = [0];
this.pointer = 0;;
this.stack = [true];
this.output = [];
this.running = true;
this.jRun.click(brf.run).text("Abort");
this.jPause.click(brf.pause).removeAttr("disabled");
this.jSource.hide();
var sourceView = this.jSourceView.empty();
this.elem = $.map(
this.jSource.val().split(""),
function(c) {
if (c == "\n") c = $("<br/>");
return $("<span/>").append(c).appendTo(sourceView);
});
this.jSourceView.show();
}
),
loop(
function() {return this.pos < this.source.length},
function() {
if (this.source[this.pos] == ",") {
this.jStep.removeAttr("disabled");
this.jStep.text(",");
}
},
select(
accept(
"run",
function() {
return exit();
}),
accept(
"pause",
function() {
this.running = ! this.running;
if (this.running) {
this.jPause.text("Pause");
this.jStep.attr("disabled", true);
} else {
this.jPause.text("Continue");
this.jStep.removeAttr("disabled");
}
}),
when(function() {return ! this.running || this.source[this.pos] == ",";})
.accept("step", function() {
this.putchar = $("#putchar_value").val()[0];
this.jStep.attr("disabled", this.running);
this.jStep.text("step");
}),
when(function() {return this.running && this.source[this.pos] != ","})
.delay(0)
),
function() {
if (this.elem[this.pos - 1])
this.elem[this.pos - 1].removeClass("em");
switch(this.source[this.pos]) {
case "+":
if (! this.stack[0]) break;
this.memory[this.pointer]++;
break;
case "-":
if (! this.stack[0]) break;
this.memory[this.pointer]--;
break;
case ">":
if (! this.stack[0]) break;
this.pointer++;
this.memory[this.pointer] =
this.memory[this.pointer] || 0;
break;
case "<":
if (! this.stack[0]) break;
this.pointer--;
this.memory[this.pointer] =
this.memory[this.pointer] || 0;
break;
case ".":
if (! this.stack[0]) break;
this.output.push(
String.fromCharCode(this.memory[this.pointer]));
break;
case ",":
if (! this.stack[0]) break;
this.memory[this.pointer] =
String.charCodeAt(this.putchar);
break;
case "[":
if (this.memory[this.pointer] == 0)
this.stack.unshift(false);
else this.stack.unshift(this.pos);
break;
case "]":
var s = this.stack.shift();
if (s) this.pos = s - 1;
break;
case "\n":
break;
default:
throw new Error("Unkown character \""
+ this.source[this.pos]
+ "\" at " + (this.pos + 1));
}
this.elem[this.pos].addClass("em");
var m = this.memory.concat();
m.splice(this.pointer, 1,
"*" + (this.memory[this.pointer] || 0));
$("#status").text(m.join(", "));
$("#output").text(this.output.join(""));
this.pos++;
}
),
exception(
function(e){
alert("Error: " + e.message);}
),
function() {
this.jPause.attr("disabled", true);
this.jPause.text("Pause");
this.jStep.attr("disabled", true);
this.jRun.click(brf.run).text("Run");
this.jSource.show();
this.jSourceView.hide();
}
)
);
});
機能が増えてる割りにはJSDeferred版よりは見通しがいいかなと思うんだけど、どうかな。