概要
paiza.ioでelixirやってみた。
練習問題やってみた。
練習問題
俺cpuのアセンブラを実行するインタープリタを書け。
サンプルコード
defmodule Va 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(x) do
Agent.update(__MODULE__, fn v ->
x
end)
end
end
defmodule Src do
use Agent
def start_link() do
Agent.start_link(fn ->
""
end, name: __MODULE__)
end
def set(x) do
Agent.update(__MODULE__, fn v ->
x
end)
end
def get() do
Agent.get(__MODULE__, fn v ->
v
end)
end
def getn(n) do
Agent.get(__MODULE__, fn v ->
Enum.at(String.split(v, "\n", trim: true), n - 1)
end)
end
def getl("end") do
0
end
def getl(a) do
Agent.get(__MODULE__, fn v ->
Enum.reduce(String.split(v, "\n", trim: true), 1, fn l, n ->
if String.starts_with?(l, a) do
#IO.puts "okok"
#IO.puts n
Va.set(n)
end
n = n + 1
end)
Va.get
end)
end
end
defmodule Sim do
def val(s) do
if String.starts_with?(s, "'") do
String.at(s, 1)
|> String.to_charlist
|> List.first
else
String.to_integer(s)
end
end
def start_link do
Agent.start_link(fn ->
[a: 0, b: 0, c: 0, pc: 1, stack: [], g: ""]
end, name: __MODULE__)
end
def push(s) do
Agent.update(__MODULE__, fn v ->
n = val(s)
#IO.puts n
stack = v[:stack]
stack = Enum.concat(stack, [n])
v = List.keyreplace(v, :stack, 0, {:stack, stack})
pc = v[:pc] + 1
List.keyreplace(v, :pc, 0, {:pc, pc})
end)
end
def set(d) do
Agent.update(__MODULE__, fn v ->
stack = v[:stack]
po = Enum.count(stack) - 1
top = Enum.at(stack, po)
stack = Enum.drop(stack, -1)
v = List.keyreplace(v, :stack, 0, {:stack, stack})
v = List.keyreplace(v, :a, 0, {:a, top})
pc = v[:pc] + 1
List.keyreplace(v, :pc, 0, {:pc, pc})
end)
end
def get(d) do
Agent.update(__MODULE__, fn v ->
a = v[:a]
stack = v[:stack]
stack = Enum.concat(stack, [a])
v = List.keyreplace(v, :stack, 0, {:stack, stack})
pc = v[:pc] + 1
List.keyreplace(v, :pc, 0, {:pc, pc})
end)
end
def gt() do
Agent.update(__MODULE__, fn v ->
stack = v[:stack]
po = Enum.count(stack) - 1
top = Enum.at(stack, po)
tmp = Enum.with_index(stack)
po = po - 1
stack = Enum.map(tmp, fn {val, ind} ->
cond do
ind == po ->
val > top
true ->
val
end
end)
stack = Enum.drop(stack, -1)
v = List.keyreplace(v, :stack, 0, {:stack, stack})
pc = v[:pc] + 1
List.keyreplace(v, :pc, 0, {:pc, pc})
end)
end
def if_(t) do
Agent.update(__MODULE__, fn v ->
stack = v[:stack]
po = Enum.count(stack) - 1
top = Enum.at(stack, po)
stack = Enum.drop(stack, -1)
v = List.keyreplace(v, :stack, 0, {:stack, stack})
if top do
pc = Src.getl(t)
List.keyreplace(v, :pc, 0, {:pc, pc})
else
pc = v[:pc] + 1
List.keyreplace(v, :pc, 0, {:pc, pc})
end
end)
end
def jmp(t) do
Agent.update(__MODULE__, fn v ->
pc = Src.getl(t)
List.keyreplace(v, :pc, 0, {:pc, pc})
end)
end
def out1() do
Agent.update(__MODULE__, fn v ->
stack = v[:stack]
g = v[:g]
po = Enum.count(stack) - 1
top = Enum.at(stack, po)
g = g <> to_string(top) <> " "
v = List.keyreplace(v, :g, 0, {:g, g})
pc = v[:pc] + 1
List.keyreplace(v, :pc, 0, {:pc, pc})
end)
end
def drop() do
Agent.update(__MODULE__, fn v ->
stack = v[:stack]
stack = Enum.drop(stack, -1)
v = List.keyreplace(v, :stack, 0, {:stack, stack})
pc = v[:pc] + 1
List.keyreplace(v, :pc, 0, {:pc, pc})
end)
end
def add() do
Agent.update(__MODULE__, fn v ->
stack = v[:stack]
po = Enum.count(stack) - 1
top = Enum.at(stack, po)
tmp = Enum.with_index(stack)
po = po - 1
stack = Enum.map(tmp, fn {val, ind} ->
cond do
ind == po ->
val + top
true ->
val
end
end)
stack = Enum.drop(stack, -1)
v = List.keyreplace(v, :stack, 0, {:stack, stack})
pc = v[:pc] + 1
List.keyreplace(v, :pc, 0, {:pc, pc})
end)
end
def print() do
Agent.get(__MODULE__, fn v ->
g = v[:g]
IO.puts g
end)
end
def pc() do
Agent.get(__MODULE__, fn v ->
v[:pc]
end)
end
def test() do
Agent.get(__MODULE__, fn v ->
v
end)
end
end
defmodule Main do
def run(0) do
Sim.print()
end
def run(pc) do
m = Src.getn(pc)
#IO.puts(m)
s = String.split(m, " ")
cond do
Enum.at(s, 1) == "set" ->
Sim.set(Enum.at(s, 2))
Enum.at(s, 1) == "get" ->
Sim.get(Enum.at(s, 2))
Enum.at(s, 1) == ">" ->
Sim.gt()
Enum.at(s, 1) == "if" ->
Sim.if_(Enum.at(s, 2))
Enum.at(s, 1) == "drop" ->
Sim.drop()
Enum.at(s, 1) == "out" ->
Sim.out1()
Enum.at(s, 1) == "+" ->
Sim.add()
Enum.at(s, 1) == "jmp" ->
Sim.jmp(Enum.at(s, 2))
true ->
Sim.push(Enum.at(s, 1))
end
#IO.inspect Sim.test
run(Sim.pc)
end
def start(str) do
Src.set(str)
run(1)
end
end
Va.start_link
Sim.start_link
Src.start_link
"""
1
set a
loop get a
100
>
if end
get a
out
get a
1
+
set a
jmp loop
"""
|> Main.start()
実行結果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
成果物
以上。