paiza.ioでelixir その150

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

# 練習問題
俺cpuのアセンブラから、x64アセンブラを生成し、コンパイル、実行せよ。
zundokoを実行せよ。

# サンプルコード

```
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 ->
			#IO.puts 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 jg(a) do
		Agent.update(__MODULE__, fn v ->
			str = "    jg          " <> a <>"\n"
			%{v | u: v.u <> str}
		end)
		Top.pop
	end
	def jl(a) do
		Agent.update(__MODULE__, fn v ->
			str = "    jl          " <> a <>"\n"
			%{v | u: v.u <> str}
		end)
		Top.pop
	end
	def je(a) do
		Agent.update(__MODULE__, fn v ->
			str = "    je          " <> a <>"\n"
			%{v | u: v.u <> str}
		end)
		Top.pop
	end
	def jmp(a) do
		Agent.update(__MODULE__, fn v ->
			str = "    jmp         " <> 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    and   $255, %rax\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 eq() 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
	def run() do
		Agent.get(__MODULE__, fn v ->
			File.write "hello.s", ".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"
            {result, 0} = System.shell("gcc -no-pie hello.s")
            IO.puts result
            {result, 0} = System.shell("./a.out")
            IO.puts result
		end)
	end
end

defmodule Main do
	def run(str) do
		Enum.map(String.split(str, "\n"), fn l ->
			#IO.puts l
			#IO.puts Top.get
			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) == "jg" ->
				Asm.jg(Enum.at(s, 2))
			Enum.at(s, 1) == "jl" ->
				Asm.jl(Enum.at(s, 2))
			Enum.at(s, 1) == "je" ->
				Asm.je(Enum.at(s, 2))
			Enum.at(s, 1) == "jmp" ->
				Asm.jmp(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()
			Enum.at(s, 1) == "=" ->
				Asm.eq()
			true ->
				IO.puts Enum.at(s, 1)
			end
		end)
		Asm.run
	end
end

Top.start_link
Asm.start_link

Main.run("""
  push  0
  set  a
  push  234
  set  b
label30:
  get  b
  push  5
  *
  set  b
  get  b
  push  1
  +
  set  b
  get  b
  push  120
  <
  jl  label100
  push  122
  out
  push  117
  out
  push  110
  out
  push  32
  out
  get  a
  push  1
  +
  set  a
  get  a
  push  3
  <
  jg  label130
  jmp  label30
label100:
  push  100
  out
  push  111
  out
  push  107
  out
  push  111
  out
  push  32
  out
  push  0
  set  a
  jmp  label30
label130:
  push  100
  out
  push  111
  out
  push  107
  out
  push  111
  out
  push  32
  out
  push  107
  out
  push  105
  out
  push  121
  out
  push  111
  out
  push  115
  out
  push  115
  out
  push  33
  out
  push  32
  out
label255:
""")



```

# 実行結果

```


zun zun doko zun zun zun doko doko zun doko zun zun doko doko doko doko zun zun doko doko zun doko doko zun zun doko doko doko doko doko zun zun zun zun doko kiyoss! 
```

# 成果物


https://paiza.io/projects/-eclLvFXRRnqROK02Nn1Ug?language=elixir


以上。