概要
ilasmでstack machineやってみた。
練習問題やってみた。
実装編
練習問題
elixirでilasmをアセンブルしてROM化せよ。
サンプルコード
defmodule Va do
use Agent
def start_link() do
Agent.start_link(fn ->
0
end, name: __MODULE__)
end
def get() do
Agent.get(__MODULE__, fn v ->
v
end)
end
def set(x) do
Agent.update(__MODULE__, fn v ->
x
end)
end
end
defmodule Src do
use Agent
def start_link() do
Agent.start_link(fn ->
""
end, name: __MODULE__)
end
def set(x) do
Agent.update(__MODULE__, fn v ->
x
end)
end
def get() do
Agent.get(__MODULE__, fn v ->
v
end)
end
def getv(m) do
Agent.get(__MODULE__, fn v ->
Va.set(0)
Enum.reduce(String.split(v, "\n", trim: true), 1, fn l, n ->
if n < m + 1 do
if String.starts_with?(l, " ldstr") do
Va.set(Va.get + 6)
else
if String.ends_with?(l, ":") do
n = n
else
Va.set(Va.get + 1)
end
end
end
n = n + 1
end)
Va.get
end)
end
def getn(n) do
Agent.get(__MODULE__, fn v ->
Enum.at(String.split(v, "\n", trim: true), n - 1)
end)
end
def getl("end") do
0
end
def getl(a) do
Agent.get(__MODULE__, fn v ->
Enum.reduce(String.split(v, "\n", trim: true), 1, fn l, n ->
if String.starts_with?(l, a) do
Va.set(n)
end
if String.starts_with?(l, " ldstr") do
n = n + 6
else
if String.ends_with?(l, ":") do
n = n
else
n = n + 1
end
end
end)
Va.get - 1
end)
end
end
defmodule Main do
def val(nil) do
0
end
def val(s) do
if String.starts_with?(s, "'") do
String.at(s, 1)
|> String.to_charlist
|> List.first
else
String.to_integer(s)
end
end
def ldstr(n, s) do
IO.puts "rom[#{n}] <= 12'h2_01;"
n = n + 1
i = String.at(s, 1)
|> String.to_charlist
|> List.first
j = Integer.floor_div(i, 16)
i = rem(i, 16)
i = Integer.to_string(i, 16)
j = Integer.to_string(j, 16)
IO.puts "rom[#{n}] <= 12'h2_#{j}#{i};"
n = n + 1
i = String.at(s, 2)
|> String.to_charlist
|> List.first
j = Integer.floor_div(i, 16)
i = rem(i, 16)
i = Integer.to_string(i, 16)
j = Integer.to_string(j, 16)
IO.puts "rom[#{n}] <= 12'h2_#{j}#{i};"
n = n + 1
i = String.at(s, 3)
|> String.to_charlist
|> List.first
j = Integer.floor_div(i, 16)
i = rem(i, 16)
i = Integer.to_string(i, 16)
j = Integer.to_string(j, 16)
IO.puts "rom[#{n}] <= 12'h2_#{j}#{i};"
n = n + 1
i = String.at(s, 4)
|> String.to_charlist
|> List.first
j = Integer.floor_div(i, 16)
i = rem(i, 16)
i = Integer.to_string(i, 16)
j = Integer.to_string(j, 16)
IO.puts "rom[#{n}] <= 12'h2_#{j}#{i};"
n = n + 1
IO.puts "rom[#{n}] <= 12'h2_00;"
end
def add(n) do
IO.puts "rom[#{n}] <= 12'hf_02;"
end
def sub(n) do
IO.puts "rom[#{n}] <= 12'hf_03;"
end
def mul(n) do
IO.puts "rom[#{n}] <= 12'hf_04;"
end
def div(n) do
IO.puts "rom[#{n}] <= 12'hf_05;"
end
def rem(n) do
IO.puts "rom[#{n}] <= 12'hf_06;"
end
def ret(n) do
IO.puts "rom[#{n}] <= 12'h0_01;"
end
def out(n) do
IO.puts "rom[#{n}] <= 12'h4_00;"
end
def outs(n) do
IO.puts "rom[#{n}] <= 12'h5_00;"
end
def dup(n) do
IO.puts "rom[#{n}] <= 12'hf_00;"
end
def drop(n) do
IO.puts "rom[#{n}] <= 12'hf_01;"
end
def push(n, s) do
i = val(s)
j = Integer.floor_div(i, 16)
i = rem(i, 16)
i = Integer.to_string(i, 16)
j = Integer.to_string(j, 16)
IO.puts "rom[#{n}] <= 12'h1_#{j}#{i};"
end
def bgt(n, s) do
i = Src.getl(s)
j = Integer.floor_div(i, 16)
i = rem(i, 16)
i = Integer.to_string(i, 16)
j = Integer.to_string(j, 16)
IO.puts "rom[#{n}] <= 12'h7_#{j}#{i};"
end
def if_(n, s) do
i = Src.getl(s)
j = Integer.floor_div(i, 16)
i = rem(i, 16)
i = Integer.to_string(i, 16)
j = Integer.to_string(j, 16)
IO.puts "rom[#{n}] <= 12'ha_#{j}#{i};"
end
def jmp(n, s) do
i = Src.getl(s)
j = Integer.floor_div(i, 16)
i = rem(i, 16)
i = Integer.to_string(i, 16)
j = Integer.to_string(j, 16)
IO.puts "rom[#{n}] <= 12'h9_#{j}#{i};"
end
def set(n, s) do
cond do
s == "a" ->
IO.puts "rom[#{n}] <= 12'hf_09;"
s == "b" ->
IO.puts "rom[#{n}] <= 12'hf_0b;"
end
end
def get(n, s) do
cond do
s == "a" ->
IO.puts "rom[#{n}] <= 12'hf_0a;"
s == "b" ->
IO.puts "rom[#{n}] <= 12'hf_0c;"
end
end
def asm(str) do
Enum.reduce(String.split(str, "\n"), 0, fn st, n ->
IO.puts "//#{st}"
s = String.split(st, " ")
m = Src.getv(n)
cond do
Enum.at(s, 1) == "ldstr" ->
ldstr(m, Enum.at(s, 2))
Enum.at(s, 1) == "ldc.i4" ->
push(m, Enum.at(s, 2))
Enum.at(s, 1) == "add" ->
add(m)
Enum.at(s, 1) == "sub" ->
sub(m)
Enum.at(s, 1) == "mul" ->
mul(m)
Enum.at(s, 1) == "div" ->
div(m)
Enum.at(s, 1) == "rem" ->
rem(m)
Enum.at(s, 1) == "ret" ->
ret(m)
Enum.at(s, 1) == "call" && Enum.at(s, 2) == "void [mscorlib] System.Console::WriteLine(int32)" ->
out(m)
Enum.at(s, 1) == "call" && Enum.at(s, 2) == "void [mscorlib] System.Console::WriteLine(string)" ->
outs(m)
Enum.at(s, 1) == "dup" ->
dup(m)
Enum.at(s, 1) == "pop" ->
drop(m)
Enum.at(s, 1) == "bgt" ->
bgt(m, Enum.at(s, 2))
Enum.at(s, 1) == "br" ->
jmp(m, Enum.at(s, 2))
Enum.at(s, 1) == "brfalse" ->
if_(m, Enum.at(s, 2))
Enum.at(s, 1) == "stloc" ->
set(m, Enum.at(s, 2))
Enum.at(s, 1) == "ldloc" ->
get(m, Enum.at(s, 2))
true ->
IO.puts(Enum.at(s, 1))
end
n = n + 1
end)
end
def start(str) do
Src.set(str)
asm(str)
end
end
Va.start_link
Src.start_link
str = """
ldc.i4 100
stloc b
ldc.i4 1
stloc a
loop:
ldloc a
ldloc b
bgt bye
ldloc a
ldc.i4 15
rem
brfalse fb
ldloc a
ldc.i4 5
rem
brfalse bb
ldloc a
ldc.i4 3
rem
brfalse ff
ldloc a
call void [mscorlib] System.Console::WriteLine(int32)
br tugi
fb:
ldstr 'fibu'
br print
bb:
ldstr 'buzz'
br print
ff:
ldstr 'fizz'
print:
call void [mscorlib] System.Console::WriteLine(string)
tugi:
ldloc a
ldc.i4 1
add
stloc a
br loop
bye:
ret
"""
Main.start(str)
実行結果
// ldc.i4 100
rom[0] <= 12'h1_64;
// stloc b
rom[1] <= 12'hf_0b;
// ldc.i4 1
rom[2] <= 12'h1_01;
// stloc a
rom[3] <= 12'hf_09;
//loop:
// ldloc a
rom[4] <= 12'hf_0a;
// ldloc b
rom[5] <= 12'hf_0c;
// bgt bye
rom[6] <= 12'h7_30;
// ldloc a
rom[7] <= 12'hf_0a;
// ldc.i4 15
rom[8] <= 12'h1_0F;
// rem
rom[9] <= 12'hf_06;
// brfalse fb
rom[10] <= 12'ha_16;
// ldloc a
rom[11] <= 12'hf_0a;
// ldc.i4 5
rom[12] <= 12'h1_05;
// rem
rom[13] <= 12'hf_06;
// brfalse bb
rom[14] <= 12'ha_1D;
// ldloc a
rom[15] <= 12'hf_0a;
// ldc.i4 3
rom[16] <= 12'h1_03;
// rem
rom[17] <= 12'hf_06;
// brfalse ff
rom[18] <= 12'ha_24;
// ldloc a
rom[19] <= 12'hf_0a;
// call void [mscorlib] System.Console::WriteLine(int32)
rom[20] <= 12'h4_00;
// br tugi
rom[21] <= 12'h9_2B;
//fb:
// ldstr 'fibu'
rom[22] <= 12'h2_01;
rom[23] <= 12'h2_66;
rom[24] <= 12'h2_69;
rom[25] <= 12'h2_62;
rom[26] <= 12'h2_75;
rom[27] <= 12'h2_00;
// br print
rom[28] <= 12'h9_2A;
//bb:
// ldstr 'buzz'
rom[29] <= 12'h2_01;
rom[30] <= 12'h2_62;
rom[31] <= 12'h2_75;
rom[32] <= 12'h2_7A;
rom[33] <= 12'h2_7A;
rom[34] <= 12'h2_00;
// br print
rom[35] <= 12'h9_2A;
//ff:
// ldstr 'fizz'
rom[36] <= 12'h2_01;
rom[37] <= 12'h2_66;
rom[38] <= 12'h2_69;
rom[39] <= 12'h2_7A;
rom[40] <= 12'h2_7A;
rom[41] <= 12'h2_00;
//print:
// call void [mscorlib] System.Console::WriteLine(string)
rom[42] <= 12'h5_00;
//tugi:
// ldloc a
rom[43] <= 12'hf_0a;
// ldc.i4 1
rom[44] <= 12'h1_01;
// add
rom[45] <= 12'hf_02;
// stloc a
rom[46] <= 12'hf_09;
// br loop
rom[47] <= 12'h9_04;
//bye:
// ret
rom[48] <= 12'h0_01;
//
成果物
以上。