xref: /freebsd/contrib/bc/src/program.c (revision fdc4a7c8012b214986cfa2e2fb6d99731f004b1b)
1 /*
2  * *****************************************************************************
3  *
4  * SPDX-License-Identifier: BSD-2-Clause
5  *
6  * Copyright (c) 2018-2025 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 /**
52  * Does a type check for something that expects a number.
53  * @param r  The result that will be checked.
54  * @param n  The result's number.
55  */
56 static inline void
bc_program_type_num(BcResult * r,BcNum * n)57 bc_program_type_num(BcResult* r, BcNum* n)
58 {
59 #if BC_ENABLED
60 
61 	// This should have already been taken care of.
62 	assert(r->t != BC_RESULT_VOID);
63 
64 #endif // BC_ENABLED
65 
66 	if (BC_ERR(!BC_PROG_NUM(r, n))) bc_err(BC_ERR_EXEC_TYPE);
67 }
68 
69 #if BC_ENABLED
70 
71 /**
72  * Does a type check.
73  * @param r  The result to check.
74  * @param t  The type that the result should be.
75  */
76 static void
bc_program_type_match(BcResult * r,BcType t)77 bc_program_type_match(BcResult* r, BcType t)
78 {
79 	if (BC_ERR((r->t != BC_RESULT_ARRAY) != (!t))) bc_err(BC_ERR_EXEC_TYPE);
80 }
81 #endif // BC_ENABLED
82 
83 /**
84  * Pulls an index out of a bytecode vector and updates the index into the vector
85  * to point to the spot after the index. For more details on bytecode indices,
86  * see the development manual (manuals/development.md#bytecode-indices).
87  * @param code  The bytecode vector.
88  * @param bgn   An in/out parameter; the index into the vector that will be
89  *              updated.
90  * @return      The index at @a bgn in the bytecode vector.
91  */
92 static size_t
bc_program_index(const char * restrict code,size_t * restrict bgn)93 bc_program_index(const char* restrict code, size_t* restrict bgn)
94 {
95 	uchar amt = (uchar) code[(*bgn)++], i = 0;
96 	size_t res = 0;
97 
98 	for (; i < amt; ++i, ++(*bgn))
99 	{
100 		size_t temp = ((size_t) ((int) (uchar) code[*bgn]) & UCHAR_MAX);
101 		res |= (temp << (i * CHAR_BIT));
102 	}
103 
104 	return res;
105 }
106 
107 /**
108  * Returns a string from a result and its number.
109  * @param p  The program.
110  * @param n  The number tied to the result.
111  * @return   The string corresponding to the result and number.
112  */
113 static inline char*
bc_program_string(BcProgram * p,const BcNum * n)114 bc_program_string(BcProgram* p, const BcNum* n)
115 {
116 	return *((char**) bc_vec_item(&p->strs, n->scale));
117 }
118 
119 #if BC_ENABLED
120 
121 /**
122  * Prepares the globals for a function call. This is only called when global
123  * stacks are on because it pushes a copy of the current globals onto each of
124  * their respective stacks.
125  * @param p  The program.
126  */
127 static void
bc_program_prepGlobals(BcProgram * p)128 bc_program_prepGlobals(BcProgram* p)
129 {
130 	size_t i;
131 
132 	for (i = 0; i < BC_PROG_GLOBALS_LEN; ++i)
133 	{
134 		bc_vec_push(p->globals_v + i, p->globals + i);
135 	}
136 
137 #if BC_ENABLE_EXTRA_MATH
138 	bc_rand_push(&p->rng);
139 #endif // BC_ENABLE_EXTRA_MATH
140 }
141 
142 /**
143  * Pops globals stacks on returning from a function, or in the case of reset,
144  * pops all but one item on each global stack.
145  * @param p      The program.
146  * @param reset  True if all but one item on each stack should be popped, false
147  *               otherwise.
148  */
149 static void
bc_program_popGlobals(BcProgram * p,bool reset)150 bc_program_popGlobals(BcProgram* p, bool reset)
151 {
152 	size_t i;
153 
154 	BC_SIG_ASSERT_LOCKED;
155 
156 	for (i = 0; i < BC_PROG_GLOBALS_LEN; ++i)
157 	{
158 		BcVec* v = p->globals_v + i;
159 		bc_vec_npop(v, reset ? v->len - 1 : 1);
160 		p->globals[i] = BC_PROG_GLOBAL(v);
161 	}
162 
163 #if BC_ENABLE_EXTRA_MATH
164 	bc_rand_pop(&p->rng, reset);
165 #endif // BC_ENABLE_EXTRA_MATH
166 }
167 
168 /**
169  * Derefeneces an array reference and returns a pointer to the real array.
170  * @param p    The program.
171  * @param vec  The reference vector.
172  * @return     A pointer to the desired array.
173  */
174 static BcVec*
bc_program_dereference(const BcProgram * p,BcVec * vec)175 bc_program_dereference(const BcProgram* p, BcVec* vec)
176 {
177 	BcVec* v;
178 	size_t vidx, nidx, i = 0;
179 
180 	// We want to be sure we have a reference vector.
181 	assert(vec->size == sizeof(uchar));
182 
183 	// Get the index of the vector in arrs, then the index of the original
184 	// referenced vector.
185 	vidx = bc_program_index(vec->v, &i);
186 	nidx = bc_program_index(vec->v, &i);
187 
188 	v = bc_vec_item(bc_vec_item(&p->arrs, vidx), nidx);
189 
190 	// We want to be sure we do *not* have a reference vector.
191 	assert(v->size != sizeof(uchar));
192 
193 	return v;
194 }
195 
196 #endif // BC_ENABLED
197 
198 /**
199  * Creates a BcNum from a BcBigDig and pushes onto the results stack. This is a
200  * convenience function.
201  * @param p     The program.
202  * @param dig   The BcBigDig to push onto the results stack.
203  * @param type  The type that the pushed result should be.
204  */
205 static void
bc_program_pushBigdig(BcProgram * p,BcBigDig dig,BcResultType type)206 bc_program_pushBigdig(BcProgram* p, BcBigDig dig, BcResultType type)
207 {
208 	BcResult res;
209 
210 	res.t = type;
211 
212 	BC_SIG_LOCK;
213 
214 	bc_num_createFromBigdig(&res.d.n, dig);
215 	bc_vec_push(&p->results, &res);
216 
217 	BC_SIG_UNLOCK;
218 }
219 
220 size_t
bc_program_addString(BcProgram * p,const char * str)221 bc_program_addString(BcProgram* p, const char* str)
222 {
223 	size_t idx;
224 
225 	BC_SIG_ASSERT_LOCKED;
226 
227 	if (bc_map_insert(&p->str_map, str, p->strs.len, &idx))
228 	{
229 		char** str_ptr;
230 		BcId* id = bc_vec_item(&p->str_map, idx);
231 
232 		// Get the index.
233 		idx = id->idx;
234 
235 		// Push an empty string on the proper vector.
236 		str_ptr = bc_vec_pushEmpty(&p->strs);
237 
238 		// We reuse the string in the ID (allocated by bc_map_insert()), because
239 		// why not?
240 		*str_ptr = id->name;
241 	}
242 	else
243 	{
244 		BcId* id = bc_vec_item(&p->str_map, idx);
245 		idx = id->idx;
246 	}
247 
248 	return idx;
249 }
250 
251 size_t
bc_program_search(BcProgram * p,const char * name,bool var)252 bc_program_search(BcProgram* p, const char* name, bool var)
253 {
254 	BcVec* v;
255 	BcVec* map;
256 	size_t i;
257 
258 	BC_SIG_ASSERT_LOCKED;
259 
260 	// Grab the right vector and map.
261 	v = var ? &p->vars : &p->arrs;
262 	map = var ? &p->var_map : &p->arr_map;
263 
264 	// We do an insert because the variable might not exist yet. This is because
265 	// the parser calls this function. If the insert succeeds, we create a stack
266 	// for the variable/array. But regardless, bc_map_insert() gives us the
267 	// index of the item in i.
268 	if (bc_map_insert(map, name, v->len, &i))
269 	{
270 		BcVec* temp = bc_vec_pushEmpty(v);
271 		bc_array_init(temp, var);
272 	}
273 
274 	return ((BcId*) bc_vec_item(map, i))->idx;
275 }
276 
277 /**
278  * Returns the correct variable or array stack for the type.
279  * @param p     The program.
280  * @param idx   The index of the variable or array in the variable or array
281  *              vector.
282  * @param type  The type of vector to return.
283  * @return      A pointer to the variable or array stack.
284  */
285 static inline BcVec*
bc_program_vec(const BcProgram * p,size_t idx,BcType type)286 bc_program_vec(const BcProgram* p, size_t idx, BcType type)
287 {
288 	const BcVec* v = (type == BC_TYPE_VAR) ? &p->vars : &p->arrs;
289 	return bc_vec_item(v, idx);
290 }
291 
292 /**
293  * Returns a pointer to the BcNum corresponding to the result. There is one
294  * case, however, where this returns a pointer to a BcVec: if the type of the
295  * result is array. In that case, the pointer is casted to a pointer to BcNum,
296  * but is never used. The function that calls this expecting an array casts the
297  * pointer back. This function is called a lot and needs to be as fast as
298  * possible.
299  * @param p  The program.
300  * @param r  The result whose number will be returned.
301  * @return   The BcNum corresponding to the result.
302  */
303 static BcNum*
bc_program_num(BcProgram * p,BcResult * r)304 bc_program_num(BcProgram* p, BcResult* r)
305 {
306 	BcNum* n;
307 
308 #ifdef _WIN32
309 	// Windows made it an error to not initialize this, so shut it up.
310 	// I don't want to do this on other platforms because this procedure
311 	// is one of the most heavily-used, and eliminating the initialization
312 	// is a performance win.
313 	n = NULL;
314 #endif // _WIN32
315 
316 	switch (r->t)
317 	{
318 		case BC_RESULT_STR:
319 		case BC_RESULT_TEMP:
320 		case BC_RESULT_IBASE:
321 		case BC_RESULT_SCALE:
322 		case BC_RESULT_OBASE:
323 #if BC_ENABLE_EXTRA_MATH
324 		case BC_RESULT_SEED:
325 #endif // BC_ENABLE_EXTRA_MATH
326 		{
327 			n = &r->d.n;
328 			break;
329 		}
330 
331 		case BC_RESULT_VAR:
332 		case BC_RESULT_ARRAY:
333 		case BC_RESULT_ARRAY_ELEM:
334 		{
335 			BcVec* v;
336 			BcType type = (r->t == BC_RESULT_VAR) ? BC_TYPE_VAR : BC_TYPE_ARRAY;
337 
338 			// Get the correct variable or array vector.
339 			v = bc_program_vec(p, r->d.loc.loc, type);
340 
341 			// Surprisingly enough, the hard case is *not* returning an array;
342 			// it's returning an array element. This is because we have to dig
343 			// deeper to get *to* the element. That's what the code inside this
344 			// if statement does.
345 			if (r->t == BC_RESULT_ARRAY_ELEM)
346 			{
347 				size_t idx = r->d.loc.idx;
348 
349 				v = bc_vec_item(v, r->d.loc.stack_idx);
350 
351 #if BC_ENABLED
352 				// If this is true, we have a reference vector, so dereference
353 				// it. The reason we don't need to worry about it for returning
354 				// a straight array is because we only care about references
355 				// when we access elements of an array that is a reference. That
356 				// is this code, so in essence, this line takes care of arrays
357 				// as well.
358 				if (v->size == sizeof(uchar)) v = bc_program_dereference(p, v);
359 #endif // BC_ENABLED
360 
361 				// We want to be sure we got a valid array of numbers.
362 				assert(v->size == sizeof(BcNum));
363 
364 				// The bc spec says that if an element is accessed that does not
365 				// exist, it should be preinitialized to 0. Well, if we access
366 				// an element *way* out there, we have to preinitialize all
367 				// elements between the current last element and the actual
368 				// accessed element.
369 				if (v->len <= idx)
370 				{
371 					BC_SIG_LOCK;
372 					bc_array_expand(v, bc_vm_growSize(idx, 1));
373 					BC_SIG_UNLOCK;
374 				}
375 
376 				n = bc_vec_item(v, idx);
377 			}
378 			// This is either a number (for a var) or an array (for an array).
379 			// Because bc_vec_top() and bc_vec_item() return a void*, we don't
380 			// need to cast.
381 			else
382 			{
383 #if BC_ENABLED
384 				if (BC_IS_BC)
385 				{
386 					n = bc_vec_item(v, r->d.loc.stack_idx);
387 				}
388 				else
389 #endif // BC_ENABLED
390 				{
391 					n = bc_vec_top(v);
392 				}
393 			}
394 
395 			break;
396 		}
397 
398 		case BC_RESULT_ZERO:
399 		{
400 			n = &vm->zero;
401 			break;
402 		}
403 
404 		case BC_RESULT_ONE:
405 		{
406 			n = &vm->one;
407 			break;
408 		}
409 
410 #if BC_ENABLED
411 		// We should never get here; this is taken care of earlier because a
412 		// result is expected.
413 		case BC_RESULT_VOID:
414 #if BC_DEBUG
415 		{
416 			abort();
417 			// Fallthrough
418 		}
419 #endif // BC_DEBUG
420 		case BC_RESULT_LAST:
421 		{
422 			n = &p->last;
423 			break;
424 		}
425 #endif // BC_ENABLED
426 
427 #if BC_GCC
428 		// This is here in GCC to quiet the "maybe-uninitialized" warning.
429 		default:
430 		{
431 			abort();
432 		}
433 #endif // BC_GCC
434 	}
435 
436 	return n;
437 }
438 
439 /**
440  * Prepares an operand for use.
441  * @param p    The program.
442  * @param r    An out parameter; this is set to the pointer to the result that
443  *             we care about.
444  * @param n    An out parameter; this is set to the pointer to the number that
445  *             we care about.
446  * @param idx  The index of the result from the top of the results stack.
447  */
448 static void
bc_program_operand(BcProgram * p,BcResult ** r,BcNum ** n,size_t idx)449 bc_program_operand(BcProgram* p, BcResult** r, BcNum** n, size_t idx)
450 {
451 	*r = bc_vec_item_rev(&p->results, idx);
452 
453 #if BC_ENABLED
454 	if (BC_ERR((*r)->t == BC_RESULT_VOID)) bc_err(BC_ERR_EXEC_VOID_VAL);
455 #endif // BC_ENABLED
456 
457 	*n = bc_program_num(p, *r);
458 }
459 
460 /**
461  * Prepares the operands of a binary operator.
462  * @param p    The program.
463  * @param l    An out parameter; this is set to the pointer to the result for
464  *             the left operand.
465  * @param ln   An out parameter; this is set to the pointer to the number for
466  *             the left operand.
467  * @param r    An out parameter; this is set to the pointer to the result for
468  *             the right operand.
469  * @param rn   An out parameter; this is set to the pointer to the number for
470  *             the right operand.
471  * @param idx  The starting index where the operands are in the results stack,
472  *             starting from the top.
473  */
474 static void
bc_program_binPrep(BcProgram * p,BcResult ** l,BcNum ** ln,BcResult ** r,BcNum ** rn,size_t idx)475 bc_program_binPrep(BcProgram* p, BcResult** l, BcNum** ln, BcResult** r,
476                    BcNum** rn, size_t idx)
477 {
478 	BcResultType lt;
479 
480 	assert(p != NULL && l != NULL && ln != NULL && r != NULL && rn != NULL);
481 
482 #ifndef BC_PROG_NO_STACK_CHECK
483 	// Check the stack for dc.
484 	if (BC_IS_DC)
485 	{
486 		if (BC_ERR(!BC_PROG_STACK(&p->results, idx + 2)))
487 		{
488 			bc_err(BC_ERR_EXEC_STACK);
489 		}
490 	}
491 #endif // BC_PROG_NO_STACK_CHECK
492 
493 	assert(BC_PROG_STACK(&p->results, idx + 2));
494 
495 	// Get the operands.
496 	bc_program_operand(p, l, ln, idx + 1);
497 	bc_program_operand(p, r, rn, idx);
498 
499 	lt = (*l)->t;
500 
501 #if BC_ENABLED
502 	// bc_program_operand() checked these for us.
503 	assert(lt != BC_RESULT_VOID && (*r)->t != BC_RESULT_VOID);
504 #endif // BC_ENABLED
505 
506 	// We run this again under these conditions in case any vector has been
507 	// reallocated out from under the BcNums or arrays we had. In other words,
508 	// this is to fix pointer invalidation.
509 	if (lt == (*r)->t && (lt == BC_RESULT_VAR || lt == BC_RESULT_ARRAY_ELEM))
510 	{
511 		*ln = bc_program_num(p, *l);
512 	}
513 
514 	if (BC_ERR(lt == BC_RESULT_STR)) bc_err(BC_ERR_EXEC_TYPE);
515 }
516 
517 /**
518  * Prepares the operands of a binary operator and type checks them. This is
519  * separate from bc_program_binPrep() because some places want this, others want
520  * bc_program_binPrep().
521  * @param p    The program.
522  * @param l    An out parameter; this is set to the pointer to the result for
523  *             the left operand.
524  * @param ln   An out parameter; this is set to the pointer to the number for
525  *             the left operand.
526  * @param r    An out parameter; this is set to the pointer to the result for
527  *             the right operand.
528  * @param rn   An out parameter; this is set to the pointer to the number for
529  *             the right operand.
530  * @param idx  The starting index where the operands are in the results stack,
531  *             starting from the top.
532  */
533 static void
bc_program_binOpPrep(BcProgram * p,BcResult ** l,BcNum ** ln,BcResult ** r,BcNum ** rn,size_t idx)534 bc_program_binOpPrep(BcProgram* p, BcResult** l, BcNum** ln, BcResult** r,
535                      BcNum** rn, size_t idx)
536 {
537 	bc_program_binPrep(p, l, ln, r, rn, idx);
538 	bc_program_type_num(*l, *ln);
539 	bc_program_type_num(*r, *rn);
540 }
541 
542 /**
543  * Prepares the operands of an assignment operator.
544  * @param p   The program.
545  * @param l   An out parameter; this is set to the pointer to the result for the
546  *            left operand.
547  * @param ln  An out parameter; this is set to the pointer to the number for the
548  *            left operand.
549  * @param r   An out parameter; this is set to the pointer to the result for the
550  *            right operand.
551  * @param rn  An out parameter; this is set to the pointer to the number for the
552  *            right operand.
553  */
554 static void
bc_program_assignPrep(BcProgram * p,BcResult ** l,BcNum ** ln,BcResult ** r,BcNum ** rn)555 bc_program_assignPrep(BcProgram* p, BcResult** l, BcNum** ln, BcResult** r,
556                       BcNum** rn)
557 {
558 	BcResultType lt, min;
559 	bool good;
560 
561 	// This is the min non-allowable result type. dc allows strings.
562 	min = BC_RESULT_TEMP - ((unsigned int) (BC_IS_BC));
563 
564 	// Prepare the operands.
565 	bc_program_binPrep(p, l, ln, r, rn, 0);
566 
567 	lt = (*l)->t;
568 
569 	// Typecheck the left.
570 	if (BC_ERR(lt >= min && lt <= BC_RESULT_ONE)) bc_err(BC_ERR_EXEC_TYPE);
571 
572 	// Strings can be assigned to variables. We are already good if we are
573 	// assigning a string.
574 	good = ((*r)->t == BC_RESULT_STR && lt <= BC_RESULT_ARRAY_ELEM);
575 
576 	assert(BC_PROG_STR(*rn) || (*r)->t != BC_RESULT_STR);
577 
578 	// If not, type check for a number.
579 	if (!good) bc_program_type_num(*r, *rn);
580 }
581 
582 /**
583  * Prepares a single operand and type checks it. This is separate from
584  * bc_program_operand() because different places want one or the other.
585  * @param p    The program.
586  * @param r    An out parameter; this is set to the pointer to the result that
587  *             we care about.
588  * @param n    An out parameter; this is set to the pointer to the number that
589  *             we care about.
590  * @param idx  The index of the result from the top of the results stack.
591  */
592 static void
bc_program_prep(BcProgram * p,BcResult ** r,BcNum ** n,size_t idx)593 bc_program_prep(BcProgram* p, BcResult** r, BcNum** n, size_t idx)
594 {
595 	assert(p != NULL && r != NULL && n != NULL);
596 
597 #ifndef BC_PROG_NO_STACK_CHECK
598 	// Check the stack for dc.
599 	if (BC_IS_DC)
600 	{
601 		if (BC_ERR(!BC_PROG_STACK(&p->results, idx + 1)))
602 		{
603 			bc_err(BC_ERR_EXEC_STACK);
604 		}
605 	}
606 #endif // BC_PROG_NO_STACK_CHECK
607 
608 	assert(BC_PROG_STACK(&p->results, idx + 1));
609 
610 	bc_program_operand(p, r, n, idx);
611 
612 	// dc does not allow strings in this case.
613 	bc_program_type_num(*r, *n);
614 }
615 
616 /**
617  * Prepares and returns a clean result for the result of an operation.
618  * @param p  The program.
619  * @return   A clean result.
620  */
621 static BcResult*
bc_program_prepResult(BcProgram * p)622 bc_program_prepResult(BcProgram* p)
623 {
624 	BcResult* res = bc_vec_pushEmpty(&p->results);
625 
626 	// Mark a result as not retired.
627 	p->nresults += 1;
628 
629 	bc_result_clear(res);
630 
631 	return res;
632 }
633 
634 /**
635  * Prepares a constant for use. This parses the constant into a number and then
636  * pushes that number onto the results stack.
637  * @param p     The program.
638  * @param code  The bytecode vector that we will pull the index of the constant
639  *              from.
640  * @param bgn   An in/out parameter; marks the start of the index in the
641  *              bytecode vector and will be updated to point to after the index.
642  */
643 static void
bc_program_const(BcProgram * p,const char * code,size_t * bgn)644 bc_program_const(BcProgram* p, const char* code, size_t* bgn)
645 {
646 	// I lied. I actually push the result first. I can do this because the
647 	// result will be popped on error. I also get the constant itself.
648 	BcResult* r = bc_program_prepResult(p);
649 	BcConst* c = bc_vec_item(&p->consts, bc_program_index(code, bgn));
650 	BcBigDig base = BC_PROG_IBASE(p);
651 
652 	assert(p->nresults == 1);
653 
654 	// Only reparse if the base changed.
655 	if (c->base != base)
656 	{
657 		// Allocate if we haven't yet.
658 		if (c->num.num == NULL)
659 		{
660 			// The plus 1 is in case of overflow with lack of clamping.
661 			size_t len = strlen(c->val) + (BC_DIGIT_CLAMP == 0);
662 
663 			BC_SIG_LOCK;
664 			bc_num_init(&c->num, BC_NUM_RDX(len));
665 			BC_SIG_UNLOCK;
666 		}
667 		// We need to zero an already existing number.
668 		else bc_num_zero(&c->num);
669 
670 		// bc_num_parse() should only do operations that cannot fail.
671 		bc_num_parse(&c->num, c->val, base);
672 
673 		c->base = base;
674 	}
675 
676 	BC_SIG_LOCK;
677 
678 	bc_num_createCopy(&r->d.n, &c->num);
679 
680 	BC_SIG_UNLOCK;
681 
682 	// XXX: Make sure to clear the number of results.
683 	p->nresults -= 1;
684 }
685 
686 /**
687  * Executes a binary operator operation.
688  * @param p     The program.
689  * @param inst  The instruction corresponding to the binary operator to execute.
690  */
691 static void
bc_program_op(BcProgram * p,uchar inst)692 bc_program_op(BcProgram* p, uchar inst)
693 {
694 	BcResult* opd1;
695 	BcResult* opd2;
696 	BcResult* res;
697 	BcNum* n1;
698 	BcNum* n2;
699 	size_t idx = inst - BC_INST_POWER;
700 
701 	res = bc_program_prepResult(p);
702 
703 	assert(p->nresults == 1);
704 
705 	bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2, 1);
706 
707 	BC_SIG_LOCK;
708 
709 	// Initialize the number with enough space, using the correct
710 	// BcNumBinaryOpReq function. This looks weird because it is executing an
711 	// item of an array. Rest assured that item is a function.
712 	bc_num_init(&res->d.n, bc_program_opReqs[idx](n1, n2, BC_PROG_SCALE(p)));
713 
714 	BC_SIG_UNLOCK;
715 
716 	assert(BC_NUM_RDX_VALID(n1));
717 	assert(BC_NUM_RDX_VALID(n2));
718 
719 	// Run the operation. This also executes an item of an array.
720 	bc_program_ops[idx](n1, n2, &res->d.n, BC_PROG_SCALE(p));
721 
722 	bc_program_retire(p, 2);
723 }
724 
725 /**
726  * Executes a read() or ? command.
727  * @param p  The program.
728  */
729 static void
bc_program_read(BcProgram * p)730 bc_program_read(BcProgram* p)
731 {
732 	BcStatus s;
733 	BcInstPtr ip;
734 	size_t i;
735 	const char* file;
736 	BcMode mode;
737 	BcFunc* f = bc_vec_item(&p->fns, BC_PROG_READ);
738 
739 	// If we are already executing a read, that is an error. So look for a read
740 	// and barf.
741 	for (i = 0; i < p->stack.len; ++i)
742 	{
743 		BcInstPtr* ip_ptr = bc_vec_item(&p->stack, i);
744 		if (ip_ptr->func == BC_PROG_READ) bc_err(BC_ERR_EXEC_REC_READ);
745 	}
746 
747 	BC_SIG_LOCK;
748 
749 	// Save the filename because we are going to overwrite it.
750 	file = vm->file;
751 	mode = vm->mode;
752 
753 	// It is a parse error if there needs to be more than one line, so we unset
754 	// this to tell the lexer to not request more. We set it back later.
755 	vm->mode = BC_MODE_FILE;
756 
757 	if (!BC_PARSE_IS_INITED(&vm->read_prs, p))
758 	{
759 		// We need to parse, but we don't want to use the existing parser
760 		// because it has state it needs to keep. (It could have a partial parse
761 		// state.) So we create a new parser. This parser is in the BcVm struct
762 		// so that it is not local, which means that a longjmp() could change
763 		// it.
764 		bc_parse_init(&vm->read_prs, p, BC_PROG_READ);
765 
766 		// We need a separate input buffer; that's why it is also in the BcVm
767 		// struct.
768 		bc_vec_init(&vm->read_buf, sizeof(char), BC_DTOR_NONE);
769 	}
770 	else
771 	{
772 		// This needs to be updated because the parser could have been used
773 		// somewhere else.
774 		bc_parse_updateFunc(&vm->read_prs, BC_PROG_READ);
775 
776 		// The read buffer also needs to be emptied or else it will still
777 		// contain previous read expressions.
778 		bc_vec_empty(&vm->read_buf);
779 	}
780 
781 	BC_SETJMP_LOCKED(vm, exec_err);
782 
783 	BC_SIG_UNLOCK;
784 
785 	// Set up the lexer and the read function.
786 	bc_lex_file(&vm->read_prs.l, bc_program_stdin_name);
787 	bc_vec_popAll(&f->code);
788 
789 	// Read a line.
790 	if (!BC_R) s = bc_read_line(&vm->read_buf, "");
791 	else s = bc_read_line(&vm->read_buf, BC_VM_READ_PROMPT);
792 
793 	// We should *not* have run into EOF.
794 	if (s == BC_STATUS_EOF) bc_err(BC_ERR_EXEC_READ_EXPR);
795 
796 	// Parse *one* expression, so mode should not be stdin.
797 	bc_parse_text(&vm->read_prs, vm->read_buf.v, BC_MODE_FILE);
798 	BC_SIG_LOCK;
799 	vm->expr(&vm->read_prs, BC_PARSE_NOREAD | BC_PARSE_NEEDVAL);
800 	BC_SIG_UNLOCK;
801 
802 	// We *must* have a valid expression. A semicolon cannot end an expression,
803 	// although EOF can.
804 	if (BC_ERR(vm->read_prs.l.t != BC_LEX_NLINE &&
805 	           vm->read_prs.l.t != BC_LEX_EOF))
806 	{
807 		bc_err(BC_ERR_EXEC_READ_EXPR);
808 	}
809 
810 #if BC_ENABLED
811 	// Push on the globals stack if necessary.
812 	if (BC_G) bc_program_prepGlobals(p);
813 #endif // BC_ENABLED
814 
815 	// Set up a new BcInstPtr.
816 	ip.func = BC_PROG_READ;
817 	ip.idx = 0;
818 	ip.len = p->results.len;
819 
820 	// Update this pointer, just in case.
821 	f = bc_vec_item(&p->fns, BC_PROG_READ);
822 
823 	// We want a return instruction to simplify things.
824 	bc_vec_pushByte(&f->code, vm->read_ret);
825 
826 	// This lock is here to make sure dc's tail calls are the same length.
827 	BC_SIG_LOCK;
828 	bc_vec_push(&p->stack, &ip);
829 
830 #if DC_ENABLED
831 	// We need a new tail call entry for dc.
832 	if (BC_IS_DC)
833 	{
834 		size_t temp = 0;
835 		bc_vec_push(&p->tail_calls, &temp);
836 	}
837 #endif // DC_ENABLED
838 
839 exec_err:
840 	BC_SIG_MAYLOCK;
841 	vm->mode = (uchar) mode;
842 	vm->file = file;
843 	BC_LONGJMP_CONT(vm);
844 }
845 
846 #if BC_ENABLE_EXTRA_MATH
847 
848 /**
849  * Execute a rand().
850  * @param p  The program.
851  */
852 static void
bc_program_rand(BcProgram * p)853 bc_program_rand(BcProgram* p)
854 {
855 	BcRand rand = bc_rand_int(&p->rng);
856 
857 	bc_program_pushBigdig(p, (BcBigDig) rand, BC_RESULT_TEMP);
858 
859 #if BC_DEBUG
860 	// This is just to ensure that the generated number is correct. I also use
861 	// braces because I declare every local at the top of the scope.
862 	{
863 		BcResult* r = bc_vec_top(&p->results);
864 		assert(BC_NUM_RDX_VALID_NP(r->d.n));
865 	}
866 #endif // BC_DEBUG
867 }
868 #endif // BC_ENABLE_EXTRA_MATH
869 
870 /**
871  * Prints a series of characters, without escapes.
872  * @param str  The string (series of characters).
873  */
874 static void
bc_program_printChars(const char * str)875 bc_program_printChars(const char* str)
876 {
877 	const char* nl;
878 	size_t len = vm->nchars + strlen(str);
879 	sig_atomic_t lock;
880 
881 	BC_SIG_TRYLOCK(lock);
882 
883 	bc_file_puts(&vm->fout, bc_flush_save, str);
884 
885 	// We need to update the number of characters, so we find the last newline
886 	// and set the characters accordingly.
887 	nl = strrchr(str, '\n');
888 
889 	if (nl != NULL) len = strlen(nl + 1);
890 
891 	vm->nchars = len > UINT16_MAX ? UINT16_MAX : (uint16_t) len;
892 
893 	BC_SIG_TRYUNLOCK(lock);
894 }
895 
896 /**
897  * Prints a string with escapes.
898  * @param str  The string.
899  */
900 static void
bc_program_printString(const char * restrict str)901 bc_program_printString(const char* restrict str)
902 {
903 	size_t i, len = strlen(str);
904 
905 #if DC_ENABLED
906 	// This is to ensure a nul byte is printed for dc's stream operation.
907 	if (!len && BC_IS_DC)
908 	{
909 		bc_vm_putchar('\0', bc_flush_save);
910 		return;
911 	}
912 #endif // DC_ENABLED
913 
914 	// Loop over the characters, processing escapes and printing the rest.
915 	for (i = 0; i < len; ++i)
916 	{
917 		int c = str[i];
918 
919 		// If we have an escape...
920 		if (c == '\\' && i != len - 1)
921 		{
922 			const char* ptr;
923 
924 			// Get the escape character and its companion.
925 			c = str[++i];
926 			ptr = strchr(bc_program_esc_chars, c);
927 
928 			// If we have a companion character...
929 			if (ptr != NULL)
930 			{
931 				// We need to specially handle a newline.
932 				if (c == 'n')
933 				{
934 					BC_SIG_LOCK;
935 					vm->nchars = UINT16_MAX;
936 					BC_SIG_UNLOCK;
937 				}
938 
939 				// Grab the actual character.
940 				c = bc_program_esc_seqs[(size_t) (ptr - bc_program_esc_chars)];
941 			}
942 			else
943 			{
944 				// Just print the backslash if there is no companion character.
945 				// The following character will be printed later after the outer
946 				// if statement.
947 				bc_vm_putchar('\\', bc_flush_save);
948 			}
949 		}
950 
951 		bc_vm_putchar(c, bc_flush_save);
952 	}
953 }
954 
955 /**
956  * Executes a print. This function handles all printing except streaming.
957  * @param p     The program.
958  * @param inst  The instruction for the type of print we are doing.
959  * @param idx   The index of the result that we are printing.
960  */
961 static void
bc_program_print(BcProgram * p,uchar inst,size_t idx)962 bc_program_print(BcProgram* p, uchar inst, size_t idx)
963 {
964 	BcResult* r;
965 	char* str;
966 	BcNum* n;
967 	bool pop = (inst != BC_INST_PRINT);
968 
969 	assert(p != NULL);
970 
971 #ifndef BC_PROG_NO_STACK_CHECK
972 	if (BC_IS_DC)
973 	{
974 		if (BC_ERR(!BC_PROG_STACK(&p->results, idx + 1)))
975 		{
976 			bc_err(BC_ERR_EXEC_STACK);
977 		}
978 	}
979 #endif // BC_PROG_NO_STACK_CHECK
980 
981 	assert(BC_PROG_STACK(&p->results, idx + 1));
982 
983 	r = bc_vec_item_rev(&p->results, idx);
984 
985 #if BC_ENABLED
986 	// If we have a void value, that's not necessarily an error. It is if pop is
987 	// true because that means that we are executing a print statement, but
988 	// attempting to do a print on a lone void value is allowed because that's
989 	// exactly how we want void values used.
990 	if (r->t == BC_RESULT_VOID)
991 	{
992 		if (BC_ERR(pop)) bc_err(BC_ERR_EXEC_VOID_VAL);
993 		bc_vec_pop(&p->results);
994 		return;
995 	}
996 #endif // BC_ENABLED
997 
998 	n = bc_program_num(p, r);
999 
1000 	// If we have a number...
1001 	if (BC_PROG_NUM(r, n))
1002 	{
1003 #if BC_ENABLED
1004 		assert(inst != BC_INST_PRINT_STR);
1005 #endif // BC_ENABLED
1006 
1007 		// Print the number.
1008 		bc_num_print(n, BC_PROG_OBASE(p), !pop);
1009 
1010 #if BC_ENABLED
1011 		// Need to store the number in last.
1012 		if (BC_IS_BC) bc_num_copy(&p->last, n);
1013 #endif // BC_ENABLED
1014 	}
1015 	else
1016 	{
1017 		// We want to flush any stuff in the stdout buffer first.
1018 		bc_file_flush(&vm->fout, bc_flush_save);
1019 		str = bc_program_string(p, n);
1020 
1021 #if BC_ENABLED
1022 		if (inst == BC_INST_PRINT_STR) bc_program_printChars(str);
1023 		else
1024 #endif // BC_ENABLED
1025 		{
1026 			bc_program_printString(str);
1027 
1028 			// Need to print a newline only in this case.
1029 			if (inst == BC_INST_PRINT) bc_vm_putchar('\n', bc_flush_err);
1030 		}
1031 	}
1032 
1033 	// bc always pops. This macro makes sure that happens.
1034 	if (BC_PROGRAM_POP(pop)) bc_vec_pop(&p->results);
1035 }
1036 
1037 void
bc_program_negate(BcResult * r,BcNum * n)1038 bc_program_negate(BcResult* r, BcNum* n)
1039 {
1040 	bc_num_copy(&r->d.n, n);
1041 	if (BC_NUM_NONZERO(&r->d.n)) BC_NUM_NEG_TGL_NP(r->d.n);
1042 }
1043 
1044 void
bc_program_not(BcResult * r,BcNum * n)1045 bc_program_not(BcResult* r, BcNum* n)
1046 {
1047 	if (!bc_num_cmpZero(n)) bc_num_one(&r->d.n);
1048 }
1049 
1050 #if BC_ENABLE_EXTRA_MATH
1051 void
bc_program_trunc(BcResult * r,BcNum * n)1052 bc_program_trunc(BcResult* r, BcNum* n)
1053 {
1054 	bc_num_copy(&r->d.n, n);
1055 	bc_num_truncate(&r->d.n, n->scale);
1056 }
1057 #endif // BC_ENABLE_EXTRA_MATH
1058 
1059 /**
1060  * Runs a unary operation.
1061  * @param p     The program.
1062  * @param inst  The unary operation.
1063  */
1064 static void
bc_program_unary(BcProgram * p,uchar inst)1065 bc_program_unary(BcProgram* p, uchar inst)
1066 {
1067 	BcResult* res;
1068 	BcResult* ptr;
1069 	BcNum* num;
1070 
1071 	res = bc_program_prepResult(p);
1072 
1073 	assert(p->nresults == 1);
1074 
1075 	bc_program_prep(p, &ptr, &num, 1);
1076 
1077 	BC_SIG_LOCK;
1078 
1079 	bc_num_init(&res->d.n, num->len);
1080 
1081 	BC_SIG_UNLOCK;
1082 
1083 	// This calls a function that is in an array.
1084 	bc_program_unarys[inst - BC_INST_NEG](res, num);
1085 	bc_program_retire(p, 1);
1086 }
1087 
1088 /**
1089  * Executes a logical operator.
1090  * @param p     The program.
1091  * @param inst  The operator.
1092  */
1093 static void
bc_program_logical(BcProgram * p,uchar inst)1094 bc_program_logical(BcProgram* p, uchar inst)
1095 {
1096 	BcResult* opd1;
1097 	BcResult* opd2;
1098 	BcResult* res;
1099 	BcNum* n1;
1100 	BcNum* n2;
1101 	bool cond = 0;
1102 	ssize_t cmp;
1103 
1104 	res = bc_program_prepResult(p);
1105 
1106 	assert(p->nresults == 1);
1107 
1108 	// All logical operators (except boolean not, which is taken care of by
1109 	// bc_program_unary()), are binary operators.
1110 	bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2, 1);
1111 
1112 	// Boolean and and or are not short circuiting. This is why; they can be
1113 	// implemented much easier this way.
1114 	if (inst == BC_INST_BOOL_AND)
1115 	{
1116 		cond = (bc_num_cmpZero(n1) && bc_num_cmpZero(n2));
1117 	}
1118 	else if (inst == BC_INST_BOOL_OR)
1119 	{
1120 		cond = (bc_num_cmpZero(n1) || bc_num_cmpZero(n2));
1121 	}
1122 	else
1123 	{
1124 		// We have a relational operator, so do a comparison.
1125 		cmp = bc_num_cmp(n1, n2);
1126 
1127 		switch (inst)
1128 		{
1129 			case BC_INST_REL_EQ:
1130 			{
1131 				cond = (cmp == 0);
1132 				break;
1133 			}
1134 
1135 			case BC_INST_REL_LE:
1136 			{
1137 				cond = (cmp <= 0);
1138 				break;
1139 			}
1140 
1141 			case BC_INST_REL_GE:
1142 			{
1143 				cond = (cmp >= 0);
1144 				break;
1145 			}
1146 
1147 			case BC_INST_REL_NE:
1148 			{
1149 				cond = (cmp != 0);
1150 				break;
1151 			}
1152 
1153 			case BC_INST_REL_LT:
1154 			{
1155 				cond = (cmp < 0);
1156 				break;
1157 			}
1158 
1159 			case BC_INST_REL_GT:
1160 			{
1161 				cond = (cmp > 0);
1162 				break;
1163 			}
1164 #if BC_DEBUG
1165 			default:
1166 			{
1167 				// There is a bug if we get here.
1168 				abort();
1169 			}
1170 #endif // BC_DEBUG
1171 		}
1172 	}
1173 
1174 	BC_SIG_LOCK;
1175 
1176 	bc_num_init(&res->d.n, BC_NUM_DEF_SIZE);
1177 
1178 	BC_SIG_UNLOCK;
1179 
1180 	if (cond) bc_num_one(&res->d.n);
1181 
1182 	bc_program_retire(p, 2);
1183 }
1184 
1185 /**
1186  * Assigns a string to a variable.
1187  * @param p     The program.
1188  * @param num   The location of the string as a BcNum.
1189  * @param v     The stack for the variable.
1190  * @param push  Whether to push the string or not. To push means to move the
1191  *              string from the results stack and push it onto the variable
1192  *              stack.
1193  */
1194 static void
bc_program_assignStr(BcProgram * p,BcNum * num,BcVec * v,bool push)1195 bc_program_assignStr(BcProgram* p, BcNum* num, BcVec* v, bool push)
1196 {
1197 	BcNum* n;
1198 
1199 	assert(BC_PROG_STACK(&p->results, 1 + !push));
1200 	assert(num != NULL && num->num == NULL && num->cap == 0);
1201 
1202 	// If we are not pushing onto the variable stack, we need to replace the
1203 	// top of the variable stack.
1204 	if (!push) bc_vec_pop(v);
1205 
1206 	bc_vec_npop(&p->results, 1 + !push);
1207 
1208 	n = bc_vec_pushEmpty(v);
1209 
1210 	// We can just copy because the num should not have allocated anything.
1211 	// NOLINTNEXTLINE
1212 	memcpy(n, num, sizeof(BcNum));
1213 }
1214 
1215 /**
1216  * Copies a value to a variable. This is used for storing in dc as well as to
1217  * set function parameters to arguments in bc.
1218  * @param p    The program.
1219  * @param idx  The index of the variable or array to copy to.
1220  * @param t    The type to copy to. This could be a variable or an array.
1221  */
1222 static void
bc_program_copyToVar(BcProgram * p,size_t idx,BcType t)1223 bc_program_copyToVar(BcProgram* p, size_t idx, BcType t)
1224 {
1225 	BcResult *ptr = NULL, r;
1226 	BcVec* vec;
1227 	BcNum* n = NULL;
1228 	bool var = (t == BC_TYPE_VAR);
1229 
1230 #if DC_ENABLED
1231 	// Check the stack for dc.
1232 	if (BC_IS_DC)
1233 	{
1234 		if (BC_ERR(!BC_PROG_STACK(&p->results, 1))) bc_err(BC_ERR_EXEC_STACK);
1235 	}
1236 #endif
1237 
1238 	assert(BC_PROG_STACK(&p->results, 1));
1239 
1240 	bc_program_operand(p, &ptr, &n, 0);
1241 
1242 #if BC_ENABLED
1243 	// Get the variable for a bc function call.
1244 	if (BC_IS_BC)
1245 	{
1246 		// Type match the result.
1247 		bc_program_type_match(ptr, t);
1248 	}
1249 #endif // BC_ENABLED
1250 
1251 	vec = bc_program_vec(p, idx, t);
1252 
1253 	// We can shortcut in dc if it's assigning a string by using
1254 	// bc_program_assignStr().
1255 	if (ptr->t == BC_RESULT_STR)
1256 	{
1257 		assert(BC_PROG_STR(n));
1258 
1259 		if (BC_ERR(!var)) bc_err(BC_ERR_EXEC_TYPE);
1260 
1261 		bc_program_assignStr(p, n, vec, true);
1262 
1263 		return;
1264 	}
1265 
1266 	BC_SIG_LOCK;
1267 
1268 	// Just create and copy for a normal variable.
1269 	if (var)
1270 	{
1271 		if (BC_PROG_STR(n))
1272 		{
1273 			// NOLINTNEXTLINE
1274 			memcpy(&r.d.n, n, sizeof(BcNum));
1275 		}
1276 		else bc_num_createCopy(&r.d.n, n);
1277 	}
1278 	else
1279 	{
1280 		// If we get here, we are handling an array. This is one place we need
1281 		// to cast the number from bc_program_num() to a vector.
1282 		BcVec* v = (BcVec*) n;
1283 		BcVec* rv = &r.d.v;
1284 
1285 #if BC_ENABLED
1286 
1287 		if (BC_IS_BC)
1288 		{
1289 			bool ref, ref_size;
1290 
1291 			// True if we are using a reference.
1292 			ref = (v->size == sizeof(BcNum) && t == BC_TYPE_REF);
1293 
1294 			// True if we already have a reference vector. This is slightly
1295 			// (okay, a lot; it just doesn't look that way) different from
1296 			// above. The above means that we need to construct a reference
1297 			// vector, whereas this means that we have one and we might have to
1298 			// *dereference* it.
1299 			ref_size = (v->size == sizeof(uchar));
1300 
1301 			// If we *should* have a reference.
1302 			if (ref || (ref_size && t == BC_TYPE_REF))
1303 			{
1304 				// Create a new reference vector.
1305 				bc_vec_init(rv, sizeof(uchar), BC_DTOR_NONE);
1306 
1307 				// If this is true, then we need to construct a reference.
1308 				if (ref)
1309 				{
1310 					// Make sure the pointer was not invalidated.
1311 					vec = bc_program_vec(p, idx, t);
1312 
1313 					// Push the indices onto the reference vector. This takes
1314 					// care of last; it ensures the reference goes to the right
1315 					// place.
1316 					bc_vec_pushIndex(rv, ptr->d.loc.loc);
1317 					bc_vec_pushIndex(rv, ptr->d.loc.stack_idx);
1318 				}
1319 				// If we get here, we are copying a ref to a ref. Just push a
1320 				// copy of all of the bytes.
1321 				else bc_vec_npush(rv, v->len * sizeof(uchar), v->v);
1322 
1323 				// Push the reference vector onto the array stack and pop the
1324 				// source.
1325 				bc_vec_push(vec, &r.d);
1326 				bc_vec_pop(&p->results);
1327 
1328 				// We need to return early to avoid executing code that we must
1329 				// not touch.
1330 				BC_SIG_UNLOCK;
1331 				return;
1332 			}
1333 			// If we get here, we have a reference, but we need an array, so
1334 			// dereference the array.
1335 			else if (ref_size && t != BC_TYPE_REF)
1336 			{
1337 				v = bc_program_dereference(p, v);
1338 			}
1339 		}
1340 #endif // BC_ENABLED
1341 
1342 		// If we get here, we need to copy the array because in bc, all
1343 		// arguments are passed by value. Yes, this is expensive.
1344 		bc_array_init(rv, true);
1345 		bc_array_copy(rv, v);
1346 	}
1347 
1348 	// Push the vector onto the array stack and pop the source.
1349 	bc_vec_push(vec, &r.d);
1350 	bc_vec_pop(&p->results);
1351 
1352 	BC_SIG_UNLOCK;
1353 }
1354 
1355 void
bc_program_assignBuiltin(BcProgram * p,bool scale,bool obase,BcBigDig val)1356 bc_program_assignBuiltin(BcProgram* p, bool scale, bool obase, BcBigDig val)
1357 {
1358 	BcBigDig* ptr_t;
1359 	BcBigDig max, min;
1360 #if BC_ENABLED
1361 	BcVec* v;
1362 	BcBigDig* ptr;
1363 #endif // BC_ENABLED
1364 
1365 	assert(!scale || !obase);
1366 
1367 	// Scale needs handling separate from ibase and obase.
1368 	if (scale)
1369 	{
1370 		// Set the min and max.
1371 		min = 0;
1372 		max = vm->maxes[BC_PROG_GLOBALS_SCALE];
1373 
1374 #if BC_ENABLED
1375 		// Get a pointer to the stack.
1376 		v = p->globals_v + BC_PROG_GLOBALS_SCALE;
1377 #endif // BC_ENABLED
1378 
1379 		// Get a pointer to the current value.
1380 		ptr_t = p->globals + BC_PROG_GLOBALS_SCALE;
1381 	}
1382 	else
1383 	{
1384 		// Set the min and max.
1385 		min = BC_NUM_MIN_BASE;
1386 		if (BC_ENABLE_EXTRA_MATH && obase && (BC_IS_DC || !BC_IS_POSIX))
1387 		{
1388 			min = 0;
1389 		}
1390 		max = vm->maxes[obase + BC_PROG_GLOBALS_IBASE];
1391 
1392 #if BC_ENABLED
1393 		// Get a pointer to the stack.
1394 		v = p->globals_v + BC_PROG_GLOBALS_IBASE + obase;
1395 #endif // BC_ENABLED
1396 
1397 		// Get a pointer to the current value.
1398 		ptr_t = p->globals + BC_PROG_GLOBALS_IBASE + obase;
1399 	}
1400 
1401 	// Check for error.
1402 	if (BC_ERR(val > max || val < min))
1403 	{
1404 		BcErr e;
1405 
1406 		// This grabs the right error.
1407 		if (scale) e = BC_ERR_EXEC_SCALE;
1408 		else if (obase) e = BC_ERR_EXEC_OBASE;
1409 		else e = BC_ERR_EXEC_IBASE;
1410 
1411 		bc_verr(e, min, max);
1412 	}
1413 
1414 #if BC_ENABLED
1415 	// Set the top of the stack.
1416 	ptr = bc_vec_top(v);
1417 	*ptr = val;
1418 #endif // BC_ENABLED
1419 
1420 	// Set the actual global variable.
1421 	*ptr_t = val;
1422 }
1423 
1424 #if BC_ENABLE_EXTRA_MATH
1425 void
bc_program_assignSeed(BcProgram * p,BcNum * val)1426 bc_program_assignSeed(BcProgram* p, BcNum* val)
1427 {
1428 	bc_num_rng(val, &p->rng);
1429 }
1430 #endif // BC_ENABLE_EXTRA_MATH
1431 
1432 /**
1433  * Executes an assignment operator.
1434  * @param p     The program.
1435  * @param inst  The assignment operator to execute.
1436  */
1437 static void
bc_program_assign(BcProgram * p,uchar inst)1438 bc_program_assign(BcProgram* p, uchar inst)
1439 {
1440 	// The local use_val is true when the assigned value needs to be copied.
1441 	BcResult* left;
1442 	BcResult* right;
1443 	BcResult res;
1444 	BcNum* l;
1445 	BcNum* r;
1446 	bool ob, sc, use_val = BC_INST_USE_VAL(inst);
1447 
1448 	bc_program_assignPrep(p, &left, &l, &right, &r);
1449 
1450 	// Assigning to a string should be impossible simply because of the parse.
1451 	assert(left->t != BC_RESULT_STR);
1452 
1453 	// If we are assigning a string...
1454 	if (right->t == BC_RESULT_STR)
1455 	{
1456 		assert(BC_PROG_STR(r));
1457 
1458 #if BC_ENABLED
1459 		if (inst != BC_INST_ASSIGN && inst != BC_INST_ASSIGN_NO_VAL)
1460 		{
1461 			bc_err(BC_ERR_EXEC_TYPE);
1462 		}
1463 #endif // BC_ENABLED
1464 
1465 		// If we are assigning to an array element...
1466 		if (left->t == BC_RESULT_ARRAY_ELEM)
1467 		{
1468 			BC_SIG_LOCK;
1469 
1470 			// We need to free the number and clear it.
1471 			bc_num_free(l);
1472 
1473 			// NOLINTNEXTLINE
1474 			memcpy(l, r, sizeof(BcNum));
1475 
1476 			// Now we can pop the results.
1477 			bc_vec_npop(&p->results, 2);
1478 
1479 			BC_SIG_UNLOCK;
1480 		}
1481 		else
1482 		{
1483 			// If we get here, we are assigning to a variable, which we can use
1484 			// bc_program_assignStr() for.
1485 			BcVec* v = bc_program_vec(p, left->d.loc.loc, BC_TYPE_VAR);
1486 			bc_program_assignStr(p, r, v, false);
1487 		}
1488 
1489 #if BC_ENABLED
1490 
1491 		// If this is true, the value is going to be used again, so we want to
1492 		// push a temporary with the string.
1493 		if (inst == BC_INST_ASSIGN)
1494 		{
1495 			res.t = BC_RESULT_STR;
1496 			// NOLINTNEXTLINE
1497 			memcpy(&res.d.n, r, sizeof(BcNum));
1498 			bc_vec_push(&p->results, &res);
1499 		}
1500 
1501 #endif // BC_ENABLED
1502 
1503 		// By using bc_program_assignStr(), we short-circuited this, so return.
1504 		return;
1505 	}
1506 
1507 	// If we have a normal assignment operator, not a math one...
1508 	if (BC_INST_IS_ASSIGN(inst))
1509 	{
1510 		// Assigning to a variable that has a string here is fine because there
1511 		// is no math done on it.
1512 
1513 		// BC_RESULT_TEMP, BC_RESULT_IBASE, BC_RESULT_OBASE, BC_RESULT_SCALE,
1514 		// and BC_RESULT_SEED all have temporary copies. Because that's the
1515 		// case, we can free the left and just move the value over. We set the
1516 		// type of right to BC_RESULT_ZERO in order to prevent it from being
1517 		// freed. We also don't have to worry about BC_RESULT_STR because it's
1518 		// take care of above.
1519 		if (right->t == BC_RESULT_TEMP || right->t >= BC_RESULT_IBASE)
1520 		{
1521 			BC_SIG_LOCK;
1522 
1523 			bc_num_free(l);
1524 			// NOLINTNEXTLINE
1525 			memcpy(l, r, sizeof(BcNum));
1526 			right->t = BC_RESULT_ZERO;
1527 
1528 			BC_SIG_UNLOCK;
1529 		}
1530 		// Copy over.
1531 		else bc_num_copy(l, r);
1532 	}
1533 #if BC_ENABLED
1534 	else
1535 	{
1536 		// If we get here, we are doing a math assignment (+=, -=, etc.). So
1537 		// we need to prepare for a binary operator.
1538 		BcBigDig scale = BC_PROG_SCALE(p);
1539 
1540 		// At this point, the left side could still be a string because it could
1541 		// be a variable that has the string. If that's the case, we have a type
1542 		// error.
1543 		if (BC_PROG_STR(l)) bc_err(BC_ERR_EXEC_TYPE);
1544 
1545 		// Get the right type of assignment operator, whether val is used or
1546 		// NO_VAL for performance.
1547 		if (!use_val)
1548 		{
1549 			inst -= (BC_INST_ASSIGN_POWER_NO_VAL - BC_INST_ASSIGN_POWER);
1550 		}
1551 
1552 		assert(BC_NUM_RDX_VALID(l));
1553 		assert(BC_NUM_RDX_VALID(r));
1554 
1555 		// Run the actual operation. We do not need worry about reallocating l
1556 		// because bc_num_binary() does that behind the scenes for us.
1557 		bc_program_ops[inst - BC_INST_ASSIGN_POWER](l, r, l, scale);
1558 	}
1559 #endif // BC_ENABLED
1560 
1561 	ob = (left->t == BC_RESULT_OBASE);
1562 	sc = (left->t == BC_RESULT_SCALE);
1563 
1564 	// The globals need special handling, especially the non-seed ones. The
1565 	// first part of the if statement handles them.
1566 	if (ob || sc || left->t == BC_RESULT_IBASE)
1567 	{
1568 		// Get the actual value.
1569 		BcBigDig val = bc_num_bigdig(l);
1570 
1571 		bc_program_assignBuiltin(p, sc, ob, val);
1572 	}
1573 #if BC_ENABLE_EXTRA_MATH
1574 	// To assign to steed, let bc_num_rng() do its magic.
1575 	else if (left->t == BC_RESULT_SEED) bc_program_assignSeed(p, l);
1576 #endif // BC_ENABLE_EXTRA_MATH
1577 
1578 	BC_SIG_LOCK;
1579 
1580 	// If we needed to use the value, then we need to copy it. Otherwise, we can
1581 	// pop indiscriminately. Oh, and the copy should be a BC_RESULT_TEMP.
1582 	if (use_val)
1583 	{
1584 		bc_num_createCopy(&res.d.n, l);
1585 		res.t = BC_RESULT_TEMP;
1586 		bc_vec_npop(&p->results, 2);
1587 		bc_vec_push(&p->results, &res);
1588 	}
1589 	else bc_vec_npop(&p->results, 2);
1590 
1591 	BC_SIG_UNLOCK;
1592 }
1593 
1594 /**
1595  * Pushes a variable's value onto the results stack.
1596  * @param p     The program.
1597  * @param code  The bytecode vector to pull the variable's index out of.
1598  * @param bgn   An in/out parameter; the start of the index in the bytecode
1599  *              vector, and will be updated to point after the index on return.
1600  * @param pop   True if the variable's value should be popped off its stack.
1601  *              This is only used in dc.
1602  * @param copy  True if the variable's value should be copied to the results
1603  *              stack. This is only used in dc.
1604  */
1605 static void
bc_program_pushVar(BcProgram * p,const char * restrict code,size_t * restrict bgn,bool pop,bool copy)1606 bc_program_pushVar(BcProgram* p, const char* restrict code,
1607                    size_t* restrict bgn, bool pop, bool copy)
1608 {
1609 	BcResult r;
1610 	size_t idx = bc_program_index(code, bgn);
1611 	BcVec* v;
1612 
1613 	// Set the result appropriately.
1614 	r.t = BC_RESULT_VAR;
1615 	r.d.loc.loc = idx;
1616 
1617 	// Get the stack for the variable. This is used in both bc and dc.
1618 	v = bc_program_vec(p, idx, BC_TYPE_VAR);
1619 	r.d.loc.stack_idx = v->len - 1;
1620 
1621 #if DC_ENABLED
1622 	// If this condition is true, then we have the hard case, where we have to
1623 	// adjust dc registers.
1624 	if (BC_IS_DC && (pop || copy))
1625 	{
1626 		// Get the number at the top at the top of the stack.
1627 		BcNum* num = bc_vec_top(v);
1628 
1629 		// Ensure there are enough elements on the stack.
1630 		if (BC_ERR(!BC_PROG_STACK(v, 2 - copy)))
1631 		{
1632 			const char* name = bc_map_name(&p->var_map, idx);
1633 			bc_verr(BC_ERR_EXEC_STACK_REGISTER, name);
1634 		}
1635 
1636 		assert(BC_PROG_STACK(v, 2 - copy));
1637 
1638 		// If the top of the stack is actually a number...
1639 		if (!BC_PROG_STR(num))
1640 		{
1641 			BC_SIG_LOCK;
1642 
1643 			// Create a copy to go onto the results stack as appropriate.
1644 			r.t = BC_RESULT_TEMP;
1645 			bc_num_createCopy(&r.d.n, num);
1646 
1647 			// If we are not actually copying, we need to do a replace, so pop.
1648 			if (!copy) bc_vec_pop(v);
1649 
1650 			bc_vec_push(&p->results, &r);
1651 
1652 			BC_SIG_UNLOCK;
1653 
1654 			return;
1655 		}
1656 		else
1657 		{
1658 			// Set the string result. We can just memcpy because all of the
1659 			// fields in the num should be cleared.
1660 			// NOLINTNEXTLINE
1661 			memcpy(&r.d.n, num, sizeof(BcNum));
1662 			r.t = BC_RESULT_STR;
1663 		}
1664 
1665 		// If we are not actually copying, we need to do a replace, so pop.
1666 		if (!copy) bc_vec_pop(v);
1667 	}
1668 #endif // DC_ENABLED
1669 
1670 	bc_vec_push(&p->results, &r);
1671 }
1672 
1673 /**
1674  * Pushes an array or an array element onto the results stack.
1675  * @param p     The program.
1676  * @param code  The bytecode vector to pull the variable's index out of.
1677  * @param bgn   An in/out parameter; the start of the index in the bytecode
1678  *              vector, and will be updated to point after the index on return.
1679  * @param inst  The instruction; whether to push an array or an array element.
1680  */
1681 static void
bc_program_pushArray(BcProgram * p,const char * restrict code,size_t * restrict bgn,uchar inst)1682 bc_program_pushArray(BcProgram* p, const char* restrict code,
1683                      size_t* restrict bgn, uchar inst)
1684 {
1685 	BcResult r;
1686 	BcResult* operand;
1687 	BcNum* num;
1688 	BcBigDig temp;
1689 	BcVec* v;
1690 
1691 	// Get the index of the array.
1692 	r.d.loc.loc = bc_program_index(code, bgn);
1693 
1694 	// We need the array to get its length.
1695 	v = bc_program_vec(p, r.d.loc.loc, BC_TYPE_ARRAY);
1696 	assert(v != NULL);
1697 
1698 	r.d.loc.stack_idx = v->len - 1;
1699 
1700 	// Doing an array is easy; just set the result type and finish.
1701 	if (inst == BC_INST_ARRAY)
1702 	{
1703 		r.t = BC_RESULT_ARRAY;
1704 		bc_vec_push(&p->results, &r);
1705 		return;
1706 	}
1707 
1708 	// Grab the top element of the results stack for the array index.
1709 	bc_program_prep(p, &operand, &num, 0);
1710 	temp = bc_num_bigdig(num);
1711 
1712 	// Set the result.
1713 	r.t = BC_RESULT_ARRAY_ELEM;
1714 	r.d.loc.idx = (size_t) temp;
1715 
1716 	BC_SIG_LOCK;
1717 
1718 	// Pop the index and push the element.
1719 	bc_vec_pop(&p->results);
1720 	bc_vec_push(&p->results, &r);
1721 
1722 	BC_SIG_UNLOCK;
1723 }
1724 
1725 #if BC_ENABLED
1726 
1727 /**
1728  * Executes an increment or decrement operator. This only handles postfix
1729  * inc/dec because the parser translates prefix inc/dec into an assignment where
1730  * the value is used.
1731  * @param p     The program.
1732  * @param inst  The instruction; whether to do an increment or decrement.
1733  */
1734 static void
bc_program_incdec(BcProgram * p,uchar inst)1735 bc_program_incdec(BcProgram* p, uchar inst)
1736 {
1737 	BcResult *ptr, res, copy;
1738 	BcNum* num;
1739 	uchar inst2;
1740 
1741 	bc_program_prep(p, &ptr, &num, 0);
1742 
1743 	BC_SIG_LOCK;
1744 
1745 	// We need a copy from *before* the operation.
1746 	copy.t = BC_RESULT_TEMP;
1747 	bc_num_createCopy(&copy.d.n, num);
1748 
1749 	BC_SETJMP_LOCKED(vm, exit);
1750 
1751 	BC_SIG_UNLOCK;
1752 
1753 	// Create the proper assignment.
1754 	res.t = BC_RESULT_ONE;
1755 	inst2 = BC_INST_ASSIGN_PLUS_NO_VAL + (inst & 0x01);
1756 
1757 	bc_vec_push(&p->results, &res);
1758 	bc_program_assign(p, inst2);
1759 
1760 	BC_SIG_LOCK;
1761 
1762 	bc_vec_push(&p->results, &copy);
1763 
1764 	BC_UNSETJMP(vm);
1765 
1766 	BC_SIG_UNLOCK;
1767 
1768 	// No need to free the copy here because we pushed it onto the stack.
1769 	return;
1770 
1771 exit:
1772 	BC_SIG_MAYLOCK;
1773 	bc_num_free(&copy.d.n);
1774 	BC_LONGJMP_CONT(vm);
1775 }
1776 
1777 /**
1778  * Executes a function call for bc.
1779  * @param p     The program.
1780  * @param code  The bytecode vector to pull the number of arguments and the
1781  *              function index out of.
1782  * @param bgn   An in/out parameter; the start of the indices in the bytecode
1783  *              vector, and will be updated to point after the indices on
1784  *              return.
1785  */
1786 static void
bc_program_call(BcProgram * p,const char * restrict code,size_t * restrict bgn)1787 bc_program_call(BcProgram* p, const char* restrict code, size_t* restrict bgn)
1788 {
1789 	BcInstPtr ip;
1790 	size_t i, nargs;
1791 	BcFunc* f;
1792 	BcVec* v;
1793 	BcAuto* a;
1794 	BcResult* arg;
1795 
1796 	// Pull the number of arguments out of the bytecode vector.
1797 	nargs = bc_program_index(code, bgn);
1798 
1799 	// Set up instruction pointer.
1800 	ip.idx = 0;
1801 	ip.func = bc_program_index(code, bgn);
1802 	f = bc_vec_item(&p->fns, ip.func);
1803 
1804 	// Error checking.
1805 	if (BC_ERR(!f->code.len)) bc_verr(BC_ERR_EXEC_UNDEF_FUNC, f->name);
1806 	if (BC_ERR(nargs != f->nparams))
1807 	{
1808 		bc_verr(BC_ERR_EXEC_PARAMS, f->nparams, nargs);
1809 	}
1810 
1811 	// Set the length of the results stack. We discount the argument, of course.
1812 	ip.len = p->results.len - nargs;
1813 
1814 	assert(BC_PROG_STACK(&p->results, nargs));
1815 
1816 	// Prepare the globals' stacks.
1817 	if (BC_G) bc_program_prepGlobals(p);
1818 
1819 	// Push the arguments onto the stacks of their respective parameters.
1820 	for (i = 0; i < nargs; ++i)
1821 	{
1822 		arg = bc_vec_top(&p->results);
1823 		if (BC_ERR(arg->t == BC_RESULT_VOID)) bc_err(BC_ERR_EXEC_VOID_VAL);
1824 
1825 		// Get the corresponding parameter.
1826 		a = bc_vec_item(&f->autos, nargs - 1 - i);
1827 
1828 		// Actually push the value onto the parameter's stack.
1829 		bc_program_copyToVar(p, a->idx, a->type);
1830 	}
1831 
1832 	BC_SIG_LOCK;
1833 
1834 	// Push zeroes onto the stacks of the auto variables.
1835 	for (; i < f->autos.len; ++i)
1836 	{
1837 		// Get the auto and its stack.
1838 		a = bc_vec_item(&f->autos, i);
1839 		v = bc_program_vec(p, a->idx, a->type);
1840 
1841 		// If a variable, just push a 0; otherwise, push an array.
1842 		if (a->type == BC_TYPE_VAR)
1843 		{
1844 			BcNum* n = bc_vec_pushEmpty(v);
1845 			bc_num_init(n, BC_NUM_DEF_SIZE);
1846 		}
1847 		else
1848 		{
1849 			BcVec* v2;
1850 
1851 			assert(a->type == BC_TYPE_ARRAY);
1852 
1853 			v2 = bc_vec_pushEmpty(v);
1854 			bc_array_init(v2, true);
1855 		}
1856 	}
1857 
1858 	// Push the instruction pointer onto the execution stack.
1859 	bc_vec_push(&p->stack, &ip);
1860 
1861 	BC_SIG_UNLOCK;
1862 }
1863 
1864 /**
1865  * Executes a return instruction.
1866  * @param p     The program.
1867  * @param inst  The return instruction. bc can return void, and we need to know
1868  *              if it is.
1869  */
1870 static void
bc_program_return(BcProgram * p,uchar inst)1871 bc_program_return(BcProgram* p, uchar inst)
1872 {
1873 	BcResult* res;
1874 	BcFunc* f;
1875 	BcInstPtr* ip;
1876 	size_t i, nresults;
1877 
1878 	// Get the instruction pointer.
1879 	ip = bc_vec_top(&p->stack);
1880 
1881 	// Get the difference between the actual number of results and the number of
1882 	// results the caller expects.
1883 	nresults = p->results.len - ip->len;
1884 
1885 	// If this isn't true, there was a missing call somewhere.
1886 	assert(BC_PROG_STACK(&p->stack, 2));
1887 
1888 	// If this isn't true, the parser screwed by giving us no value when we
1889 	// expected one, or giving us a value when we expected none.
1890 	assert(BC_PROG_STACK(&p->results, ip->len + (inst == BC_INST_RET)));
1891 
1892 	// Get the function we are returning from.
1893 	f = bc_vec_item(&p->fns, ip->func);
1894 
1895 	res = bc_program_prepResult(p);
1896 
1897 	assert(p->nresults == 1);
1898 
1899 	// If we are returning normally...
1900 	if (inst == BC_INST_RET)
1901 	{
1902 		BcNum* num;
1903 		BcResult* operand;
1904 
1905 		// Prepare and copy the return value.
1906 		bc_program_operand(p, &operand, &num, 1);
1907 
1908 		if (BC_PROG_STR(num))
1909 		{
1910 			// We need to set this because otherwise, it will be a
1911 			// BC_RESULT_TEMP, and BC_RESULT_TEMP needs an actual number to make
1912 			// it easier to do type checking.
1913 			res->t = BC_RESULT_STR;
1914 
1915 			// NOLINTNEXTLINE
1916 			memcpy(&res->d.n, num, sizeof(BcNum));
1917 		}
1918 		else
1919 		{
1920 			BC_SIG_LOCK;
1921 
1922 			bc_num_createCopy(&res->d.n, num);
1923 		}
1924 	}
1925 	// Void is easy; set the result.
1926 	else if (inst == BC_INST_RET_VOID) res->t = BC_RESULT_VOID;
1927 	else
1928 	{
1929 		BC_SIG_LOCK;
1930 
1931 		// If we get here, the instruction is for returning a zero, so do that.
1932 		bc_num_init(&res->d.n, BC_NUM_DEF_SIZE);
1933 	}
1934 
1935 	BC_SIG_MAYUNLOCK;
1936 
1937 	// We need to pop items off of the stacks of arguments and autos as well.
1938 	for (i = 0; i < f->autos.len; ++i)
1939 	{
1940 		BcAuto* a = bc_vec_item(&f->autos, i);
1941 		BcVec* v = bc_program_vec(p, a->idx, a->type);
1942 
1943 		bc_vec_pop(v);
1944 	}
1945 
1946 	BC_SIG_LOCK;
1947 
1948 	// When we retire, pop all of the unused results.
1949 	bc_program_retire(p, nresults);
1950 
1951 	// Pop the globals, if necessary.
1952 	if (BC_G) bc_program_popGlobals(p, false);
1953 
1954 	// Pop the stack. This is what causes the function to actually "return."
1955 	bc_vec_pop(&p->stack);
1956 
1957 	BC_SIG_UNLOCK;
1958 }
1959 #endif // BC_ENABLED
1960 
1961 /**
1962  * Executes a builtin function.
1963  * @param p     The program.
1964  * @param inst  The builtin to execute.
1965  */
1966 static void
bc_program_builtin(BcProgram * p,uchar inst)1967 bc_program_builtin(BcProgram* p, uchar inst)
1968 {
1969 	BcResult* opd;
1970 	BcResult* res;
1971 	BcNum* num;
1972 	bool len = (inst == BC_INST_LENGTH);
1973 
1974 	// Ensure we have a valid builtin.
1975 #if BC_ENABLE_EXTRA_MATH
1976 	assert(inst >= BC_INST_LENGTH && inst <= BC_INST_IRAND);
1977 #else // BC_ENABLE_EXTRA_MATH
1978 	assert(inst >= BC_INST_LENGTH && inst <= BC_INST_IS_STRING);
1979 #endif // BC_ENABLE_EXTRA_MATH
1980 
1981 #ifndef BC_PROG_NO_STACK_CHECK
1982 	// Check stack for dc.
1983 	if (BC_IS_DC && BC_ERR(!BC_PROG_STACK(&p->results, 1)))
1984 	{
1985 		bc_err(BC_ERR_EXEC_STACK);
1986 	}
1987 #endif // BC_PROG_NO_STACK_CHECK
1988 
1989 	assert(BC_PROG_STACK(&p->results, 1));
1990 
1991 	res = bc_program_prepResult(p);
1992 
1993 	assert(p->nresults == 1);
1994 
1995 	bc_program_operand(p, &opd, &num, 1);
1996 
1997 	assert(num != NULL);
1998 
1999 	// We need to ensure that strings and arrays aren't passed to most builtins.
2000 	// The scale function can take strings in dc.
2001 	if (!len && (inst != BC_INST_SCALE_FUNC || BC_IS_BC) &&
2002 	    inst != BC_INST_IS_NUMBER && inst != BC_INST_IS_STRING)
2003 	{
2004 		bc_program_type_num(opd, num);
2005 	}
2006 
2007 	// Square root is easy.
2008 	if (inst == BC_INST_SQRT) bc_num_sqrt(num, &res->d.n, BC_PROG_SCALE(p));
2009 
2010 	// Absolute value is easy.
2011 	else if (inst == BC_INST_ABS)
2012 	{
2013 		BC_SIG_LOCK;
2014 
2015 		bc_num_createCopy(&res->d.n, num);
2016 
2017 		BC_SIG_UNLOCK;
2018 
2019 		BC_NUM_NEG_CLR_NP(res->d.n);
2020 	}
2021 
2022 	// Testing for number or string is easy.
2023 	else if (inst == BC_INST_IS_NUMBER || inst == BC_INST_IS_STRING)
2024 	{
2025 		bool cond;
2026 		bool is_str;
2027 
2028 		BC_SIG_LOCK;
2029 
2030 		bc_num_init(&res->d.n, BC_NUM_DEF_SIZE);
2031 
2032 		BC_SIG_UNLOCK;
2033 
2034 		// Test if the number is a string.
2035 		is_str = BC_PROG_STR(num);
2036 
2037 		// This confusing condition simply means that the instruction must be
2038 		// true if is_str is, or it must be false if is_str is. Otherwise, the
2039 		// returned value is false (0).
2040 		cond = ((inst == BC_INST_IS_STRING) == is_str);
2041 		if (cond) bc_num_one(&res->d.n);
2042 	}
2043 
2044 #if BC_ENABLE_EXTRA_MATH
2045 
2046 	// irand() is easy.
2047 	else if (inst == BC_INST_IRAND)
2048 	{
2049 		BC_SIG_LOCK;
2050 
2051 		bc_num_init(&res->d.n, num->len - BC_NUM_RDX_VAL(num));
2052 
2053 		BC_SIG_UNLOCK;
2054 
2055 		bc_num_irand(num, &res->d.n, &p->rng);
2056 	}
2057 
2058 #endif // BC_ENABLE_EXTRA_MATH
2059 
2060 	// Everything else is...not easy.
2061 	else
2062 	{
2063 		BcBigDig val = 0;
2064 
2065 		// Well, scale() is easy, but length() is not.
2066 		if (len)
2067 		{
2068 			// If we are bc and we have an array...
2069 			if (opd->t == BC_RESULT_ARRAY)
2070 			{
2071 				// Yes, this is one place where we need to cast the number from
2072 				// bc_program_num() to a vector.
2073 				BcVec* v = (BcVec*) num;
2074 
2075 				// XXX: If this is changed, you should also change the similar
2076 				// code in bc_program_asciify().
2077 
2078 #if BC_ENABLED
2079 				// Dereference the array, if necessary.
2080 				if (BC_IS_BC && v->size == sizeof(uchar))
2081 				{
2082 					v = bc_program_dereference(p, v);
2083 				}
2084 #endif // BC_ENABLED
2085 
2086 				assert(v->size == sizeof(BcNum));
2087 
2088 				val = (BcBigDig) v->len;
2089 			}
2090 			else
2091 			{
2092 				// If the item is a string...
2093 				if (!BC_PROG_NUM(opd, num))
2094 				{
2095 					char* str;
2096 
2097 					// Get the string, then get the length.
2098 					str = bc_program_string(p, num);
2099 					val = (BcBigDig) strlen(str);
2100 				}
2101 				else
2102 				{
2103 					// Calculate the length of the number.
2104 					val = (BcBigDig) bc_num_len(num);
2105 				}
2106 			}
2107 		}
2108 		// Like I said; scale() is actually easy. It just also needs the integer
2109 		// conversion that length() does.
2110 		else if (BC_IS_BC || BC_PROG_NUM(opd, num))
2111 		{
2112 			val = (BcBigDig) bc_num_scale(num);
2113 		}
2114 
2115 		BC_SIG_LOCK;
2116 
2117 		// Create the result.
2118 		bc_num_createFromBigdig(&res->d.n, val);
2119 
2120 		BC_SIG_UNLOCK;
2121 	}
2122 
2123 	bc_program_retire(p, 1);
2124 }
2125 
2126 /**
2127  * Executes a divmod.
2128  * @param p  The program.
2129  */
2130 static void
bc_program_divmod(BcProgram * p)2131 bc_program_divmod(BcProgram* p)
2132 {
2133 	BcResult* opd1;
2134 	BcResult* opd2;
2135 	BcResult* res;
2136 	BcResult* res2;
2137 	BcNum* n1;
2138 	BcNum* n2;
2139 	size_t req;
2140 
2141 	// We grow first to avoid pointer invalidation.
2142 	bc_vec_grow(&p->results, 2);
2143 
2144 	// We don't need to update the pointer because
2145 	// the capacity is enough due to the line above.
2146 	res2 = bc_program_prepResult(p);
2147 	res = bc_program_prepResult(p);
2148 	assert(p->nresults == 2);
2149 
2150 	// Prepare the operands.
2151 	bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2, 2);
2152 
2153 	req = bc_num_mulReq(n1, n2, BC_PROG_SCALE(p));
2154 
2155 	BC_SIG_LOCK;
2156 
2157 	// Initialize the results.
2158 	bc_num_init(&res->d.n, req);
2159 	bc_num_init(&res2->d.n, req);
2160 
2161 	BC_SIG_UNLOCK;
2162 
2163 	// Execute.
2164 	bc_num_divmod(n1, n2, &res2->d.n, &res->d.n, BC_PROG_SCALE(p));
2165 
2166 	bc_program_retire(p, 2);
2167 }
2168 
2169 /**
2170  * Executes modular exponentiation.
2171  * @param p  The program.
2172  */
2173 static void
bc_program_modexp(BcProgram * p)2174 bc_program_modexp(BcProgram* p)
2175 {
2176 	BcResult* r1;
2177 	BcResult* r2;
2178 	BcResult* r3;
2179 	BcResult* res;
2180 	BcNum* n1;
2181 	BcNum* n2;
2182 	BcNum* n3;
2183 
2184 #if DC_ENABLED
2185 
2186 	// Check the stack.
2187 	if (BC_IS_DC && BC_ERR(!BC_PROG_STACK(&p->results, 3)))
2188 	{
2189 		bc_err(BC_ERR_EXEC_STACK);
2190 	}
2191 
2192 #endif // DC_ENABLED
2193 
2194 	assert(BC_PROG_STACK(&p->results, 3));
2195 
2196 	res = bc_program_prepResult(p);
2197 
2198 	assert(p->nresults == 1);
2199 
2200 	// Get the first operand and typecheck.
2201 	bc_program_operand(p, &r1, &n1, 3);
2202 	bc_program_type_num(r1, n1);
2203 
2204 	// Get the last two operands.
2205 	bc_program_binOpPrep(p, &r2, &n2, &r3, &n3, 1);
2206 
2207 	// Make sure that the values have their pointers updated, if necessary.
2208 	// Only array elements are possible because this is dc.
2209 	if (r1->t == BC_RESULT_ARRAY_ELEM && (r1->t == r2->t || r1->t == r3->t))
2210 	{
2211 		n1 = bc_program_num(p, r1);
2212 	}
2213 
2214 	BC_SIG_LOCK;
2215 
2216 	bc_num_init(&res->d.n, n3->len);
2217 
2218 	BC_SIG_UNLOCK;
2219 
2220 	bc_num_modexp(n1, n2, n3, &res->d.n);
2221 
2222 	bc_program_retire(p, 3);
2223 }
2224 
2225 /**
2226  * Asciifies a number for dc. This is a helper for bc_program_asciify().
2227  * @param p  The program.
2228  * @param n  The number to asciify.
2229  */
2230 static uchar
bc_program_asciifyNum(BcProgram * p,BcNum * n)2231 bc_program_asciifyNum(BcProgram* p, BcNum* n)
2232 {
2233 	bc_num_copy(&p->asciify, n);
2234 
2235 	// We want to clear the scale and sign for easy mod later.
2236 	bc_num_truncate(&p->asciify, p->asciify.scale);
2237 	BC_NUM_NEG_CLR(&p->asciify);
2238 
2239 	// This is guaranteed to not have a divide by 0
2240 	// because strmb is equal to 256.
2241 	bc_num_mod(&p->asciify, &p->strmb, &p->asciify, 0);
2242 
2243 	// This is also guaranteed to not error because num is in the range
2244 	// [0, UCHAR_MAX], which is definitely in range for a BcBigDig. And
2245 	// it is not negative.
2246 	return (uchar) bc_num_bigdig2(&p->asciify);
2247 }
2248 
2249 /**
2250  * Executes the "asciify" command in bc and dc.
2251  * @param p  The program.
2252  */
2253 static void
bc_program_asciify(BcProgram * p)2254 bc_program_asciify(BcProgram* p)
2255 {
2256 	BcResult *r, res;
2257 	BcNum* n;
2258 	uchar c;
2259 	size_t idx;
2260 #if BC_ENABLED
2261 	// This is in the outer scope because it has to be freed after a jump.
2262 	char* temp_str;
2263 #endif // BC_ENABLED
2264 
2265 	// Check the stack.
2266 	if (BC_ERR(!BC_PROG_STACK(&p->results, 1))) bc_err(BC_ERR_EXEC_STACK);
2267 
2268 	assert(BC_PROG_STACK(&p->results, 1));
2269 
2270 	// Get the top of the results stack.
2271 	bc_program_operand(p, &r, &n, 0);
2272 
2273 	assert(n != NULL);
2274 	assert(BC_IS_BC || r->t != BC_RESULT_ARRAY);
2275 
2276 #if BC_ENABLED
2277 	// Handle arrays in bc specially.
2278 	if (r->t == BC_RESULT_ARRAY)
2279 	{
2280 		// Yes, this is one place where we need to cast the number from
2281 		// bc_program_num() to a vector.
2282 		BcVec* v = (BcVec*) n;
2283 		size_t i;
2284 
2285 		// XXX: If this is changed, you should also change the similar code in
2286 		// bc_program_builtin().
2287 
2288 		// Dereference the array, if necessary.
2289 		if (v->size == sizeof(uchar))
2290 		{
2291 			v = bc_program_dereference(p, v);
2292 		}
2293 
2294 		assert(v->size == sizeof(BcNum));
2295 
2296 		// Allocate the string and set the jump for it.
2297 		BC_SIG_LOCK;
2298 		temp_str = bc_vm_malloc(v->len + 1);
2299 		BC_SETJMP_LOCKED(vm, exit);
2300 		BC_SIG_UNLOCK;
2301 
2302 		// Convert the array.
2303 		for (i = 0; i < v->len; ++i)
2304 		{
2305 			BcNum* num = (BcNum*) bc_vec_item(v, i);
2306 
2307 			if (BC_PROG_STR(num))
2308 			{
2309 				temp_str[i] = (bc_program_string(p, num))[0];
2310 			}
2311 			else
2312 			{
2313 				temp_str[i] = (char) bc_program_asciifyNum(p, num);
2314 			}
2315 		}
2316 
2317 		temp_str[v->len] = '\0';
2318 
2319 		// Store the string in the slab and map, and free the temp string.
2320 		BC_SIG_LOCK;
2321 		idx = bc_program_addString(p, temp_str);
2322 		free(temp_str);
2323 		BC_UNSETJMP(vm);
2324 		BC_SIG_UNLOCK;
2325 	}
2326 	else
2327 #endif // BC_ENABLED
2328 	{
2329 		char str[2];
2330 		char* str2;
2331 
2332 		// Asciify.
2333 		if (BC_PROG_NUM(r, n)) c = bc_program_asciifyNum(p, n);
2334 		else
2335 		{
2336 			// Get the string itself, then the first character.
2337 			str2 = bc_program_string(p, n);
2338 			c = (uchar) str2[0];
2339 		}
2340 
2341 		// Fill the resulting string.
2342 		str[0] = (char) c;
2343 		str[1] = '\0';
2344 
2345 		// Add the string to the data structures.
2346 		BC_SIG_LOCK;
2347 		idx = bc_program_addString(p, str);
2348 		BC_SIG_UNLOCK;
2349 	}
2350 
2351 	// Set the result
2352 	res.t = BC_RESULT_STR;
2353 	bc_num_clear(&res.d.n);
2354 	res.d.n.scale = idx;
2355 
2356 	// Pop and push.
2357 	bc_vec_pop(&p->results);
2358 	bc_vec_push(&p->results, &res);
2359 
2360 	return;
2361 
2362 #if BC_ENABLED
2363 exit:
2364 	free(temp_str);
2365 #endif // BC_ENABLED
2366 }
2367 
2368 /**
2369  * Streams a number or a string to stdout.
2370  * @param p  The program.
2371  */
2372 static void
bc_program_printStream(BcProgram * p)2373 bc_program_printStream(BcProgram* p)
2374 {
2375 	BcResult* r;
2376 	BcNum* n;
2377 
2378 	// Check the stack.
2379 	if (BC_ERR(!BC_PROG_STACK(&p->results, 1))) bc_err(BC_ERR_EXEC_STACK);
2380 
2381 	assert(BC_PROG_STACK(&p->results, 1));
2382 
2383 	// Get the top of the results stack.
2384 	bc_program_operand(p, &r, &n, 0);
2385 
2386 	assert(n != NULL);
2387 
2388 	// Stream appropriately.
2389 	if (BC_PROG_NUM(r, n)) bc_num_stream(n);
2390 	else bc_program_printChars(bc_program_string(p, n));
2391 
2392 	// Pop the operand.
2393 	bc_vec_pop(&p->results);
2394 }
2395 
2396 #if DC_ENABLED
2397 
2398 /**
2399  * Gets the length of a register in dc and pushes it onto the results stack.
2400  * @param p     The program.
2401  * @param code  The bytecode vector to pull the register's index out of.
2402  * @param bgn   An in/out parameter; the start of the index in the bytecode
2403  *              vector, and will be updated to point after the index on return.
2404  */
2405 static void
bc_program_regStackLen(BcProgram * p,const char * restrict code,size_t * restrict bgn)2406 bc_program_regStackLen(BcProgram* p, const char* restrict code,
2407                        size_t* restrict bgn)
2408 {
2409 	size_t idx = bc_program_index(code, bgn);
2410 	BcVec* v = bc_program_vec(p, idx, BC_TYPE_VAR);
2411 
2412 	bc_program_pushBigdig(p, (BcBigDig) v->len, BC_RESULT_TEMP);
2413 }
2414 
2415 /**
2416  * Pushes the length of the results stack onto the results stack.
2417  * @param p  The program.
2418  */
2419 static void
bc_program_stackLen(BcProgram * p)2420 bc_program_stackLen(BcProgram* p)
2421 {
2422 	bc_program_pushBigdig(p, (BcBigDig) p->results.len, BC_RESULT_TEMP);
2423 }
2424 
2425 /**
2426  * Pops a certain number of elements off the execution stack.
2427  * @param p     The program.
2428  * @param inst  The instruction to tell us how many. There is one to pop up to
2429  *              2, and one to pop the amount equal to the number at the top of
2430  *              the results stack.
2431  */
2432 static void
bc_program_nquit(BcProgram * p,uchar inst)2433 bc_program_nquit(BcProgram* p, uchar inst)
2434 {
2435 	BcResult* opnd;
2436 	BcNum* num;
2437 	BcBigDig val;
2438 	size_t i;
2439 
2440 	// Ensure that the tail calls stack is correct.
2441 	assert(p->stack.len == p->tail_calls.len);
2442 
2443 	// Get the number of executions to pop.
2444 	if (inst == BC_INST_QUIT) val = 2;
2445 	else
2446 	{
2447 		bc_program_prep(p, &opnd, &num, 0);
2448 		val = bc_num_bigdig(num);
2449 
2450 		bc_vec_pop(&p->results);
2451 	}
2452 
2453 	// Loop over the tail call stack and adjust the quit value appropriately.
2454 	for (i = 0; val && i < p->tail_calls.len; ++i)
2455 	{
2456 		// Get the number of tail calls for this one.
2457 		size_t calls = *((size_t*) bc_vec_item_rev(&p->tail_calls, i)) + 1;
2458 
2459 		// Adjust the value.
2460 		if (calls >= val) val = 0;
2461 		else val -= (BcBigDig) calls;
2462 	}
2463 
2464 	// If we don't have enough executions, just quit.
2465 	if (i == p->stack.len)
2466 	{
2467 		vm->status = BC_STATUS_QUIT;
2468 		BC_JMP;
2469 	}
2470 	else
2471 	{
2472 		// We can always pop the last item we reached on the tail call stack
2473 		// because these are for tail calls. That means that any executions that
2474 		// we would not have quit in that position on the stack would have quit
2475 		// anyway.
2476 		BC_SIG_LOCK;
2477 		bc_vec_npop(&p->stack, i);
2478 		bc_vec_npop(&p->tail_calls, i);
2479 		BC_SIG_UNLOCK;
2480 	}
2481 }
2482 
2483 /**
2484  * Pushes the depth of the execution stack onto the stack.
2485  * @param p  The program.
2486  */
2487 static void
bc_program_execStackLen(BcProgram * p)2488 bc_program_execStackLen(BcProgram* p)
2489 {
2490 	size_t i, amt, len = p->tail_calls.len;
2491 
2492 	amt = len;
2493 
2494 	for (i = 0; i < len; ++i)
2495 	{
2496 		amt += *((size_t*) bc_vec_item(&p->tail_calls, i));
2497 	}
2498 
2499 	bc_program_pushBigdig(p, (BcBigDig) amt, BC_RESULT_TEMP);
2500 }
2501 
2502 /**
2503  *
2504  * @param p     The program.
2505  * @param code  The bytecode vector to pull the register's index out of.
2506  * @param bgn   An in/out parameter; the start of the index in the bytecode
2507  *              vector, and will be updated to point after the index on return.
2508  * @param cond  True if the execution is conditional, false otherwise.
2509  * @param len   The number of bytes in the bytecode vector.
2510  */
2511 static void
bc_program_execStr(BcProgram * p,const char * restrict code,size_t * restrict bgn,bool cond,size_t len)2512 bc_program_execStr(BcProgram* p, const char* restrict code,
2513                    size_t* restrict bgn, bool cond, size_t len)
2514 {
2515 	BcResult* r;
2516 	char* str;
2517 	BcFunc* f;
2518 	BcInstPtr ip;
2519 	size_t fidx;
2520 	BcNum* n;
2521 
2522 	assert(p->stack.len == p->tail_calls.len);
2523 
2524 	// Check the stack.
2525 	if (BC_ERR(!BC_PROG_STACK(&p->results, 1))) bc_err(BC_ERR_EXEC_STACK);
2526 
2527 	assert(BC_PROG_STACK(&p->results, 1));
2528 
2529 	// Get the operand.
2530 	bc_program_operand(p, &r, &n, 0);
2531 
2532 	// If execution is conditional...
2533 	if (cond)
2534 	{
2535 		bool exec;
2536 		size_t then_idx;
2537 		// These are volatile to quiet warnings on GCC about clobbering with
2538 		// longjmp().
2539 		volatile size_t else_idx;
2540 		volatile size_t idx;
2541 
2542 		// Get the index of the "then" var and "else" var.
2543 		then_idx = bc_program_index(code, bgn);
2544 		else_idx = bc_program_index(code, bgn);
2545 
2546 		// Figure out if we should execute.
2547 		exec = (r->d.n.len != 0);
2548 
2549 		idx = exec ? then_idx : else_idx;
2550 
2551 		BC_SIG_LOCK;
2552 		BC_SETJMP_LOCKED(vm, exit);
2553 
2554 		// If we are supposed to execute, execute. If else_idx == SIZE_MAX, that
2555 		// means there was no else clause, so if execute is false and else does
2556 		// not exist, we don't execute. The goto skips all of the setup for the
2557 		// execution.
2558 		if (exec || (else_idx != SIZE_MAX))
2559 		{
2560 			n = bc_vec_top(bc_program_vec(p, idx, BC_TYPE_VAR));
2561 		}
2562 		else goto exit;
2563 
2564 		if (BC_ERR(!BC_PROG_STR(n))) bc_err(BC_ERR_EXEC_TYPE);
2565 
2566 		BC_UNSETJMP(vm);
2567 		BC_SIG_UNLOCK;
2568 	}
2569 	else
2570 	{
2571 		// In non-conditional situations, only the top of stack can be executed,
2572 		// and in those cases, variables are not allowed to be "on the stack";
2573 		// they are only put on the stack to be assigned to.
2574 		assert(r->t != BC_RESULT_VAR);
2575 
2576 		if (r->t != BC_RESULT_STR) return;
2577 	}
2578 
2579 	assert(BC_PROG_STR(n));
2580 
2581 	// Get the string.
2582 	str = bc_program_string(p, n);
2583 
2584 	// Get the function index and function.
2585 	BC_SIG_LOCK;
2586 	fidx = bc_program_insertFunc(p, str);
2587 	BC_SIG_UNLOCK;
2588 	f = bc_vec_item(&p->fns, fidx);
2589 
2590 	// If the function has not been parsed yet...
2591 	if (!f->code.len)
2592 	{
2593 		BC_SIG_LOCK;
2594 
2595 		if (!BC_PARSE_IS_INITED(&vm->read_prs, p))
2596 		{
2597 			bc_parse_init(&vm->read_prs, p, fidx);
2598 
2599 			// Initialize this too because bc_vm_shutdown() expects them to be
2600 			// initialized togther.
2601 			bc_vec_init(&vm->read_buf, sizeof(char), BC_DTOR_NONE);
2602 		}
2603 		// This needs to be updated because the parser could have been used
2604 		// somewhere else
2605 		else bc_parse_updateFunc(&vm->read_prs, fidx);
2606 
2607 		bc_lex_file(&vm->read_prs.l, vm->file);
2608 
2609 		BC_SETJMP_LOCKED(vm, err);
2610 
2611 		BC_SIG_UNLOCK;
2612 
2613 		// Parse. Only one expression is needed, so stdin isn't used.
2614 		bc_parse_text(&vm->read_prs, str, BC_MODE_FILE);
2615 
2616 		BC_SIG_LOCK;
2617 		vm->expr(&vm->read_prs, BC_PARSE_NOCALL);
2618 
2619 		BC_UNSETJMP(vm);
2620 
2621 		// We can just assert this here because
2622 		// dc should parse everything until EOF.
2623 		assert(vm->read_prs.l.t == BC_LEX_EOF);
2624 
2625 		BC_SIG_UNLOCK;
2626 	}
2627 
2628 	// Set the instruction pointer.
2629 	ip.idx = 0;
2630 	ip.len = p->results.len;
2631 	ip.func = fidx;
2632 
2633 	BC_SIG_LOCK;
2634 
2635 	// Pop the operand.
2636 	bc_vec_pop(&p->results);
2637 
2638 	// Tail call processing. This condition means that there is more on the
2639 	// execution stack, and we are at the end of the bytecode vector, and the
2640 	// last instruction is just a BC_INST_POP_EXEC, which would return.
2641 	if (p->stack.len > 1 && *bgn == len - 1 && code[*bgn] == BC_INST_POP_EXEC)
2642 	{
2643 		size_t* call_ptr = bc_vec_top(&p->tail_calls);
2644 
2645 		// Add one to the tail call.
2646 		*call_ptr += 1;
2647 
2648 		// Pop the execution stack before pushing the new instruction pointer
2649 		// on.
2650 		bc_vec_pop(&p->stack);
2651 	}
2652 	// If not a tail call, just push a new one.
2653 	else bc_vec_push(&p->tail_calls, &ip.idx);
2654 
2655 	// Push the new function onto the execution stack and return.
2656 	bc_vec_push(&p->stack, &ip);
2657 
2658 	BC_SIG_UNLOCK;
2659 
2660 	return;
2661 
2662 err:
2663 	BC_SIG_MAYLOCK;
2664 
2665 	f = bc_vec_item(&p->fns, fidx);
2666 
2667 	// Make sure to erase the bytecode vector so dc knows it is not parsed.
2668 	bc_vec_popAll(&f->code);
2669 
2670 exit:
2671 	bc_vec_pop(&p->results);
2672 	BC_LONGJMP_CONT(vm);
2673 }
2674 
2675 /**
2676  * Prints every item on the results stack, one per line.
2677  * @param p  The program.
2678  */
2679 static void
bc_program_printStack(BcProgram * p)2680 bc_program_printStack(BcProgram* p)
2681 {
2682 	size_t idx;
2683 
2684 	for (idx = 0; idx < p->results.len; ++idx)
2685 	{
2686 		bc_program_print(p, BC_INST_PRINT, idx);
2687 	}
2688 }
2689 #endif // DC_ENABLED
2690 
2691 /**
2692  * Pushes the value of a global onto the results stack.
2693  * @param p     The program.
2694  * @param inst  Which global to push, as an instruction.
2695  */
2696 static void
bc_program_pushGlobal(BcProgram * p,uchar inst)2697 bc_program_pushGlobal(BcProgram* p, uchar inst)
2698 {
2699 	BcResultType t;
2700 
2701 	// Make sure the instruction is valid.
2702 	assert(inst >= BC_INST_IBASE && inst <= BC_INST_SCALE);
2703 
2704 	// Push the global.
2705 	t = inst - BC_INST_IBASE + BC_RESULT_IBASE;
2706 	bc_program_pushBigdig(p, p->globals[inst - BC_INST_IBASE], t);
2707 }
2708 
2709 /**
2710  * Pushes the value of a global setting onto the stack.
2711  * @param p     The program.
2712  * @param inst  Which global setting to push, as an instruction.
2713  */
2714 static void
bc_program_globalSetting(BcProgram * p,uchar inst)2715 bc_program_globalSetting(BcProgram* p, uchar inst)
2716 {
2717 	BcBigDig val;
2718 
2719 	// Make sure the instruction is valid.
2720 #if DC_ENABLED
2721 	assert((inst >= BC_INST_LINE_LENGTH && inst <= BC_INST_LEADING_ZERO) ||
2722 	       (BC_IS_DC && inst == BC_INST_EXTENDED_REGISTERS));
2723 #else // DC_ENABLED
2724 	assert(inst >= BC_INST_LINE_LENGTH && inst <= BC_INST_LEADING_ZERO);
2725 #endif // DC_ENABLED
2726 
2727 	if (inst == BC_INST_LINE_LENGTH)
2728 	{
2729 		val = (BcBigDig) vm->line_len;
2730 	}
2731 #if BC_ENABLED
2732 	else if (inst == BC_INST_GLOBAL_STACKS)
2733 	{
2734 		val = (BC_G != 0);
2735 	}
2736 #endif // BC_ENABLED
2737 #if DC_ENABLED
2738 	else if (inst == BC_INST_EXTENDED_REGISTERS)
2739 	{
2740 		val = (DC_X != 0);
2741 	}
2742 #endif // DC_ENABLED
2743 	else val = (BC_Z != 0);
2744 
2745 	// Push the global.
2746 	bc_program_pushBigdig(p, val, BC_RESULT_TEMP);
2747 }
2748 
2749 #if BC_ENABLE_EXTRA_MATH
2750 
2751 /**
2752  * Pushes the value of seed on the stack.
2753  * @param p  The program.
2754  */
2755 static void
bc_program_pushSeed(BcProgram * p)2756 bc_program_pushSeed(BcProgram* p)
2757 {
2758 	BcResult* res;
2759 
2760 	res = bc_program_prepResult(p);
2761 
2762 	assert(p->nresults == 1);
2763 
2764 	res->t = BC_RESULT_SEED;
2765 
2766 	BC_SIG_LOCK;
2767 
2768 	// We need 2*BC_RAND_NUM_SIZE because of the size of the state.
2769 	bc_num_init(&res->d.n, 2 * BC_RAND_NUM_SIZE);
2770 
2771 	BC_SIG_UNLOCK;
2772 
2773 	bc_num_createFromRNG(&res->d.n, &p->rng);
2774 
2775 	// XXX: Clear the number of results.
2776 	p->nresults = 0;
2777 }
2778 
2779 #endif // BC_ENABLE_EXTRA_MATH
2780 
2781 /**
2782  * Adds a function to the fns array. The function's ID must have already been
2783  * inserted into the map.
2784  * @param p       The program.
2785  * @param id_ptr  The ID of the function as inserted into the map.
2786  */
2787 static void
bc_program_addFunc(BcProgram * p,BcId * id_ptr)2788 bc_program_addFunc(BcProgram* p, BcId* id_ptr)
2789 {
2790 	BcFunc* f;
2791 
2792 	BC_SIG_ASSERT_LOCKED;
2793 
2794 	// Push and init.
2795 	f = bc_vec_pushEmpty(&p->fns);
2796 	bc_func_init(f, id_ptr->name);
2797 }
2798 
2799 size_t
bc_program_insertFunc(BcProgram * p,const char * name)2800 bc_program_insertFunc(BcProgram* p, const char* name)
2801 {
2802 	BcId* id_ptr;
2803 	bool new;
2804 	size_t idx;
2805 
2806 	BC_SIG_ASSERT_LOCKED;
2807 
2808 	assert(p != NULL && name != NULL);
2809 
2810 	// Insert into the map and get the resulting ID.
2811 	new = bc_map_insert(&p->fn_map, name, p->fns.len, &idx);
2812 	id_ptr = (BcId*) bc_vec_item(&p->fn_map, idx);
2813 	idx = id_ptr->idx;
2814 
2815 	// If the function is new...
2816 	if (new)
2817 	{
2818 		// Add the function to the fns array.
2819 		bc_program_addFunc(p, id_ptr);
2820 	}
2821 #if BC_ENABLED
2822 	// bc has to reset the function because it's about to be redefined.
2823 	else if (BC_IS_BC)
2824 	{
2825 		BcFunc* func = bc_vec_item(&p->fns, idx);
2826 		bc_func_reset(func);
2827 	}
2828 #endif // BC_ENABLED
2829 
2830 	return idx;
2831 }
2832 
2833 #if BC_DEBUG || BC_ENABLE_MEMCHECK
2834 void
bc_program_free(BcProgram * p)2835 bc_program_free(BcProgram* p)
2836 {
2837 #if BC_ENABLED
2838 	size_t i;
2839 #endif // BC_ENABLED
2840 
2841 	BC_SIG_ASSERT_LOCKED;
2842 
2843 	assert(p != NULL);
2844 
2845 #if BC_ENABLED
2846 	// Free the globals stacks.
2847 	for (i = 0; i < BC_PROG_GLOBALS_LEN; ++i)
2848 	{
2849 		bc_vec_free(p->globals_v + i);
2850 	}
2851 #endif // BC_ENABLED
2852 
2853 	bc_vec_free(&p->fns);
2854 	bc_vec_free(&p->fn_map);
2855 	bc_vec_free(&p->vars);
2856 	bc_vec_free(&p->var_map);
2857 	bc_vec_free(&p->arrs);
2858 	bc_vec_free(&p->arr_map);
2859 	bc_vec_free(&p->results);
2860 	bc_vec_free(&p->stack);
2861 	bc_vec_free(&p->consts);
2862 	bc_vec_free(&p->const_map);
2863 	bc_vec_free(&p->strs);
2864 	bc_vec_free(&p->str_map);
2865 
2866 	bc_num_free(&p->asciify);
2867 
2868 #if BC_ENABLED
2869 	if (BC_IS_BC) bc_num_free(&p->last);
2870 #endif // BC_ENABLED
2871 
2872 #if BC_ENABLE_EXTRA_MATH
2873 	bc_rand_free(&p->rng);
2874 #endif // BC_ENABLE_EXTRA_MATH
2875 
2876 #if DC_ENABLED
2877 	if (BC_IS_DC) bc_vec_free(&p->tail_calls);
2878 #endif // DC_ENABLED
2879 }
2880 #endif // BC_DEBUG || BC_ENABLE_MEMCHECK
2881 
2882 void
bc_program_init(BcProgram * p)2883 bc_program_init(BcProgram* p)
2884 {
2885 	BcInstPtr ip;
2886 	size_t i;
2887 
2888 	BC_SIG_ASSERT_LOCKED;
2889 
2890 	assert(p != NULL);
2891 
2892 	// We want this clear.
2893 	// NOLINTNEXTLINE
2894 	memset(&ip, 0, sizeof(BcInstPtr));
2895 
2896 	// Setup the globals stacks and the current values.
2897 	for (i = 0; i < BC_PROG_GLOBALS_LEN; ++i)
2898 	{
2899 		BcBigDig val = i == BC_PROG_GLOBALS_SCALE ? 0 : BC_BASE;
2900 
2901 #if BC_ENABLED
2902 		bc_vec_init(p->globals_v + i, sizeof(BcBigDig), BC_DTOR_NONE);
2903 		bc_vec_push(p->globals_v + i, &val);
2904 #endif // BC_ENABLED
2905 
2906 		p->globals[i] = val;
2907 	}
2908 
2909 #if DC_ENABLED
2910 	// dc-only setup.
2911 	if (BC_IS_DC)
2912 	{
2913 		bc_vec_init(&p->tail_calls, sizeof(size_t), BC_DTOR_NONE);
2914 
2915 		// We want an item for the main function on the tail call stack.
2916 		i = 0;
2917 		bc_vec_push(&p->tail_calls, &i);
2918 	}
2919 #endif // DC_ENABLED
2920 
2921 	bc_num_setup(&p->strmb, p->strmb_num, BC_NUM_BIGDIG_LOG10);
2922 	bc_num_bigdig2num(&p->strmb, BC_NUM_STREAM_BASE);
2923 
2924 	bc_num_init(&p->asciify, BC_NUM_DEF_SIZE);
2925 
2926 #if BC_ENABLE_EXTRA_MATH
2927 	// We need to initialize srand() just in case /dev/urandom and /dev/random
2928 	// are not available.
2929 	srand((unsigned int) time(NULL));
2930 	bc_rand_init(&p->rng);
2931 #endif // BC_ENABLE_EXTRA_MATH
2932 
2933 #if BC_ENABLED
2934 	if (BC_IS_BC) bc_num_init(&p->last, BC_NUM_DEF_SIZE);
2935 #endif // BC_ENABLED
2936 
2937 #if BC_DEBUG
2938 	bc_vec_init(&p->fns, sizeof(BcFunc), BC_DTOR_FUNC);
2939 #else // BC_DEBUG
2940 	bc_vec_init(&p->fns, sizeof(BcFunc), BC_DTOR_NONE);
2941 #endif // BC_DEBUG
2942 	bc_map_init(&p->fn_map);
2943 	bc_program_insertFunc(p, bc_func_main);
2944 	bc_program_insertFunc(p, bc_func_read);
2945 
2946 	bc_vec_init(&p->vars, sizeof(BcVec), BC_DTOR_VEC);
2947 	bc_map_init(&p->var_map);
2948 
2949 	bc_vec_init(&p->arrs, sizeof(BcVec), BC_DTOR_VEC);
2950 	bc_map_init(&p->arr_map);
2951 
2952 	bc_vec_init(&p->results, sizeof(BcResult), BC_DTOR_RESULT);
2953 
2954 	// Push the first instruction pointer onto the execution stack.
2955 	bc_vec_init(&p->stack, sizeof(BcInstPtr), BC_DTOR_NONE);
2956 	bc_vec_push(&p->stack, &ip);
2957 
2958 	bc_vec_init(&p->consts, sizeof(BcConst), BC_DTOR_CONST);
2959 	bc_map_init(&p->const_map);
2960 	bc_vec_init(&p->strs, sizeof(char*), BC_DTOR_NONE);
2961 	bc_map_init(&p->str_map);
2962 
2963 	// XXX: Clear the number of results.
2964 	p->nresults = 0;
2965 }
2966 
2967 void
bc_program_printStackTrace(BcProgram * p)2968 bc_program_printStackTrace(BcProgram* p)
2969 {
2970 	size_t i, max_digits;
2971 
2972 	max_digits = bc_vm_numDigits(p->stack.len - 1);
2973 
2974 	for (i = 0; i < p->stack.len; ++i)
2975 	{
2976 		BcInstPtr* ip = bc_vec_item_rev(&p->stack, i);
2977 		BcFunc* f = bc_vec_item(&p->fns, ip->func);
2978 		size_t j, digits;
2979 
2980 		digits = bc_vm_numDigits(i);
2981 
2982 		bc_file_puts(&vm->ferr, bc_flush_none, "    ");
2983 
2984 		for (j = 0; j < max_digits - digits; ++j)
2985 		{
2986 			bc_file_putchar(&vm->ferr, bc_flush_none, ' ');
2987 		}
2988 
2989 		bc_file_printf(&vm->ferr, "%zu: %s", i, f->name);
2990 
2991 #if BC_ENABLED
2992 		if (BC_IS_BC && ip->func != BC_PROG_MAIN && ip->func != BC_PROG_READ)
2993 		{
2994 			bc_file_puts(&vm->ferr, bc_flush_none, "()");
2995 		}
2996 #endif // BC_ENABLED
2997 
2998 		bc_file_putchar(&vm->ferr, bc_flush_none, '\n');
2999 	}
3000 }
3001 
3002 void
bc_program_reset(BcProgram * p)3003 bc_program_reset(BcProgram* p)
3004 {
3005 	BcFunc* f;
3006 	BcInstPtr* ip;
3007 
3008 	BC_SIG_ASSERT_LOCKED;
3009 
3010 	// Pop all but the last execution.
3011 	bc_vec_npop(&p->stack, p->stack.len - 1);
3012 
3013 #if DC_ENABLED
3014 	// We need to pop tail calls too.
3015 	if (BC_IS_DC) bc_vec_npop(&p->tail_calls, p->tail_calls.len - 1);
3016 #endif // DC_ENABLED
3017 
3018 	// Clear the stack if we are in bc. We have to do this in bc because bc's
3019 	// stack is implicit.
3020 	//
3021 	// XXX: We don't do this in dc because other dc implementations don't.
3022 	// However, we *MUST* pop the items for results that are not retired yet.
3023 	if (BC_IS_DC && BC_I) bc_vec_npop(&p->results, p->nresults);
3024 	else bc_vec_popAll(&p->results);
3025 
3026 	// Now clear how many results there are.
3027 	p->nresults = 0;
3028 
3029 #if BC_ENABLED
3030 	// Clear the globals' stacks.
3031 	if (BC_G) bc_program_popGlobals(p, true);
3032 #endif // BC_ENABLED
3033 
3034 	// Clear the bytecode vector of the main function.
3035 	f = bc_vec_item(&p->fns, BC_PROG_MAIN);
3036 	bc_vec_npop(&f->code, f->code.len);
3037 
3038 	// Reset the instruction pointer.
3039 	ip = bc_vec_top(&p->stack);
3040 	// NOLINTNEXTLINE
3041 	memset(ip, 0, sizeof(BcInstPtr));
3042 
3043 	if (BC_SIG_INTERRUPT(vm))
3044 	{
3045 		// Write the ready message for a signal.
3046 		bc_file_printf(&vm->fout, "%s", bc_program_ready_msg);
3047 		bc_file_flush(&vm->fout, bc_flush_err);
3048 	}
3049 
3050 	// Clear the signal.
3051 	vm->sig = 0;
3052 }
3053 
3054 void
bc_program_exec(BcProgram * p)3055 bc_program_exec(BcProgram* p)
3056 {
3057 	size_t idx;
3058 	BcResult r;
3059 	BcResult* ptr;
3060 	BcInstPtr* ip;
3061 	BcFunc* func;
3062 	char* code;
3063 	bool cond = false;
3064 	uchar inst;
3065 #if BC_ENABLED
3066 	BcNum* num;
3067 #endif // BC_ENABLED
3068 #if !BC_HAS_COMPUTED_GOTO
3069 #if BC_DEBUG
3070 	size_t jmp_bufs_len;
3071 #endif // BC_DEBUG
3072 #endif // !BC_HAS_COMPUTED_GOTO
3073 
3074 #if BC_HAS_COMPUTED_GOTO
3075 
3076 #if BC_GCC
3077 #pragma GCC diagnostic push
3078 #pragma GCC diagnostic ignored "-Wpedantic"
3079 #endif // BC_GCC
3080 
3081 #if BC_CLANG
3082 #pragma clang diagnostic push
3083 #pragma clang diagnostic ignored "-Wgnu-label-as-value"
3084 #endif // BC_CLANG
3085 
3086 	BC_PROG_LBLS;
3087 	BC_PROG_LBLS_ASSERT;
3088 
3089 #if BC_CLANG
3090 #pragma clang diagnostic pop
3091 #endif // BC_CLANG
3092 
3093 #if BC_GCC
3094 #pragma GCC diagnostic pop
3095 #endif // BC_GCC
3096 
3097 	// BC_INST_INVALID is a marker for the end so that we don't have to have an
3098 	// execution loop.
3099 	func = (BcFunc*) bc_vec_item(&p->fns, BC_PROG_MAIN);
3100 	bc_vec_pushByte(&func->code, BC_INST_INVALID);
3101 #endif // BC_HAS_COMPUTED_GOTO
3102 
3103 	BC_SETJMP(vm, end);
3104 
3105 	ip = bc_vec_top(&p->stack);
3106 	func = (BcFunc*) bc_vec_item(&p->fns, ip->func);
3107 	code = func->code.v;
3108 
3109 #if !BC_HAS_COMPUTED_GOTO
3110 
3111 #if BC_DEBUG
3112 	jmp_bufs_len = vm->jmp_bufs.len;
3113 #endif // BC_DEBUG
3114 
3115 	// This loop is the heart of the execution engine. It *is* the engine. For
3116 	// computed goto, it is ignored.
3117 	while (ip->idx < func->code.len)
3118 #endif // !BC_HAS_COMPUTED_GOTO
3119 	{
3120 		BC_SIG_ASSERT_NOT_LOCKED;
3121 
3122 #if BC_HAS_COMPUTED_GOTO
3123 
3124 #if BC_GCC
3125 #pragma GCC diagnostic push
3126 #pragma GCC diagnostic ignored "-Wpedantic"
3127 #endif // BC_GCC
3128 
3129 #if BC_CLANG
3130 #pragma clang diagnostic push
3131 #pragma clang diagnostic ignored "-Wgnu-label-as-value"
3132 #endif // BC_CLANG
3133 
3134 		BC_PROG_JUMP(inst, code, ip);
3135 
3136 #else // BC_HAS_COMPUTED_GOTO
3137 
3138 		// Get the next instruction and increment the index.
3139 		inst = (uchar) code[(ip->idx)++];
3140 
3141 #endif // BC_HAS_COMPUTED_GOTO
3142 
3143 #if BC_DEBUG_CODE
3144 		bc_file_printf(&vm->ferr, "inst: %s\n", bc_inst_names[inst]);
3145 		bc_file_flush(&vm->ferr, bc_flush_none);
3146 #endif // BC_DEBUG_CODE
3147 
3148 #if !BC_HAS_COMPUTED_GOTO
3149 		switch (inst)
3150 #endif // !BC_HAS_COMPUTED_GOTO
3151 		{
3152 #if BC_ENABLED
3153 			// This just sets up the condition for the unconditional jump below,
3154 			// which checks the condition, if necessary.
3155 			// clang-format off
3156 			BC_PROG_LBL(BC_INST_JUMP_ZERO):
3157 			// clang-format on
3158 			{
3159 				bc_program_prep(p, &ptr, &num, 0);
3160 
3161 				cond = !bc_num_cmpZero(num);
3162 				bc_vec_pop(&p->results);
3163 
3164 				BC_PROG_DIRECT_JUMP(BC_INST_JUMP)
3165 			}
3166 			// Fallthrough.
3167 			BC_PROG_FALLTHROUGH
3168 
3169 			// clang-format off
3170 			BC_PROG_LBL(BC_INST_JUMP):
3171 			// clang-format on
3172 			{
3173 				idx = bc_program_index(code, &ip->idx);
3174 
3175 				// If a jump is required...
3176 				if (inst == BC_INST_JUMP || cond)
3177 				{
3178 					// Get the address to jump to.
3179 					size_t* addr = bc_vec_item(&func->labels, idx);
3180 
3181 					// If this fails, then the parser failed to set up the
3182 					// labels correctly.
3183 					assert(*addr != SIZE_MAX);
3184 
3185 					// Set the new address.
3186 					ip->idx = *addr;
3187 				}
3188 
3189 				BC_PROG_JUMP(inst, code, ip);
3190 			}
3191 
3192 			// clang-format off
3193 			BC_PROG_LBL(BC_INST_CALL):
3194 			// clang-format on
3195 			{
3196 				assert(BC_IS_BC);
3197 
3198 				bc_program_call(p, code, &ip->idx);
3199 
3200 				// Because we changed the execution stack and where we are
3201 				// executing, we have to update all of this.
3202 				BC_SIG_LOCK;
3203 				ip = bc_vec_top(&p->stack);
3204 				func = bc_vec_item(&p->fns, ip->func);
3205 				code = func->code.v;
3206 				BC_SIG_UNLOCK;
3207 
3208 				BC_PROG_JUMP(inst, code, ip);
3209 			}
3210 
3211 			// clang-format off
3212 			BC_PROG_LBL(BC_INST_INC):
3213 			BC_PROG_LBL(BC_INST_DEC):
3214 			// clang-format on
3215 			{
3216 				bc_program_incdec(p, inst);
3217 				BC_PROG_JUMP(inst, code, ip);
3218 			}
3219 
3220 			// clang-format off
3221 			BC_PROG_LBL(BC_INST_HALT):
3222 			// clang-format on
3223 			{
3224 				vm->status = BC_STATUS_QUIT;
3225 
3226 				// Just jump out. The jump series will take care of everything.
3227 				BC_JMP;
3228 
3229 				BC_PROG_JUMP(inst, code, ip);
3230 			}
3231 
3232 			// clang-format off
3233 			BC_PROG_LBL(BC_INST_RET):
3234 			BC_PROG_LBL(BC_INST_RET0):
3235 			BC_PROG_LBL(BC_INST_RET_VOID):
3236 			// clang-format on
3237 			{
3238 				bc_program_return(p, inst);
3239 
3240 				// Because we changed the execution stack and where we are
3241 				// executing, we have to update all of this.
3242 				BC_SIG_LOCK;
3243 				ip = bc_vec_top(&p->stack);
3244 				func = bc_vec_item(&p->fns, ip->func);
3245 				code = func->code.v;
3246 				BC_SIG_UNLOCK;
3247 
3248 				BC_PROG_JUMP(inst, code, ip);
3249 			}
3250 #endif // BC_ENABLED
3251 
3252 			// clang-format off
3253 			BC_PROG_LBL(BC_INST_BOOL_OR):
3254 			BC_PROG_LBL(BC_INST_BOOL_AND):
3255 			BC_PROG_LBL(BC_INST_REL_EQ):
3256 			BC_PROG_LBL(BC_INST_REL_LE):
3257 			BC_PROG_LBL(BC_INST_REL_GE):
3258 			BC_PROG_LBL(BC_INST_REL_NE):
3259 			BC_PROG_LBL(BC_INST_REL_LT):
3260 			BC_PROG_LBL(BC_INST_REL_GT):
3261 			// clang-format on
3262 			{
3263 				bc_program_logical(p, inst);
3264 				BC_PROG_JUMP(inst, code, ip);
3265 			}
3266 
3267 			// clang-format off
3268 			BC_PROG_LBL(BC_INST_READ):
3269 			// clang-format on
3270 			{
3271 				// We want to flush output before
3272 				// this in case there is a prompt.
3273 				bc_file_flush(&vm->fout, bc_flush_save);
3274 
3275 				bc_program_read(p);
3276 
3277 				// Because we changed the execution stack and where we are
3278 				// executing, we have to update all of this.
3279 				BC_SIG_LOCK;
3280 				ip = bc_vec_top(&p->stack);
3281 				func = bc_vec_item(&p->fns, ip->func);
3282 				code = func->code.v;
3283 				BC_SIG_UNLOCK;
3284 
3285 				BC_PROG_JUMP(inst, code, ip);
3286 			}
3287 
3288 #if BC_ENABLE_EXTRA_MATH
3289 			// clang-format off
3290 			BC_PROG_LBL(BC_INST_RAND):
3291 			// clang-format on
3292 			{
3293 				bc_program_rand(p);
3294 				BC_PROG_JUMP(inst, code, ip);
3295 			}
3296 #endif // BC_ENABLE_EXTRA_MATH
3297 
3298 			// clang-format off
3299 			BC_PROG_LBL(BC_INST_MAXIBASE):
3300 			BC_PROG_LBL(BC_INST_MAXOBASE):
3301 			BC_PROG_LBL(BC_INST_MAXSCALE):
3302 #if BC_ENABLE_EXTRA_MATH
3303 			BC_PROG_LBL(BC_INST_MAXRAND):
3304 #endif // BC_ENABLE_EXTRA_MATH
3305 			// clang-format on
3306 			{
3307 				BcBigDig dig = vm->maxes[inst - BC_INST_MAXIBASE];
3308 				bc_program_pushBigdig(p, dig, BC_RESULT_TEMP);
3309 				BC_PROG_JUMP(inst, code, ip);
3310 			}
3311 
3312 			// clang-format off
3313 			BC_PROG_LBL(BC_INST_LINE_LENGTH):
3314 #if BC_ENABLED
3315 			BC_PROG_LBL(BC_INST_GLOBAL_STACKS):
3316 #endif // BC_ENABLED
3317 #if DC_ENABLED
3318 			BC_PROG_LBL(BC_INST_EXTENDED_REGISTERS):
3319 #endif // DC_ENABLE
3320 			BC_PROG_LBL(BC_INST_LEADING_ZERO):
3321 			// clang-format on
3322 			{
3323 				bc_program_globalSetting(p, inst);
3324 				BC_PROG_JUMP(inst, code, ip);
3325 			}
3326 
3327 			// clang-format off
3328 			BC_PROG_LBL(BC_INST_VAR):
3329 			// clang-format on
3330 			{
3331 				bc_program_pushVar(p, code, &ip->idx, false, false);
3332 				BC_PROG_JUMP(inst, code, ip);
3333 			}
3334 
3335 			// clang-format off
3336 			BC_PROG_LBL(BC_INST_ARRAY_ELEM):
3337 			BC_PROG_LBL(BC_INST_ARRAY):
3338 			// clang-format on
3339 			{
3340 				bc_program_pushArray(p, code, &ip->idx, inst);
3341 				BC_PROG_JUMP(inst, code, ip);
3342 			}
3343 
3344 			// clang-format off
3345 			BC_PROG_LBL(BC_INST_IBASE):
3346 			BC_PROG_LBL(BC_INST_SCALE):
3347 			BC_PROG_LBL(BC_INST_OBASE):
3348 			// clang-format on
3349 			{
3350 				bc_program_pushGlobal(p, inst);
3351 				BC_PROG_JUMP(inst, code, ip);
3352 			}
3353 
3354 #if BC_ENABLE_EXTRA_MATH
3355 			// clang-format off
3356 			BC_PROG_LBL(BC_INST_SEED):
3357 			// clang-format on
3358 			{
3359 				bc_program_pushSeed(p);
3360 				BC_PROG_JUMP(inst, code, ip);
3361 			}
3362 #endif // BC_ENABLE_EXTRA_MATH
3363 
3364 			// clang-format off
3365 			BC_PROG_LBL(BC_INST_LENGTH):
3366 			BC_PROG_LBL(BC_INST_SCALE_FUNC):
3367 			BC_PROG_LBL(BC_INST_SQRT):
3368 			BC_PROG_LBL(BC_INST_ABS):
3369 			BC_PROG_LBL(BC_INST_IS_NUMBER):
3370 			BC_PROG_LBL(BC_INST_IS_STRING):
3371 #if BC_ENABLE_EXTRA_MATH
3372 			BC_PROG_LBL(BC_INST_IRAND):
3373 #endif // BC_ENABLE_EXTRA_MATH
3374 			// clang-format on
3375 			{
3376 				bc_program_builtin(p, inst);
3377 				BC_PROG_JUMP(inst, code, ip);
3378 			}
3379 
3380 			// clang-format off
3381 			BC_PROG_LBL(BC_INST_ASCIIFY):
3382 			// clang-format on
3383 			{
3384 				bc_program_asciify(p);
3385 
3386 				// Because we changed the execution stack and where we are
3387 				// executing, we have to update all of this.
3388 				BC_SIG_LOCK;
3389 				ip = bc_vec_top(&p->stack);
3390 				func = bc_vec_item(&p->fns, ip->func);
3391 				code = func->code.v;
3392 				BC_SIG_UNLOCK;
3393 
3394 				BC_PROG_JUMP(inst, code, ip);
3395 			}
3396 
3397 			// clang-format off
3398 			BC_PROG_LBL(BC_INST_NUM):
3399 			// clang-format on
3400 			{
3401 				bc_program_const(p, code, &ip->idx);
3402 				BC_PROG_JUMP(inst, code, ip);
3403 			}
3404 
3405 			// clang-format off
3406 			BC_PROG_LBL(BC_INST_ZERO):
3407 			BC_PROG_LBL(BC_INST_ONE):
3408 #if BC_ENABLED
3409 			BC_PROG_LBL(BC_INST_LAST):
3410 #endif // BC_ENABLED
3411 			// clang-format on
3412 			{
3413 				r.t = BC_RESULT_ZERO + (inst - BC_INST_ZERO);
3414 				bc_vec_push(&p->results, &r);
3415 				BC_PROG_JUMP(inst, code, ip);
3416 			}
3417 
3418 			// clang-format off
3419 			BC_PROG_LBL(BC_INST_PRINT):
3420 			BC_PROG_LBL(BC_INST_PRINT_POP):
3421 #if BC_ENABLED
3422 			BC_PROG_LBL(BC_INST_PRINT_STR):
3423 #endif // BC_ENABLED
3424 			// clang-format on
3425 			{
3426 				bc_program_print(p, inst, 0);
3427 
3428 				// We want to flush right away to save the output for history,
3429 				// if history must preserve it when taking input.
3430 				bc_file_flush(&vm->fout, bc_flush_save);
3431 
3432 				BC_PROG_JUMP(inst, code, ip);
3433 			}
3434 
3435 			// clang-format off
3436 			BC_PROG_LBL(BC_INST_STR):
3437 			// clang-format on
3438 			{
3439 				// Set up the result and push.
3440 				r.t = BC_RESULT_STR;
3441 				bc_num_clear(&r.d.n);
3442 				r.d.n.scale = bc_program_index(code, &ip->idx);
3443 				bc_vec_push(&p->results, &r);
3444 				BC_PROG_JUMP(inst, code, ip);
3445 			}
3446 
3447 			// clang-format off
3448 			BC_PROG_LBL(BC_INST_POWER):
3449 			BC_PROG_LBL(BC_INST_MULTIPLY):
3450 			BC_PROG_LBL(BC_INST_DIVIDE):
3451 			BC_PROG_LBL(BC_INST_MODULUS):
3452 			BC_PROG_LBL(BC_INST_PLUS):
3453 			BC_PROG_LBL(BC_INST_MINUS):
3454 #if BC_ENABLE_EXTRA_MATH
3455 			BC_PROG_LBL(BC_INST_PLACES):
3456 			BC_PROG_LBL(BC_INST_LSHIFT):
3457 			BC_PROG_LBL(BC_INST_RSHIFT):
3458 #endif // BC_ENABLE_EXTRA_MATH
3459 			// clang-format on
3460 			{
3461 				bc_program_op(p, inst);
3462 				BC_PROG_JUMP(inst, code, ip);
3463 			}
3464 
3465 			// clang-format off
3466 			BC_PROG_LBL(BC_INST_NEG):
3467 			BC_PROG_LBL(BC_INST_BOOL_NOT):
3468 #if BC_ENABLE_EXTRA_MATH
3469 			BC_PROG_LBL(BC_INST_TRUNC):
3470 #endif // BC_ENABLE_EXTRA_MATH
3471 			// clang-format on
3472 			{
3473 				bc_program_unary(p, inst);
3474 				BC_PROG_JUMP(inst, code, ip);
3475 			}
3476 
3477 			// clang-format off
3478 #if BC_ENABLED
3479 			BC_PROG_LBL(BC_INST_ASSIGN_POWER):
3480 			BC_PROG_LBL(BC_INST_ASSIGN_MULTIPLY):
3481 			BC_PROG_LBL(BC_INST_ASSIGN_DIVIDE):
3482 			BC_PROG_LBL(BC_INST_ASSIGN_MODULUS):
3483 			BC_PROG_LBL(BC_INST_ASSIGN_PLUS):
3484 			BC_PROG_LBL(BC_INST_ASSIGN_MINUS):
3485 #if BC_ENABLE_EXTRA_MATH
3486 			BC_PROG_LBL(BC_INST_ASSIGN_PLACES):
3487 			BC_PROG_LBL(BC_INST_ASSIGN_LSHIFT):
3488 			BC_PROG_LBL(BC_INST_ASSIGN_RSHIFT):
3489 #endif // BC_ENABLE_EXTRA_MATH
3490 			BC_PROG_LBL(BC_INST_ASSIGN):
3491 			BC_PROG_LBL(BC_INST_ASSIGN_POWER_NO_VAL):
3492 			BC_PROG_LBL(BC_INST_ASSIGN_MULTIPLY_NO_VAL):
3493 			BC_PROG_LBL(BC_INST_ASSIGN_DIVIDE_NO_VAL):
3494 			BC_PROG_LBL(BC_INST_ASSIGN_MODULUS_NO_VAL):
3495 			BC_PROG_LBL(BC_INST_ASSIGN_PLUS_NO_VAL):
3496 			BC_PROG_LBL(BC_INST_ASSIGN_MINUS_NO_VAL):
3497 #if BC_ENABLE_EXTRA_MATH
3498 			BC_PROG_LBL(BC_INST_ASSIGN_PLACES_NO_VAL):
3499 			BC_PROG_LBL(BC_INST_ASSIGN_LSHIFT_NO_VAL):
3500 			BC_PROG_LBL(BC_INST_ASSIGN_RSHIFT_NO_VAL):
3501 #endif // BC_ENABLE_EXTRA_MATH
3502 #endif // BC_ENABLED
3503 			BC_PROG_LBL(BC_INST_ASSIGN_NO_VAL):
3504 			// clang-format on
3505 			{
3506 				bc_program_assign(p, inst);
3507 				BC_PROG_JUMP(inst, code, ip);
3508 			}
3509 
3510 			// clang-format off
3511 			BC_PROG_LBL(BC_INST_POP):
3512 			// clang-format on
3513 			{
3514 #ifndef BC_PROG_NO_STACK_CHECK
3515 				// dc must do a stack check, but bc does not.
3516 				if (BC_IS_DC)
3517 				{
3518 					if (BC_ERR(!BC_PROG_STACK(&p->results, 1)))
3519 					{
3520 						bc_err(BC_ERR_EXEC_STACK);
3521 					}
3522 				}
3523 #endif // BC_PROG_NO_STACK_CHECK
3524 
3525 				assert(BC_PROG_STACK(&p->results, 1));
3526 
3527 				bc_vec_pop(&p->results);
3528 
3529 				BC_PROG_JUMP(inst, code, ip);
3530 			}
3531 
3532 			// clang-format off
3533 			BC_PROG_LBL(BC_INST_SWAP):
3534 			// clang-format on
3535 			{
3536 				BcResult* ptr2;
3537 
3538 				// Check the stack.
3539 				if (BC_ERR(!BC_PROG_STACK(&p->results, 2)))
3540 				{
3541 					bc_err(BC_ERR_EXEC_STACK);
3542 				}
3543 
3544 				assert(BC_PROG_STACK(&p->results, 2));
3545 
3546 				// Get the two items.
3547 				ptr = bc_vec_item_rev(&p->results, 0);
3548 				ptr2 = bc_vec_item_rev(&p->results, 1);
3549 
3550 				// Swap. It's just easiest to do it this way.
3551 				// NOLINTNEXTLINE
3552 				memcpy(&r, ptr, sizeof(BcResult));
3553 				// NOLINTNEXTLINE
3554 				memcpy(ptr, ptr2, sizeof(BcResult));
3555 				// NOLINTNEXTLINE
3556 				memcpy(ptr2, &r, sizeof(BcResult));
3557 
3558 				BC_PROG_JUMP(inst, code, ip);
3559 			}
3560 
3561 			// clang-format off
3562 			BC_PROG_LBL(BC_INST_MODEXP):
3563 			// clang-format on
3564 			{
3565 				bc_program_modexp(p);
3566 				BC_PROG_JUMP(inst, code, ip);
3567 			}
3568 
3569 			// clang-format off
3570 			BC_PROG_LBL(BC_INST_DIVMOD):
3571 			// clang-format on
3572 			{
3573 				bc_program_divmod(p);
3574 				BC_PROG_JUMP(inst, code, ip);
3575 			}
3576 
3577 			// clang-format off
3578 			BC_PROG_LBL(BC_INST_PRINT_STREAM):
3579 			// clang-format on
3580 			{
3581 				bc_program_printStream(p);
3582 				BC_PROG_JUMP(inst, code, ip);
3583 			}
3584 
3585 #if DC_ENABLED
3586 			// clang-format off
3587 			BC_PROG_LBL(BC_INST_POP_EXEC):
3588 			// clang-format on
3589 			{
3590 				// If this fails, the dc parser got something wrong.
3591 				assert(BC_PROG_STACK(&p->stack, 2));
3592 
3593 				// Pop the execution stack and tail call stack.
3594 				bc_vec_pop(&p->stack);
3595 				bc_vec_pop(&p->tail_calls);
3596 
3597 				// Because we changed the execution stack and where we are
3598 				// executing, we have to update all of this.
3599 				BC_SIG_LOCK;
3600 				ip = bc_vec_top(&p->stack);
3601 				func = bc_vec_item(&p->fns, ip->func);
3602 				code = func->code.v;
3603 				BC_SIG_UNLOCK;
3604 
3605 				BC_PROG_JUMP(inst, code, ip);
3606 			}
3607 
3608 			// clang-format off
3609 			BC_PROG_LBL(BC_INST_EXECUTE):
3610 			BC_PROG_LBL(BC_INST_EXEC_COND):
3611 			// clang-format on
3612 			{
3613 				cond = (inst == BC_INST_EXEC_COND);
3614 
3615 				bc_program_execStr(p, code, &ip->idx, cond, func->code.len);
3616 
3617 				// Because we changed the execution stack and where we are
3618 				// executing, we have to update all of this.
3619 				BC_SIG_LOCK;
3620 				ip = bc_vec_top(&p->stack);
3621 				func = bc_vec_item(&p->fns, ip->func);
3622 				code = func->code.v;
3623 				BC_SIG_UNLOCK;
3624 
3625 				BC_PROG_JUMP(inst, code, ip);
3626 			}
3627 
3628 			// clang-format off
3629 			BC_PROG_LBL(BC_INST_PRINT_STACK):
3630 			// clang-format on
3631 			{
3632 				bc_program_printStack(p);
3633 				BC_PROG_JUMP(inst, code, ip);
3634 			}
3635 
3636 			// clang-format off
3637 			BC_PROG_LBL(BC_INST_CLEAR_STACK):
3638 			// clang-format on
3639 			{
3640 				bc_vec_popAll(&p->results);
3641 				BC_PROG_JUMP(inst, code, ip);
3642 			}
3643 
3644 			// clang-format off
3645 			BC_PROG_LBL(BC_INST_REG_STACK_LEN):
3646 			// clang-format on
3647 			{
3648 				bc_program_regStackLen(p, code, &ip->idx);
3649 				BC_PROG_JUMP(inst, code, ip);
3650 			}
3651 
3652 			// clang-format off
3653 			BC_PROG_LBL(BC_INST_STACK_LEN):
3654 			// clang-format on
3655 			{
3656 				bc_program_stackLen(p);
3657 				BC_PROG_JUMP(inst, code, ip);
3658 			}
3659 
3660 			// clang-format off
3661 			BC_PROG_LBL(BC_INST_DUPLICATE):
3662 			// clang-format on
3663 			{
3664 				// Check the stack.
3665 				if (BC_ERR(!BC_PROG_STACK(&p->results, 1)))
3666 				{
3667 					bc_err(BC_ERR_EXEC_STACK);
3668 				}
3669 
3670 				assert(BC_PROG_STACK(&p->results, 1));
3671 
3672 				// Get the top of the stack.
3673 				ptr = bc_vec_top(&p->results);
3674 
3675 				BC_SIG_LOCK;
3676 
3677 				// Copy and push.
3678 				bc_result_copy(&r, ptr);
3679 				bc_vec_push(&p->results, &r);
3680 
3681 				BC_SIG_UNLOCK;
3682 
3683 				BC_PROG_JUMP(inst, code, ip);
3684 			}
3685 
3686 			// clang-format off
3687 			BC_PROG_LBL(BC_INST_LOAD):
3688 			BC_PROG_LBL(BC_INST_PUSH_VAR):
3689 			// clang-format on
3690 			{
3691 				bool copy = (inst == BC_INST_LOAD);
3692 				bc_program_pushVar(p, code, &ip->idx, true, copy);
3693 				BC_PROG_JUMP(inst, code, ip);
3694 			}
3695 
3696 			// clang-format off
3697 			BC_PROG_LBL(BC_INST_PUSH_TO_VAR):
3698 			// clang-format on
3699 			{
3700 				idx = bc_program_index(code, &ip->idx);
3701 				bc_program_copyToVar(p, idx, BC_TYPE_VAR);
3702 				BC_PROG_JUMP(inst, code, ip);
3703 			}
3704 
3705 			// clang-format off
3706 			BC_PROG_LBL(BC_INST_QUIT):
3707 			BC_PROG_LBL(BC_INST_NQUIT):
3708 			// clang-format on
3709 			{
3710 				bc_program_nquit(p, inst);
3711 
3712 				// Because we changed the execution stack and where we are
3713 				// executing, we have to update all of this.
3714 				BC_SIG_LOCK;
3715 				ip = bc_vec_top(&p->stack);
3716 				func = bc_vec_item(&p->fns, ip->func);
3717 				code = func->code.v;
3718 				BC_SIG_UNLOCK;
3719 
3720 				BC_PROG_JUMP(inst, code, ip);
3721 			}
3722 
3723 			// clang-format off
3724 			BC_PROG_LBL(BC_INST_EXEC_STACK_LEN):
3725 			// clang-format on
3726 			{
3727 				bc_program_execStackLen(p);
3728 				BC_PROG_JUMP(inst, code, ip);
3729 			}
3730 #endif // DC_ENABLED
3731 
3732 #if BC_HAS_COMPUTED_GOTO
3733 			// clang-format off
3734 			BC_PROG_LBL(BC_INST_INVALID):
3735 			// clang-format on
3736 			{
3737 				goto end;
3738 			}
3739 #else // BC_HAS_COMPUTED_GOTO
3740 			default:
3741 			{
3742 				BC_UNREACHABLE
3743 #if BC_DEBUG && !BC_CLANG
3744 				abort();
3745 #endif // BC_DEBUG && !BC_CLANG
3746 			}
3747 #endif // BC_HAS_COMPUTED_GOTO
3748 		}
3749 
3750 #if BC_HAS_COMPUTED_GOTO
3751 
3752 #if BC_CLANG
3753 #pragma clang diagnostic pop
3754 #endif // BC_CLANG
3755 
3756 #if BC_GCC
3757 #pragma GCC diagnostic pop
3758 #endif // BC_GCC
3759 
3760 #else // BC_HAS_COMPUTED_GOTO
3761 
3762 #if BC_DEBUG
3763 		// This is to allow me to use a debugger to see the last instruction,
3764 		// which will point to which function was the problem. But it's also a
3765 		// good smoke test for error handling changes.
3766 		assert(jmp_bufs_len == vm->jmp_bufs.len);
3767 #endif // BC_DEBUG
3768 
3769 #endif // BC_HAS_COMPUTED_GOTO
3770 	}
3771 
3772 end:
3773 	BC_SIG_MAYLOCK;
3774 
3775 	// This is here just to print a stack trace on interrupts. This is for
3776 	// finding infinite loops.
3777 	if (BC_SIG_INTERRUPT(vm))
3778 	{
3779 		BcStatus s;
3780 
3781 		bc_file_putchar(&vm->ferr, bc_flush_none, '\n');
3782 
3783 		bc_program_printStackTrace(p);
3784 
3785 		s = bc_file_flushErr(&vm->ferr, bc_flush_err);
3786 		if (BC_ERR(s != BC_STATUS_SUCCESS && vm->status == BC_STATUS_SUCCESS))
3787 		{
3788 			vm->status = (sig_atomic_t) s;
3789 		}
3790 	}
3791 
3792 	BC_LONGJMP_CONT(vm);
3793 }
3794 
3795 #if BC_DEBUG_CODE
3796 #if BC_ENABLED && DC_ENABLED
3797 void
bc_program_printStackDebug(BcProgram * p)3798 bc_program_printStackDebug(BcProgram* p)
3799 {
3800 	bc_file_puts(&vm->fout, bc_flush_err, "-------------- Stack ----------\n");
3801 	bc_program_printStack(p);
3802 	bc_file_puts(&vm->fout, bc_flush_err, "-------------- Stack End ------\n");
3803 }
3804 
3805 static void
bc_program_printIndex(const char * restrict code,size_t * restrict bgn)3806 bc_program_printIndex(const char* restrict code, size_t* restrict bgn)
3807 {
3808 	uchar byte, i, bytes = (uchar) code[(*bgn)++];
3809 	ulong val = 0;
3810 
3811 	for (byte = 1, i = 0; byte && i < bytes; ++i)
3812 	{
3813 		byte = (uchar) code[(*bgn)++];
3814 		if (byte) val |= ((ulong) byte) << (CHAR_BIT * i);
3815 	}
3816 
3817 	bc_vm_printf(" (%lu) ", val);
3818 }
3819 
3820 static void
bc_program_printStr(const BcProgram * p,const char * restrict code,size_t * restrict bgn)3821 bc_program_printStr(const BcProgram* p, const char* restrict code,
3822                     size_t* restrict bgn)
3823 {
3824 	size_t idx = bc_program_index(code, bgn);
3825 	char* s;
3826 
3827 	s = *((char**) bc_vec_item(&p->strs, idx));
3828 
3829 	bc_vm_printf(" (\"%s\") ", s);
3830 }
3831 
3832 void
bc_program_printInst(const BcProgram * p,const char * restrict code,size_t * restrict bgn)3833 bc_program_printInst(const BcProgram* p, const char* restrict code,
3834                      size_t* restrict bgn)
3835 {
3836 	uchar inst = (uchar) code[(*bgn)++];
3837 
3838 	bc_vm_printf("Inst[%zu]: %s [%lu]; ", *bgn - 1, bc_inst_names[inst],
3839 	             (unsigned long) inst);
3840 
3841 	if (inst == BC_INST_VAR || inst == BC_INST_ARRAY_ELEM ||
3842 	    inst == BC_INST_ARRAY)
3843 	{
3844 		bc_program_printIndex(code, bgn);
3845 	}
3846 	else if (inst == BC_INST_STR) bc_program_printStr(p, code, bgn);
3847 	else if (inst == BC_INST_NUM)
3848 	{
3849 		size_t idx = bc_program_index(code, bgn);
3850 		BcConst* c = bc_vec_item(&p->consts, idx);
3851 		bc_vm_printf("(%s)", c->val);
3852 	}
3853 	else if (inst == BC_INST_CALL ||
3854 	         (inst > BC_INST_STR && inst <= BC_INST_JUMP_ZERO))
3855 	{
3856 		bc_program_printIndex(code, bgn);
3857 		if (inst == BC_INST_CALL) bc_program_printIndex(code, bgn);
3858 	}
3859 
3860 	bc_vm_putchar('\n', bc_flush_err);
3861 }
3862 
3863 void
bc_program_code(const BcProgram * p)3864 bc_program_code(const BcProgram* p)
3865 {
3866 	BcFunc* f;
3867 	char* code;
3868 	BcInstPtr ip;
3869 	size_t i;
3870 
3871 	for (i = 0; i < p->fns.len; ++i)
3872 	{
3873 		ip.idx = ip.len = 0;
3874 		ip.func = i;
3875 
3876 		f = bc_vec_item(&p->fns, ip.func);
3877 		code = f->code.v;
3878 
3879 		bc_vm_printf("func[%zu]:\n", ip.func);
3880 		while (ip.idx < f->code.len)
3881 		{
3882 			bc_program_printInst(p, code, &ip.idx);
3883 		}
3884 		bc_file_puts(&vm->fout, bc_flush_err, "\n\n");
3885 	}
3886 }
3887 #endif // BC_ENABLED && DC_ENABLED
3888 #endif // BC_DEBUG_CODE
3889