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