概要
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
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 ->
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.run
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
""")
実行結果
01 02 03 04 05 06 07 08 09
02 04 06 08 10 12 14 16 18
03 06 09 12 15 18 21 24 27
04 08 12 16 20 24 28 32 36
05 10 15 20 25 30 35 40 45
06 12 18 24 30 36 42 48 54
07 14 21 28 35 42 49 56 63
08 16 24 32 40 48 56 64 72
09 18 27 36 45 54 63 72 81
成果物
以上。