-
Notifications
You must be signed in to change notification settings - Fork 0
/
sol08a.erl
executable file
·69 lines (57 loc) · 1.62 KB
/
sol08a.erl
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
#!/usr/bin/escript
-record(i, {op :: atom(),
param :: integer(),
anno :: map()
}).
-record(state, {acc :: integer(),
pc :: integer()
}).
main([]) ->
main(["sol08.data"]);
main([Filename]) ->
{ok, File} = file:open(Filename, [read, binary]),
Code = compile(File),
file:close(File),
State = #state{acc=0, pc=0},
NewState = exec(Code, State),
io:format("~p~n", [NewState#state.acc]).
compile(File) ->
compile(File, 0, #{}).
compile(File, LineNo, Ins) ->
case file:read_line(File) of
eof ->
Ins;
{ok, Line} ->
NewIns = Ins#{LineNo => compile_line(string:chomp(Line))},
compile(File, LineNo+1, NewIns)
end.
compile_line(<<Ins:3/binary, " ", Sgn:1/binary, Value/binary>>) ->
#i{op=map_instruction(Ins), param=map_param(Sgn, Value), anno=#{reps=>0}}.
map_instruction(Ins) ->
binary_to_atom(Ins).
map_param(<<"-">>, Value) ->
-binary_to_integer(Value);
map_param(<<"+">>, Value) ->
binary_to_integer(Value).
exec(Code, #state{pc=PC} = State) ->
Instr = maps:get(PC, Code, #i{anno=#{halt => 1}}),
#i{op=Op, param=Param, anno=Anno} = Instr,
io:format("Exec ~p ~p~n", [Instr, State]),
case Anno of
#{halt:=_} ->
State;
#{reps:=N} when N < 1 ->
NewState = exec_instruction(Op, Param, State),
NewAnno = Anno#{reps => N+1},
NewInstr = Instr#i{anno=NewAnno},
NewCode = Code#{PC => NewInstr},
exec(NewCode, NewState);
#{reps:=N} when N >= 1 ->
State
end.
exec_instruction(nop, _, #state{pc=PC} = State) ->
State#state{pc=PC+1};
exec_instruction(acc, N, #state{acc=Acc, pc=PC} = State) ->
State#state{acc=Acc+N, pc=PC+1};
exec_instruction(jmp, N, #state{pc=PC} = State) ->
State#state{pc=PC+N}.