day 5 part 1
[aoc_eblake.git] / 2019 / intcode.m4
blob865dc8ff09ccb939a39fe9d4cd778c420fba01a6
1 divert(-1)dnl -*- m4 -*-
2 # Not intended for standalone usage. Instead, include it from dayXX.m4 as:
3 # include(`intcode.m4')ifelse(intcode(2), `ok', `',
4 # `errprint(`Missing IntCode initialization
5 # ')m4exit(1)')
7 include(`common.m4')ifdef(`common', `',
8 `errprint(`Missing common initialization
9 ')m4exit(1)')
10 include(`math64.m4')
12 # Common utility functions
13 define(`oneshot', `pushdef(`$1', `popdef(`$1')$2')')
14 define(`oops', `errprintn(`unexpected state at pc='pc)m4exit(1)')
15 define(`run_after_read', `ifelse($1, 0, `run($2)', `oops()')')
16 define(`pause_on_read', `ifelse($1, 0, `', `oops()')')
17 define(`pause_after_read', `ifelse($1, 0, `define(`pc', $2)', `oops()')')
18 define(`run_after_write', `ifelse($1, 1, `run($2)', `oops()')')
19 define(`pause_after_write', `ifelse($1, 1, `define(`pc', $2)', `oops()')')
21 # Parse in the input file.
22 define(`parse', `define(`pos', 0)define(`base', 0)define(`pc',
23   0)chew(len(`$1'), `$1')define(`pos', decr(pos))')
24 define(`_parse', `define(`mem'pos, $1)define(`pos', incr(pos))')
25 ifdef(`__gnu__', `
26   define(`chew', `patsubst(`$2', `\([^;]*\);', `_parse(`\1')')')
27 ', `
28   define(`_chew', `_parse(substr(`$1', 0, index(`$1', `;')))define(`tail',
29     substr(`$1', incr(index(`$1', `;'))))ifelse(index(defn(`tail'), `;'), -1,
30     `', `$0(defn(`tail'))')')
31   define(`chew', `ifelse(eval($1 < 35), 1, `_$0(`$2')', `$0(eval($1/2),
32     substr(`$2', 0, eval($1/2)))$0(eval(len(defn(`tail')) + $1 - $1/2),
33     defn(`tail')substr(`$2', eval($1/2)))')')
36 define(`mem', `ifdef(`mem$1', `mem$1`'', 0)')
37 define(`get0', `mem(mem(eval(pc + $1)))')
38 define(`get', defn(`get0'))
39 define(`get1', `mem(eval(pc + $1))')
40 define(`get2', `mem(eval(base + mem(eval(pc + $1))))')
41 define(`_put', `define(`mem$1', $2)')
42 define(`put0', `_put(mem(eval(pc + $1)), $2)')
43 define(`put', defn(`put0'))
44 define(`put1', `errprintn(`unexpected mode at 'pc)')
45 define(`put2', `_put(eval(base + mem(eval(pc + $1))), $2)')
47 # Either use save/run/restore for rerunning a program, or copy/runs for
48 # running parallel versions of a program
49 define(`saved_put', `ifdef(`$1s', `define', `define(`$1s')pushdef(`_restore',
50   `popdef(`$1s', `$1', `_restore')')pushdef')($@)')
51 define(`save', `pushdef(`base', base)pushdef(`pc', pc)pushdef(`_put',
52   `saved_put(`mem'$'`1, $'`2)')')
53 define(`restore', `ifdef(`_$0', `$0(_$0())', `popdef(`base', `pc', `_put')')')
54 define(`copy', `pushdef(`s', ``mem$1_'')forloop_arg(0, pos,
55   `_$0')define(`pc$1_', 0)define(`base$1_', 0)popdef(`s')')
56 define(`_copy', `define(s`'$1, mem$1)')
57 define(`_copy_mem', `ifdef(pre`'$1, pre`'$1`', 0)')
58 define(`_copy_put', `define(pre`'$@)')
59 oneshot(`copy', `define(`pre', ``mem'')define(`mem', defn(`_copy_mem'))define(
60   `_put', defn(`_copy_put'))define(`oops',
61   `errprintn(`unexpected state: pc='pc` during 'pre)m4exit(1)')$0($@)')
62 define(`runs', `pushdef(`pre', ``mem'$1_')pushdef(`s', $1)pushdef(`base',
63   base$1_)pushdef(`pc', pc$1_)run(pc)define(`pc$1_', pc)define(`base$1_',
64   base)popdef(`pre', `pc', `base', `s')')
66 define(`io', `run($2)')
67 define(`done')
68 define(`op1', `put$3(3, add64(get$1(1), get$2(2)))run(eval(pc + 4))')
69 define(`op2', `put$3(3, mul64(get$1(1), get$2(2)))run(eval(pc + 4))')
70 define(`op3', `put$1(1, read)io(0, eval(pc + 2))')
71 define(`op4', `write(get$1(1))io(1, eval(pc + 2))')
72 define(`op5', `ifelse(get$1(1), 0, `run(eval(pc + 3))', `run(get$2(2))')')
73 define(`op6', `ifelse(get$1(1), 0, `run(get$2(2))', `run(eval(pc + 3))')')
74 define(`op7', `put$3(3, lt64(get$1(1), get$2(2)))run(eval(pc + 4))')
75 define(`op8', `put$3(3, ifelse(get$1(1), get$2(2), 1, 0))run(eval(pc + 4))')
76 define(`op9', `define(`base', eval(base + get$1(1)))run(eval(pc + 2))')
77 define(`op99', `done()')
78 define(`decode', `ifelse(eval($4$3$2 > 0), 1,
79   `define(`op'eval(1000$4$3$2 % 1000)`0$1', `op$1($2, $3, $4)')')')
80 define(`unary', `decode($1, 1)decode($1, 2)')
81 unary(3)
82 unary(4)
83 unary(9)
84 define(`binary', `forloop_var(`a', 0, 2, `forloop_var(`b', 0, 2,
85   `decode($1, a, b)')')')
86 binary(5)
87 binary(6)
88 define(`ternary', `forloop_var(`a', 0, 2, `forloop_var(`b', 0, 2,
89   `decode($1, a, b)decode($1, a, b, 2)')')')
90 ternary(1)
91 ternary(2)
92 ternary(7)
93 ternary(8)
94 define(`op', `ifdef(`op$1', `op$1', `opX')`'')
95 define(`opX', `errprintn(`unexpected opcode at 'pc)')
97 define(`_run', `ifelse($1, `', `', `define(`pc', $1)')')
98 define(`run', `_$0($1)op(mem(pc))')
99 define(`step', `_run($1)oneshot(`run', defn(`_run'))op(mem(pc))')
101 define(`intcode', `common($1)define(`input',
102   translit((include(defn(`file'))), nl`,()', `;;'))')