xref: /freebsd/contrib/bc/src/program.c (revision 839fdcfc0c1dba34f728813d9756515ad82ff58a)
1 /*
2  * *****************************************************************************
3  *
4  * SPDX-License-Identifier: BSD-2-Clause
5  *
6  * Copyright (c) 2018-2021 Gavin D. Howard and contributors.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions are met:
10  *
11  * * Redistributions of source code must retain the above copyright notice, this
12  *   list of conditions and the following disclaimer.
13  *
14  * * Redistributions in binary form must reproduce the above copyright notice,
15  *   this list of conditions and the following disclaimer in the documentation
16  *   and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28  * POSSIBILITY OF SUCH DAMAGE.
29  *
30  * *****************************************************************************
31  *
32  * Code to execute bc programs.
33  *
34  */
35 
36 #include <assert.h>
37 #include <stdbool.h>
38 #include <string.h>
39 
40 #include <setjmp.h>
41 
42 #include <signal.h>
43 
44 #include <time.h>
45 
46 #include <read.h>
47 #include <parse.h>
48 #include <program.h>
49 #include <vm.h>
50 
51 static void bc_program_addFunc(BcProgram *p, BcFunc *f, BcId *id_ptr);
52 
53 static inline void bc_program_setVecs(BcProgram *p, BcFunc *f) {
54 	p->consts = &f->consts;
55 	if (BC_IS_BC) p->strs = &f->strs;
56 }
57 
58 static inline void bc_program_type_num(BcResult *r, BcNum *n) {
59 
60 #if BC_ENABLED
61 	assert(r->t != BC_RESULT_VOID);
62 #endif // BC_ENABLED
63 
64 	if (BC_ERR(!BC_PROG_NUM(r, n))) bc_vm_err(BC_ERR_EXEC_TYPE);
65 }
66 
67 #if BC_ENABLED
68 static void bc_program_type_match(BcResult *r, BcType t) {
69 
70 #if DC_ENABLED
71 	assert(BC_IS_DC || BC_NO_ERR(r->t != BC_RESULT_STR));
72 #endif // DC_ENABLED
73 
74 	if (BC_ERR((r->t != BC_RESULT_ARRAY) != (!t)))
75 		bc_vm_err(BC_ERR_EXEC_TYPE);
76 }
77 #endif // BC_ENABLED
78 
79 static size_t bc_program_index(const char *restrict code, size_t *restrict bgn)
80 {
81 	uchar amt = (uchar) code[(*bgn)++], i = 0;
82 	size_t res = 0;
83 
84 	for (; i < amt; ++i, ++(*bgn)) {
85 		size_t temp = ((size_t) ((int) (uchar) code[*bgn]) & UCHAR_MAX);
86 		res |= (temp << (i * CHAR_BIT));
87 	}
88 
89 	return res;
90 }
91 
92 #if BC_ENABLED
93 static void bc_program_prepGlobals(BcProgram *p) {
94 
95 	size_t i;
96 
97 	for (i = 0; i < BC_PROG_GLOBALS_LEN; ++i)
98 		bc_vec_push(p->globals_v + i, p->globals + i);
99 
100 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
101 	bc_rand_push(&p->rng);
102 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
103 }
104 
105 static void bc_program_popGlobals(BcProgram *p, bool reset) {
106 
107 	size_t i;
108 
109 	for (i = 0; i < BC_PROG_GLOBALS_LEN; ++i) {
110 		BcVec *v = p->globals_v + i;
111 		bc_vec_npop(v, reset ? v->len - 1 : 1);
112 		p->globals[i] = BC_PROG_GLOBAL(v);
113 	}
114 
115 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
116 	bc_rand_pop(&p->rng, reset);
117 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
118 }
119 #endif // BC_ENABLED
120 
121 static void bc_program_pushBigdig(BcProgram *p, BcBigDig dig, BcResultType type)
122 {
123 	BcResult res;
124 
125 	res.t = type;
126 
127 	BC_SIG_LOCK;
128 
129 	bc_num_createFromBigdig(&res.d.n, dig);
130 	bc_vec_push(&p->results, &res);
131 
132 	BC_SIG_UNLOCK;
133 }
134 
135 #if BC_ENABLED
136 static BcVec* bc_program_dereference(const BcProgram *p, BcVec *vec) {
137 
138 	BcVec *v;
139 	size_t vidx, nidx, i = 0;
140 
141 	assert(vec->size == sizeof(uchar));
142 
143 	vidx = bc_program_index(vec->v, &i);
144 	nidx = bc_program_index(vec->v, &i);
145 
146 	v = bc_vec_item(bc_vec_item(&p->arrs, vidx), nidx);
147 
148 	assert(v->size != sizeof(uchar));
149 
150 	return v;
151 }
152 #endif // BC_ENABLED
153 
154 size_t bc_program_search(BcProgram *p, const char *id, bool var) {
155 
156 	BcVec *v, *map;
157 	size_t i;
158 	BcResultData data;
159 
160 	v = var ? &p->vars : &p->arrs;
161 	map = var ? &p->var_map : &p->arr_map;
162 
163 	BC_SIG_LOCK;
164 
165 	if (bc_map_insert(map, id, v->len, &i)) {
166 		bc_array_init(&data.v, var);
167 		bc_vec_push(v, &data.v);
168 	}
169 
170 	BC_SIG_UNLOCK;
171 
172 	return ((BcId*) bc_vec_item(map, i))->idx;
173 }
174 
175 static inline BcVec* bc_program_vec(const BcProgram *p, size_t idx, BcType type)
176 {
177 	const BcVec *v = (type == BC_TYPE_VAR) ? &p->vars : &p->arrs;
178 	return bc_vec_item(v, idx);
179 }
180 
181 static BcNum* bc_program_num(BcProgram *p, BcResult *r) {
182 
183 	BcNum *n;
184 
185 	switch (r->t) {
186 
187 		case BC_RESULT_STR:
188 		case BC_RESULT_TEMP:
189 		case BC_RESULT_IBASE:
190 		case BC_RESULT_SCALE:
191 		case BC_RESULT_OBASE:
192 #if BC_ENABLE_EXTRA_MATH
193 		case BC_RESULT_SEED:
194 #endif // BC_ENABLE_EXTRA_MATH
195 		{
196 			n = &r->d.n;
197 			break;
198 		}
199 
200 		case BC_RESULT_VAR:
201 #if BC_ENABLED
202 		case BC_RESULT_ARRAY:
203 #endif // BC_ENABLED
204 		case BC_RESULT_ARRAY_ELEM:
205 		{
206 			BcVec *v;
207 			BcType type = (r->t == BC_RESULT_VAR) ? BC_TYPE_VAR : BC_TYPE_ARRAY;
208 
209 			v = bc_program_vec(p, r->d.loc.loc, type);
210 
211 			if (r->t == BC_RESULT_ARRAY_ELEM) {
212 
213 				size_t idx = r->d.loc.idx;
214 
215 				v = bc_vec_top(v);
216 
217 #if BC_ENABLED
218 				if (v->size == sizeof(uchar)) v = bc_program_dereference(p, v);
219 #endif // BC_ENABLED
220 
221 				assert(v->size == sizeof(BcNum));
222 
223 				if (v->len <= idx) {
224 					BC_SIG_LOCK;
225 					bc_array_expand(v, bc_vm_growSize(idx, 1));
226 					BC_SIG_UNLOCK;
227 				}
228 
229 				n = bc_vec_item(v, idx);
230 			}
231 			else n = bc_vec_top(v);
232 
233 			break;
234 		}
235 
236 		case BC_RESULT_ZERO:
237 		{
238 			n = &p->zero;
239 			break;
240 		}
241 
242 		case BC_RESULT_ONE:
243 		{
244 			n = &p->one;
245 			break;
246 		}
247 
248 #if BC_ENABLED
249 		case BC_RESULT_VOID:
250 #ifndef NDEBUG
251 		{
252 			abort();
253 		}
254 #endif // NDEBUG
255 		// Fallthrough
256 		case BC_RESULT_LAST:
257 		{
258 			n = &p->last;
259 			break;
260 		}
261 #endif // BC_ENABLED
262 	}
263 
264 	return n;
265 }
266 
267 static void bc_program_operand(BcProgram *p, BcResult **r,
268                                BcNum **n, size_t idx)
269 {
270 	*r = bc_vec_item_rev(&p->results, idx);
271 
272 #if BC_ENABLED
273 	if (BC_ERR((*r)->t == BC_RESULT_VOID)) bc_vm_err(BC_ERR_EXEC_VOID_VAL);
274 #endif // BC_ENABLED
275 
276 	*n = bc_program_num(p, *r);
277 }
278 
279 static void bc_program_binPrep(BcProgram *p, BcResult **l, BcNum **ln,
280                                BcResult **r, BcNum **rn, size_t idx)
281 {
282 	BcResultType lt;
283 
284 	assert(p != NULL && l != NULL && ln != NULL && r != NULL && rn != NULL);
285 
286 #ifndef BC_PROG_NO_STACK_CHECK
287 	if (BC_IS_DC) {
288 		if (BC_ERR(!BC_PROG_STACK(&p->results, idx + 2)))
289 			bc_vm_err(BC_ERR_EXEC_STACK);
290 	}
291 #endif // BC_PROG_NO_STACK_CHECK
292 
293 	assert(BC_PROG_STACK(&p->results, idx + 2));
294 
295 	bc_program_operand(p, l, ln, idx + 1);
296 	bc_program_operand(p, r, rn, idx);
297 
298 	lt = (*l)->t;
299 
300 #if BC_ENABLED
301 	assert(lt != BC_RESULT_VOID && (*r)->t != BC_RESULT_VOID);
302 #endif // BC_ENABLED
303 
304 	// We run this again under these conditions in case any vector has been
305 	// reallocated out from under the BcNums or arrays we had.
306 	if (lt == (*r)->t && (lt == BC_RESULT_VAR || lt == BC_RESULT_ARRAY_ELEM))
307 		*ln = bc_program_num(p, *l);
308 
309 	if (BC_ERR(lt == BC_RESULT_STR)) bc_vm_err(BC_ERR_EXEC_TYPE);
310 }
311 
312 static void bc_program_binOpPrep(BcProgram *p, BcResult **l, BcNum **ln,
313                                  BcResult **r, BcNum **rn, size_t idx)
314 {
315 	bc_program_binPrep(p, l, ln, r, rn, idx);
316 	bc_program_type_num(*l, *ln);
317 	bc_program_type_num(*r, *rn);
318 }
319 
320 static void bc_program_assignPrep(BcProgram *p, BcResult **l, BcNum **ln,
321                                   BcResult **r, BcNum **rn)
322 {
323 	BcResultType lt, min;
324 
325 	min = BC_RESULT_TEMP - ((unsigned int) (BC_IS_BC));
326 
327 	bc_program_binPrep(p, l, ln, r, rn, 0);
328 
329 	lt = (*l)->t;
330 
331 	if (BC_ERR(lt >= min && lt <= BC_RESULT_ONE))
332 		bc_vm_err(BC_ERR_EXEC_TYPE);
333 
334 #if DC_ENABLED
335 	if(BC_IS_DC) {
336 
337 		bool good = (((*r)->t == BC_RESULT_STR || BC_PROG_STR(*rn)) &&
338 		             lt <= BC_RESULT_ARRAY_ELEM);
339 
340 		if (!good) bc_program_type_num(*r, *rn);
341 	}
342 #else
343 	assert((*r)->t != BC_RESULT_STR);
344 #endif // DC_ENABLED
345 }
346 
347 static void bc_program_prep(BcProgram *p, BcResult **r, BcNum **n, size_t idx) {
348 
349 	assert(p != NULL && r != NULL && n != NULL);
350 
351 #ifndef BC_PROG_NO_STACK_CHECK
352 	if (BC_IS_DC) {
353 		if (BC_ERR(!BC_PROG_STACK(&p->results, idx + 1)))
354 			bc_vm_err(BC_ERR_EXEC_STACK);
355 	}
356 #endif // BC_PROG_NO_STACK_CHECK
357 
358 	assert(BC_PROG_STACK(&p->results, idx + 1));
359 
360 	bc_program_operand(p, r, n, idx);
361 
362 #if DC_ENABLED
363 	assert((*r)->t != BC_RESULT_VAR || !BC_PROG_STR(*n));
364 #endif // DC_ENABLED
365 
366 	bc_program_type_num(*r, *n);
367 }
368 
369 static BcResult* bc_program_prepResult(BcProgram *p) {
370 
371 	BcResult res;
372 
373 	bc_result_clear(&res);
374 	bc_vec_push(&p->results, &res);
375 
376 	return bc_vec_top(&p->results);
377 }
378 
379 static void bc_program_const(BcProgram *p, const char *code, size_t *bgn) {
380 
381 	BcResult *r = bc_program_prepResult(p);
382 	BcConst *c = bc_vec_item(p->consts, bc_program_index(code, bgn));
383 	BcBigDig base = BC_PROG_IBASE(p);
384 
385 	if (c->base != base) {
386 
387 		if (c->num.num == NULL) {
388 			BC_SIG_LOCK;
389 			bc_num_init(&c->num, BC_NUM_RDX(strlen(c->val)));
390 			BC_SIG_UNLOCK;
391 		}
392 
393 		// bc_num_parse() should only do operations that cannot fail.
394 		bc_num_parse(&c->num, c->val, base);
395 
396 		c->base = base;
397 	}
398 
399 	BC_SIG_LOCK;
400 
401 	bc_num_createCopy(&r->d.n, &c->num);
402 
403 	BC_SIG_UNLOCK;
404 }
405 
406 static void bc_program_op(BcProgram *p, uchar inst) {
407 
408 	BcResult *opd1, *opd2, *res;
409 	BcNum *n1, *n2;
410 	size_t idx = inst - BC_INST_POWER;
411 
412 	res = bc_program_prepResult(p);
413 
414 	bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2, 1);
415 
416 	BC_SIG_LOCK;
417 
418 	bc_num_init(&res->d.n, bc_program_opReqs[idx](n1, n2, BC_PROG_SCALE(p)));
419 
420 	BC_SIG_UNLOCK;
421 
422 	assert(BC_NUM_RDX_VALID(n1));
423 	assert(BC_NUM_RDX_VALID(n2));
424 
425 	bc_program_ops[idx](n1, n2, &res->d.n, BC_PROG_SCALE(p));
426 
427 	bc_program_retire(p, 1, 2);
428 }
429 
430 static void bc_program_read(BcProgram *p) {
431 
432 	BcStatus s;
433 	BcParse parse;
434 	BcVec buf;
435 	BcInstPtr ip;
436 	size_t i;
437 	const char* file;
438 	BcFunc *f = bc_vec_item(&p->fns, BC_PROG_READ);
439 
440 	for (i = 0; i < p->stack.len; ++i) {
441 		BcInstPtr *ip_ptr = bc_vec_item(&p->stack, i);
442 		if (ip_ptr->func == BC_PROG_READ)
443 			bc_vm_err(BC_ERR_EXEC_REC_READ);
444 	}
445 
446 	BC_SIG_LOCK;
447 
448 	file = vm.file;
449 	bc_parse_init(&parse, p, BC_PROG_READ);
450 	bc_vec_init(&buf, sizeof(char), NULL);
451 
452 	BC_SETJMP_LOCKED(exec_err);
453 
454 	BC_SIG_UNLOCK;
455 
456 	bc_lex_file(&parse.l, bc_program_stdin_name);
457 	bc_vec_popAll(&f->code);
458 
459 	s = bc_read_line(&buf, BC_IS_BC ? "read> " : "?> ");
460 	if (s == BC_STATUS_EOF) bc_vm_err(BC_ERR_EXEC_READ_EXPR);
461 
462 	bc_parse_text(&parse, buf.v);
463 	vm.expr(&parse, BC_PARSE_NOREAD | BC_PARSE_NEEDVAL);
464 
465 	if (BC_ERR(parse.l.t != BC_LEX_NLINE && parse.l.t != BC_LEX_EOF))
466 		bc_vm_err(BC_ERR_EXEC_READ_EXPR);
467 
468 #if BC_ENABLED
469 	if (BC_G) bc_program_prepGlobals(p);
470 #endif // BC_ENABLED
471 
472 	ip.func = BC_PROG_READ;
473 	ip.idx = 0;
474 	ip.len = p->results.len;
475 
476 	// Update this pointer, just in case.
477 	f = bc_vec_item(&p->fns, BC_PROG_READ);
478 
479 	bc_vec_pushByte(&f->code, vm.read_ret);
480 	bc_vec_push(&p->stack, &ip);
481 
482 #if DC_ENABLED
483 	if (BC_IS_DC) {
484 		size_t temp = 0;
485 		bc_vec_push(&p->tail_calls, &temp);
486 	}
487 #endif // DC_ENABLED
488 
489 exec_err:
490 	BC_SIG_MAYLOCK;
491 	bc_parse_free(&parse);
492 	bc_vec_free(&buf);
493 	vm.file = file;
494 	BC_LONGJMP_CONT;
495 }
496 
497 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
498 static void bc_program_rand(BcProgram *p) {
499 	BcRand rand = bc_rand_int(&p->rng);
500 	bc_program_pushBigdig(p, (BcBigDig) rand, BC_RESULT_TEMP);
501 #ifndef NDEBUG
502 	{
503 		BcResult *r = bc_vec_top(&p->results);
504 		assert(BC_NUM_RDX_VALID_NP(r->d.n));
505 	}
506 #endif // NDEBUG
507 }
508 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
509 
510 static void bc_program_printChars(const char *str) {
511 
512 	const char *nl;
513 	size_t len = vm.nchars + strlen(str);
514 
515 	bc_file_puts(&vm.fout, str);
516 	nl = strrchr(str, '\n');
517 
518 	if (nl != NULL) len = strlen(nl + 1);
519 
520 	vm.nchars = len > UINT16_MAX ? UINT16_MAX : (uint16_t) len;
521 }
522 
523 static void bc_program_printString(const char *restrict str) {
524 
525 	size_t i, len = strlen(str);
526 
527 #if DC_ENABLED
528 	if (!len && BC_IS_DC) {
529 		bc_vm_putchar('\0');
530 		return;
531 	}
532 #endif // DC_ENABLED
533 
534 	for (i = 0; i < len; ++i) {
535 
536 		int c = str[i];
537 
538 		if (c == '\\' && i != len - 1) {
539 
540 			const char *ptr;
541 
542 			c = str[++i];
543 			ptr = strchr(bc_program_esc_chars, c);
544 
545 			if (ptr != NULL) {
546 				if (c == 'n') vm.nchars = UINT16_MAX;
547 				c = bc_program_esc_seqs[(size_t) (ptr - bc_program_esc_chars)];
548 			}
549 			else {
550 				// Just print the backslash. The following
551 				// character will be printed later.
552 				bc_vm_putchar('\\');
553 			}
554 		}
555 
556 		bc_vm_putchar(c);
557 	}
558 }
559 
560 static void bc_program_print(BcProgram *p, uchar inst, size_t idx) {
561 
562 	BcResult *r;
563 	char *str;
564 	BcNum *n;
565 	bool pop = (inst != BC_INST_PRINT);
566 
567 	assert(p != NULL);
568 
569 #ifndef BC_PROG_NO_STACK_CHECK
570 	if (BC_IS_DC) {
571 		if (BC_ERR(!BC_PROG_STACK(&p->results, idx + 1)))
572 			bc_vm_err(BC_ERR_EXEC_STACK);
573 	}
574 #endif // BC_PROG_NO_STACK_CHECK
575 
576 	assert(BC_PROG_STACK(&p->results, idx + 1));
577 
578 	r = bc_vec_item_rev(&p->results, idx);
579 
580 #if BC_ENABLED
581 	if (r->t == BC_RESULT_VOID) {
582 		if (BC_ERR(pop)) bc_vm_err(BC_ERR_EXEC_VOID_VAL);
583 		bc_vec_pop(&p->results);
584 		return;
585 	}
586 #endif // BC_ENABLED
587 
588 	n = bc_program_num(p, r);
589 
590 	if (BC_PROG_NUM(r, n)) {
591 		assert(inst != BC_INST_PRINT_STR);
592 		bc_num_print(n, BC_PROG_OBASE(p), !pop);
593 #if BC_ENABLED
594 		if (BC_IS_BC) bc_num_copy(&p->last, n);
595 #endif // BC_ENABLED
596 	}
597 	else {
598 
599 		size_t i = (r->t == BC_RESULT_STR) ? r->d.loc.loc : n->scale;
600 
601 		bc_file_flush(&vm.fout);
602 		str = *((char**) bc_vec_item(p->strs, i));
603 
604 		if (inst == BC_INST_PRINT_STR) bc_program_printChars(str);
605 		else {
606 			bc_program_printString(str);
607 			if (inst == BC_INST_PRINT) bc_vm_putchar('\n');
608 		}
609 	}
610 
611 	if (BC_IS_BC || pop) bc_vec_pop(&p->results);
612 }
613 
614 void bc_program_negate(BcResult *r, BcNum *n) {
615 	bc_num_copy(&r->d.n, n);
616 	if (BC_NUM_NONZERO(&r->d.n)) BC_NUM_NEG_TGL_NP(r->d.n);
617 }
618 
619 void bc_program_not(BcResult *r, BcNum *n) {
620 	if (!bc_num_cmpZero(n)) bc_num_one(&r->d.n);
621 }
622 
623 #if BC_ENABLE_EXTRA_MATH
624 void bc_program_trunc(BcResult *r, BcNum *n) {
625 	bc_num_copy(&r->d.n, n);
626 	bc_num_truncate(&r->d.n, n->scale);
627 }
628 #endif // BC_ENABLE_EXTRA_MATH
629 
630 static void bc_program_unary(BcProgram *p, uchar inst) {
631 
632 	BcResult *res, *ptr;
633 	BcNum *num;
634 
635 	res = bc_program_prepResult(p);
636 
637 	bc_program_prep(p, &ptr, &num, 1);
638 
639 	BC_SIG_LOCK;
640 
641 	bc_num_init(&res->d.n, num->len);
642 
643 	BC_SIG_UNLOCK;
644 
645 	bc_program_unarys[inst - BC_INST_NEG](res, num);
646 	bc_program_retire(p, 1, 1);
647 }
648 
649 static void bc_program_logical(BcProgram *p, uchar inst) {
650 
651 	BcResult *opd1, *opd2, *res;
652 	BcNum *n1, *n2;
653 	bool cond = 0;
654 	ssize_t cmp;
655 
656 	res = bc_program_prepResult(p);
657 
658 	bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2, 1);
659 
660 	if (inst == BC_INST_BOOL_AND)
661 		cond = (bc_num_cmpZero(n1) && bc_num_cmpZero(n2));
662 	else if (inst == BC_INST_BOOL_OR)
663 		cond = (bc_num_cmpZero(n1) || bc_num_cmpZero(n2));
664 	else {
665 
666 		cmp = bc_num_cmp(n1, n2);
667 
668 		switch (inst) {
669 
670 			case BC_INST_REL_EQ:
671 			{
672 				cond = (cmp == 0);
673 				break;
674 			}
675 
676 			case BC_INST_REL_LE:
677 			{
678 				cond = (cmp <= 0);
679 				break;
680 			}
681 
682 			case BC_INST_REL_GE:
683 			{
684 				cond = (cmp >= 0);
685 				break;
686 			}
687 
688 			case BC_INST_REL_NE:
689 			{
690 				cond = (cmp != 0);
691 				break;
692 			}
693 
694 			case BC_INST_REL_LT:
695 			{
696 				cond = (cmp < 0);
697 				break;
698 			}
699 
700 			case BC_INST_REL_GT:
701 			{
702 				cond = (cmp > 0);
703 				break;
704 			}
705 #ifndef NDEBUG
706 			default:
707 			{
708 				abort();
709 			}
710 #endif // NDEBUG
711 		}
712 	}
713 
714 	BC_SIG_LOCK;
715 
716 	bc_num_init(&res->d.n, BC_NUM_DEF_SIZE);
717 
718 	BC_SIG_UNLOCK;
719 
720 	if (cond) bc_num_one(&res->d.n);
721 
722 	bc_program_retire(p, 1, 2);
723 }
724 
725 #if DC_ENABLED
726 static void bc_program_assignStr(BcProgram *p, size_t idx,
727                                  BcVec *v, bool push)
728 {
729 	BcNum n2;
730 
731 	bc_num_clear(&n2);
732 	n2.scale = idx;
733 
734 	assert(BC_PROG_STACK(&p->results, 1 + !push));
735 
736 	if (!push) bc_vec_pop(v);
737 
738 	bc_vec_npop(&p->results, 1 + !push);
739 	bc_vec_push(v, &n2);
740 }
741 #endif // DC_ENABLED
742 
743 static void bc_program_copyToVar(BcProgram *p, size_t idx,
744                                  BcType t, bool last)
745 {
746 	BcResult *ptr = NULL, r;
747 	BcVec *vec;
748 	BcNum *n = NULL;
749 	bool var = (t == BC_TYPE_VAR);
750 
751 #if DC_ENABLED
752 	if (BC_IS_DC) {
753 
754 		if (BC_ERR(!BC_PROG_STACK(&p->results, 1)))
755 			bc_vm_err(BC_ERR_EXEC_STACK);
756 
757 		assert(BC_PROG_STACK(&p->results, 1));
758 
759 		bc_program_operand(p, &ptr, &n, 0);
760 	}
761 #endif
762 
763 #if BC_ENABLED
764 	if (BC_IS_BC)
765 	{
766 		ptr = bc_vec_top(&p->results);
767 
768 		bc_program_type_match(ptr, t);
769 
770 		if (last) n = bc_program_num(p, ptr);
771 		else if (var)
772 			n = bc_vec_item_rev(bc_program_vec(p, ptr->d.loc.loc, t), 1);
773 	}
774 #endif // BC_ENABLED
775 
776 	vec = bc_program_vec(p, idx, t);
777 
778 #if DC_ENABLED
779 	if (BC_IS_DC && (ptr->t == BC_RESULT_STR || BC_PROG_STR(n))) {
780 
781 		size_t str_idx = ptr->t == BC_RESULT_STR ? ptr->d.loc.loc : n->scale;
782 
783 		if (BC_ERR(!var)) bc_vm_err(BC_ERR_EXEC_TYPE);
784 
785 		bc_program_assignStr(p, str_idx, vec, true);
786 
787 		return;
788 	}
789 #endif // DC_ENABLED
790 
791 	BC_SIG_LOCK;
792 
793 	if (var) bc_num_createCopy(&r.d.n, n);
794 	else {
795 
796 		BcVec *v = (BcVec*) n, *rv = &r.d.v;
797 #if BC_ENABLED
798 		BcVec *parent;
799 		bool ref, ref_size;
800 
801 		parent = bc_program_vec(p, ptr->d.loc.loc, t);
802 		assert(parent != NULL);
803 
804 		if (!last) v = bc_vec_item_rev(parent, !last);
805 		assert(v != NULL);
806 
807 		ref = (v->size == sizeof(BcNum) && t == BC_TYPE_REF);
808 		ref_size = (v->size == sizeof(uchar));
809 
810 		if (ref || (ref_size && t == BC_TYPE_REF)) {
811 
812 			bc_vec_init(rv, sizeof(uchar), NULL);
813 
814 			if (ref) {
815 
816 				assert(parent->len >= (size_t) (!last + 1));
817 
818 				// Make sure the pointer was not invalidated.
819 				vec = bc_program_vec(p, idx, t);
820 
821 				bc_vec_pushIndex(rv, ptr->d.loc.loc);
822 				bc_vec_pushIndex(rv, parent->len - !last - 1);
823 			}
824 			// If we get here, we are copying a ref to a ref.
825 			else bc_vec_npush(rv, v->len * sizeof(uchar), v->v);
826 
827 			// We need to return early.
828 			bc_vec_push(vec, &r.d);
829 			bc_vec_pop(&p->results);
830 
831 			BC_SIG_UNLOCK;
832 			return;
833 		}
834 		else if (ref_size && t != BC_TYPE_REF) v = bc_program_dereference(p, v);
835 #endif // BC_ENABLED
836 
837 		bc_array_init(rv, true);
838 		bc_array_copy(rv, v);
839 	}
840 
841 	bc_vec_push(vec, &r.d);
842 	bc_vec_pop(&p->results);
843 
844 	BC_SIG_UNLOCK;
845 }
846 
847 static void bc_program_assign(BcProgram *p, uchar inst) {
848 
849 	BcResult *left, *right, res;
850 	BcNum *l, *r;
851 	bool ob, sc, use_val = BC_INST_USE_VAL(inst);
852 
853 	bc_program_assignPrep(p, &left, &l, &right, &r);
854 
855 #if DC_ENABLED
856 	assert(left->t != BC_RESULT_STR);
857 
858 	if (right->t == BC_RESULT_STR || BC_PROG_STR(r)) {
859 
860 		size_t idx = right->t == BC_RESULT_STR ? right->d.loc.loc : r->scale;
861 
862 		if (left->t == BC_RESULT_ARRAY_ELEM) {
863 			BC_SIG_LOCK;
864 			bc_num_free(l);
865 			bc_num_clear(l);
866 			l->scale = idx;
867 			bc_vec_npop(&p->results, 2);
868 			BC_SIG_UNLOCK;
869 		}
870 		else {
871 			BcVec *v = bc_program_vec(p, left->d.loc.loc, BC_TYPE_VAR);
872 			bc_program_assignStr(p, idx, v, false);
873 		}
874 
875 		return;
876 	}
877 #endif // DC_ENABLED
878 
879 	if (BC_INST_IS_ASSIGN(inst)) bc_num_copy(l, r);
880 #if BC_ENABLED
881 	else {
882 
883 		BcBigDig scale = BC_PROG_SCALE(p);
884 
885 		if (!use_val)
886 			inst -= (BC_INST_ASSIGN_POWER_NO_VAL - BC_INST_ASSIGN_POWER);
887 
888 		assert(BC_NUM_RDX_VALID(l));
889 		assert(BC_NUM_RDX_VALID(r));
890 
891 		bc_program_ops[inst - BC_INST_ASSIGN_POWER](l, r, l, scale);
892 	}
893 #endif // BC_ENABLED
894 
895 	ob = (left->t == BC_RESULT_OBASE);
896 	sc = (left->t == BC_RESULT_SCALE);
897 
898 	if (ob || sc || left->t == BC_RESULT_IBASE) {
899 
900 		BcVec *v;
901 		BcBigDig *ptr, *ptr_t, val, max, min;
902 		BcErr e;
903 
904 		bc_num_bigdig(l, &val);
905 		e = left->t - BC_RESULT_IBASE + BC_ERR_EXEC_IBASE;
906 
907 		if (sc) {
908 			min = 0;
909 			max = vm.maxes[BC_PROG_GLOBALS_SCALE];
910 			v = p->globals_v + BC_PROG_GLOBALS_SCALE;
911 			ptr_t = p->globals + BC_PROG_GLOBALS_SCALE;
912 		}
913 		else {
914 			min = BC_NUM_MIN_BASE;
915 			if (BC_ENABLE_EXTRA_MATH && ob && (BC_IS_DC || !BC_IS_POSIX))
916 				min = 0;
917 			max = vm.maxes[ob + BC_PROG_GLOBALS_IBASE];
918 			v = p->globals_v + BC_PROG_GLOBALS_IBASE + ob;
919 			ptr_t = p->globals + BC_PROG_GLOBALS_IBASE + ob;
920 		}
921 
922 		if (BC_ERR(val > max || val < min)) bc_vm_verr(e, min, max);
923 
924 		ptr = bc_vec_top(v);
925 		*ptr = val;
926 		*ptr_t = val;
927 	}
928 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
929 	else if (left->t == BC_RESULT_SEED) bc_num_rng(l, &p->rng);
930 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
931 
932 	BC_SIG_LOCK;
933 
934 	if (use_val) {
935 		bc_num_createCopy(&res.d.n, l);
936 		res.t = BC_RESULT_TEMP;
937 		bc_vec_npop(&p->results, 2);
938 		bc_vec_push(&p->results, &res);
939 	}
940 	else bc_vec_npop(&p->results, 2);
941 
942 	BC_SIG_UNLOCK;
943 }
944 
945 static void bc_program_pushVar(BcProgram *p, const char *restrict code,
946                                size_t *restrict bgn, bool pop, bool copy)
947 {
948 	BcResult r;
949 	size_t idx = bc_program_index(code, bgn);
950 
951 	r.t = BC_RESULT_VAR;
952 	r.d.loc.loc = idx;
953 
954 #if DC_ENABLED
955 	if (BC_IS_DC && (pop || copy)) {
956 
957 		BcVec *v = bc_program_vec(p, idx, BC_TYPE_VAR);
958 		BcNum *num = bc_vec_top(v);
959 
960 		if (BC_ERR(!BC_PROG_STACK(v, 2 - copy))) bc_vm_err(BC_ERR_EXEC_STACK);
961 
962 		assert(BC_PROG_STACK(v, 2 - copy));
963 
964 		if (!BC_PROG_STR(num)) {
965 
966 			BC_SIG_LOCK;
967 
968 			r.t = BC_RESULT_TEMP;
969 			bc_num_createCopy(&r.d.n, num);
970 
971 			if (!copy) bc_vec_pop(v);
972 
973 			bc_vec_push(&p->results, &r);
974 
975 			BC_SIG_UNLOCK;
976 
977 			return;
978 		}
979 		else {
980 			r.d.loc.loc = num->scale;
981 			r.t = BC_RESULT_STR;
982 		}
983 
984 		if (!copy) bc_vec_pop(v);
985 	}
986 #endif // DC_ENABLED
987 
988 	bc_vec_push(&p->results, &r);
989 }
990 
991 static void bc_program_pushArray(BcProgram *p, const char *restrict code,
992                                  size_t *restrict bgn, uchar inst)
993 {
994 	BcResult r, *operand;
995 	BcNum *num;
996 	BcBigDig temp;
997 
998 	r.d.loc.loc = bc_program_index(code, bgn);
999 
1000 #if BC_ENABLED
1001 	if (inst == BC_INST_ARRAY) {
1002 		r.t = BC_RESULT_ARRAY;
1003 		bc_vec_push(&p->results, &r);
1004 		return;
1005 	}
1006 #endif // BC_ENABLED
1007 
1008 	bc_program_prep(p, &operand, &num, 0);
1009 	bc_num_bigdig(num, &temp);
1010 
1011 	r.t = BC_RESULT_ARRAY_ELEM;
1012 	r.d.loc.idx = (size_t) temp;
1013 
1014 	BC_SIG_LOCK;
1015 
1016 	bc_vec_pop(&p->results);
1017 	bc_vec_push(&p->results, &r);
1018 
1019 	BC_SIG_UNLOCK;
1020 }
1021 
1022 #if BC_ENABLED
1023 static void bc_program_incdec(BcProgram *p, uchar inst) {
1024 
1025 	BcResult *ptr, res, copy;
1026 	BcNum *num;
1027 	uchar inst2;
1028 
1029 	bc_program_prep(p, &ptr, &num, 0);
1030 
1031 	BC_SIG_LOCK;
1032 
1033 	copy.t = BC_RESULT_TEMP;
1034 	bc_num_createCopy(&copy.d.n, num);
1035 
1036 	BC_SETJMP_LOCKED(exit);
1037 
1038 	BC_SIG_UNLOCK;
1039 
1040 	res.t = BC_RESULT_ONE;
1041 	inst2 = BC_INST_ASSIGN_PLUS + (inst & 0x01);
1042 
1043 	bc_vec_push(&p->results, &res);
1044 	bc_program_assign(p, inst2);
1045 
1046 	BC_SIG_LOCK;
1047 
1048 	bc_vec_pop(&p->results);
1049 	bc_vec_push(&p->results, &copy);
1050 
1051 	BC_UNSETJMP;
1052 
1053 	BC_SIG_UNLOCK;
1054 
1055 	return;
1056 
1057 exit:
1058 	BC_SIG_MAYLOCK;
1059 	bc_num_free(&copy.d.n);
1060 	BC_LONGJMP_CONT;
1061 }
1062 
1063 static void bc_program_call(BcProgram *p, const char *restrict code,
1064                             size_t *restrict idx)
1065 {
1066 	BcInstPtr ip;
1067 	size_t i, nparams = bc_program_index(code, idx);
1068 	BcFunc *f;
1069 	BcVec *v;
1070 	BcLoc *a;
1071 	BcResultData param;
1072 	BcResult *arg;
1073 
1074 	ip.idx = 0;
1075 	ip.func = bc_program_index(code, idx);
1076 	f = bc_vec_item(&p->fns, ip.func);
1077 
1078 	if (BC_ERR(!f->code.len)) bc_vm_verr(BC_ERR_EXEC_UNDEF_FUNC, f->name);
1079 	if (BC_ERR(nparams != f->nparams))
1080 		bc_vm_verr(BC_ERR_EXEC_PARAMS, f->nparams, nparams);
1081 	ip.len = p->results.len - nparams;
1082 
1083 	assert(BC_PROG_STACK(&p->results, nparams));
1084 
1085 	if (BC_G) bc_program_prepGlobals(p);
1086 
1087 	for (i = 0; i < nparams; ++i) {
1088 
1089 		size_t j;
1090 		bool last = true;
1091 
1092 		arg = bc_vec_top(&p->results);
1093 		if (BC_ERR(arg->t == BC_RESULT_VOID)) bc_vm_err(BC_ERR_EXEC_VOID_VAL);
1094 
1095 		a = bc_vec_item(&f->autos, nparams - 1 - i);
1096 
1097 		// If I have already pushed to a var, I need to make sure I
1098 		// get the previous version, not the already pushed one.
1099 		if (arg->t == BC_RESULT_VAR || arg->t == BC_RESULT_ARRAY) {
1100 			for (j = 0; j < i && last; ++j) {
1101 				BcLoc *loc = bc_vec_item(&f->autos, nparams - 1 - j);
1102 				last = (arg->d.loc.loc != loc->loc ||
1103 				        (!loc->idx) != (arg->t == BC_RESULT_VAR));
1104 			}
1105 		}
1106 
1107 		bc_program_copyToVar(p, a->loc, (BcType) a->idx, last);
1108 	}
1109 
1110 	BC_SIG_LOCK;
1111 
1112 	for (; i < f->autos.len; ++i) {
1113 
1114 		a = bc_vec_item(&f->autos, i);
1115 		v = bc_program_vec(p, a->loc, (BcType) a->idx);
1116 
1117 		if (a->idx == BC_TYPE_VAR) {
1118 			bc_num_init(&param.n, BC_NUM_DEF_SIZE);
1119 			bc_vec_push(v, &param.n);
1120 		}
1121 		else {
1122 			assert(a->idx == BC_TYPE_ARRAY);
1123 			bc_array_init(&param.v, true);
1124 			bc_vec_push(v, &param.v);
1125 		}
1126 	}
1127 
1128 	bc_vec_push(&p->stack, &ip);
1129 
1130 	BC_SIG_UNLOCK;
1131 }
1132 
1133 static void bc_program_return(BcProgram *p, uchar inst) {
1134 
1135 	BcResult *res;
1136 	BcFunc *f;
1137 	BcInstPtr *ip = bc_vec_top(&p->stack);
1138 	size_t i, nops = p->results.len - ip->len;
1139 
1140 	assert(BC_PROG_STACK(&p->stack, 2));
1141 	assert(BC_PROG_STACK(&p->results, ip->len + (inst == BC_INST_RET)));
1142 
1143 	f = bc_vec_item(&p->fns, ip->func);
1144 	res = bc_program_prepResult(p);
1145 
1146 	if (inst == BC_INST_RET) {
1147 
1148 		BcNum *num;
1149 		BcResult *operand;
1150 
1151 		bc_program_operand(p, &operand, &num, 1);
1152 
1153 		BC_SIG_LOCK;
1154 
1155 		bc_num_createCopy(&res->d.n, num);
1156 	}
1157 	else if (inst == BC_INST_RET_VOID) res->t = BC_RESULT_VOID;
1158 	else {
1159 		BC_SIG_LOCK;
1160 		bc_num_init(&res->d.n, BC_NUM_DEF_SIZE);
1161 	}
1162 
1163 	BC_SIG_MAYUNLOCK;
1164 
1165 	// We need to pop arguments as well, so this takes that into account.
1166 	for (i = 0; i < f->autos.len; ++i) {
1167 
1168 		BcLoc *a = bc_vec_item(&f->autos, i);
1169 		BcVec *v = bc_program_vec(p, a->loc, (BcType) a->idx);
1170 
1171 		bc_vec_pop(v);
1172 	}
1173 
1174 	bc_program_retire(p, 1, nops);
1175 
1176 	if (BC_G) bc_program_popGlobals(p, false);
1177 
1178 	bc_vec_pop(&p->stack);
1179 }
1180 #endif // BC_ENABLED
1181 
1182 static void bc_program_builtin(BcProgram *p, uchar inst) {
1183 
1184 	BcResult *opd, *res;
1185 	BcNum *num;
1186 	bool len = (inst == BC_INST_LENGTH);
1187 
1188 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1189 	assert(inst >= BC_INST_LENGTH && inst <= BC_INST_IRAND);
1190 #else // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1191 	assert(inst >= BC_INST_LENGTH && inst <= BC_INST_ABS);
1192 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1193 
1194 #ifndef BC_PROG_NO_STACK_CHECK
1195 	if (BC_IS_DC) {
1196 		if (BC_ERR(!BC_PROG_STACK(&p->results, 1)))
1197 			bc_vm_err(BC_ERR_EXEC_STACK);
1198 	}
1199 #endif // BC_PROG_NO_STACK_CHECK
1200 
1201 	assert(BC_PROG_STACK(&p->results, 1));
1202 
1203 	res = bc_program_prepResult(p);
1204 
1205 	bc_program_operand(p, &opd, &num, 1);
1206 
1207 	assert(num != NULL);
1208 
1209 #if DC_ENABLED
1210 	if (!len && inst != BC_INST_SCALE_FUNC) bc_program_type_num(opd, num);
1211 #endif // DC_ENABLED
1212 
1213 	if (inst == BC_INST_SQRT) bc_num_sqrt(num, &res->d.n, BC_PROG_SCALE(p));
1214 	else if (inst == BC_INST_ABS) {
1215 
1216 		BC_SIG_LOCK;
1217 
1218 		bc_num_createCopy(&res->d.n, num);
1219 
1220 		BC_SIG_UNLOCK;
1221 
1222 		BC_NUM_NEG_CLR_NP(res->d.n);
1223 	}
1224 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1225 	else if (inst == BC_INST_IRAND) {
1226 
1227 		BC_SIG_LOCK;
1228 
1229 		bc_num_init(&res->d.n, num->len - num->rdx);
1230 
1231 		BC_SIG_UNLOCK;
1232 
1233 		bc_num_irand(num, &res->d.n, &p->rng);
1234 	}
1235 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1236 	else {
1237 
1238 		BcBigDig val = 0;
1239 
1240 		if (len) {
1241 #if BC_ENABLED
1242 			if (BC_IS_BC && opd->t == BC_RESULT_ARRAY) {
1243 
1244 				BcVec *v = (BcVec*) num;
1245 
1246 				if (v->size == sizeof(uchar)) v = bc_program_dereference(p, v);
1247 
1248 				assert(v->size == sizeof(BcNum));
1249 
1250 				val = (BcBigDig) v->len;
1251 			}
1252 			else
1253 #endif // BC_ENABLED
1254 			{
1255 #if DC_ENABLED
1256 				if (!BC_PROG_NUM(opd, num)) {
1257 
1258 					size_t idx;
1259 					char *str;
1260 
1261 					idx = opd->t == BC_RESULT_STR ? opd->d.loc.loc : num->scale;
1262 					str = *((char**) bc_vec_item(p->strs, idx));
1263 					val = (BcBigDig) strlen(str);
1264 				}
1265 				else
1266 #endif // DC_ENABLED
1267 				{
1268 					val = (BcBigDig) bc_num_len(num);
1269 				}
1270 			}
1271 		}
1272 		else if (BC_IS_BC || BC_PROG_NUM(opd, num))
1273 			val = (BcBigDig) bc_num_scale(num);
1274 
1275 		BC_SIG_LOCK;
1276 
1277 		bc_num_createFromBigdig(&res->d.n, val);
1278 
1279 		BC_SIG_UNLOCK;
1280 	}
1281 
1282 	bc_program_retire(p, 1, 1);
1283 }
1284 
1285 #if DC_ENABLED
1286 static void bc_program_divmod(BcProgram *p) {
1287 
1288 	BcResult *opd1, *opd2, *res, *res2;
1289 	BcNum *n1, *n2;
1290 	size_t req;
1291 
1292 	bc_vec_grow(&p->results, 2);
1293 
1294 	// We don't need to update the pointer because
1295 	// the capacity is enough due to the line above.
1296 	res2 = bc_program_prepResult(p);
1297 	res = bc_program_prepResult(p);
1298 
1299 	bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2, 2);
1300 
1301 	req = bc_num_mulReq(n1, n2, BC_PROG_SCALE(p));
1302 
1303 	BC_SIG_LOCK;
1304 
1305 	bc_num_init(&res->d.n, req);
1306 	bc_num_init(&res2->d.n, req);
1307 
1308 	BC_SIG_UNLOCK;
1309 
1310 	bc_num_divmod(n1, n2, &res2->d.n, &res->d.n, BC_PROG_SCALE(p));
1311 
1312 	bc_program_retire(p, 2, 2);
1313 }
1314 
1315 static void bc_program_modexp(BcProgram *p) {
1316 
1317 	BcResult *r1, *r2, *r3, *res;
1318 	BcNum *n1, *n2, *n3;
1319 
1320 	if (BC_ERR(!BC_PROG_STACK(&p->results, 3))) bc_vm_err(BC_ERR_EXEC_STACK);
1321 
1322 	assert(BC_PROG_STACK(&p->results, 3));
1323 
1324 	res = bc_program_prepResult(p);
1325 
1326 	bc_program_operand(p, &r1, &n1, 3);
1327 	bc_program_type_num(r1, n1);
1328 
1329 	bc_program_binOpPrep(p, &r2, &n2, &r3, &n3, 1);
1330 
1331 	// Make sure that the values have their pointers updated, if necessary.
1332 	// Only array elements are possible.
1333 	if (r1->t == BC_RESULT_ARRAY_ELEM && (r1->t == r2->t || r1->t == r3->t))
1334 		n1 = bc_program_num(p, r1);
1335 
1336 	BC_SIG_LOCK;
1337 
1338 	bc_num_init(&res->d.n, n3->len);
1339 
1340 	BC_SIG_UNLOCK;
1341 
1342 	bc_num_modexp(n1, n2, n3, &res->d.n);
1343 
1344 	bc_program_retire(p, 1, 3);
1345 }
1346 
1347 static void bc_program_stackLen(BcProgram *p) {
1348 	bc_program_pushBigdig(p, (BcBigDig) p->results.len, BC_RESULT_TEMP);
1349 }
1350 
1351 static uchar bc_program_asciifyNum(BcProgram *p, BcNum *n) {
1352 
1353 	BcNum num;
1354 	BcBigDig val = 0;
1355 
1356 	bc_num_clear(&num);
1357 
1358 	BC_SETJMP(num_err);
1359 
1360 	BC_SIG_LOCK;
1361 
1362 	bc_num_createCopy(&num, n);
1363 
1364 	BC_SIG_UNLOCK;
1365 
1366 	bc_num_truncate(&num, num.scale);
1367 	BC_NUM_NEG_CLR_NP(num);
1368 
1369 	// This is guaranteed to not have a divide by 0
1370 	// because strmb is equal to UCHAR_MAX + 1.
1371 	bc_num_mod(&num, &p->strmb, &num, 0);
1372 
1373 	// This is also guaranteed to not error because num is in the range
1374 	// [0, UCHAR_MAX], which is definitely in range for a BcBigDig. And
1375 	// it is not negative.
1376 	bc_num_bigdig2(&num, &val);
1377 
1378 num_err:
1379 	BC_SIG_MAYLOCK;
1380 	bc_num_free(&num);
1381 	BC_LONGJMP_CONT;
1382 	return (uchar) val;
1383 }
1384 
1385 static void bc_program_asciify(BcProgram *p) {
1386 
1387 	BcResult *r, res;
1388 	BcNum *n;
1389 	char str[2], *str2;
1390 	uchar c;
1391 	size_t idx;
1392 
1393 	if (BC_ERR(!BC_PROG_STACK(&p->results, 1))) bc_vm_err(BC_ERR_EXEC_STACK);
1394 
1395 	assert(BC_PROG_STACK(&p->results, 1));
1396 
1397 	bc_program_operand(p, &r, &n, 0);
1398 
1399 	assert(n != NULL);
1400 
1401 	assert(p->strs->len + BC_PROG_REQ_FUNCS == p->fns.len);
1402 
1403 	if (BC_PROG_NUM(r, n)) c = bc_program_asciifyNum(p, n);
1404 	else {
1405 		size_t index = r->t == BC_RESULT_STR ? r->d.loc.loc : n->scale;
1406 		str2 = *((char**) bc_vec_item(p->strs, index));
1407 		c = (uchar) str2[0];
1408 	}
1409 
1410 	str[0] = (char) c;
1411 	str[1] = '\0';
1412 
1413 	BC_SIG_LOCK;
1414 
1415 	idx = bc_program_insertFunc(p, str) - BC_PROG_REQ_FUNCS;
1416 
1417 	BC_SIG_UNLOCK;
1418 
1419 	res.t = BC_RESULT_STR;
1420 	res.d.loc.loc = idx;
1421 	bc_vec_pop(&p->results);
1422 	bc_vec_push(&p->results, &res);
1423 }
1424 
1425 static void bc_program_printStream(BcProgram *p) {
1426 
1427 	BcResult *r;
1428 	BcNum *n;
1429 
1430 	if (BC_ERR(!BC_PROG_STACK(&p->results, 1))) bc_vm_err(BC_ERR_EXEC_STACK);
1431 
1432 	assert(BC_PROG_STACK(&p->results, 1));
1433 
1434 	bc_program_operand(p, &r, &n, 0);
1435 
1436 	assert(n != NULL);
1437 
1438 	if (BC_PROG_NUM(r, n)) bc_num_stream(n, p->strm);
1439 	else {
1440 		size_t idx = (r->t == BC_RESULT_STR) ? r->d.loc.loc : n->scale;
1441 		bc_program_printChars(*((char**) bc_vec_item(p->strs, idx)));
1442 	}
1443 }
1444 
1445 static void bc_program_nquit(BcProgram *p, uchar inst) {
1446 
1447 	BcResult *opnd;
1448 	BcNum *num;
1449 	BcBigDig val;
1450 	size_t i;
1451 
1452 	assert(p->stack.len == p->tail_calls.len);
1453 
1454 	if (inst == BC_INST_QUIT) val = 2;
1455 	else {
1456 
1457 		bc_program_prep(p, &opnd, &num, 0);
1458 		bc_num_bigdig(num, &val);
1459 
1460 		bc_vec_pop(&p->results);
1461 	}
1462 
1463 	for (i = 0; val && i < p->tail_calls.len; ++i) {
1464 		size_t calls = *((size_t*) bc_vec_item_rev(&p->tail_calls, i)) + 1;
1465 		if (calls >= val) val = 0;
1466 		else val -= calls;
1467 	}
1468 
1469 	if (i == p->stack.len) {
1470 		vm.status = BC_STATUS_QUIT;
1471 		BC_VM_JMP;
1472 	}
1473 	else {
1474 		bc_vec_npop(&p->stack, i);
1475 		bc_vec_npop(&p->tail_calls, i);
1476 	}
1477 }
1478 
1479 static void bc_program_execStr(BcProgram *p, const char *restrict code,
1480                                    size_t *restrict bgn, bool cond, size_t len)
1481 {
1482 	BcResult *r;
1483 	char *str;
1484 	BcFunc *f;
1485 	BcParse prs;
1486 	BcInstPtr ip;
1487 	size_t fidx, sidx;
1488 	BcNum *n;
1489 
1490 	assert(p->stack.len == p->tail_calls.len);
1491 
1492 	if (BC_ERR(!BC_PROG_STACK(&p->results, 1))) bc_vm_err(BC_ERR_EXEC_STACK);
1493 
1494 	assert(BC_PROG_STACK(&p->results, 1));
1495 
1496 	bc_program_operand(p, &r, &n, 0);
1497 
1498 	if (cond) {
1499 
1500 		bool exec;
1501 		size_t idx, then_idx, else_idx;
1502 
1503 		then_idx = bc_program_index(code, bgn);
1504 		else_idx = bc_program_index(code, bgn);
1505 
1506 		exec = (r->d.n.len != 0);
1507 
1508 		idx = exec ? then_idx : else_idx;
1509 
1510 		BC_SIG_LOCK;
1511 		BC_SETJMP_LOCKED(exit);
1512 
1513 		if (exec || (else_idx != SIZE_MAX))
1514 			n = bc_vec_top(bc_program_vec(p, idx, BC_TYPE_VAR));
1515 		else goto exit;
1516 
1517 		if (BC_ERR(!BC_PROG_STR(n))) bc_vm_err(BC_ERR_EXEC_TYPE);
1518 
1519 		BC_UNSETJMP;
1520 		BC_SIG_UNLOCK;
1521 
1522 		sidx = n->scale;
1523 	}
1524 	else {
1525 
1526 		// In non-conditional situations, only the top of stack can be executed,
1527 		// and in those cases, variables are not allowed to be "on the stack";
1528 		// they are only put on the stack to be assigned to.
1529 		assert(r->t != BC_RESULT_VAR);
1530 
1531 		if (r->t == BC_RESULT_STR) sidx = r->d.loc.loc;
1532 		else return;
1533 	}
1534 
1535 	fidx = sidx + BC_PROG_REQ_FUNCS;
1536 	str = *((char**) bc_vec_item(p->strs, sidx));
1537 	f = bc_vec_item(&p->fns, fidx);
1538 
1539 	if (!f->code.len) {
1540 
1541 		BC_SIG_LOCK;
1542 
1543 		bc_parse_init(&prs, p, fidx);
1544 		bc_lex_file(&prs.l, vm.file);
1545 
1546 		BC_SETJMP_LOCKED(err);
1547 
1548 		BC_SIG_UNLOCK;
1549 
1550 		bc_parse_text(&prs, str);
1551 		vm.expr(&prs, BC_PARSE_NOCALL);
1552 
1553 		BC_SIG_LOCK;
1554 
1555 		BC_UNSETJMP;
1556 
1557 		// We can just assert this here because
1558 		// dc should parse everything until EOF.
1559 		assert(prs.l.t == BC_LEX_EOF);
1560 
1561 		bc_parse_free(&prs);
1562 
1563 		BC_SIG_UNLOCK;
1564 	}
1565 
1566 	ip.idx = 0;
1567 	ip.len = p->results.len;
1568 	ip.func = fidx;
1569 
1570 	bc_vec_pop(&p->results);
1571 
1572 	// Tail call.
1573 	if (p->stack.len > 1 && *bgn == len - 1 && code[*bgn] == BC_INST_POP_EXEC) {
1574 		size_t *call_ptr = bc_vec_top(&p->tail_calls);
1575 		*call_ptr += 1;
1576 		bc_vec_pop(&p->stack);
1577 	}
1578 	else bc_vec_push(&p->tail_calls, &ip.idx);
1579 
1580 	bc_vec_push(&p->stack, &ip);
1581 
1582 	return;
1583 
1584 err:
1585 	BC_SIG_MAYLOCK;
1586 	bc_parse_free(&prs);
1587 	f = bc_vec_item(&p->fns, fidx);
1588 	bc_vec_popAll(&f->code);
1589 exit:
1590 	bc_vec_pop(&p->results);
1591 	BC_LONGJMP_CONT;
1592 }
1593 
1594 static void bc_program_printStack(BcProgram *p) {
1595 
1596 	size_t idx;
1597 
1598 	for (idx = 0; idx < p->results.len; ++idx)
1599 		bc_program_print(p, BC_INST_PRINT, idx);
1600 }
1601 #endif // DC_ENABLED
1602 
1603 static void bc_program_pushGlobal(BcProgram *p, uchar inst) {
1604 
1605 	BcResultType t;
1606 
1607 	assert(inst >= BC_INST_IBASE && inst <= BC_INST_SCALE);
1608 
1609 	t = inst - BC_INST_IBASE + BC_RESULT_IBASE;
1610 	bc_program_pushBigdig(p, p->globals[inst - BC_INST_IBASE], t);
1611 }
1612 
1613 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1614 static void bc_program_pushSeed(BcProgram *p) {
1615 
1616 	BcResult *res;
1617 
1618 	res = bc_program_prepResult(p);
1619 	res->t = BC_RESULT_SEED;
1620 
1621 	BC_SIG_LOCK;
1622 
1623 	bc_num_init(&res->d.n, 2 * BC_RAND_NUM_SIZE);
1624 
1625 	BC_SIG_UNLOCK;
1626 
1627 	bc_num_createFromRNG(&res->d.n, &p->rng);
1628 }
1629 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1630 
1631 static void bc_program_addFunc(BcProgram *p, BcFunc *f, BcId *id_ptr) {
1632 
1633 	BcInstPtr *ip;
1634 
1635 	BC_SIG_ASSERT_LOCKED;
1636 
1637 	bc_func_init(f, id_ptr->name);
1638 	bc_vec_push(&p->fns, f);
1639 
1640 	// This is to make sure pointers are updated if the array was moved.
1641 	if (p->stack.len) {
1642 		ip = bc_vec_top(&p->stack);
1643 		bc_program_setVecs(p, (BcFunc*) bc_vec_item(&p->fns, ip->func));
1644 	}
1645 }
1646 
1647 size_t bc_program_insertFunc(BcProgram *p, const char *name) {
1648 
1649 	BcId *id_ptr;
1650 	BcFunc f;
1651 	bool new;
1652 	size_t idx;
1653 
1654 	BC_SIG_ASSERT_LOCKED;
1655 
1656 	assert(p != NULL && name != NULL);
1657 
1658 	new = bc_map_insert(&p->fn_map, name, p->fns.len, &idx);
1659 	id_ptr = (BcId*) bc_vec_item(&p->fn_map, idx);
1660 	idx = id_ptr->idx;
1661 
1662 	if (!new) {
1663 		if (BC_IS_BC) {
1664 			BcFunc *func = bc_vec_item(&p->fns, idx);
1665 			bc_func_reset(func);
1666 		}
1667 	}
1668 	else {
1669 
1670 		bc_program_addFunc(p, &f, id_ptr);
1671 
1672 #if DC_ENABLED
1673 		if (BC_IS_DC && idx >= BC_PROG_REQ_FUNCS) {
1674 			bc_vec_push(p->strs, &id_ptr->name);
1675 			assert(p->strs->len == p->fns.len - BC_PROG_REQ_FUNCS);
1676 		}
1677 #endif // DC_ENABLED
1678 	}
1679 
1680 	return idx;
1681 }
1682 
1683 #ifndef NDEBUG
1684 void bc_program_free(BcProgram *p) {
1685 
1686 	size_t i;
1687 
1688 	BC_SIG_ASSERT_LOCKED;
1689 
1690 	assert(p != NULL);
1691 
1692 	for (i = 0; i < BC_PROG_GLOBALS_LEN; ++i) bc_vec_free(p->globals_v + i);
1693 
1694 	bc_vec_free(&p->fns);
1695 	bc_vec_free(&p->fn_map);
1696 	bc_vec_free(&p->vars);
1697 	bc_vec_free(&p->var_map);
1698 	bc_vec_free(&p->arrs);
1699 	bc_vec_free(&p->arr_map);
1700 	bc_vec_free(&p->results);
1701 	bc_vec_free(&p->stack);
1702 
1703 #if BC_ENABLED
1704 	if (BC_IS_BC) bc_num_free(&p->last);
1705 #endif // BC_ENABLED
1706 
1707 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1708 	bc_rand_free(&p->rng);
1709 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1710 
1711 #if DC_ENABLED
1712 	if (BC_IS_DC) {
1713 		bc_vec_free(&p->tail_calls);
1714 		bc_vec_free(&p->strs_v);
1715 	}
1716 #endif // DC_ENABLED
1717 }
1718 #endif // NDEBUG
1719 
1720 void bc_program_init(BcProgram *p) {
1721 
1722 	BcInstPtr ip;
1723 	size_t i;
1724 
1725 	BC_SIG_ASSERT_LOCKED;
1726 
1727 	assert(p != NULL);
1728 
1729 	memset(p, 0, sizeof(BcProgram));
1730 	memset(&ip, 0, sizeof(BcInstPtr));
1731 
1732 	for (i = 0; i < BC_PROG_GLOBALS_LEN; ++i) {
1733 		BcBigDig val = i == BC_PROG_GLOBALS_SCALE ? 0 : BC_BASE;
1734 		bc_vec_init(p->globals_v + i, sizeof(BcBigDig), NULL);
1735 		bc_vec_push(p->globals_v + i, &val);
1736 		p->globals[i] = val;
1737 	}
1738 
1739 #if DC_ENABLED
1740 	if (BC_IS_DC) {
1741 
1742 		bc_vec_init(&p->strs_v, sizeof(char*), bc_string_free);
1743 		p->strs = &p->strs_v;
1744 
1745 		bc_vec_init(&p->tail_calls, sizeof(size_t), NULL);
1746 		i = 0;
1747 		bc_vec_push(&p->tail_calls, &i);
1748 
1749 		p->strm = UCHAR_MAX + 1;
1750 		bc_num_setup(&p->strmb, p->strmb_num, BC_NUM_BIGDIG_LOG10);
1751 		bc_num_bigdig2num(&p->strmb, p->strm);
1752 	}
1753 #endif // DC_ENABLED
1754 
1755 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1756 	srand((unsigned int) time(NULL));
1757 	bc_rand_init(&p->rng);
1758 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1759 
1760 	bc_num_setup(&p->zero, p->zero_num, BC_PROG_ONE_CAP);
1761 
1762 	bc_num_setup(&p->one, p->one_num, BC_PROG_ONE_CAP);
1763 	bc_num_one(&p->one);
1764 
1765 #if BC_ENABLED
1766 	if (BC_IS_BC) bc_num_init(&p->last, BC_NUM_DEF_SIZE);
1767 #endif // BC_ENABLED
1768 
1769 	bc_vec_init(&p->fns, sizeof(BcFunc), bc_func_free);
1770 	bc_map_init(&p->fn_map);
1771 	bc_program_insertFunc(p, bc_func_main);
1772 	bc_program_insertFunc(p, bc_func_read);
1773 
1774 	bc_vec_init(&p->vars, sizeof(BcVec), bc_vec_free);
1775 	bc_map_init(&p->var_map);
1776 
1777 	bc_vec_init(&p->arrs, sizeof(BcVec), bc_vec_free);
1778 	bc_map_init(&p->arr_map);
1779 
1780 	bc_vec_init(&p->results, sizeof(BcResult), bc_result_free);
1781 	bc_vec_init(&p->stack, sizeof(BcInstPtr), NULL);
1782 	bc_vec_push(&p->stack, &ip);
1783 
1784 	bc_program_setVecs(p, (BcFunc*) bc_vec_item(&p->fns, BC_PROG_MAIN));
1785 
1786 	assert(p->consts != NULL && p->strs != NULL);
1787 }
1788 
1789 void bc_program_reset(BcProgram *p) {
1790 
1791 	BcFunc *f;
1792 	BcInstPtr *ip;
1793 
1794 	BC_SIG_ASSERT_LOCKED;
1795 
1796 	bc_vec_npop(&p->stack, p->stack.len - 1);
1797 	bc_vec_popAll(&p->results);
1798 
1799 #if BC_ENABLED
1800 	if (BC_G) bc_program_popGlobals(p, true);
1801 #endif // BC_ENABLED
1802 
1803 	f = bc_vec_item(&p->fns, BC_PROG_MAIN);
1804 	bc_vec_npop(&f->code, f->code.len);
1805 	ip = bc_vec_top(&p->stack);
1806 	bc_program_setVecs(p, f);
1807 	memset(ip, 0, sizeof(BcInstPtr));
1808 
1809 	if (vm.sig) {
1810 		bc_file_write(&vm.fout, bc_program_ready_msg, bc_program_ready_msg_len);
1811 		bc_file_flush(&vm.fout);
1812 		vm.sig = 0;
1813 	}
1814 }
1815 
1816 void bc_program_exec(BcProgram *p) {
1817 
1818 	size_t idx;
1819 	BcResult r, *ptr;
1820 	BcInstPtr *ip = bc_vec_top(&p->stack);
1821 	BcFunc *func = (BcFunc*) bc_vec_item(&p->fns, ip->func);
1822 	char *code = func->code.v;
1823 	bool cond = false;
1824 #if BC_ENABLED
1825 	BcNum *num;
1826 #endif // BC_ENABLED
1827 #ifndef NDEBUG
1828 	size_t jmp_bufs_len;
1829 #endif // NDEBUG
1830 
1831 #ifndef NDEBUG
1832 	jmp_bufs_len = vm.jmp_bufs.len;
1833 #endif // NDEBUG
1834 
1835 	bc_program_setVecs(p, func);
1836 
1837 	while (ip->idx < func->code.len) {
1838 
1839 		BC_SIG_ASSERT_NOT_LOCKED;
1840 
1841 		uchar inst = (uchar) code[(ip->idx)++];
1842 
1843 		switch (inst) {
1844 
1845 #if BC_ENABLED
1846 			case BC_INST_JUMP_ZERO:
1847 			{
1848 				bc_program_prep(p, &ptr, &num, 0);
1849 				cond = !bc_num_cmpZero(num);
1850 				bc_vec_pop(&p->results);
1851 			}
1852 			// Fallthrough.
1853 			BC_FALLTHROUGH
1854 
1855 			case BC_INST_JUMP:
1856 			{
1857 				idx = bc_program_index(code, &ip->idx);
1858 
1859 				if (inst == BC_INST_JUMP || cond) {
1860 
1861 					size_t *addr = bc_vec_item(&func->labels, idx);
1862 
1863 					assert(*addr != SIZE_MAX);
1864 
1865 					ip->idx = *addr;
1866 				}
1867 
1868 				break;
1869 			}
1870 
1871 			case BC_INST_CALL:
1872 			{
1873 				assert(BC_IS_BC);
1874 
1875 				bc_program_call(p, code, &ip->idx);
1876 
1877 				ip = bc_vec_top(&p->stack);
1878 				func = bc_vec_item(&p->fns, ip->func);
1879 				code = func->code.v;
1880 
1881 				bc_program_setVecs(p, func);
1882 
1883 				break;
1884 			}
1885 
1886 			case BC_INST_INC:
1887 			case BC_INST_DEC:
1888 			{
1889 				bc_program_incdec(p, inst);
1890 				break;
1891 			}
1892 
1893 			case BC_INST_HALT:
1894 			{
1895 				vm.status = BC_STATUS_QUIT;
1896 				BC_VM_JMP;
1897 				break;
1898 			}
1899 
1900 			case BC_INST_RET:
1901 			case BC_INST_RET0:
1902 			case BC_INST_RET_VOID:
1903 			{
1904 				bc_program_return(p, inst);
1905 
1906 				ip = bc_vec_top(&p->stack);
1907 				func = bc_vec_item(&p->fns, ip->func);
1908 				code = func->code.v;
1909 
1910 				bc_program_setVecs(p, func);
1911 
1912 				break;
1913 			}
1914 #endif // BC_ENABLED
1915 
1916 			case BC_INST_BOOL_OR:
1917 			case BC_INST_BOOL_AND:
1918 			case BC_INST_REL_EQ:
1919 			case BC_INST_REL_LE:
1920 			case BC_INST_REL_GE:
1921 			case BC_INST_REL_NE:
1922 			case BC_INST_REL_LT:
1923 			case BC_INST_REL_GT:
1924 			{
1925 				bc_program_logical(p, inst);
1926 				break;
1927 			}
1928 
1929 			case BC_INST_READ:
1930 			{
1931 				// We want to flush output before
1932 				// this in case there is a prompt.
1933 				bc_file_flush(&vm.fout);
1934 
1935 				bc_program_read(p);
1936 
1937 				ip = bc_vec_top(&p->stack);
1938 				func = bc_vec_item(&p->fns, ip->func);
1939 				code = func->code.v;
1940 
1941 				bc_program_setVecs(p, func);
1942 
1943 				break;
1944 			}
1945 
1946 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1947 			case BC_INST_RAND:
1948 			{
1949 				bc_program_rand(p);
1950 				break;
1951 			}
1952 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1953 
1954 			case BC_INST_MAXIBASE:
1955 			case BC_INST_MAXOBASE:
1956 			case BC_INST_MAXSCALE:
1957 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1958 			case BC_INST_MAXRAND:
1959 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1960 			{
1961 				BcBigDig dig = vm.maxes[inst - BC_INST_MAXIBASE];
1962 				bc_program_pushBigdig(p, dig, BC_RESULT_TEMP);
1963 				break;
1964 			}
1965 
1966 			case BC_INST_VAR:
1967 			{
1968 				bc_program_pushVar(p, code, &ip->idx, false, false);
1969 				break;
1970 			}
1971 
1972 			case BC_INST_ARRAY_ELEM:
1973 #if BC_ENABLED
1974 			case BC_INST_ARRAY:
1975 #endif // BC_ENABLED
1976 			{
1977 				bc_program_pushArray(p, code, &ip->idx, inst);
1978 				break;
1979 			}
1980 
1981 			case BC_INST_IBASE:
1982 			case BC_INST_SCALE:
1983 			case BC_INST_OBASE:
1984 			{
1985 				bc_program_pushGlobal(p, inst);
1986 				break;
1987 			}
1988 
1989 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1990 			case BC_INST_SEED:
1991 			{
1992 				bc_program_pushSeed(p);
1993 				break;
1994 			}
1995 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1996 
1997 			case BC_INST_LENGTH:
1998 			case BC_INST_SCALE_FUNC:
1999 			case BC_INST_SQRT:
2000 			case BC_INST_ABS:
2001 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
2002 			case BC_INST_IRAND:
2003 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
2004 			{
2005 				bc_program_builtin(p, inst);
2006 				break;
2007 			}
2008 
2009 			case BC_INST_NUM:
2010 			{
2011 				bc_program_const(p, code, &ip->idx);
2012 				break;
2013 			}
2014 
2015 			case BC_INST_ZERO:
2016 			case BC_INST_ONE:
2017 #if BC_ENABLED
2018 			case BC_INST_LAST:
2019 #endif // BC_ENABLED
2020 			{
2021 				r.t = BC_RESULT_ZERO + (inst - BC_INST_ZERO);
2022 				bc_vec_push(&p->results, &r);
2023 				break;
2024 			}
2025 
2026 			case BC_INST_PRINT:
2027 			case BC_INST_PRINT_POP:
2028 			case BC_INST_PRINT_STR:
2029 			{
2030 				bc_program_print(p, inst, 0);
2031 				break;
2032 			}
2033 
2034 			case BC_INST_STR:
2035 			{
2036 				r.t = BC_RESULT_STR;
2037 				r.d.loc.loc = bc_program_index(code, &ip->idx);
2038 				bc_vec_push(&p->results, &r);
2039 				break;
2040 			}
2041 
2042 			case BC_INST_POWER:
2043 			case BC_INST_MULTIPLY:
2044 			case BC_INST_DIVIDE:
2045 			case BC_INST_MODULUS:
2046 			case BC_INST_PLUS:
2047 			case BC_INST_MINUS:
2048 #if BC_ENABLE_EXTRA_MATH
2049 			case BC_INST_PLACES:
2050 			case BC_INST_LSHIFT:
2051 			case BC_INST_RSHIFT:
2052 #endif // BC_ENABLE_EXTRA_MATH
2053 			{
2054 				bc_program_op(p, inst);
2055 				break;
2056 			}
2057 
2058 			case BC_INST_NEG:
2059 			case BC_INST_BOOL_NOT:
2060 #if BC_ENABLE_EXTRA_MATH
2061 			case BC_INST_TRUNC:
2062 #endif // BC_ENABLE_EXTRA_MATH
2063 			{
2064 				bc_program_unary(p, inst);
2065 				break;
2066 			}
2067 
2068 #if BC_ENABLED
2069 			case BC_INST_ASSIGN_POWER:
2070 			case BC_INST_ASSIGN_MULTIPLY:
2071 			case BC_INST_ASSIGN_DIVIDE:
2072 			case BC_INST_ASSIGN_MODULUS:
2073 			case BC_INST_ASSIGN_PLUS:
2074 			case BC_INST_ASSIGN_MINUS:
2075 #if BC_ENABLE_EXTRA_MATH
2076 			case BC_INST_ASSIGN_PLACES:
2077 			case BC_INST_ASSIGN_LSHIFT:
2078 			case BC_INST_ASSIGN_RSHIFT:
2079 #endif // BC_ENABLE_EXTRA_MATH
2080 			case BC_INST_ASSIGN:
2081 			case BC_INST_ASSIGN_POWER_NO_VAL:
2082 			case BC_INST_ASSIGN_MULTIPLY_NO_VAL:
2083 			case BC_INST_ASSIGN_DIVIDE_NO_VAL:
2084 			case BC_INST_ASSIGN_MODULUS_NO_VAL:
2085 			case BC_INST_ASSIGN_PLUS_NO_VAL:
2086 			case BC_INST_ASSIGN_MINUS_NO_VAL:
2087 #if BC_ENABLE_EXTRA_MATH
2088 			case BC_INST_ASSIGN_PLACES_NO_VAL:
2089 			case BC_INST_ASSIGN_LSHIFT_NO_VAL:
2090 			case BC_INST_ASSIGN_RSHIFT_NO_VAL:
2091 #endif // BC_ENABLE_EXTRA_MATH
2092 #endif // BC_ENABLED
2093 			case BC_INST_ASSIGN_NO_VAL:
2094 			{
2095 				bc_program_assign(p, inst);
2096 				break;
2097 			}
2098 
2099 			case BC_INST_POP:
2100 			{
2101 #ifndef BC_PROG_NO_STACK_CHECK
2102 				if (!BC_IS_BC) {
2103 					if (BC_ERR(!BC_PROG_STACK(&p->results, 1)))
2104 						bc_vm_err(BC_ERR_EXEC_STACK);
2105 				}
2106 #endif // BC_PROG_NO_STACK_CHECK
2107 
2108 				assert(BC_PROG_STACK(&p->results, 1));
2109 
2110 				bc_vec_pop(&p->results);
2111 				break;
2112 			}
2113 
2114 #if DC_ENABLED
2115 			case BC_INST_POP_EXEC:
2116 			{
2117 				assert(BC_PROG_STACK(&p->stack, 2));
2118 				bc_vec_pop(&p->stack);
2119 				bc_vec_pop(&p->tail_calls);
2120 				ip = bc_vec_top(&p->stack);
2121 				func = bc_vec_item(&p->fns, ip->func);
2122 				code = func->code.v;
2123 				bc_program_setVecs(p, func);
2124 				break;
2125 			}
2126 
2127 			case BC_INST_MODEXP:
2128 			{
2129 				bc_program_modexp(p);
2130 				break;
2131 			}
2132 
2133 			case BC_INST_DIVMOD:
2134 			{
2135 				bc_program_divmod(p);
2136 				break;
2137 			}
2138 
2139 			case BC_INST_EXECUTE:
2140 			case BC_INST_EXEC_COND:
2141 			{
2142 				cond = (inst == BC_INST_EXEC_COND);
2143 				bc_program_execStr(p, code, &ip->idx, cond, func->code.len);
2144 				ip = bc_vec_top(&p->stack);
2145 				func = bc_vec_item(&p->fns, ip->func);
2146 				code = func->code.v;
2147 				bc_program_setVecs(p, func);
2148 				break;
2149 			}
2150 
2151 			case BC_INST_PRINT_STACK:
2152 			{
2153 				bc_program_printStack(p);
2154 				break;
2155 			}
2156 
2157 			case BC_INST_CLEAR_STACK:
2158 			{
2159 				bc_vec_popAll(&p->results);
2160 				break;
2161 			}
2162 
2163 			case BC_INST_STACK_LEN:
2164 			{
2165 				bc_program_stackLen(p);
2166 				break;
2167 			}
2168 
2169 			case BC_INST_DUPLICATE:
2170 			{
2171 				if (BC_ERR(!BC_PROG_STACK(&p->results, 1)))
2172 					bc_vm_err(BC_ERR_EXEC_STACK);
2173 
2174 				assert(BC_PROG_STACK(&p->results, 1));
2175 
2176 				ptr = bc_vec_top(&p->results);
2177 
2178 				BC_SIG_LOCK;
2179 
2180 				bc_result_copy(&r, ptr);
2181 				bc_vec_push(&p->results, &r);
2182 
2183 				BC_SIG_UNLOCK;
2184 
2185 				break;
2186 			}
2187 
2188 			case BC_INST_SWAP:
2189 			{
2190 				BcResult *ptr2;
2191 
2192 				if (BC_ERR(!BC_PROG_STACK(&p->results, 2)))
2193 					bc_vm_err(BC_ERR_EXEC_STACK);
2194 
2195 				assert(BC_PROG_STACK(&p->results, 2));
2196 
2197 				ptr = bc_vec_item_rev(&p->results, 0);
2198 				ptr2 = bc_vec_item_rev(&p->results, 1);
2199 				memcpy(&r, ptr, sizeof(BcResult));
2200 				memcpy(ptr, ptr2, sizeof(BcResult));
2201 				memcpy(ptr2, &r, sizeof(BcResult));
2202 
2203 				break;
2204 			}
2205 
2206 			case BC_INST_ASCIIFY:
2207 			{
2208 				bc_program_asciify(p);
2209 				ip = bc_vec_top(&p->stack);
2210 				func = bc_vec_item(&p->fns, ip->func);
2211 				code = func->code.v;
2212 				bc_program_setVecs(p, func);
2213 				break;
2214 			}
2215 
2216 			case BC_INST_PRINT_STREAM:
2217 			{
2218 				bc_program_printStream(p);
2219 				break;
2220 			}
2221 
2222 			case BC_INST_LOAD:
2223 			case BC_INST_PUSH_VAR:
2224 			{
2225 				bool copy = (inst == BC_INST_LOAD);
2226 				bc_program_pushVar(p, code, &ip->idx, true, copy);
2227 				break;
2228 			}
2229 
2230 			case BC_INST_PUSH_TO_VAR:
2231 			{
2232 				idx = bc_program_index(code, &ip->idx);
2233 				bc_program_copyToVar(p, idx, BC_TYPE_VAR, true);
2234 				break;
2235 			}
2236 
2237 			case BC_INST_QUIT:
2238 			case BC_INST_NQUIT:
2239 			{
2240 				bc_program_nquit(p, inst);
2241 				ip = bc_vec_top(&p->stack);
2242 				func = bc_vec_item(&p->fns, ip->func);
2243 				code = func->code.v;
2244 				bc_program_setVecs(p, func);
2245 				break;
2246 			}
2247 #endif // DC_ENABLED
2248 #ifndef NDEBUG
2249 			default:
2250 			{
2251 				abort();
2252 			}
2253 #endif // NDEBUG
2254 		}
2255 
2256 #ifndef NDEBUG
2257 		// This is to allow me to use a debugger to see the last instruction,
2258 		// which will point to which function was the problem.
2259 		assert(jmp_bufs_len == vm.jmp_bufs.len);
2260 #endif // NDEBUG
2261 	}
2262 }
2263 
2264 #if BC_DEBUG_CODE
2265 #if BC_ENABLED && DC_ENABLED
2266 void bc_program_printStackDebug(BcProgram *p) {
2267 	bc_file_puts(&vm.fout, "-------------- Stack ----------\n");
2268 	bc_program_printStack(p);
2269 	bc_file_puts(&vm.fout, "-------------- Stack End ------\n");
2270 }
2271 
2272 static void bc_program_printIndex(const char *restrict code,
2273                                   size_t *restrict bgn)
2274 {
2275 	uchar byte, i, bytes = (uchar) code[(*bgn)++];
2276 	ulong val = 0;
2277 
2278 	for (byte = 1, i = 0; byte && i < bytes; ++i) {
2279 		byte = (uchar) code[(*bgn)++];
2280 		if (byte) val |= ((ulong) byte) << (CHAR_BIT * i);
2281 	}
2282 
2283 	bc_vm_printf(" (%lu) ", val);
2284 }
2285 
2286 static void bc_program_printStr(const BcProgram *p, const char *restrict code,
2287                          size_t *restrict bgn)
2288 {
2289 	size_t idx = bc_program_index(code, bgn);
2290 	char *s;
2291 
2292 	s = *((char**) bc_vec_item(p->strs, idx));
2293 
2294 	bc_vm_printf(" (\"%s\") ", s);
2295 }
2296 
2297 void bc_program_printInst(const BcProgram *p, const char *restrict code,
2298                           size_t *restrict bgn)
2299 {
2300 	uchar inst = (uchar) code[(*bgn)++];
2301 
2302 	bc_vm_printf("Inst[%zu]: %s [%lu]; ", *bgn - 1,
2303 	             bc_inst_names[inst], (unsigned long) inst);
2304 
2305 	if (inst == BC_INST_VAR || inst == BC_INST_ARRAY_ELEM ||
2306 	    inst == BC_INST_ARRAY)
2307 	{
2308 		bc_program_printIndex(code, bgn);
2309 	}
2310 	else if (inst == BC_INST_STR) bc_program_printStr(p, code, bgn);
2311 	else if (inst == BC_INST_NUM) {
2312 		size_t idx = bc_program_index(code, bgn);
2313 		BcConst *c = bc_vec_item(p->consts, idx);
2314 		bc_vm_printf("(%s)", c->val);
2315 	}
2316 	else if (inst == BC_INST_CALL ||
2317 	         (inst > BC_INST_STR && inst <= BC_INST_JUMP_ZERO))
2318 	{
2319 		bc_program_printIndex(code, bgn);
2320 		if (inst == BC_INST_CALL) bc_program_printIndex(code, bgn);
2321 	}
2322 
2323 	bc_vm_putchar('\n');
2324 }
2325 
2326 void bc_program_code(const BcProgram* p) {
2327 
2328 	BcFunc *f;
2329 	char *code;
2330 	BcInstPtr ip;
2331 	size_t i;
2332 
2333 	for (i = 0; i < p->fns.len; ++i) {
2334 
2335 		ip.idx = ip.len = 0;
2336 		ip.func = i;
2337 
2338 		f = bc_vec_item(&p->fns, ip.func);
2339 		code = f->code.v;
2340 
2341 		bc_vm_printf("func[%zu]:\n", ip.func);
2342 		while (ip.idx < f->code.len) bc_program_printInst(p, code, &ip.idx);
2343 		bc_file_puts(&vm.fout, "\n\n");
2344 	}
2345 }
2346 #endif // BC_ENABLED && DC_ENABLED
2347 #endif // BC_DEBUG_CODE
2348