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