ilasmでstack machine その59

# 概要
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;
//

```

# 成果物

https://paiza.io/projects/g86QquMvLfojgHPeZTAakA


以上。