概要
ilasmでstack machineやってみた。
練習問題やってみた。
練習問題
ilasmを日本語に変換するコンパイラを書け。
fizzbuzzをコンパイルせよ。
方針
- Plunkerを使う。
- 仕様
ニーモニック | 日本語 |
---|---|
ldstr "fizz" | 文字列 "fizz" を積み |
ldc.i4 100 | 数値 100 を積み |
stloc i | 変数 i に移動し |
ldloc i | 変数 i を積み |
call System.Console::WriteLine(int32) | 数値印字し |
call System.Console::WriteLine(string) | 文字印字し |
brtrue tugi | 真なら tugi へ飛ぶ |
brfalse tugi | 偽なら tugi へ飛ぶ |
bgt tugi | 比べて大なら tugi へ飛ぶ |
add | 足す |
mul | 掛ける |
sub | 引く |
div | 割る |
rem | 剰余し |
br loop | 無条件で loop へ飛ぶ |
ret | 終わり。 |
写真
投入したソース
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
実行結果
数値 100 を積み
変数 n に移動し
数値 1 を積み
変数 i に移動し
loop:
変数 i を積み
変数 n を積み
比べて大なら bye へ飛ぶ
変数 i を積み
数値 15 を積み
剰余し
偽なら fb へ飛ぶ
変数 i を積み
数値 5 を積み
剰余し
偽なら b へ飛ぶ
変数 i を積み
数値 3 を積み
剰余し
偽なら f へ飛ぶ
変数 i を積み
数値印字し
無条件で tugi へ飛ぶ
fb:
文字列 "fizzbuzz" を積み
無条件で print へ飛ぶ
b:
文字列 "buzz" を積み
無条件で print へ飛ぶ
f:
文字列 "fizz" を積み
print:
文字印字し
tugi:
変数 i を積み
数値 1 を積み
足す
変数 i に移動し
無条件で loop へ飛ぶ
bye:
終わり。
サンプルコード
コンパイラ
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)
{
var code = codes[pc].split(" ");
switch (code[1])
{
case "drop":
pc++;
break;
case "dup":
pc++;
break;
case "ldstr":
res += " 文字列 " + code[2] + " を積み\n";
pc++;
break;
case "ldc.i4":
res += " 数値 " + code[2] + " を積み\n";
pc++;
break;
case "stloc":
res += " 変数 "+ code[2] + " に移動し\n";
pc++;
break;
case "ldloc":
res += " 変数 "+ code[2] + " を積み\n";
pc++;
break;
case "call":
if (code[4] == "System.Console::WriteLine(int32)")
res += " 数値印字し\n";
if (code[4] == "System.Console::WriteLine(string)")
res += " 文字印字し\n";
pc++;
break;
case "brtrue":
res += " 真なら "+ code[2] + " へ飛ぶ\n";
pc++;
break;
case "brfalse":
res += " 偽なら "+ code[2] + " へ飛ぶ\n";
pc++;
break;
case "bgt":
res += " 比べて大なら "+ code[2] + " へ飛ぶ\n";
pc++;
break;
case "add":
res += " 足す\n";
pc++;
break;
case "mul":
res += " 掛ける\n";
pc++;
break;
case "sub":
res += " 引く\n";
pc++;
break;
case "div":
res += " 割る\n";
pc++;
break;
case "rem":
res += " 剰余し\n";
pc++;
break;
case "br":
res += " 無条件で "+ code[2] + " へ飛ぶ\n";
pc++;
break;
case "ret":
res += " 終わり。\n";
i = 0;
break;
case undefined:
res += code[0] + "\n";
pc++;
break;
default:
alert(code[1]);
pc++;
break;
}
}
out.value = res;
}
成果物
以上