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