概要
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!"
成果物
以上。