概要
ilasmでstack machineやってみた。
練習問題やってみた。
練習問題
ilasmが動く、インタープリタを書け。
fizzbuzzを動作させよ。
方針
-
Plunker、使う。
-
命令セット
ニーモニック | 意味 | stackの状態 |
---|---|---|
nop | 何もしない。 | 変化無し |
ldc.i4 1 | stackに整数 1を積む。 | 1個増える |
ldstr "fizzbuzz" | stackに「fizzbuzz」を積む。 | 1個増える |
ldloc i | stackに変数iの値を積む。 | 1個増える |
stloc i | 変数iにstackを移動。 | 1個減る |
call void [mscorlib] System.Console::WriteLine(int32) | stackを数値印刷。 | 1個減る |
call void [mscorlib] System.Console::WriteLine(string) | stackを文字印刷。 | 1個減る |
callvirt instance int32 [mscorlib]System.Random::Next(int32) | 乱数を積む | 1個減る |
beq bye | セカンドとトップを比べて等しいならbyeに飛ぶ。 | 2個減る |
bgt bye | セカンドとトップを比べて小さいならbyeに飛ぶ。 | 2個減る |
blt bye | セカンドとトップを比べて大きいならbyeに飛ぶ。 | 2個減る |
br tugi | tugiへ飛ぶ。 | 変化無し |
brfalse fizzbuzz | ゼロで無いならfizzbuzzに飛ぶ。 | 1個減る |
brtrue fizzbuzz | ゼロならfizzbuzzに飛ぶ。 | 1個減る |
dup | stackにコピーを積む。 | 1個増える |
drop | stackを一個減らす。 | 1個減る |
add | セカンドとトップの加算を求める。 | 1個減る |
sub | セカンドとトップの減算を求める。 | 1個減る |
mul | セカンドとトップの乗算を求める。 | 1個減る |
div | セカンドとトップの除算を求める。 | 1個減る |
rem | セカンドとトップの剰余を求める。 | 1個減る |
サンプルコード
var out = document.getElementById("out");
var src = document.getElementById("src");
function run() {
var str = src.value;
str = str.replace(/\t/g, " ");
str = str.replace(/ /g, " ");
str = str.replace(/ /g, " ");
str = str.replace(/ /g, " ");
var codes = str.split("\n");
var pc = 0;
var sp = 0;
var len = codes.length;
var i;
var label = {};
var val = {};
var ram = [];
var res = "";
for (i = 0; i < len; i++)
{
if (codes[i].indexOf(":") > -1)
{
label[codes[i]] = i;
}
}
while (i > 0)
{
//alert(pc);
var code = codes[pc].split(" ");
switch (code[1])
{
case "drop":
sp--;
pc++;
break;
case "dup":
ram[sp] = ram[sp - 1];
sp++;
pc++;
break;
case "ldstr":
ram[sp] = code[2];
sp++;
pc++;
break;
case "ldc.i4":
ram[sp] = code[2];
sp++;
pc++;
break;
case "stloc":
sp--;
val[code[2]] = ram[sp];
pc++;
break;
case "ldloc":
ram[sp] = val[code[2]];
sp++;
pc++;
break;
case "call":
sp--;
res += ram[sp] + "\n";
pc++;
break;
case "brtrue":
sp--;
if (ram[sp] == 1)
{
pc = label[code[2] + ":"];
}
else
{
pc++;
}
break;
case "brfalse":
sp--;
if (ram[sp] == 0)
{
pc = label[code[2] + ":"];
}
else
{
pc++;
}
break;
case "bgt":
sp--;
if (parseInt(ram[sp - 1]) > parseInt(ram[sp]))
{
sp--;
pc = label[code[2] + ":"];
}
else
{
sp--;
pc++;
}
break;
case "add":
sp--;
ram[sp - 1] = parseInt(ram[sp - 1]) + parseInt(ram[sp]);
pc++;
break;
case "mul":
sp--;
ram[sp - 1] = parseInt(ram[sp - 1]) * parseInt(ram[sp]);
pc++;
break;
case "sub":
sp--;
ram[sp - 1] = parseInt(ram[sp - 1]) - parseInt(ram[sp]);
pc++;
break;
case "div":
sp--;
ram[sp - 1] = parseInt(ram[sp - 1]) / parseInt(ram[sp]);
pc++;
break;
case "rem":
sp--;
ram[sp - 1] = parseInt(ram[sp - 1]) % parseInt(ram[sp]);
pc++;
break;
case "br":
pc = label[code[2] + ":"];
break;
case "ret":
i = 0;
break;
case undefined:
pc++;
break;
default:
alert(code[1]);
pc++;
break;
}
}
//alert("ok");
out.value = res;
}
投入したソース
fizzbuzz
ldc.i4 100
stloc n
ldc.i4 1
stloc i
loop:
ldloc i
ldloc n
bgt bye
ldloc i
ldc.i4 15
rem
brfalse fb
ldloc i
ldc.i4 5
rem
brfalse b
ldloc i
ldc.i4 3
rem
brfalse f
ldloc i
call void [mscorlib] System.Console::WriteLine(int32)
br tugi
fb:
ldstr "fizzbuzz"
br print
b:
ldstr "buzz"
br print
f:
ldstr "fizz"
print:
call void [mscorlib] System.Console::WriteLine(string)
tugi:
ldloc i
ldc.i4 1
add
stloc i
br loop
bye:
ret
実行結果
1
2
"fizz"
4
"buzz"
"fizz"
7
8
"fizz"
"buzz"
11
"fizz"
13
14
"fizzbuzz"
16
17
"fizz"
19
"buzz"
"fizz"
22
23
"fizz"
"buzz"
26
"fizz"
28
29
"fizzbuzz"
31
32
"fizz"
34
"buzz"
"fizz"
37
38
"fizz"
"buzz"
41
"fizz"
43
44
"fizzbuzz"
46
47
"fizz"
49
"buzz"
"fizz"
52
53
"fizz"
"buzz"
56
"fizz"
58
59
"fizzbuzz"
61
62
"fizz"
64
"buzz"
"fizz"
67
68
"fizz"
"buzz"
71
"fizz"
73
74
"fizzbuzz"
76
77
"fizz"
79
"buzz"
"fizz"
82
83
"fizz"
"buzz"
86
"fizz"
88
89
"fizzbuzz"
91
92
"fizz"
94
"buzz"
"fizz"
97
98
"fizz"
"buzz"
成果物
以上