2 * *****************************************************************************
4 * SPDX-License-Identifier: BSD-2-Clause
6 * Copyright (c) 2018-2021 Gavin D. Howard and contributors.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are met:
11 * * Redistributions of source code must retain the above copyright notice, this
12 * list of conditions and the following disclaimer.
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.
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.
30 * *****************************************************************************
32 * Code to execute bc programs.
52 * Quickly sets the const and strs vector pointers in the program. This is a
53 * convenience function.
54 * @param p The program.
55 * @param f The new function.
57 static inline void bc_program_setVecs(BcProgram *p, BcFunc *f) {
58 p->consts = &f->consts;
63 * Does a type check for something that expects a number.
64 * @param r The result that will be checked.
65 * @param n The result's number.
67 static inline void bc_program_type_num(BcResult *r, BcNum *n) {
71 // This should have already been taken care of.
72 assert(r->t != BC_RESULT_VOID);
76 if (BC_ERR(!BC_PROG_NUM(r, n))) bc_err(BC_ERR_EXEC_TYPE);
83 * @param r The result to check.
84 * @param t The type that the result should be.
86 static void bc_program_type_match(BcResult *r, BcType t) {
87 if (BC_ERR((r->t != BC_RESULT_ARRAY) != (!t))) bc_err(BC_ERR_EXEC_TYPE);
92 * Pulls an index out of a bytecode vector and updates the index into the vector
93 * to point to the spot after the index. For more details on bytecode indices,
94 * see the development manual (manuals/development.md#bytecode-indices).
95 * @param code The bytecode vector.
96 * @param bgn An in/out parameter; the index into the vector that will be
98 * @return The index at @a bgn in the bytecode vector.
100 static size_t bc_program_index(const char *restrict code, size_t *restrict bgn)
102 uchar amt = (uchar) code[(*bgn)++], i = 0;
105 for (; i < amt; ++i, ++(*bgn)) {
106 size_t temp = ((size_t) ((int) (uchar) code[*bgn]) & UCHAR_MAX);
107 res |= (temp << (i * CHAR_BIT));
114 * Returns a string from a result and its number.
115 * @param p The program.
116 * @param n The number tied to the result.
117 * @return The string corresponding to the result and number.
119 static char* bc_program_string(BcProgram *p, const BcNum *n) {
120 BcFunc *f = bc_vec_item(&p->fns, n->rdx);
121 return *((char**) bc_vec_item(&f->strs, n->scale));
127 * Prepares the globals for a function call. This is only called when global
128 * stacks are on because it pushes a copy of the current globals onto each of
129 * their respective stacks.
130 * @param p The program.
132 static void bc_program_prepGlobals(BcProgram *p) {
136 for (i = 0; i < BC_PROG_GLOBALS_LEN; ++i)
137 bc_vec_push(p->globals_v + i, p->globals + i);
139 #if BC_ENABLE_EXTRA_MATH
140 bc_rand_push(&p->rng);
141 #endif // BC_ENABLE_EXTRA_MATH
145 * Pops globals stacks on returning from a function, or in the case of reset,
146 * pops all but one item on each global stack.
147 * @param p The program.
148 * @param reset True if all but one item on each stack should be popped, false
151 static void bc_program_popGlobals(BcProgram *p, bool reset) {
155 for (i = 0; i < BC_PROG_GLOBALS_LEN; ++i) {
156 BcVec *v = p->globals_v + i;
157 bc_vec_npop(v, reset ? v->len - 1 : 1);
158 p->globals[i] = BC_PROG_GLOBAL(v);
161 #if BC_ENABLE_EXTRA_MATH
162 bc_rand_pop(&p->rng, reset);
163 #endif // BC_ENABLE_EXTRA_MATH
167 * Derefeneces an array reference and returns a pointer to the real array.
168 * @param p The program.
169 * @param vec The reference vector.
170 * @return A pointer to the desired array.
172 static BcVec* bc_program_dereference(const BcProgram *p, BcVec *vec) {
175 size_t vidx, nidx, i = 0;
177 // We want to be sure we have a reference vector.
178 assert(vec->size == sizeof(uchar));
180 // Get the index of the vector in arrs, then the index of the original
181 // referenced vector.
182 vidx = bc_program_index(vec->v, &i);
183 nidx = bc_program_index(vec->v, &i);
185 v = bc_vec_item(bc_vec_item(&p->arrs, vidx), nidx);
187 // We want to be sure we do *not* have a reference vector.
188 assert(v->size != sizeof(uchar));
195 * Creates a BcNum from a BcBigDig and pushes onto the results stack. This is a
196 * convenience function.
197 * @param p The program.
198 * @param dig The BcBigDig to push onto the results stack.
199 * @param type The type that the pushed result should be.
201 static void bc_program_pushBigdig(BcProgram *p, BcBigDig dig, BcResultType type)
209 bc_num_createFromBigdig(&res.d.n, dig);
210 bc_vec_push(&p->results, &res);
215 size_t bc_program_addString(BcProgram *p, const char *str, size_t fidx) {
221 BC_SIG_ASSERT_LOCKED;
223 // Push an empty string on the proper vector.
224 f = bc_vec_item(&p->fns, fidx);
225 str_ptr = bc_vec_pushEmpty(&f->strs);
227 // Figure out which slab vector to use.
228 slabs = fidx == BC_PROG_MAIN || fidx == BC_PROG_READ ?
229 &vm.main_slabs : &vm.other_slabs;
231 *str_ptr = bc_slabvec_strdup(slabs, str);
233 return f->strs.len - 1;
236 size_t bc_program_search(BcProgram *p, const char *id, bool var) {
241 // Grab the right vector and map.
242 v = var ? &p->vars : &p->arrs;
243 map = var ? &p->var_map : &p->arr_map;
247 // We do an insert because the variable might not exist yet. This is because
248 // the parser calls this function. If the insert succeeds, we create a stack
249 // for the variable/array. But regardless, bc_map_insert() gives us the
250 // index of the item in i.
251 if (bc_map_insert(map, id, v->len, &i)) {
252 BcVec *temp = bc_vec_pushEmpty(v);
253 bc_array_init(temp, var);
258 return ((BcId*) bc_vec_item(map, i))->idx;
262 * Returns the correct variable or array stack for the type.
263 * @param p The program.
264 * @param idx The index of the variable or array in the variable or array
266 * @param type The type of vector to return.
267 * @return A pointer to the variable or array stack.
269 static inline BcVec* bc_program_vec(const BcProgram *p, size_t idx, BcType type)
271 const BcVec *v = (type == BC_TYPE_VAR) ? &p->vars : &p->arrs;
272 return bc_vec_item(v, idx);
276 * Returns a pointer to the BcNum corresponding to the result. There is one
277 * case, however, where this returns a pointer to a BcVec: if the type of the
278 * result is array. In that case, the pointer is casted to a pointer to BcNum,
279 * but is never used. The function that calls this expecting an array casts the
280 * pointer back. This function is called a lot and needs to be as fast as
282 * @param p The program.
283 * @param r The result whose number will be returned.
284 * @return The BcNum corresponding to the result.
286 static BcNum* bc_program_num(BcProgram *p, BcResult *r) {
291 // Windows made it an error to not initialize this, so shut it up.
292 // I don't want to do this on other platforms because this procedure
293 // is one of the most heavily-used, and eliminating the initialization
294 // is a performance win.
302 case BC_RESULT_IBASE:
303 case BC_RESULT_SCALE:
304 case BC_RESULT_OBASE:
305 #if BC_ENABLE_EXTRA_MATH
307 #endif // BC_ENABLE_EXTRA_MATH
314 case BC_RESULT_ARRAY:
315 case BC_RESULT_ARRAY_ELEM:
318 BcType type = (r->t == BC_RESULT_VAR) ? BC_TYPE_VAR : BC_TYPE_ARRAY;
320 // Get the correct variable or array vector.
321 v = bc_program_vec(p, r->d.loc.loc, type);
323 // Surprisingly enough, the hard case is *not* returning an array;
324 // it's returning an array element. This is because we have to dig
325 // deeper to get *to* the element. That's what the code inside this
326 // if statement does.
327 if (r->t == BC_RESULT_ARRAY_ELEM) {
329 size_t idx = r->d.loc.idx;
334 // If this is true, we have a reference vector, so dereference
335 // it. The reason we don't need to worry about it for returning
336 // a straight array is because we only care about references
337 // when we access elements of an array that is a reference. That
338 // is this code, so in essence, this line takes care of arrays
340 if (v->size == sizeof(uchar)) v = bc_program_dereference(p, v);
343 // We want to be sure we got a valid array of numbers.
344 assert(v->size == sizeof(BcNum));
346 // The bc spec says that if an element is accessed that does not
347 // exist, it should be preinitialized to 0. Well, if we access
348 // an element *way* out there, we have to preinitialize all
349 // elements between the current last element and the actual
353 bc_array_expand(v, bc_vm_growSize(idx, 1));
357 n = bc_vec_item(v, idx);
359 // This is either a number (for a var) or an array (for an array).
360 // Because bc_vec_top() returns a void*, we don't need to cast.
361 else n = bc_vec_top(v);
379 // We should never get here; this is taken care of earlier because a
380 // result is expected.
400 * Prepares an operand for use.
401 * @param p The program.
402 * @param r An out parameter; this is set to the pointer to the result that
404 * @param n An out parameter; this is set to the pointer to the number that
406 * @param idx The index of the result from the top of the results stack.
408 static void bc_program_operand(BcProgram *p, BcResult **r,
409 BcNum **n, size_t idx)
411 *r = bc_vec_item_rev(&p->results, idx);
414 if (BC_ERR((*r)->t == BC_RESULT_VOID)) bc_err(BC_ERR_EXEC_VOID_VAL);
417 *n = bc_program_num(p, *r);
421 * Prepares the operands of a binary operator.
422 * @param p The program.
423 * @param l An out parameter; this is set to the pointer to the result for
425 * @param ln An out parameter; this is set to the pointer to the number for
427 * @param r An out parameter; this is set to the pointer to the result for
429 * @param rn An out parameter; this is set to the pointer to the number for
431 * @param idx The starting index where the operands are in the results stack,
432 * starting from the top.
434 static void bc_program_binPrep(BcProgram *p, BcResult **l, BcNum **ln,
435 BcResult **r, BcNum **rn, size_t idx)
439 assert(p != NULL && l != NULL && ln != NULL && r != NULL && rn != NULL);
441 #ifndef BC_PROG_NO_STACK_CHECK
442 // Check the stack for dc.
444 if (BC_ERR(!BC_PROG_STACK(&p->results, idx + 2)))
445 bc_err(BC_ERR_EXEC_STACK);
447 #endif // BC_PROG_NO_STACK_CHECK
449 assert(BC_PROG_STACK(&p->results, idx + 2));
452 bc_program_operand(p, l, ln, idx + 1);
453 bc_program_operand(p, r, rn, idx);
458 // bc_program_operand() checked these for us.
459 assert(lt != BC_RESULT_VOID && (*r)->t != BC_RESULT_VOID);
462 // We run this again under these conditions in case any vector has been
463 // reallocated out from under the BcNums or arrays we had. In other words,
464 // this is to fix pointer invalidation.
465 if (lt == (*r)->t && (lt == BC_RESULT_VAR || lt == BC_RESULT_ARRAY_ELEM))
466 *ln = bc_program_num(p, *l);
468 if (BC_ERR(lt == BC_RESULT_STR)) bc_err(BC_ERR_EXEC_TYPE);
472 * Prepares the operands of a binary operator and type checks them. This is
473 * separate from bc_program_binPrep() because some places want this, others want
474 * bc_program_binPrep().
475 * @param p The program.
476 * @param l An out parameter; this is set to the pointer to the result for
478 * @param ln An out parameter; this is set to the pointer to the number for
480 * @param r An out parameter; this is set to the pointer to the result for
482 * @param rn An out parameter; this is set to the pointer to the number for
484 * @param idx The starting index where the operands are in the results stack,
485 * starting from the top.
487 static void bc_program_binOpPrep(BcProgram *p, BcResult **l, BcNum **ln,
488 BcResult **r, BcNum **rn, size_t idx)
490 bc_program_binPrep(p, l, ln, r, rn, idx);
491 bc_program_type_num(*l, *ln);
492 bc_program_type_num(*r, *rn);
496 * Prepares the operands of an assignment operator.
497 * @param p The program.
498 * @param l An out parameter; this is set to the pointer to the result for the
500 * @param ln An out parameter; this is set to the pointer to the number for the
502 * @param r An out parameter; this is set to the pointer to the result for the
504 * @param rn An out parameter; this is set to the pointer to the number for the
507 static void bc_program_assignPrep(BcProgram *p, BcResult **l, BcNum **ln,
508 BcResult **r, BcNum **rn)
510 BcResultType lt, min;
512 // This is the min non-allowable result type. dc allows strings.
513 min = BC_RESULT_TEMP - ((unsigned int) (BC_IS_BC));
515 // Prepare the operands.
516 bc_program_binPrep(p, l, ln, r, rn, 0);
520 // Typecheck the left.
521 if (BC_ERR(lt >= min && lt <= BC_RESULT_ONE)) bc_err(BC_ERR_EXEC_TYPE);
523 // Strings can be assigned to variables. We are already good if we are
524 // assigning a string.
525 bool good = ((*r)->t == BC_RESULT_STR && lt <= BC_RESULT_ARRAY_ELEM);
527 assert(BC_PROG_STR(*rn) || (*r)->t != BC_RESULT_STR);
529 // If not, type check for a number.
530 if (!good) bc_program_type_num(*r, *rn);
534 * Prepares a single operand and type checks it. This is separate from
535 * bc_program_operand() because different places want one or the other.
536 * @param p The program.
537 * @param r An out parameter; this is set to the pointer to the result that
539 * @param n An out parameter; this is set to the pointer to the number that
541 * @param idx The index of the result from the top of the results stack.
543 static void bc_program_prep(BcProgram *p, BcResult **r, BcNum **n, size_t idx) {
545 assert(p != NULL && r != NULL && n != NULL);
547 #ifndef BC_PROG_NO_STACK_CHECK
548 // Check the stack for dc.
550 if (BC_ERR(!BC_PROG_STACK(&p->results, idx + 1)))
551 bc_err(BC_ERR_EXEC_STACK);
553 #endif // BC_PROG_NO_STACK_CHECK
555 assert(BC_PROG_STACK(&p->results, idx + 1));
557 bc_program_operand(p, r, n, idx);
559 // dc does not allow strings in this case.
560 bc_program_type_num(*r, *n);
564 * Prepares and returns a clean result for the result of an operation.
565 * @param p The program.
566 * @return A clean result.
568 static BcResult* bc_program_prepResult(BcProgram *p) {
570 BcResult *res = bc_vec_pushEmpty(&p->results);
572 bc_result_clear(res);
578 * Prepares a constant for use. This parses the constant into a number and then
579 * pushes that number onto the results stack.
580 * @param p The program.
581 * @param code The bytecode vector that we will pull the index of the constant
583 * @param bgn An in/out parameter; marks the start of the index in the
584 * bytecode vector and will be updated to point to after the index.
586 static void bc_program_const(BcProgram *p, const char *code, size_t *bgn) {
588 // I lied. I actually push the result first. I can do this because the
589 // result will be popped on error. I also get the constant itself.
590 BcResult *r = bc_program_prepResult(p);
591 BcConst *c = bc_vec_item(p->consts, bc_program_index(code, bgn));
592 BcBigDig base = BC_PROG_IBASE(p);
594 // Only reparse if the base changed.
595 if (c->base != base) {
597 // Allocate if we haven't yet.
598 if (c->num.num == NULL) {
600 bc_num_init(&c->num, BC_NUM_RDX(strlen(c->val)));
604 // bc_num_parse() should only do operations that cannot fail.
605 bc_num_parse(&c->num, c->val, base);
612 bc_num_createCopy(&r->d.n, &c->num);
618 * Executes a binary operator operation.
619 * @param p The program.
620 * @param inst The instruction corresponding to the binary operator to execute.
622 static void bc_program_op(BcProgram *p, uchar inst) {
624 BcResult *opd1, *opd2, *res;
626 size_t idx = inst - BC_INST_POWER;
628 res = bc_program_prepResult(p);
630 bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2, 1);
634 // Initialize the number with enough space, using the correct
635 // BcNumBinaryOpReq function. This looks weird because it is executing an
636 // item of an array. Rest assured that item is a function.
637 bc_num_init(&res->d.n, bc_program_opReqs[idx](n1, n2, BC_PROG_SCALE(p)));
641 assert(BC_NUM_RDX_VALID(n1));
642 assert(BC_NUM_RDX_VALID(n2));
644 // Run the operation. This also executes an item of an array.
645 bc_program_ops[idx](n1, n2, &res->d.n, BC_PROG_SCALE(p));
647 bc_program_retire(p, 1, 2);
651 * Executes a read() or ? command.
652 * @param p The program.
654 static void bc_program_read(BcProgram *p) {
661 BcFunc *f = bc_vec_item(&p->fns, BC_PROG_READ);
663 // If we are already executing a read, that is an error. So look for a read
665 for (i = 0; i < p->stack.len; ++i) {
666 BcInstPtr *ip_ptr = bc_vec_item(&p->stack, i);
667 if (ip_ptr->func == BC_PROG_READ) bc_err(BC_ERR_EXEC_REC_READ);
672 // Save the filename because we are going to overwrite it.
674 is_stdin = vm.is_stdin;
676 // It is a parse error if there needs to be more than one line, so we unset
677 // this to tell the lexer to not request more. We set it back later.
680 if (!BC_PARSE_IS_INITED(&vm.read_prs, p)) {
682 // We need to parse, but we don't want to use the existing parser
683 // because it has state it needs to keep. (It could have a partial parse
684 // state.) So we create a new parser. This parser is in the BcVm struct
685 // so that it is not local, which means that a longjmp() could change
687 bc_parse_init(&vm.read_prs, p, BC_PROG_READ);
689 // We need a separate input buffer; that's why it is also in the BcVm
691 bc_vec_init(&vm.read_buf, sizeof(char), BC_DTOR_NONE);
693 // This needs to be updated because the parser could have been used
695 else bc_parse_updateFunc(&vm.read_prs, BC_PROG_READ);
697 BC_SETJMP_LOCKED(exec_err);
701 // Set up the lexer and the read function.
702 bc_lex_file(&vm.read_prs.l, bc_program_stdin_name);
703 bc_vec_popAll(&f->code);
706 if (!BC_R) s = bc_read_line(&vm.read_buf, "");
707 else s = bc_read_line(&vm.read_buf, BC_IS_BC ? "read> " : "?> ");
709 // We should *not* have run into EOF.
710 if (s == BC_STATUS_EOF) bc_err(BC_ERR_EXEC_READ_EXPR);
712 // Parse *one* expression.
713 bc_parse_text(&vm.read_prs, vm.read_buf.v, false);
714 vm.expr(&vm.read_prs, BC_PARSE_NOREAD | BC_PARSE_NEEDVAL);
716 // We *must* have a valid expression. A semicolon cannot end an expression,
718 if (BC_ERR(vm.read_prs.l.t != BC_LEX_NLINE &&
719 vm.read_prs.l.t != BC_LEX_EOF))
721 bc_err(BC_ERR_EXEC_READ_EXPR);
725 // Push on the globals stack if necessary.
726 if (BC_G) bc_program_prepGlobals(p);
729 // Set up a new BcInstPtr.
730 ip.func = BC_PROG_READ;
732 ip.len = p->results.len;
734 // Update this pointer, just in case.
735 f = bc_vec_item(&p->fns, BC_PROG_READ);
737 // We want a return instruction to simplify things.
738 bc_vec_pushByte(&f->code, vm.read_ret);
739 bc_vec_push(&p->stack, &ip);
742 // We need a new tail call entry for dc.
745 bc_vec_push(&p->tail_calls, &temp);
751 vm.is_stdin = is_stdin;
756 #if BC_ENABLE_EXTRA_MATH
760 * @param p The program.
762 static void bc_program_rand(BcProgram *p) {
764 BcRand rand = bc_rand_int(&p->rng);
766 bc_program_pushBigdig(p, (BcBigDig) rand, BC_RESULT_TEMP);
769 // This is just to ensure that the generated number is correct. I also use
770 // braces because I declare every local at the top of the scope.
772 BcResult *r = bc_vec_top(&p->results);
773 assert(BC_NUM_RDX_VALID_NP(r->d.n));
777 #endif // BC_ENABLE_EXTRA_MATH
780 * Prints a series of characters, without escapes.
781 * @param str The string (series of characters).
783 static void bc_program_printChars(const char *str) {
786 size_t len = vm.nchars + strlen(str);
788 bc_file_puts(&vm.fout, bc_flush_save, str);
790 // We need to update the number of characters, so we find the last newline
791 // and set the characters accordingly.
792 nl = strrchr(str, '\n');
794 if (nl != NULL) len = strlen(nl + 1);
796 vm.nchars = len > UINT16_MAX ? UINT16_MAX : (uint16_t) len;
800 * Prints a string with escapes.
801 * @param str The string.
803 static void bc_program_printString(const char *restrict str) {
805 size_t i, len = strlen(str);
808 // This is to ensure a nul byte is printed for dc's stream operation.
809 if (!len && BC_IS_DC) {
810 bc_vm_putchar('\0', bc_flush_save);
815 // Loop over the characters, processing escapes and printing the rest.
816 for (i = 0; i < len; ++i) {
820 // If we have an escape...
821 if (c == '\\' && i != len - 1) {
825 // Get the escape character and its companion.
827 ptr = strchr(bc_program_esc_chars, c);
829 // If we have a companion character...
832 // We need to specially handle a newline.
833 if (c == 'n') vm.nchars = UINT16_MAX;
835 // Grab the actual character.
836 c = bc_program_esc_seqs[(size_t) (ptr - bc_program_esc_chars)];
839 // Just print the backslash if there is no companion character.
840 // The following character will be printed later after the outer
842 bc_vm_putchar('\\', bc_flush_save);
846 bc_vm_putchar(c, bc_flush_save);
851 * Executes a print. This function handles all printing except streaming.
852 * @param p The program.
853 * @param inst The instruction for the type of print we are doing.
854 * @param idx The index of the result that we are printing.
856 static void bc_program_print(BcProgram *p, uchar inst, size_t idx) {
861 bool pop = (inst != BC_INST_PRINT);
865 #ifndef BC_PROG_NO_STACK_CHECK
867 if (BC_ERR(!BC_PROG_STACK(&p->results, idx + 1)))
868 bc_err(BC_ERR_EXEC_STACK);
870 #endif // BC_PROG_NO_STACK_CHECK
872 assert(BC_PROG_STACK(&p->results, idx + 1));
874 r = bc_vec_item_rev(&p->results, idx);
877 // If we have a void value, that's not necessarily an error. It is if pop is
878 // true because that means that we are executing a print statement, but
879 // attempting to do a print on a lone void value is allowed because that's
880 // exactly how we want void values used.
881 if (r->t == BC_RESULT_VOID) {
882 if (BC_ERR(pop)) bc_err(BC_ERR_EXEC_VOID_VAL);
883 bc_vec_pop(&p->results);
888 n = bc_program_num(p, r);
890 // If we have a number...
891 if (BC_PROG_NUM(r, n)) {
894 assert(inst != BC_INST_PRINT_STR);
898 bc_num_print(n, BC_PROG_OBASE(p), !pop);
901 // Need to store the number in last.
902 if (BC_IS_BC) bc_num_copy(&p->last, n);
907 // We want to flush any stuff in the stdout buffer first.
908 bc_file_flush(&vm.fout, bc_flush_save);
909 str = bc_program_string(p, n);
912 if (inst == BC_INST_PRINT_STR) bc_program_printChars(str);
916 bc_program_printString(str);
918 // Need to print a newline only in this case.
919 if (inst == BC_INST_PRINT)
920 bc_vm_putchar('\n', bc_flush_err);
925 if (BC_IS_BC || pop) bc_vec_pop(&p->results);
928 void bc_program_negate(BcResult *r, BcNum *n) {
929 bc_num_copy(&r->d.n, n);
930 if (BC_NUM_NONZERO(&r->d.n)) BC_NUM_NEG_TGL_NP(r->d.n);
933 void bc_program_not(BcResult *r, BcNum *n) {
934 if (!bc_num_cmpZero(n)) bc_num_one(&r->d.n);
937 #if BC_ENABLE_EXTRA_MATH
938 void bc_program_trunc(BcResult *r, BcNum *n) {
939 bc_num_copy(&r->d.n, n);
940 bc_num_truncate(&r->d.n, n->scale);
942 #endif // BC_ENABLE_EXTRA_MATH
945 * Runs a unary operation.
946 * @param p The program.
947 * @param inst The unary operation.
949 static void bc_program_unary(BcProgram *p, uchar inst) {
954 res = bc_program_prepResult(p);
956 bc_program_prep(p, &ptr, &num, 1);
960 bc_num_init(&res->d.n, num->len);
964 // This calls a function that is in an array.
965 bc_program_unarys[inst - BC_INST_NEG](res, num);
966 bc_program_retire(p, 1, 1);
970 * Executes a logical operator.
971 * @param p The program.
972 * @param inst The operator.
974 static void bc_program_logical(BcProgram *p, uchar inst) {
976 BcResult *opd1, *opd2, *res;
981 res = bc_program_prepResult(p);
983 // All logical operators (except boolean not, which is taken care of by
984 // bc_program_unary()), are binary operators.
985 bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2, 1);
987 // Boolean and and or are not short circuiting. This is why; they can be
988 // implemented much easier this way.
989 if (inst == BC_INST_BOOL_AND)
990 cond = (bc_num_cmpZero(n1) && bc_num_cmpZero(n2));
991 else if (inst == BC_INST_BOOL_OR)
992 cond = (bc_num_cmpZero(n1) || bc_num_cmpZero(n2));
995 // We have a relational operator, so do a comparison.
996 cmp = bc_num_cmp(n1, n2);
1000 case BC_INST_REL_EQ:
1006 case BC_INST_REL_LE:
1012 case BC_INST_REL_GE:
1018 case BC_INST_REL_NE:
1024 case BC_INST_REL_LT:
1030 case BC_INST_REL_GT:
1038 // There is a bug if we get here.
1047 bc_num_init(&res->d.n, BC_NUM_DEF_SIZE);
1051 if (cond) bc_num_one(&res->d.n);
1053 bc_program_retire(p, 1, 2);
1057 * Assigns a string to a variable.
1058 * @param p The program.
1059 * @param num The location of the string as a BcNum.
1060 * @param v The stack for the variable.
1061 * @param push Whether to push the string or not. To push means to move the
1062 * string from the results stack and push it onto the variable
1065 static void bc_program_assignStr(BcProgram *p, BcNum *num, BcVec *v, bool push)
1069 assert(BC_PROG_STACK(&p->results, 1 + !push));
1070 assert(num != NULL && num->num == NULL && num->cap == 0);
1072 // If we are not pushing onto the variable stack, we need to replace the
1073 // top of the variable stack.
1074 if (!push) bc_vec_pop(v);
1076 bc_vec_npop(&p->results, 1 + !push);
1078 n = bc_vec_pushEmpty(v);
1080 // We can just copy because the num should not have allocated anything.
1081 memcpy(n, num, sizeof(BcNum));
1085 * Copies a value to a variable. This is used for storing in dc as well as to
1086 * set function parameters to arguments in bc.
1087 * @param p The program.
1088 * @param idx The index of the variable or array to copy to.
1089 * @param t The type to copy to. This could be a variable or an array.
1090 * @param last Whether to grab the last item on the variable stack or not (for
1091 * bc function parameters). This is important because if a new
1092 * value has been pushed to the variable already, we need to grab
1093 * the value pushed before. This happens when you have a parameter
1094 * named something like "x", and a variable "x" is passed to
1095 * another parameter.
1097 static void bc_program_copyToVar(BcProgram *p, size_t idx, BcType t, bool last)
1099 BcResult *ptr = NULL, r;
1102 bool var = (t == BC_TYPE_VAR);
1105 // Check the stack for dc.
1107 if (BC_ERR(!BC_PROG_STACK(&p->results, 1))) bc_err(BC_ERR_EXEC_STACK);
1111 assert(BC_PROG_STACK(&p->results, 1));
1113 bc_program_operand(p, &ptr, &n, 0);
1116 // Get the variable for a bc function call.
1119 // Type match the result.
1120 bc_program_type_match(ptr, t);
1122 // Get the variable or array, taking care to get the real item. We take
1123 // care of last with arrays later.
1125 n = bc_vec_item_rev(bc_program_vec(p, ptr->d.loc.loc, t), 1);
1127 #endif // BC_ENABLED
1129 vec = bc_program_vec(p, idx, t);
1131 // We can shortcut in dc if it's assigning a string by using
1132 // bc_program_assignStr().
1133 if (ptr->t == BC_RESULT_STR) {
1135 assert(BC_PROG_STR(n));
1137 if (BC_ERR(!var)) bc_err(BC_ERR_EXEC_TYPE);
1139 bc_program_assignStr(p, n, vec, true);
1146 // Just create and copy for a normal variable.
1148 if (BC_PROG_STR(n)) memcpy(&r.d.n, n, sizeof(BcNum));
1149 else bc_num_createCopy(&r.d.n, n);
1153 // If we get here, we are handling an array. This is one place we need
1154 // to cast the number from bc_program_num() to a vector.
1155 BcVec *v = (BcVec*) n, *rv = &r.d.v;
1164 // We need to figure out if the parameter is a reference or not and
1165 // construct the reference vector, if necessary. So this gets the
1166 // parent stack for the array.
1167 parent = bc_program_vec(p, ptr->d.loc.loc, t);
1168 assert(parent != NULL);
1170 // This takes care of last for arrays. Mostly.
1171 if (!last) v = bc_vec_item_rev(parent, !last);
1174 // True if we are using a reference.
1175 ref = (v->size == sizeof(BcNum) && t == BC_TYPE_REF);
1177 // True if we already have a reference vector. This is slightly
1178 // (okay, a lot; it just doesn't look that way) different from
1179 // above. The above means that we need to construct a reference
1180 // vector, whereas this means that we have one and we might have to
1181 // *dereference* it.
1182 ref_size = (v->size == sizeof(uchar));
1184 // If we *should* have a reference.
1185 if (ref || (ref_size && t == BC_TYPE_REF)) {
1187 // Create a new reference vector.
1188 bc_vec_init(rv, sizeof(uchar), BC_DTOR_NONE);
1190 // If this is true, then we need to construct a reference.
1193 assert(parent->len >= (size_t) (!last + 1));
1195 // Make sure the pointer was not invalidated.
1196 vec = bc_program_vec(p, idx, t);
1198 // Push the indices onto the reference vector. This takes
1199 // care of last; it ensures the reference goes to the right
1201 bc_vec_pushIndex(rv, ptr->d.loc.loc);
1202 bc_vec_pushIndex(rv, parent->len - !last - 1);
1204 // If we get here, we are copying a ref to a ref. Just push a
1205 // copy of all of the bytes.
1206 else bc_vec_npush(rv, v->len * sizeof(uchar), v->v);
1208 // Push the reference vector onto the array stack and pop the
1210 bc_vec_push(vec, &r.d);
1211 bc_vec_pop(&p->results);
1213 // We need to return early to avoid executing code that we must
1218 // If we get here, we have a reference, but we need an array, so
1219 // dereference the array.
1220 else if (ref_size && t != BC_TYPE_REF)
1221 v = bc_program_dereference(p, v);
1223 #endif // BC_ENABLED
1225 // If we get here, we need to copy the array because in bc, all
1226 // arguments are passed by value. Yes, this is expensive.
1227 bc_array_init(rv, true);
1228 bc_array_copy(rv, v);
1231 // Push the vector onto the array stack and pop the source.
1232 bc_vec_push(vec, &r.d);
1233 bc_vec_pop(&p->results);
1239 * Executes an assignment operator.
1240 * @param p The program.
1241 * @param inst The assignment operator to execute.
1243 static void bc_program_assign(BcProgram *p, uchar inst) {
1245 // The local use_val is true when the assigned value needs to be copied.
1246 BcResult *left, *right, res;
1248 bool ob, sc, use_val = BC_INST_USE_VAL(inst);
1250 bc_program_assignPrep(p, &left, &l, &right, &r);
1252 // Assigning to a string should be impossible simply because of the parse.
1253 assert(left->t != BC_RESULT_STR);
1255 // If we are assigning a string...
1256 if (right->t == BC_RESULT_STR) {
1258 assert(BC_PROG_STR(r));
1261 if (inst != BC_INST_ASSIGN && inst != BC_INST_ASSIGN_NO_VAL)
1262 bc_err(BC_ERR_EXEC_TYPE);
1263 #endif // BC_ENABLED
1265 // If we are assigning to an array element...
1266 if (left->t == BC_RESULT_ARRAY_ELEM) {
1270 // We need to free the number and clear it.
1273 memcpy(l, r, sizeof(BcNum));
1275 // Now we can pop the results.
1276 bc_vec_npop(&p->results, 2);
1282 // If we get here, we are assigning to a variable, which we can use
1283 // bc_program_assignStr() for.
1284 BcVec *v = bc_program_vec(p, left->d.loc.loc, BC_TYPE_VAR);
1285 bc_program_assignStr(p, r, v, false);
1290 // If this is true, the value is going to be used again, so we want to
1291 // push a temporary with the string.
1292 if (inst == BC_INST_ASSIGN) {
1293 res.t = BC_RESULT_STR;
1294 memcpy(&res.d.n, r, sizeof(BcNum));
1295 bc_vec_push(&p->results, &res);
1298 #endif // BC_ENABLED
1300 // By using bc_program_assignStr(), we short-circuited this, so return.
1304 // If we have a normal assignment operator, not a math one...
1305 if (BC_INST_IS_ASSIGN(inst)) {
1307 // Assigning to a variable that has a string here is fine because there
1308 // is no math done on it.
1310 // BC_RESULT_TEMP, BC_RESULT_IBASE, BC_RESULT_OBASE, BC_RESULT_SCALE,
1311 // and BC_RESULT_SEED all have temporary copies. Because that's the
1312 // case, we can free the left and just move the value over. We set the
1313 // type of right to BC_RESULT_ZERO in order to prevent it from being
1314 // freed. We also don't have to worry about BC_RESULT_STR because it's
1315 // take care of above.
1316 if (right->t == BC_RESULT_TEMP || right->t >= BC_RESULT_IBASE) {
1321 memcpy(l, r, sizeof(BcNum));
1322 right->t = BC_RESULT_ZERO;
1327 else bc_num_copy(l, r);
1332 // If we get here, we are doing a math assignment (+=, -=, etc.). So
1333 // we need to prepare for a binary operator.
1334 BcBigDig scale = BC_PROG_SCALE(p);
1336 // At this point, the left side could still be a string because it could
1337 // be a variable that has the string. If that's the case, we have a type
1339 if (BC_PROG_STR(l)) bc_err(BC_ERR_EXEC_TYPE);
1341 // Get the right type of assignment operator, whether val is used or
1342 // NO_VAL for performance.
1344 inst -= (BC_INST_ASSIGN_POWER_NO_VAL - BC_INST_ASSIGN_POWER);
1346 assert(BC_NUM_RDX_VALID(l));
1347 assert(BC_NUM_RDX_VALID(r));
1349 // Run the actual operation. We do not need worry about reallocating l
1350 // because bc_num_binary() does that behind the scenes for us.
1351 bc_program_ops[inst - BC_INST_ASSIGN_POWER](l, r, l, scale);
1353 #endif // BC_ENABLED
1355 ob = (left->t == BC_RESULT_OBASE);
1356 sc = (left->t == BC_RESULT_SCALE);
1358 // The globals need special handling, especially the non-seed ones. The
1359 // first part of the if statement handles them.
1360 if (ob || sc || left->t == BC_RESULT_IBASE) {
1363 BcBigDig *ptr, *ptr_t, val, max, min;
1365 // Get the actual value.
1366 val = bc_num_bigdig(l);
1368 // Scale needs handling separate from ibase and obase.
1371 // Set the min and max.
1373 max = vm.maxes[BC_PROG_GLOBALS_SCALE];
1375 // Get a pointer to the stack and to the current value.
1376 v = p->globals_v + BC_PROG_GLOBALS_SCALE;
1377 ptr_t = p->globals + BC_PROG_GLOBALS_SCALE;
1381 // Set the min and max.
1382 min = BC_NUM_MIN_BASE;
1383 if (BC_ENABLE_EXTRA_MATH && ob && (BC_IS_DC || !BC_IS_POSIX))
1385 max = vm.maxes[ob + BC_PROG_GLOBALS_IBASE];
1387 // Get a pointer to the stack and to the current value.
1388 v = p->globals_v + BC_PROG_GLOBALS_IBASE + ob;
1389 ptr_t = p->globals + BC_PROG_GLOBALS_IBASE + ob;
1393 if (BC_ERR(val > max || val < min)) {
1395 // This grabs the right error.
1396 BcErr e = left->t - BC_RESULT_IBASE + BC_ERR_EXEC_IBASE;
1398 bc_verr(e, min, max);
1401 // Set the top of the stack and the actual global value.
1402 ptr = bc_vec_top(v);
1406 #if BC_ENABLE_EXTRA_MATH
1407 // To assign to steed, let bc_num_rng() do its magic.
1408 else if (left->t == BC_RESULT_SEED) bc_num_rng(l, &p->rng);
1409 #endif // BC_ENABLE_EXTRA_MATH
1413 // If we needed to use the value, then we need to copy it. Otherwise, we can
1414 // pop indiscriminately. Oh, and the copy should be a BC_RESULT_TEMP.
1416 bc_num_createCopy(&res.d.n, l);
1417 res.t = BC_RESULT_TEMP;
1418 bc_vec_npop(&p->results, 2);
1419 bc_vec_push(&p->results, &res);
1421 else bc_vec_npop(&p->results, 2);
1427 * Pushes a variable's value onto the results stack.
1428 * @param p The program.
1429 * @param code The bytecode vector to pull the variable's index out of.
1430 * @param bgn An in/out parameter; the start of the index in the bytecode
1431 * vector, and will be updated to point after the index on return.
1432 * @param pop True if the variable's value should be popped off its stack.
1433 * This is only used in dc.
1434 * @param copy True if the variable's value should be copied to the results
1435 * stack. This is only used in dc.
1437 static void bc_program_pushVar(BcProgram *p, const char *restrict code,
1438 size_t *restrict bgn, bool pop, bool copy)
1441 size_t idx = bc_program_index(code, bgn);
1443 // Set the result appropriately.
1444 r.t = BC_RESULT_VAR;
1448 // If this condition is true, then we have the hard case, where we have to
1449 // adjust dc registers.
1450 if (BC_IS_DC && (pop || copy)) {
1452 // Get the stack for the variable and the number at the top.
1453 BcVec *v = bc_program_vec(p, idx, BC_TYPE_VAR);
1454 BcNum *num = bc_vec_top(v);
1456 // Ensure there are enough elements on the stack.
1457 if (BC_ERR(!BC_PROG_STACK(v, 2 - copy))) {
1458 const char *name = bc_map_name(&p->var_map, idx);
1459 bc_verr(BC_ERR_EXEC_STACK_REGISTER, name);
1462 assert(BC_PROG_STACK(v, 2 - copy));
1464 // If the top of the stack is actually a number...
1465 if (!BC_PROG_STR(num)) {
1469 // Create a copy to go onto the results stack as appropriate.
1470 r.t = BC_RESULT_TEMP;
1471 bc_num_createCopy(&r.d.n, num);
1473 // If we are not actually copying, we need to do a replace, so pop.
1474 if (!copy) bc_vec_pop(v);
1476 bc_vec_push(&p->results, &r);
1483 // Set the string result. We can just memcpy because all of the
1484 // fields in the num should be cleared.
1485 memcpy(&r.d.n, num, sizeof(BcNum));
1486 r.t = BC_RESULT_STR;
1489 // If we are not actually copying, we need to do a replace, so pop.
1490 if (!copy) bc_vec_pop(v);
1492 #endif // DC_ENABLED
1494 bc_vec_push(&p->results, &r);
1498 * Pushes an array or an array element onto the results stack.
1499 * @param p The program.
1500 * @param code The bytecode vector to pull the variable's index out of.
1501 * @param bgn An in/out parameter; the start of the index in the bytecode
1502 * vector, and will be updated to point after the index on return.
1503 * @param inst The instruction; whether to push an array or an array element.
1505 static void bc_program_pushArray(BcProgram *p, const char *restrict code,
1506 size_t *restrict bgn, uchar inst)
1508 BcResult r, *operand;
1512 // Get the index of the array.
1513 r.d.loc.loc = bc_program_index(code, bgn);
1515 // Doing an array is easy; just set the result type and finish.
1516 if (inst == BC_INST_ARRAY) {
1517 r.t = BC_RESULT_ARRAY;
1518 bc_vec_push(&p->results, &r);
1522 // Grab the top element of the results stack for the array index.
1523 bc_program_prep(p, &operand, &num, 0);
1524 temp = bc_num_bigdig(num);
1527 r.t = BC_RESULT_ARRAY_ELEM;
1528 r.d.loc.idx = (size_t) temp;
1532 // Pop the index and push the element.
1533 bc_vec_pop(&p->results);
1534 bc_vec_push(&p->results, &r);
1542 * Executes an increment or decrement operator. This only handles postfix
1543 * inc/dec because the parser translates prefix inc/dec into an assignment where
1544 * the value is used.
1545 * @param p The program.
1546 * @param inst The instruction; whether to do an increment or decrement.
1548 static void bc_program_incdec(BcProgram *p, uchar inst) {
1550 BcResult *ptr, res, copy;
1554 bc_program_prep(p, &ptr, &num, 0);
1558 // We need a copy from *before* the operation.
1559 copy.t = BC_RESULT_TEMP;
1560 bc_num_createCopy(©.d.n, num);
1562 BC_SETJMP_LOCKED(exit);
1566 // Create the proper assignment.
1567 res.t = BC_RESULT_ONE;
1568 inst2 = BC_INST_ASSIGN_PLUS_NO_VAL + (inst & 0x01);
1570 bc_vec_push(&p->results, &res);
1571 bc_program_assign(p, inst2);
1575 bc_vec_push(&p->results, ©);
1581 // No need to free the copy here because we pushed it onto the stack.
1586 bc_num_free(©.d.n);
1591 * Executes a function call for bc.
1592 * @param p The program.
1593 * @param code The bytecode vector to pull the number of arguments and the
1594 * function index out of.
1595 * @param bgn An in/out parameter; the start of the indices in the bytecode
1596 * vector, and will be updated to point after the indices on
1599 static void bc_program_call(BcProgram *p, const char *restrict code,
1600 size_t *restrict bgn)
1609 // Pull the number of arguments out of the bytecode vector.
1610 nargs = bc_program_index(code, bgn);
1612 // Set up instruction pointer.
1614 ip.func = bc_program_index(code, bgn);
1615 f = bc_vec_item(&p->fns, ip.func);
1618 if (BC_ERR(!f->code.len)) bc_verr(BC_ERR_EXEC_UNDEF_FUNC, f->name);
1619 if (BC_ERR(nargs != f->nparams))
1620 bc_verr(BC_ERR_EXEC_PARAMS, f->nparams, nargs);
1622 // Set the length of the results stack. We discount the argument, of course.
1623 ip.len = p->results.len - nargs;
1625 assert(BC_PROG_STACK(&p->results, nargs));
1627 // Prepare the globals' stacks.
1628 if (BC_G) bc_program_prepGlobals(p);
1630 // Push the arguments onto the stacks of their respective parameters.
1631 for (i = 0; i < nargs; ++i) {
1636 arg = bc_vec_top(&p->results);
1637 if (BC_ERR(arg->t == BC_RESULT_VOID)) bc_err(BC_ERR_EXEC_VOID_VAL);
1639 // Get the corresponding parameter.
1640 a = bc_vec_item(&f->autos, nargs - 1 - i);
1642 // If I have already pushed to a var, I need to make sure I
1643 // get the previous version, not the already pushed one. This condition
1644 // must be true for that to even be possible.
1645 if (arg->t == BC_RESULT_VAR || arg->t == BC_RESULT_ARRAY) {
1647 // Loop through all of the previous parameters.
1648 for (j = 0; j < i && last; ++j) {
1650 BcAuto *aptr = bc_vec_item(&f->autos, nargs - 1 - j);
1652 // This condition is true if there is a previous parameter with
1653 // the same name *and* type because variables and arrays do not
1654 // interfere with each other.
1655 last = (arg->d.loc.loc != aptr->idx ||
1656 (!aptr->type) != (arg->t == BC_RESULT_VAR));
1660 // Actually push the value onto the parameter's stack.
1661 bc_program_copyToVar(p, a->idx, a->type, last);
1666 // Push zeroes onto the stacks of the auto variables.
1667 for (; i < f->autos.len; ++i) {
1669 // Get the auto and its stack.
1670 a = bc_vec_item(&f->autos, i);
1671 v = bc_program_vec(p, a->idx, a->type);
1673 // If a variable, just push a 0; otherwise, push an array.
1674 if (a->type == BC_TYPE_VAR) {
1675 BcNum *n = bc_vec_pushEmpty(v);
1676 bc_num_init(n, BC_NUM_DEF_SIZE);
1682 assert(a->type == BC_TYPE_ARRAY);
1684 v2 = bc_vec_pushEmpty(v);
1685 bc_array_init(v2, true);
1689 // Push the instruction pointer onto the execution stack.
1690 bc_vec_push(&p->stack, &ip);
1696 * Executes a return instruction.
1697 * @param p The program.
1698 * @param inst The return instruction. bc can return void, and we need to know
1701 static void bc_program_return(BcProgram *p, uchar inst) {
1708 // Get the instruction pointer.
1709 ip = bc_vec_top(&p->stack);
1711 // Get the difference between the actual number of results and the number of
1712 // results the caller expects.
1713 nresults = p->results.len - ip->len;
1715 // If this isn't true, there was a missing call somewhere.
1716 assert(BC_PROG_STACK(&p->stack, 2));
1718 // If this isn't true, the parser screwed by giving us no value when we
1719 // expected one, or giving us a value when we expected none.
1720 assert(BC_PROG_STACK(&p->results, ip->len + (inst == BC_INST_RET)));
1722 // Get the function we are returning from.
1723 f = bc_vec_item(&p->fns, ip->func);
1725 res = bc_program_prepResult(p);
1727 // If we are returning normally...
1728 if (inst == BC_INST_RET) {
1733 // Prepare and copy the return value.
1734 bc_program_operand(p, &operand, &num, 1);
1736 if (BC_PROG_STR(num)) {
1738 // We need to set this because otherwise, it will be a
1739 // BC_RESULT_TEMP, and BC_RESULT_TEMP needs an actual number to make
1740 // it easier to do type checking.
1741 res->t = BC_RESULT_STR;
1743 memcpy(&res->d.n, num, sizeof(BcNum));
1749 bc_num_createCopy(&res->d.n, num);
1752 // Void is easy; set the result.
1753 else if (inst == BC_INST_RET_VOID) res->t = BC_RESULT_VOID;
1758 // If we get here, the instruction is for returning a zero, so do that.
1759 bc_num_init(&res->d.n, BC_NUM_DEF_SIZE);
1764 // We need to pop items off of the stacks of arguments and autos as well.
1765 for (i = 0; i < f->autos.len; ++i) {
1767 BcAuto *a = bc_vec_item(&f->autos, i);
1768 BcVec *v = bc_program_vec(p, a->idx, a->type);
1773 // When we retire, pop all of the unused results.
1774 bc_program_retire(p, 1, nresults);
1776 // Pop the globals, if necessary.
1777 if (BC_G) bc_program_popGlobals(p, false);
1779 // Pop the stack. This is what causes the function to actually "return."
1780 bc_vec_pop(&p->stack);
1782 #endif // BC_ENABLED
1785 * Executes a builtin function.
1786 * @param p The program.
1787 * @param inst The builtin to execute.
1789 static void bc_program_builtin(BcProgram *p, uchar inst) {
1791 BcResult *opd, *res;
1793 bool len = (inst == BC_INST_LENGTH);
1795 // Ensure we have a valid builtin.
1796 #if BC_ENABLE_EXTRA_MATH
1797 assert(inst >= BC_INST_LENGTH && inst <= BC_INST_IRAND);
1798 #else // BC_ENABLE_EXTRA_MATH
1799 assert(inst >= BC_INST_LENGTH && inst <= BC_INST_ABS);
1800 #endif // BC_ENABLE_EXTRA_MATH
1802 #ifndef BC_PROG_NO_STACK_CHECK
1803 // Check stack for dc.
1804 if (BC_IS_DC && BC_ERR(!BC_PROG_STACK(&p->results, 1)))
1805 bc_err(BC_ERR_EXEC_STACK);
1806 #endif // BC_PROG_NO_STACK_CHECK
1808 assert(BC_PROG_STACK(&p->results, 1));
1810 res = bc_program_prepResult(p);
1812 bc_program_operand(p, &opd, &num, 1);
1814 assert(num != NULL);
1816 // We need to ensure that strings and arrays aren't passed to most builtins.
1817 // The scale function can take strings in dc.
1818 if (!len && (inst != BC_INST_SCALE_FUNC || BC_IS_BC))
1819 bc_program_type_num(opd, num);
1821 // Square root is easy.
1822 if (inst == BC_INST_SQRT) bc_num_sqrt(num, &res->d.n, BC_PROG_SCALE(p));
1824 // Absolute value is easy.
1825 else if (inst == BC_INST_ABS) {
1829 bc_num_createCopy(&res->d.n, num);
1833 BC_NUM_NEG_CLR_NP(res->d.n);
1835 #if BC_ENABLE_EXTRA_MATH
1837 else if (inst == BC_INST_IRAND) {
1841 bc_num_init(&res->d.n, num->len - BC_NUM_RDX_VAL(num));
1845 bc_num_irand(num, &res->d.n, &p->rng);
1847 #endif // BC_ENABLE_EXTRA_MATH
1849 // Everything else is...not easy.
1854 // Well, scale() is easy, but length() is not.
1857 // If we are bc and we have an array...
1858 if (opd->t == BC_RESULT_ARRAY) {
1860 // Yes, this is one place where we need to cast the number from
1861 // bc_program_num() to a vector.
1862 BcVec *v = (BcVec*) num;
1865 // Dereference the array, if necessary.
1866 if (BC_IS_BC && v->size == sizeof(uchar))
1867 v = bc_program_dereference(p, v);
1868 #endif // BC_ENABLED
1870 assert(v->size == sizeof(BcNum));
1872 val = (BcBigDig) v->len;
1876 // If the item is a string...
1877 if (!BC_PROG_NUM(opd, num)) {
1881 // Get the string, then get the length.
1882 str = bc_program_string(p, num);
1883 val = (BcBigDig) strlen(str);
1887 // Calculate the length of the number.
1888 val = (BcBigDig) bc_num_len(num);
1892 // Like I said; scale() is actually easy. It just also needs the integer
1893 // conversion that length() does.
1894 else if (BC_IS_BC || BC_PROG_NUM(opd, num))
1895 val = (BcBigDig) bc_num_scale(num);
1899 // Create the result.
1900 bc_num_createFromBigdig(&res->d.n, val);
1905 bc_program_retire(p, 1, 1);
1909 * Executes a divmod.
1910 * @param p The program.
1912 static void bc_program_divmod(BcProgram *p) {
1914 BcResult *opd1, *opd2, *res, *res2;
1918 // We grow first to avoid pointer invalidation.
1919 bc_vec_grow(&p->results, 2);
1921 // We don't need to update the pointer because
1922 // the capacity is enough due to the line above.
1923 res2 = bc_program_prepResult(p);
1924 res = bc_program_prepResult(p);
1926 // Prepare the operands.
1927 bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2, 2);
1929 req = bc_num_mulReq(n1, n2, BC_PROG_SCALE(p));
1933 // Initialize the results.
1934 bc_num_init(&res->d.n, req);
1935 bc_num_init(&res2->d.n, req);
1940 bc_num_divmod(n1, n2, &res2->d.n, &res->d.n, BC_PROG_SCALE(p));
1942 bc_program_retire(p, 2, 2);
1946 * Executes modular exponentiation.
1947 * @param p The program.
1949 static void bc_program_modexp(BcProgram *p) {
1951 BcResult *r1, *r2, *r3, *res;
1952 BcNum *n1, *n2, *n3;
1957 if (BC_IS_DC && BC_ERR(!BC_PROG_STACK(&p->results, 3)))
1958 bc_err(BC_ERR_EXEC_STACK);
1960 #endif // DC_ENABLED
1962 assert(BC_PROG_STACK(&p->results, 3));
1964 res = bc_program_prepResult(p);
1966 // Get the first operand and typecheck.
1967 bc_program_operand(p, &r1, &n1, 3);
1968 bc_program_type_num(r1, n1);
1970 // Get the last two operands.
1971 bc_program_binOpPrep(p, &r2, &n2, &r3, &n3, 1);
1973 // Make sure that the values have their pointers updated, if necessary.
1974 // Only array elements are possible because this is dc.
1975 if (r1->t == BC_RESULT_ARRAY_ELEM && (r1->t == r2->t || r1->t == r3->t))
1976 n1 = bc_program_num(p, r1);
1980 bc_num_init(&res->d.n, n3->len);
1984 bc_num_modexp(n1, n2, n3, &res->d.n);
1986 bc_program_retire(p, 1, 3);
1990 * Asciifies a number for dc. This is a helper for bc_program_asciify().
1991 * @param p The program.
1992 * @param n The number to asciify.
1994 static uchar bc_program_asciifyNum(BcProgram *p, BcNum *n) {
2000 // This is entirely to satisfy a useless scan-build error.
2010 bc_num_createCopy(&num, n);
2014 // We want to clear the scale and sign for easy mod later.
2015 bc_num_truncate(&num, num.scale);
2016 BC_NUM_NEG_CLR_NP(num);
2018 // This is guaranteed to not have a divide by 0
2019 // because strmb is equal to 256.
2020 bc_num_mod(&num, &p->strmb, &num, 0);
2022 // This is also guaranteed to not error because num is in the range
2023 // [0, UCHAR_MAX], which is definitely in range for a BcBigDig. And
2024 // it is not negative.
2025 val = bc_num_bigdig2(&num);
2035 * Executes the "asciify" command in dc.
2036 * @param p The program.
2037 * @param fidx The index of the current function.
2039 static void bc_program_asciify(BcProgram *p, size_t fidx) {
2048 if (BC_ERR(!BC_PROG_STACK(&p->results, 1))) bc_err(BC_ERR_EXEC_STACK);
2050 assert(BC_PROG_STACK(&p->results, 1));
2052 // Get the top of the results stack.
2053 bc_program_operand(p, &r, &n, 0);
2058 if (BC_PROG_NUM(r, n)) c = bc_program_asciifyNum(p, n);
2061 // Get the string itself, then the first character.
2062 str2 = bc_program_string(p, n);
2063 c = (uchar) str2[0];
2066 // Fill the resulting string.
2070 // Add the string to the data structures.
2072 idx = bc_program_addString(p, str, fidx);
2076 res.t = BC_RESULT_STR;
2077 bc_num_clear(&res.d.n);
2079 res.d.n.scale = idx;
2082 bc_vec_pop(&p->results);
2083 bc_vec_push(&p->results, &res);
2087 * Streams a number or a string to stdout.
2088 * @param p The program.
2090 static void bc_program_printStream(BcProgram *p) {
2096 if (BC_ERR(!BC_PROG_STACK(&p->results, 1))) bc_err(BC_ERR_EXEC_STACK);
2098 assert(BC_PROG_STACK(&p->results, 1));
2100 // Get the top of the results stack.
2101 bc_program_operand(p, &r, &n, 0);
2105 // Stream appropriately.
2106 if (BC_PROG_NUM(r, n)) bc_num_stream(n);
2107 else bc_program_printChars(bc_program_string(p, n));
2110 bc_vec_pop(&p->results);
2116 * Gets the length of a register in dc and pushes it onto the results stack.
2117 * @param p The program.
2118 * @param code The bytecode vector to pull the register's index out of.
2119 * @param bgn An in/out parameter; the start of the index in the bytecode
2120 * vector, and will be updated to point after the index on return.
2122 static void bc_program_regStackLen(BcProgram *p, const char *restrict code,
2123 size_t *restrict bgn)
2125 size_t idx = bc_program_index(code, bgn);
2126 BcVec *v = bc_program_vec(p, idx, BC_TYPE_VAR);
2128 bc_program_pushBigdig(p, (BcBigDig) v->len, BC_RESULT_TEMP);
2132 * Pushes the length of the results stack onto the results stack.
2133 * @param p The program.
2135 static void bc_program_stackLen(BcProgram *p) {
2136 bc_program_pushBigdig(p, (BcBigDig) p->results.len, BC_RESULT_TEMP);
2140 * Pops a certain number of elements off the execution stack.
2141 * @param p The program.
2142 * @param inst The instruction to tell us how many. There is one to pop up to
2143 * 2, and one to pop the amount equal to the number at the top of
2144 * the results stack.
2146 static void bc_program_nquit(BcProgram *p, uchar inst) {
2153 // Ensure that the tail calls stack is correct.
2154 assert(p->stack.len == p->tail_calls.len);
2156 // Get the number of executions to pop.
2157 if (inst == BC_INST_QUIT) val = 2;
2160 bc_program_prep(p, &opnd, &num, 0);
2161 val = bc_num_bigdig(num);
2163 bc_vec_pop(&p->results);
2166 // Loop over the tail call stack and adjust the quit value appropriately.
2167 for (i = 0; val && i < p->tail_calls.len; ++i) {
2169 // Get the number of tail calls for this one.
2170 size_t calls = *((size_t*) bc_vec_item_rev(&p->tail_calls, i)) + 1;
2172 // Adjust the value.
2173 if (calls >= val) val = 0;
2174 else val -= (BcBigDig) calls;
2177 // If we don't have enough executions, just quit.
2178 if (i == p->stack.len) {
2179 vm.status = BC_STATUS_QUIT;
2183 // We can always pop the last item we reached on the tail call stack
2184 // because these are for tail calls. That means that any executions that
2185 // we would not have quit in that position on the stack would have quit
2187 bc_vec_npop(&p->stack, i);
2188 bc_vec_npop(&p->tail_calls, i);
2193 * Pushes the depth of the execution stack onto the stack.
2194 * @param p The program.
2196 static void bc_program_execStackLen(BcProgram *p) {
2198 size_t i, amt, len = p->tail_calls.len;
2202 for (i = 0; i < len; ++i)
2203 amt += *((size_t*) bc_vec_item(&p->tail_calls, i));
2205 bc_program_pushBigdig(p, (BcBigDig) amt, BC_RESULT_TEMP);
2210 * @param p The program.
2211 * @param code The bytecode vector to pull the register's index out of.
2212 * @param bgn An in/out parameter; the start of the index in the bytecode
2213 * vector, and will be updated to point after the index on return.
2214 * @param cond True if the execution is conditional, false otherwise.
2215 * @param len The number of bytes in the bytecode vector.
2217 static void bc_program_execStr(BcProgram *p, const char *restrict code,
2218 size_t *restrict bgn, bool cond, size_t len)
2227 assert(p->stack.len == p->tail_calls.len);
2230 if (BC_ERR(!BC_PROG_STACK(&p->results, 1))) bc_err(BC_ERR_EXEC_STACK);
2232 assert(BC_PROG_STACK(&p->results, 1));
2235 bc_program_operand(p, &r, &n, 0);
2237 // If execution is conditional...
2241 size_t idx, then_idx, else_idx;
2243 // Get the index of the "then" var and "else" var.
2244 then_idx = bc_program_index(code, bgn);
2245 else_idx = bc_program_index(code, bgn);
2247 // Figure out if we should execute.
2248 exec = (r->d.n.len != 0);
2250 idx = exec ? then_idx : else_idx;
2253 BC_SETJMP_LOCKED(exit);
2255 // If we are supposed to execute, execute. If else_idx == SIZE_MAX, that
2256 // means there was no else clause, so if execute is false and else does
2257 // not exist, we don't execute. The goto skips all of the setup for the
2259 if (exec || (else_idx != SIZE_MAX))
2260 n = bc_vec_top(bc_program_vec(p, idx, BC_TYPE_VAR));
2263 if (BC_ERR(!BC_PROG_STR(n))) bc_err(BC_ERR_EXEC_TYPE);
2270 // In non-conditional situations, only the top of stack can be executed,
2271 // and in those cases, variables are not allowed to be "on the stack";
2272 // they are only put on the stack to be assigned to.
2273 assert(r->t != BC_RESULT_VAR);
2275 if (r->t != BC_RESULT_STR) return;
2278 assert(BC_PROG_STR(n));
2281 str = bc_program_string(p, n);
2283 // Get the function index and function.
2285 fidx = bc_program_insertFunc(p, str);
2287 f = bc_vec_item(&p->fns, fidx);
2289 // If the function has not been parsed yet...
2294 if (!BC_PARSE_IS_INITED(&vm.read_prs, p)) {
2296 bc_parse_init(&vm.read_prs, p, fidx);
2298 // Initialize this too because bc_vm_shutdown() expects them to be
2299 // initialized togther.
2300 bc_vec_init(&vm.read_buf, sizeof(char), BC_DTOR_NONE);
2302 // This needs to be updated because the parser could have been used
2304 else bc_parse_updateFunc(&vm.read_prs, fidx);
2306 bc_lex_file(&vm.read_prs.l, vm.file);
2308 BC_SETJMP_LOCKED(err);
2313 bc_parse_text(&vm.read_prs, str, false);
2314 vm.expr(&vm.read_prs, BC_PARSE_NOCALL);
2320 // We can just assert this here because
2321 // dc should parse everything until EOF.
2322 assert(vm.read_prs.l.t == BC_LEX_EOF);
2327 // Set the instruction pointer.
2329 ip.len = p->results.len;
2333 bc_vec_pop(&p->results);
2335 // Tail call processing. This condition means that there is more on the
2336 // execution stack, and we are at the end of the bytecode vector, and the
2337 // last instruction is just a BC_INST_POP_EXEC, which would return.
2338 if (p->stack.len > 1 && *bgn == len - 1 && code[*bgn] == BC_INST_POP_EXEC) {
2340 size_t *call_ptr = bc_vec_top(&p->tail_calls);
2342 // Add one to the tail call.
2345 // Pop the execution stack before pushing the new instruction pointer
2347 bc_vec_pop(&p->stack);
2349 // If not a tail call, just push a new one.
2350 else bc_vec_push(&p->tail_calls, &ip.idx);
2352 // Push the new function onto the execution stack and return.
2353 bc_vec_push(&p->stack, &ip);
2360 f = bc_vec_item(&p->fns, fidx);
2362 // Make sure to erase the bytecode vector so dc knows it is not parsed.
2363 bc_vec_popAll(&f->code);
2366 bc_vec_pop(&p->results);
2371 * Prints every item on the results stack, one per line.
2372 * @param p The program.
2374 static void bc_program_printStack(BcProgram *p) {
2378 for (idx = 0; idx < p->results.len; ++idx)
2379 bc_program_print(p, BC_INST_PRINT, idx);
2381 #endif // DC_ENABLED
2384 * Pushes the value of a global onto the results stack.
2385 * @param p The program.
2386 * @param inst Which global to push, as an instruction.
2388 static void bc_program_pushGlobal(BcProgram *p, uchar inst) {
2392 // Make sure the instruction is valid.
2393 assert(inst >= BC_INST_IBASE && inst <= BC_INST_SCALE);
2396 t = inst - BC_INST_IBASE + BC_RESULT_IBASE;
2397 bc_program_pushBigdig(p, p->globals[inst - BC_INST_IBASE], t);
2401 * Pushes the value of a global setting onto the stack.
2402 * @param p The program.
2403 * @param inst Which global setting to push, as an instruction.
2405 static void bc_program_globalSetting(BcProgram *p, uchar inst) {
2409 // Make sure the instruction is valid.
2410 assert(inst >= BC_INST_LINE_LENGTH && inst <= BC_INST_LEADING_ZERO);
2412 if (inst == BC_INST_LINE_LENGTH) val = (BcBigDig) vm.line_len;
2414 else if (inst == BC_INST_GLOBAL_STACKS) val = (BC_G != 0);
2415 #endif // BC_ENABLED
2416 else val = (BC_Z != 0);
2419 bc_program_pushBigdig(p, val, BC_RESULT_TEMP);
2422 #if BC_ENABLE_EXTRA_MATH
2425 * Pushes the value of seed on the stack.
2426 * @param p The program.
2428 static void bc_program_pushSeed(BcProgram *p) {
2432 res = bc_program_prepResult(p);
2433 res->t = BC_RESULT_SEED;
2437 // We need 2*BC_RAND_NUM_SIZE because of the size of the state.
2438 bc_num_init(&res->d.n, 2 * BC_RAND_NUM_SIZE);
2442 bc_num_createFromRNG(&res->d.n, &p->rng);
2445 #endif // BC_ENABLE_EXTRA_MATH
2448 * Adds a function to the fns array. The function's ID must have already been
2449 * inserted into the map.
2450 * @param p The program.
2451 * @param id_ptr The ID of the function as inserted into the map.
2453 static void bc_program_addFunc(BcProgram *p, BcId *id_ptr) {
2458 BC_SIG_ASSERT_LOCKED;
2461 f = bc_vec_pushEmpty(&p->fns);
2462 bc_func_init(f, id_ptr->name);
2464 // This is to make sure pointers are updated if the array was moved.
2466 ip = bc_vec_top(&p->stack);
2467 bc_program_setVecs(p, (BcFunc*) bc_vec_item(&p->fns, ip->func));
2471 size_t bc_program_insertFunc(BcProgram *p, const char *name) {
2477 BC_SIG_ASSERT_LOCKED;
2479 assert(p != NULL && name != NULL);
2481 // Insert into the map and get the resulting ID.
2482 new = bc_map_insert(&p->fn_map, name, p->fns.len, &idx);
2483 id_ptr = (BcId*) bc_vec_item(&p->fn_map, idx);
2486 // If the function is new...
2489 // Add the function to the fns array.
2490 bc_program_addFunc(p, id_ptr);
2493 // bc has to reset the function because it's about to be redefined.
2494 else if (BC_IS_BC) {
2495 BcFunc *func = bc_vec_item(&p->fns, idx);
2496 bc_func_reset(func);
2498 #endif // BC_ENABLED
2504 void bc_program_free(BcProgram *p) {
2508 BC_SIG_ASSERT_LOCKED;
2512 // Free the globals stacks.
2513 for (i = 0; i < BC_PROG_GLOBALS_LEN; ++i) bc_vec_free(p->globals_v + i);
2515 bc_vec_free(&p->fns);
2516 bc_vec_free(&p->fn_map);
2517 bc_vec_free(&p->vars);
2518 bc_vec_free(&p->var_map);
2519 bc_vec_free(&p->arrs);
2520 bc_vec_free(&p->arr_map);
2521 bc_vec_free(&p->results);
2522 bc_vec_free(&p->stack);
2525 if (BC_IS_BC) bc_num_free(&p->last);
2526 #endif // BC_ENABLED
2528 #if BC_ENABLE_EXTRA_MATH
2529 bc_rand_free(&p->rng);
2530 #endif // BC_ENABLE_EXTRA_MATH
2533 if (BC_IS_DC) bc_vec_free(&p->tail_calls);
2534 #endif // DC_ENABLED
2538 void bc_program_init(BcProgram *p) {
2543 BC_SIG_ASSERT_LOCKED;
2547 // We want this clear.
2548 memset(&ip, 0, sizeof(BcInstPtr));
2550 // Setup the globals stacks and the current values.
2551 for (i = 0; i < BC_PROG_GLOBALS_LEN; ++i) {
2553 BcBigDig val = i == BC_PROG_GLOBALS_SCALE ? 0 : BC_BASE;
2555 bc_vec_init(p->globals_v + i, sizeof(BcBigDig), BC_DTOR_NONE);
2556 bc_vec_push(p->globals_v + i, &val);
2558 p->globals[i] = val;
2565 bc_vec_init(&p->tail_calls, sizeof(size_t), BC_DTOR_NONE);
2567 // We want an item for the main function on the tail call stack.
2569 bc_vec_push(&p->tail_calls, &i);
2571 #endif // DC_ENABLED
2573 bc_num_setup(&p->strmb, p->strmb_num, BC_NUM_BIGDIG_LOG10);
2574 bc_num_bigdig2num(&p->strmb, BC_NUM_STREAM_BASE);
2576 #if BC_ENABLE_EXTRA_MATH
2577 // We need to initialize srand() just in case /dev/urandom and /dev/random
2578 // are not available.
2579 srand((unsigned int) time(NULL));
2580 bc_rand_init(&p->rng);
2581 #endif // BC_ENABLE_EXTRA_MATH
2584 if (BC_IS_BC) bc_num_init(&p->last, BC_NUM_DEF_SIZE);
2585 #endif // BC_ENABLED
2588 bc_vec_init(&p->fns, sizeof(BcFunc), BC_DTOR_FUNC);
2590 bc_vec_init(&p->fns, sizeof(BcFunc), BC_DTOR_NONE);
2592 bc_map_init(&p->fn_map);
2593 bc_program_insertFunc(p, bc_func_main);
2594 bc_program_insertFunc(p, bc_func_read);
2596 bc_vec_init(&p->vars, sizeof(BcVec), BC_DTOR_VEC);
2597 bc_map_init(&p->var_map);
2599 bc_vec_init(&p->arrs, sizeof(BcVec), BC_DTOR_VEC);
2600 bc_map_init(&p->arr_map);
2602 bc_vec_init(&p->results, sizeof(BcResult), BC_DTOR_RESULT);
2604 // Push the first instruction pointer onto the execution stack.
2605 bc_vec_init(&p->stack, sizeof(BcInstPtr), BC_DTOR_NONE);
2606 bc_vec_push(&p->stack, &ip);
2608 // Make sure the pointers are properly set up.
2609 bc_program_setVecs(p, (BcFunc*) bc_vec_item(&p->fns, BC_PROG_MAIN));
2611 assert(p->consts != NULL && p->strs != NULL);
2614 void bc_program_reset(BcProgram *p) {
2619 BC_SIG_ASSERT_LOCKED;
2621 // Pop all but the last execution and all results.
2622 bc_vec_npop(&p->stack, p->stack.len - 1);
2623 bc_vec_popAll(&p->results);
2626 // Clear the globals' stacks.
2627 if (BC_G) bc_program_popGlobals(p, true);
2628 #endif // BC_ENABLED
2630 // Clear the bytecode vector of the main function.
2631 f = bc_vec_item(&p->fns, BC_PROG_MAIN);
2632 bc_vec_npop(&f->code, f->code.len);
2634 // Reset the instruction pointer.
2635 ip = bc_vec_top(&p->stack);
2636 bc_program_setVecs(p, f);
2637 memset(ip, 0, sizeof(BcInstPtr));
2639 // Write the ready message for a signal, and clear the signal.
2641 bc_file_write(&vm.fout, bc_flush_none, bc_program_ready_msg,
2642 bc_program_ready_msg_len);
2643 bc_file_flush(&vm.fout, bc_flush_err);
2648 void bc_program_exec(BcProgram *p) {
2659 #endif // BC_ENABLED
2660 #if !BC_HAS_COMPUTED_GOTO
2662 size_t jmp_bufs_len;
2664 #endif // !BC_HAS_COMPUTED_GOTO
2666 #if BC_HAS_COMPUTED_GOTO
2668 BC_PROG_LBLS_ASSERT;
2670 // BC_INST_INVALID is a marker for the end so that we don't have to have an
2672 func = (BcFunc*) bc_vec_item(&p->fns, BC_PROG_MAIN);
2673 bc_vec_pushByte(&func->code, BC_INST_INVALID);
2674 #endif // BC_HAS_COMPUTED_GOTO
2676 ip = bc_vec_top(&p->stack);
2677 func = (BcFunc*) bc_vec_item(&p->fns, ip->func);
2678 code = func->code.v;
2680 // Ensure the pointers are correct.
2681 bc_program_setVecs(p, func);
2683 #if !BC_HAS_COMPUTED_GOTO
2686 jmp_bufs_len = vm.jmp_bufs.len;
2689 // This loop is the heart of the execution engine. It *is* the engine. For
2690 // computed goto, it is ignored.
2691 while (ip->idx < func->code.len)
2692 #endif // !BC_HAS_COMPUTED_GOTO
2695 BC_SIG_ASSERT_NOT_LOCKED;
2697 #if BC_HAS_COMPUTED_GOTO
2699 BC_PROG_JUMP(inst, code, ip);
2701 #else // BC_HAS_COMPUTED_GOTO
2703 // Get the next instruction and increment the index.
2704 inst = (uchar) code[(ip->idx)++];
2706 #endif // BC_HAS_COMPUTED_GOTO
2709 bc_file_printf(&vm.ferr, "inst: %s\n", bc_inst_names[inst]);
2710 bc_file_flush(&vm.ferr, bc_flush_none);
2711 #endif // BC_DEBUG_CODE
2713 #if !BC_HAS_COMPUTED_GOTO
2715 #endif // !BC_HAS_COMPUTED_GOTO
2719 // This just sets up the condition for the unconditional jump below,
2720 // which checks the condition, if necessary.
2721 BC_PROG_LBL(BC_INST_JUMP_ZERO):
2723 bc_program_prep(p, &ptr, &num, 0);
2725 cond = !bc_num_cmpZero(num);
2726 bc_vec_pop(&p->results);
2728 BC_PROG_DIRECT_JUMP(BC_INST_JUMP)
2733 BC_PROG_LBL(BC_INST_JUMP):
2735 idx = bc_program_index(code, &ip->idx);
2737 // If a jump is required...
2738 if (inst == BC_INST_JUMP || cond) {
2740 // Get the address to jump to.
2741 size_t *addr = bc_vec_item(&func->labels, idx);
2743 // If this fails, then the parser failed to set up the
2744 // labels correctly.
2745 assert(*addr != SIZE_MAX);
2747 // Set the new address.
2751 BC_PROG_JUMP(inst, code, ip);
2754 BC_PROG_LBL(BC_INST_CALL):
2758 bc_program_call(p, code, &ip->idx);
2760 // Because we changed the execution stack and where we are
2761 // executing, we have to update all of this.
2762 ip = bc_vec_top(&p->stack);
2763 func = bc_vec_item(&p->fns, ip->func);
2764 code = func->code.v;
2765 bc_program_setVecs(p, func);
2767 BC_PROG_JUMP(inst, code, ip);
2770 BC_PROG_LBL(BC_INST_INC):
2771 BC_PROG_LBL(BC_INST_DEC):
2773 bc_program_incdec(p, inst);
2774 BC_PROG_JUMP(inst, code, ip);
2777 BC_PROG_LBL(BC_INST_HALT):
2779 vm.status = BC_STATUS_QUIT;
2781 // Just jump out. The jump series will take care of everything.
2784 BC_PROG_JUMP(inst, code, ip);
2787 BC_PROG_LBL(BC_INST_RET):
2788 BC_PROG_LBL(BC_INST_RET0):
2789 BC_PROG_LBL(BC_INST_RET_VOID):
2791 bc_program_return(p, inst);
2793 // Because we changed the execution stack and where we are
2794 // executing, we have to update all of this.
2795 ip = bc_vec_top(&p->stack);
2796 func = bc_vec_item(&p->fns, ip->func);
2797 code = func->code.v;
2798 bc_program_setVecs(p, func);
2800 BC_PROG_JUMP(inst, code, ip);
2802 #endif // BC_ENABLED
2804 BC_PROG_LBL(BC_INST_BOOL_OR):
2805 BC_PROG_LBL(BC_INST_BOOL_AND):
2806 BC_PROG_LBL(BC_INST_REL_EQ):
2807 BC_PROG_LBL(BC_INST_REL_LE):
2808 BC_PROG_LBL(BC_INST_REL_GE):
2809 BC_PROG_LBL(BC_INST_REL_NE):
2810 BC_PROG_LBL(BC_INST_REL_LT):
2811 BC_PROG_LBL(BC_INST_REL_GT):
2813 bc_program_logical(p, inst);
2814 BC_PROG_JUMP(inst, code, ip);
2817 BC_PROG_LBL(BC_INST_READ):
2819 // We want to flush output before
2820 // this in case there is a prompt.
2821 bc_file_flush(&vm.fout, bc_flush_save);
2825 // Because we changed the execution stack and where we are
2826 // executing, we have to update all of this.
2827 ip = bc_vec_top(&p->stack);
2828 func = bc_vec_item(&p->fns, ip->func);
2829 code = func->code.v;
2830 bc_program_setVecs(p, func);
2832 BC_PROG_JUMP(inst, code, ip);
2835 #if BC_ENABLE_EXTRA_MATH
2836 BC_PROG_LBL(BC_INST_RAND):
2839 BC_PROG_JUMP(inst, code, ip);
2841 #endif // BC_ENABLE_EXTRA_MATH
2843 BC_PROG_LBL(BC_INST_MAXIBASE):
2844 BC_PROG_LBL(BC_INST_MAXOBASE):
2845 BC_PROG_LBL(BC_INST_MAXSCALE):
2846 #if BC_ENABLE_EXTRA_MATH
2847 BC_PROG_LBL(BC_INST_MAXRAND):
2848 #endif // BC_ENABLE_EXTRA_MATH
2850 BcBigDig dig = vm.maxes[inst - BC_INST_MAXIBASE];
2851 bc_program_pushBigdig(p, dig, BC_RESULT_TEMP);
2852 BC_PROG_JUMP(inst, code, ip);
2855 BC_PROG_LBL(BC_INST_LINE_LENGTH):
2857 BC_PROG_LBL(BC_INST_GLOBAL_STACKS):
2858 #endif // BC_ENABLED
2859 BC_PROG_LBL(BC_INST_LEADING_ZERO):
2861 bc_program_globalSetting(p, inst);
2862 BC_PROG_JUMP(inst, code, ip);
2865 BC_PROG_LBL(BC_INST_VAR):
2867 bc_program_pushVar(p, code, &ip->idx, false, false);
2868 BC_PROG_JUMP(inst, code, ip);
2871 BC_PROG_LBL(BC_INST_ARRAY_ELEM):
2872 BC_PROG_LBL(BC_INST_ARRAY):
2874 bc_program_pushArray(p, code, &ip->idx, inst);
2875 BC_PROG_JUMP(inst, code, ip);
2878 BC_PROG_LBL(BC_INST_IBASE):
2879 BC_PROG_LBL(BC_INST_SCALE):
2880 BC_PROG_LBL(BC_INST_OBASE):
2882 bc_program_pushGlobal(p, inst);
2883 BC_PROG_JUMP(inst, code, ip);
2886 #if BC_ENABLE_EXTRA_MATH
2887 BC_PROG_LBL(BC_INST_SEED):
2889 bc_program_pushSeed(p);
2890 BC_PROG_JUMP(inst, code, ip);
2892 #endif // BC_ENABLE_EXTRA_MATH
2894 BC_PROG_LBL(BC_INST_LENGTH):
2895 BC_PROG_LBL(BC_INST_SCALE_FUNC):
2896 BC_PROG_LBL(BC_INST_SQRT):
2897 BC_PROG_LBL(BC_INST_ABS):
2898 #if BC_ENABLE_EXTRA_MATH
2899 BC_PROG_LBL(BC_INST_IRAND):
2900 #endif // BC_ENABLE_EXTRA_MATH
2902 bc_program_builtin(p, inst);
2903 BC_PROG_JUMP(inst, code, ip);
2906 BC_PROG_LBL(BC_INST_ASCIIFY):
2908 bc_program_asciify(p, ip->func);
2910 // Because we changed the execution stack and where we are
2911 // executing, we have to update all of this.
2912 ip = bc_vec_top(&p->stack);
2913 func = bc_vec_item(&p->fns, ip->func);
2914 code = func->code.v;
2915 bc_program_setVecs(p, func);
2917 BC_PROG_JUMP(inst, code, ip);
2920 BC_PROG_LBL(BC_INST_NUM):
2922 bc_program_const(p, code, &ip->idx);
2923 BC_PROG_JUMP(inst, code, ip);
2926 BC_PROG_LBL(BC_INST_ZERO):
2927 BC_PROG_LBL(BC_INST_ONE):
2929 BC_PROG_LBL(BC_INST_LAST):
2930 #endif // BC_ENABLED
2932 r.t = BC_RESULT_ZERO + (inst - BC_INST_ZERO);
2933 bc_vec_push(&p->results, &r);
2934 BC_PROG_JUMP(inst, code, ip);
2937 BC_PROG_LBL(BC_INST_PRINT):
2938 BC_PROG_LBL(BC_INST_PRINT_POP):
2940 BC_PROG_LBL(BC_INST_PRINT_STR):
2941 #endif // BC_ENABLED
2943 bc_program_print(p, inst, 0);
2945 // We want to flush right away to save the output for history,
2946 // if history must preserve it when taking input.
2947 bc_file_flush(&vm.fout, bc_flush_save);
2949 BC_PROG_JUMP(inst, code, ip);
2952 BC_PROG_LBL(BC_INST_STR):
2954 // Set up the result and push.
2955 r.t = BC_RESULT_STR;
2956 bc_num_clear(&r.d.n);
2957 r.d.n.rdx = bc_program_index(code, &ip->idx);
2958 r.d.n.scale = bc_program_index(code, &ip->idx);
2959 bc_vec_push(&p->results, &r);
2960 BC_PROG_JUMP(inst, code, ip);
2963 BC_PROG_LBL(BC_INST_POWER):
2964 BC_PROG_LBL(BC_INST_MULTIPLY):
2965 BC_PROG_LBL(BC_INST_DIVIDE):
2966 BC_PROG_LBL(BC_INST_MODULUS):
2967 BC_PROG_LBL(BC_INST_PLUS):
2968 BC_PROG_LBL(BC_INST_MINUS):
2969 #if BC_ENABLE_EXTRA_MATH
2970 BC_PROG_LBL(BC_INST_PLACES):
2971 BC_PROG_LBL(BC_INST_LSHIFT):
2972 BC_PROG_LBL(BC_INST_RSHIFT):
2973 #endif // BC_ENABLE_EXTRA_MATH
2975 bc_program_op(p, inst);
2976 BC_PROG_JUMP(inst, code, ip);
2979 BC_PROG_LBL(BC_INST_NEG):
2980 BC_PROG_LBL(BC_INST_BOOL_NOT):
2981 #if BC_ENABLE_EXTRA_MATH
2982 BC_PROG_LBL(BC_INST_TRUNC):
2983 #endif // BC_ENABLE_EXTRA_MATH
2985 bc_program_unary(p, inst);
2986 BC_PROG_JUMP(inst, code, ip);
2990 BC_PROG_LBL(BC_INST_ASSIGN_POWER):
2991 BC_PROG_LBL(BC_INST_ASSIGN_MULTIPLY):
2992 BC_PROG_LBL(BC_INST_ASSIGN_DIVIDE):
2993 BC_PROG_LBL(BC_INST_ASSIGN_MODULUS):
2994 BC_PROG_LBL(BC_INST_ASSIGN_PLUS):
2995 BC_PROG_LBL(BC_INST_ASSIGN_MINUS):
2996 #if BC_ENABLE_EXTRA_MATH
2997 BC_PROG_LBL(BC_INST_ASSIGN_PLACES):
2998 BC_PROG_LBL(BC_INST_ASSIGN_LSHIFT):
2999 BC_PROG_LBL(BC_INST_ASSIGN_RSHIFT):
3000 #endif // BC_ENABLE_EXTRA_MATH
3001 BC_PROG_LBL(BC_INST_ASSIGN):
3002 BC_PROG_LBL(BC_INST_ASSIGN_POWER_NO_VAL):
3003 BC_PROG_LBL(BC_INST_ASSIGN_MULTIPLY_NO_VAL):
3004 BC_PROG_LBL(BC_INST_ASSIGN_DIVIDE_NO_VAL):
3005 BC_PROG_LBL(BC_INST_ASSIGN_MODULUS_NO_VAL):
3006 BC_PROG_LBL(BC_INST_ASSIGN_PLUS_NO_VAL):
3007 BC_PROG_LBL(BC_INST_ASSIGN_MINUS_NO_VAL):
3008 #if BC_ENABLE_EXTRA_MATH
3009 BC_PROG_LBL(BC_INST_ASSIGN_PLACES_NO_VAL):
3010 BC_PROG_LBL(BC_INST_ASSIGN_LSHIFT_NO_VAL):
3011 BC_PROG_LBL(BC_INST_ASSIGN_RSHIFT_NO_VAL):
3012 #endif // BC_ENABLE_EXTRA_MATH
3013 #endif // BC_ENABLED
3014 BC_PROG_LBL(BC_INST_ASSIGN_NO_VAL):
3016 bc_program_assign(p, inst);
3017 BC_PROG_JUMP(inst, code, ip);
3020 BC_PROG_LBL(BC_INST_POP):
3022 #ifndef BC_PROG_NO_STACK_CHECK
3023 // dc must do a stack check, but bc does not.
3025 if (BC_ERR(!BC_PROG_STACK(&p->results, 1)))
3026 bc_err(BC_ERR_EXEC_STACK);
3028 #endif // BC_PROG_NO_STACK_CHECK
3030 assert(BC_PROG_STACK(&p->results, 1));
3032 bc_vec_pop(&p->results);
3034 BC_PROG_JUMP(inst, code, ip);
3037 BC_PROG_LBL(BC_INST_SWAP):
3042 if (BC_ERR(!BC_PROG_STACK(&p->results, 2)))
3043 bc_err(BC_ERR_EXEC_STACK);
3045 assert(BC_PROG_STACK(&p->results, 2));
3047 // Get the two items.
3048 ptr = bc_vec_item_rev(&p->results, 0);
3049 ptr2 = bc_vec_item_rev(&p->results, 1);
3051 // Swap. It's just easiest to do it this way.
3052 memcpy(&r, ptr, sizeof(BcResult));
3053 memcpy(ptr, ptr2, sizeof(BcResult));
3054 memcpy(ptr2, &r, sizeof(BcResult));
3056 BC_PROG_JUMP(inst, code, ip);
3059 BC_PROG_LBL(BC_INST_MODEXP):
3061 bc_program_modexp(p);
3062 BC_PROG_JUMP(inst, code, ip);
3065 BC_PROG_LBL(BC_INST_DIVMOD):
3067 bc_program_divmod(p);
3068 BC_PROG_JUMP(inst, code, ip);
3071 BC_PROG_LBL(BC_INST_PRINT_STREAM):
3073 bc_program_printStream(p);
3074 BC_PROG_JUMP(inst, code, ip);
3078 BC_PROG_LBL(BC_INST_POP_EXEC):
3080 // If this fails, the dc parser got something wrong.
3081 assert(BC_PROG_STACK(&p->stack, 2));
3083 // Pop the execution stack and tail call stack.
3084 bc_vec_pop(&p->stack);
3085 bc_vec_pop(&p->tail_calls);
3087 // Because we changed the execution stack and where we are
3088 // executing, we have to update all of this.
3089 ip = bc_vec_top(&p->stack);
3090 func = bc_vec_item(&p->fns, ip->func);
3091 code = func->code.v;
3092 bc_program_setVecs(p, func);
3094 BC_PROG_JUMP(inst, code, ip);
3097 BC_PROG_LBL(BC_INST_EXECUTE):
3098 BC_PROG_LBL(BC_INST_EXEC_COND):
3100 cond = (inst == BC_INST_EXEC_COND);
3102 bc_program_execStr(p, code, &ip->idx, cond, func->code.len);
3104 // Because we changed the execution stack and where we are
3105 // executing, we have to update all of this.
3106 ip = bc_vec_top(&p->stack);
3107 func = bc_vec_item(&p->fns, ip->func);
3108 code = func->code.v;
3109 bc_program_setVecs(p, func);
3111 BC_PROG_JUMP(inst, code, ip);
3114 BC_PROG_LBL(BC_INST_PRINT_STACK):
3116 bc_program_printStack(p);
3117 BC_PROG_JUMP(inst, code, ip);
3120 BC_PROG_LBL(BC_INST_CLEAR_STACK):
3122 bc_vec_popAll(&p->results);
3123 BC_PROG_JUMP(inst, code, ip);
3126 BC_PROG_LBL(BC_INST_REG_STACK_LEN):
3128 bc_program_regStackLen(p, code, &ip->idx);
3129 BC_PROG_JUMP(inst, code, ip);
3132 BC_PROG_LBL(BC_INST_STACK_LEN):
3134 bc_program_stackLen(p);
3135 BC_PROG_JUMP(inst, code, ip);
3138 BC_PROG_LBL(BC_INST_DUPLICATE):
3141 if (BC_ERR(!BC_PROG_STACK(&p->results, 1)))
3142 bc_err(BC_ERR_EXEC_STACK);
3144 assert(BC_PROG_STACK(&p->results, 1));
3146 // Get the top of the stack.
3147 ptr = bc_vec_top(&p->results);
3152 bc_result_copy(&r, ptr);
3153 bc_vec_push(&p->results, &r);
3157 BC_PROG_JUMP(inst, code, ip);
3160 BC_PROG_LBL(BC_INST_LOAD):
3161 BC_PROG_LBL(BC_INST_PUSH_VAR):
3163 bool copy = (inst == BC_INST_LOAD);
3164 bc_program_pushVar(p, code, &ip->idx, true, copy);
3165 BC_PROG_JUMP(inst, code, ip);
3168 BC_PROG_LBL(BC_INST_PUSH_TO_VAR):
3170 idx = bc_program_index(code, &ip->idx);
3171 bc_program_copyToVar(p, idx, BC_TYPE_VAR, true);
3172 BC_PROG_JUMP(inst, code, ip);
3175 BC_PROG_LBL(BC_INST_QUIT):
3176 BC_PROG_LBL(BC_INST_NQUIT):
3178 bc_program_nquit(p, inst);
3180 // Because we changed the execution stack and where we are
3181 // executing, we have to update all of this.
3182 ip = bc_vec_top(&p->stack);
3183 func = bc_vec_item(&p->fns, ip->func);
3184 code = func->code.v;
3185 bc_program_setVecs(p, func);
3187 BC_PROG_JUMP(inst, code, ip);
3190 BC_PROG_LBL(BC_INST_EXEC_STACK_LEN):
3192 bc_program_execStackLen(p);
3193 BC_PROG_JUMP(inst, code, ip);
3195 #endif // DC_ENABLED
3197 #if BC_HAS_COMPUTED_GOTO
3198 BC_PROG_LBL(BC_INST_INVALID):
3202 #else // BC_HAS_COMPUTED_GOTO
3210 #endif // BC_HAS_COMPUTED_GOTO
3213 #if !BC_HAS_COMPUTED_GOTO
3215 // This is to allow me to use a debugger to see the last instruction,
3216 // which will point to which function was the problem. But it's also a
3217 // good smoke test for error handling changes.
3218 assert(jmp_bufs_len == vm.jmp_bufs.len);
3220 #endif // !BC_HAS_COMPUTED_GOTO
3225 #if BC_ENABLED && DC_ENABLED
3226 void bc_program_printStackDebug(BcProgram *p) {
3227 bc_file_puts(&vm.fout, bc_flush_err, "-------------- Stack ----------\n");
3228 bc_program_printStack(p);
3229 bc_file_puts(&vm.fout, bc_flush_err, "-------------- Stack End ------\n");
3232 static void bc_program_printIndex(const char *restrict code,
3233 size_t *restrict bgn)
3235 uchar byte, i, bytes = (uchar) code[(*bgn)++];
3238 for (byte = 1, i = 0; byte && i < bytes; ++i) {
3239 byte = (uchar) code[(*bgn)++];
3240 if (byte) val |= ((ulong) byte) << (CHAR_BIT * i);
3243 bc_vm_printf(" (%lu) ", val);
3246 static void bc_program_printStr(const BcProgram *p, const char *restrict code,
3247 size_t *restrict bgn)
3249 size_t idx = bc_program_index(code, bgn);
3252 s = *((char**) bc_vec_item(p->strs, idx));
3254 bc_vm_printf(" (\"%s\") ", s);
3257 void bc_program_printInst(const BcProgram *p, const char *restrict code,
3258 size_t *restrict bgn)
3260 uchar inst = (uchar) code[(*bgn)++];
3262 bc_vm_printf("Inst[%zu]: %s [%lu]; ", *bgn - 1,
3263 bc_inst_names[inst], (unsigned long) inst);
3265 if (inst == BC_INST_VAR || inst == BC_INST_ARRAY_ELEM ||
3266 inst == BC_INST_ARRAY)
3268 bc_program_printIndex(code, bgn);
3270 else if (inst == BC_INST_STR) bc_program_printStr(p, code, bgn);
3271 else if (inst == BC_INST_NUM) {
3272 size_t idx = bc_program_index(code, bgn);
3273 BcConst *c = bc_vec_item(p->consts, idx);
3274 bc_vm_printf("(%s)", c->val);
3276 else if (inst == BC_INST_CALL ||
3277 (inst > BC_INST_STR && inst <= BC_INST_JUMP_ZERO))
3279 bc_program_printIndex(code, bgn);
3280 if (inst == BC_INST_CALL) bc_program_printIndex(code, bgn);
3283 bc_vm_putchar('\n', bc_flush_err);
3286 void bc_program_code(const BcProgram* p) {
3293 for (i = 0; i < p->fns.len; ++i) {
3295 ip.idx = ip.len = 0;
3298 f = bc_vec_item(&p->fns, ip.func);
3301 bc_vm_printf("func[%zu]:\n", ip.func);
3302 while (ip.idx < f->code.len) bc_program_printInst(p, code, &ip.idx);
3303 bc_file_puts(&vm.fout, bc_flush_err, "\n\n");
3306 #endif // BC_ENABLED && DC_ENABLED
3307 #endif // BC_DEBUG_CODE