12 static int debug_level
= -1;
16 debug_level
= atoi(getenv("DEBUG") ?: "0");
19 static void __attribute__((format(printf
, 2, 3)))
20 debug_raw(int level
, const char *fmt
, ...) {
22 if (debug_level
>= level
) {
24 vfprintf(stderr
, fmt
, ap
);
28 #define debug(...) debug_raw(1, __VA_ARGS__)
30 static int __attribute__((noreturn
)) __attribute__((format(printf
, 1, 2)))
31 die(const char *fmt
, ...)
42 static int64_t orig
[LIMIT
];
55 static struct state s
;
58 dump(struct state
*s
) {
61 debug(" state of id=%d: pc=%d base=%d in=%s%" PRId64
" out=%s%" PRId64
62 " steps=%d\n", s
->id
, s
->pc
, s
->base
,
63 s
->has_in
? "" : "!", s
->in
, s
->has_out
? "" : "!", s
->out
, s
->steps
);
64 for (int i
= 0; i
< len
; i
++)
65 debug_raw(3, "%" PRId64
",", s
->a
[i
]);
69 static void __attribute__((noreturn
))
70 crash(struct state
*s
, const char *msg
) {
71 printf("invalid program id=%d, pc=%d: %s\n", s
->id
, s
->pc
, msg
);
76 get(struct state
*s
, int param
) {
77 int64_t op
= s
->a
[s
->pc
];
82 if (op
> 99999 || op
< 0)
83 crash(s
, "unexpected opcode");
84 if (s
->pc
+ param
> LIMIT
)
85 crash(s
, "memory too short for opcode");
86 value
= s
->a
[s
->pc
+ param
];
89 mode
= (op
/ scale
) % 10;
90 debug_raw(3, "get op=%" PRId64
" mode=%d value=%" PRId64
"\n",
94 if (value
> LIMIT
|| value
< 0)
95 crash(s
, "in position mode, param beyond memory");
101 if (value
> LIMIT
|| value
< 0)
102 crash(s
, "in relative mode, param beyond memory");
105 crash(s
, "unexpected mode");
110 put(struct state
*s
, int param
, int64_t value
) {
111 int64_t op
= s
->a
[s
->pc
];
116 if (op
> 99999 || op
< 0)
117 crash(s
, "unexpected opcode");
118 if (s
->pc
+ param
> LIMIT
)
119 crash(s
, "memory too short for opcode");
120 offset
= s
->a
[s
->pc
+ param
];
123 mode
= (op
/ scale
) % 10;
124 debug_raw(3, "put op=%" PRId64
" mode=%d value=%" PRId64
" offset=%" PRId64
125 "\n", op
, mode
, value
, offset
);
128 if (offset
> LIMIT
|| offset
< 0)
129 crash(s
, "in position mode, param beyond memory");
130 s
->a
[offset
] = value
;
134 if (offset
> LIMIT
|| offset
< 0)
135 crash(s
, "in relative mode, param beyond memory");
136 s
->a
[offset
] = value
;
139 crash(s
, "unexpected mode");
144 init(struct state
*s
, int64_t in
) {
145 memset(s
, 0, sizeof *s
);
146 memcpy(s
->a
, orig
, len
* sizeof orig
[0]);
152 /* Returns -1 for stalled on input, 0 for done, 1 for stalled on output */
154 run(struct state
*s
) {
158 debug_raw(2, "executing id=%d step=%d pc=%d base=%d %" PRId64
159 ",%" PRId64
",%" PRId64
",%" PRId64
"\n", s
->id
,
160 s
->steps
++, s
->pc
, s
->base
, s
->a
[s
->pc
], s
->a
[s
->pc
+1],
161 s
->a
[s
->pc
+2], s
->a
[s
->pc
+3]);
162 if (!(s
->steps
% 10000))
163 debug(" steps=%d\n", s
->steps
);
164 if (s
->pc
> LIMIT
|| s
->pc
< 0)
165 crash(s
, "program ran out of bounds");
166 switch (s
->a
[s
->pc
] % 100) {
168 put(s
, 3, get(s
, 1) + get(s
, 2));
172 put(s
, 3, get(s
, 1) * get(s
, 2));
177 debug_raw(2, "id=%d stalling for input\n", s
->id
);
187 debug_raw(2, "id=%d stalling for output\n", s
->id
);
210 put(s
, 3, get(s
, 1) < get(s
, 2));
214 put(s
, 3, get(s
, 1) == get(s
, 2));
218 s
->base
+= get(s
, 1);
219 if (s
->base
< 0 || s
->base
> LIMIT
)
220 crash(s
, "relative base out of bounds");
224 debug_raw(2, "id=%d halting\n", s
->id
);
227 crash(s
, "unexpected opcode");
236 static char buf
[20 * 9];
238 const char *items
[] = { "jam", "loom", "mug", "spool of cat6",
239 "prime number", "food ration", "fuel cell",
243 for (j
= 0; j
< 8; j
++) {
245 p
= stpcpy(p
, "take ");
247 p
= stpcpy(p
, "drop ");
248 p
= stpcpy(p
, items
[j
]);
251 p
= stpcpy(p
, "north\n");
256 main(int argc
, char **argv
) {
258 bool output
= false, seen_bang
= false;
260 const char *p
= "", prep
[] =
278 "take prime number\n"
288 "take spool of cat6\n"
305 if (argc
> 1 && strcmp("-", argv
[1]))
306 if (!(stdin
= freopen(argv
[1], "r", stdin
))) {
311 while (scanf("%" SCNd64
"%*[,\n]", &orig
[len
]) == 1)
312 if (len
++ > LIMIT
- 3)
313 die("recompile with larger LIMIT");
314 printf("Read %u slots\n", len
);
315 f
= fopen("/dev/tty", "r");
317 die("failed to open tty");
323 while (run(&s
) && !feof(f
)) {
325 if (isascii(s
.out
)) {
330 debug("seen bang\n");
333 die("unexpected output %" PRId64
, s
.out
);
338 die("expecting input to be consumed");
343 if (seen_bang
&& i
<= 256) {
345 debug("trying: %s\n", p
);