13 static int64_t orig
[LIMIT
];
27 static int debug_level
= -1;
31 debug_level
= atoi(getenv("DEBUG") ?: "0");
34 static void __attribute__((format(printf
, 2, 3)))
35 debug_raw(int level
, const char *fmt
, ...) {
37 if (debug_level
>= level
) {
39 vfprintf(stderr
, fmt
, ap
);
43 #define debug(...) debug_raw(1, __VA_ARGS__)
45 static int __attribute__((noreturn
)) __attribute__((format(printf
, 1, 2)))
46 die(const char *fmt
, ...)
57 dump(struct state
*s
) {
60 debug(" state of id=%d: pc=%d base=%d in=%s%" PRId64
" out=%s%" PRId64
61 " steps=%d\n", s
->id
, s
->pc
, s
->base
,
62 s
->has_in
? "" : "!", s
->in
, s
->has_out
? "" : "!", s
->out
, s
->steps
);
63 for (int i
= 0; i
< len
; i
++)
64 debug_raw(3, "%" PRId64
",", s
->a
[i
]);
68 static void __attribute__((noreturn
))
69 crash(struct state
*s
, const char *msg
) {
70 printf("invalid program id=%d, pc=%d: %s\n", s
->id
, s
->pc
, msg
);
75 get(struct state
*s
, int param
) {
76 int64_t op
= s
->a
[s
->pc
];
81 if (op
> 99999 || op
< 0)
82 crash(s
, "unexpected opcode");
83 if (s
->pc
+ param
> LIMIT
)
84 crash(s
, "memory too short for opcode");
85 value
= s
->a
[s
->pc
+ param
];
88 mode
= (op
/ scale
) % 10;
89 debug_raw(3, "get op=%" PRId64
" mode=%d value=%" PRId64
"\n",
93 if (value
> LIMIT
|| value
< 0)
94 crash(s
, "in position mode, param beyond memory");
100 if (value
> LIMIT
|| value
< 0)
101 crash(s
, "in relative mode, param beyond memory");
104 crash(s
, "unexpected mode");
109 put(struct state
*s
, int param
, int64_t value
) {
110 int64_t op
= s
->a
[s
->pc
];
115 if (op
> 99999 || op
< 0)
116 crash(s
, "unexpected opcode");
117 if (s
->pc
+ param
> LIMIT
)
118 crash(s
, "memory too short for opcode");
119 offset
= s
->a
[s
->pc
+ param
];
122 mode
= (op
/ scale
) % 10;
123 debug_raw(3, "put op=%" PRId64
" mode=%d value=%" PRId64
" offset=%" PRId64
124 "\n", op
, mode
, value
, offset
);
127 if (offset
> LIMIT
|| offset
< 0)
128 crash(s
, "in position mode, param beyond memory");
129 s
->a
[offset
] = value
;
133 if (offset
> LIMIT
|| offset
< 0)
134 crash(s
, "in relative mode, param beyond memory");
135 s
->a
[offset
] = value
;
138 crash(s
, "unexpected mode");
143 init(struct state
*s
, int64_t in
) {
144 memset(s
, 0, sizeof *s
);
145 memcpy(s
->a
, orig
, len
* sizeof orig
[0]);
151 /* Returns -1 for stalled on input, 0 for done, 1 for stalled on output */
153 run(struct state
*s
) {
157 debug_raw(2, "executing id=%d step=%d pc=%d base=%d %" PRId64
158 ",%" PRId64
",%" PRId64
",%" PRId64
"\n", s
->id
,
159 s
->steps
++, s
->pc
, s
->base
, s
->a
[s
->pc
], s
->a
[s
->pc
+1],
160 s
->a
[s
->pc
+2], s
->a
[s
->pc
+3]);
161 if (!(s
->steps
% 10000))
162 debug(" steps=%d\n", s
->steps
);
163 if (s
->pc
> LIMIT
|| s
->pc
< 0)
164 crash(s
, "program ran out of bounds");
165 switch (s
->a
[s
->pc
] % 100) {
167 put(s
, 3, get(s
, 1) + get(s
, 2));
171 put(s
, 3, get(s
, 1) * get(s
, 2));
176 debug_raw(2, "id=%d stalling for input\n", s
->id
);
186 debug_raw(2, "id=%d stalling for output\n", s
->id
);
209 put(s
, 3, get(s
, 1) < get(s
, 2));
213 put(s
, 3, get(s
, 1) == get(s
, 2));
217 s
->base
+= get(s
, 1);
218 if (s
->base
< 0 || s
->base
> LIMIT
)
219 crash(s
, "relative base out of bounds");
223 debug_raw(2, "id=%d halting\n", s
->id
);
226 crash(s
, "unexpected opcode");
233 static struct state s
;
236 try(const char *in
, int iter
) {
239 debug(" input for iter %d will be:\n%s", iter
, in
);
242 while (run(&s
) && *p
) {
245 debug("read '%c'\n", (char)s
.out
);
247 die("unexpected output %" PRId64
, s
.out
);
252 die("expecting input to be consumed");
257 die("unconsumed input: %s", p
);
258 debug(" output stream:\n");
259 while (s
.has_out
&& isascii(s
.out
)) {
260 debug("%c", (char) s
.out
);
263 die("no input to provide");
266 die("expecting output");
271 main(int argc
, char **argv
) {
275 if (argc
> 1 && strcmp("-", argv
[1]))
276 if (!(stdin
= freopen(argv
[1], "r", stdin
))) {
281 while (scanf("%" SCNd64
"%*[,\n]", &orig
[len
]) == 1)
282 if (len
++ > LIMIT
- 3)
283 die("recompile with larger LIMIT");
284 printf("Read %u slots\n", len
);
286 r
= try("NOT C J\nAND D J\nNOT A T\nOR T J\nWALK\n", 0);
288 die("failed execution");
289 printf("walking detected %" PRId64
" damage\n", r
);
291 r
= try("NOT F J\nOR E J\nOR H J\nAND D J\nNOT C T\nAND T J\n"
292 "NOT D T\nOR B T\nOR E T\nNOT T T\nOR T J\n"
293 "NOT A T\nOR T J\nRUN\n", 1);
295 die("failed execution");
296 printf("running detected %" PRId64
" damage\n", r
);