概要
ilasmでstack machineやってみた。
練習問題やってみた。
練習問題
日本語をilasmに変換するコンパイラを書け。
fizzbuzzをコンパイルせよ。
方針
- Plunker使う。
写真
投入したソース
数値 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:
終わり。
実行結果
.assembly extern mscorlib {}
.assembly fizzbuzz {}
.method static void main() {
.entrypoint
.locals init (int32 n, int32 i)
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
}
検証
>ilasm fizzbuzz2.il
Microsoft (R) .NET Framework IL Assembler. Version 4.8.9105.0
Copyright (c) Microsoft Corporation. All rights reserved.
Assembling 'fizzbuzz2.il' to EXE --> 'fizzbuzz2.exe'
Source file is ANSI
Assembled global method main
Creating PE file
Emitting classes:
Emitting fields and methods:
Global Methods: 1;
Emitting events and properties:
Global
Writing PE file
Operation completed successfully
>fizzbuzz2
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
サンプルコード
コンパイラ
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 i = 1;
var res = ".assembly extern mscorlib {}\n.assembly fizzbuzz {}\n.method static void main() {\n.entrypoint\n.locals init (int32 n, int32 i)\n";
while (i > 0)
{
var code = codes[pc].split(" ");
switch (code[1])
{
case "drop":
pc++;
break;
case "dup":
pc++;
break;
case "文字列":
res += " ldstr " + code[2] + "\n";
pc++;
break;
case "数値":
res += " ldc.i4 " + code[2] + "\n";
pc++;
break;
case "変数":
if (code[3] == "を積み")
res += " ldloc " + code[2] + "\n";
if (code[3] == "に移動し")
res += " stloc " + code[2] + "\n";
pc++;
break;
case "数値印字し":
res += " call void [mscorlib] System.Console::WriteLine(int32)\n";
pc++;
break;
case "文字印字し":
res += " call void [mscorlib] System.Console::WriteLine(string)\n";
pc++;
break;
case "真なら":
res += " brtrue "+ code[2] + "\n";
pc++;
break;
case "偽なら":
res += " brfalse "+ code[2] + "\n";
pc++;
break;
case "比べて大なら":
res += " bgt "+ code[2] + "\n";
pc++;
break;
case "足す":
res += " add\n";
pc++;
break;
case "mul":
res += " 掛ける\n";
pc++;
break;
case "sub":
res += " 引く\n";
pc++;
break;
case "div":
res += " 割る\n";
pc++;
break;
case "剰余し":
res += " rem\n";
pc++;
break;
case "無条件で":
res += " br "+ code[2] + "\n";
pc++;
break;
case "終わり。":
res += " ret\n}\n";
i = 0;
break;
case undefined:
res += code[0] + "\n";
pc++;
break;
default:
alert(code[1]);
pc++;
break;
}
}
out.value = res;
}
成果物
以上