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