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