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