2 * *****************************************************************************
4 * SPDX-License-Identifier: BSD-2-Clause
6 * Copyright (c) 2018-2020 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.
51 static void bc_program_addFunc(BcProgram *p, BcFunc *f, BcId *id_ptr);
53 static inline void bc_program_setVecs(BcProgram *p, BcFunc *f) {
54 p->consts = &f->consts;
55 if (BC_IS_BC) p->strs = &f->strs;
58 static inline void bc_program_type_num(BcResult *r, BcNum *n) {
61 assert(r->t != BC_RESULT_VOID);
64 if (BC_ERR(!BC_PROG_NUM(r, n))) bc_vm_err(BC_ERR_EXEC_TYPE);
68 static void bc_program_type_match(BcResult *r, BcType t) {
71 assert(BC_IS_DC || BC_NO_ERR(r->t != BC_RESULT_STR));
74 if (BC_ERR((r->t != BC_RESULT_ARRAY) != (!t)))
75 bc_vm_err(BC_ERR_EXEC_TYPE);
79 static size_t bc_program_index(const char *restrict code, size_t *restrict bgn)
81 uchar amt = (uchar) code[(*bgn)++], i = 0;
84 for (; i < amt; ++i, ++(*bgn)) {
85 size_t temp = ((size_t) ((int) (uchar) code[*bgn]) & UCHAR_MAX);
86 res |= (temp << (i * CHAR_BIT));
93 static void bc_program_prepGlobals(BcProgram *p) {
97 for (i = 0; i < BC_PROG_GLOBALS_LEN; ++i)
98 bc_vec_push(p->globals_v + i, p->globals + i);
100 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
101 bc_rand_push(&p->rng);
102 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
105 static void bc_program_popGlobals(BcProgram *p, bool reset) {
109 for (i = 0; i < BC_PROG_GLOBALS_LEN; ++i) {
110 BcVec *v = p->globals_v + i;
111 bc_vec_npop(v, reset ? v->len - 1 : 1);
112 p->globals[i] = BC_PROG_GLOBAL(v);
115 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
116 bc_rand_pop(&p->rng, reset);
117 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
121 static void bc_program_pushBigdig(BcProgram *p, BcBigDig dig, BcResultType type)
129 bc_num_createFromBigdig(&res.d.n, dig);
130 bc_vec_push(&p->results, &res);
136 static BcVec* bc_program_dereference(const BcProgram *p, BcVec *vec) {
139 size_t vidx, nidx, i = 0;
141 assert(vec->size == sizeof(uchar));
143 vidx = bc_program_index(vec->v, &i);
144 nidx = bc_program_index(vec->v, &i);
146 v = bc_vec_item(bc_vec_item(&p->arrs, vidx), nidx);
148 assert(v->size != sizeof(uchar));
154 size_t bc_program_search(BcProgram *p, const char *id, bool var) {
160 v = var ? &p->vars : &p->arrs;
161 map = var ? &p->var_map : &p->arr_map;
165 if (bc_map_insert(map, id, v->len, &i)) {
166 bc_array_init(&data.v, var);
167 bc_vec_push(v, &data.v);
172 return ((BcId*) bc_vec_item(map, i))->idx;
175 static inline BcVec* bc_program_vec(const BcProgram *p, size_t idx, BcType type)
177 const BcVec *v = (type == BC_TYPE_VAR) ? &p->vars : &p->arrs;
178 return bc_vec_item(v, idx);
181 static BcNum* bc_program_num(BcProgram *p, BcResult *r) {
189 case BC_RESULT_IBASE:
190 case BC_RESULT_SCALE:
191 case BC_RESULT_OBASE:
192 #if BC_ENABLE_EXTRA_MATH
194 #endif // BC_ENABLE_EXTRA_MATH
202 case BC_RESULT_ARRAY:
204 case BC_RESULT_ARRAY_ELEM:
207 BcType type = (r->t == BC_RESULT_VAR) ? BC_TYPE_VAR : BC_TYPE_ARRAY;
209 v = bc_program_vec(p, r->d.loc.loc, type);
211 if (r->t == BC_RESULT_ARRAY_ELEM) {
213 size_t idx = r->d.loc.idx;
218 if (v->size == sizeof(uchar)) v = bc_program_dereference(p, v);
221 assert(v->size == sizeof(BcNum));
225 bc_array_expand(v, bc_vm_growSize(idx, 1));
229 n = bc_vec_item(v, idx);
231 else n = bc_vec_top(v);
267 static void bc_program_operand(BcProgram *p, BcResult **r,
268 BcNum **n, size_t idx)
270 *r = bc_vec_item_rev(&p->results, idx);
273 if (BC_ERR((*r)->t == BC_RESULT_VOID)) bc_vm_err(BC_ERR_EXEC_VOID_VAL);
276 *n = bc_program_num(p, *r);
279 static void bc_program_binPrep(BcProgram *p, BcResult **l, BcNum **ln,
280 BcResult **r, BcNum **rn, size_t idx)
284 assert(p != NULL && l != NULL && ln != NULL && r != NULL && rn != NULL);
286 #ifndef BC_PROG_NO_STACK_CHECK
288 if (BC_ERR(!BC_PROG_STACK(&p->results, idx + 2)))
289 bc_vm_err(BC_ERR_EXEC_STACK);
291 #endif // BC_PROG_NO_STACK_CHECK
293 assert(BC_PROG_STACK(&p->results, idx + 2));
295 bc_program_operand(p, l, ln, idx + 1);
296 bc_program_operand(p, r, rn, idx);
301 assert(lt != BC_RESULT_VOID && (*r)->t != BC_RESULT_VOID);
304 // We run this again under these conditions in case any vector has been
305 // reallocated out from under the BcNums or arrays we had.
306 if (lt == (*r)->t && (lt == BC_RESULT_VAR || lt == BC_RESULT_ARRAY_ELEM))
307 *ln = bc_program_num(p, *l);
309 if (BC_ERR(lt == BC_RESULT_STR)) bc_vm_err(BC_ERR_EXEC_TYPE);
312 static void bc_program_binOpPrep(BcProgram *p, BcResult **l, BcNum **ln,
313 BcResult **r, BcNum **rn, size_t idx)
315 bc_program_binPrep(p, l, ln, r, rn, idx);
316 bc_program_type_num(*l, *ln);
317 bc_program_type_num(*r, *rn);
320 static void bc_program_assignPrep(BcProgram *p, BcResult **l, BcNum **ln,
321 BcResult **r, BcNum **rn)
323 BcResultType lt, min;
325 min = BC_RESULT_TEMP - ((unsigned int) (BC_IS_BC));
327 bc_program_binPrep(p, l, ln, r, rn, 0);
331 if (BC_ERR(lt >= min && lt <= BC_RESULT_ONE))
332 bc_vm_err(BC_ERR_EXEC_TYPE);
337 bool good = (((*r)->t == BC_RESULT_STR || BC_PROG_STR(*rn)) &&
338 lt <= BC_RESULT_ARRAY_ELEM);
340 if (!good) bc_program_type_num(*r, *rn);
343 assert((*r)->t != BC_RESULT_STR);
347 static void bc_program_prep(BcProgram *p, BcResult **r, BcNum **n, size_t idx) {
349 assert(p != NULL && r != NULL && n != NULL);
351 #ifndef BC_PROG_NO_STACK_CHECK
353 if (BC_ERR(!BC_PROG_STACK(&p->results, idx + 1)))
354 bc_vm_err(BC_ERR_EXEC_STACK);
356 #endif // BC_PROG_NO_STACK_CHECK
358 assert(BC_PROG_STACK(&p->results, idx + 1));
360 bc_program_operand(p, r, n, idx);
363 assert((*r)->t != BC_RESULT_VAR || !BC_PROG_STR(*n));
366 bc_program_type_num(*r, *n);
369 static BcResult* bc_program_prepResult(BcProgram *p) {
373 bc_result_clear(&res);
374 bc_vec_push(&p->results, &res);
376 return bc_vec_top(&p->results);
379 static void bc_program_const(BcProgram *p, const char *code, size_t *bgn) {
381 BcResult *r = bc_program_prepResult(p);
382 BcConst *c = bc_vec_item(p->consts, bc_program_index(code, bgn));
383 BcBigDig base = BC_PROG_IBASE(p);
385 if (c->base != base) {
387 if (c->num.num == NULL) {
389 bc_num_init(&c->num, BC_NUM_RDX(strlen(c->val)));
393 // bc_num_parse() should only do operations that cannot fail.
394 bc_num_parse(&c->num, c->val, base);
401 bc_num_createCopy(&r->d.n, &c->num);
406 static void bc_program_op(BcProgram *p, uchar inst) {
408 BcResult *opd1, *opd2, *res;
410 size_t idx = inst - BC_INST_POWER;
412 res = bc_program_prepResult(p);
414 bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2, 1);
418 bc_num_init(&res->d.n, bc_program_opReqs[idx](n1, n2, BC_PROG_SCALE(p)));
422 assert(BC_NUM_RDX_VALID(n1));
423 assert(BC_NUM_RDX_VALID(n2));
425 bc_program_ops[idx](n1, n2, &res->d.n, BC_PROG_SCALE(p));
427 bc_program_retire(p, 1, 2);
430 static void bc_program_read(BcProgram *p) {
438 BcFunc *f = bc_vec_item(&p->fns, BC_PROG_READ);
440 for (i = 0; i < p->stack.len; ++i) {
441 BcInstPtr *ip_ptr = bc_vec_item(&p->stack, i);
442 if (ip_ptr->func == BC_PROG_READ)
443 bc_vm_err(BC_ERR_EXEC_REC_READ);
449 bc_parse_init(&parse, p, BC_PROG_READ);
450 bc_vec_init(&buf, sizeof(char), NULL);
452 BC_SETJMP_LOCKED(exec_err);
456 bc_lex_file(&parse.l, bc_program_stdin_name);
457 bc_vec_npop(&f->code, f->code.len);
459 s = bc_read_line(&buf, BC_IS_BC ? "read> " : "?> ");
460 if (s == BC_STATUS_EOF) bc_vm_err(BC_ERR_EXEC_READ_EXPR);
462 bc_parse_text(&parse, buf.v);
463 vm.expr(&parse, BC_PARSE_NOREAD | BC_PARSE_NEEDVAL);
465 if (BC_ERR(parse.l.t != BC_LEX_NLINE && parse.l.t != BC_LEX_EOF))
466 bc_vm_err(BC_ERR_EXEC_READ_EXPR);
469 if (BC_G) bc_program_prepGlobals(p);
472 ip.func = BC_PROG_READ;
474 ip.len = p->results.len;
476 // Update this pointer, just in case.
477 f = bc_vec_item(&p->fns, BC_PROG_READ);
479 bc_vec_pushByte(&f->code, vm.read_ret);
480 bc_vec_push(&p->stack, &ip);
485 bc_vec_push(&p->tail_calls, &temp);
491 bc_parse_free(&parse);
497 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
498 static void bc_program_rand(BcProgram *p) {
499 BcRand rand = bc_rand_int(&p->rng);
500 bc_program_pushBigdig(p, (BcBigDig) rand, BC_RESULT_TEMP);
503 BcResult *r = bc_vec_top(&p->results);
504 assert(BC_NUM_RDX_VALID_NP(r->d.n));
508 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
510 static void bc_program_printChars(const char *str) {
513 size_t len = vm.nchars + strlen(str);
515 bc_file_puts(&vm.fout, str);
516 nl = strrchr(str, '\n');
518 if (nl != NULL) len = strlen(nl + 1);
520 vm.nchars = len > UINT16_MAX ? UINT16_MAX : (uint16_t) len;
523 static void bc_program_printString(const char *restrict str) {
525 size_t i, len = strlen(str);
528 if (!len && BC_IS_DC) {
534 for (i = 0; i < len; ++i) {
538 if (c == '\\' && i != len - 1) {
543 ptr = strchr(bc_program_esc_chars, c);
546 if (c == 'n') vm.nchars = UINT16_MAX;
547 c = bc_program_esc_seqs[(size_t) (ptr - bc_program_esc_chars)];
550 // Just print the backslash. The following
551 // character will be printed later.
560 static void bc_program_print(BcProgram *p, uchar inst, size_t idx) {
565 bool pop = (inst != BC_INST_PRINT);
569 #ifndef BC_PROG_NO_STACK_CHECK
571 if (BC_ERR(!BC_PROG_STACK(&p->results, idx + 1)))
572 bc_vm_err(BC_ERR_EXEC_STACK);
574 #endif // BC_PROG_NO_STACK_CHECK
576 assert(BC_PROG_STACK(&p->results, idx + 1));
578 r = bc_vec_item_rev(&p->results, idx);
581 if (r->t == BC_RESULT_VOID) {
582 if (BC_ERR(pop)) bc_vm_err(BC_ERR_EXEC_VOID_VAL);
583 bc_vec_pop(&p->results);
588 n = bc_program_num(p, r);
590 if (BC_PROG_NUM(r, n)) {
591 assert(inst != BC_INST_PRINT_STR);
592 bc_num_print(n, BC_PROG_OBASE(p), !pop);
594 if (BC_IS_BC) bc_num_copy(&p->last, n);
599 size_t i = (r->t == BC_RESULT_STR) ? r->d.loc.loc : n->scale;
601 bc_file_flush(&vm.fout);
602 str = *((char**) bc_vec_item(p->strs, i));
604 if (inst == BC_INST_PRINT_STR) bc_program_printChars(str);
606 bc_program_printString(str);
607 if (inst == BC_INST_PRINT) bc_vm_putchar('\n');
611 if (BC_IS_BC || pop) bc_vec_pop(&p->results);
614 void bc_program_negate(BcResult *r, BcNum *n) {
615 bc_num_copy(&r->d.n, n);
616 if (BC_NUM_NONZERO(&r->d.n)) BC_NUM_NEG_TGL_NP(r->d.n);
619 void bc_program_not(BcResult *r, BcNum *n) {
620 if (!bc_num_cmpZero(n)) bc_num_one(&r->d.n);
623 #if BC_ENABLE_EXTRA_MATH
624 void bc_program_trunc(BcResult *r, BcNum *n) {
625 bc_num_copy(&r->d.n, n);
626 bc_num_truncate(&r->d.n, n->scale);
628 #endif // BC_ENABLE_EXTRA_MATH
630 static void bc_program_unary(BcProgram *p, uchar inst) {
635 res = bc_program_prepResult(p);
637 bc_program_prep(p, &ptr, &num, 1);
641 bc_num_init(&res->d.n, num->len);
645 bc_program_unarys[inst - BC_INST_NEG](res, num);
646 bc_program_retire(p, 1, 1);
649 static void bc_program_logical(BcProgram *p, uchar inst) {
651 BcResult *opd1, *opd2, *res;
656 res = bc_program_prepResult(p);
658 bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2, 1);
660 if (inst == BC_INST_BOOL_AND)
661 cond = (bc_num_cmpZero(n1) && bc_num_cmpZero(n2));
662 else if (inst == BC_INST_BOOL_OR)
663 cond = (bc_num_cmpZero(n1) || bc_num_cmpZero(n2));
666 cmp = bc_num_cmp(n1, n2);
716 bc_num_init(&res->d.n, BC_NUM_DEF_SIZE);
720 if (cond) bc_num_one(&res->d.n);
722 bc_program_retire(p, 1, 2);
726 static void bc_program_assignStr(BcProgram *p, BcResult *r,
732 n2.scale = r->d.loc.loc;
734 assert(BC_PROG_STACK(&p->results, 1 + !push));
736 if (!push) bc_vec_pop(v);
738 bc_vec_npop(&p->results, 1 + !push);
743 static void bc_program_copyToVar(BcProgram *p, size_t idx,
746 BcResult *ptr = NULL, r;
749 bool var = (t == BC_TYPE_VAR);
754 if (BC_ERR(!BC_PROG_STACK(&p->results, 1)))
755 bc_vm_err(BC_ERR_EXEC_STACK);
757 assert(BC_PROG_STACK(&p->results, 1));
759 bc_program_operand(p, &ptr, &n, 0);
766 ptr = bc_vec_top(&p->results);
768 bc_program_type_match(ptr, t);
770 if (last) n = bc_program_num(p, ptr);
772 n = bc_vec_item_rev(bc_program_vec(p, ptr->d.loc.loc, t), 1);
776 vec = bc_program_vec(p, idx, t);
779 if (BC_IS_DC && (ptr->t == BC_RESULT_STR || BC_PROG_STR(n))) {
780 if (BC_ERR(!var)) bc_vm_err(BC_ERR_EXEC_TYPE);
781 bc_program_assignStr(p, ptr, vec, true);
788 if (var) bc_num_createCopy(&r.d.n, n);
791 BcVec *v = (BcVec*) n, *rv = &r.d.v;
796 parent = bc_program_vec(p, ptr->d.loc.loc, t);
797 assert(parent != NULL);
799 if (!last) v = bc_vec_item_rev(parent, !last);
802 ref = (v->size == sizeof(BcNum) && t == BC_TYPE_REF);
803 ref_size = (v->size == sizeof(uchar));
805 if (ref || (ref_size && t == BC_TYPE_REF)) {
807 bc_vec_init(rv, sizeof(uchar), NULL);
811 assert(parent->len >= (size_t) (!last + 1));
813 // Make sure the pointer was not invalidated.
814 vec = bc_program_vec(p, idx, t);
816 bc_vec_pushIndex(rv, ptr->d.loc.loc);
817 bc_vec_pushIndex(rv, parent->len - !last - 1);
819 // If we get here, we are copying a ref to a ref.
820 else bc_vec_npush(rv, v->len * sizeof(uchar), v->v);
822 // We need to return early.
823 bc_vec_push(vec, &r.d);
824 bc_vec_pop(&p->results);
829 else if (ref_size && t != BC_TYPE_REF) v = bc_program_dereference(p, v);
832 bc_array_init(rv, true);
833 bc_array_copy(rv, v);
836 bc_vec_push(vec, &r.d);
837 bc_vec_pop(&p->results);
842 static void bc_program_assign(BcProgram *p, uchar inst) {
844 BcResult *left, *right, res;
846 bool ob, sc, use_val = BC_INST_USE_VAL(inst);
848 bc_program_assignPrep(p, &left, &l, &right, &r);
851 assert(left->t != BC_RESULT_STR);
853 if (right->t == BC_RESULT_STR || BC_PROG_STR(r)) {
855 size_t idx = right->t == BC_RESULT_STR ? right->d.loc.loc : r->scale;
857 if (left->t == BC_RESULT_ARRAY_ELEM) {
862 bc_vec_npop(&p->results, 2);
866 BcVec *v = bc_program_vec(p, left->d.loc.loc, BC_TYPE_VAR);
867 bc_program_assignStr(p, right, v, false);
874 if (BC_INST_IS_ASSIGN(inst)) bc_num_copy(l, r);
878 BcBigDig scale = BC_PROG_SCALE(p);
881 inst -= (BC_INST_ASSIGN_POWER_NO_VAL - BC_INST_ASSIGN_POWER);
883 assert(BC_NUM_RDX_VALID(l));
884 assert(BC_NUM_RDX_VALID(r));
886 bc_program_ops[inst - BC_INST_ASSIGN_POWER](l, r, l, scale);
890 ob = (left->t == BC_RESULT_OBASE);
891 sc = (left->t == BC_RESULT_SCALE);
893 if (ob || sc || left->t == BC_RESULT_IBASE) {
896 BcBigDig *ptr, *ptr_t, val, max, min;
899 bc_num_bigdig(l, &val);
900 e = left->t - BC_RESULT_IBASE + BC_ERR_EXEC_IBASE;
904 max = vm.maxes[BC_PROG_GLOBALS_SCALE];
905 v = p->globals_v + BC_PROG_GLOBALS_SCALE;
906 ptr_t = p->globals + BC_PROG_GLOBALS_SCALE;
909 min = BC_NUM_MIN_BASE;
910 if (BC_ENABLE_EXTRA_MATH && ob && (BC_IS_DC || !BC_IS_POSIX))
912 max = vm.maxes[ob + BC_PROG_GLOBALS_IBASE];
913 v = p->globals_v + BC_PROG_GLOBALS_IBASE + ob;
914 ptr_t = p->globals + BC_PROG_GLOBALS_IBASE + ob;
917 if (BC_ERR(val > max || val < min)) bc_vm_verr(e, min, max);
923 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
924 else if (left->t == BC_RESULT_SEED) bc_num_rng(l, &p->rng);
925 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
930 bc_num_createCopy(&res.d.n, l);
931 res.t = BC_RESULT_TEMP;
932 bc_vec_npop(&p->results, 2);
933 bc_vec_push(&p->results, &res);
935 else bc_vec_npop(&p->results, 2);
940 static void bc_program_pushVar(BcProgram *p, const char *restrict code,
941 size_t *restrict bgn, bool pop, bool copy)
944 size_t idx = bc_program_index(code, bgn);
950 if (BC_IS_DC && (pop || copy)) {
952 BcVec *v = bc_program_vec(p, idx, BC_TYPE_VAR);
953 BcNum *num = bc_vec_top(v);
955 if (BC_ERR(!BC_PROG_STACK(v, 2 - copy))) bc_vm_err(BC_ERR_EXEC_STACK);
957 assert(BC_PROG_STACK(v, 2 - copy));
959 if (!BC_PROG_STR(num)) {
963 r.t = BC_RESULT_TEMP;
964 bc_num_createCopy(&r.d.n, num);
966 if (!copy) bc_vec_pop(v);
968 bc_vec_push(&p->results, &r);
975 r.d.loc.loc = num->scale;
979 if (!copy) bc_vec_pop(v);
983 bc_vec_push(&p->results, &r);
986 static void bc_program_pushArray(BcProgram *p, const char *restrict code,
987 size_t *restrict bgn, uchar inst)
989 BcResult r, *operand;
993 r.d.loc.loc = bc_program_index(code, bgn);
996 if (inst == BC_INST_ARRAY) {
997 r.t = BC_RESULT_ARRAY;
998 bc_vec_push(&p->results, &r);
1001 #endif // BC_ENABLED
1003 bc_program_prep(p, &operand, &num, 0);
1004 bc_num_bigdig(num, &temp);
1006 r.t = BC_RESULT_ARRAY_ELEM;
1007 r.d.loc.idx = (size_t) temp;
1011 bc_vec_pop(&p->results);
1012 bc_vec_push(&p->results, &r);
1018 static void bc_program_incdec(BcProgram *p, uchar inst) {
1020 BcResult *ptr, res, copy;
1024 bc_program_prep(p, &ptr, &num, 0);
1028 copy.t = BC_RESULT_TEMP;
1029 bc_num_createCopy(©.d.n, num);
1031 BC_SETJMP_LOCKED(exit);
1035 res.t = BC_RESULT_ONE;
1036 inst2 = BC_INST_ASSIGN_PLUS + (inst & 0x01);
1038 bc_vec_push(&p->results, &res);
1039 bc_program_assign(p, inst2);
1043 bc_vec_pop(&p->results);
1044 bc_vec_push(&p->results, ©);
1054 bc_num_free(©.d.n);
1058 static void bc_program_call(BcProgram *p, const char *restrict code,
1059 size_t *restrict idx)
1062 size_t i, nparams = bc_program_index(code, idx);
1070 ip.func = bc_program_index(code, idx);
1071 f = bc_vec_item(&p->fns, ip.func);
1073 if (BC_ERR(!f->code.len)) bc_vm_verr(BC_ERR_EXEC_UNDEF_FUNC, f->name);
1074 if (BC_ERR(nparams != f->nparams))
1075 bc_vm_verr(BC_ERR_EXEC_PARAMS, f->nparams, nparams);
1076 ip.len = p->results.len - nparams;
1078 assert(BC_PROG_STACK(&p->results, nparams));
1080 if (BC_G) bc_program_prepGlobals(p);
1082 for (i = 0; i < nparams; ++i) {
1087 arg = bc_vec_top(&p->results);
1088 if (BC_ERR(arg->t == BC_RESULT_VOID)) bc_vm_err(BC_ERR_EXEC_VOID_VAL);
1090 a = bc_vec_item(&f->autos, nparams - 1 - i);
1092 // If I have already pushed to a var, I need to make sure I
1093 // get the previous version, not the already pushed one.
1094 if (arg->t == BC_RESULT_VAR || arg->t == BC_RESULT_ARRAY) {
1095 for (j = 0; j < i && last; ++j) {
1096 BcLoc *loc = bc_vec_item(&f->autos, nparams - 1 - j);
1097 last = (arg->d.loc.loc != loc->loc ||
1098 (!loc->idx) != (arg->t == BC_RESULT_VAR));
1102 bc_program_copyToVar(p, a->loc, (BcType) a->idx, last);
1107 for (; i < f->autos.len; ++i) {
1109 a = bc_vec_item(&f->autos, i);
1110 v = bc_program_vec(p, a->loc, (BcType) a->idx);
1112 if (a->idx == BC_TYPE_VAR) {
1113 bc_num_init(¶m.n, BC_NUM_DEF_SIZE);
1114 bc_vec_push(v, ¶m.n);
1117 assert(a->idx == BC_TYPE_ARRAY);
1118 bc_array_init(¶m.v, true);
1119 bc_vec_push(v, ¶m.v);
1123 bc_vec_push(&p->stack, &ip);
1128 static void bc_program_return(BcProgram *p, uchar inst) {
1132 BcInstPtr *ip = bc_vec_top(&p->stack);
1133 size_t i, nops = p->results.len - ip->len;
1135 assert(BC_PROG_STACK(&p->stack, 2));
1136 assert(BC_PROG_STACK(&p->results, ip->len + (inst == BC_INST_RET)));
1138 f = bc_vec_item(&p->fns, ip->func);
1139 res = bc_program_prepResult(p);
1141 if (inst == BC_INST_RET) {
1146 bc_program_operand(p, &operand, &num, 1);
1150 bc_num_createCopy(&res->d.n, num);
1152 else if (inst == BC_INST_RET_VOID) res->t = BC_RESULT_VOID;
1155 bc_num_init(&res->d.n, BC_NUM_DEF_SIZE);
1160 // We need to pop arguments as well, so this takes that into account.
1161 for (i = 0; i < f->autos.len; ++i) {
1163 BcLoc *a = bc_vec_item(&f->autos, i);
1164 BcVec *v = bc_program_vec(p, a->loc, (BcType) a->idx);
1169 bc_program_retire(p, 1, nops);
1171 if (BC_G) bc_program_popGlobals(p, false);
1173 bc_vec_pop(&p->stack);
1175 #endif // BC_ENABLED
1177 static void bc_program_builtin(BcProgram *p, uchar inst) {
1179 BcResult *opd, *res;
1181 bool len = (inst == BC_INST_LENGTH);
1183 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1184 assert(inst >= BC_INST_LENGTH && inst <= BC_INST_IRAND);
1185 #else // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1186 assert(inst >= BC_INST_LENGTH && inst <= BC_INST_ABS);
1187 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1189 #ifndef BC_PROG_NO_STACK_CHECK
1191 if (BC_ERR(!BC_PROG_STACK(&p->results, 1)))
1192 bc_vm_err(BC_ERR_EXEC_STACK);
1194 #endif // BC_PROG_NO_STACK_CHECK
1196 assert(BC_PROG_STACK(&p->results, 1));
1198 res = bc_program_prepResult(p);
1200 bc_program_operand(p, &opd, &num, 1);
1202 assert(num != NULL);
1205 if (!len && inst != BC_INST_SCALE_FUNC) bc_program_type_num(opd, num);
1206 #endif // DC_ENABLED
1208 if (inst == BC_INST_SQRT) bc_num_sqrt(num, &res->d.n, BC_PROG_SCALE(p));
1209 else if (inst == BC_INST_ABS) {
1213 bc_num_createCopy(&res->d.n, num);
1217 BC_NUM_NEG_CLR_NP(res->d.n);
1219 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1220 else if (inst == BC_INST_IRAND) {
1224 bc_num_init(&res->d.n, num->len - num->rdx);
1228 bc_num_irand(num, &res->d.n, &p->rng);
1230 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1237 if (BC_IS_BC && opd->t == BC_RESULT_ARRAY) {
1239 BcVec *v = (BcVec*) num;
1241 if (v->size == sizeof(uchar)) v = bc_program_dereference(p, v);
1243 assert(v->size == sizeof(BcNum));
1245 val = (BcBigDig) v->len;
1248 #endif // BC_ENABLED
1251 if (!BC_PROG_NUM(opd, num)) {
1254 idx = opd->t == BC_RESULT_STR ? opd->d.loc.loc : num->scale;
1255 str = *((char**) bc_vec_item(p->strs, idx));
1256 val = (BcBigDig) strlen(str);
1259 #endif // DC_ENABLED
1261 val = (BcBigDig) bc_num_len(num);
1265 else if (BC_IS_BC || BC_PROG_NUM(opd, num))
1266 val = (BcBigDig) bc_num_scale(num);
1270 bc_num_createFromBigdig(&res->d.n, val);
1275 bc_program_retire(p, 1, 1);
1279 static void bc_program_divmod(BcProgram *p) {
1281 BcResult *opd1, *opd2, *res, *res2;
1285 bc_vec_grow(&p->results, 2);
1287 // We don't need to update the pointer because
1288 // the capacity is enough due to the line above.
1289 res2 = bc_program_prepResult(p);
1290 res = bc_program_prepResult(p);
1292 bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2, 2);
1294 req = bc_num_mulReq(n1, n2, BC_PROG_SCALE(p));
1298 bc_num_init(&res->d.n, req);
1299 bc_num_init(&res2->d.n, req);
1303 bc_num_divmod(n1, n2, &res2->d.n, &res->d.n, BC_PROG_SCALE(p));
1305 bc_program_retire(p, 2, 2);
1308 static void bc_program_modexp(BcProgram *p) {
1310 BcResult *r1, *r2, *r3, *res;
1311 BcNum *n1, *n2, *n3;
1313 if (BC_ERR(!BC_PROG_STACK(&p->results, 3))) bc_vm_err(BC_ERR_EXEC_STACK);
1315 assert(BC_PROG_STACK(&p->results, 3));
1317 res = bc_program_prepResult(p);
1319 bc_program_operand(p, &r1, &n1, 3);
1320 bc_program_type_num(r1, n1);
1322 bc_program_binOpPrep(p, &r2, &n2, &r3, &n3, 1);
1324 // Make sure that the values have their pointers updated, if necessary.
1325 // Only array elements are possible.
1326 if (r1->t == BC_RESULT_ARRAY_ELEM && (r1->t == r2->t || r1->t == r3->t))
1327 n1 = bc_program_num(p, r1);
1331 bc_num_init(&res->d.n, n3->len);
1335 bc_num_modexp(n1, n2, n3, &res->d.n);
1337 bc_program_retire(p, 1, 3);
1340 static void bc_program_stackLen(BcProgram *p) {
1341 bc_program_pushBigdig(p, (BcBigDig) p->results.len, BC_RESULT_TEMP);
1344 static uchar bc_program_asciifyNum(BcProgram *p, BcNum *n) {
1355 bc_num_createCopy(&num, n);
1359 bc_num_truncate(&num, num.scale);
1360 BC_NUM_NEG_CLR_NP(num);
1362 // This is guaranteed to not have a divide by 0
1363 // because strmb is equal to UCHAR_MAX + 1.
1364 bc_num_mod(&num, &p->strmb, &num, 0);
1366 // This is also guaranteed to not error because num is in the range
1367 // [0, UCHAR_MAX], which is definitely in range for a BcBigDig. And
1368 // it is not negative.
1369 bc_num_bigdig2(&num, &val);
1378 static void bc_program_asciify(BcProgram *p) {
1386 if (BC_ERR(!BC_PROG_STACK(&p->results, 1))) bc_vm_err(BC_ERR_EXEC_STACK);
1388 assert(BC_PROG_STACK(&p->results, 1));
1390 bc_program_operand(p, &r, &n, 0);
1394 assert(p->strs->len + BC_PROG_REQ_FUNCS == p->fns.len);
1396 if (BC_PROG_NUM(r, n)) c = bc_program_asciifyNum(p, n);
1398 size_t index = r->t == BC_RESULT_STR ? r->d.loc.loc : n->scale;
1399 str2 = *((char**) bc_vec_item(p->strs, index));
1400 c = (uchar) str2[0];
1408 idx = bc_program_insertFunc(p, str) - BC_PROG_REQ_FUNCS;
1412 res.t = BC_RESULT_STR;
1413 res.d.loc.loc = idx;
1414 bc_vec_pop(&p->results);
1415 bc_vec_push(&p->results, &res);
1418 static void bc_program_printStream(BcProgram *p) {
1423 if (BC_ERR(!BC_PROG_STACK(&p->results, 1))) bc_vm_err(BC_ERR_EXEC_STACK);
1425 assert(BC_PROG_STACK(&p->results, 1));
1427 bc_program_operand(p, &r, &n, 0);
1431 if (BC_PROG_NUM(r, n)) bc_num_stream(n, p->strm);
1433 size_t idx = (r->t == BC_RESULT_STR) ? r->d.loc.loc : n->scale;
1434 bc_program_printChars(*((char**) bc_vec_item(p->strs, idx)));
1438 static void bc_program_nquit(BcProgram *p, uchar inst) {
1445 assert(p->stack.len == p->tail_calls.len);
1447 if (inst == BC_INST_QUIT) val = 2;
1450 bc_program_prep(p, &opnd, &num, 0);
1451 bc_num_bigdig(num, &val);
1453 bc_vec_pop(&p->results);
1456 for (i = 0; val && i < p->tail_calls.len; ++i) {
1457 size_t calls = *((size_t*) bc_vec_item_rev(&p->tail_calls, i)) + 1;
1458 if (calls >= val) val = 0;
1462 if (i == p->stack.len) {
1463 vm.status = BC_STATUS_QUIT;
1467 bc_vec_npop(&p->stack, i);
1468 bc_vec_npop(&p->tail_calls, i);
1472 static void bc_program_execStr(BcProgram *p, const char *restrict code,
1473 size_t *restrict bgn, bool cond, size_t len)
1483 assert(p->stack.len == p->tail_calls.len);
1485 if (BC_ERR(!BC_PROG_STACK(&p->results, 1))) bc_vm_err(BC_ERR_EXEC_STACK);
1487 assert(BC_PROG_STACK(&p->results, 1));
1489 bc_program_operand(p, &r, &n, 0);
1494 size_t idx, then_idx, else_idx;
1496 then_idx = bc_program_index(code, bgn);
1497 else_idx = bc_program_index(code, bgn);
1499 exec = (r->d.n.len != 0);
1501 idx = exec ? then_idx : else_idx;
1504 BC_SETJMP_LOCKED(exit);
1506 if (exec || (else_idx != SIZE_MAX))
1507 n = bc_vec_top(bc_program_vec(p, idx, BC_TYPE_VAR));
1510 if (BC_ERR(!BC_PROG_STR(n))) bc_vm_err(BC_ERR_EXEC_TYPE);
1519 // In non-conditional situations, only the top of stack can be executed,
1520 // and in those cases, variables are not allowed to be "on the stack";
1521 // they are only put on the stack to be assigned to.
1522 assert(r->t != BC_RESULT_VAR);
1524 if (r->t == BC_RESULT_STR) sidx = r->d.loc.loc;
1528 fidx = sidx + BC_PROG_REQ_FUNCS;
1529 str = *((char**) bc_vec_item(p->strs, sidx));
1530 f = bc_vec_item(&p->fns, fidx);
1536 bc_parse_init(&prs, p, fidx);
1537 bc_lex_file(&prs.l, vm.file);
1539 BC_SETJMP_LOCKED(err);
1543 bc_parse_text(&prs, str);
1544 vm.expr(&prs, BC_PARSE_NOCALL);
1550 // We can just assert this here because
1551 // dc should parse everything until EOF.
1552 assert(prs.l.t == BC_LEX_EOF);
1554 bc_parse_free(&prs);
1560 ip.len = p->results.len;
1563 bc_vec_pop(&p->results);
1566 if (p->stack.len > 1 && *bgn == len - 1 && code[*bgn] == BC_INST_POP_EXEC) {
1567 size_t *call_ptr = bc_vec_top(&p->tail_calls);
1569 bc_vec_pop(&p->stack);
1571 else bc_vec_push(&p->tail_calls, &ip.idx);
1573 bc_vec_push(&p->stack, &ip);
1579 bc_parse_free(&prs);
1580 f = bc_vec_item(&p->fns, fidx);
1581 bc_vec_npop(&f->code, f->code.len);
1583 bc_vec_pop(&p->results);
1587 static void bc_program_printStack(BcProgram *p) {
1591 for (idx = 0; idx < p->results.len; ++idx)
1592 bc_program_print(p, BC_INST_PRINT, idx);
1594 #endif // DC_ENABLED
1596 static void bc_program_pushGlobal(BcProgram *p, uchar inst) {
1600 assert(inst >= BC_INST_IBASE && inst <= BC_INST_SCALE);
1602 t = inst - BC_INST_IBASE + BC_RESULT_IBASE;
1603 bc_program_pushBigdig(p, p->globals[inst - BC_INST_IBASE], t);
1606 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1607 static void bc_program_pushSeed(BcProgram *p) {
1611 res = bc_program_prepResult(p);
1612 res->t = BC_RESULT_SEED;
1616 bc_num_init(&res->d.n, 2 * BC_RAND_NUM_SIZE);
1620 bc_num_createFromRNG(&res->d.n, &p->rng);
1622 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1624 static void bc_program_addFunc(BcProgram *p, BcFunc *f, BcId *id_ptr) {
1628 BC_SIG_ASSERT_LOCKED;
1630 bc_func_init(f, id_ptr->name);
1631 bc_vec_push(&p->fns, f);
1633 // This is to make sure pointers are updated if the array was moved.
1635 ip = bc_vec_top(&p->stack);
1636 bc_program_setVecs(p, (BcFunc*) bc_vec_item(&p->fns, ip->func));
1640 size_t bc_program_insertFunc(BcProgram *p, const char *name) {
1647 BC_SIG_ASSERT_LOCKED;
1649 assert(p != NULL && name != NULL);
1651 new = bc_map_insert(&p->fn_map, name, p->fns.len, &idx);
1652 id_ptr = (BcId*) bc_vec_item(&p->fn_map, idx);
1657 BcFunc *func = bc_vec_item(&p->fns, idx);
1658 bc_func_reset(func);
1663 bc_program_addFunc(p, &f, id_ptr);
1666 if (BC_IS_DC && idx >= BC_PROG_REQ_FUNCS) {
1667 bc_vec_push(p->strs, &id_ptr->name);
1668 assert(p->strs->len == p->fns.len - BC_PROG_REQ_FUNCS);
1670 #endif // DC_ENABLED
1677 void bc_program_free(BcProgram *p) {
1681 BC_SIG_ASSERT_LOCKED;
1685 for (i = 0; i < BC_PROG_GLOBALS_LEN; ++i) bc_vec_free(p->globals_v + i);
1687 bc_vec_free(&p->fns);
1688 bc_vec_free(&p->fn_map);
1689 bc_vec_free(&p->vars);
1690 bc_vec_free(&p->var_map);
1691 bc_vec_free(&p->arrs);
1692 bc_vec_free(&p->arr_map);
1693 bc_vec_free(&p->results);
1694 bc_vec_free(&p->stack);
1697 if (BC_IS_BC) bc_num_free(&p->last);
1698 #endif // BC_ENABLED
1700 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1701 bc_rand_free(&p->rng);
1702 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1706 bc_vec_free(&p->tail_calls);
1707 bc_vec_free(&p->strs_v);
1709 #endif // DC_ENABLED
1713 void bc_program_init(BcProgram *p) {
1717 BcBigDig val = BC_BASE;
1719 BC_SIG_ASSERT_LOCKED;
1723 memset(p, 0, sizeof(BcProgram));
1724 memset(&ip, 0, sizeof(BcInstPtr));
1726 for (i = 0; i < BC_PROG_GLOBALS_LEN; ++i) {
1727 bc_vec_init(p->globals_v + i, sizeof(BcBigDig), NULL);
1728 val = i == BC_PROG_GLOBALS_SCALE ? 0 : val;
1729 bc_vec_push(p->globals_v + i, &val);
1730 p->globals[i] = val;
1736 bc_vec_init(&p->strs_v, sizeof(char*), bc_string_free);
1737 p->strs = &p->strs_v;
1739 bc_vec_init(&p->tail_calls, sizeof(size_t), NULL);
1741 bc_vec_push(&p->tail_calls, &i);
1743 p->strm = UCHAR_MAX + 1;
1744 bc_num_setup(&p->strmb, p->strmb_num, BC_NUM_BIGDIG_LOG10);
1745 bc_num_bigdig2num(&p->strmb, p->strm);
1747 #endif // DC_ENABLED
1749 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1750 srand((unsigned int) time(NULL));
1751 bc_rand_init(&p->rng);
1752 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1754 bc_num_setup(&p->zero, p->zero_num, BC_PROG_ONE_CAP);
1756 bc_num_setup(&p->one, p->one_num, BC_PROG_ONE_CAP);
1757 bc_num_one(&p->one);
1760 if (BC_IS_BC) bc_num_init(&p->last, BC_NUM_DEF_SIZE);
1761 #endif // BC_ENABLED
1763 bc_vec_init(&p->fns, sizeof(BcFunc), bc_func_free);
1764 bc_map_init(&p->fn_map);
1765 bc_program_insertFunc(p, bc_func_main);
1766 bc_program_insertFunc(p, bc_func_read);
1768 bc_vec_init(&p->vars, sizeof(BcVec), bc_vec_free);
1769 bc_map_init(&p->var_map);
1771 bc_vec_init(&p->arrs, sizeof(BcVec), bc_vec_free);
1772 bc_map_init(&p->arr_map);
1774 bc_vec_init(&p->results, sizeof(BcResult), bc_result_free);
1775 bc_vec_init(&p->stack, sizeof(BcInstPtr), NULL);
1776 bc_vec_push(&p->stack, &ip);
1778 bc_program_setVecs(p, (BcFunc*) bc_vec_item(&p->fns, BC_PROG_MAIN));
1780 assert(p->consts != NULL && p->strs != NULL);
1783 void bc_program_reset(BcProgram *p) {
1788 BC_SIG_ASSERT_LOCKED;
1790 bc_vec_npop(&p->stack, p->stack.len - 1);
1791 bc_vec_npop(&p->results, p->results.len);
1794 if (BC_G) bc_program_popGlobals(p, true);
1795 #endif // BC_ENABLED
1797 f = bc_vec_item(&p->fns, BC_PROG_MAIN);
1798 ip = bc_vec_top(&p->stack);
1799 bc_program_setVecs(p, f);
1800 ip->idx = f->code.len;
1803 bc_file_write(&vm.fout, bc_program_ready_msg, bc_program_ready_msg_len);
1804 bc_file_flush(&vm.fout);
1809 void bc_program_exec(BcProgram *p) {
1813 BcInstPtr *ip = bc_vec_top(&p->stack);
1814 BcFunc *func = (BcFunc*) bc_vec_item(&p->fns, ip->func);
1815 char *code = func->code.v;
1819 #endif // BC_ENABLED
1821 size_t jmp_bufs_len;
1825 jmp_bufs_len = vm.jmp_bufs.len;
1828 bc_program_setVecs(p, func);
1830 while (ip->idx < func->code.len) {
1832 BC_SIG_ASSERT_NOT_LOCKED;
1834 uchar inst = (uchar) code[(ip->idx)++];
1839 case BC_INST_JUMP_ZERO:
1841 bc_program_prep(p, &ptr, &num, 0);
1842 cond = !bc_num_cmpZero(num);
1843 bc_vec_pop(&p->results);
1850 idx = bc_program_index(code, &ip->idx);
1852 if (inst == BC_INST_JUMP || cond) {
1854 size_t *addr = bc_vec_item(&func->labels, idx);
1856 assert(*addr != SIZE_MAX);
1868 bc_program_call(p, code, &ip->idx);
1870 ip = bc_vec_top(&p->stack);
1871 func = bc_vec_item(&p->fns, ip->func);
1872 code = func->code.v;
1874 bc_program_setVecs(p, func);
1882 bc_program_incdec(p, inst);
1888 vm.status = BC_STATUS_QUIT;
1895 case BC_INST_RET_VOID:
1897 bc_program_return(p, inst);
1899 ip = bc_vec_top(&p->stack);
1900 func = bc_vec_item(&p->fns, ip->func);
1901 code = func->code.v;
1903 bc_program_setVecs(p, func);
1907 #endif // BC_ENABLED
1909 case BC_INST_BOOL_OR:
1910 case BC_INST_BOOL_AND:
1911 case BC_INST_REL_EQ:
1912 case BC_INST_REL_LE:
1913 case BC_INST_REL_GE:
1914 case BC_INST_REL_NE:
1915 case BC_INST_REL_LT:
1916 case BC_INST_REL_GT:
1918 bc_program_logical(p, inst);
1926 ip = bc_vec_top(&p->stack);
1927 func = bc_vec_item(&p->fns, ip->func);
1928 code = func->code.v;
1930 bc_program_setVecs(p, func);
1935 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1941 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1943 case BC_INST_MAXIBASE:
1944 case BC_INST_MAXOBASE:
1945 case BC_INST_MAXSCALE:
1946 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1947 case BC_INST_MAXRAND:
1948 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1950 BcBigDig dig = vm.maxes[inst - BC_INST_MAXIBASE];
1951 bc_program_pushBigdig(p, dig, BC_RESULT_TEMP);
1957 bc_program_pushVar(p, code, &ip->idx, false, false);
1961 case BC_INST_ARRAY_ELEM:
1964 #endif // BC_ENABLED
1966 bc_program_pushArray(p, code, &ip->idx, inst);
1974 bc_program_pushGlobal(p, inst);
1978 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1981 bc_program_pushSeed(p);
1984 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1986 case BC_INST_LENGTH:
1987 case BC_INST_SCALE_FUNC:
1990 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1992 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1994 bc_program_builtin(p, inst);
2000 bc_program_const(p, code, &ip->idx);
2008 #endif // BC_ENABLED
2010 r.t = BC_RESULT_ZERO + (inst - BC_INST_ZERO);
2011 bc_vec_push(&p->results, &r);
2016 case BC_INST_PRINT_POP:
2017 case BC_INST_PRINT_STR:
2019 bc_program_print(p, inst, 0);
2025 r.t = BC_RESULT_STR;
2026 r.d.loc.loc = bc_program_index(code, &ip->idx);
2027 bc_vec_push(&p->results, &r);
2032 case BC_INST_MULTIPLY:
2033 case BC_INST_DIVIDE:
2034 case BC_INST_MODULUS:
2037 #if BC_ENABLE_EXTRA_MATH
2038 case BC_INST_PLACES:
2039 case BC_INST_LSHIFT:
2040 case BC_INST_RSHIFT:
2041 #endif // BC_ENABLE_EXTRA_MATH
2043 bc_program_op(p, inst);
2048 case BC_INST_BOOL_NOT:
2049 #if BC_ENABLE_EXTRA_MATH
2051 #endif // BC_ENABLE_EXTRA_MATH
2053 bc_program_unary(p, inst);
2058 case BC_INST_ASSIGN_POWER:
2059 case BC_INST_ASSIGN_MULTIPLY:
2060 case BC_INST_ASSIGN_DIVIDE:
2061 case BC_INST_ASSIGN_MODULUS:
2062 case BC_INST_ASSIGN_PLUS:
2063 case BC_INST_ASSIGN_MINUS:
2064 #if BC_ENABLE_EXTRA_MATH
2065 case BC_INST_ASSIGN_PLACES:
2066 case BC_INST_ASSIGN_LSHIFT:
2067 case BC_INST_ASSIGN_RSHIFT:
2068 #endif // BC_ENABLE_EXTRA_MATH
2069 case BC_INST_ASSIGN:
2070 case BC_INST_ASSIGN_POWER_NO_VAL:
2071 case BC_INST_ASSIGN_MULTIPLY_NO_VAL:
2072 case BC_INST_ASSIGN_DIVIDE_NO_VAL:
2073 case BC_INST_ASSIGN_MODULUS_NO_VAL:
2074 case BC_INST_ASSIGN_PLUS_NO_VAL:
2075 case BC_INST_ASSIGN_MINUS_NO_VAL:
2076 #if BC_ENABLE_EXTRA_MATH
2077 case BC_INST_ASSIGN_PLACES_NO_VAL:
2078 case BC_INST_ASSIGN_LSHIFT_NO_VAL:
2079 case BC_INST_ASSIGN_RSHIFT_NO_VAL:
2080 #endif // BC_ENABLE_EXTRA_MATH
2081 #endif // BC_ENABLED
2082 case BC_INST_ASSIGN_NO_VAL:
2084 bc_program_assign(p, inst);
2090 #ifndef BC_PROG_NO_STACK_CHECK
2092 if (BC_ERR(!BC_PROG_STACK(&p->results, 1)))
2093 bc_vm_err(BC_ERR_EXEC_STACK);
2095 #endif // BC_PROG_NO_STACK_CHECK
2097 assert(BC_PROG_STACK(&p->results, 1));
2099 bc_vec_pop(&p->results);
2104 case BC_INST_POP_EXEC:
2106 assert(BC_PROG_STACK(&p->stack, 2));
2107 bc_vec_pop(&p->stack);
2108 bc_vec_pop(&p->tail_calls);
2109 ip = bc_vec_top(&p->stack);
2110 func = bc_vec_item(&p->fns, ip->func);
2111 code = func->code.v;
2112 bc_program_setVecs(p, func);
2116 case BC_INST_MODEXP:
2118 bc_program_modexp(p);
2122 case BC_INST_DIVMOD:
2124 bc_program_divmod(p);
2128 case BC_INST_EXECUTE:
2129 case BC_INST_EXEC_COND:
2131 cond = (inst == BC_INST_EXEC_COND);
2132 bc_program_execStr(p, code, &ip->idx, cond, func->code.len);
2133 ip = bc_vec_top(&p->stack);
2134 func = bc_vec_item(&p->fns, ip->func);
2135 code = func->code.v;
2136 bc_program_setVecs(p, func);
2140 case BC_INST_PRINT_STACK:
2142 bc_program_printStack(p);
2146 case BC_INST_CLEAR_STACK:
2148 bc_vec_npop(&p->results, p->results.len);
2152 case BC_INST_STACK_LEN:
2154 bc_program_stackLen(p);
2158 case BC_INST_DUPLICATE:
2160 if (BC_ERR(!BC_PROG_STACK(&p->results, 1)))
2161 bc_vm_err(BC_ERR_EXEC_STACK);
2163 assert(BC_PROG_STACK(&p->results, 1));
2165 ptr = bc_vec_top(&p->results);
2169 bc_result_copy(&r, ptr);
2170 bc_vec_push(&p->results, &r);
2181 if (BC_ERR(!BC_PROG_STACK(&p->results, 2)))
2182 bc_vm_err(BC_ERR_EXEC_STACK);
2184 assert(BC_PROG_STACK(&p->results, 2));
2186 ptr = bc_vec_item_rev(&p->results, 0);
2187 ptr2 = bc_vec_item_rev(&p->results, 1);
2188 memcpy(&r, ptr, sizeof(BcResult));
2189 memcpy(ptr, ptr2, sizeof(BcResult));
2190 memcpy(ptr2, &r, sizeof(BcResult));
2195 case BC_INST_ASCIIFY:
2197 bc_program_asciify(p);
2198 ip = bc_vec_top(&p->stack);
2199 func = bc_vec_item(&p->fns, ip->func);
2200 code = func->code.v;
2201 bc_program_setVecs(p, func);
2205 case BC_INST_PRINT_STREAM:
2207 bc_program_printStream(p);
2212 case BC_INST_PUSH_VAR:
2214 bool copy = (inst == BC_INST_LOAD);
2215 bc_program_pushVar(p, code, &ip->idx, true, copy);
2219 case BC_INST_PUSH_TO_VAR:
2221 idx = bc_program_index(code, &ip->idx);
2222 bc_program_copyToVar(p, idx, BC_TYPE_VAR, true);
2229 bc_program_nquit(p, inst);
2230 ip = bc_vec_top(&p->stack);
2231 func = bc_vec_item(&p->fns, ip->func);
2232 code = func->code.v;
2233 bc_program_setVecs(p, func);
2236 #endif // DC_ENABLED
2246 // This is to allow me to use a debugger to see the last instruction,
2247 // which will point to which function was the problem.
2248 assert(jmp_bufs_len == vm.jmp_bufs.len);
2254 #if BC_ENABLED && DC_ENABLED
2255 void bc_program_printStackDebug(BcProgram *p) {
2256 bc_file_puts(&vm.fout, "-------------- Stack ----------\n");
2257 bc_program_printStack(p);
2258 bc_file_puts(&vm.fout, "-------------- Stack End ------\n");
2261 static void bc_program_printIndex(const char *restrict code,
2262 size_t *restrict bgn)
2264 uchar byte, i, bytes = (uchar) code[(*bgn)++];
2267 for (byte = 1, i = 0; byte && i < bytes; ++i) {
2268 byte = (uchar) code[(*bgn)++];
2269 if (byte) val |= ((ulong) byte) << (CHAR_BIT * i);
2272 bc_vm_printf(" (%lu) ", val);
2275 static void bc_program_printStr(const BcProgram *p, const char *restrict code,
2276 size_t *restrict bgn)
2278 size_t idx = bc_program_index(code, bgn);
2281 s = *((char**) bc_vec_item(p->strs, idx));
2283 bc_vm_printf(" (\"%s\") ", s);
2286 void bc_program_printInst(const BcProgram *p, const char *restrict code,
2287 size_t *restrict bgn)
2289 uchar inst = (uchar) code[(*bgn)++];
2291 bc_vm_printf("Inst[%zu]: %s [%lu]; ", *bgn - 1,
2292 bc_inst_names[inst], (unsigned long) inst);
2294 if (inst == BC_INST_VAR || inst == BC_INST_ARRAY_ELEM ||
2295 inst == BC_INST_ARRAY)
2297 bc_program_printIndex(code, bgn);
2299 else if (inst == BC_INST_STR) bc_program_printStr(p, code, bgn);
2300 else if (inst == BC_INST_NUM) {
2301 size_t idx = bc_program_index(code, bgn);
2302 BcConst *c = bc_vec_item(p->consts, idx);
2303 bc_vm_printf("(%s)", c->val);
2305 else if (inst == BC_INST_CALL ||
2306 (inst > BC_INST_STR && inst <= BC_INST_JUMP_ZERO))
2308 bc_program_printIndex(code, bgn);
2309 if (inst == BC_INST_CALL) bc_program_printIndex(code, bgn);
2312 bc_vm_putchar('\n');
2315 void bc_program_code(const BcProgram* p) {
2322 for (i = 0; i < p->fns.len; ++i) {
2324 ip.idx = ip.len = 0;
2327 f = bc_vec_item(&p->fns, ip.func);
2330 bc_vm_printf("func[%zu]:\n", ip.func);
2331 while (ip.idx < f->code.len) bc_program_printInst(p, code, &ip.idx);
2332 bc_file_puts(&vm.fout, "\n\n");
2335 #endif // BC_ENABLED && DC_ENABLED
2336 #endif // BC_DEBUG_CODE