paiza.ioでelixir その149

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

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

# サンプルコード

```
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    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
label20:
  get  a
  push  1
  +
  set  a
  get  a
  push  100
  <
  jg  label255
  get  a
  push  15
  %
  set  b
  get  b
  push  0
  =
  je  label120
  get  a
  push  5
  %
  set  b
  get  b
  push  0
  =
  je  label140
  get  a
  push  3
  %
  set  b
  get  b
  push  0
  =
  je  label160
  get  a
  push  10
  /
  push  48
  +
  out
  get  a
  push  10
  %
  push  48
  +
  out
  push  32
  out
  jmp  label20
label120:
  push  102
  out
  push  105
  out
  push  122
  out
  push  122
  out
  push  98
  out
  push  117
  out
  push  122
  out
  push  122
  out
  push  32
  out
  jmp  label20
label140:
  push  98
  out
  push  117
  out
  push  122
  out
  push  122
  out
  push  32
  out
  jmp  label20
label160:
  push  102
  out
  push  105
  out
  push  122
  out
  push  122
  out
  push  32
  out
  jmp  label20
label255:
""")


```

# 実行結果

```

01 02 fizz 04 buzz fizz 07 08 fizz buzz 11 fizz 13 14 fizzbuzz 16 17 fizz 19 buzz fizz 22 23 fizz buzz 26 fizz 28 29 fizzbuzz 31 32 fizz 34 buzz fizz 37 38 fizz buzz 41 fizz 43 44 fizzbuzz 46 47 fizz 49 buzz fizz 52 53 fizz buzz 56 fizz 58 59 fizzbuzz 61 62 fizz 64 buzz fizz 67 68 fizz buzz 71 fizz 73 74 fizzbuzz 76 77 fizz 79 buzz fizz 82 83 fizz buzz 86 fizz 88 89 fizzbuzz 91 92 fizz 94 buzz fizz 97 98 fizz buzz 
```

# 成果物

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


以上。