xref: /freebsd/contrib/bc/src/program.c (revision 9e5787d2284e187abb5b654d924394a65772e004)
1 /*
2  * *****************************************************************************
3  *
4  * SPDX-License-Identifier: BSD-2-Clause
5  *
6  * Copyright (c) 2018-2020 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_ERROR_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_ERROR_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 = NULL;
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_ERROR_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_ERROR_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_ERROR_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_ERROR_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_ERROR_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, !c->val[1]);
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 	bc_program_ops[idx](n1, n2, &res->d.n, BC_PROG_SCALE(p));
423 
424 	bc_program_retire(p, 1, 2);
425 }
426 
427 static void bc_program_read(BcProgram *p) {
428 
429 	BcStatus s;
430 	BcParse parse;
431 	BcVec buf;
432 	BcInstPtr ip;
433 	size_t i;
434 	const char* file;
435 	BcFunc *f = bc_vec_item(&p->fns, BC_PROG_READ);
436 
437 	for (i = 0; i < p->stack.len; ++i) {
438 		BcInstPtr *ip_ptr = bc_vec_item(&p->stack, i);
439 		if (ip_ptr->func == BC_PROG_READ)
440 			bc_vm_err(BC_ERROR_EXEC_REC_READ);
441 	}
442 
443 	BC_SIG_LOCK;
444 
445 	file = vm.file;
446 	bc_parse_init(&parse, p, BC_PROG_READ);
447 	bc_vec_init(&buf, sizeof(char), NULL);
448 
449 	BC_SETJMP_LOCKED(exec_err);
450 
451 	BC_SIG_UNLOCK;
452 
453 	bc_lex_file(&parse.l, bc_program_stdin_name);
454 	bc_vec_npop(&f->code, f->code.len);
455 
456 	s = bc_read_line(&buf, BC_IS_BC ? "read> " : "?> ");
457 	if (s == BC_STATUS_EOF) bc_vm_err(BC_ERROR_EXEC_READ_EXPR);
458 
459 	bc_parse_text(&parse, buf.v);
460 	vm.expr(&parse, BC_PARSE_NOREAD | BC_PARSE_NEEDVAL);
461 
462 	if (BC_ERR(parse.l.t != BC_LEX_NLINE && parse.l.t != BC_LEX_EOF))
463 		bc_vm_err(BC_ERROR_EXEC_READ_EXPR);
464 
465 #if BC_ENABLED
466 	if (BC_G) bc_program_prepGlobals(p);
467 #endif // BC_ENABLED
468 
469 	ip.func = BC_PROG_READ;
470 	ip.idx = 0;
471 	ip.len = p->results.len;
472 
473 	// Update this pointer, just in case.
474 	f = bc_vec_item(&p->fns, BC_PROG_READ);
475 
476 	bc_vec_pushByte(&f->code, vm.read_ret);
477 	bc_vec_push(&p->stack, &ip);
478 
479 #if DC_ENABLED
480 	if (BC_IS_DC) {
481 		size_t temp = 0;
482 		bc_vec_push(&p->tail_calls, &temp);
483 	}
484 #endif // DC_ENABLED
485 
486 exec_err:
487 	BC_SIG_MAYLOCK;
488 	bc_parse_free(&parse);
489 	bc_vec_free(&buf);
490 	vm.file = file;
491 	BC_LONGJMP_CONT;
492 }
493 
494 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
495 static void bc_program_rand(BcProgram *p) {
496 	BcRand rand = bc_rand_int(&p->rng);
497 	bc_program_pushBigdig(p, (BcBigDig) rand, BC_RESULT_TEMP);
498 }
499 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
500 
501 static void bc_program_printChars(const char *str) {
502 
503 	const char *nl;
504 	size_t len = vm.nchars + strlen(str);
505 
506 	bc_file_puts(&vm.fout, str);
507 	nl = strrchr(str, '\n');
508 
509 	if (nl != NULL) len = strlen(nl + 1);
510 
511 	vm.nchars = len > UINT16_MAX ? UINT16_MAX : (uint16_t) len;
512 }
513 
514 static void bc_program_printString(const char *restrict str) {
515 
516 	size_t i, len = strlen(str);
517 
518 #if DC_ENABLED
519 	if (!len && BC_IS_DC) {
520 		bc_vm_putchar('\0');
521 		return;
522 	}
523 #endif // DC_ENABLED
524 
525 	for (i = 0; i < len; ++i) {
526 
527 		int c = str[i];
528 
529 		if (c == '\\' && i != len - 1) {
530 
531 			const char *ptr;
532 
533 			c = str[++i];
534 			ptr = strchr(bc_program_esc_chars, c);
535 
536 			if (ptr != NULL) {
537 				if (c == 'n') vm.nchars = UINT16_MAX;
538 				c = bc_program_esc_seqs[(size_t) (ptr - bc_program_esc_chars)];
539 			}
540 			else {
541 				// Just print the backslash. The following
542 				// character will be printed later.
543 				bc_vm_putchar('\\');
544 			}
545 		}
546 
547 		bc_vm_putchar(c);
548 	}
549 }
550 
551 static void bc_program_print(BcProgram *p, uchar inst, size_t idx) {
552 
553 	BcResult *r;
554 	char *str;
555 	BcNum *n;
556 	bool pop = (inst != BC_INST_PRINT);
557 
558 	assert(p != NULL);
559 
560 #ifndef BC_PROG_NO_STACK_CHECK
561 	if (BC_IS_DC) {
562 		if (BC_ERR(!BC_PROG_STACK(&p->results, idx + 1)))
563 			bc_vm_err(BC_ERROR_EXEC_STACK);
564 	}
565 #endif // BC_PROG_NO_STACK_CHECK
566 
567 	assert(BC_PROG_STACK(&p->results, idx + 1));
568 
569 	r = bc_vec_item_rev(&p->results, idx);
570 
571 #if BC_ENABLED
572 	if (r->t == BC_RESULT_VOID) {
573 		if (BC_ERR(pop)) bc_vm_err(BC_ERROR_EXEC_VOID_VAL);
574 		bc_vec_pop(&p->results);
575 		return;
576 	}
577 #endif // BC_ENABLED
578 
579 	n = bc_program_num(p, r);
580 
581 	if (BC_PROG_NUM(r, n)) {
582 		assert(inst != BC_INST_PRINT_STR);
583 		bc_num_print(n, BC_PROG_OBASE(p), !pop);
584 #if BC_ENABLED
585 		if (BC_IS_BC) bc_num_copy(&p->last, n);
586 #endif // BC_ENABLED
587 	}
588 	else {
589 
590 		size_t i = (r->t == BC_RESULT_STR) ? r->d.loc.loc : n->scale;
591 
592 		bc_file_flush(&vm.fout);
593 		str = *((char**) bc_vec_item(p->strs, i));
594 
595 		if (inst == BC_INST_PRINT_STR) bc_program_printChars(str);
596 		else {
597 			bc_program_printString(str);
598 			if (inst == BC_INST_PRINT) bc_vm_putchar('\n');
599 		}
600 	}
601 
602 	if (BC_IS_BC || pop) bc_vec_pop(&p->results);
603 }
604 
605 void bc_program_negate(BcResult *r, BcNum *n) {
606 	bc_num_copy(&r->d.n, n);
607 	if (BC_NUM_NONZERO(&r->d.n)) r->d.n.neg = !r->d.n.neg;
608 }
609 
610 void bc_program_not(BcResult *r, BcNum *n) {
611 	if (!bc_num_cmpZero(n)) bc_num_one(&r->d.n);
612 }
613 
614 #if BC_ENABLE_EXTRA_MATH
615 void bc_program_trunc(BcResult *r, BcNum *n) {
616 	bc_num_copy(&r->d.n, n);
617 	bc_num_truncate(&r->d.n, n->scale);
618 }
619 #endif // BC_ENABLE_EXTRA_MATH
620 
621 static void bc_program_unary(BcProgram *p, uchar inst) {
622 
623 	BcResult *res, *ptr;
624 	BcNum *num;
625 
626 	res = bc_program_prepResult(p);
627 
628 	bc_program_prep(p, &ptr, &num, 1);
629 
630 	BC_SIG_LOCK;
631 
632 	bc_num_init(&res->d.n, num->len);
633 
634 	BC_SIG_UNLOCK;
635 
636 	bc_program_unarys[inst - BC_INST_NEG](res, num);
637 	bc_program_retire(p, 1, 1);
638 }
639 
640 static void bc_program_logical(BcProgram *p, uchar inst) {
641 
642 	BcResult *opd1, *opd2, *res;
643 	BcNum *n1, *n2;
644 	bool cond = 0;
645 	ssize_t cmp;
646 
647 	res = bc_program_prepResult(p);
648 
649 	bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2, 1);
650 
651 	if (inst == BC_INST_BOOL_AND)
652 		cond = (bc_num_cmpZero(n1) && bc_num_cmpZero(n2));
653 	else if (inst == BC_INST_BOOL_OR)
654 		cond = (bc_num_cmpZero(n1) || bc_num_cmpZero(n2));
655 	else {
656 
657 		cmp = bc_num_cmp(n1, n2);
658 
659 		switch (inst) {
660 
661 			case BC_INST_REL_EQ:
662 			{
663 				cond = (cmp == 0);
664 				break;
665 			}
666 
667 			case BC_INST_REL_LE:
668 			{
669 				cond = (cmp <= 0);
670 				break;
671 			}
672 
673 			case BC_INST_REL_GE:
674 			{
675 				cond = (cmp >= 0);
676 				break;
677 			}
678 
679 			case BC_INST_REL_NE:
680 			{
681 				cond = (cmp != 0);
682 				break;
683 			}
684 
685 			case BC_INST_REL_LT:
686 			{
687 				cond = (cmp < 0);
688 				break;
689 			}
690 
691 			case BC_INST_REL_GT:
692 			{
693 				cond = (cmp > 0);
694 				break;
695 			}
696 #ifndef NDEBUG
697 			default:
698 			{
699 				abort();
700 			}
701 #endif // NDEBUG
702 		}
703 	}
704 
705 	BC_SIG_LOCK;
706 
707 	bc_num_init(&res->d.n, BC_NUM_DEF_SIZE);
708 
709 	BC_SIG_UNLOCK;
710 
711 	if (cond) bc_num_one(&res->d.n);
712 
713 	bc_program_retire(p, 1, 2);
714 }
715 
716 #if DC_ENABLED
717 static void bc_program_assignStr(BcProgram *p, BcResult *r,
718                                  BcVec *v, bool push)
719 {
720 	BcNum n2;
721 
722 	bc_num_clear(&n2);
723 	n2.scale = r->d.loc.loc;
724 
725 	assert(BC_PROG_STACK(&p->results, 1 + !push));
726 
727 	if (!push) bc_vec_pop(v);
728 
729 	bc_vec_npop(&p->results, 1 + !push);
730 	bc_vec_push(v, &n2);
731 }
732 #endif // DC_ENABLED
733 
734 static void bc_program_copyToVar(BcProgram *p, size_t idx,
735                                  BcType t, bool last)
736 {
737 	BcResult *ptr = NULL, r;
738 	BcVec *vec;
739 	BcNum *n = NULL;
740 	bool var = (t == BC_TYPE_VAR);
741 
742 #if DC_ENABLED
743 	if (BC_IS_DC) {
744 
745 		if (BC_ERR(!BC_PROG_STACK(&p->results, 1)))
746 			bc_vm_err(BC_ERROR_EXEC_STACK);
747 
748 		assert(BC_PROG_STACK(&p->results, 1));
749 
750 		bc_program_operand(p, &ptr, &n, 0);
751 	}
752 #endif
753 
754 #if BC_ENABLED
755 	if (BC_IS_BC)
756 	{
757 		ptr = bc_vec_top(&p->results);
758 
759 		bc_program_type_match(ptr, t);
760 
761 		if (last) n = bc_program_num(p, ptr);
762 		else if (var)
763 			n = bc_vec_item_rev(bc_program_vec(p, ptr->d.loc.loc, t), 1);
764 	}
765 #endif // BC_ENABLED
766 
767 	vec = bc_program_vec(p, idx, t);
768 
769 #if DC_ENABLED
770 	if (BC_IS_DC && (ptr->t == BC_RESULT_STR || BC_PROG_STR(n))) {
771 		if (BC_ERR(!var)) bc_vm_err(BC_ERROR_EXEC_TYPE);
772 		bc_program_assignStr(p, ptr, vec, true);
773 		return;
774 	}
775 #endif // DC_ENABLED
776 
777 	BC_SIG_LOCK;
778 
779 	if (var) bc_num_createCopy(&r.d.n, n);
780 	else {
781 
782 		BcVec *v = (BcVec*) n, *rv = &r.d.v;
783 #if BC_ENABLED
784 		BcVec *parent;
785 		bool ref, ref_size;
786 
787 		parent = bc_program_vec(p, ptr->d.loc.loc, t);
788 		assert(parent != NULL);
789 
790 		if (!last) v = bc_vec_item_rev(parent, !last);
791 		assert(v != NULL);
792 
793 		ref = (v->size == sizeof(BcNum) && t == BC_TYPE_REF);
794 		ref_size = (v->size == sizeof(uchar));
795 
796 		if (ref || (ref_size && t == BC_TYPE_REF)) {
797 
798 			bc_vec_init(rv, sizeof(uchar), NULL);
799 
800 			if (ref) {
801 
802 				assert(parent->len >= (size_t) (!last + 1));
803 
804 				// Make sure the pointer was not invalidated.
805 				vec = bc_program_vec(p, idx, t);
806 
807 				bc_vec_pushIndex(rv, ptr->d.loc.loc);
808 				bc_vec_pushIndex(rv, parent->len - !last - 1);
809 			}
810 			// If we get here, we are copying a ref to a ref.
811 			else bc_vec_npush(rv, v->len * sizeof(uchar), v->v);
812 
813 			// We need to return early.
814 			bc_vec_push(vec, &r.d);
815 			bc_vec_pop(&p->results);
816 
817 			BC_SIG_UNLOCK;
818 			return;
819 		}
820 		else if (ref_size && t != BC_TYPE_REF) v = bc_program_dereference(p, v);
821 #endif // BC_ENABLED
822 
823 		bc_array_init(rv, true);
824 		bc_array_copy(rv, v);
825 	}
826 
827 	bc_vec_push(vec, &r.d);
828 	bc_vec_pop(&p->results);
829 
830 	BC_SIG_UNLOCK;
831 }
832 
833 static void bc_program_assign(BcProgram *p, uchar inst) {
834 
835 	BcResult *left, *right, res;
836 	BcNum *l, *r;
837 	bool ob, sc, use_val = BC_INST_USE_VAL(inst);
838 
839 	bc_program_assignPrep(p, &left, &l, &right, &r);
840 
841 #if DC_ENABLED
842 	assert(left->t != BC_RESULT_STR);
843 
844 	if (right->t == BC_RESULT_STR || BC_PROG_STR(r)) {
845 
846 		size_t idx = right->t == BC_RESULT_STR ? right->d.loc.loc : r->scale;
847 
848 		if (left->t == BC_RESULT_ARRAY_ELEM) {
849 			BC_SIG_LOCK;
850 			bc_num_free(l);
851 			bc_num_clear(l);
852 			l->scale = idx;
853 			bc_vec_npop(&p->results, 2);
854 			BC_SIG_UNLOCK;
855 		}
856 		else {
857 			BcVec *v = bc_program_vec(p, left->d.loc.loc, BC_TYPE_VAR);
858 			bc_program_assignStr(p, right, v, false);
859 		}
860 
861 		return;
862 	}
863 #endif // DC_ENABLED
864 
865 	if (BC_INST_IS_ASSIGN(inst)) bc_num_copy(l, r);
866 #if BC_ENABLED
867 	else {
868 
869 		BcBigDig scale = BC_PROG_SCALE(p);
870 
871 		if (!use_val)
872 			inst -= (BC_INST_ASSIGN_POWER_NO_VAL - BC_INST_ASSIGN_POWER);
873 
874 		bc_program_ops[inst - BC_INST_ASSIGN_POWER](l, r, l, scale);
875 	}
876 #endif // BC_ENABLED
877 
878 	ob = (left->t == BC_RESULT_OBASE);
879 	sc = (left->t == BC_RESULT_SCALE);
880 
881 	if (ob || sc || left->t == BC_RESULT_IBASE) {
882 
883 		BcVec *v;
884 		BcBigDig *ptr, *ptr_t, val, max, min;
885 		BcError e;
886 
887 		bc_num_bigdig(l, &val);
888 		e = left->t - BC_RESULT_IBASE + BC_ERROR_EXEC_IBASE;
889 
890 		if (sc) {
891 			min = 0;
892 			max = vm.maxes[BC_PROG_GLOBALS_SCALE];
893 			v = p->globals_v + BC_PROG_GLOBALS_SCALE;
894 			ptr_t = p->globals + BC_PROG_GLOBALS_SCALE;
895 		}
896 		else {
897 			min = BC_NUM_MIN_BASE;
898 			if (BC_ENABLE_EXTRA_MATH && ob && (BC_IS_DC || !BC_IS_POSIX))
899 				min = 0;
900 			max = vm.maxes[ob + BC_PROG_GLOBALS_IBASE];
901 			v = p->globals_v + BC_PROG_GLOBALS_IBASE + ob;
902 			ptr_t = p->globals + BC_PROG_GLOBALS_IBASE + ob;
903 		}
904 
905 		if (BC_ERR(val > max || val < min)) bc_vm_verr(e, min, max);
906 
907 		ptr = bc_vec_top(v);
908 		*ptr = val;
909 		*ptr_t = val;
910 	}
911 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
912 	else if (left->t == BC_RESULT_SEED) bc_num_rng(l, &p->rng);
913 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
914 
915 	BC_SIG_LOCK;
916 
917 	if (use_val) {
918 		bc_num_createCopy(&res.d.n, l);
919 		res.t = BC_RESULT_TEMP;
920 		bc_vec_npop(&p->results, 2);
921 		bc_vec_push(&p->results, &res);
922 	}
923 	else bc_vec_npop(&p->results, 2);
924 
925 	BC_SIG_UNLOCK;
926 }
927 
928 static void bc_program_pushVar(BcProgram *p, const char *restrict code,
929                                size_t *restrict bgn, bool pop, bool copy)
930 {
931 	BcResult r;
932 	size_t idx = bc_program_index(code, bgn);
933 
934 	r.t = BC_RESULT_VAR;
935 	r.d.loc.loc = idx;
936 
937 #if DC_ENABLED
938 	if (BC_IS_DC && (pop || copy)) {
939 
940 		BcVec *v = bc_program_vec(p, idx, BC_TYPE_VAR);
941 		BcNum *num = bc_vec_top(v);
942 
943 		if (BC_ERR(!BC_PROG_STACK(v, 2 - copy))) bc_vm_err(BC_ERROR_EXEC_STACK);
944 
945 		assert(BC_PROG_STACK(v, 2 - copy));
946 
947 		if (!BC_PROG_STR(num)) {
948 
949 			BC_SIG_LOCK;
950 
951 			r.t = BC_RESULT_TEMP;
952 			bc_num_createCopy(&r.d.n, num);
953 
954 			if (!copy) bc_vec_pop(v);
955 
956 			bc_vec_push(&p->results, &r);
957 
958 			BC_SIG_UNLOCK;
959 
960 			return;
961 		}
962 		else {
963 			r.d.loc.loc = num->scale;
964 			r.t = BC_RESULT_STR;
965 		}
966 
967 		if (!copy) bc_vec_pop(v);
968 	}
969 #endif // DC_ENABLED
970 
971 	bc_vec_push(&p->results, &r);
972 }
973 
974 static void bc_program_pushArray(BcProgram *p, const char *restrict code,
975                                  size_t *restrict bgn, uchar inst)
976 {
977 	BcResult r, *operand;
978 	BcNum *num;
979 	BcBigDig temp;
980 
981 	r.d.loc.loc = bc_program_index(code, bgn);
982 
983 #if BC_ENABLED
984 	if (inst == BC_INST_ARRAY) {
985 		r.t = BC_RESULT_ARRAY;
986 		bc_vec_push(&p->results, &r);
987 		return;
988 	}
989 #endif // BC_ENABLED
990 
991 	bc_program_prep(p, &operand, &num, 0);
992 	bc_num_bigdig(num, &temp);
993 
994 	r.t = BC_RESULT_ARRAY_ELEM;
995 	r.d.loc.idx = (size_t) temp;
996 
997 	BC_SIG_LOCK;
998 
999 	bc_vec_pop(&p->results);
1000 	bc_vec_push(&p->results, &r);
1001 
1002 	BC_SIG_UNLOCK;
1003 }
1004 
1005 #if BC_ENABLED
1006 static void bc_program_incdec(BcProgram *p, uchar inst) {
1007 
1008 	BcResult *ptr, res, copy;
1009 	BcNum *num;
1010 	uchar inst2;
1011 
1012 	bc_program_prep(p, &ptr, &num, 0);
1013 
1014 	BC_SIG_LOCK;
1015 
1016 	copy.t = BC_RESULT_TEMP;
1017 	bc_num_createCopy(&copy.d.n, num);
1018 
1019 	BC_SETJMP_LOCKED(exit);
1020 
1021 	BC_SIG_UNLOCK;
1022 
1023 	res.t = BC_RESULT_ONE;
1024 	inst2 = BC_INST_ASSIGN_PLUS + (inst & 0x01);
1025 
1026 	bc_vec_push(&p->results, &res);
1027 	bc_program_assign(p, inst2);
1028 
1029 	BC_SIG_LOCK;
1030 
1031 	bc_vec_pop(&p->results);
1032 	bc_vec_push(&p->results, &copy);
1033 
1034 	BC_UNSETJMP;
1035 
1036 	BC_SIG_UNLOCK;
1037 
1038 	return;
1039 
1040 exit:
1041 	BC_SIG_MAYLOCK;
1042 	bc_num_free(&copy.d.n);
1043 	BC_LONGJMP_CONT;
1044 }
1045 
1046 static void bc_program_call(BcProgram *p, const char *restrict code,
1047                             size_t *restrict idx)
1048 {
1049 	BcInstPtr ip;
1050 	size_t i, nparams = bc_program_index(code, idx);
1051 	BcFunc *f;
1052 	BcVec *v;
1053 	BcLoc *a;
1054 	BcResultData param;
1055 	BcResult *arg;
1056 
1057 	ip.idx = 0;
1058 	ip.func = bc_program_index(code, idx);
1059 	f = bc_vec_item(&p->fns, ip.func);
1060 
1061 	if (BC_ERR(!f->code.len)) bc_vm_verr(BC_ERROR_EXEC_UNDEF_FUNC, f->name);
1062 	if (BC_ERR(nparams != f->nparams))
1063 		bc_vm_verr(BC_ERROR_EXEC_PARAMS, f->nparams, nparams);
1064 	ip.len = p->results.len - nparams;
1065 
1066 	assert(BC_PROG_STACK(&p->results, nparams));
1067 
1068 	if (BC_G) bc_program_prepGlobals(p);
1069 
1070 	for (i = 0; i < nparams; ++i) {
1071 
1072 		size_t j;
1073 		bool last = true;
1074 
1075 		arg = bc_vec_top(&p->results);
1076 		if (BC_ERR(arg->t == BC_RESULT_VOID))
1077 			bc_vm_err(BC_ERROR_EXEC_VOID_VAL);
1078 
1079 		a = bc_vec_item(&f->autos, nparams - 1 - i);
1080 
1081 		// If I have already pushed to a var, I need to make sure I
1082 		// get the previous version, not the already pushed one.
1083 		if (arg->t == BC_RESULT_VAR || arg->t == BC_RESULT_ARRAY) {
1084 			for (j = 0; j < i && last; ++j) {
1085 				BcLoc *loc = bc_vec_item(&f->autos, nparams - 1 - j);
1086 				last = (arg->d.loc.loc != loc->loc ||
1087 				        (!loc->idx) != (arg->t == BC_RESULT_VAR));
1088 			}
1089 		}
1090 
1091 		bc_program_copyToVar(p, a->loc, (BcType) a->idx, last);
1092 	}
1093 
1094 	BC_SIG_LOCK;
1095 
1096 	for (; i < f->autos.len; ++i) {
1097 
1098 		a = bc_vec_item(&f->autos, i);
1099 		v = bc_program_vec(p, a->loc, (BcType) a->idx);
1100 
1101 		if (a->idx == BC_TYPE_VAR) {
1102 			bc_num_init(&param.n, BC_NUM_DEF_SIZE);
1103 			bc_vec_push(v, &param.n);
1104 		}
1105 		else {
1106 			assert(a->idx == BC_TYPE_ARRAY);
1107 			bc_array_init(&param.v, true);
1108 			bc_vec_push(v, &param.v);
1109 		}
1110 	}
1111 
1112 	bc_vec_push(&p->stack, &ip);
1113 
1114 	BC_SIG_UNLOCK;
1115 }
1116 
1117 static void bc_program_return(BcProgram *p, uchar inst) {
1118 
1119 	BcResult *res;
1120 	BcFunc *f;
1121 	BcInstPtr *ip = bc_vec_top(&p->stack);
1122 	size_t i, nops = p->results.len - ip->len;
1123 
1124 	assert(BC_PROG_STACK(&p->stack, 2));
1125 	assert(BC_PROG_STACK(&p->results, ip->len + (inst == BC_INST_RET)));
1126 
1127 	f = bc_vec_item(&p->fns, ip->func);
1128 	res = bc_program_prepResult(p);
1129 
1130 	if (inst == BC_INST_RET) {
1131 
1132 		BcNum *num;
1133 		BcResult *operand;
1134 
1135 		bc_program_operand(p, &operand, &num, 1);
1136 
1137 		BC_SIG_LOCK;
1138 
1139 		bc_num_createCopy(&res->d.n, num);
1140 	}
1141 	else if (inst == BC_INST_RET_VOID) res->t = BC_RESULT_VOID;
1142 	else {
1143 		BC_SIG_LOCK;
1144 		bc_num_init(&res->d.n, BC_NUM_DEF_SIZE);
1145 	}
1146 
1147 	BC_SIG_MAYUNLOCK;
1148 
1149 	// We need to pop arguments as well, so this takes that into account.
1150 	for (i = 0; i < f->autos.len; ++i) {
1151 
1152 		BcLoc *a = bc_vec_item(&f->autos, i);
1153 		BcVec *v = bc_program_vec(p, a->loc, (BcType) a->idx);
1154 
1155 		bc_vec_pop(v);
1156 	}
1157 
1158 	bc_program_retire(p, 1, nops);
1159 
1160 	if (BC_G) bc_program_popGlobals(p, false);
1161 
1162 	bc_vec_pop(&p->stack);
1163 }
1164 #endif // BC_ENABLED
1165 
1166 static void bc_program_builtin(BcProgram *p, uchar inst) {
1167 
1168 	BcResult *opd, *res;
1169 	BcNum *num;
1170 	bool len = (inst == BC_INST_LENGTH);
1171 
1172 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1173 	assert(inst >= BC_INST_LENGTH && inst <= BC_INST_IRAND);
1174 #else // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1175 	assert(inst >= BC_INST_LENGTH && inst <= BC_INST_ABS);
1176 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1177 
1178 #ifndef BC_PROG_NO_STACK_CHECK
1179 	if (BC_IS_DC) {
1180 		if (BC_ERR(!BC_PROG_STACK(&p->results, 1)))
1181 			bc_vm_err(BC_ERROR_EXEC_STACK);
1182 	}
1183 #endif // BC_PROG_NO_STACK_CHECK
1184 
1185 	assert(BC_PROG_STACK(&p->results, 1));
1186 
1187 	res = bc_program_prepResult(p);
1188 
1189 	bc_program_operand(p, &opd, &num, 1);
1190 
1191 	assert(num != NULL);
1192 
1193 #if DC_ENABLED
1194 	if (!len && inst != BC_INST_SCALE_FUNC) bc_program_type_num(opd, num);
1195 #endif // DC_ENABLED
1196 
1197 	if (inst == BC_INST_SQRT) bc_num_sqrt(num, &res->d.n, BC_PROG_SCALE(p));
1198 	else if (inst == BC_INST_ABS) {
1199 
1200 		BC_SIG_LOCK;
1201 
1202 		bc_num_createCopy(&res->d.n, num);
1203 
1204 		BC_SIG_UNLOCK;
1205 
1206 		res->d.n.neg = false;
1207 	}
1208 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1209 	else if (inst == BC_INST_IRAND) {
1210 
1211 		BC_SIG_LOCK;
1212 
1213 		bc_num_init(&res->d.n, num->len - num->rdx);
1214 
1215 		BC_SIG_UNLOCK;
1216 
1217 		bc_num_irand(num, &res->d.n, &p->rng);
1218 	}
1219 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1220 	else {
1221 
1222 		BcBigDig val = 0;
1223 
1224 		if (len) {
1225 #if BC_ENABLED
1226 			if (BC_IS_BC && opd->t == BC_RESULT_ARRAY) {
1227 
1228 				BcVec *v = (BcVec*) num;
1229 
1230 				if (v->size == sizeof(uchar)) v = bc_program_dereference(p, v);
1231 
1232 				assert(v->size == sizeof(BcNum));
1233 
1234 				val = (BcBigDig) v->len;
1235 			}
1236 			else
1237 #endif // BC_ENABLED
1238 			{
1239 #if DC_ENABLED
1240 				if (!BC_PROG_NUM(opd, num)) {
1241 					size_t idx;
1242 					char *str;
1243 					idx = opd->t == BC_RESULT_STR ? opd->d.loc.loc : num->scale;
1244 					str = *((char**) bc_vec_item(p->strs, idx));
1245 					val = (BcBigDig) strlen(str);
1246 				}
1247 				else
1248 #endif // DC_ENABLED
1249 				{
1250 					val = (BcBigDig) bc_num_len(num);
1251 				}
1252 			}
1253 		}
1254 		else if (BC_IS_BC || BC_PROG_NUM(opd, num))
1255 			val = (BcBigDig) bc_num_scale(num);
1256 
1257 		BC_SIG_LOCK;
1258 
1259 		bc_num_createFromBigdig(&res->d.n, val);
1260 
1261 		BC_SIG_UNLOCK;
1262 	}
1263 
1264 	bc_program_retire(p, 1, 1);
1265 }
1266 
1267 #if DC_ENABLED
1268 static void bc_program_divmod(BcProgram *p) {
1269 
1270 	BcResult *opd1, *opd2, *res, *res2;
1271 	BcNum *n1, *n2;
1272 	size_t req;
1273 
1274 	bc_vec_expand(&p->results, p->results.len + 2);
1275 
1276 	// We don't need to update the pointer because
1277 	// the capacity is enough due to the line above.
1278 	res2 = bc_program_prepResult(p);
1279 	res = bc_program_prepResult(p);
1280 
1281 	bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2, 2);
1282 
1283 	req = bc_num_mulReq(n1, n2, BC_PROG_SCALE(p));
1284 
1285 	BC_SIG_LOCK;
1286 
1287 	bc_num_init(&res->d.n, req);
1288 	bc_num_init(&res2->d.n, req);
1289 
1290 	BC_SIG_UNLOCK;
1291 
1292 	bc_num_divmod(n1, n2, &res2->d.n, &res->d.n, BC_PROG_SCALE(p));
1293 
1294 	bc_program_retire(p, 2, 2);
1295 }
1296 
1297 static void bc_program_modexp(BcProgram *p) {
1298 
1299 	BcResult *r1, *r2, *r3, *res;
1300 	BcNum *n1, *n2, *n3;
1301 
1302 	if (BC_ERR(!BC_PROG_STACK(&p->results, 3))) bc_vm_err(BC_ERROR_EXEC_STACK);
1303 
1304 	assert(BC_PROG_STACK(&p->results, 3));
1305 
1306 	res = bc_program_prepResult(p);
1307 
1308 	bc_program_operand(p, &r1, &n1, 3);
1309 	bc_program_type_num(r1, n1);
1310 
1311 	bc_program_binOpPrep(p, &r2, &n2, &r3, &n3, 1);
1312 
1313 	// Make sure that the values have their pointers updated, if necessary.
1314 	// Only array elements are possible.
1315 	if (r1->t == BC_RESULT_ARRAY_ELEM && (r1->t == r2->t || r1->t == r3->t))
1316 		n1 = bc_program_num(p, r1);
1317 
1318 	BC_SIG_LOCK;
1319 
1320 	bc_num_init(&res->d.n, n3->len);
1321 
1322 	BC_SIG_UNLOCK;
1323 
1324 	bc_num_modexp(n1, n2, n3, &res->d.n);
1325 
1326 	bc_program_retire(p, 1, 3);
1327 }
1328 
1329 static void bc_program_stackLen(BcProgram *p) {
1330 	bc_program_pushBigdig(p, (BcBigDig) p->results.len, BC_RESULT_TEMP);
1331 }
1332 
1333 static uchar bc_program_asciifyNum(BcProgram *p, BcNum *n) {
1334 
1335 	BcNum num;
1336 	BcBigDig val = 0;
1337 
1338 	bc_num_clear(&num);
1339 
1340 	BC_SETJMP(num_err);
1341 
1342 	BC_SIG_LOCK;
1343 
1344 	bc_num_createCopy(&num, n);
1345 
1346 	BC_SIG_UNLOCK;
1347 
1348 	bc_num_truncate(&num, num.scale);
1349 	num.neg = false;
1350 
1351 	// This is guaranteed to not have a divide by 0
1352 	// because strmb is equal to UCHAR_MAX + 1.
1353 	bc_num_mod(&num, &p->strmb, &num, 0);
1354 
1355 	// This is also guaranteed to not error because num is in the range
1356 	// [0, UCHAR_MAX], which is definitely in range for a BcBigDig. And
1357 	// it is not negative.
1358 	bc_num_bigdig2(&num, &val);
1359 
1360 num_err:
1361 	BC_SIG_MAYLOCK;
1362 	bc_num_free(&num);
1363 	BC_LONGJMP_CONT;
1364 	return (uchar) val;
1365 }
1366 
1367 static void bc_program_asciify(BcProgram *p) {
1368 
1369 	BcResult *r, res;
1370 	BcNum *n;
1371 	char str[2], *str2;
1372 	uchar c;
1373 	size_t idx;
1374 
1375 	if (BC_ERR(!BC_PROG_STACK(&p->results, 1))) bc_vm_err(BC_ERROR_EXEC_STACK);
1376 
1377 	assert(BC_PROG_STACK(&p->results, 1));
1378 
1379 	bc_program_operand(p, &r, &n, 0);
1380 
1381 	assert(n != NULL);
1382 
1383 	assert(p->strs->len + BC_PROG_REQ_FUNCS == p->fns.len);
1384 
1385 	if (BC_PROG_NUM(r, n)) c = bc_program_asciifyNum(p, n);
1386 	else {
1387 		size_t index = r->t == BC_RESULT_STR ? r->d.loc.loc : n->scale;
1388 		str2 = *((char**) bc_vec_item(p->strs, index));
1389 		c = (uchar) str2[0];
1390 	}
1391 
1392 	str[0] = (char) c;
1393 	str[1] = '\0';
1394 
1395 	BC_SIG_LOCK;
1396 
1397 	idx = bc_program_insertFunc(p, str) - BC_PROG_REQ_FUNCS;
1398 
1399 	BC_SIG_UNLOCK;
1400 
1401 	res.t = BC_RESULT_STR;
1402 	res.d.loc.loc = idx;
1403 	bc_vec_pop(&p->results);
1404 	bc_vec_push(&p->results, &res);
1405 }
1406 
1407 static void bc_program_printStream(BcProgram *p) {
1408 
1409 	BcResult *r;
1410 	BcNum *n;
1411 
1412 	if (BC_ERR(!BC_PROG_STACK(&p->results, 1))) bc_vm_err(BC_ERROR_EXEC_STACK);
1413 
1414 	assert(BC_PROG_STACK(&p->results, 1));
1415 
1416 	bc_program_operand(p, &r, &n, 0);
1417 
1418 	assert(n != NULL);
1419 
1420 	if (BC_PROG_NUM(r, n)) bc_num_stream(n, p->strm);
1421 	else {
1422 		size_t idx = (r->t == BC_RESULT_STR) ? r->d.loc.loc : n->scale;
1423 		bc_program_printChars(*((char**) bc_vec_item(p->strs, idx)));
1424 	}
1425 }
1426 
1427 static void bc_program_nquit(BcProgram *p, uchar inst) {
1428 
1429 	BcResult *opnd;
1430 	BcNum *num;
1431 	BcBigDig val;
1432 	size_t i;
1433 
1434 	assert(p->stack.len == p->tail_calls.len);
1435 
1436 	if (inst == BC_INST_QUIT) val = 2;
1437 	else {
1438 
1439 		bc_program_prep(p, &opnd, &num, 0);
1440 		bc_num_bigdig(num, &val);
1441 
1442 		bc_vec_pop(&p->results);
1443 	}
1444 
1445 	for (i = 0; val && i < p->tail_calls.len; ++i) {
1446 		size_t calls = *((size_t*) bc_vec_item_rev(&p->tail_calls, i)) + 1;
1447 		if (calls >= val) val = 0;
1448 		else val -= calls;
1449 	}
1450 
1451 	if (i == p->stack.len) {
1452 		vm.status = BC_STATUS_QUIT;
1453 		BC_VM_JMP;
1454 	}
1455 	else {
1456 		bc_vec_npop(&p->stack, i);
1457 		bc_vec_npop(&p->tail_calls, i);
1458 	}
1459 }
1460 
1461 static void bc_program_execStr(BcProgram *p, const char *restrict code,
1462                                    size_t *restrict bgn, bool cond, size_t len)
1463 {
1464 	BcResult *r;
1465 	char *str;
1466 	BcFunc *f;
1467 	BcParse prs;
1468 	BcInstPtr ip;
1469 	size_t fidx, sidx;
1470 	BcNum *n;
1471 
1472 	assert(p->stack.len == p->tail_calls.len);
1473 
1474 	if (BC_ERR(!BC_PROG_STACK(&p->results, 1))) bc_vm_err(BC_ERROR_EXEC_STACK);
1475 
1476 	assert(BC_PROG_STACK(&p->results, 1));
1477 
1478 	bc_program_operand(p, &r, &n, 0);
1479 
1480 	if (cond) {
1481 
1482 		bool exec;
1483 		size_t idx, then_idx, else_idx;
1484 
1485 		then_idx = bc_program_index(code, bgn);
1486 		else_idx = bc_program_index(code, bgn);
1487 
1488 		exec = (r->d.n.len != 0);
1489 
1490 		idx = exec ? then_idx : else_idx;
1491 
1492 		BC_SIG_LOCK;
1493 		BC_SETJMP_LOCKED(exit);
1494 
1495 		if (exec || (else_idx != SIZE_MAX))
1496 			n = bc_vec_top(bc_program_vec(p, idx, BC_TYPE_VAR));
1497 		else goto exit;
1498 
1499 		if (BC_ERR(!BC_PROG_STR(n))) bc_vm_err(BC_ERROR_EXEC_TYPE);
1500 
1501 		BC_UNSETJMP;
1502 		BC_SIG_UNLOCK;
1503 
1504 		sidx = n->scale;
1505 	}
1506 	else {
1507 
1508 		// In non-conditional situations, only the top of stack can be executed,
1509 		// and in those cases, variables are not allowed to be "on the stack";
1510 		// they are only put on the stack to be assigned to.
1511 		assert(r->t != BC_RESULT_VAR);
1512 
1513 		if (r->t == BC_RESULT_STR) sidx = r->d.loc.loc;
1514 		else return;
1515 	}
1516 
1517 	fidx = sidx + BC_PROG_REQ_FUNCS;
1518 	str = *((char**) bc_vec_item(p->strs, sidx));
1519 	f = bc_vec_item(&p->fns, fidx);
1520 
1521 	if (!f->code.len) {
1522 
1523 		BC_SIG_LOCK;
1524 
1525 		bc_parse_init(&prs, p, fidx);
1526 		bc_lex_file(&prs.l, vm.file);
1527 
1528 		BC_SETJMP_LOCKED(err);
1529 
1530 		BC_SIG_UNLOCK;
1531 
1532 		bc_parse_text(&prs, str);
1533 		vm.expr(&prs, BC_PARSE_NOCALL);
1534 
1535 		BC_SIG_LOCK;
1536 
1537 		BC_UNSETJMP;
1538 
1539 		// We can just assert this here because
1540 		// dc should parse everything until EOF.
1541 		assert(prs.l.t == BC_LEX_EOF);
1542 
1543 		bc_parse_free(&prs);
1544 
1545 		BC_SIG_UNLOCK;
1546 	}
1547 
1548 	ip.idx = 0;
1549 	ip.len = p->results.len;
1550 	ip.func = fidx;
1551 
1552 	bc_vec_pop(&p->results);
1553 
1554 	// Tail call.
1555 	if (p->stack.len > 1 && *bgn == len - 1 && code[*bgn] == BC_INST_POP_EXEC) {
1556 		size_t *call_ptr = bc_vec_top(&p->tail_calls);
1557 		*call_ptr += 1;
1558 		bc_vec_pop(&p->stack);
1559 	}
1560 	else bc_vec_push(&p->tail_calls, &ip.idx);
1561 
1562 	bc_vec_push(&p->stack, &ip);
1563 
1564 	return;
1565 
1566 err:
1567 	BC_SIG_MAYLOCK;
1568 	bc_parse_free(&prs);
1569 	f = bc_vec_item(&p->fns, fidx);
1570 	bc_vec_npop(&f->code, f->code.len);
1571 exit:
1572 	bc_vec_pop(&p->results);
1573 	BC_LONGJMP_CONT;
1574 }
1575 
1576 static void bc_program_printStack(BcProgram *p) {
1577 
1578 	size_t idx;
1579 
1580 	for (idx = 0; idx < p->results.len; ++idx)
1581 		bc_program_print(p, BC_INST_PRINT, idx);
1582 }
1583 #endif // DC_ENABLED
1584 
1585 static void bc_program_pushGlobal(BcProgram *p, uchar inst) {
1586 
1587 	BcResultType t;
1588 
1589 	assert(inst >= BC_INST_IBASE && inst <= BC_INST_SCALE);
1590 
1591 	t = inst - BC_INST_IBASE + BC_RESULT_IBASE;
1592 	bc_program_pushBigdig(p, p->globals[inst - BC_INST_IBASE], t);
1593 }
1594 
1595 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1596 static void bc_program_pushSeed(BcProgram *p) {
1597 
1598 	BcResult *res;
1599 
1600 	res = bc_program_prepResult(p);
1601 	res->t = BC_RESULT_SEED;
1602 
1603 	BC_SIG_LOCK;
1604 
1605 	bc_num_init(&res->d.n, 2 * BC_RAND_NUM_SIZE);
1606 
1607 	BC_SIG_UNLOCK;
1608 
1609 	bc_num_createFromRNG(&res->d.n, &p->rng);
1610 }
1611 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1612 
1613 static void bc_program_addFunc(BcProgram *p, BcFunc *f, BcId *id_ptr) {
1614 
1615 	BcInstPtr *ip;
1616 
1617 	BC_SIG_ASSERT_LOCKED;
1618 
1619 	bc_func_init(f, id_ptr->name);
1620 	bc_vec_push(&p->fns, f);
1621 
1622 	// This is to make sure pointers are updated if the array was moved.
1623 	if (p->stack.len) {
1624 		ip = bc_vec_top(&p->stack);
1625 		bc_program_setVecs(p, (BcFunc*) bc_vec_item(&p->fns, ip->func));
1626 	}
1627 }
1628 
1629 size_t bc_program_insertFunc(BcProgram *p, const char *name) {
1630 
1631 	BcId *id_ptr;
1632 	BcFunc f;
1633 	bool new;
1634 	size_t idx;
1635 
1636 	BC_SIG_ASSERT_LOCKED;
1637 
1638 	assert(p != NULL && name != NULL);
1639 
1640 	new = bc_map_insert(&p->fn_map, name, p->fns.len, &idx);
1641 	id_ptr = (BcId*) bc_vec_item(&p->fn_map, idx);
1642 	idx = id_ptr->idx;
1643 
1644 	if (!new) {
1645 		if (BC_IS_BC) {
1646 			BcFunc *func = bc_vec_item(&p->fns, idx);
1647 			bc_func_reset(func);
1648 		}
1649 	}
1650 	else {
1651 
1652 		bc_program_addFunc(p, &f, id_ptr);
1653 
1654 #if DC_ENABLED
1655 		if (BC_IS_DC && idx >= BC_PROG_REQ_FUNCS) {
1656 			bc_vec_push(p->strs, &id_ptr->name);
1657 			assert(p->strs->len == p->fns.len - BC_PROG_REQ_FUNCS);
1658 		}
1659 #endif // DC_ENABLED
1660 	}
1661 
1662 	return idx;
1663 }
1664 
1665 #ifndef NDEBUG
1666 void bc_program_free(BcProgram *p) {
1667 
1668 	size_t i;
1669 
1670 	BC_SIG_ASSERT_LOCKED;
1671 
1672 	assert(p != NULL);
1673 
1674 	for (i = 0; i < BC_PROG_GLOBALS_LEN; ++i) bc_vec_free(p->globals_v + i);
1675 
1676 	bc_vec_free(&p->fns);
1677 	bc_vec_free(&p->fn_map);
1678 	bc_vec_free(&p->vars);
1679 	bc_vec_free(&p->var_map);
1680 	bc_vec_free(&p->arrs);
1681 	bc_vec_free(&p->arr_map);
1682 	bc_vec_free(&p->results);
1683 	bc_vec_free(&p->stack);
1684 
1685 #if BC_ENABLED
1686 	if (BC_IS_BC) bc_num_free(&p->last);
1687 #endif // BC_ENABLED
1688 
1689 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1690 	bc_rand_free(&p->rng);
1691 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1692 
1693 #if DC_ENABLED
1694 	if (BC_IS_DC) {
1695 		bc_vec_free(&p->tail_calls);
1696 		bc_vec_free(&p->strs_v);
1697 	}
1698 #endif // DC_ENABLED
1699 }
1700 #endif // NDEBUG
1701 
1702 void bc_program_init(BcProgram *p) {
1703 
1704 	BcInstPtr ip;
1705 	size_t i;
1706 	BcBigDig val = BC_BASE;
1707 
1708 	BC_SIG_ASSERT_LOCKED;
1709 
1710 	assert(p != NULL);
1711 
1712 	memset(p, 0, sizeof(BcProgram));
1713 	memset(&ip, 0, sizeof(BcInstPtr));
1714 
1715 	for (i = 0; i < BC_PROG_GLOBALS_LEN; ++i) {
1716 		bc_vec_init(p->globals_v + i, sizeof(BcBigDig), NULL);
1717 		val = i == BC_PROG_GLOBALS_SCALE ? 0 : val;
1718 		bc_vec_push(p->globals_v + i, &val);
1719 		p->globals[i] = val;
1720 	}
1721 
1722 #if DC_ENABLED
1723 	if (BC_IS_DC) {
1724 
1725 		bc_vec_init(&p->strs_v, sizeof(char*), bc_string_free);
1726 		p->strs = &p->strs_v;
1727 
1728 		bc_vec_init(&p->tail_calls, sizeof(size_t), NULL);
1729 		i = 0;
1730 		bc_vec_push(&p->tail_calls, &i);
1731 
1732 		p->strm = UCHAR_MAX + 1;
1733 		bc_num_setup(&p->strmb, p->strmb_num, BC_NUM_BIGDIG_LOG10);
1734 		bc_num_bigdig2num(&p->strmb, p->strm);
1735 	}
1736 #endif // DC_ENABLED
1737 
1738 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1739 	srand((unsigned int) time(NULL));
1740 	bc_rand_init(&p->rng);
1741 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1742 
1743 	bc_num_setup(&p->zero, p->zero_num, BC_PROG_ONE_CAP);
1744 
1745 	bc_num_setup(&p->one, p->one_num, BC_PROG_ONE_CAP);
1746 	bc_num_one(&p->one);
1747 
1748 #if BC_ENABLED
1749 	if (BC_IS_BC) bc_num_init(&p->last, BC_NUM_DEF_SIZE);
1750 #endif // BC_ENABLED
1751 
1752 	bc_vec_init(&p->fns, sizeof(BcFunc), bc_func_free);
1753 	bc_map_init(&p->fn_map);
1754 	bc_program_insertFunc(p, bc_func_main);
1755 	bc_program_insertFunc(p, bc_func_read);
1756 
1757 	bc_vec_init(&p->vars, sizeof(BcVec), bc_vec_free);
1758 	bc_map_init(&p->var_map);
1759 
1760 	bc_vec_init(&p->arrs, sizeof(BcVec), bc_vec_free);
1761 	bc_map_init(&p->arr_map);
1762 
1763 	bc_vec_init(&p->results, sizeof(BcResult), bc_result_free);
1764 	bc_vec_init(&p->stack, sizeof(BcInstPtr), NULL);
1765 	bc_vec_push(&p->stack, &ip);
1766 
1767 	bc_program_setVecs(p, (BcFunc*) bc_vec_item(&p->fns, BC_PROG_MAIN));
1768 
1769 	assert(p->consts != NULL && p->strs != NULL);
1770 }
1771 
1772 void bc_program_reset(BcProgram *p) {
1773 
1774 	BcFunc *f;
1775 	BcInstPtr *ip;
1776 
1777 	BC_SIG_ASSERT_LOCKED;
1778 
1779 	bc_vec_npop(&p->stack, p->stack.len - 1);
1780 	bc_vec_npop(&p->results, p->results.len);
1781 
1782 #if BC_ENABLED
1783 	if (BC_G) bc_program_popGlobals(p, true);
1784 #endif // BC_ENABLED
1785 
1786 	f = bc_vec_item(&p->fns, BC_PROG_MAIN);
1787 	ip = bc_vec_top(&p->stack);
1788 	bc_program_setVecs(p, f);
1789 	ip->idx = f->code.len;
1790 
1791 	if (vm.sig) {
1792 		bc_file_write(&vm.fout, bc_program_ready_msg, bc_program_ready_msg_len);
1793 		bc_file_flush(&vm.fout);
1794 		vm.sig = 0;
1795 	}
1796 }
1797 
1798 void bc_program_exec(BcProgram *p) {
1799 
1800 	size_t idx;
1801 	BcResult r, *ptr;
1802 	BcInstPtr *ip = bc_vec_top(&p->stack);
1803 	BcFunc *func = (BcFunc*) bc_vec_item(&p->fns, ip->func);
1804 	char *code = func->code.v;
1805 	bool cond = false;
1806 #if BC_ENABLED
1807 	BcNum *num;
1808 #endif // BC_ENABLED
1809 #ifndef NDEBUG
1810 	size_t jmp_bufs_len;
1811 #endif // NDEBUG
1812 
1813 #ifndef NDEBUG
1814 	jmp_bufs_len = vm.jmp_bufs.len;
1815 #endif // NDEBUG
1816 
1817 	bc_program_setVecs(p, func);
1818 
1819 	while (ip->idx < func->code.len) {
1820 
1821 		BC_SIG_ASSERT_NOT_LOCKED;
1822 
1823 		uchar inst = (uchar) code[(ip->idx)++];
1824 
1825 		switch (inst) {
1826 
1827 #if BC_ENABLED
1828 			case BC_INST_JUMP_ZERO:
1829 			{
1830 				bc_program_prep(p, &ptr, &num, 0);
1831 				cond = !bc_num_cmpZero(num);
1832 				bc_vec_pop(&p->results);
1833 			}
1834 			// Fallthrough.
1835 			case BC_INST_JUMP:
1836 			{
1837 				idx = bc_program_index(code, &ip->idx);
1838 
1839 				if (inst == BC_INST_JUMP || cond) {
1840 
1841 					size_t *addr = bc_vec_item(&func->labels, idx);
1842 
1843 					assert(*addr != SIZE_MAX);
1844 
1845 					ip->idx = *addr;
1846 				}
1847 
1848 				break;
1849 			}
1850 
1851 			case BC_INST_CALL:
1852 			{
1853 				assert(BC_IS_BC);
1854 
1855 				bc_program_call(p, code, &ip->idx);
1856 
1857 				ip = bc_vec_top(&p->stack);
1858 				func = bc_vec_item(&p->fns, ip->func);
1859 				code = func->code.v;
1860 
1861 				bc_program_setVecs(p, func);
1862 
1863 				break;
1864 			}
1865 
1866 			case BC_INST_INC:
1867 			case BC_INST_DEC:
1868 			{
1869 				bc_program_incdec(p, inst);
1870 				break;
1871 			}
1872 
1873 			case BC_INST_HALT:
1874 			{
1875 				vm.status = BC_STATUS_QUIT;
1876 				BC_VM_JMP;
1877 				break;
1878 			}
1879 
1880 			case BC_INST_RET:
1881 			case BC_INST_RET0:
1882 			case BC_INST_RET_VOID:
1883 			{
1884 				bc_program_return(p, inst);
1885 
1886 				ip = bc_vec_top(&p->stack);
1887 				func = bc_vec_item(&p->fns, ip->func);
1888 				code = func->code.v;
1889 
1890 				bc_program_setVecs(p, func);
1891 
1892 				break;
1893 			}
1894 #endif // BC_ENABLED
1895 
1896 			case BC_INST_BOOL_OR:
1897 			case BC_INST_BOOL_AND:
1898 			case BC_INST_REL_EQ:
1899 			case BC_INST_REL_LE:
1900 			case BC_INST_REL_GE:
1901 			case BC_INST_REL_NE:
1902 			case BC_INST_REL_LT:
1903 			case BC_INST_REL_GT:
1904 			{
1905 				bc_program_logical(p, inst);
1906 				break;
1907 			}
1908 
1909 			case BC_INST_READ:
1910 			{
1911 				bc_program_read(p);
1912 
1913 				ip = bc_vec_top(&p->stack);
1914 				func = bc_vec_item(&p->fns, ip->func);
1915 				code = func->code.v;
1916 
1917 				bc_program_setVecs(p, func);
1918 
1919 				break;
1920 			}
1921 
1922 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1923 			case BC_INST_RAND:
1924 			{
1925 				bc_program_rand(p);
1926 				break;
1927 			}
1928 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1929 
1930 			case BC_INST_MAXIBASE:
1931 			case BC_INST_MAXOBASE:
1932 			case BC_INST_MAXSCALE:
1933 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1934 			case BC_INST_MAXRAND:
1935 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1936 			{
1937 				BcBigDig dig = vm.maxes[inst - BC_INST_MAXIBASE];
1938 				bc_program_pushBigdig(p, dig, BC_RESULT_TEMP);
1939 				break;
1940 			}
1941 
1942 			case BC_INST_VAR:
1943 			{
1944 				bc_program_pushVar(p, code, &ip->idx, false, false);
1945 				break;
1946 			}
1947 
1948 			case BC_INST_ARRAY_ELEM:
1949 #if BC_ENABLED
1950 			case BC_INST_ARRAY:
1951 #endif // BC_ENABLED
1952 			{
1953 				bc_program_pushArray(p, code, &ip->idx, inst);
1954 				break;
1955 			}
1956 
1957 			case BC_INST_IBASE:
1958 			case BC_INST_SCALE:
1959 			case BC_INST_OBASE:
1960 			{
1961 				bc_program_pushGlobal(p, inst);
1962 				break;
1963 			}
1964 
1965 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1966 			case BC_INST_SEED:
1967 			{
1968 				bc_program_pushSeed(p);
1969 				break;
1970 			}
1971 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1972 
1973 			case BC_INST_LENGTH:
1974 			case BC_INST_SCALE_FUNC:
1975 			case BC_INST_SQRT:
1976 			case BC_INST_ABS:
1977 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1978 			case BC_INST_IRAND:
1979 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1980 			{
1981 				bc_program_builtin(p, inst);
1982 				break;
1983 			}
1984 
1985 			case BC_INST_NUM:
1986 			{
1987 				bc_program_const(p, code, &ip->idx);
1988 				break;
1989 			}
1990 
1991 			case BC_INST_ZERO:
1992 			case BC_INST_ONE:
1993 #if BC_ENABLED
1994 			case BC_INST_LAST:
1995 #endif // BC_ENABLED
1996 			{
1997 				r.t = BC_RESULT_ZERO + (inst - BC_INST_ZERO);
1998 				bc_vec_push(&p->results, &r);
1999 				break;
2000 			}
2001 
2002 			case BC_INST_PRINT:
2003 			case BC_INST_PRINT_POP:
2004 			case BC_INST_PRINT_STR:
2005 			{
2006 				bc_program_print(p, inst, 0);
2007 				break;
2008 			}
2009 
2010 			case BC_INST_STR:
2011 			{
2012 				r.t = BC_RESULT_STR;
2013 				r.d.loc.loc = bc_program_index(code, &ip->idx);
2014 				bc_vec_push(&p->results, &r);
2015 				break;
2016 			}
2017 
2018 			case BC_INST_POWER:
2019 			case BC_INST_MULTIPLY:
2020 			case BC_INST_DIVIDE:
2021 			case BC_INST_MODULUS:
2022 			case BC_INST_PLUS:
2023 			case BC_INST_MINUS:
2024 #if BC_ENABLE_EXTRA_MATH
2025 			case BC_INST_PLACES:
2026 			case BC_INST_LSHIFT:
2027 			case BC_INST_RSHIFT:
2028 #endif // BC_ENABLE_EXTRA_MATH
2029 			{
2030 				bc_program_op(p, inst);
2031 				break;
2032 			}
2033 
2034 			case BC_INST_NEG:
2035 			case BC_INST_BOOL_NOT:
2036 #if BC_ENABLE_EXTRA_MATH
2037 			case BC_INST_TRUNC:
2038 #endif // BC_ENABLE_EXTRA_MATH
2039 			{
2040 				bc_program_unary(p, inst);
2041 				break;
2042 			}
2043 
2044 #if BC_ENABLED
2045 			case BC_INST_ASSIGN_POWER:
2046 			case BC_INST_ASSIGN_MULTIPLY:
2047 			case BC_INST_ASSIGN_DIVIDE:
2048 			case BC_INST_ASSIGN_MODULUS:
2049 			case BC_INST_ASSIGN_PLUS:
2050 			case BC_INST_ASSIGN_MINUS:
2051 #if BC_ENABLE_EXTRA_MATH
2052 			case BC_INST_ASSIGN_PLACES:
2053 			case BC_INST_ASSIGN_LSHIFT:
2054 			case BC_INST_ASSIGN_RSHIFT:
2055 #endif // BC_ENABLE_EXTRA_MATH
2056 			case BC_INST_ASSIGN:
2057 			case BC_INST_ASSIGN_POWER_NO_VAL:
2058 			case BC_INST_ASSIGN_MULTIPLY_NO_VAL:
2059 			case BC_INST_ASSIGN_DIVIDE_NO_VAL:
2060 			case BC_INST_ASSIGN_MODULUS_NO_VAL:
2061 			case BC_INST_ASSIGN_PLUS_NO_VAL:
2062 			case BC_INST_ASSIGN_MINUS_NO_VAL:
2063 #if BC_ENABLE_EXTRA_MATH
2064 			case BC_INST_ASSIGN_PLACES_NO_VAL:
2065 			case BC_INST_ASSIGN_LSHIFT_NO_VAL:
2066 			case BC_INST_ASSIGN_RSHIFT_NO_VAL:
2067 #endif // BC_ENABLE_EXTRA_MATH
2068 #endif // BC_ENABLED
2069 			case BC_INST_ASSIGN_NO_VAL:
2070 			{
2071 				bc_program_assign(p, inst);
2072 				break;
2073 			}
2074 
2075 			case BC_INST_POP:
2076 			{
2077 #ifndef BC_PROG_NO_STACK_CHECK
2078 				if (!BC_IS_BC) {
2079 					if (BC_ERR(!BC_PROG_STACK(&p->results, 1)))
2080 						bc_vm_err(BC_ERROR_EXEC_STACK);
2081 				}
2082 #endif // BC_PROG_NO_STACK_CHECK
2083 
2084 				assert(BC_PROG_STACK(&p->results, 1));
2085 
2086 				bc_vec_pop(&p->results);
2087 				break;
2088 			}
2089 
2090 #if DC_ENABLED
2091 			case BC_INST_POP_EXEC:
2092 			{
2093 				assert(BC_PROG_STACK(&p->stack, 2));
2094 				bc_vec_pop(&p->stack);
2095 				bc_vec_pop(&p->tail_calls);
2096 				ip = bc_vec_top(&p->stack);
2097 				func = bc_vec_item(&p->fns, ip->func);
2098 				code = func->code.v;
2099 				bc_program_setVecs(p, func);
2100 				break;
2101 			}
2102 
2103 			case BC_INST_MODEXP:
2104 			{
2105 				bc_program_modexp(p);
2106 				break;
2107 			}
2108 
2109 			case BC_INST_DIVMOD:
2110 			{
2111 				bc_program_divmod(p);
2112 				break;
2113 			}
2114 
2115 			case BC_INST_EXECUTE:
2116 			case BC_INST_EXEC_COND:
2117 			{
2118 				cond = (inst == BC_INST_EXEC_COND);
2119 				bc_program_execStr(p, code, &ip->idx, cond, func->code.len);
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_PRINT_STACK:
2128 			{
2129 				bc_program_printStack(p);
2130 				break;
2131 			}
2132 
2133 			case BC_INST_CLEAR_STACK:
2134 			{
2135 				bc_vec_npop(&p->results, p->results.len);
2136 				break;
2137 			}
2138 
2139 			case BC_INST_STACK_LEN:
2140 			{
2141 				bc_program_stackLen(p);
2142 				break;
2143 			}
2144 
2145 			case BC_INST_DUPLICATE:
2146 			{
2147 				if (BC_ERR(!BC_PROG_STACK(&p->results, 1)))
2148 					bc_vm_err(BC_ERROR_EXEC_STACK);
2149 
2150 				assert(BC_PROG_STACK(&p->results, 1));
2151 
2152 				ptr = bc_vec_top(&p->results);
2153 
2154 				BC_SIG_LOCK;
2155 
2156 				bc_result_copy(&r, ptr);
2157 				bc_vec_push(&p->results, &r);
2158 
2159 				BC_SIG_UNLOCK;
2160 
2161 				break;
2162 			}
2163 
2164 			case BC_INST_SWAP:
2165 			{
2166 				BcResult *ptr2;
2167 
2168 				if (BC_ERR(!BC_PROG_STACK(&p->results, 2)))
2169 					bc_vm_err(BC_ERROR_EXEC_STACK);
2170 
2171 				assert(BC_PROG_STACK(&p->results, 2));
2172 
2173 				ptr = bc_vec_item_rev(&p->results, 0);
2174 				ptr2 = bc_vec_item_rev(&p->results, 1);
2175 				memcpy(&r, ptr, sizeof(BcResult));
2176 				memcpy(ptr, ptr2, sizeof(BcResult));
2177 				memcpy(ptr2, &r, sizeof(BcResult));
2178 
2179 				break;
2180 			}
2181 
2182 			case BC_INST_ASCIIFY:
2183 			{
2184 				bc_program_asciify(p);
2185 				ip = bc_vec_top(&p->stack);
2186 				func = bc_vec_item(&p->fns, ip->func);
2187 				code = func->code.v;
2188 				bc_program_setVecs(p, func);
2189 				break;
2190 			}
2191 
2192 			case BC_INST_PRINT_STREAM:
2193 			{
2194 				bc_program_printStream(p);
2195 				break;
2196 			}
2197 
2198 			case BC_INST_LOAD:
2199 			case BC_INST_PUSH_VAR:
2200 			{
2201 				bool copy = (inst == BC_INST_LOAD);
2202 				bc_program_pushVar(p, code, &ip->idx, true, copy);
2203 				break;
2204 			}
2205 
2206 			case BC_INST_PUSH_TO_VAR:
2207 			{
2208 				idx = bc_program_index(code, &ip->idx);
2209 				bc_program_copyToVar(p, idx, BC_TYPE_VAR, true);
2210 				break;
2211 			}
2212 
2213 			case BC_INST_QUIT:
2214 			case BC_INST_NQUIT:
2215 			{
2216 				bc_program_nquit(p, inst);
2217 				ip = bc_vec_top(&p->stack);
2218 				func = bc_vec_item(&p->fns, ip->func);
2219 				code = func->code.v;
2220 				bc_program_setVecs(p, func);
2221 				break;
2222 			}
2223 #endif // DC_ENABLED
2224 #ifndef NDEBUG
2225 			default:
2226 			{
2227 				abort();
2228 			}
2229 #endif // NDEBUG
2230 		}
2231 
2232 #ifndef NDEBUG
2233 		// This is to allow me to use a debugger to see the last instruction,
2234 		// which will point to which function was the problem.
2235 		assert(jmp_bufs_len == vm.jmp_bufs.len);
2236 #endif // NDEBUG
2237 	}
2238 }
2239 
2240 #if BC_DEBUG_CODE
2241 #if BC_ENABLED && DC_ENABLED
2242 void bc_program_printStackDebug(BcProgram *p) {
2243 	bc_file_puts(&vm.fout, "-------------- Stack ----------\n");
2244 	bc_program_printStack(p);
2245 	bc_file_puts(&vm.fout, "-------------- Stack End ------\n");
2246 }
2247 
2248 static void bc_program_printIndex(const char *restrict code,
2249                                   size_t *restrict bgn)
2250 {
2251 	uchar byte, i, bytes = (uchar) code[(*bgn)++];
2252 	ulong val = 0;
2253 
2254 	for (byte = 1, i = 0; byte && i < bytes; ++i) {
2255 		byte = (uchar) code[(*bgn)++];
2256 		if (byte) val |= ((ulong) byte) << (CHAR_BIT * i);
2257 	}
2258 
2259 	bc_vm_printf(" (%lu) ", val);
2260 }
2261 
2262 static void bc_program_printStr(const BcProgram *p, const char *restrict code,
2263                          size_t *restrict bgn)
2264 {
2265 	size_t idx = bc_program_index(code, bgn);
2266 	char *s;
2267 
2268 	s = *((char**) bc_vec_item(p->strs, idx));
2269 
2270 	bc_vm_printf(" (\"%s\") ", s);
2271 }
2272 
2273 void bc_program_printInst(const BcProgram *p, const char *restrict code,
2274                           size_t *restrict bgn)
2275 {
2276 	uchar inst = (uchar) code[(*bgn)++];
2277 
2278 	bc_vm_printf("Inst[%zu]: %s [%lu]; ", *bgn - 1,
2279 	             bc_inst_names[inst], (unsigned long) inst);
2280 
2281 	if (inst == BC_INST_VAR || inst == BC_INST_ARRAY_ELEM ||
2282 	    inst == BC_INST_ARRAY)
2283 	{
2284 		bc_program_printIndex(code, bgn);
2285 	}
2286 	else if (inst == BC_INST_STR) bc_program_printStr(p, code, bgn);
2287 	else if (inst == BC_INST_NUM) {
2288 		size_t idx = bc_program_index(code, bgn);
2289 		BcConst *c = bc_vec_item(p->consts, idx);
2290 		bc_vm_printf("(%s)", c->val);
2291 	}
2292 	else if (inst == BC_INST_CALL ||
2293 	         (inst > BC_INST_STR && inst <= BC_INST_JUMP_ZERO))
2294 	{
2295 		bc_program_printIndex(code, bgn);
2296 		if (inst == BC_INST_CALL) bc_program_printIndex(code, bgn);
2297 	}
2298 
2299 	bc_vm_putchar('\n');
2300 }
2301 
2302 void bc_program_code(const BcProgram* p) {
2303 
2304 	BcFunc *f;
2305 	char *code;
2306 	BcInstPtr ip;
2307 	size_t i;
2308 
2309 	for (i = 0; i < p->fns.len; ++i) {
2310 
2311 		ip.idx = ip.len = 0;
2312 		ip.func = i;
2313 
2314 		f = bc_vec_item(&p->fns, ip.func);
2315 		code = f->code.v;
2316 
2317 		bc_vm_printf("func[%zu]:\n", ip.func);
2318 		while (ip.idx < f->code.len) bc_program_printInst(p, code, &ip.idx);
2319 		bc_file_puts(&vm.fout, "\n\n");
2320 	}
2321 }
2322 #endif // BC_ENABLED && DC_ENABLED
2323 #endif // BC_DEBUG_CODE
2324