• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * *****************************************************************************
3  *
4  * SPDX-License-Identifier: BSD-2-Clause
5  *
6  * Copyright (c) 2018-2021 Gavin D. Howard and contributors.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions are met:
10  *
11  * * Redistributions of source code must retain the above copyright notice, this
12  *   list of conditions and the following disclaimer.
13  *
14  * * Redistributions in binary form must reproduce the above copyright notice,
15  *   this list of conditions and the following disclaimer in the documentation
16  *   and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28  * POSSIBILITY OF SUCH DAMAGE.
29  *
30  * *****************************************************************************
31  *
32  * Code to execute bc programs.
33  *
34  */
35 
36 #include <assert.h>
37 #include <stdbool.h>
38 #include <string.h>
39 
40 #include <setjmp.h>
41 
42 #include <signal.h>
43 
44 #include <time.h>
45 
46 #include <read.h>
47 #include <parse.h>
48 #include <program.h>
49 #include <vm.h>
50 
51 static void bc_program_addFunc(BcProgram *p, BcFunc *f, BcId *id_ptr);
52 
bc_program_setVecs(BcProgram * p,BcFunc * f)53 static inline void bc_program_setVecs(BcProgram *p, BcFunc *f) {
54 	p->consts = &f->consts;
55 	if (BC_IS_BC) p->strs = &f->strs;
56 }
57 
bc_program_type_num(BcResult * r,BcNum * n)58 static inline void bc_program_type_num(BcResult *r, BcNum *n) {
59 
60 #if BC_ENABLED
61 	assert(r->t != BC_RESULT_VOID);
62 #endif // BC_ENABLED
63 
64 	if (BC_ERR(!BC_PROG_NUM(r, n))) bc_vm_err(BC_ERR_EXEC_TYPE);
65 }
66 
67 #if BC_ENABLED
bc_program_type_match(BcResult * r,BcType t)68 static void bc_program_type_match(BcResult *r, BcType t) {
69 
70 #if DC_ENABLED
71 	assert(BC_IS_DC || BC_NO_ERR(r->t != BC_RESULT_STR));
72 #endif // DC_ENABLED
73 
74 	if (BC_ERR((r->t != BC_RESULT_ARRAY) != (!t)))
75 		bc_vm_err(BC_ERR_EXEC_TYPE);
76 }
77 #endif // BC_ENABLED
78 
bc_program_index(const char * restrict code,size_t * restrict bgn)79 static size_t bc_program_index(const char *restrict code, size_t *restrict bgn)
80 {
81 	uchar amt = (uchar) code[(*bgn)++], i = 0;
82 	size_t res = 0;
83 
84 	for (; i < amt; ++i, ++(*bgn)) {
85 		size_t temp = ((size_t) ((int) (uchar) code[*bgn]) & UCHAR_MAX);
86 		res |= (temp << (i * CHAR_BIT));
87 	}
88 
89 	return res;
90 }
91 
92 #if BC_ENABLED
bc_program_prepGlobals(BcProgram * p)93 static void bc_program_prepGlobals(BcProgram *p) {
94 
95 	size_t i;
96 
97 	for (i = 0; i < BC_PROG_GLOBALS_LEN; ++i)
98 		bc_vec_push(p->globals_v + i, p->globals + i);
99 
100 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
101 	bc_rand_push(&p->rng);
102 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
103 }
104 
bc_program_popGlobals(BcProgram * p,bool reset)105 static void bc_program_popGlobals(BcProgram *p, bool reset) {
106 
107 	size_t i;
108 
109 	for (i = 0; i < BC_PROG_GLOBALS_LEN; ++i) {
110 		BcVec *v = p->globals_v + i;
111 		bc_vec_npop(v, reset ? v->len - 1 : 1);
112 		p->globals[i] = BC_PROG_GLOBAL(v);
113 	}
114 
115 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
116 	bc_rand_pop(&p->rng, reset);
117 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
118 }
119 #endif // BC_ENABLED
120 
bc_program_pushBigdig(BcProgram * p,BcBigDig dig,BcResultType type)121 static void bc_program_pushBigdig(BcProgram *p, BcBigDig dig, BcResultType type)
122 {
123 	BcResult res;
124 
125 	res.t = type;
126 
127 	BC_SIG_LOCK;
128 
129 	bc_num_createFromBigdig(&res.d.n, dig);
130 	bc_vec_push(&p->results, &res);
131 
132 	BC_SIG_UNLOCK;
133 }
134 
135 #if BC_ENABLED
bc_program_dereference(const BcProgram * p,BcVec * vec)136 static BcVec* bc_program_dereference(const BcProgram *p, BcVec *vec) {
137 
138 	BcVec *v;
139 	size_t vidx, nidx, i = 0;
140 
141 	assert(vec->size == sizeof(uchar));
142 
143 	vidx = bc_program_index(vec->v, &i);
144 	nidx = bc_program_index(vec->v, &i);
145 
146 	v = bc_vec_item(bc_vec_item(&p->arrs, vidx), nidx);
147 
148 	assert(v->size != sizeof(uchar));
149 
150 	return v;
151 }
152 #endif // BC_ENABLED
153 
bc_program_search(BcProgram * p,const char * id,bool var)154 size_t bc_program_search(BcProgram *p, const char *id, bool var) {
155 
156 	BcVec *v, *map;
157 	size_t i;
158 	BcResultData data;
159 
160 	v = var ? &p->vars : &p->arrs;
161 	map = var ? &p->var_map : &p->arr_map;
162 
163 	BC_SIG_LOCK;
164 
165 	if (bc_map_insert(map, id, v->len, &i)) {
166 		bc_array_init(&data.v, var);
167 		bc_vec_push(v, &data.v);
168 	}
169 
170 	BC_SIG_UNLOCK;
171 
172 	return ((BcId*) bc_vec_item(map, i))->idx;
173 }
174 
bc_program_vec(const BcProgram * p,size_t idx,BcType type)175 static inline BcVec* bc_program_vec(const BcProgram *p, size_t idx, BcType type)
176 {
177 	const BcVec *v = (type == BC_TYPE_VAR) ? &p->vars : &p->arrs;
178 	return bc_vec_item(v, idx);
179 }
180 
bc_program_num(BcProgram * p,BcResult * r)181 static BcNum* bc_program_num(BcProgram *p, BcResult *r) {
182 
183 	BcNum *n;
184 
185 	switch (r->t) {
186 
187 		case BC_RESULT_STR:
188 		case BC_RESULT_TEMP:
189 		case BC_RESULT_IBASE:
190 		case BC_RESULT_SCALE:
191 		case BC_RESULT_OBASE:
192 #if BC_ENABLE_EXTRA_MATH
193 		case BC_RESULT_SEED:
194 #endif // BC_ENABLE_EXTRA_MATH
195 		{
196 			n = &r->d.n;
197 			break;
198 		}
199 
200 		case BC_RESULT_VAR:
201 #if BC_ENABLED
202 		case BC_RESULT_ARRAY:
203 #endif // BC_ENABLED
204 		case BC_RESULT_ARRAY_ELEM:
205 		{
206 			BcVec *v;
207 			BcType type = (r->t == BC_RESULT_VAR) ? BC_TYPE_VAR : BC_TYPE_ARRAY;
208 
209 			v = bc_program_vec(p, r->d.loc.loc, type);
210 
211 			if (r->t == BC_RESULT_ARRAY_ELEM) {
212 
213 				size_t idx = r->d.loc.idx;
214 
215 				v = bc_vec_top(v);
216 
217 #if BC_ENABLED
218 				if (v->size == sizeof(uchar)) v = bc_program_dereference(p, v);
219 #endif // BC_ENABLED
220 
221 				assert(v->size == sizeof(BcNum));
222 
223 				if (v->len <= idx) {
224 					BC_SIG_LOCK;
225 					bc_array_expand(v, bc_vm_growSize(idx, 1));
226 					BC_SIG_UNLOCK;
227 				}
228 
229 				n = bc_vec_item(v, idx);
230 			}
231 			else n = bc_vec_top(v);
232 
233 			break;
234 		}
235 
236 		case BC_RESULT_ZERO:
237 		{
238 			n = &p->zero;
239 			break;
240 		}
241 
242 		case BC_RESULT_ONE:
243 		{
244 			n = &p->one;
245 			break;
246 		}
247 
248 #if BC_ENABLED
249 		case BC_RESULT_VOID:
250 #ifndef NDEBUG
251 		{
252 			abort();
253 		}
254 #endif // NDEBUG
255 		// Fallthrough
256 		case BC_RESULT_LAST:
257 		{
258 			n = &p->last;
259 			break;
260 		}
261 #endif // BC_ENABLED
262 	}
263 
264 	return n;
265 }
266 
bc_program_operand(BcProgram * p,BcResult ** r,BcNum ** n,size_t idx)267 static void bc_program_operand(BcProgram *p, BcResult **r,
268                                BcNum **n, size_t idx)
269 {
270 	*r = bc_vec_item_rev(&p->results, idx);
271 
272 #if BC_ENABLED
273 	if (BC_ERR((*r)->t == BC_RESULT_VOID)) bc_vm_err(BC_ERR_EXEC_VOID_VAL);
274 #endif // BC_ENABLED
275 
276 	*n = bc_program_num(p, *r);
277 }
278 
bc_program_binPrep(BcProgram * p,BcResult ** l,BcNum ** ln,BcResult ** r,BcNum ** rn,size_t idx)279 static void bc_program_binPrep(BcProgram *p, BcResult **l, BcNum **ln,
280                                BcResult **r, BcNum **rn, size_t idx)
281 {
282 	BcResultType lt;
283 
284 	assert(p != NULL && l != NULL && ln != NULL && r != NULL && rn != NULL);
285 
286 #ifndef BC_PROG_NO_STACK_CHECK
287 	if (BC_IS_DC) {
288 		if (BC_ERR(!BC_PROG_STACK(&p->results, idx + 2)))
289 			bc_vm_err(BC_ERR_EXEC_STACK);
290 	}
291 #endif // BC_PROG_NO_STACK_CHECK
292 
293 	assert(BC_PROG_STACK(&p->results, idx + 2));
294 
295 	bc_program_operand(p, l, ln, idx + 1);
296 	bc_program_operand(p, r, rn, idx);
297 
298 	lt = (*l)->t;
299 
300 #if BC_ENABLED
301 	assert(lt != BC_RESULT_VOID && (*r)->t != BC_RESULT_VOID);
302 #endif // BC_ENABLED
303 
304 	// We run this again under these conditions in case any vector has been
305 	// reallocated out from under the BcNums or arrays we had.
306 	if (lt == (*r)->t && (lt == BC_RESULT_VAR || lt == BC_RESULT_ARRAY_ELEM))
307 		*ln = bc_program_num(p, *l);
308 
309 	if (BC_ERR(lt == BC_RESULT_STR)) bc_vm_err(BC_ERR_EXEC_TYPE);
310 }
311 
bc_program_binOpPrep(BcProgram * p,BcResult ** l,BcNum ** ln,BcResult ** r,BcNum ** rn,size_t idx)312 static void bc_program_binOpPrep(BcProgram *p, BcResult **l, BcNum **ln,
313                                  BcResult **r, BcNum **rn, size_t idx)
314 {
315 	bc_program_binPrep(p, l, ln, r, rn, idx);
316 	bc_program_type_num(*l, *ln);
317 	bc_program_type_num(*r, *rn);
318 }
319 
bc_program_assignPrep(BcProgram * p,BcResult ** l,BcNum ** ln,BcResult ** r,BcNum ** rn)320 static void bc_program_assignPrep(BcProgram *p, BcResult **l, BcNum **ln,
321                                   BcResult **r, BcNum **rn)
322 {
323 	BcResultType lt, min;
324 
325 	min = BC_RESULT_TEMP - ((unsigned int) (BC_IS_BC));
326 
327 	bc_program_binPrep(p, l, ln, r, rn, 0);
328 
329 	lt = (*l)->t;
330 
331 	if (BC_ERR(lt >= min && lt <= BC_RESULT_ONE))
332 		bc_vm_err(BC_ERR_EXEC_TYPE);
333 
334 #if DC_ENABLED
335 	if(BC_IS_DC) {
336 
337 		bool good = (((*r)->t == BC_RESULT_STR || BC_PROG_STR(*rn)) &&
338 		             lt <= BC_RESULT_ARRAY_ELEM);
339 
340 		if (!good) bc_program_type_num(*r, *rn);
341 	}
342 #else
343 	assert((*r)->t != BC_RESULT_STR);
344 #endif // DC_ENABLED
345 }
346 
bc_program_prep(BcProgram * p,BcResult ** r,BcNum ** n,size_t idx)347 static void bc_program_prep(BcProgram *p, BcResult **r, BcNum **n, size_t idx) {
348 
349 	assert(p != NULL && r != NULL && n != NULL);
350 
351 #ifndef BC_PROG_NO_STACK_CHECK
352 	if (BC_IS_DC) {
353 		if (BC_ERR(!BC_PROG_STACK(&p->results, idx + 1)))
354 			bc_vm_err(BC_ERR_EXEC_STACK);
355 	}
356 #endif // BC_PROG_NO_STACK_CHECK
357 
358 	assert(BC_PROG_STACK(&p->results, idx + 1));
359 
360 	bc_program_operand(p, r, n, idx);
361 
362 #if DC_ENABLED
363 	assert((*r)->t != BC_RESULT_VAR || !BC_PROG_STR(*n));
364 #endif // DC_ENABLED
365 
366 	bc_program_type_num(*r, *n);
367 }
368 
bc_program_prepResult(BcProgram * p)369 static BcResult* bc_program_prepResult(BcProgram *p) {
370 
371 	BcResult res;
372 
373 	bc_result_clear(&res);
374 	bc_vec_push(&p->results, &res);
375 
376 	return bc_vec_top(&p->results);
377 }
378 
bc_program_const(BcProgram * p,const char * code,size_t * bgn)379 static void bc_program_const(BcProgram *p, const char *code, size_t *bgn) {
380 
381 	BcResult *r = bc_program_prepResult(p);
382 	BcConst *c = bc_vec_item(p->consts, bc_program_index(code, bgn));
383 	BcBigDig base = BC_PROG_IBASE(p);
384 
385 	if (c->base != base) {
386 
387 		if (c->num.num == NULL) {
388 			BC_SIG_LOCK;
389 			bc_num_init(&c->num, BC_NUM_RDX(strlen(c->val)));
390 			BC_SIG_UNLOCK;
391 		}
392 
393 		// bc_num_parse() should only do operations that cannot fail.
394 		bc_num_parse(&c->num, c->val, base);
395 
396 		c->base = base;
397 	}
398 
399 	BC_SIG_LOCK;
400 
401 	bc_num_createCopy(&r->d.n, &c->num);
402 
403 	BC_SIG_UNLOCK;
404 }
405 
bc_program_op(BcProgram * p,uchar inst)406 static void bc_program_op(BcProgram *p, uchar inst) {
407 
408 	BcResult *opd1, *opd2, *res;
409 	BcNum *n1, *n2;
410 	size_t idx = inst - BC_INST_POWER;
411 
412 	res = bc_program_prepResult(p);
413 
414 	bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2, 1);
415 
416 	BC_SIG_LOCK;
417 
418 	bc_num_init(&res->d.n, bc_program_opReqs[idx](n1, n2, BC_PROG_SCALE(p)));
419 
420 	BC_SIG_UNLOCK;
421 
422 	assert(BC_NUM_RDX_VALID(n1));
423 	assert(BC_NUM_RDX_VALID(n2));
424 
425 	bc_program_ops[idx](n1, n2, &res->d.n, BC_PROG_SCALE(p));
426 
427 	bc_program_retire(p, 1, 2);
428 }
429 
bc_program_read(BcProgram * p)430 static void bc_program_read(BcProgram *p) {
431 
432 	BcStatus s;
433 	BcParse parse;
434 	BcVec buf;
435 	BcInstPtr ip;
436 	size_t i;
437 	const char* file;
438 	BcFunc *f = bc_vec_item(&p->fns, BC_PROG_READ);
439 
440 	for (i = 0; i < p->stack.len; ++i) {
441 		BcInstPtr *ip_ptr = bc_vec_item(&p->stack, i);
442 		if (ip_ptr->func == BC_PROG_READ)
443 			bc_vm_err(BC_ERR_EXEC_REC_READ);
444 	}
445 
446 	BC_SIG_LOCK;
447 
448 	file = vm.file;
449 	bc_parse_init(&parse, p, BC_PROG_READ);
450 	bc_vec_init(&buf, sizeof(char), NULL);
451 
452 	BC_SETJMP_LOCKED(exec_err);
453 
454 	BC_SIG_UNLOCK;
455 
456 	bc_lex_file(&parse.l, bc_program_stdin_name);
457 	bc_vec_popAll(&f->code);
458 
459 	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 
491 exec_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
bc_program_rand(BcProgram * p)500 static 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 
bc_program_printChars(const char * str)512 static 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 
bc_program_printString(const char * restrict str)525 static 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 
bc_program_print(BcProgram * p,uchar inst,size_t idx)562 static 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 
bc_program_negate(BcResult * r,BcNum * n)617 void 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 
bc_program_not(BcResult * r,BcNum * n)622 void 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
bc_program_trunc(BcResult * r,BcNum * n)627 void 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 
bc_program_unary(BcProgram * p,uchar inst)633 static 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 
bc_program_logical(BcProgram * p,uchar inst)652 static 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
bc_program_assignStr(BcProgram * p,size_t idx,BcVec * v,bool push)729 static 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 
bc_program_copyToVar(BcProgram * p,size_t idx,BcType t,bool last)746 static 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 
bc_program_assign(BcProgram * p,uchar inst)850 static 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 
bc_program_pushVar(BcProgram * p,const char * restrict code,size_t * restrict bgn,bool pop,bool copy)948 static 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 
bc_program_pushArray(BcProgram * p,const char * restrict code,size_t * restrict bgn,uchar inst)994 static 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
bc_program_incdec(BcProgram * p,uchar inst)1026 static 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 
1060 exit:
1061 	BC_SIG_MAYLOCK;
1062 	bc_num_free(&copy.d.n);
1063 	BC_LONGJMP_CONT;
1064 }
1065 
bc_program_call(BcProgram * p,const char * restrict code,size_t * restrict idx)1066 static 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 
bc_program_return(BcProgram * p,uchar inst)1136 static 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 
bc_program_builtin(BcProgram * p,uchar inst)1185 static 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
bc_program_divmod(BcProgram * p)1289 static 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 
bc_program_modexp(BcProgram * p)1318 static 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 
bc_program_stackLen(BcProgram * p)1350 static void bc_program_stackLen(BcProgram *p) {
1351 	bc_program_pushBigdig(p, (BcBigDig) p->results.len, BC_RESULT_TEMP);
1352 }
1353 
bc_program_asciifyNum(BcProgram * p,BcNum * n)1354 static 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 
1381 num_err:
1382 	BC_SIG_MAYLOCK;
1383 	bc_num_free(&num);
1384 	BC_LONGJMP_CONT;
1385 	return (uchar) val;
1386 }
1387 
bc_program_asciify(BcProgram * p)1388 static 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 
bc_program_printStream(BcProgram * p)1428 static 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 
bc_program_nquit(BcProgram * p,uchar inst)1450 static 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 
bc_program_execStr(BcProgram * p,const char * restrict code,size_t * restrict bgn,bool cond,size_t len)1484 static 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 
1589 err:
1590 	BC_SIG_MAYLOCK;
1591 	bc_parse_free(&prs);
1592 	f = bc_vec_item(&p->fns, fidx);
1593 	bc_vec_popAll(&f->code);
1594 exit:
1595 	bc_vec_pop(&p->results);
1596 	BC_LONGJMP_CONT;
1597 }
1598 
bc_program_printStack(BcProgram * p)1599 static 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 
bc_program_pushGlobal(BcProgram * p,uchar inst)1608 static 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
bc_program_pushSeed(BcProgram * p)1619 static 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 
bc_program_addFunc(BcProgram * p,BcFunc * f,BcId * id_ptr)1636 static 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 
bc_program_insertFunc(BcProgram * p,const char * name)1652 size_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
bc_program_free(BcProgram * p)1689 void 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 
bc_program_init(BcProgram * p)1725 void 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 
bc_program_reset(BcProgram * p)1794 void 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 
bc_program_exec(BcProgram * p)1822 void 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
bc_program_printStackDebug(BcProgram * p)2273 void 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 
bc_program_printIndex(const char * restrict code,size_t * restrict bgn)2279 static 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 
bc_program_printStr(const BcProgram * p,const char * restrict code,size_t * restrict bgn)2293 static 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 
bc_program_printInst(const BcProgram * p,const char * restrict code,size_t * restrict bgn)2304 void 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 
bc_program_code(const BcProgram * p)2333 void 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