概要
ilasmでstack machineやってみた。
練習問題やってみた。
練習問題
日本語をilasmに変換するコンパイラを書け。
湯婆婆をコンパイルせよ。
方針
Plunker使う。
写真
投入したソース
文字列 "契約書\r\n" を積み
文字列印字し
文字列 "甲は油屋当主として、乙を油屋に雇用することを契約し、\r\n" を積み
文字列印字し
文字列 "労働に伴う対価の支払いを右の通り、約定する。\r\n" を積み
文字列印字し
文字列 "なお、一日の労働の対価は金百円とする。\r\n" を積み
文字列印字し
文字列 "甲 油屋当主 湯婆婆\r\n" を積み
文字列印字し
文字列 "乙\r\n" を積み
文字列印字し
文字列 "契約書だよ。そこに名前を書きな。" を積み
文字列印字し
入力し
コピペし
コピペし
変数 str に移動し
文字列 "フン。" を積み
文字印字し
文字印字し
文字列 "というのかい。贅沢な名だねぇ。" を積み
文字列印字し
乱数召喚し
数値 2 を積み
乱数し
変数 str を積み
長さし
剰余し
数値 1 を積み
切り出し
コピペし
コピペし
文字列 "今からお前の名前は" を積み
文字印字し
文字印字し
文字列 "だ。いいかい、" を積み
文字印字し
文字印字し
文字列 "だよ。分かったら返事をするんだ、" を積み
文字印字し
文字印字し
文字列 "!!" を積み
文字列印字し
終わり。
実行結果
.assembly extern mscorlib {}
.assembly yuba {}
.method static void main() {
.maxstack 16
.entrypoint
.locals init (class [mscorlib]System.Random r, string str)
ldstr "契約書\r\n"
call void [mscorlib] System.Console::WriteLine(string)
ldstr "甲は油屋当主として、乙を油屋に雇用することを契約し、\r\n"
call void [mscorlib] System.Console::WriteLine(string)
ldstr "労働に伴う対価の支払いを右の通り、約定する。\r\n"
call void [mscorlib] System.Console::WriteLine(string)
ldstr "なお、一日の労働の対価は金百円とする。\r\n"
call void [mscorlib] System.Console::WriteLine(string)
ldstr "甲 油屋当主 湯婆婆\r\n"
call void [mscorlib] System.Console::WriteLine(string)
ldstr "乙\r\n"
call void [mscorlib] System.Console::WriteLine(string)
ldstr "契約書だよ。そこに名前を書きな。"
call void [mscorlib] System.Console::WriteLine(string)
call string [mscorlib]System.Console::ReadLine()
dup
dup
stloc str
ldstr "フン。"
call void [mscorlib] System.Console::Write(string)
call void [mscorlib] System.Console::Write(string)
ldstr "というのかい。贅沢な名だねぇ。"
call void [mscorlib] System.Console::WriteLine(string)
newobj instance void [mscorlib]System.Random::.ctor()
ldc.i4 2
callvirt instance int32 [mscorlib]System.Random::Next(int32)
ldloc str
callvirt instance int32 [mscorlib]System.String::get_Length()
rem
ldc.i4 1
callvirt instance string [mscorlib]System.String::Substring(int32, int32)
dup
dup
ldstr "今からお前の名前は"
call void [mscorlib] System.Console::Write(string)
call void [mscorlib] System.Console::Write(string)
ldstr "だ。いいかい、"
call void [mscorlib] System.Console::Write(string)
call void [mscorlib] System.Console::Write(string)
ldstr "だよ。分かったら返事をするんだ、"
call void [mscorlib] System.Console::Write(string)
call void [mscorlib] System.Console::Write(string)
ldstr "!!"
call void [mscorlib] System.Console::WriteLine(string)
ret
}
検証
>ilasm yuba2.il
Microsoft (R) .NET Framework IL Assembler. Version 4.8.9105.0
Copyright (c) Microsoft Corporation. All rights reserved.
Assembling 'yuba2.il' to EXE --> 'yuba2.exe'
Source file is UTF-8
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
>yuba2
契約書
甲は油屋当主として、乙を油屋に雇用することを契約し、
労働に伴う対価の支払いを右の通り、約定する。
なお、一日の労働の対価は金百円とする。
甲 油屋当主 湯婆婆
乙
契約書だよ。そこに名前を書きな。
腹美恵子
フン。腹美恵子というのかい。贅沢な名だねぇ。
今からお前の名前は美だ。いいかい、美だよ。分かったら返事をするんだ、美!!
サンプルコード
コンパイラ
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 yuba {}\n.method static void main() {\n.maxstack 16\n.entrypoint\n.locals init (class [mscorlib]System.Random r, string str)\n";
while (i > 0)
{
var code = codes[pc].split(" ");
switch (code[1])
{
case "入力し":
res += " call string [mscorlib]System.Console::ReadLine()\n";
pc++;
break;
case "コピペし":
res += " dup\n";
pc++;
break;
case "乱数召喚し":
res += " newobj instance void [mscorlib]System.Random::.ctor()\n";
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::Write(string)\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 += " callvirt instance int32 [mscorlib]System.Random::Next(int32)\n";
pc++;
break;
case "長さし":
res += " callvirt instance int32 [mscorlib]System.String::get_Length()\n";
pc++;
break;
case "切り出し":
res += " callvirt instance string [mscorlib]System.String::Substring(int32, int32)\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;
}
成果物
以上