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 if (BC_R) s = bc_read_line(&buf, ""); 460 else s = bc_read_line(&buf, BC_IS_BC ? "read> " : "?> "); 461 462 if (s == BC_STATUS_EOF) bc_vm_err(BC_ERR_EXEC_READ_EXPR); 463 464 bc_parse_text(&parse, buf.v); 465 vm.expr(&parse, BC_PARSE_NOREAD | BC_PARSE_NEEDVAL); 466 467 if (BC_ERR(parse.l.t != BC_LEX_NLINE && parse.l.t != BC_LEX_EOF)) 468 bc_vm_err(BC_ERR_EXEC_READ_EXPR); 469 470 #if BC_ENABLED 471 if (BC_G) bc_program_prepGlobals(p); 472 #endif // BC_ENABLED 473 474 ip.func = BC_PROG_READ; 475 ip.idx = 0; 476 ip.len = p->results.len; 477 478 // Update this pointer, just in case. 479 f = bc_vec_item(&p->fns, BC_PROG_READ); 480 481 bc_vec_pushByte(&f->code, vm.read_ret); 482 bc_vec_push(&p->stack, &ip); 483 484 #if DC_ENABLED 485 if (BC_IS_DC) { 486 size_t temp = 0; 487 bc_vec_push(&p->tail_calls, &temp); 488 } 489 #endif // DC_ENABLED 490 491 exec_err: 492 BC_SIG_MAYLOCK; 493 bc_parse_free(&parse); 494 bc_vec_free(&buf); 495 vm.file = file; 496 BC_LONGJMP_CONT; 497 } 498 499 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND 500 static void bc_program_rand(BcProgram *p) { 501 BcRand rand = bc_rand_int(&p->rng); 502 bc_program_pushBigdig(p, (BcBigDig) rand, BC_RESULT_TEMP); 503 #ifndef NDEBUG 504 { 505 BcResult *r = bc_vec_top(&p->results); 506 assert(BC_NUM_RDX_VALID_NP(r->d.n)); 507 } 508 #endif // NDEBUG 509 } 510 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND 511 512 static void bc_program_printChars(const char *str) { 513 514 const char *nl; 515 size_t len = vm.nchars + strlen(str); 516 517 bc_file_puts(&vm.fout, bc_flush_save, str); 518 nl = strrchr(str, '\n'); 519 520 if (nl != NULL) len = strlen(nl + 1); 521 522 vm.nchars = len > UINT16_MAX ? UINT16_MAX : (uint16_t) len; 523 } 524 525 static void bc_program_printString(const char *restrict str) { 526 527 size_t i, len = strlen(str); 528 529 #if DC_ENABLED 530 if (!len && BC_IS_DC) { 531 bc_vm_putchar('\0', bc_flush_save); 532 return; 533 } 534 #endif // DC_ENABLED 535 536 for (i = 0; i < len; ++i) { 537 538 int c = str[i]; 539 540 if (c == '\\' && i != len - 1) { 541 542 const char *ptr; 543 544 c = str[++i]; 545 ptr = strchr(bc_program_esc_chars, c); 546 547 if (ptr != NULL) { 548 if (c == 'n') vm.nchars = UINT16_MAX; 549 c = bc_program_esc_seqs[(size_t) (ptr - bc_program_esc_chars)]; 550 } 551 else { 552 // Just print the backslash. The following 553 // character will be printed later. 554 bc_vm_putchar('\\', bc_flush_save); 555 } 556 } 557 558 bc_vm_putchar(c, bc_flush_save); 559 } 560 } 561 562 static void bc_program_print(BcProgram *p, uchar inst, size_t idx) { 563 564 BcResult *r; 565 char *str; 566 BcNum *n; 567 bool pop = (inst != BC_INST_PRINT); 568 569 assert(p != NULL); 570 571 #ifndef BC_PROG_NO_STACK_CHECK 572 if (BC_IS_DC) { 573 if (BC_ERR(!BC_PROG_STACK(&p->results, idx + 1))) 574 bc_vm_err(BC_ERR_EXEC_STACK); 575 } 576 #endif // BC_PROG_NO_STACK_CHECK 577 578 assert(BC_PROG_STACK(&p->results, idx + 1)); 579 580 r = bc_vec_item_rev(&p->results, idx); 581 582 #if BC_ENABLED 583 if (r->t == BC_RESULT_VOID) { 584 if (BC_ERR(pop)) bc_vm_err(BC_ERR_EXEC_VOID_VAL); 585 bc_vec_pop(&p->results); 586 return; 587 } 588 #endif // BC_ENABLED 589 590 n = bc_program_num(p, r); 591 592 if (BC_PROG_NUM(r, n)) { 593 assert(inst != BC_INST_PRINT_STR); 594 bc_num_print(n, BC_PROG_OBASE(p), !pop); 595 #if BC_ENABLED 596 if (BC_IS_BC) bc_num_copy(&p->last, n); 597 #endif // BC_ENABLED 598 } 599 else { 600 601 size_t i = (r->t == BC_RESULT_STR) ? r->d.loc.loc : n->scale; 602 603 bc_file_flush(&vm.fout, bc_flush_save); 604 str = *((char**) bc_vec_item(p->strs, i)); 605 606 if (inst == BC_INST_PRINT_STR) bc_program_printChars(str); 607 else { 608 bc_program_printString(str); 609 if (inst == BC_INST_PRINT) 610 bc_vm_putchar('\n', bc_flush_err); 611 } 612 } 613 614 if (BC_IS_BC || pop) bc_vec_pop(&p->results); 615 } 616 617 void bc_program_negate(BcResult *r, BcNum *n) { 618 bc_num_copy(&r->d.n, n); 619 if (BC_NUM_NONZERO(&r->d.n)) BC_NUM_NEG_TGL_NP(r->d.n); 620 } 621 622 void bc_program_not(BcResult *r, BcNum *n) { 623 if (!bc_num_cmpZero(n)) bc_num_one(&r->d.n); 624 } 625 626 #if BC_ENABLE_EXTRA_MATH 627 void bc_program_trunc(BcResult *r, BcNum *n) { 628 bc_num_copy(&r->d.n, n); 629 bc_num_truncate(&r->d.n, n->scale); 630 } 631 #endif // BC_ENABLE_EXTRA_MATH 632 633 static void bc_program_unary(BcProgram *p, uchar inst) { 634 635 BcResult *res, *ptr; 636 BcNum *num; 637 638 res = bc_program_prepResult(p); 639 640 bc_program_prep(p, &ptr, &num, 1); 641 642 BC_SIG_LOCK; 643 644 bc_num_init(&res->d.n, num->len); 645 646 BC_SIG_UNLOCK; 647 648 bc_program_unarys[inst - BC_INST_NEG](res, num); 649 bc_program_retire(p, 1, 1); 650 } 651 652 static void bc_program_logical(BcProgram *p, uchar inst) { 653 654 BcResult *opd1, *opd2, *res; 655 BcNum *n1, *n2; 656 bool cond = 0; 657 ssize_t cmp; 658 659 res = bc_program_prepResult(p); 660 661 bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2, 1); 662 663 if (inst == BC_INST_BOOL_AND) 664 cond = (bc_num_cmpZero(n1) && bc_num_cmpZero(n2)); 665 else if (inst == BC_INST_BOOL_OR) 666 cond = (bc_num_cmpZero(n1) || bc_num_cmpZero(n2)); 667 else { 668 669 cmp = bc_num_cmp(n1, n2); 670 671 switch (inst) { 672 673 case BC_INST_REL_EQ: 674 { 675 cond = (cmp == 0); 676 break; 677 } 678 679 case BC_INST_REL_LE: 680 { 681 cond = (cmp <= 0); 682 break; 683 } 684 685 case BC_INST_REL_GE: 686 { 687 cond = (cmp >= 0); 688 break; 689 } 690 691 case BC_INST_REL_NE: 692 { 693 cond = (cmp != 0); 694 break; 695 } 696 697 case BC_INST_REL_LT: 698 { 699 cond = (cmp < 0); 700 break; 701 } 702 703 case BC_INST_REL_GT: 704 { 705 cond = (cmp > 0); 706 break; 707 } 708 #ifndef NDEBUG 709 default: 710 { 711 abort(); 712 } 713 #endif // NDEBUG 714 } 715 } 716 717 BC_SIG_LOCK; 718 719 bc_num_init(&res->d.n, BC_NUM_DEF_SIZE); 720 721 BC_SIG_UNLOCK; 722 723 if (cond) bc_num_one(&res->d.n); 724 725 bc_program_retire(p, 1, 2); 726 } 727 728 #if DC_ENABLED 729 static void bc_program_assignStr(BcProgram *p, size_t idx, 730 BcVec *v, bool push) 731 { 732 BcNum n2; 733 734 bc_num_clear(&n2); 735 n2.scale = idx; 736 737 assert(BC_PROG_STACK(&p->results, 1 + !push)); 738 739 if (!push) bc_vec_pop(v); 740 741 bc_vec_npop(&p->results, 1 + !push); 742 bc_vec_push(v, &n2); 743 } 744 #endif // DC_ENABLED 745 746 static void bc_program_copyToVar(BcProgram *p, size_t idx, 747 BcType t, bool last) 748 { 749 BcResult *ptr = NULL, r; 750 BcVec *vec; 751 BcNum *n = NULL; 752 bool var = (t == BC_TYPE_VAR); 753 754 #if DC_ENABLED 755 if (BC_IS_DC) { 756 757 if (BC_ERR(!BC_PROG_STACK(&p->results, 1))) 758 bc_vm_err(BC_ERR_EXEC_STACK); 759 760 assert(BC_PROG_STACK(&p->results, 1)); 761 762 bc_program_operand(p, &ptr, &n, 0); 763 } 764 #endif 765 766 #if BC_ENABLED 767 if (BC_IS_BC) 768 { 769 ptr = bc_vec_top(&p->results); 770 771 bc_program_type_match(ptr, t); 772 773 if (last) n = bc_program_num(p, ptr); 774 else if (var) 775 n = bc_vec_item_rev(bc_program_vec(p, ptr->d.loc.loc, t), 1); 776 } 777 #endif // BC_ENABLED 778 779 vec = bc_program_vec(p, idx, t); 780 781 #if DC_ENABLED 782 if (BC_IS_DC && (ptr->t == BC_RESULT_STR || BC_PROG_STR(n))) { 783 784 size_t str_idx = ptr->t == BC_RESULT_STR ? ptr->d.loc.loc : n->scale; 785 786 if (BC_ERR(!var)) bc_vm_err(BC_ERR_EXEC_TYPE); 787 788 bc_program_assignStr(p, str_idx, vec, true); 789 790 return; 791 } 792 #endif // DC_ENABLED 793 794 BC_SIG_LOCK; 795 796 if (var) bc_num_createCopy(&r.d.n, n); 797 else { 798 799 BcVec *v = (BcVec*) n, *rv = &r.d.v; 800 #if BC_ENABLED 801 BcVec *parent; 802 bool ref, ref_size; 803 804 parent = bc_program_vec(p, ptr->d.loc.loc, t); 805 assert(parent != NULL); 806 807 if (!last) v = bc_vec_item_rev(parent, !last); 808 assert(v != NULL); 809 810 ref = (v->size == sizeof(BcNum) && t == BC_TYPE_REF); 811 ref_size = (v->size == sizeof(uchar)); 812 813 if (ref || (ref_size && t == BC_TYPE_REF)) { 814 815 bc_vec_init(rv, sizeof(uchar), NULL); 816 817 if (ref) { 818 819 assert(parent->len >= (size_t) (!last + 1)); 820 821 // Make sure the pointer was not invalidated. 822 vec = bc_program_vec(p, idx, t); 823 824 bc_vec_pushIndex(rv, ptr->d.loc.loc); 825 bc_vec_pushIndex(rv, parent->len - !last - 1); 826 } 827 // If we get here, we are copying a ref to a ref. 828 else bc_vec_npush(rv, v->len * sizeof(uchar), v->v); 829 830 // We need to return early. 831 bc_vec_push(vec, &r.d); 832 bc_vec_pop(&p->results); 833 834 BC_SIG_UNLOCK; 835 return; 836 } 837 else if (ref_size && t != BC_TYPE_REF) v = bc_program_dereference(p, v); 838 #endif // BC_ENABLED 839 840 bc_array_init(rv, true); 841 bc_array_copy(rv, v); 842 } 843 844 bc_vec_push(vec, &r.d); 845 bc_vec_pop(&p->results); 846 847 BC_SIG_UNLOCK; 848 } 849 850 static void bc_program_assign(BcProgram *p, uchar inst) { 851 852 BcResult *left, *right, res; 853 BcNum *l, *r; 854 bool ob, sc, use_val = BC_INST_USE_VAL(inst); 855 856 bc_program_assignPrep(p, &left, &l, &right, &r); 857 858 #if DC_ENABLED 859 assert(left->t != BC_RESULT_STR); 860 861 if (right->t == BC_RESULT_STR || BC_PROG_STR(r)) { 862 863 size_t idx = right->t == BC_RESULT_STR ? right->d.loc.loc : r->scale; 864 865 if (left->t == BC_RESULT_ARRAY_ELEM) { 866 BC_SIG_LOCK; 867 bc_num_free(l); 868 bc_num_clear(l); 869 l->scale = idx; 870 bc_vec_npop(&p->results, 2); 871 BC_SIG_UNLOCK; 872 } 873 else { 874 BcVec *v = bc_program_vec(p, left->d.loc.loc, BC_TYPE_VAR); 875 bc_program_assignStr(p, idx, v, false); 876 } 877 878 return; 879 } 880 #endif // DC_ENABLED 881 882 if (BC_INST_IS_ASSIGN(inst)) bc_num_copy(l, r); 883 #if BC_ENABLED 884 else { 885 886 BcBigDig scale = BC_PROG_SCALE(p); 887 888 if (!use_val) 889 inst -= (BC_INST_ASSIGN_POWER_NO_VAL - BC_INST_ASSIGN_POWER); 890 891 assert(BC_NUM_RDX_VALID(l)); 892 assert(BC_NUM_RDX_VALID(r)); 893 894 bc_program_ops[inst - BC_INST_ASSIGN_POWER](l, r, l, scale); 895 } 896 #endif // BC_ENABLED 897 898 ob = (left->t == BC_RESULT_OBASE); 899 sc = (left->t == BC_RESULT_SCALE); 900 901 if (ob || sc || left->t == BC_RESULT_IBASE) { 902 903 BcVec *v; 904 BcBigDig *ptr, *ptr_t, val, max, min; 905 BcErr e; 906 907 bc_num_bigdig(l, &val); 908 e = left->t - BC_RESULT_IBASE + BC_ERR_EXEC_IBASE; 909 910 if (sc) { 911 min = 0; 912 max = vm.maxes[BC_PROG_GLOBALS_SCALE]; 913 v = p->globals_v + BC_PROG_GLOBALS_SCALE; 914 ptr_t = p->globals + BC_PROG_GLOBALS_SCALE; 915 } 916 else { 917 min = BC_NUM_MIN_BASE; 918 if (BC_ENABLE_EXTRA_MATH && ob && (BC_IS_DC || !BC_IS_POSIX)) 919 min = 0; 920 max = vm.maxes[ob + BC_PROG_GLOBALS_IBASE]; 921 v = p->globals_v + BC_PROG_GLOBALS_IBASE + ob; 922 ptr_t = p->globals + BC_PROG_GLOBALS_IBASE + ob; 923 } 924 925 if (BC_ERR(val > max || val < min)) bc_vm_verr(e, min, max); 926 927 ptr = bc_vec_top(v); 928 *ptr = val; 929 *ptr_t = val; 930 } 931 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND 932 else if (left->t == BC_RESULT_SEED) bc_num_rng(l, &p->rng); 933 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND 934 935 BC_SIG_LOCK; 936 937 if (use_val) { 938 bc_num_createCopy(&res.d.n, l); 939 res.t = BC_RESULT_TEMP; 940 bc_vec_npop(&p->results, 2); 941 bc_vec_push(&p->results, &res); 942 } 943 else bc_vec_npop(&p->results, 2); 944 945 BC_SIG_UNLOCK; 946 } 947 948 static void bc_program_pushVar(BcProgram *p, const char *restrict code, 949 size_t *restrict bgn, bool pop, bool copy) 950 { 951 BcResult r; 952 size_t idx = bc_program_index(code, bgn); 953 954 r.t = BC_RESULT_VAR; 955 r.d.loc.loc = idx; 956 957 #if DC_ENABLED 958 if (BC_IS_DC && (pop || copy)) { 959 960 BcVec *v = bc_program_vec(p, idx, BC_TYPE_VAR); 961 BcNum *num = bc_vec_top(v); 962 963 if (BC_ERR(!BC_PROG_STACK(v, 2 - copy))) bc_vm_err(BC_ERR_EXEC_STACK); 964 965 assert(BC_PROG_STACK(v, 2 - copy)); 966 967 if (!BC_PROG_STR(num)) { 968 969 BC_SIG_LOCK; 970 971 r.t = BC_RESULT_TEMP; 972 bc_num_createCopy(&r.d.n, num); 973 974 if (!copy) bc_vec_pop(v); 975 976 bc_vec_push(&p->results, &r); 977 978 BC_SIG_UNLOCK; 979 980 return; 981 } 982 else { 983 r.d.loc.loc = num->scale; 984 r.t = BC_RESULT_STR; 985 } 986 987 if (!copy) bc_vec_pop(v); 988 } 989 #endif // DC_ENABLED 990 991 bc_vec_push(&p->results, &r); 992 } 993 994 static void bc_program_pushArray(BcProgram *p, const char *restrict code, 995 size_t *restrict bgn, uchar inst) 996 { 997 BcResult r, *operand; 998 BcNum *num; 999 BcBigDig temp; 1000 1001 r.d.loc.loc = bc_program_index(code, bgn); 1002 1003 #if BC_ENABLED 1004 if (inst == BC_INST_ARRAY) { 1005 r.t = BC_RESULT_ARRAY; 1006 bc_vec_push(&p->results, &r); 1007 return; 1008 } 1009 #endif // BC_ENABLED 1010 1011 bc_program_prep(p, &operand, &num, 0); 1012 bc_num_bigdig(num, &temp); 1013 1014 r.t = BC_RESULT_ARRAY_ELEM; 1015 r.d.loc.idx = (size_t) temp; 1016 1017 BC_SIG_LOCK; 1018 1019 bc_vec_pop(&p->results); 1020 bc_vec_push(&p->results, &r); 1021 1022 BC_SIG_UNLOCK; 1023 } 1024 1025 #if BC_ENABLED 1026 static void bc_program_incdec(BcProgram *p, uchar inst) { 1027 1028 BcResult *ptr, res, copy; 1029 BcNum *num; 1030 uchar inst2; 1031 1032 bc_program_prep(p, &ptr, &num, 0); 1033 1034 BC_SIG_LOCK; 1035 1036 copy.t = BC_RESULT_TEMP; 1037 bc_num_createCopy(©.d.n, num); 1038 1039 BC_SETJMP_LOCKED(exit); 1040 1041 BC_SIG_UNLOCK; 1042 1043 res.t = BC_RESULT_ONE; 1044 inst2 = BC_INST_ASSIGN_PLUS + (inst & 0x01); 1045 1046 bc_vec_push(&p->results, &res); 1047 bc_program_assign(p, inst2); 1048 1049 BC_SIG_LOCK; 1050 1051 bc_vec_pop(&p->results); 1052 bc_vec_push(&p->results, ©); 1053 1054 BC_UNSETJMP; 1055 1056 BC_SIG_UNLOCK; 1057 1058 return; 1059 1060 exit: 1061 BC_SIG_MAYLOCK; 1062 bc_num_free(©.d.n); 1063 BC_LONGJMP_CONT; 1064 } 1065 1066 static void bc_program_call(BcProgram *p, const char *restrict code, 1067 size_t *restrict idx) 1068 { 1069 BcInstPtr ip; 1070 size_t i, nparams = bc_program_index(code, idx); 1071 BcFunc *f; 1072 BcVec *v; 1073 BcLoc *a; 1074 BcResultData param; 1075 BcResult *arg; 1076 1077 ip.idx = 0; 1078 ip.func = bc_program_index(code, idx); 1079 f = bc_vec_item(&p->fns, ip.func); 1080 1081 if (BC_ERR(!f->code.len)) bc_vm_verr(BC_ERR_EXEC_UNDEF_FUNC, f->name); 1082 if (BC_ERR(nparams != f->nparams)) 1083 bc_vm_verr(BC_ERR_EXEC_PARAMS, f->nparams, nparams); 1084 ip.len = p->results.len - nparams; 1085 1086 assert(BC_PROG_STACK(&p->results, nparams)); 1087 1088 if (BC_G) bc_program_prepGlobals(p); 1089 1090 for (i = 0; i < nparams; ++i) { 1091 1092 size_t j; 1093 bool last = true; 1094 1095 arg = bc_vec_top(&p->results); 1096 if (BC_ERR(arg->t == BC_RESULT_VOID)) bc_vm_err(BC_ERR_EXEC_VOID_VAL); 1097 1098 a = bc_vec_item(&f->autos, nparams - 1 - i); 1099 1100 // If I have already pushed to a var, I need to make sure I 1101 // get the previous version, not the already pushed one. 1102 if (arg->t == BC_RESULT_VAR || arg->t == BC_RESULT_ARRAY) { 1103 for (j = 0; j < i && last; ++j) { 1104 BcLoc *loc = bc_vec_item(&f->autos, nparams - 1 - j); 1105 last = (arg->d.loc.loc != loc->loc || 1106 (!loc->idx) != (arg->t == BC_RESULT_VAR)); 1107 } 1108 } 1109 1110 bc_program_copyToVar(p, a->loc, (BcType) a->idx, last); 1111 } 1112 1113 BC_SIG_LOCK; 1114 1115 for (; i < f->autos.len; ++i) { 1116 1117 a = bc_vec_item(&f->autos, i); 1118 v = bc_program_vec(p, a->loc, (BcType) a->idx); 1119 1120 if (a->idx == BC_TYPE_VAR) { 1121 bc_num_init(¶m.n, BC_NUM_DEF_SIZE); 1122 bc_vec_push(v, ¶m.n); 1123 } 1124 else { 1125 assert(a->idx == BC_TYPE_ARRAY); 1126 bc_array_init(¶m.v, true); 1127 bc_vec_push(v, ¶m.v); 1128 } 1129 } 1130 1131 bc_vec_push(&p->stack, &ip); 1132 1133 BC_SIG_UNLOCK; 1134 } 1135 1136 static void bc_program_return(BcProgram *p, uchar inst) { 1137 1138 BcResult *res; 1139 BcFunc *f; 1140 BcInstPtr *ip = bc_vec_top(&p->stack); 1141 size_t i, nops = p->results.len - ip->len; 1142 1143 assert(BC_PROG_STACK(&p->stack, 2)); 1144 assert(BC_PROG_STACK(&p->results, ip->len + (inst == BC_INST_RET))); 1145 1146 f = bc_vec_item(&p->fns, ip->func); 1147 res = bc_program_prepResult(p); 1148 1149 if (inst == BC_INST_RET) { 1150 1151 BcNum *num; 1152 BcResult *operand; 1153 1154 bc_program_operand(p, &operand, &num, 1); 1155 1156 BC_SIG_LOCK; 1157 1158 bc_num_createCopy(&res->d.n, num); 1159 } 1160 else if (inst == BC_INST_RET_VOID) res->t = BC_RESULT_VOID; 1161 else { 1162 BC_SIG_LOCK; 1163 bc_num_init(&res->d.n, BC_NUM_DEF_SIZE); 1164 } 1165 1166 BC_SIG_MAYUNLOCK; 1167 1168 // We need to pop arguments as well, so this takes that into account. 1169 for (i = 0; i < f->autos.len; ++i) { 1170 1171 BcLoc *a = bc_vec_item(&f->autos, i); 1172 BcVec *v = bc_program_vec(p, a->loc, (BcType) a->idx); 1173 1174 bc_vec_pop(v); 1175 } 1176 1177 bc_program_retire(p, 1, nops); 1178 1179 if (BC_G) bc_program_popGlobals(p, false); 1180 1181 bc_vec_pop(&p->stack); 1182 } 1183 #endif // BC_ENABLED 1184 1185 static void bc_program_builtin(BcProgram *p, uchar inst) { 1186 1187 BcResult *opd, *res; 1188 BcNum *num; 1189 bool len = (inst == BC_INST_LENGTH); 1190 1191 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND 1192 assert(inst >= BC_INST_LENGTH && inst <= BC_INST_IRAND); 1193 #else // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND 1194 assert(inst >= BC_INST_LENGTH && inst <= BC_INST_ABS); 1195 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND 1196 1197 #ifndef BC_PROG_NO_STACK_CHECK 1198 if (BC_IS_DC) { 1199 if (BC_ERR(!BC_PROG_STACK(&p->results, 1))) 1200 bc_vm_err(BC_ERR_EXEC_STACK); 1201 } 1202 #endif // BC_PROG_NO_STACK_CHECK 1203 1204 assert(BC_PROG_STACK(&p->results, 1)); 1205 1206 res = bc_program_prepResult(p); 1207 1208 bc_program_operand(p, &opd, &num, 1); 1209 1210 assert(num != NULL); 1211 1212 #if DC_ENABLED 1213 if (!len && inst != BC_INST_SCALE_FUNC) bc_program_type_num(opd, num); 1214 #endif // DC_ENABLED 1215 1216 if (inst == BC_INST_SQRT) bc_num_sqrt(num, &res->d.n, BC_PROG_SCALE(p)); 1217 else if (inst == BC_INST_ABS) { 1218 1219 BC_SIG_LOCK; 1220 1221 bc_num_createCopy(&res->d.n, num); 1222 1223 BC_SIG_UNLOCK; 1224 1225 BC_NUM_NEG_CLR_NP(res->d.n); 1226 } 1227 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND 1228 else if (inst == BC_INST_IRAND) { 1229 1230 BC_SIG_LOCK; 1231 1232 bc_num_init(&res->d.n, num->len - num->rdx); 1233 1234 BC_SIG_UNLOCK; 1235 1236 bc_num_irand(num, &res->d.n, &p->rng); 1237 } 1238 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND 1239 else { 1240 1241 BcBigDig val = 0; 1242 1243 if (len) { 1244 #if BC_ENABLED 1245 if (BC_IS_BC && opd->t == BC_RESULT_ARRAY) { 1246 1247 BcVec *v = (BcVec*) num; 1248 1249 if (v->size == sizeof(uchar)) v = bc_program_dereference(p, v); 1250 1251 assert(v->size == sizeof(BcNum)); 1252 1253 val = (BcBigDig) v->len; 1254 } 1255 else 1256 #endif // BC_ENABLED 1257 { 1258 #if DC_ENABLED 1259 if (!BC_PROG_NUM(opd, num)) { 1260 1261 size_t idx; 1262 char *str; 1263 1264 idx = opd->t == BC_RESULT_STR ? opd->d.loc.loc : num->scale; 1265 str = *((char**) bc_vec_item(p->strs, idx)); 1266 val = (BcBigDig) strlen(str); 1267 } 1268 else 1269 #endif // DC_ENABLED 1270 { 1271 val = (BcBigDig) bc_num_len(num); 1272 } 1273 } 1274 } 1275 else if (BC_IS_BC || BC_PROG_NUM(opd, num)) 1276 val = (BcBigDig) bc_num_scale(num); 1277 1278 BC_SIG_LOCK; 1279 1280 bc_num_createFromBigdig(&res->d.n, val); 1281 1282 BC_SIG_UNLOCK; 1283 } 1284 1285 bc_program_retire(p, 1, 1); 1286 } 1287 1288 #if DC_ENABLED 1289 static void bc_program_divmod(BcProgram *p) { 1290 1291 BcResult *opd1, *opd2, *res, *res2; 1292 BcNum *n1, *n2; 1293 size_t req; 1294 1295 bc_vec_grow(&p->results, 2); 1296 1297 // We don't need to update the pointer because 1298 // the capacity is enough due to the line above. 1299 res2 = bc_program_prepResult(p); 1300 res = bc_program_prepResult(p); 1301 1302 bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2, 2); 1303 1304 req = bc_num_mulReq(n1, n2, BC_PROG_SCALE(p)); 1305 1306 BC_SIG_LOCK; 1307 1308 bc_num_init(&res->d.n, req); 1309 bc_num_init(&res2->d.n, req); 1310 1311 BC_SIG_UNLOCK; 1312 1313 bc_num_divmod(n1, n2, &res2->d.n, &res->d.n, BC_PROG_SCALE(p)); 1314 1315 bc_program_retire(p, 2, 2); 1316 } 1317 1318 static void bc_program_modexp(BcProgram *p) { 1319 1320 BcResult *r1, *r2, *r3, *res; 1321 BcNum *n1, *n2, *n3; 1322 1323 if (BC_ERR(!BC_PROG_STACK(&p->results, 3))) bc_vm_err(BC_ERR_EXEC_STACK); 1324 1325 assert(BC_PROG_STACK(&p->results, 3)); 1326 1327 res = bc_program_prepResult(p); 1328 1329 bc_program_operand(p, &r1, &n1, 3); 1330 bc_program_type_num(r1, n1); 1331 1332 bc_program_binOpPrep(p, &r2, &n2, &r3, &n3, 1); 1333 1334 // Make sure that the values have their pointers updated, if necessary. 1335 // Only array elements are possible. 1336 if (r1->t == BC_RESULT_ARRAY_ELEM && (r1->t == r2->t || r1->t == r3->t)) 1337 n1 = bc_program_num(p, r1); 1338 1339 BC_SIG_LOCK; 1340 1341 bc_num_init(&res->d.n, n3->len); 1342 1343 BC_SIG_UNLOCK; 1344 1345 bc_num_modexp(n1, n2, n3, &res->d.n); 1346 1347 bc_program_retire(p, 1, 3); 1348 } 1349 1350 static void bc_program_stackLen(BcProgram *p) { 1351 bc_program_pushBigdig(p, (BcBigDig) p->results.len, BC_RESULT_TEMP); 1352 } 1353 1354 static uchar bc_program_asciifyNum(BcProgram *p, BcNum *n) { 1355 1356 BcNum num; 1357 BcBigDig val = 0; 1358 1359 bc_num_clear(&num); 1360 1361 BC_SETJMP(num_err); 1362 1363 BC_SIG_LOCK; 1364 1365 bc_num_createCopy(&num, n); 1366 1367 BC_SIG_UNLOCK; 1368 1369 bc_num_truncate(&num, num.scale); 1370 BC_NUM_NEG_CLR_NP(num); 1371 1372 // This is guaranteed to not have a divide by 0 1373 // because strmb is equal to UCHAR_MAX + 1. 1374 bc_num_mod(&num, &p->strmb, &num, 0); 1375 1376 // This is also guaranteed to not error because num is in the range 1377 // [0, UCHAR_MAX], which is definitely in range for a BcBigDig. And 1378 // it is not negative. 1379 bc_num_bigdig2(&num, &val); 1380 1381 num_err: 1382 BC_SIG_MAYLOCK; 1383 bc_num_free(&num); 1384 BC_LONGJMP_CONT; 1385 return (uchar) val; 1386 } 1387 1388 static void bc_program_asciify(BcProgram *p) { 1389 1390 BcResult *r, res; 1391 BcNum *n; 1392 char str[2], *str2; 1393 uchar c; 1394 size_t idx; 1395 1396 if (BC_ERR(!BC_PROG_STACK(&p->results, 1))) bc_vm_err(BC_ERR_EXEC_STACK); 1397 1398 assert(BC_PROG_STACK(&p->results, 1)); 1399 1400 bc_program_operand(p, &r, &n, 0); 1401 1402 assert(n != NULL); 1403 1404 assert(p->strs->len + BC_PROG_REQ_FUNCS == p->fns.len); 1405 1406 if (BC_PROG_NUM(r, n)) c = bc_program_asciifyNum(p, n); 1407 else { 1408 size_t index = r->t == BC_RESULT_STR ? r->d.loc.loc : n->scale; 1409 str2 = *((char**) bc_vec_item(p->strs, index)); 1410 c = (uchar) str2[0]; 1411 } 1412 1413 str[0] = (char) c; 1414 str[1] = '\0'; 1415 1416 BC_SIG_LOCK; 1417 1418 idx = bc_program_insertFunc(p, str) - BC_PROG_REQ_FUNCS; 1419 1420 BC_SIG_UNLOCK; 1421 1422 res.t = BC_RESULT_STR; 1423 res.d.loc.loc = idx; 1424 bc_vec_pop(&p->results); 1425 bc_vec_push(&p->results, &res); 1426 } 1427 1428 static void bc_program_printStream(BcProgram *p) { 1429 1430 BcResult *r; 1431 BcNum *n; 1432 1433 if (BC_ERR(!BC_PROG_STACK(&p->results, 1))) bc_vm_err(BC_ERR_EXEC_STACK); 1434 1435 assert(BC_PROG_STACK(&p->results, 1)); 1436 1437 bc_program_operand(p, &r, &n, 0); 1438 1439 assert(n != NULL); 1440 1441 if (BC_PROG_NUM(r, n)) bc_num_stream(n, p->strm); 1442 else { 1443 size_t idx = (r->t == BC_RESULT_STR) ? r->d.loc.loc : n->scale; 1444 bc_program_printChars(*((char**) bc_vec_item(p->strs, idx))); 1445 } 1446 1447 bc_vec_pop(&p->results); 1448 } 1449 1450 static void bc_program_nquit(BcProgram *p, uchar inst) { 1451 1452 BcResult *opnd; 1453 BcNum *num; 1454 BcBigDig val; 1455 size_t i; 1456 1457 assert(p->stack.len == p->tail_calls.len); 1458 1459 if (inst == BC_INST_QUIT) val = 2; 1460 else { 1461 1462 bc_program_prep(p, &opnd, &num, 0); 1463 bc_num_bigdig(num, &val); 1464 1465 bc_vec_pop(&p->results); 1466 } 1467 1468 for (i = 0; val && i < p->tail_calls.len; ++i) { 1469 size_t calls = *((size_t*) bc_vec_item_rev(&p->tail_calls, i)) + 1; 1470 if (calls >= val) val = 0; 1471 else val -= (BcBigDig) calls; 1472 } 1473 1474 if (i == p->stack.len) { 1475 vm.status = BC_STATUS_QUIT; 1476 BC_VM_JMP; 1477 } 1478 else { 1479 bc_vec_npop(&p->stack, i); 1480 bc_vec_npop(&p->tail_calls, i); 1481 } 1482 } 1483 1484 static void bc_program_execStr(BcProgram *p, const char *restrict code, 1485 size_t *restrict bgn, bool cond, size_t len) 1486 { 1487 BcResult *r; 1488 char *str; 1489 BcFunc *f; 1490 BcParse prs; 1491 BcInstPtr ip; 1492 size_t fidx, sidx; 1493 BcNum *n; 1494 1495 assert(p->stack.len == p->tail_calls.len); 1496 1497 if (BC_ERR(!BC_PROG_STACK(&p->results, 1))) bc_vm_err(BC_ERR_EXEC_STACK); 1498 1499 assert(BC_PROG_STACK(&p->results, 1)); 1500 1501 bc_program_operand(p, &r, &n, 0); 1502 1503 if (cond) { 1504 1505 bool exec; 1506 size_t idx, then_idx, else_idx; 1507 1508 then_idx = bc_program_index(code, bgn); 1509 else_idx = bc_program_index(code, bgn); 1510 1511 exec = (r->d.n.len != 0); 1512 1513 idx = exec ? then_idx : else_idx; 1514 1515 BC_SIG_LOCK; 1516 BC_SETJMP_LOCKED(exit); 1517 1518 if (exec || (else_idx != SIZE_MAX)) 1519 n = bc_vec_top(bc_program_vec(p, idx, BC_TYPE_VAR)); 1520 else goto exit; 1521 1522 if (BC_ERR(!BC_PROG_STR(n))) bc_vm_err(BC_ERR_EXEC_TYPE); 1523 1524 BC_UNSETJMP; 1525 BC_SIG_UNLOCK; 1526 1527 sidx = n->scale; 1528 } 1529 else { 1530 1531 // In non-conditional situations, only the top of stack can be executed, 1532 // and in those cases, variables are not allowed to be "on the stack"; 1533 // they are only put on the stack to be assigned to. 1534 assert(r->t != BC_RESULT_VAR); 1535 1536 if (r->t == BC_RESULT_STR) sidx = r->d.loc.loc; 1537 else return; 1538 } 1539 1540 fidx = sidx + BC_PROG_REQ_FUNCS; 1541 str = *((char**) bc_vec_item(p->strs, sidx)); 1542 f = bc_vec_item(&p->fns, fidx); 1543 1544 if (!f->code.len) { 1545 1546 BC_SIG_LOCK; 1547 1548 bc_parse_init(&prs, p, fidx); 1549 bc_lex_file(&prs.l, vm.file); 1550 1551 BC_SETJMP_LOCKED(err); 1552 1553 BC_SIG_UNLOCK; 1554 1555 bc_parse_text(&prs, str); 1556 vm.expr(&prs, BC_PARSE_NOCALL); 1557 1558 BC_SIG_LOCK; 1559 1560 BC_UNSETJMP; 1561 1562 // We can just assert this here because 1563 // dc should parse everything until EOF. 1564 assert(prs.l.t == BC_LEX_EOF); 1565 1566 bc_parse_free(&prs); 1567 1568 BC_SIG_UNLOCK; 1569 } 1570 1571 ip.idx = 0; 1572 ip.len = p->results.len; 1573 ip.func = fidx; 1574 1575 bc_vec_pop(&p->results); 1576 1577 // Tail call. 1578 if (p->stack.len > 1 && *bgn == len - 1 && code[*bgn] == BC_INST_POP_EXEC) { 1579 size_t *call_ptr = bc_vec_top(&p->tail_calls); 1580 *call_ptr += 1; 1581 bc_vec_pop(&p->stack); 1582 } 1583 else bc_vec_push(&p->tail_calls, &ip.idx); 1584 1585 bc_vec_push(&p->stack, &ip); 1586 1587 return; 1588 1589 err: 1590 BC_SIG_MAYLOCK; 1591 bc_parse_free(&prs); 1592 f = bc_vec_item(&p->fns, fidx); 1593 bc_vec_popAll(&f->code); 1594 exit: 1595 bc_vec_pop(&p->results); 1596 BC_LONGJMP_CONT; 1597 } 1598 1599 static void bc_program_printStack(BcProgram *p) { 1600 1601 size_t idx; 1602 1603 for (idx = 0; idx < p->results.len; ++idx) 1604 bc_program_print(p, BC_INST_PRINT, idx); 1605 } 1606 #endif // DC_ENABLED 1607 1608 static void bc_program_pushGlobal(BcProgram *p, uchar inst) { 1609 1610 BcResultType t; 1611 1612 assert(inst >= BC_INST_IBASE && inst <= BC_INST_SCALE); 1613 1614 t = inst - BC_INST_IBASE + BC_RESULT_IBASE; 1615 bc_program_pushBigdig(p, p->globals[inst - BC_INST_IBASE], t); 1616 } 1617 1618 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND 1619 static void bc_program_pushSeed(BcProgram *p) { 1620 1621 BcResult *res; 1622 1623 res = bc_program_prepResult(p); 1624 res->t = BC_RESULT_SEED; 1625 1626 BC_SIG_LOCK; 1627 1628 bc_num_init(&res->d.n, 2 * BC_RAND_NUM_SIZE); 1629 1630 BC_SIG_UNLOCK; 1631 1632 bc_num_createFromRNG(&res->d.n, &p->rng); 1633 } 1634 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND 1635 1636 static void bc_program_addFunc(BcProgram *p, BcFunc *f, BcId *id_ptr) { 1637 1638 BcInstPtr *ip; 1639 1640 BC_SIG_ASSERT_LOCKED; 1641 1642 bc_func_init(f, id_ptr->name); 1643 bc_vec_push(&p->fns, f); 1644 1645 // This is to make sure pointers are updated if the array was moved. 1646 if (p->stack.len) { 1647 ip = bc_vec_top(&p->stack); 1648 bc_program_setVecs(p, (BcFunc*) bc_vec_item(&p->fns, ip->func)); 1649 } 1650 } 1651 1652 size_t bc_program_insertFunc(BcProgram *p, const char *name) { 1653 1654 BcId *id_ptr; 1655 BcFunc f; 1656 bool new; 1657 size_t idx; 1658 1659 BC_SIG_ASSERT_LOCKED; 1660 1661 assert(p != NULL && name != NULL); 1662 1663 new = bc_map_insert(&p->fn_map, name, p->fns.len, &idx); 1664 id_ptr = (BcId*) bc_vec_item(&p->fn_map, idx); 1665 idx = id_ptr->idx; 1666 1667 if (!new) { 1668 if (BC_IS_BC) { 1669 BcFunc *func = bc_vec_item(&p->fns, idx); 1670 bc_func_reset(func); 1671 } 1672 } 1673 else { 1674 1675 bc_program_addFunc(p, &f, id_ptr); 1676 1677 #if DC_ENABLED 1678 if (BC_IS_DC && idx >= BC_PROG_REQ_FUNCS) { 1679 bc_vec_push(p->strs, &id_ptr->name); 1680 assert(p->strs->len == p->fns.len - BC_PROG_REQ_FUNCS); 1681 } 1682 #endif // DC_ENABLED 1683 } 1684 1685 return idx; 1686 } 1687 1688 #ifndef NDEBUG 1689 void bc_program_free(BcProgram *p) { 1690 1691 size_t i; 1692 1693 BC_SIG_ASSERT_LOCKED; 1694 1695 assert(p != NULL); 1696 1697 for (i = 0; i < BC_PROG_GLOBALS_LEN; ++i) bc_vec_free(p->globals_v + i); 1698 1699 bc_vec_free(&p->fns); 1700 bc_vec_free(&p->fn_map); 1701 bc_vec_free(&p->vars); 1702 bc_vec_free(&p->var_map); 1703 bc_vec_free(&p->arrs); 1704 bc_vec_free(&p->arr_map); 1705 bc_vec_free(&p->results); 1706 bc_vec_free(&p->stack); 1707 1708 #if BC_ENABLED 1709 if (BC_IS_BC) bc_num_free(&p->last); 1710 #endif // BC_ENABLED 1711 1712 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND 1713 bc_rand_free(&p->rng); 1714 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND 1715 1716 #if DC_ENABLED 1717 if (BC_IS_DC) { 1718 bc_vec_free(&p->tail_calls); 1719 bc_vec_free(&p->strs_v); 1720 } 1721 #endif // DC_ENABLED 1722 } 1723 #endif // NDEBUG 1724 1725 void bc_program_init(BcProgram *p) { 1726 1727 BcInstPtr ip; 1728 size_t i; 1729 1730 BC_SIG_ASSERT_LOCKED; 1731 1732 assert(p != NULL); 1733 1734 memset(p, 0, sizeof(BcProgram)); 1735 memset(&ip, 0, sizeof(BcInstPtr)); 1736 1737 for (i = 0; i < BC_PROG_GLOBALS_LEN; ++i) { 1738 BcBigDig val = i == BC_PROG_GLOBALS_SCALE ? 0 : BC_BASE; 1739 bc_vec_init(p->globals_v + i, sizeof(BcBigDig), NULL); 1740 bc_vec_push(p->globals_v + i, &val); 1741 p->globals[i] = val; 1742 } 1743 1744 #if DC_ENABLED 1745 if (BC_IS_DC) { 1746 1747 bc_vec_init(&p->strs_v, sizeof(char*), bc_string_free); 1748 p->strs = &p->strs_v; 1749 1750 bc_vec_init(&p->tail_calls, sizeof(size_t), NULL); 1751 i = 0; 1752 bc_vec_push(&p->tail_calls, &i); 1753 1754 p->strm = UCHAR_MAX + 1; 1755 bc_num_setup(&p->strmb, p->strmb_num, BC_NUM_BIGDIG_LOG10); 1756 bc_num_bigdig2num(&p->strmb, p->strm); 1757 } 1758 #endif // DC_ENABLED 1759 1760 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND 1761 srand((unsigned int) time(NULL)); 1762 bc_rand_init(&p->rng); 1763 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND 1764 1765 bc_num_setup(&p->zero, p->zero_num, BC_PROG_ONE_CAP); 1766 1767 bc_num_setup(&p->one, p->one_num, BC_PROG_ONE_CAP); 1768 bc_num_one(&p->one); 1769 1770 #if BC_ENABLED 1771 if (BC_IS_BC) bc_num_init(&p->last, BC_NUM_DEF_SIZE); 1772 #endif // BC_ENABLED 1773 1774 bc_vec_init(&p->fns, sizeof(BcFunc), bc_func_free); 1775 bc_map_init(&p->fn_map); 1776 bc_program_insertFunc(p, bc_func_main); 1777 bc_program_insertFunc(p, bc_func_read); 1778 1779 bc_vec_init(&p->vars, sizeof(BcVec), bc_vec_free); 1780 bc_map_init(&p->var_map); 1781 1782 bc_vec_init(&p->arrs, sizeof(BcVec), bc_vec_free); 1783 bc_map_init(&p->arr_map); 1784 1785 bc_vec_init(&p->results, sizeof(BcResult), bc_result_free); 1786 bc_vec_init(&p->stack, sizeof(BcInstPtr), NULL); 1787 bc_vec_push(&p->stack, &ip); 1788 1789 bc_program_setVecs(p, (BcFunc*) bc_vec_item(&p->fns, BC_PROG_MAIN)); 1790 1791 assert(p->consts != NULL && p->strs != NULL); 1792 } 1793 1794 void bc_program_reset(BcProgram *p) { 1795 1796 BcFunc *f; 1797 BcInstPtr *ip; 1798 1799 BC_SIG_ASSERT_LOCKED; 1800 1801 bc_vec_npop(&p->stack, p->stack.len - 1); 1802 bc_vec_popAll(&p->results); 1803 1804 #if BC_ENABLED 1805 if (BC_G) bc_program_popGlobals(p, true); 1806 #endif // BC_ENABLED 1807 1808 f = bc_vec_item(&p->fns, BC_PROG_MAIN); 1809 bc_vec_npop(&f->code, f->code.len); 1810 ip = bc_vec_top(&p->stack); 1811 bc_program_setVecs(p, f); 1812 memset(ip, 0, sizeof(BcInstPtr)); 1813 1814 if (vm.sig) { 1815 bc_file_write(&vm.fout, bc_flush_none, bc_program_ready_msg, 1816 bc_program_ready_msg_len); 1817 bc_file_flush(&vm.fout, bc_flush_err); 1818 vm.sig = 0; 1819 } 1820 } 1821 1822 void bc_program_exec(BcProgram *p) { 1823 1824 size_t idx; 1825 BcResult r, *ptr; 1826 BcInstPtr *ip = bc_vec_top(&p->stack); 1827 BcFunc *func = (BcFunc*) bc_vec_item(&p->fns, ip->func); 1828 char *code = func->code.v; 1829 bool cond = false; 1830 #if BC_ENABLED 1831 BcNum *num; 1832 #endif // BC_ENABLED 1833 #ifndef NDEBUG 1834 size_t jmp_bufs_len; 1835 #endif // NDEBUG 1836 1837 #ifndef NDEBUG 1838 jmp_bufs_len = vm.jmp_bufs.len; 1839 #endif // NDEBUG 1840 1841 bc_program_setVecs(p, func); 1842 1843 while (ip->idx < func->code.len) { 1844 1845 BC_SIG_ASSERT_NOT_LOCKED; 1846 1847 uchar inst = (uchar) code[(ip->idx)++]; 1848 1849 switch (inst) { 1850 1851 #if BC_ENABLED 1852 case BC_INST_JUMP_ZERO: 1853 { 1854 bc_program_prep(p, &ptr, &num, 0); 1855 cond = !bc_num_cmpZero(num); 1856 bc_vec_pop(&p->results); 1857 } 1858 // Fallthrough. 1859 BC_FALLTHROUGH 1860 1861 case BC_INST_JUMP: 1862 { 1863 idx = bc_program_index(code, &ip->idx); 1864 1865 if (inst == BC_INST_JUMP || cond) { 1866 1867 size_t *addr = bc_vec_item(&func->labels, idx); 1868 1869 assert(*addr != SIZE_MAX); 1870 1871 ip->idx = *addr; 1872 } 1873 1874 break; 1875 } 1876 1877 case BC_INST_CALL: 1878 { 1879 assert(BC_IS_BC); 1880 1881 bc_program_call(p, code, &ip->idx); 1882 1883 ip = bc_vec_top(&p->stack); 1884 func = bc_vec_item(&p->fns, ip->func); 1885 code = func->code.v; 1886 1887 bc_program_setVecs(p, func); 1888 1889 break; 1890 } 1891 1892 case BC_INST_INC: 1893 case BC_INST_DEC: 1894 { 1895 bc_program_incdec(p, inst); 1896 break; 1897 } 1898 1899 case BC_INST_HALT: 1900 { 1901 vm.status = BC_STATUS_QUIT; 1902 BC_VM_JMP; 1903 break; 1904 } 1905 1906 case BC_INST_RET: 1907 case BC_INST_RET0: 1908 case BC_INST_RET_VOID: 1909 { 1910 bc_program_return(p, inst); 1911 1912 ip = bc_vec_top(&p->stack); 1913 func = bc_vec_item(&p->fns, ip->func); 1914 code = func->code.v; 1915 1916 bc_program_setVecs(p, func); 1917 1918 break; 1919 } 1920 #endif // BC_ENABLED 1921 1922 case BC_INST_BOOL_OR: 1923 case BC_INST_BOOL_AND: 1924 case BC_INST_REL_EQ: 1925 case BC_INST_REL_LE: 1926 case BC_INST_REL_GE: 1927 case BC_INST_REL_NE: 1928 case BC_INST_REL_LT: 1929 case BC_INST_REL_GT: 1930 { 1931 bc_program_logical(p, inst); 1932 break; 1933 } 1934 1935 case BC_INST_READ: 1936 { 1937 // We want to flush output before 1938 // this in case there is a prompt. 1939 bc_file_flush(&vm.fout, bc_flush_save); 1940 1941 bc_program_read(p); 1942 1943 ip = bc_vec_top(&p->stack); 1944 func = bc_vec_item(&p->fns, ip->func); 1945 code = func->code.v; 1946 1947 bc_program_setVecs(p, func); 1948 1949 break; 1950 } 1951 1952 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND 1953 case BC_INST_RAND: 1954 { 1955 bc_program_rand(p); 1956 break; 1957 } 1958 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND 1959 1960 case BC_INST_MAXIBASE: 1961 case BC_INST_MAXOBASE: 1962 case BC_INST_MAXSCALE: 1963 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND 1964 case BC_INST_MAXRAND: 1965 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND 1966 { 1967 BcBigDig dig = vm.maxes[inst - BC_INST_MAXIBASE]; 1968 bc_program_pushBigdig(p, dig, BC_RESULT_TEMP); 1969 break; 1970 } 1971 1972 case BC_INST_VAR: 1973 { 1974 bc_program_pushVar(p, code, &ip->idx, false, false); 1975 break; 1976 } 1977 1978 case BC_INST_ARRAY_ELEM: 1979 #if BC_ENABLED 1980 case BC_INST_ARRAY: 1981 #endif // BC_ENABLED 1982 { 1983 bc_program_pushArray(p, code, &ip->idx, inst); 1984 break; 1985 } 1986 1987 case BC_INST_IBASE: 1988 case BC_INST_SCALE: 1989 case BC_INST_OBASE: 1990 { 1991 bc_program_pushGlobal(p, inst); 1992 break; 1993 } 1994 1995 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND 1996 case BC_INST_SEED: 1997 { 1998 bc_program_pushSeed(p); 1999 break; 2000 } 2001 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND 2002 2003 case BC_INST_LENGTH: 2004 case BC_INST_SCALE_FUNC: 2005 case BC_INST_SQRT: 2006 case BC_INST_ABS: 2007 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND 2008 case BC_INST_IRAND: 2009 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND 2010 { 2011 bc_program_builtin(p, inst); 2012 break; 2013 } 2014 2015 case BC_INST_NUM: 2016 { 2017 bc_program_const(p, code, &ip->idx); 2018 break; 2019 } 2020 2021 case BC_INST_ZERO: 2022 case BC_INST_ONE: 2023 #if BC_ENABLED 2024 case BC_INST_LAST: 2025 #endif // BC_ENABLED 2026 { 2027 r.t = BC_RESULT_ZERO + (inst - BC_INST_ZERO); 2028 bc_vec_push(&p->results, &r); 2029 break; 2030 } 2031 2032 case BC_INST_PRINT: 2033 case BC_INST_PRINT_POP: 2034 case BC_INST_PRINT_STR: 2035 { 2036 bc_program_print(p, inst, 0); 2037 bc_file_flush(&vm.fout, bc_flush_save); 2038 break; 2039 } 2040 2041 case BC_INST_STR: 2042 { 2043 r.t = BC_RESULT_STR; 2044 r.d.loc.loc = bc_program_index(code, &ip->idx); 2045 bc_vec_push(&p->results, &r); 2046 break; 2047 } 2048 2049 case BC_INST_POWER: 2050 case BC_INST_MULTIPLY: 2051 case BC_INST_DIVIDE: 2052 case BC_INST_MODULUS: 2053 case BC_INST_PLUS: 2054 case BC_INST_MINUS: 2055 #if BC_ENABLE_EXTRA_MATH 2056 case BC_INST_PLACES: 2057 case BC_INST_LSHIFT: 2058 case BC_INST_RSHIFT: 2059 #endif // BC_ENABLE_EXTRA_MATH 2060 { 2061 bc_program_op(p, inst); 2062 break; 2063 } 2064 2065 case BC_INST_NEG: 2066 case BC_INST_BOOL_NOT: 2067 #if BC_ENABLE_EXTRA_MATH 2068 case BC_INST_TRUNC: 2069 #endif // BC_ENABLE_EXTRA_MATH 2070 { 2071 bc_program_unary(p, inst); 2072 break; 2073 } 2074 2075 #if BC_ENABLED 2076 case BC_INST_ASSIGN_POWER: 2077 case BC_INST_ASSIGN_MULTIPLY: 2078 case BC_INST_ASSIGN_DIVIDE: 2079 case BC_INST_ASSIGN_MODULUS: 2080 case BC_INST_ASSIGN_PLUS: 2081 case BC_INST_ASSIGN_MINUS: 2082 #if BC_ENABLE_EXTRA_MATH 2083 case BC_INST_ASSIGN_PLACES: 2084 case BC_INST_ASSIGN_LSHIFT: 2085 case BC_INST_ASSIGN_RSHIFT: 2086 #endif // BC_ENABLE_EXTRA_MATH 2087 case BC_INST_ASSIGN: 2088 case BC_INST_ASSIGN_POWER_NO_VAL: 2089 case BC_INST_ASSIGN_MULTIPLY_NO_VAL: 2090 case BC_INST_ASSIGN_DIVIDE_NO_VAL: 2091 case BC_INST_ASSIGN_MODULUS_NO_VAL: 2092 case BC_INST_ASSIGN_PLUS_NO_VAL: 2093 case BC_INST_ASSIGN_MINUS_NO_VAL: 2094 #if BC_ENABLE_EXTRA_MATH 2095 case BC_INST_ASSIGN_PLACES_NO_VAL: 2096 case BC_INST_ASSIGN_LSHIFT_NO_VAL: 2097 case BC_INST_ASSIGN_RSHIFT_NO_VAL: 2098 #endif // BC_ENABLE_EXTRA_MATH 2099 #endif // BC_ENABLED 2100 case BC_INST_ASSIGN_NO_VAL: 2101 { 2102 bc_program_assign(p, inst); 2103 break; 2104 } 2105 2106 case BC_INST_POP: 2107 { 2108 #ifndef BC_PROG_NO_STACK_CHECK 2109 if (!BC_IS_BC) { 2110 if (BC_ERR(!BC_PROG_STACK(&p->results, 1))) 2111 bc_vm_err(BC_ERR_EXEC_STACK); 2112 } 2113 #endif // BC_PROG_NO_STACK_CHECK 2114 2115 assert(BC_PROG_STACK(&p->results, 1)); 2116 2117 bc_vec_pop(&p->results); 2118 break; 2119 } 2120 2121 #if DC_ENABLED 2122 case BC_INST_POP_EXEC: 2123 { 2124 assert(BC_PROG_STACK(&p->stack, 2)); 2125 bc_vec_pop(&p->stack); 2126 bc_vec_pop(&p->tail_calls); 2127 ip = bc_vec_top(&p->stack); 2128 func = bc_vec_item(&p->fns, ip->func); 2129 code = func->code.v; 2130 bc_program_setVecs(p, func); 2131 break; 2132 } 2133 2134 case BC_INST_MODEXP: 2135 { 2136 bc_program_modexp(p); 2137 break; 2138 } 2139 2140 case BC_INST_DIVMOD: 2141 { 2142 bc_program_divmod(p); 2143 break; 2144 } 2145 2146 case BC_INST_EXECUTE: 2147 case BC_INST_EXEC_COND: 2148 { 2149 cond = (inst == BC_INST_EXEC_COND); 2150 bc_program_execStr(p, code, &ip->idx, cond, func->code.len); 2151 ip = bc_vec_top(&p->stack); 2152 func = bc_vec_item(&p->fns, ip->func); 2153 code = func->code.v; 2154 bc_program_setVecs(p, func); 2155 break; 2156 } 2157 2158 case BC_INST_PRINT_STACK: 2159 { 2160 bc_program_printStack(p); 2161 break; 2162 } 2163 2164 case BC_INST_CLEAR_STACK: 2165 { 2166 bc_vec_popAll(&p->results); 2167 break; 2168 } 2169 2170 case BC_INST_STACK_LEN: 2171 { 2172 bc_program_stackLen(p); 2173 break; 2174 } 2175 2176 case BC_INST_DUPLICATE: 2177 { 2178 if (BC_ERR(!BC_PROG_STACK(&p->results, 1))) 2179 bc_vm_err(BC_ERR_EXEC_STACK); 2180 2181 assert(BC_PROG_STACK(&p->results, 1)); 2182 2183 ptr = bc_vec_top(&p->results); 2184 2185 BC_SIG_LOCK; 2186 2187 bc_result_copy(&r, ptr); 2188 bc_vec_push(&p->results, &r); 2189 2190 BC_SIG_UNLOCK; 2191 2192 break; 2193 } 2194 2195 case BC_INST_SWAP: 2196 { 2197 BcResult *ptr2; 2198 2199 if (BC_ERR(!BC_PROG_STACK(&p->results, 2))) 2200 bc_vm_err(BC_ERR_EXEC_STACK); 2201 2202 assert(BC_PROG_STACK(&p->results, 2)); 2203 2204 ptr = bc_vec_item_rev(&p->results, 0); 2205 ptr2 = bc_vec_item_rev(&p->results, 1); 2206 memcpy(&r, ptr, sizeof(BcResult)); 2207 memcpy(ptr, ptr2, sizeof(BcResult)); 2208 memcpy(ptr2, &r, sizeof(BcResult)); 2209 2210 break; 2211 } 2212 2213 case BC_INST_ASCIIFY: 2214 { 2215 bc_program_asciify(p); 2216 ip = bc_vec_top(&p->stack); 2217 func = bc_vec_item(&p->fns, ip->func); 2218 code = func->code.v; 2219 bc_program_setVecs(p, func); 2220 break; 2221 } 2222 2223 case BC_INST_PRINT_STREAM: 2224 { 2225 bc_program_printStream(p); 2226 break; 2227 } 2228 2229 case BC_INST_LOAD: 2230 case BC_INST_PUSH_VAR: 2231 { 2232 bool copy = (inst == BC_INST_LOAD); 2233 bc_program_pushVar(p, code, &ip->idx, true, copy); 2234 break; 2235 } 2236 2237 case BC_INST_PUSH_TO_VAR: 2238 { 2239 idx = bc_program_index(code, &ip->idx); 2240 bc_program_copyToVar(p, idx, BC_TYPE_VAR, true); 2241 break; 2242 } 2243 2244 case BC_INST_QUIT: 2245 case BC_INST_NQUIT: 2246 { 2247 bc_program_nquit(p, inst); 2248 ip = bc_vec_top(&p->stack); 2249 func = bc_vec_item(&p->fns, ip->func); 2250 code = func->code.v; 2251 bc_program_setVecs(p, func); 2252 break; 2253 } 2254 #endif // DC_ENABLED 2255 #ifndef NDEBUG 2256 default: 2257 { 2258 abort(); 2259 } 2260 #endif // NDEBUG 2261 } 2262 2263 #ifndef NDEBUG 2264 // This is to allow me to use a debugger to see the last instruction, 2265 // which will point to which function was the problem. 2266 assert(jmp_bufs_len == vm.jmp_bufs.len); 2267 #endif // NDEBUG 2268 } 2269 } 2270 2271 #if BC_DEBUG_CODE 2272 #if BC_ENABLED && DC_ENABLED 2273 void bc_program_printStackDebug(BcProgram *p) { 2274 bc_file_puts(&vm.fout, bc_flush_err, "-------------- Stack ----------\n"); 2275 bc_program_printStack(p); 2276 bc_file_puts(&vm.fout, bc_flush_err, "-------------- Stack End ------\n"); 2277 } 2278 2279 static void bc_program_printIndex(const char *restrict code, 2280 size_t *restrict bgn) 2281 { 2282 uchar byte, i, bytes = (uchar) code[(*bgn)++]; 2283 ulong val = 0; 2284 2285 for (byte = 1, i = 0; byte && i < bytes; ++i) { 2286 byte = (uchar) code[(*bgn)++]; 2287 if (byte) val |= ((ulong) byte) << (CHAR_BIT * i); 2288 } 2289 2290 bc_vm_printf(" (%lu) ", val); 2291 } 2292 2293 static void bc_program_printStr(const BcProgram *p, const char *restrict code, 2294 size_t *restrict bgn) 2295 { 2296 size_t idx = bc_program_index(code, bgn); 2297 char *s; 2298 2299 s = *((char**) bc_vec_item(p->strs, idx)); 2300 2301 bc_vm_printf(" (\"%s\") ", s); 2302 } 2303 2304 void bc_program_printInst(const BcProgram *p, const char *restrict code, 2305 size_t *restrict bgn) 2306 { 2307 uchar inst = (uchar) code[(*bgn)++]; 2308 2309 bc_vm_printf("Inst[%zu]: %s [%lu]; ", *bgn - 1, 2310 bc_inst_names[inst], (unsigned long) inst); 2311 2312 if (inst == BC_INST_VAR || inst == BC_INST_ARRAY_ELEM || 2313 inst == BC_INST_ARRAY) 2314 { 2315 bc_program_printIndex(code, bgn); 2316 } 2317 else if (inst == BC_INST_STR) bc_program_printStr(p, code, bgn); 2318 else if (inst == BC_INST_NUM) { 2319 size_t idx = bc_program_index(code, bgn); 2320 BcConst *c = bc_vec_item(p->consts, idx); 2321 bc_vm_printf("(%s)", c->val); 2322 } 2323 else if (inst == BC_INST_CALL || 2324 (inst > BC_INST_STR && inst <= BC_INST_JUMP_ZERO)) 2325 { 2326 bc_program_printIndex(code, bgn); 2327 if (inst == BC_INST_CALL) bc_program_printIndex(code, bgn); 2328 } 2329 2330 bc_vm_putchar('\n', bc_flush_err); 2331 } 2332 2333 void bc_program_code(const BcProgram* p) { 2334 2335 BcFunc *f; 2336 char *code; 2337 BcInstPtr ip; 2338 size_t i; 2339 2340 for (i = 0; i < p->fns.len; ++i) { 2341 2342 ip.idx = ip.len = 0; 2343 ip.func = i; 2344 2345 f = bc_vec_item(&p->fns, ip.func); 2346 code = f->code.v; 2347 2348 bc_vm_printf("func[%zu]:\n", ip.func); 2349 while (ip.idx < f->code.len) bc_program_printInst(p, code, &ip.idx); 2350 bc_file_puts(&vm.fout, bc_flush_err, "\n\n"); 2351 } 2352 } 2353 #endif // BC_ENABLED && DC_ENABLED 2354 #endif // BC_DEBUG_CODE 2355