1 /* 2 * ***************************************************************************** 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 * 6 * Copyright (c) 2018-2021 Gavin D. Howard and contributors. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions are met: 10 * 11 * * Redistributions of source code must retain the above copyright notice, this 12 * list of conditions and the following disclaimer. 13 * 14 * * Redistributions in binary form must reproduce the above copyright notice, 15 * this list of conditions and the following disclaimer in the documentation 16 * and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGE. 29 * 30 * ***************************************************************************** 31 * 32 * Code to execute bc programs. 33 * 34 */ 35 36 #include <assert.h> 37 #include <stdbool.h> 38 #include <string.h> 39 40 #include <setjmp.h> 41 42 #include <signal.h> 43 44 #include <time.h> 45 46 #include <read.h> 47 #include <parse.h> 48 #include <program.h> 49 #include <vm.h> 50 51 static void bc_program_addFunc(BcProgram *p, BcFunc *f, BcId *id_ptr); 52 53 static inline void bc_program_setVecs(BcProgram *p, BcFunc *f) { 54 p->consts = &f->consts; 55 if (BC_IS_BC) p->strs = &f->strs; 56 } 57 58 static inline void bc_program_type_num(BcResult *r, BcNum *n) { 59 60 #if BC_ENABLED 61 assert(r->t != BC_RESULT_VOID); 62 #endif // BC_ENABLED 63 64 if (BC_ERR(!BC_PROG_NUM(r, n))) bc_vm_err(BC_ERR_EXEC_TYPE); 65 } 66 67 #if BC_ENABLED 68 static void bc_program_type_match(BcResult *r, BcType t) { 69 70 #if DC_ENABLED 71 assert(BC_IS_DC || BC_NO_ERR(r->t != BC_RESULT_STR)); 72 #endif // DC_ENABLED 73 74 if (BC_ERR((r->t != BC_RESULT_ARRAY) != (!t))) 75 bc_vm_err(BC_ERR_EXEC_TYPE); 76 } 77 #endif // BC_ENABLED 78 79 static size_t bc_program_index(const char *restrict code, size_t *restrict bgn) 80 { 81 uchar amt = (uchar) code[(*bgn)++], i = 0; 82 size_t res = 0; 83 84 for (; i < amt; ++i, ++(*bgn)) { 85 size_t temp = ((size_t) ((int) (uchar) code[*bgn]) & UCHAR_MAX); 86 res |= (temp << (i * CHAR_BIT)); 87 } 88 89 return res; 90 } 91 92 #if BC_ENABLED 93 static void bc_program_prepGlobals(BcProgram *p) { 94 95 size_t i; 96 97 for (i = 0; i < BC_PROG_GLOBALS_LEN; ++i) 98 bc_vec_push(p->globals_v + i, p->globals + i); 99 100 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND 101 bc_rand_push(&p->rng); 102 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND 103 } 104 105 static void bc_program_popGlobals(BcProgram *p, bool reset) { 106 107 size_t i; 108 109 for (i = 0; i < BC_PROG_GLOBALS_LEN; ++i) { 110 BcVec *v = p->globals_v + i; 111 bc_vec_npop(v, reset ? v->len - 1 : 1); 112 p->globals[i] = BC_PROG_GLOBAL(v); 113 } 114 115 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND 116 bc_rand_pop(&p->rng, reset); 117 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND 118 } 119 #endif // BC_ENABLED 120 121 static void bc_program_pushBigdig(BcProgram *p, BcBigDig dig, BcResultType type) 122 { 123 BcResult res; 124 125 res.t = type; 126 127 BC_SIG_LOCK; 128 129 bc_num_createFromBigdig(&res.d.n, dig); 130 bc_vec_push(&p->results, &res); 131 132 BC_SIG_UNLOCK; 133 } 134 135 #if BC_ENABLED 136 static BcVec* bc_program_dereference(const BcProgram *p, BcVec *vec) { 137 138 BcVec *v; 139 size_t vidx, nidx, i = 0; 140 141 assert(vec->size == sizeof(uchar)); 142 143 vidx = bc_program_index(vec->v, &i); 144 nidx = bc_program_index(vec->v, &i); 145 146 v = bc_vec_item(bc_vec_item(&p->arrs, vidx), nidx); 147 148 assert(v->size != sizeof(uchar)); 149 150 return v; 151 } 152 #endif // BC_ENABLED 153 154 size_t bc_program_search(BcProgram *p, const char *id, bool var) { 155 156 BcVec *v, *map; 157 size_t i; 158 BcResultData data; 159 160 v = var ? &p->vars : &p->arrs; 161 map = var ? &p->var_map : &p->arr_map; 162 163 BC_SIG_LOCK; 164 165 if (bc_map_insert(map, id, v->len, &i)) { 166 bc_array_init(&data.v, var); 167 bc_vec_push(v, &data.v); 168 } 169 170 BC_SIG_UNLOCK; 171 172 return ((BcId*) bc_vec_item(map, i))->idx; 173 } 174 175 static inline BcVec* bc_program_vec(const BcProgram *p, size_t idx, BcType type) 176 { 177 const BcVec *v = (type == BC_TYPE_VAR) ? &p->vars : &p->arrs; 178 return bc_vec_item(v, idx); 179 } 180 181 static BcNum* bc_program_num(BcProgram *p, BcResult *r) { 182 183 BcNum *n; 184 185 switch (r->t) { 186 187 case BC_RESULT_STR: 188 case BC_RESULT_TEMP: 189 case BC_RESULT_IBASE: 190 case BC_RESULT_SCALE: 191 case BC_RESULT_OBASE: 192 #if BC_ENABLE_EXTRA_MATH 193 case BC_RESULT_SEED: 194 #endif // BC_ENABLE_EXTRA_MATH 195 { 196 n = &r->d.n; 197 break; 198 } 199 200 case BC_RESULT_VAR: 201 #if BC_ENABLED 202 case BC_RESULT_ARRAY: 203 #endif // BC_ENABLED 204 case BC_RESULT_ARRAY_ELEM: 205 { 206 BcVec *v; 207 BcType type = (r->t == BC_RESULT_VAR) ? BC_TYPE_VAR : BC_TYPE_ARRAY; 208 209 v = bc_program_vec(p, r->d.loc.loc, type); 210 211 if (r->t == BC_RESULT_ARRAY_ELEM) { 212 213 size_t idx = r->d.loc.idx; 214 215 v = bc_vec_top(v); 216 217 #if BC_ENABLED 218 if (v->size == sizeof(uchar)) v = bc_program_dereference(p, v); 219 #endif // BC_ENABLED 220 221 assert(v->size == sizeof(BcNum)); 222 223 if (v->len <= idx) { 224 BC_SIG_LOCK; 225 bc_array_expand(v, bc_vm_growSize(idx, 1)); 226 BC_SIG_UNLOCK; 227 } 228 229 n = bc_vec_item(v, idx); 230 } 231 else n = bc_vec_top(v); 232 233 break; 234 } 235 236 case BC_RESULT_ZERO: 237 { 238 n = &p->zero; 239 break; 240 } 241 242 case BC_RESULT_ONE: 243 { 244 n = &p->one; 245 break; 246 } 247 248 #if BC_ENABLED 249 case BC_RESULT_VOID: 250 #ifndef NDEBUG 251 { 252 abort(); 253 } 254 #endif // NDEBUG 255 // Fallthrough 256 case BC_RESULT_LAST: 257 { 258 n = &p->last; 259 break; 260 } 261 #endif // BC_ENABLED 262 } 263 264 return n; 265 } 266 267 static void bc_program_operand(BcProgram *p, BcResult **r, 268 BcNum **n, size_t idx) 269 { 270 *r = bc_vec_item_rev(&p->results, idx); 271 272 #if BC_ENABLED 273 if (BC_ERR((*r)->t == BC_RESULT_VOID)) bc_vm_err(BC_ERR_EXEC_VOID_VAL); 274 #endif // BC_ENABLED 275 276 *n = bc_program_num(p, *r); 277 } 278 279 static void bc_program_binPrep(BcProgram *p, BcResult **l, BcNum **ln, 280 BcResult **r, BcNum **rn, size_t idx) 281 { 282 BcResultType lt; 283 284 assert(p != NULL && l != NULL && ln != NULL && r != NULL && rn != NULL); 285 286 #ifndef BC_PROG_NO_STACK_CHECK 287 if (BC_IS_DC) { 288 if (BC_ERR(!BC_PROG_STACK(&p->results, idx + 2))) 289 bc_vm_err(BC_ERR_EXEC_STACK); 290 } 291 #endif // BC_PROG_NO_STACK_CHECK 292 293 assert(BC_PROG_STACK(&p->results, idx + 2)); 294 295 bc_program_operand(p, l, ln, idx + 1); 296 bc_program_operand(p, r, rn, idx); 297 298 lt = (*l)->t; 299 300 #if BC_ENABLED 301 assert(lt != BC_RESULT_VOID && (*r)->t != BC_RESULT_VOID); 302 #endif // BC_ENABLED 303 304 // We run this again under these conditions in case any vector has been 305 // reallocated out from under the BcNums or arrays we had. 306 if (lt == (*r)->t && (lt == BC_RESULT_VAR || lt == BC_RESULT_ARRAY_ELEM)) 307 *ln = bc_program_num(p, *l); 308 309 if (BC_ERR(lt == BC_RESULT_STR)) bc_vm_err(BC_ERR_EXEC_TYPE); 310 } 311 312 static void bc_program_binOpPrep(BcProgram *p, BcResult **l, BcNum **ln, 313 BcResult **r, BcNum **rn, size_t idx) 314 { 315 bc_program_binPrep(p, l, ln, r, rn, idx); 316 bc_program_type_num(*l, *ln); 317 bc_program_type_num(*r, *rn); 318 } 319 320 static void bc_program_assignPrep(BcProgram *p, BcResult **l, BcNum **ln, 321 BcResult **r, BcNum **rn) 322 { 323 BcResultType lt, min; 324 325 min = BC_RESULT_TEMP - ((unsigned int) (BC_IS_BC)); 326 327 bc_program_binPrep(p, l, ln, r, rn, 0); 328 329 lt = (*l)->t; 330 331 if (BC_ERR(lt >= min && lt <= BC_RESULT_ONE)) 332 bc_vm_err(BC_ERR_EXEC_TYPE); 333 334 #if DC_ENABLED 335 if(BC_IS_DC) { 336 337 bool good = (((*r)->t == BC_RESULT_STR || BC_PROG_STR(*rn)) && 338 lt <= BC_RESULT_ARRAY_ELEM); 339 340 if (!good) bc_program_type_num(*r, *rn); 341 } 342 #else 343 assert((*r)->t != BC_RESULT_STR); 344 #endif // DC_ENABLED 345 } 346 347 static void bc_program_prep(BcProgram *p, BcResult **r, BcNum **n, size_t idx) { 348 349 assert(p != NULL && r != NULL && n != NULL); 350 351 #ifndef BC_PROG_NO_STACK_CHECK 352 if (BC_IS_DC) { 353 if (BC_ERR(!BC_PROG_STACK(&p->results, idx + 1))) 354 bc_vm_err(BC_ERR_EXEC_STACK); 355 } 356 #endif // BC_PROG_NO_STACK_CHECK 357 358 assert(BC_PROG_STACK(&p->results, idx + 1)); 359 360 bc_program_operand(p, r, n, idx); 361 362 #if DC_ENABLED 363 assert((*r)->t != BC_RESULT_VAR || !BC_PROG_STR(*n)); 364 #endif // DC_ENABLED 365 366 bc_program_type_num(*r, *n); 367 } 368 369 static BcResult* bc_program_prepResult(BcProgram *p) { 370 371 BcResult res; 372 373 bc_result_clear(&res); 374 bc_vec_push(&p->results, &res); 375 376 return bc_vec_top(&p->results); 377 } 378 379 static void bc_program_const(BcProgram *p, const char *code, size_t *bgn) { 380 381 BcResult *r = bc_program_prepResult(p); 382 BcConst *c = bc_vec_item(p->consts, bc_program_index(code, bgn)); 383 BcBigDig base = BC_PROG_IBASE(p); 384 385 if (c->base != base) { 386 387 if (c->num.num == NULL) { 388 BC_SIG_LOCK; 389 bc_num_init(&c->num, BC_NUM_RDX(strlen(c->val))); 390 BC_SIG_UNLOCK; 391 } 392 393 // bc_num_parse() should only do operations that cannot fail. 394 bc_num_parse(&c->num, c->val, base); 395 396 c->base = base; 397 } 398 399 BC_SIG_LOCK; 400 401 bc_num_createCopy(&r->d.n, &c->num); 402 403 BC_SIG_UNLOCK; 404 } 405 406 static void bc_program_op(BcProgram *p, uchar inst) { 407 408 BcResult *opd1, *opd2, *res; 409 BcNum *n1, *n2; 410 size_t idx = inst - BC_INST_POWER; 411 412 res = bc_program_prepResult(p); 413 414 bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2, 1); 415 416 BC_SIG_LOCK; 417 418 bc_num_init(&res->d.n, bc_program_opReqs[idx](n1, n2, BC_PROG_SCALE(p))); 419 420 BC_SIG_UNLOCK; 421 422 assert(BC_NUM_RDX_VALID(n1)); 423 assert(BC_NUM_RDX_VALID(n2)); 424 425 bc_program_ops[idx](n1, n2, &res->d.n, BC_PROG_SCALE(p)); 426 427 bc_program_retire(p, 1, 2); 428 } 429 430 static void bc_program_read(BcProgram *p) { 431 432 BcStatus s; 433 BcParse parse; 434 BcVec buf; 435 BcInstPtr ip; 436 size_t i; 437 const char* file; 438 BcFunc *f = bc_vec_item(&p->fns, BC_PROG_READ); 439 440 for (i = 0; i < p->stack.len; ++i) { 441 BcInstPtr *ip_ptr = bc_vec_item(&p->stack, i); 442 if (ip_ptr->func == BC_PROG_READ) 443 bc_vm_err(BC_ERR_EXEC_REC_READ); 444 } 445 446 BC_SIG_LOCK; 447 448 file = vm.file; 449 bc_parse_init(&parse, p, BC_PROG_READ); 450 bc_vec_init(&buf, sizeof(char), NULL); 451 452 BC_SETJMP_LOCKED(exec_err); 453 454 BC_SIG_UNLOCK; 455 456 bc_lex_file(&parse.l, bc_program_stdin_name); 457 bc_vec_popAll(&f->code); 458 459 s = bc_read_line(&buf, BC_IS_BC ? "read> " : "?> "); 460 if (s == BC_STATUS_EOF) bc_vm_err(BC_ERR_EXEC_READ_EXPR); 461 462 bc_parse_text(&parse, buf.v); 463 vm.expr(&parse, BC_PARSE_NOREAD | BC_PARSE_NEEDVAL); 464 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); 467 468 #if BC_ENABLED 469 if (BC_G) bc_program_prepGlobals(p); 470 #endif // BC_ENABLED 471 472 ip.func = BC_PROG_READ; 473 ip.idx = 0; 474 ip.len = p->results.len; 475 476 // Update this pointer, just in case. 477 f = bc_vec_item(&p->fns, BC_PROG_READ); 478 479 bc_vec_pushByte(&f->code, vm.read_ret); 480 bc_vec_push(&p->stack, &ip); 481 482 #if DC_ENABLED 483 if (BC_IS_DC) { 484 size_t temp = 0; 485 bc_vec_push(&p->tail_calls, &temp); 486 } 487 #endif // DC_ENABLED 488 489 exec_err: 490 BC_SIG_MAYLOCK; 491 bc_parse_free(&parse); 492 bc_vec_free(&buf); 493 vm.file = file; 494 BC_LONGJMP_CONT; 495 } 496 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); 501 #ifndef NDEBUG 502 { 503 BcResult *r = bc_vec_top(&p->results); 504 assert(BC_NUM_RDX_VALID_NP(r->d.n)); 505 } 506 #endif // NDEBUG 507 } 508 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND 509 510 static void bc_program_printChars(const char *str) { 511 512 const char *nl; 513 size_t len = vm.nchars + strlen(str); 514 515 bc_file_puts(&vm.fout, str); 516 nl = strrchr(str, '\n'); 517 518 if (nl != NULL) len = strlen(nl + 1); 519 520 vm.nchars = len > UINT16_MAX ? UINT16_MAX : (uint16_t) len; 521 } 522 523 static void bc_program_printString(const char *restrict str) { 524 525 size_t i, len = strlen(str); 526 527 #if DC_ENABLED 528 if (!len && BC_IS_DC) { 529 bc_vm_putchar('\0'); 530 return; 531 } 532 #endif // DC_ENABLED 533 534 for (i = 0; i < len; ++i) { 535 536 int c = str[i]; 537 538 if (c == '\\' && i != len - 1) { 539 540 const char *ptr; 541 542 c = str[++i]; 543 ptr = strchr(bc_program_esc_chars, c); 544 545 if (ptr != NULL) { 546 if (c == 'n') vm.nchars = UINT16_MAX; 547 c = bc_program_esc_seqs[(size_t) (ptr - bc_program_esc_chars)]; 548 } 549 else { 550 // Just print the backslash. The following 551 // character will be printed later. 552 bc_vm_putchar('\\'); 553 } 554 } 555 556 bc_vm_putchar(c); 557 } 558 } 559 560 static void bc_program_print(BcProgram *p, uchar inst, size_t idx) { 561 562 BcResult *r; 563 char *str; 564 BcNum *n; 565 bool pop = (inst != BC_INST_PRINT); 566 567 assert(p != NULL); 568 569 #ifndef BC_PROG_NO_STACK_CHECK 570 if (BC_IS_DC) { 571 if (BC_ERR(!BC_PROG_STACK(&p->results, idx + 1))) 572 bc_vm_err(BC_ERR_EXEC_STACK); 573 } 574 #endif // BC_PROG_NO_STACK_CHECK 575 576 assert(BC_PROG_STACK(&p->results, idx + 1)); 577 578 r = bc_vec_item_rev(&p->results, idx); 579 580 #if BC_ENABLED 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); 584 return; 585 } 586 #endif // BC_ENABLED 587 588 n = bc_program_num(p, r); 589 590 if (BC_PROG_NUM(r, n)) { 591 assert(inst != BC_INST_PRINT_STR); 592 bc_num_print(n, BC_PROG_OBASE(p), !pop); 593 #if BC_ENABLED 594 if (BC_IS_BC) bc_num_copy(&p->last, n); 595 #endif // BC_ENABLED 596 } 597 else { 598 599 size_t i = (r->t == BC_RESULT_STR) ? r->d.loc.loc : n->scale; 600 601 bc_file_flush(&vm.fout); 602 str = *((char**) bc_vec_item(p->strs, i)); 603 604 if (inst == BC_INST_PRINT_STR) bc_program_printChars(str); 605 else { 606 bc_program_printString(str); 607 if (inst == BC_INST_PRINT) bc_vm_putchar('\n'); 608 } 609 } 610 611 if (BC_IS_BC || pop) bc_vec_pop(&p->results); 612 } 613 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); 617 } 618 619 void bc_program_not(BcResult *r, BcNum *n) { 620 if (!bc_num_cmpZero(n)) bc_num_one(&r->d.n); 621 } 622 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); 627 } 628 #endif // BC_ENABLE_EXTRA_MATH 629 630 static void bc_program_unary(BcProgram *p, uchar inst) { 631 632 BcResult *res, *ptr; 633 BcNum *num; 634 635 res = bc_program_prepResult(p); 636 637 bc_program_prep(p, &ptr, &num, 1); 638 639 BC_SIG_LOCK; 640 641 bc_num_init(&res->d.n, num->len); 642 643 BC_SIG_UNLOCK; 644 645 bc_program_unarys[inst - BC_INST_NEG](res, num); 646 bc_program_retire(p, 1, 1); 647 } 648 649 static void bc_program_logical(BcProgram *p, uchar inst) { 650 651 BcResult *opd1, *opd2, *res; 652 BcNum *n1, *n2; 653 bool cond = 0; 654 ssize_t cmp; 655 656 res = bc_program_prepResult(p); 657 658 bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2, 1); 659 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)); 664 else { 665 666 cmp = bc_num_cmp(n1, n2); 667 668 switch (inst) { 669 670 case BC_INST_REL_EQ: 671 { 672 cond = (cmp == 0); 673 break; 674 } 675 676 case BC_INST_REL_LE: 677 { 678 cond = (cmp <= 0); 679 break; 680 } 681 682 case BC_INST_REL_GE: 683 { 684 cond = (cmp >= 0); 685 break; 686 } 687 688 case BC_INST_REL_NE: 689 { 690 cond = (cmp != 0); 691 break; 692 } 693 694 case BC_INST_REL_LT: 695 { 696 cond = (cmp < 0); 697 break; 698 } 699 700 case BC_INST_REL_GT: 701 { 702 cond = (cmp > 0); 703 break; 704 } 705 #ifndef NDEBUG 706 default: 707 { 708 abort(); 709 } 710 #endif // NDEBUG 711 } 712 } 713 714 BC_SIG_LOCK; 715 716 bc_num_init(&res->d.n, BC_NUM_DEF_SIZE); 717 718 BC_SIG_UNLOCK; 719 720 if (cond) bc_num_one(&res->d.n); 721 722 bc_program_retire(p, 1, 2); 723 } 724 725 #if DC_ENABLED 726 static void bc_program_assignStr(BcProgram *p, size_t idx, 727 BcVec *v, bool push) 728 { 729 BcNum n2; 730 731 bc_num_clear(&n2); 732 n2.scale = idx; 733 734 assert(BC_PROG_STACK(&p->results, 1 + !push)); 735 736 if (!push) bc_vec_pop(v); 737 738 bc_vec_npop(&p->results, 1 + !push); 739 bc_vec_push(v, &n2); 740 } 741 #endif // DC_ENABLED 742 743 static void bc_program_copyToVar(BcProgram *p, size_t idx, 744 BcType t, bool last) 745 { 746 BcResult *ptr = NULL, r; 747 BcVec *vec; 748 BcNum *n = NULL; 749 bool var = (t == BC_TYPE_VAR); 750 751 #if DC_ENABLED 752 if (BC_IS_DC) { 753 754 if (BC_ERR(!BC_PROG_STACK(&p->results, 1))) 755 bc_vm_err(BC_ERR_EXEC_STACK); 756 757 assert(BC_PROG_STACK(&p->results, 1)); 758 759 bc_program_operand(p, &ptr, &n, 0); 760 } 761 #endif 762 763 #if BC_ENABLED 764 if (BC_IS_BC) 765 { 766 ptr = bc_vec_top(&p->results); 767 768 bc_program_type_match(ptr, t); 769 770 if (last) n = bc_program_num(p, ptr); 771 else if (var) 772 n = bc_vec_item_rev(bc_program_vec(p, ptr->d.loc.loc, t), 1); 773 } 774 #endif // BC_ENABLED 775 776 vec = bc_program_vec(p, idx, t); 777 778 #if DC_ENABLED 779 if (BC_IS_DC && (ptr->t == BC_RESULT_STR || BC_PROG_STR(n))) { 780 781 size_t str_idx = ptr->t == BC_RESULT_STR ? ptr->d.loc.loc : n->scale; 782 783 if (BC_ERR(!var)) bc_vm_err(BC_ERR_EXEC_TYPE); 784 785 bc_program_assignStr(p, str_idx, vec, true); 786 787 return; 788 } 789 #endif // DC_ENABLED 790 791 BC_SIG_LOCK; 792 793 if (var) bc_num_createCopy(&r.d.n, n); 794 else { 795 796 BcVec *v = (BcVec*) n, *rv = &r.d.v; 797 #if BC_ENABLED 798 BcVec *parent; 799 bool ref, ref_size; 800 801 parent = bc_program_vec(p, ptr->d.loc.loc, t); 802 assert(parent != NULL); 803 804 if (!last) v = bc_vec_item_rev(parent, !last); 805 assert(v != NULL); 806 807 ref = (v->size == sizeof(BcNum) && t == BC_TYPE_REF); 808 ref_size = (v->size == sizeof(uchar)); 809 810 if (ref || (ref_size && t == BC_TYPE_REF)) { 811 812 bc_vec_init(rv, sizeof(uchar), NULL); 813 814 if (ref) { 815 816 assert(parent->len >= (size_t) (!last + 1)); 817 818 // Make sure the pointer was not invalidated. 819 vec = bc_program_vec(p, idx, t); 820 821 bc_vec_pushIndex(rv, ptr->d.loc.loc); 822 bc_vec_pushIndex(rv, parent->len - !last - 1); 823 } 824 // If we get here, we are copying a ref to a ref. 825 else bc_vec_npush(rv, v->len * sizeof(uchar), v->v); 826 827 // We need to return early. 828 bc_vec_push(vec, &r.d); 829 bc_vec_pop(&p->results); 830 831 BC_SIG_UNLOCK; 832 return; 833 } 834 else if (ref_size && t != BC_TYPE_REF) v = bc_program_dereference(p, v); 835 #endif // BC_ENABLED 836 837 bc_array_init(rv, true); 838 bc_array_copy(rv, v); 839 } 840 841 bc_vec_push(vec, &r.d); 842 bc_vec_pop(&p->results); 843 844 BC_SIG_UNLOCK; 845 } 846 847 static void bc_program_assign(BcProgram *p, uchar inst) { 848 849 BcResult *left, *right, res; 850 BcNum *l, *r; 851 bool ob, sc, use_val = BC_INST_USE_VAL(inst); 852 853 bc_program_assignPrep(p, &left, &l, &right, &r); 854 855 #if DC_ENABLED 856 assert(left->t != BC_RESULT_STR); 857 858 if (right->t == BC_RESULT_STR || BC_PROG_STR(r)) { 859 860 size_t idx = right->t == BC_RESULT_STR ? right->d.loc.loc : r->scale; 861 862 if (left->t == BC_RESULT_ARRAY_ELEM) { 863 BC_SIG_LOCK; 864 bc_num_free(l); 865 bc_num_clear(l); 866 l->scale = idx; 867 bc_vec_npop(&p->results, 2); 868 BC_SIG_UNLOCK; 869 } 870 else { 871 BcVec *v = bc_program_vec(p, left->d.loc.loc, BC_TYPE_VAR); 872 bc_program_assignStr(p, idx, v, false); 873 } 874 875 return; 876 } 877 #endif // DC_ENABLED 878 879 if (BC_INST_IS_ASSIGN(inst)) bc_num_copy(l, r); 880 #if BC_ENABLED 881 else { 882 883 BcBigDig scale = BC_PROG_SCALE(p); 884 885 if (!use_val) 886 inst -= (BC_INST_ASSIGN_POWER_NO_VAL - BC_INST_ASSIGN_POWER); 887 888 assert(BC_NUM_RDX_VALID(l)); 889 assert(BC_NUM_RDX_VALID(r)); 890 891 bc_program_ops[inst - BC_INST_ASSIGN_POWER](l, r, l, scale); 892 } 893 #endif // BC_ENABLED 894 895 ob = (left->t == BC_RESULT_OBASE); 896 sc = (left->t == BC_RESULT_SCALE); 897 898 if (ob || sc || left->t == BC_RESULT_IBASE) { 899 900 BcVec *v; 901 BcBigDig *ptr, *ptr_t, val, max, min; 902 BcErr e; 903 904 bc_num_bigdig(l, &val); 905 e = left->t - BC_RESULT_IBASE + BC_ERR_EXEC_IBASE; 906 907 if (sc) { 908 min = 0; 909 max = vm.maxes[BC_PROG_GLOBALS_SCALE]; 910 v = p->globals_v + BC_PROG_GLOBALS_SCALE; 911 ptr_t = p->globals + BC_PROG_GLOBALS_SCALE; 912 } 913 else { 914 min = BC_NUM_MIN_BASE; 915 if (BC_ENABLE_EXTRA_MATH && ob && (BC_IS_DC || !BC_IS_POSIX)) 916 min = 0; 917 max = vm.maxes[ob + BC_PROG_GLOBALS_IBASE]; 918 v = p->globals_v + BC_PROG_GLOBALS_IBASE + ob; 919 ptr_t = p->globals + BC_PROG_GLOBALS_IBASE + ob; 920 } 921 922 if (BC_ERR(val > max || val < min)) bc_vm_verr(e, min, max); 923 924 ptr = bc_vec_top(v); 925 *ptr = val; 926 *ptr_t = val; 927 } 928 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND 929 else if (left->t == BC_RESULT_SEED) bc_num_rng(l, &p->rng); 930 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND 931 932 BC_SIG_LOCK; 933 934 if (use_val) { 935 bc_num_createCopy(&res.d.n, l); 936 res.t = BC_RESULT_TEMP; 937 bc_vec_npop(&p->results, 2); 938 bc_vec_push(&p->results, &res); 939 } 940 else bc_vec_npop(&p->results, 2); 941 942 BC_SIG_UNLOCK; 943 } 944 945 static void bc_program_pushVar(BcProgram *p, const char *restrict code, 946 size_t *restrict bgn, bool pop, bool copy) 947 { 948 BcResult r; 949 size_t idx = bc_program_index(code, bgn); 950 951 r.t = BC_RESULT_VAR; 952 r.d.loc.loc = idx; 953 954 #if DC_ENABLED 955 if (BC_IS_DC && (pop || copy)) { 956 957 BcVec *v = bc_program_vec(p, idx, BC_TYPE_VAR); 958 BcNum *num = bc_vec_top(v); 959 960 if (BC_ERR(!BC_PROG_STACK(v, 2 - copy))) bc_vm_err(BC_ERR_EXEC_STACK); 961 962 assert(BC_PROG_STACK(v, 2 - copy)); 963 964 if (!BC_PROG_STR(num)) { 965 966 BC_SIG_LOCK; 967 968 r.t = BC_RESULT_TEMP; 969 bc_num_createCopy(&r.d.n, num); 970 971 if (!copy) bc_vec_pop(v); 972 973 bc_vec_push(&p->results, &r); 974 975 BC_SIG_UNLOCK; 976 977 return; 978 } 979 else { 980 r.d.loc.loc = num->scale; 981 r.t = BC_RESULT_STR; 982 } 983 984 if (!copy) bc_vec_pop(v); 985 } 986 #endif // DC_ENABLED 987 988 bc_vec_push(&p->results, &r); 989 } 990 991 static void bc_program_pushArray(BcProgram *p, const char *restrict code, 992 size_t *restrict bgn, uchar inst) 993 { 994 BcResult r, *operand; 995 BcNum *num; 996 BcBigDig temp; 997 998 r.d.loc.loc = bc_program_index(code, bgn); 999 1000 #if BC_ENABLED 1001 if (inst == BC_INST_ARRAY) { 1002 r.t = BC_RESULT_ARRAY; 1003 bc_vec_push(&p->results, &r); 1004 return; 1005 } 1006 #endif // BC_ENABLED 1007 1008 bc_program_prep(p, &operand, &num, 0); 1009 bc_num_bigdig(num, &temp); 1010 1011 r.t = BC_RESULT_ARRAY_ELEM; 1012 r.d.loc.idx = (size_t) temp; 1013 1014 BC_SIG_LOCK; 1015 1016 bc_vec_pop(&p->results); 1017 bc_vec_push(&p->results, &r); 1018 1019 BC_SIG_UNLOCK; 1020 } 1021 1022 #if BC_ENABLED 1023 static void bc_program_incdec(BcProgram *p, uchar inst) { 1024 1025 BcResult *ptr, res, copy; 1026 BcNum *num; 1027 uchar inst2; 1028 1029 bc_program_prep(p, &ptr, &num, 0); 1030 1031 BC_SIG_LOCK; 1032 1033 copy.t = BC_RESULT_TEMP; 1034 bc_num_createCopy(©.d.n, num); 1035 1036 BC_SETJMP_LOCKED(exit); 1037 1038 BC_SIG_UNLOCK; 1039 1040 res.t = BC_RESULT_ONE; 1041 inst2 = BC_INST_ASSIGN_PLUS + (inst & 0x01); 1042 1043 bc_vec_push(&p->results, &res); 1044 bc_program_assign(p, inst2); 1045 1046 BC_SIG_LOCK; 1047 1048 bc_vec_pop(&p->results); 1049 bc_vec_push(&p->results, ©); 1050 1051 BC_UNSETJMP; 1052 1053 BC_SIG_UNLOCK; 1054 1055 return; 1056 1057 exit: 1058 BC_SIG_MAYLOCK; 1059 bc_num_free(©.d.n); 1060 BC_LONGJMP_CONT; 1061 } 1062 1063 static void bc_program_call(BcProgram *p, const char *restrict code, 1064 size_t *restrict idx) 1065 { 1066 BcInstPtr ip; 1067 size_t i, nparams = bc_program_index(code, idx); 1068 BcFunc *f; 1069 BcVec *v; 1070 BcLoc *a; 1071 BcResultData param; 1072 BcResult *arg; 1073 1074 ip.idx = 0; 1075 ip.func = bc_program_index(code, idx); 1076 f = bc_vec_item(&p->fns, ip.func); 1077 1078 if (BC_ERR(!f->code.len)) bc_vm_verr(BC_ERR_EXEC_UNDEF_FUNC, f->name); 1079 if (BC_ERR(nparams != f->nparams)) 1080 bc_vm_verr(BC_ERR_EXEC_PARAMS, f->nparams, nparams); 1081 ip.len = p->results.len - nparams; 1082 1083 assert(BC_PROG_STACK(&p->results, nparams)); 1084 1085 if (BC_G) bc_program_prepGlobals(p); 1086 1087 for (i = 0; i < nparams; ++i) { 1088 1089 size_t j; 1090 bool last = true; 1091 1092 arg = bc_vec_top(&p->results); 1093 if (BC_ERR(arg->t == BC_RESULT_VOID)) bc_vm_err(BC_ERR_EXEC_VOID_VAL); 1094 1095 a = bc_vec_item(&f->autos, nparams - 1 - i); 1096 1097 // If I have already pushed to a var, I need to make sure I 1098 // get the previous version, not the already pushed one. 1099 if (arg->t == BC_RESULT_VAR || arg->t == BC_RESULT_ARRAY) { 1100 for (j = 0; j < i && last; ++j) { 1101 BcLoc *loc = bc_vec_item(&f->autos, nparams - 1 - j); 1102 last = (arg->d.loc.loc != loc->loc || 1103 (!loc->idx) != (arg->t == BC_RESULT_VAR)); 1104 } 1105 } 1106 1107 bc_program_copyToVar(p, a->loc, (BcType) a->idx, last); 1108 } 1109 1110 BC_SIG_LOCK; 1111 1112 for (; i < f->autos.len; ++i) { 1113 1114 a = bc_vec_item(&f->autos, i); 1115 v = bc_program_vec(p, a->loc, (BcType) a->idx); 1116 1117 if (a->idx == BC_TYPE_VAR) { 1118 bc_num_init(¶m.n, BC_NUM_DEF_SIZE); 1119 bc_vec_push(v, ¶m.n); 1120 } 1121 else { 1122 assert(a->idx == BC_TYPE_ARRAY); 1123 bc_array_init(¶m.v, true); 1124 bc_vec_push(v, ¶m.v); 1125 } 1126 } 1127 1128 bc_vec_push(&p->stack, &ip); 1129 1130 BC_SIG_UNLOCK; 1131 } 1132 1133 static void bc_program_return(BcProgram *p, uchar inst) { 1134 1135 BcResult *res; 1136 BcFunc *f; 1137 BcInstPtr *ip = bc_vec_top(&p->stack); 1138 size_t i, nops = p->results.len - ip->len; 1139 1140 assert(BC_PROG_STACK(&p->stack, 2)); 1141 assert(BC_PROG_STACK(&p->results, ip->len + (inst == BC_INST_RET))); 1142 1143 f = bc_vec_item(&p->fns, ip->func); 1144 res = bc_program_prepResult(p); 1145 1146 if (inst == BC_INST_RET) { 1147 1148 BcNum *num; 1149 BcResult *operand; 1150 1151 bc_program_operand(p, &operand, &num, 1); 1152 1153 BC_SIG_LOCK; 1154 1155 bc_num_createCopy(&res->d.n, num); 1156 } 1157 else if (inst == BC_INST_RET_VOID) res->t = BC_RESULT_VOID; 1158 else { 1159 BC_SIG_LOCK; 1160 bc_num_init(&res->d.n, BC_NUM_DEF_SIZE); 1161 } 1162 1163 BC_SIG_MAYUNLOCK; 1164 1165 // We need to pop arguments as well, so this takes that into account. 1166 for (i = 0; i < f->autos.len; ++i) { 1167 1168 BcLoc *a = bc_vec_item(&f->autos, i); 1169 BcVec *v = bc_program_vec(p, a->loc, (BcType) a->idx); 1170 1171 bc_vec_pop(v); 1172 } 1173 1174 bc_program_retire(p, 1, nops); 1175 1176 if (BC_G) bc_program_popGlobals(p, false); 1177 1178 bc_vec_pop(&p->stack); 1179 } 1180 #endif // BC_ENABLED 1181 1182 static void bc_program_builtin(BcProgram *p, uchar inst) { 1183 1184 BcResult *opd, *res; 1185 BcNum *num; 1186 bool len = (inst == BC_INST_LENGTH); 1187 1188 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND 1189 assert(inst >= BC_INST_LENGTH && inst <= BC_INST_IRAND); 1190 #else // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND 1191 assert(inst >= BC_INST_LENGTH && inst <= BC_INST_ABS); 1192 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND 1193 1194 #ifndef BC_PROG_NO_STACK_CHECK 1195 if (BC_IS_DC) { 1196 if (BC_ERR(!BC_PROG_STACK(&p->results, 1))) 1197 bc_vm_err(BC_ERR_EXEC_STACK); 1198 } 1199 #endif // BC_PROG_NO_STACK_CHECK 1200 1201 assert(BC_PROG_STACK(&p->results, 1)); 1202 1203 res = bc_program_prepResult(p); 1204 1205 bc_program_operand(p, &opd, &num, 1); 1206 1207 assert(num != NULL); 1208 1209 #if DC_ENABLED 1210 if (!len && inst != BC_INST_SCALE_FUNC) bc_program_type_num(opd, num); 1211 #endif // DC_ENABLED 1212 1213 if (inst == BC_INST_SQRT) bc_num_sqrt(num, &res->d.n, BC_PROG_SCALE(p)); 1214 else if (inst == BC_INST_ABS) { 1215 1216 BC_SIG_LOCK; 1217 1218 bc_num_createCopy(&res->d.n, num); 1219 1220 BC_SIG_UNLOCK; 1221 1222 BC_NUM_NEG_CLR_NP(res->d.n); 1223 } 1224 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND 1225 else if (inst == BC_INST_IRAND) { 1226 1227 BC_SIG_LOCK; 1228 1229 bc_num_init(&res->d.n, num->len - num->rdx); 1230 1231 BC_SIG_UNLOCK; 1232 1233 bc_num_irand(num, &res->d.n, &p->rng); 1234 } 1235 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND 1236 else { 1237 1238 BcBigDig val = 0; 1239 1240 if (len) { 1241 #if BC_ENABLED 1242 if (BC_IS_BC && opd->t == BC_RESULT_ARRAY) { 1243 1244 BcVec *v = (BcVec*) num; 1245 1246 if (v->size == sizeof(uchar)) v = bc_program_dereference(p, v); 1247 1248 assert(v->size == sizeof(BcNum)); 1249 1250 val = (BcBigDig) v->len; 1251 } 1252 else 1253 #endif // BC_ENABLED 1254 { 1255 #if DC_ENABLED 1256 if (!BC_PROG_NUM(opd, num)) { 1257 1258 size_t idx; 1259 char *str; 1260 1261 idx = opd->t == BC_RESULT_STR ? opd->d.loc.loc : num->scale; 1262 str = *((char**) bc_vec_item(p->strs, idx)); 1263 val = (BcBigDig) strlen(str); 1264 } 1265 else 1266 #endif // DC_ENABLED 1267 { 1268 val = (BcBigDig) bc_num_len(num); 1269 } 1270 } 1271 } 1272 else if (BC_IS_BC || BC_PROG_NUM(opd, num)) 1273 val = (BcBigDig) bc_num_scale(num); 1274 1275 BC_SIG_LOCK; 1276 1277 bc_num_createFromBigdig(&res->d.n, val); 1278 1279 BC_SIG_UNLOCK; 1280 } 1281 1282 bc_program_retire(p, 1, 1); 1283 } 1284 1285 #if DC_ENABLED 1286 static void bc_program_divmod(BcProgram *p) { 1287 1288 BcResult *opd1, *opd2, *res, *res2; 1289 BcNum *n1, *n2; 1290 size_t req; 1291 1292 bc_vec_grow(&p->results, 2); 1293 1294 // We don't need to update the pointer because 1295 // the capacity is enough due to the line above. 1296 res2 = bc_program_prepResult(p); 1297 res = bc_program_prepResult(p); 1298 1299 bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2, 2); 1300 1301 req = bc_num_mulReq(n1, n2, BC_PROG_SCALE(p)); 1302 1303 BC_SIG_LOCK; 1304 1305 bc_num_init(&res->d.n, req); 1306 bc_num_init(&res2->d.n, req); 1307 1308 BC_SIG_UNLOCK; 1309 1310 bc_num_divmod(n1, n2, &res2->d.n, &res->d.n, BC_PROG_SCALE(p)); 1311 1312 bc_program_retire(p, 2, 2); 1313 } 1314 1315 static void bc_program_modexp(BcProgram *p) { 1316 1317 BcResult *r1, *r2, *r3, *res; 1318 BcNum *n1, *n2, *n3; 1319 1320 if (BC_ERR(!BC_PROG_STACK(&p->results, 3))) bc_vm_err(BC_ERR_EXEC_STACK); 1321 1322 assert(BC_PROG_STACK(&p->results, 3)); 1323 1324 res = bc_program_prepResult(p); 1325 1326 bc_program_operand(p, &r1, &n1, 3); 1327 bc_program_type_num(r1, n1); 1328 1329 bc_program_binOpPrep(p, &r2, &n2, &r3, &n3, 1); 1330 1331 // Make sure that the values have their pointers updated, if necessary. 1332 // Only array elements are possible. 1333 if (r1->t == BC_RESULT_ARRAY_ELEM && (r1->t == r2->t || r1->t == r3->t)) 1334 n1 = bc_program_num(p, r1); 1335 1336 BC_SIG_LOCK; 1337 1338 bc_num_init(&res->d.n, n3->len); 1339 1340 BC_SIG_UNLOCK; 1341 1342 bc_num_modexp(n1, n2, n3, &res->d.n); 1343 1344 bc_program_retire(p, 1, 3); 1345 } 1346 1347 static void bc_program_stackLen(BcProgram *p) { 1348 bc_program_pushBigdig(p, (BcBigDig) p->results.len, BC_RESULT_TEMP); 1349 } 1350 1351 static uchar bc_program_asciifyNum(BcProgram *p, BcNum *n) { 1352 1353 BcNum num; 1354 BcBigDig val = 0; 1355 1356 bc_num_clear(&num); 1357 1358 BC_SETJMP(num_err); 1359 1360 BC_SIG_LOCK; 1361 1362 bc_num_createCopy(&num, n); 1363 1364 BC_SIG_UNLOCK; 1365 1366 bc_num_truncate(&num, num.scale); 1367 BC_NUM_NEG_CLR_NP(num); 1368 1369 // This is guaranteed to not have a divide by 0 1370 // because strmb is equal to UCHAR_MAX + 1. 1371 bc_num_mod(&num, &p->strmb, &num, 0); 1372 1373 // This is also guaranteed to not error because num is in the range 1374 // [0, UCHAR_MAX], which is definitely in range for a BcBigDig. And 1375 // it is not negative. 1376 bc_num_bigdig2(&num, &val); 1377 1378 num_err: 1379 BC_SIG_MAYLOCK; 1380 bc_num_free(&num); 1381 BC_LONGJMP_CONT; 1382 return (uchar) val; 1383 } 1384 1385 static void bc_program_asciify(BcProgram *p) { 1386 1387 BcResult *r, res; 1388 BcNum *n; 1389 char str[2], *str2; 1390 uchar c; 1391 size_t idx; 1392 1393 if (BC_ERR(!BC_PROG_STACK(&p->results, 1))) bc_vm_err(BC_ERR_EXEC_STACK); 1394 1395 assert(BC_PROG_STACK(&p->results, 1)); 1396 1397 bc_program_operand(p, &r, &n, 0); 1398 1399 assert(n != NULL); 1400 1401 assert(p->strs->len + BC_PROG_REQ_FUNCS == p->fns.len); 1402 1403 if (BC_PROG_NUM(r, n)) c = bc_program_asciifyNum(p, n); 1404 else { 1405 size_t index = r->t == BC_RESULT_STR ? r->d.loc.loc : n->scale; 1406 str2 = *((char**) bc_vec_item(p->strs, index)); 1407 c = (uchar) str2[0]; 1408 } 1409 1410 str[0] = (char) c; 1411 str[1] = '\0'; 1412 1413 BC_SIG_LOCK; 1414 1415 idx = bc_program_insertFunc(p, str) - BC_PROG_REQ_FUNCS; 1416 1417 BC_SIG_UNLOCK; 1418 1419 res.t = BC_RESULT_STR; 1420 res.d.loc.loc = idx; 1421 bc_vec_pop(&p->results); 1422 bc_vec_push(&p->results, &res); 1423 } 1424 1425 static void bc_program_printStream(BcProgram *p) { 1426 1427 BcResult *r; 1428 BcNum *n; 1429 1430 if (BC_ERR(!BC_PROG_STACK(&p->results, 1))) bc_vm_err(BC_ERR_EXEC_STACK); 1431 1432 assert(BC_PROG_STACK(&p->results, 1)); 1433 1434 bc_program_operand(p, &r, &n, 0); 1435 1436 assert(n != NULL); 1437 1438 if (BC_PROG_NUM(r, n)) bc_num_stream(n, p->strm); 1439 else { 1440 size_t idx = (r->t == BC_RESULT_STR) ? r->d.loc.loc : n->scale; 1441 bc_program_printChars(*((char**) bc_vec_item(p->strs, idx))); 1442 } 1443 } 1444 1445 static void bc_program_nquit(BcProgram *p, uchar inst) { 1446 1447 BcResult *opnd; 1448 BcNum *num; 1449 BcBigDig val; 1450 size_t i; 1451 1452 assert(p->stack.len == p->tail_calls.len); 1453 1454 if (inst == BC_INST_QUIT) val = 2; 1455 else { 1456 1457 bc_program_prep(p, &opnd, &num, 0); 1458 bc_num_bigdig(num, &val); 1459 1460 bc_vec_pop(&p->results); 1461 } 1462 1463 for (i = 0; val && i < p->tail_calls.len; ++i) { 1464 size_t calls = *((size_t*) bc_vec_item_rev(&p->tail_calls, i)) + 1; 1465 if (calls >= val) val = 0; 1466 else val -= calls; 1467 } 1468 1469 if (i == p->stack.len) { 1470 vm.status = BC_STATUS_QUIT; 1471 BC_VM_JMP; 1472 } 1473 else { 1474 bc_vec_npop(&p->stack, i); 1475 bc_vec_npop(&p->tail_calls, i); 1476 } 1477 } 1478 1479 static void bc_program_execStr(BcProgram *p, const char *restrict code, 1480 size_t *restrict bgn, bool cond, size_t len) 1481 { 1482 BcResult *r; 1483 char *str; 1484 BcFunc *f; 1485 BcParse prs; 1486 BcInstPtr ip; 1487 size_t fidx, sidx; 1488 BcNum *n; 1489 1490 assert(p->stack.len == p->tail_calls.len); 1491 1492 if (BC_ERR(!BC_PROG_STACK(&p->results, 1))) bc_vm_err(BC_ERR_EXEC_STACK); 1493 1494 assert(BC_PROG_STACK(&p->results, 1)); 1495 1496 bc_program_operand(p, &r, &n, 0); 1497 1498 if (cond) { 1499 1500 bool exec; 1501 size_t idx, then_idx, else_idx; 1502 1503 then_idx = bc_program_index(code, bgn); 1504 else_idx = bc_program_index(code, bgn); 1505 1506 exec = (r->d.n.len != 0); 1507 1508 idx = exec ? then_idx : else_idx; 1509 1510 BC_SIG_LOCK; 1511 BC_SETJMP_LOCKED(exit); 1512 1513 if (exec || (else_idx != SIZE_MAX)) 1514 n = bc_vec_top(bc_program_vec(p, idx, BC_TYPE_VAR)); 1515 else goto exit; 1516 1517 if (BC_ERR(!BC_PROG_STR(n))) bc_vm_err(BC_ERR_EXEC_TYPE); 1518 1519 BC_UNSETJMP; 1520 BC_SIG_UNLOCK; 1521 1522 sidx = n->scale; 1523 } 1524 else { 1525 1526 // In non-conditional situations, only the top of stack can be executed, 1527 // and in those cases, variables are not allowed to be "on the stack"; 1528 // they are only put on the stack to be assigned to. 1529 assert(r->t != BC_RESULT_VAR); 1530 1531 if (r->t == BC_RESULT_STR) sidx = r->d.loc.loc; 1532 else return; 1533 } 1534 1535 fidx = sidx + BC_PROG_REQ_FUNCS; 1536 str = *((char**) bc_vec_item(p->strs, sidx)); 1537 f = bc_vec_item(&p->fns, fidx); 1538 1539 if (!f->code.len) { 1540 1541 BC_SIG_LOCK; 1542 1543 bc_parse_init(&prs, p, fidx); 1544 bc_lex_file(&prs.l, vm.file); 1545 1546 BC_SETJMP_LOCKED(err); 1547 1548 BC_SIG_UNLOCK; 1549 1550 bc_parse_text(&prs, str); 1551 vm.expr(&prs, BC_PARSE_NOCALL); 1552 1553 BC_SIG_LOCK; 1554 1555 BC_UNSETJMP; 1556 1557 // We can just assert this here because 1558 // dc should parse everything until EOF. 1559 assert(prs.l.t == BC_LEX_EOF); 1560 1561 bc_parse_free(&prs); 1562 1563 BC_SIG_UNLOCK; 1564 } 1565 1566 ip.idx = 0; 1567 ip.len = p->results.len; 1568 ip.func = fidx; 1569 1570 bc_vec_pop(&p->results); 1571 1572 // Tail call. 1573 if (p->stack.len > 1 && *bgn == len - 1 && code[*bgn] == BC_INST_POP_EXEC) { 1574 size_t *call_ptr = bc_vec_top(&p->tail_calls); 1575 *call_ptr += 1; 1576 bc_vec_pop(&p->stack); 1577 } 1578 else bc_vec_push(&p->tail_calls, &ip.idx); 1579 1580 bc_vec_push(&p->stack, &ip); 1581 1582 return; 1583 1584 err: 1585 BC_SIG_MAYLOCK; 1586 bc_parse_free(&prs); 1587 f = bc_vec_item(&p->fns, fidx); 1588 bc_vec_popAll(&f->code); 1589 exit: 1590 bc_vec_pop(&p->results); 1591 BC_LONGJMP_CONT; 1592 } 1593 1594 static void bc_program_printStack(BcProgram *p) { 1595 1596 size_t idx; 1597 1598 for (idx = 0; idx < p->results.len; ++idx) 1599 bc_program_print(p, BC_INST_PRINT, idx); 1600 } 1601 #endif // DC_ENABLED 1602 1603 static void bc_program_pushGlobal(BcProgram *p, uchar inst) { 1604 1605 BcResultType t; 1606 1607 assert(inst >= BC_INST_IBASE && inst <= BC_INST_SCALE); 1608 1609 t = inst - BC_INST_IBASE + BC_RESULT_IBASE; 1610 bc_program_pushBigdig(p, p->globals[inst - BC_INST_IBASE], t); 1611 } 1612 1613 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND 1614 static void bc_program_pushSeed(BcProgram *p) { 1615 1616 BcResult *res; 1617 1618 res = bc_program_prepResult(p); 1619 res->t = BC_RESULT_SEED; 1620 1621 BC_SIG_LOCK; 1622 1623 bc_num_init(&res->d.n, 2 * BC_RAND_NUM_SIZE); 1624 1625 BC_SIG_UNLOCK; 1626 1627 bc_num_createFromRNG(&res->d.n, &p->rng); 1628 } 1629 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND 1630 1631 static void bc_program_addFunc(BcProgram *p, BcFunc *f, BcId *id_ptr) { 1632 1633 BcInstPtr *ip; 1634 1635 BC_SIG_ASSERT_LOCKED; 1636 1637 bc_func_init(f, id_ptr->name); 1638 bc_vec_push(&p->fns, f); 1639 1640 // This is to make sure pointers are updated if the array was moved. 1641 if (p->stack.len) { 1642 ip = bc_vec_top(&p->stack); 1643 bc_program_setVecs(p, (BcFunc*) bc_vec_item(&p->fns, ip->func)); 1644 } 1645 } 1646 1647 size_t bc_program_insertFunc(BcProgram *p, const char *name) { 1648 1649 BcId *id_ptr; 1650 BcFunc f; 1651 bool new; 1652 size_t idx; 1653 1654 BC_SIG_ASSERT_LOCKED; 1655 1656 assert(p != NULL && name != NULL); 1657 1658 new = bc_map_insert(&p->fn_map, name, p->fns.len, &idx); 1659 id_ptr = (BcId*) bc_vec_item(&p->fn_map, idx); 1660 idx = id_ptr->idx; 1661 1662 if (!new) { 1663 if (BC_IS_BC) { 1664 BcFunc *func = bc_vec_item(&p->fns, idx); 1665 bc_func_reset(func); 1666 } 1667 } 1668 else { 1669 1670 bc_program_addFunc(p, &f, id_ptr); 1671 1672 #if DC_ENABLED 1673 if (BC_IS_DC && idx >= BC_PROG_REQ_FUNCS) { 1674 bc_vec_push(p->strs, &id_ptr->name); 1675 assert(p->strs->len == p->fns.len - BC_PROG_REQ_FUNCS); 1676 } 1677 #endif // DC_ENABLED 1678 } 1679 1680 return idx; 1681 } 1682 1683 #ifndef NDEBUG 1684 void bc_program_free(BcProgram *p) { 1685 1686 size_t i; 1687 1688 BC_SIG_ASSERT_LOCKED; 1689 1690 assert(p != NULL); 1691 1692 for (i = 0; i < BC_PROG_GLOBALS_LEN; ++i) bc_vec_free(p->globals_v + i); 1693 1694 bc_vec_free(&p->fns); 1695 bc_vec_free(&p->fn_map); 1696 bc_vec_free(&p->vars); 1697 bc_vec_free(&p->var_map); 1698 bc_vec_free(&p->arrs); 1699 bc_vec_free(&p->arr_map); 1700 bc_vec_free(&p->results); 1701 bc_vec_free(&p->stack); 1702 1703 #if BC_ENABLED 1704 if (BC_IS_BC) bc_num_free(&p->last); 1705 #endif // BC_ENABLED 1706 1707 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND 1708 bc_rand_free(&p->rng); 1709 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND 1710 1711 #if DC_ENABLED 1712 if (BC_IS_DC) { 1713 bc_vec_free(&p->tail_calls); 1714 bc_vec_free(&p->strs_v); 1715 } 1716 #endif // DC_ENABLED 1717 } 1718 #endif // NDEBUG 1719 1720 void bc_program_init(BcProgram *p) { 1721 1722 BcInstPtr ip; 1723 size_t i; 1724 1725 BC_SIG_ASSERT_LOCKED; 1726 1727 assert(p != NULL); 1728 1729 memset(p, 0, sizeof(BcProgram)); 1730 memset(&ip, 0, sizeof(BcInstPtr)); 1731 1732 for (i = 0; i < BC_PROG_GLOBALS_LEN; ++i) { 1733 BcBigDig val = i == BC_PROG_GLOBALS_SCALE ? 0 : BC_BASE; 1734 bc_vec_init(p->globals_v + i, sizeof(BcBigDig), NULL); 1735 bc_vec_push(p->globals_v + i, &val); 1736 p->globals[i] = val; 1737 } 1738 1739 #if DC_ENABLED 1740 if (BC_IS_DC) { 1741 1742 bc_vec_init(&p->strs_v, sizeof(char*), bc_string_free); 1743 p->strs = &p->strs_v; 1744 1745 bc_vec_init(&p->tail_calls, sizeof(size_t), NULL); 1746 i = 0; 1747 bc_vec_push(&p->tail_calls, &i); 1748 1749 p->strm = UCHAR_MAX + 1; 1750 bc_num_setup(&p->strmb, p->strmb_num, BC_NUM_BIGDIG_LOG10); 1751 bc_num_bigdig2num(&p->strmb, p->strm); 1752 } 1753 #endif // DC_ENABLED 1754 1755 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND 1756 srand((unsigned int) time(NULL)); 1757 bc_rand_init(&p->rng); 1758 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND 1759 1760 bc_num_setup(&p->zero, p->zero_num, BC_PROG_ONE_CAP); 1761 1762 bc_num_setup(&p->one, p->one_num, BC_PROG_ONE_CAP); 1763 bc_num_one(&p->one); 1764 1765 #if BC_ENABLED 1766 if (BC_IS_BC) bc_num_init(&p->last, BC_NUM_DEF_SIZE); 1767 #endif // BC_ENABLED 1768 1769 bc_vec_init(&p->fns, sizeof(BcFunc), bc_func_free); 1770 bc_map_init(&p->fn_map); 1771 bc_program_insertFunc(p, bc_func_main); 1772 bc_program_insertFunc(p, bc_func_read); 1773 1774 bc_vec_init(&p->vars, sizeof(BcVec), bc_vec_free); 1775 bc_map_init(&p->var_map); 1776 1777 bc_vec_init(&p->arrs, sizeof(BcVec), bc_vec_free); 1778 bc_map_init(&p->arr_map); 1779 1780 bc_vec_init(&p->results, sizeof(BcResult), bc_result_free); 1781 bc_vec_init(&p->stack, sizeof(BcInstPtr), NULL); 1782 bc_vec_push(&p->stack, &ip); 1783 1784 bc_program_setVecs(p, (BcFunc*) bc_vec_item(&p->fns, BC_PROG_MAIN)); 1785 1786 assert(p->consts != NULL && p->strs != NULL); 1787 } 1788 1789 void bc_program_reset(BcProgram *p) { 1790 1791 BcFunc *f; 1792 BcInstPtr *ip; 1793 1794 BC_SIG_ASSERT_LOCKED; 1795 1796 bc_vec_npop(&p->stack, p->stack.len - 1); 1797 bc_vec_popAll(&p->results); 1798 1799 #if BC_ENABLED 1800 if (BC_G) bc_program_popGlobals(p, true); 1801 #endif // BC_ENABLED 1802 1803 f = bc_vec_item(&p->fns, BC_PROG_MAIN); 1804 bc_vec_npop(&f->code, f->code.len); 1805 ip = bc_vec_top(&p->stack); 1806 bc_program_setVecs(p, f); 1807 memset(ip, 0, sizeof(BcInstPtr)); 1808 1809 if (vm.sig) { 1810 bc_file_write(&vm.fout, bc_program_ready_msg, bc_program_ready_msg_len); 1811 bc_file_flush(&vm.fout); 1812 vm.sig = 0; 1813 } 1814 } 1815 1816 void bc_program_exec(BcProgram *p) { 1817 1818 size_t idx; 1819 BcResult r, *ptr; 1820 BcInstPtr *ip = bc_vec_top(&p->stack); 1821 BcFunc *func = (BcFunc*) bc_vec_item(&p->fns, ip->func); 1822 char *code = func->code.v; 1823 bool cond = false; 1824 #if BC_ENABLED 1825 BcNum *num; 1826 #endif // BC_ENABLED 1827 #ifndef NDEBUG 1828 size_t jmp_bufs_len; 1829 #endif // NDEBUG 1830 1831 #ifndef NDEBUG 1832 jmp_bufs_len = vm.jmp_bufs.len; 1833 #endif // NDEBUG 1834 1835 bc_program_setVecs(p, func); 1836 1837 while (ip->idx < func->code.len) { 1838 1839 BC_SIG_ASSERT_NOT_LOCKED; 1840 1841 uchar inst = (uchar) code[(ip->idx)++]; 1842 1843 switch (inst) { 1844 1845 #if BC_ENABLED 1846 case BC_INST_JUMP_ZERO: 1847 { 1848 bc_program_prep(p, &ptr, &num, 0); 1849 cond = !bc_num_cmpZero(num); 1850 bc_vec_pop(&p->results); 1851 } 1852 // Fallthrough. 1853 BC_FALLTHROUGH 1854 1855 case BC_INST_JUMP: 1856 { 1857 idx = bc_program_index(code, &ip->idx); 1858 1859 if (inst == BC_INST_JUMP || cond) { 1860 1861 size_t *addr = bc_vec_item(&func->labels, idx); 1862 1863 assert(*addr != SIZE_MAX); 1864 1865 ip->idx = *addr; 1866 } 1867 1868 break; 1869 } 1870 1871 case BC_INST_CALL: 1872 { 1873 assert(BC_IS_BC); 1874 1875 bc_program_call(p, code, &ip->idx); 1876 1877 ip = bc_vec_top(&p->stack); 1878 func = bc_vec_item(&p->fns, ip->func); 1879 code = func->code.v; 1880 1881 bc_program_setVecs(p, func); 1882 1883 break; 1884 } 1885 1886 case BC_INST_INC: 1887 case BC_INST_DEC: 1888 { 1889 bc_program_incdec(p, inst); 1890 break; 1891 } 1892 1893 case BC_INST_HALT: 1894 { 1895 vm.status = BC_STATUS_QUIT; 1896 BC_VM_JMP; 1897 break; 1898 } 1899 1900 case BC_INST_RET: 1901 case BC_INST_RET0: 1902 case BC_INST_RET_VOID: 1903 { 1904 bc_program_return(p, inst); 1905 1906 ip = bc_vec_top(&p->stack); 1907 func = bc_vec_item(&p->fns, ip->func); 1908 code = func->code.v; 1909 1910 bc_program_setVecs(p, func); 1911 1912 break; 1913 } 1914 #endif // BC_ENABLED 1915 1916 case BC_INST_BOOL_OR: 1917 case BC_INST_BOOL_AND: 1918 case BC_INST_REL_EQ: 1919 case BC_INST_REL_LE: 1920 case BC_INST_REL_GE: 1921 case BC_INST_REL_NE: 1922 case BC_INST_REL_LT: 1923 case BC_INST_REL_GT: 1924 { 1925 bc_program_logical(p, inst); 1926 break; 1927 } 1928 1929 case BC_INST_READ: 1930 { 1931 // We want to flush output before 1932 // this in case there is a prompt. 1933 bc_file_flush(&vm.fout); 1934 1935 bc_program_read(p); 1936 1937 ip = bc_vec_top(&p->stack); 1938 func = bc_vec_item(&p->fns, ip->func); 1939 code = func->code.v; 1940 1941 bc_program_setVecs(p, func); 1942 1943 break; 1944 } 1945 1946 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND 1947 case BC_INST_RAND: 1948 { 1949 bc_program_rand(p); 1950 break; 1951 } 1952 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND 1953 1954 case BC_INST_MAXIBASE: 1955 case BC_INST_MAXOBASE: 1956 case BC_INST_MAXSCALE: 1957 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND 1958 case BC_INST_MAXRAND: 1959 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND 1960 { 1961 BcBigDig dig = vm.maxes[inst - BC_INST_MAXIBASE]; 1962 bc_program_pushBigdig(p, dig, BC_RESULT_TEMP); 1963 break; 1964 } 1965 1966 case BC_INST_VAR: 1967 { 1968 bc_program_pushVar(p, code, &ip->idx, false, false); 1969 break; 1970 } 1971 1972 case BC_INST_ARRAY_ELEM: 1973 #if BC_ENABLED 1974 case BC_INST_ARRAY: 1975 #endif // BC_ENABLED 1976 { 1977 bc_program_pushArray(p, code, &ip->idx, inst); 1978 break; 1979 } 1980 1981 case BC_INST_IBASE: 1982 case BC_INST_SCALE: 1983 case BC_INST_OBASE: 1984 { 1985 bc_program_pushGlobal(p, inst); 1986 break; 1987 } 1988 1989 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND 1990 case BC_INST_SEED: 1991 { 1992 bc_program_pushSeed(p); 1993 break; 1994 } 1995 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND 1996 1997 case BC_INST_LENGTH: 1998 case BC_INST_SCALE_FUNC: 1999 case BC_INST_SQRT: 2000 case BC_INST_ABS: 2001 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND 2002 case BC_INST_IRAND: 2003 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND 2004 { 2005 bc_program_builtin(p, inst); 2006 break; 2007 } 2008 2009 case BC_INST_NUM: 2010 { 2011 bc_program_const(p, code, &ip->idx); 2012 break; 2013 } 2014 2015 case BC_INST_ZERO: 2016 case BC_INST_ONE: 2017 #if BC_ENABLED 2018 case BC_INST_LAST: 2019 #endif // BC_ENABLED 2020 { 2021 r.t = BC_RESULT_ZERO + (inst - BC_INST_ZERO); 2022 bc_vec_push(&p->results, &r); 2023 break; 2024 } 2025 2026 case BC_INST_PRINT: 2027 case BC_INST_PRINT_POP: 2028 case BC_INST_PRINT_STR: 2029 { 2030 bc_program_print(p, inst, 0); 2031 break; 2032 } 2033 2034 case BC_INST_STR: 2035 { 2036 r.t = BC_RESULT_STR; 2037 r.d.loc.loc = bc_program_index(code, &ip->idx); 2038 bc_vec_push(&p->results, &r); 2039 break; 2040 } 2041 2042 case BC_INST_POWER: 2043 case BC_INST_MULTIPLY: 2044 case BC_INST_DIVIDE: 2045 case BC_INST_MODULUS: 2046 case BC_INST_PLUS: 2047 case BC_INST_MINUS: 2048 #if BC_ENABLE_EXTRA_MATH 2049 case BC_INST_PLACES: 2050 case BC_INST_LSHIFT: 2051 case BC_INST_RSHIFT: 2052 #endif // BC_ENABLE_EXTRA_MATH 2053 { 2054 bc_program_op(p, inst); 2055 break; 2056 } 2057 2058 case BC_INST_NEG: 2059 case BC_INST_BOOL_NOT: 2060 #if BC_ENABLE_EXTRA_MATH 2061 case BC_INST_TRUNC: 2062 #endif // BC_ENABLE_EXTRA_MATH 2063 { 2064 bc_program_unary(p, inst); 2065 break; 2066 } 2067 2068 #if BC_ENABLED 2069 case BC_INST_ASSIGN_POWER: 2070 case BC_INST_ASSIGN_MULTIPLY: 2071 case BC_INST_ASSIGN_DIVIDE: 2072 case BC_INST_ASSIGN_MODULUS: 2073 case BC_INST_ASSIGN_PLUS: 2074 case BC_INST_ASSIGN_MINUS: 2075 #if BC_ENABLE_EXTRA_MATH 2076 case BC_INST_ASSIGN_PLACES: 2077 case BC_INST_ASSIGN_LSHIFT: 2078 case BC_INST_ASSIGN_RSHIFT: 2079 #endif // BC_ENABLE_EXTRA_MATH 2080 case BC_INST_ASSIGN: 2081 case BC_INST_ASSIGN_POWER_NO_VAL: 2082 case BC_INST_ASSIGN_MULTIPLY_NO_VAL: 2083 case BC_INST_ASSIGN_DIVIDE_NO_VAL: 2084 case BC_INST_ASSIGN_MODULUS_NO_VAL: 2085 case BC_INST_ASSIGN_PLUS_NO_VAL: 2086 case BC_INST_ASSIGN_MINUS_NO_VAL: 2087 #if BC_ENABLE_EXTRA_MATH 2088 case BC_INST_ASSIGN_PLACES_NO_VAL: 2089 case BC_INST_ASSIGN_LSHIFT_NO_VAL: 2090 case BC_INST_ASSIGN_RSHIFT_NO_VAL: 2091 #endif // BC_ENABLE_EXTRA_MATH 2092 #endif // BC_ENABLED 2093 case BC_INST_ASSIGN_NO_VAL: 2094 { 2095 bc_program_assign(p, inst); 2096 break; 2097 } 2098 2099 case BC_INST_POP: 2100 { 2101 #ifndef BC_PROG_NO_STACK_CHECK 2102 if (!BC_IS_BC) { 2103 if (BC_ERR(!BC_PROG_STACK(&p->results, 1))) 2104 bc_vm_err(BC_ERR_EXEC_STACK); 2105 } 2106 #endif // BC_PROG_NO_STACK_CHECK 2107 2108 assert(BC_PROG_STACK(&p->results, 1)); 2109 2110 bc_vec_pop(&p->results); 2111 break; 2112 } 2113 2114 #if DC_ENABLED 2115 case BC_INST_POP_EXEC: 2116 { 2117 assert(BC_PROG_STACK(&p->stack, 2)); 2118 bc_vec_pop(&p->stack); 2119 bc_vec_pop(&p->tail_calls); 2120 ip = bc_vec_top(&p->stack); 2121 func = bc_vec_item(&p->fns, ip->func); 2122 code = func->code.v; 2123 bc_program_setVecs(p, func); 2124 break; 2125 } 2126 2127 case BC_INST_MODEXP: 2128 { 2129 bc_program_modexp(p); 2130 break; 2131 } 2132 2133 case BC_INST_DIVMOD: 2134 { 2135 bc_program_divmod(p); 2136 break; 2137 } 2138 2139 case BC_INST_EXECUTE: 2140 case BC_INST_EXEC_COND: 2141 { 2142 cond = (inst == BC_INST_EXEC_COND); 2143 bc_program_execStr(p, code, &ip->idx, cond, func->code.len); 2144 ip = bc_vec_top(&p->stack); 2145 func = bc_vec_item(&p->fns, ip->func); 2146 code = func->code.v; 2147 bc_program_setVecs(p, func); 2148 break; 2149 } 2150 2151 case BC_INST_PRINT_STACK: 2152 { 2153 bc_program_printStack(p); 2154 break; 2155 } 2156 2157 case BC_INST_CLEAR_STACK: 2158 { 2159 bc_vec_popAll(&p->results); 2160 break; 2161 } 2162 2163 case BC_INST_STACK_LEN: 2164 { 2165 bc_program_stackLen(p); 2166 break; 2167 } 2168 2169 case BC_INST_DUPLICATE: 2170 { 2171 if (BC_ERR(!BC_PROG_STACK(&p->results, 1))) 2172 bc_vm_err(BC_ERR_EXEC_STACK); 2173 2174 assert(BC_PROG_STACK(&p->results, 1)); 2175 2176 ptr = bc_vec_top(&p->results); 2177 2178 BC_SIG_LOCK; 2179 2180 bc_result_copy(&r, ptr); 2181 bc_vec_push(&p->results, &r); 2182 2183 BC_SIG_UNLOCK; 2184 2185 break; 2186 } 2187 2188 case BC_INST_SWAP: 2189 { 2190 BcResult *ptr2; 2191 2192 if (BC_ERR(!BC_PROG_STACK(&p->results, 2))) 2193 bc_vm_err(BC_ERR_EXEC_STACK); 2194 2195 assert(BC_PROG_STACK(&p->results, 2)); 2196 2197 ptr = bc_vec_item_rev(&p->results, 0); 2198 ptr2 = bc_vec_item_rev(&p->results, 1); 2199 memcpy(&r, ptr, sizeof(BcResult)); 2200 memcpy(ptr, ptr2, sizeof(BcResult)); 2201 memcpy(ptr2, &r, sizeof(BcResult)); 2202 2203 break; 2204 } 2205 2206 case BC_INST_ASCIIFY: 2207 { 2208 bc_program_asciify(p); 2209 ip = bc_vec_top(&p->stack); 2210 func = bc_vec_item(&p->fns, ip->func); 2211 code = func->code.v; 2212 bc_program_setVecs(p, func); 2213 break; 2214 } 2215 2216 case BC_INST_PRINT_STREAM: 2217 { 2218 bc_program_printStream(p); 2219 break; 2220 } 2221 2222 case BC_INST_LOAD: 2223 case BC_INST_PUSH_VAR: 2224 { 2225 bool copy = (inst == BC_INST_LOAD); 2226 bc_program_pushVar(p, code, &ip->idx, true, copy); 2227 break; 2228 } 2229 2230 case BC_INST_PUSH_TO_VAR: 2231 { 2232 idx = bc_program_index(code, &ip->idx); 2233 bc_program_copyToVar(p, idx, BC_TYPE_VAR, true); 2234 break; 2235 } 2236 2237 case BC_INST_QUIT: 2238 case BC_INST_NQUIT: 2239 { 2240 bc_program_nquit(p, inst); 2241 ip = bc_vec_top(&p->stack); 2242 func = bc_vec_item(&p->fns, ip->func); 2243 code = func->code.v; 2244 bc_program_setVecs(p, func); 2245 break; 2246 } 2247 #endif // DC_ENABLED 2248 #ifndef NDEBUG 2249 default: 2250 { 2251 abort(); 2252 } 2253 #endif // NDEBUG 2254 } 2255 2256 #ifndef NDEBUG 2257 // This is to allow me to use a debugger to see the last instruction, 2258 // which will point to which function was the problem. 2259 assert(jmp_bufs_len == vm.jmp_bufs.len); 2260 #endif // NDEBUG 2261 } 2262 } 2263 2264 #if BC_DEBUG_CODE 2265 #if BC_ENABLED && DC_ENABLED 2266 void bc_program_printStackDebug(BcProgram *p) { 2267 bc_file_puts(&vm.fout, "-------------- Stack ----------\n"); 2268 bc_program_printStack(p); 2269 bc_file_puts(&vm.fout, "-------------- Stack End ------\n"); 2270 } 2271 2272 static void bc_program_printIndex(const char *restrict code, 2273 size_t *restrict bgn) 2274 { 2275 uchar byte, i, bytes = (uchar) code[(*bgn)++]; 2276 ulong val = 0; 2277 2278 for (byte = 1, i = 0; byte && i < bytes; ++i) { 2279 byte = (uchar) code[(*bgn)++]; 2280 if (byte) val |= ((ulong) byte) << (CHAR_BIT * i); 2281 } 2282 2283 bc_vm_printf(" (%lu) ", val); 2284 } 2285 2286 static void bc_program_printStr(const BcProgram *p, const char *restrict code, 2287 size_t *restrict bgn) 2288 { 2289 size_t idx = bc_program_index(code, bgn); 2290 char *s; 2291 2292 s = *((char**) bc_vec_item(p->strs, idx)); 2293 2294 bc_vm_printf(" (\"%s\") ", s); 2295 } 2296 2297 void bc_program_printInst(const BcProgram *p, const char *restrict code, 2298 size_t *restrict bgn) 2299 { 2300 uchar inst = (uchar) code[(*bgn)++]; 2301 2302 bc_vm_printf("Inst[%zu]: %s [%lu]; ", *bgn - 1, 2303 bc_inst_names[inst], (unsigned long) inst); 2304 2305 if (inst == BC_INST_VAR || inst == BC_INST_ARRAY_ELEM || 2306 inst == BC_INST_ARRAY) 2307 { 2308 bc_program_printIndex(code, bgn); 2309 } 2310 else if (inst == BC_INST_STR) bc_program_printStr(p, code, bgn); 2311 else if (inst == BC_INST_NUM) { 2312 size_t idx = bc_program_index(code, bgn); 2313 BcConst *c = bc_vec_item(p->consts, idx); 2314 bc_vm_printf("(%s)", c->val); 2315 } 2316 else if (inst == BC_INST_CALL || 2317 (inst > BC_INST_STR && inst <= BC_INST_JUMP_ZERO)) 2318 { 2319 bc_program_printIndex(code, bgn); 2320 if (inst == BC_INST_CALL) bc_program_printIndex(code, bgn); 2321 } 2322 2323 bc_vm_putchar('\n'); 2324 } 2325 2326 void bc_program_code(const BcProgram* p) { 2327 2328 BcFunc *f; 2329 char *code; 2330 BcInstPtr ip; 2331 size_t i; 2332 2333 for (i = 0; i < p->fns.len; ++i) { 2334 2335 ip.idx = ip.len = 0; 2336 ip.func = i; 2337 2338 f = bc_vec_item(&p->fns, ip.func); 2339 code = f->code.v; 2340 2341 bc_vm_printf("func[%zu]:\n", ip.func); 2342 while (ip.idx < f->code.len) bc_program_printInst(p, code, &ip.idx); 2343 bc_file_puts(&vm.fout, "\n\n"); 2344 } 2345 } 2346 #endif // BC_ENABLED && DC_ENABLED 2347 #endif // BC_DEBUG_CODE 2348