paiza.ioでelixir その147

# 概要
paiza.ioでelixirやってみた。
練習問題やってみた。

# 練習問題
俺cpuのアセンブラから、x64アセンブラを生成せよ。

# サンプルコード

```
defmodule Top 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() do
		Agent.update(__MODULE__, fn v ->
	        0
		end)
	end
	def push() do
		Agent.update(__MODULE__, fn v ->
	        v + 1
		end)
	end
	def pop() do
		Agent.update(__MODULE__, fn v ->
	        v - 1
		end)
	end
end
defmodule Asm do
	def start_link do
		Agent.start_link(fn ->
			%{u: ""}
		end, name: __MODULE__)
	end
	def push(a) do
		Agent.update(__MODULE__, fn v ->
		    cond do
            Top.get == 0 ->
			    str = "    mov 	$#{a}, %r11\n"
			    %{v | u: v.u <> str}
            Top.get == 1 ->
			    str = "    mov 	$#{a}, %r12\n"
			    %{v | u: v.u <> str}
		    true ->
			    str = "    push?\n"
			    %{v | u: v.u <> str}
            end
		end)
		Top.push
	end
	def set(a) do
		Agent.update(__MODULE__, fn v ->
            cond do
            Top.get == 0 && a == "a" ->
			    str = "    mov 	%r12, %r13\n"
			    %{v | u: v.u <> str}
            Top.get == 0 && a == "b" ->
			    str = "    mov 	%r12, %r14\n"
			    %{v | u: v.u <> str}
            Top.get == 0 && a == "c" ->
			    str = "    mov 	%r12, %r15\n"
			    %{v | u: v.u <> str}
            Top.get == 1 && a == "a" ->
			    str = "    mov 	%r11, %r13\n"
			    %{v | u: v.u <> str}
            Top.get == 1 && a == "b" ->
			    str = "    mov 	%r11, %r14\n"
			    %{v | u: v.u <> str}
            Top.get == 1 && a == "c" ->
			    str = "    mov 	%r11, %r15\n"
			    %{v | u: v.u <> str}
			true ->
			    str = "    set?\n"
			    %{v | u: v.u <> str}
			end
		end)
		Top.pop
	end
	def get(a) do
		Agent.update(__MODULE__, fn v ->
            cond do
            Top.get == 0 && a == "a" ->
			    str = "    mov 	%r13, %r11\n"
			    %{v | u: v.u <> str}
            Top.get == 0 && a == "b" ->
			    str = "    mov 	%r14, %r11\n"
			    %{v | u: v.u <> str}
            Top.get == 0 && a == "c" ->
			    str = "    mov 	%r15, %r11\n"
			    %{v | u: v.u <> str}
            Top.get == 1 && a == "a" ->
			    str = "    mov 	%r13, %r12\n"
			    %{v | u: v.u <> str}
            Top.get == 1 && a == "b" ->
			    str = "    mov 	%r14, %r12\n"
			    %{v | u: v.u <> str}
            Top.get == 1 && a == "c" ->
			    str = "    mov 	%r15, %r12\n"
			    %{v | u: v.u <> str}
			true ->
			    str = "    get?\n"
			    %{v | u: v.u <> str}
			end
		end)
		Top.push
	end
	def jz(a) do
		Agent.update(__MODULE__, fn v ->
			str = "    jl   " <> a <>"\n"
			%{v | u: v.u <> str}
		end)
		Top.pop
	end
	def label(a) do
		Agent.update(__MODULE__, fn v ->
			str = a <> "\n"
			%{v | u: v.u <> str}
		end)
	end
	def out() do
		Agent.update(__MODULE__, fn v ->
			str = "    lea	 	msg(%rip), %rdi\n    mov   	%r11, %rax;\n    mov	        %rax, (%rdi)\n    mov   	$1, %rax;\n    mov   	$1, %rdi;\n    mov   	$msg, %rsi;\n    mov   	$1, %rdx;\n    syscall;\n"
			%{v | u: v.u <> str}
		end)
		Top.pop
	end
	def add() do
		Agent.update(__MODULE__, fn v ->
			str = "    mov		%r11, %rax\n    add		%r12, %rax\n    mov		%rax, %r11\n"
			%{v | u: v.u <> str}
		end)
		Top.pop
	end
	def sub() do
		Agent.update(__MODULE__, fn v ->
			str = "    mov		%r11, %rax\n    sub		%r12, %rax\n    mov		%rax, %r11\n"
			%{v | u: v.u <> str}
		end)
		Top.pop
	end
	def mul() do
		Agent.update(__MODULE__, fn v ->
			str = "    mov		%r11, %rax\n    mul		%r12\n    mov		%rax, %r11\n"
			%{v | u: v.u <> str}
		end)
		Top.pop
	end
	def div() do
		Agent.update(__MODULE__, fn v ->
			str = "    mov		%r11, %rax\n	mov	 	$0, %rdx\n    div		%r12\n    mov		%rax, %r11\n"
			%{v | u: v.u <> str}
		end)
		Top.pop
	end
	def rem() do
		Agent.update(__MODULE__, fn v ->
			str = "    mov		%r11, %rax\n	mov	 	$0, %rdx\n    div		%r12\n    mov		%rdx, %r11\n"
			%{v | u: v.u <> str}
		end)
		Top.pop
	end
	def gt() do
		Agent.update(__MODULE__, fn v ->
			str = "    mov		%r11, %rax\n    cmp		%r12, %rax\n    mov		%rax, %r11\n"
			%{v | u: v.u <> str}
		end)
		Top.pop
	end
	def echo() do
		Agent.get(__MODULE__, fn v ->
			IO.puts ".code64\n.text\n.globl main\nmain:\n" <>
			v.u <> "bye:\n    mov   	$60, %rax;\n    mov 	$0, %rdi\n    syscall;\n.data\nmsg:\n	.asciz \"Hello world!\"\n"
		end)
	end
end

defmodule Main do
	def run(str) do
		Enum.map(String.split(str, "\n"), fn l ->
			s = String.split(l, "  ")
			cond do
			Enum.at(s, 1) == "push" ->
				Asm.push(Enum.at(s, 2))
			Enum.at(s, 1) == "set" ->
				Asm.set(Enum.at(s, 2))
			Enum.at(s, 1) == "get" ->
				Asm.get(Enum.at(s, 2))
			Enum.at(s, 1) == "jz" ->
				Asm.jz(Enum.at(s, 2))
			Enum.at(s, 0) != "" ->
				Asm.label(Enum.at(s, 0))
			Enum.at(s, 1) == "out" ->
				Asm.out()
			Enum.at(s, 1) == "+" ->
				Asm.add()
			Enum.at(s, 1) == "-" ->
				Asm.sub()
			Enum.at(s, 1) == "*" ->
				Asm.mul()
			Enum.at(s, 1) == "/" ->
				Asm.div()
			Enum.at(s, 1) == "%" ->
				Asm.rem()
			Enum.at(s, 1) == "<" ->
				Asm.gt()
			true ->
				IO.puts Enum.at(s, 1)
			end
		end)
		Asm.echo
	end
end

Top.start_link
Asm.start_link

Main.run("""
  push  1
  set  a
  push  1
  set  b
label30:
  get  a
  get  b
  *  
  set  c
  get  c
  push  10
  /  
  push  48
  +  
  out
label31:
  get  c
  push  10
  %  
  push  48
  +  
  out
label32:
  push  32
  out  	
label33:
  get  a
  push  1
  +  
  set  a
  get  a
  push  10
  <  
  jz  label30
  push  10
  out  
label34:
  get  b
  push  1
  +  
  set  b
  push  1
  set  a
  get  b
  push  10
  <  
  jz  label30
""")


```

