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