# 実行結果

```

.code64
.text
.globl main
main:
    mov 	$1, %r11
    mov 	%r11, %r13
    mov 	$1, %r11
    mov 	%r11, %r14
label30:
    mov 	%r13, %r11
    mov 	%r14, %r12
    mov		%r11, %rax
    mul		%r12
    mov		%rax, %r11
    mov 	%r11, %r15
    mov 	%r15, %r11
    mov 	$10, %r12
    mov		%r11, %rax
	mov	 	$0, %rdx
    div		%r12
    mov		%rax, %r11
    mov 	$48, %r12
    mov		%r11, %rax
    add		%r12, %rax
    mov		%rax, %r11
    lea	 	msg(%rip), %rdi
    mov   	%r11, %rax;
    mov	        %rax, (%rdi)
    mov   	$1, %rax;
    mov   	$1, %rdi;
    mov   	$msg, %rsi;
    mov   	$1, %rdx;
    syscall;
label31:
    mov 	%r15, %r11
    mov 	$10, %r12
    mov		%r11, %rax
	mov	 	$0, %rdx
    div		%r12
    mov		%rdx, %r11
    mov 	$48, %r12
    mov		%r11, %rax
    add		%r12, %rax
    mov		%rax, %r11
    lea	 	msg(%rip), %rdi
    mov   	%r11, %rax;
    mov	        %rax, (%rdi)
    mov   	$1, %rax;
    mov   	$1, %rdi;
    mov   	$msg, %rsi;
    mov   	$1, %rdx;
    syscall;
label32:
    mov 	$32, %r11
    lea	 	msg(%rip), %rdi
    mov   	%r11, %rax;
    mov	        %rax, (%rdi)
    mov   	$1, %rax;
    mov   	$1, %rdi;
    mov   	$msg, %rsi;
    mov   	$1, %rdx;
    syscall;
label33:
    mov 	%r13, %r11
    mov 	$1, %r12
    mov		%r11, %rax
    add		%r12, %rax
    mov		%rax, %r11
    mov 	%r11, %r13
    mov 	%r13, %r11
    mov 	$10, %r12
    mov		%r11, %rax
    cmp		%r12, %rax
    mov		%rax, %r11
    jl   label30
    mov 	$10, %r11
    lea	 	msg(%rip), %rdi
    mov   	%r11, %rax;
    mov	        %rax, (%rdi)
    mov   	$1, %rax;
    mov   	$1, %rdi;
    mov   	$msg, %rsi;
    mov   	$1, %rdx;
    syscall;
label34:
    mov 	%r14, %r11
    mov 	$1, %r12
    mov		%r11, %rax
    add		%r12, %rax
    mov		%rax, %r11
    mov 	%r11, %r14
    mov 	$1, %r11
    mov 	%r11, %r13
    mov 	%r14, %r11
    mov 	$10, %r12
    mov		%r11, %rax
    cmp		%r12, %rax
    mov		%rax, %r11
    jl   label30
bye:
    mov   	$60, %rax;
    mov 	$0, %rdi
    syscall;
.data
msg:
	.asciz "Hello world!"

```

# 成果物

https://paiza.io/projects/Ix3v_kR6EAbK_4acO1ED_Q?language=elixir

以上。