1 /* 2 * ***************************************************************************** 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 * 6 * Copyright (c) 2018-2025 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 /** 52 * Does a type check for something that expects a number. 53 * @param r The result that will be checked. 54 * @param n The result's number. 55 */ 56 static inline void 57 bc_program_type_num(BcResult* r, BcNum* n) 58 { 59 #if BC_ENABLED 60 61 // This should have already been taken care of. 62 assert(r->t != BC_RESULT_VOID); 63 64 #endif // BC_ENABLED 65 66 if (BC_ERR(!BC_PROG_NUM(r, n))) bc_err(BC_ERR_EXEC_TYPE); 67 } 68 69 #if BC_ENABLED 70 71 /** 72 * Does a type check. 73 * @param r The result to check. 74 * @param t The type that the result should be. 75 */ 76 static void 77 bc_program_type_match(BcResult* r, BcType t) 78 { 79 if (BC_ERR((r->t != BC_RESULT_ARRAY) != (!t))) bc_err(BC_ERR_EXEC_TYPE); 80 } 81 #endif // BC_ENABLED 82 83 /** 84 * Pulls an index out of a bytecode vector and updates the index into the vector 85 * to point to the spot after the index. For more details on bytecode indices, 86 * see the development manual (manuals/development.md#bytecode-indices). 87 * @param code The bytecode vector. 88 * @param bgn An in/out parameter; the index into the vector that will be 89 * updated. 90 * @return The index at @a bgn in the bytecode vector. 91 */ 92 static size_t 93 bc_program_index(const char* restrict code, size_t* restrict bgn) 94 { 95 uchar amt = (uchar) code[(*bgn)++], i = 0; 96 size_t res = 0; 97 98 for (; i < amt; ++i, ++(*bgn)) 99 { 100 size_t temp = ((size_t) ((int) (uchar) code[*bgn]) & UCHAR_MAX); 101 res |= (temp << (i * CHAR_BIT)); 102 } 103 104 return res; 105 } 106 107 /** 108 * Returns a string from a result and its number. 109 * @param p The program. 110 * @param n The number tied to the result. 111 * @return The string corresponding to the result and number. 112 */ 113 static inline char* 114 bc_program_string(BcProgram* p, const BcNum* n) 115 { 116 return *((char**) bc_vec_item(&p->strs, n->scale)); 117 } 118 119 #if BC_ENABLED 120 121 /** 122 * Prepares the globals for a function call. This is only called when global 123 * stacks are on because it pushes a copy of the current globals onto each of 124 * their respective stacks. 125 * @param p The program. 126 */ 127 static void 128 bc_program_prepGlobals(BcProgram* p) 129 { 130 size_t i; 131 132 for (i = 0; i < BC_PROG_GLOBALS_LEN; ++i) 133 { 134 bc_vec_push(p->globals_v + i, p->globals + i); 135 } 136 137 #if BC_ENABLE_EXTRA_MATH 138 bc_rand_push(&p->rng); 139 #endif // BC_ENABLE_EXTRA_MATH 140 } 141 142 /** 143 * Pops globals stacks on returning from a function, or in the case of reset, 144 * pops all but one item on each global stack. 145 * @param p The program. 146 * @param reset True if all but one item on each stack should be popped, false 147 * otherwise. 148 */ 149 static void 150 bc_program_popGlobals(BcProgram* p, bool reset) 151 { 152 size_t i; 153 154 BC_SIG_ASSERT_LOCKED; 155 156 for (i = 0; i < BC_PROG_GLOBALS_LEN; ++i) 157 { 158 BcVec* v = p->globals_v + i; 159 bc_vec_npop(v, reset ? v->len - 1 : 1); 160 p->globals[i] = BC_PROG_GLOBAL(v); 161 } 162 163 #if BC_ENABLE_EXTRA_MATH 164 bc_rand_pop(&p->rng, reset); 165 #endif // BC_ENABLE_EXTRA_MATH 166 } 167 168 /** 169 * Derefeneces an array reference and returns a pointer to the real array. 170 * @param p The program. 171 * @param vec The reference vector. 172 * @return A pointer to the desired array. 173 */ 174 static BcVec* 175 bc_program_dereference(const BcProgram* p, BcVec* vec) 176 { 177 BcVec* v; 178 size_t vidx, nidx, i = 0; 179 180 // We want to be sure we have a reference vector. 181 assert(vec->size == sizeof(uchar)); 182 183 // Get the index of the vector in arrs, then the index of the original 184 // referenced vector. 185 vidx = bc_program_index(vec->v, &i); 186 nidx = bc_program_index(vec->v, &i); 187 188 v = bc_vec_item(bc_vec_item(&p->arrs, vidx), nidx); 189 190 // We want to be sure we do *not* have a reference vector. 191 assert(v->size != sizeof(uchar)); 192 193 return v; 194 } 195 196 #endif // BC_ENABLED 197 198 /** 199 * Creates a BcNum from a BcBigDig and pushes onto the results stack. This is a 200 * convenience function. 201 * @param p The program. 202 * @param dig The BcBigDig to push onto the results stack. 203 * @param type The type that the pushed result should be. 204 */ 205 static void 206 bc_program_pushBigdig(BcProgram* p, BcBigDig dig, BcResultType type) 207 { 208 BcResult res; 209 210 res.t = type; 211 212 BC_SIG_LOCK; 213 214 bc_num_createFromBigdig(&res.d.n, dig); 215 bc_vec_push(&p->results, &res); 216 217 BC_SIG_UNLOCK; 218 } 219 220 size_t 221 bc_program_addString(BcProgram* p, const char* str) 222 { 223 size_t idx; 224 225 BC_SIG_ASSERT_LOCKED; 226 227 if (bc_map_insert(&p->str_map, str, p->strs.len, &idx)) 228 { 229 char** str_ptr; 230 BcId* id = bc_vec_item(&p->str_map, idx); 231 232 // Get the index. 233 idx = id->idx; 234 235 // Push an empty string on the proper vector. 236 str_ptr = bc_vec_pushEmpty(&p->strs); 237 238 // We reuse the string in the ID (allocated by bc_map_insert()), because 239 // why not? 240 *str_ptr = id->name; 241 } 242 else 243 { 244 BcId* id = bc_vec_item(&p->str_map, idx); 245 idx = id->idx; 246 } 247 248 return idx; 249 } 250 251 size_t 252 bc_program_search(BcProgram* p, const char* name, bool var) 253 { 254 BcVec* v; 255 BcVec* map; 256 size_t i; 257 258 BC_SIG_ASSERT_LOCKED; 259 260 // Grab the right vector and map. 261 v = var ? &p->vars : &p->arrs; 262 map = var ? &p->var_map : &p->arr_map; 263 264 // We do an insert because the variable might not exist yet. This is because 265 // the parser calls this function. If the insert succeeds, we create a stack 266 // for the variable/array. But regardless, bc_map_insert() gives us the 267 // index of the item in i. 268 if (bc_map_insert(map, name, v->len, &i)) 269 { 270 BcVec* temp = bc_vec_pushEmpty(v); 271 bc_array_init(temp, var); 272 } 273 274 return ((BcId*) bc_vec_item(map, i))->idx; 275 } 276 277 /** 278 * Returns the correct variable or array stack for the type. 279 * @param p The program. 280 * @param idx The index of the variable or array in the variable or array 281 * vector. 282 * @param type The type of vector to return. 283 * @return A pointer to the variable or array stack. 284 */ 285 static inline BcVec* 286 bc_program_vec(const BcProgram* p, size_t idx, BcType type) 287 { 288 const BcVec* v = (type == BC_TYPE_VAR) ? &p->vars : &p->arrs; 289 return bc_vec_item(v, idx); 290 } 291 292 /** 293 * Returns a pointer to the BcNum corresponding to the result. There is one 294 * case, however, where this returns a pointer to a BcVec: if the type of the 295 * result is array. In that case, the pointer is casted to a pointer to BcNum, 296 * but is never used. The function that calls this expecting an array casts the 297 * pointer back. This function is called a lot and needs to be as fast as 298 * possible. 299 * @param p The program. 300 * @param r The result whose number will be returned. 301 * @return The BcNum corresponding to the result. 302 */ 303 static BcNum* 304 bc_program_num(BcProgram* p, BcResult* r) 305 { 306 BcNum* n; 307 308 #ifdef _WIN32 309 // Windows made it an error to not initialize this, so shut it up. 310 // I don't want to do this on other platforms because this procedure 311 // is one of the most heavily-used, and eliminating the initialization 312 // is a performance win. 313 n = NULL; 314 #endif // _WIN32 315 316 switch (r->t) 317 { 318 case BC_RESULT_STR: 319 case BC_RESULT_TEMP: 320 case BC_RESULT_IBASE: 321 case BC_RESULT_SCALE: 322 case BC_RESULT_OBASE: 323 #if BC_ENABLE_EXTRA_MATH 324 case BC_RESULT_SEED: 325 #endif // BC_ENABLE_EXTRA_MATH 326 { 327 n = &r->d.n; 328 break; 329 } 330 331 case BC_RESULT_VAR: 332 case BC_RESULT_ARRAY: 333 case BC_RESULT_ARRAY_ELEM: 334 { 335 BcVec* v; 336 BcType type = (r->t == BC_RESULT_VAR) ? BC_TYPE_VAR : BC_TYPE_ARRAY; 337 338 // Get the correct variable or array vector. 339 v = bc_program_vec(p, r->d.loc.loc, type); 340 341 // Surprisingly enough, the hard case is *not* returning an array; 342 // it's returning an array element. This is because we have to dig 343 // deeper to get *to* the element. That's what the code inside this 344 // if statement does. 345 if (r->t == BC_RESULT_ARRAY_ELEM) 346 { 347 size_t idx = r->d.loc.idx; 348 349 v = bc_vec_item(v, r->d.loc.stack_idx); 350 351 #if BC_ENABLED 352 // If this is true, we have a reference vector, so dereference 353 // it. The reason we don't need to worry about it for returning 354 // a straight array is because we only care about references 355 // when we access elements of an array that is a reference. That 356 // is this code, so in essence, this line takes care of arrays 357 // as well. 358 if (v->size == sizeof(uchar)) v = bc_program_dereference(p, v); 359 #endif // BC_ENABLED 360 361 // We want to be sure we got a valid array of numbers. 362 assert(v->size == sizeof(BcNum)); 363 364 // The bc spec says that if an element is accessed that does not 365 // exist, it should be preinitialized to 0. Well, if we access 366 // an element *way* out there, we have to preinitialize all 367 // elements between the current last element and the actual 368 // accessed element. 369 if (v->len <= idx) 370 { 371 BC_SIG_LOCK; 372 bc_array_expand(v, bc_vm_growSize(idx, 1)); 373 BC_SIG_UNLOCK; 374 } 375 376 n = bc_vec_item(v, idx); 377 } 378 // This is either a number (for a var) or an array (for an array). 379 // Because bc_vec_top() and bc_vec_item() return a void*, we don't 380 // need to cast. 381 else 382 { 383 #if BC_ENABLED 384 if (BC_IS_BC) 385 { 386 n = bc_vec_item(v, r->d.loc.stack_idx); 387 } 388 else 389 #endif // BC_ENABLED 390 { 391 n = bc_vec_top(v); 392 } 393 } 394 395 break; 396 } 397 398 case BC_RESULT_ZERO: 399 { 400 n = &vm->zero; 401 break; 402 } 403 404 case BC_RESULT_ONE: 405 { 406 n = &vm->one; 407 break; 408 } 409 410 #if BC_ENABLED 411 // We should never get here; this is taken care of earlier because a 412 // result is expected. 413 case BC_RESULT_VOID: 414 #if BC_DEBUG 415 { 416 abort(); 417 // Fallthrough 418 } 419 #endif // BC_DEBUG 420 case BC_RESULT_LAST: 421 { 422 n = &p->last; 423 break; 424 } 425 #endif // BC_ENABLED 426 427 #if BC_GCC 428 // This is here in GCC to quiet the "maybe-uninitialized" warning. 429 default: 430 { 431 abort(); 432 } 433 #endif // BC_GCC 434 } 435 436 return n; 437 } 438 439 /** 440 * Prepares an operand for use. 441 * @param p The program. 442 * @param r An out parameter; this is set to the pointer to the result that 443 * we care about. 444 * @param n An out parameter; this is set to the pointer to the number that 445 * we care about. 446 * @param idx The index of the result from the top of the results stack. 447 */ 448 static void 449 bc_program_operand(BcProgram* p, BcResult** r, BcNum** n, size_t idx) 450 { 451 *r = bc_vec_item_rev(&p->results, idx); 452 453 #if BC_ENABLED 454 if (BC_ERR((*r)->t == BC_RESULT_VOID)) bc_err(BC_ERR_EXEC_VOID_VAL); 455 #endif // BC_ENABLED 456 457 *n = bc_program_num(p, *r); 458 } 459 460 /** 461 * Prepares the operands of a binary operator. 462 * @param p The program. 463 * @param l An out parameter; this is set to the pointer to the result for 464 * the left operand. 465 * @param ln An out parameter; this is set to the pointer to the number for 466 * the left operand. 467 * @param r An out parameter; this is set to the pointer to the result for 468 * the right operand. 469 * @param rn An out parameter; this is set to the pointer to the number for 470 * the right operand. 471 * @param idx The starting index where the operands are in the results stack, 472 * starting from the top. 473 */ 474 static void 475 bc_program_binPrep(BcProgram* p, BcResult** l, BcNum** ln, BcResult** r, 476 BcNum** rn, size_t idx) 477 { 478 BcResultType lt; 479 480 assert(p != NULL && l != NULL && ln != NULL && r != NULL && rn != NULL); 481 482 #ifndef BC_PROG_NO_STACK_CHECK 483 // Check the stack for dc. 484 if (BC_IS_DC) 485 { 486 if (BC_ERR(!BC_PROG_STACK(&p->results, idx + 2))) 487 { 488 bc_err(BC_ERR_EXEC_STACK); 489 } 490 } 491 #endif // BC_PROG_NO_STACK_CHECK 492 493 assert(BC_PROG_STACK(&p->results, idx + 2)); 494 495 // Get the operands. 496 bc_program_operand(p, l, ln, idx + 1); 497 bc_program_operand(p, r, rn, idx); 498 499 lt = (*l)->t; 500 501 #if BC_ENABLED 502 // bc_program_operand() checked these for us. 503 assert(lt != BC_RESULT_VOID && (*r)->t != BC_RESULT_VOID); 504 #endif // BC_ENABLED 505 506 // We run this again under these conditions in case any vector has been 507 // reallocated out from under the BcNums or arrays we had. In other words, 508 // this is to fix pointer invalidation. 509 if (lt == (*r)->t && (lt == BC_RESULT_VAR || lt == BC_RESULT_ARRAY_ELEM)) 510 { 511 *ln = bc_program_num(p, *l); 512 } 513 514 if (BC_ERR(lt == BC_RESULT_STR)) bc_err(BC_ERR_EXEC_TYPE); 515 } 516 517 /** 518 * Prepares the operands of a binary operator and type checks them. This is 519 * separate from bc_program_binPrep() because some places want this, others want 520 * bc_program_binPrep(). 521 * @param p The program. 522 * @param l An out parameter; this is set to the pointer to the result for 523 * the left operand. 524 * @param ln An out parameter; this is set to the pointer to the number for 525 * the left operand. 526 * @param r An out parameter; this is set to the pointer to the result for 527 * the right operand. 528 * @param rn An out parameter; this is set to the pointer to the number for 529 * the right operand. 530 * @param idx The starting index where the operands are in the results stack, 531 * starting from the top. 532 */ 533 static void 534 bc_program_binOpPrep(BcProgram* p, BcResult** l, BcNum** ln, BcResult** r, 535 BcNum** rn, size_t idx) 536 { 537 bc_program_binPrep(p, l, ln, r, rn, idx); 538 bc_program_type_num(*l, *ln); 539 bc_program_type_num(*r, *rn); 540 } 541 542 /** 543 * Prepares the operands of an assignment operator. 544 * @param p The program. 545 * @param l An out parameter; this is set to the pointer to the result for the 546 * left operand. 547 * @param ln An out parameter; this is set to the pointer to the number for the 548 * left operand. 549 * @param r An out parameter; this is set to the pointer to the result for the 550 * right operand. 551 * @param rn An out parameter; this is set to the pointer to the number for the 552 * right operand. 553 */ 554 static void 555 bc_program_assignPrep(BcProgram* p, BcResult** l, BcNum** ln, BcResult** r, 556 BcNum** rn) 557 { 558 BcResultType lt, min; 559 bool good; 560 561 // This is the min non-allowable result type. dc allows strings. 562 min = BC_RESULT_TEMP - ((unsigned int) (BC_IS_BC)); 563 564 // Prepare the operands. 565 bc_program_binPrep(p, l, ln, r, rn, 0); 566 567 lt = (*l)->t; 568 569 // Typecheck the left. 570 if (BC_ERR(lt >= min && lt <= BC_RESULT_ONE)) bc_err(BC_ERR_EXEC_TYPE); 571 572 // Strings can be assigned to variables. We are already good if we are 573 // assigning a string. 574 good = ((*r)->t == BC_RESULT_STR && lt <= BC_RESULT_ARRAY_ELEM); 575 576 assert(BC_PROG_STR(*rn) || (*r)->t != BC_RESULT_STR); 577 578 // If not, type check for a number. 579 if (!good) bc_program_type_num(*r, *rn); 580 } 581 582 /** 583 * Prepares a single operand and type checks it. This is separate from 584 * bc_program_operand() because different places want one or the other. 585 * @param p The program. 586 * @param r An out parameter; this is set to the pointer to the result that 587 * we care about. 588 * @param n An out parameter; this is set to the pointer to the number that 589 * we care about. 590 * @param idx The index of the result from the top of the results stack. 591 */ 592 static void 593 bc_program_prep(BcProgram* p, BcResult** r, BcNum** n, size_t idx) 594 { 595 assert(p != NULL && r != NULL && n != NULL); 596 597 #ifndef BC_PROG_NO_STACK_CHECK 598 // Check the stack for dc. 599 if (BC_IS_DC) 600 { 601 if (BC_ERR(!BC_PROG_STACK(&p->results, idx + 1))) 602 { 603 bc_err(BC_ERR_EXEC_STACK); 604 } 605 } 606 #endif // BC_PROG_NO_STACK_CHECK 607 608 assert(BC_PROG_STACK(&p->results, idx + 1)); 609 610 bc_program_operand(p, r, n, idx); 611 612 // dc does not allow strings in this case. 613 bc_program_type_num(*r, *n); 614 } 615 616 /** 617 * Prepares and returns a clean result for the result of an operation. 618 * @param p The program. 619 * @return A clean result. 620 */ 621 static BcResult* 622 bc_program_prepResult(BcProgram* p) 623 { 624 BcResult* res = bc_vec_pushEmpty(&p->results); 625 626 // Mark a result as not retired. 627 p->nresults += 1; 628 629 bc_result_clear(res); 630 631 return res; 632 } 633 634 /** 635 * Prepares a constant for use. This parses the constant into a number and then 636 * pushes that number onto the results stack. 637 * @param p The program. 638 * @param code The bytecode vector that we will pull the index of the constant 639 * from. 640 * @param bgn An in/out parameter; marks the start of the index in the 641 * bytecode vector and will be updated to point to after the index. 642 */ 643 static void 644 bc_program_const(BcProgram* p, const char* code, size_t* bgn) 645 { 646 // I lied. I actually push the result first. I can do this because the 647 // result will be popped on error. I also get the constant itself. 648 BcResult* r = bc_program_prepResult(p); 649 BcConst* c = bc_vec_item(&p->consts, bc_program_index(code, bgn)); 650 BcBigDig base = BC_PROG_IBASE(p); 651 652 assert(p->nresults == 1); 653 654 // Only reparse if the base changed. 655 if (c->base != base) 656 { 657 // Allocate if we haven't yet. 658 if (c->num.num == NULL) 659 { 660 // The plus 1 is in case of overflow with lack of clamping. 661 size_t len = strlen(c->val) + (BC_DIGIT_CLAMP == 0); 662 663 BC_SIG_LOCK; 664 bc_num_init(&c->num, BC_NUM_RDX(len)); 665 BC_SIG_UNLOCK; 666 } 667 // We need to zero an already existing number. 668 else bc_num_zero(&c->num); 669 670 // bc_num_parse() should only do operations that cannot fail. 671 bc_num_parse(&c->num, c->val, base); 672 673 c->base = base; 674 } 675 676 BC_SIG_LOCK; 677 678 bc_num_createCopy(&r->d.n, &c->num); 679 680 BC_SIG_UNLOCK; 681 682 // XXX: Make sure to clear the number of results. 683 p->nresults -= 1; 684 } 685 686 /** 687 * Executes a binary operator operation. 688 * @param p The program. 689 * @param inst The instruction corresponding to the binary operator to execute. 690 */ 691 static void 692 bc_program_op(BcProgram* p, uchar inst) 693 { 694 BcResult* opd1; 695 BcResult* opd2; 696 BcResult* res; 697 BcNum* n1; 698 BcNum* n2; 699 size_t idx = inst - BC_INST_POWER; 700 701 res = bc_program_prepResult(p); 702 703 assert(p->nresults == 1); 704 705 bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2, 1); 706 707 BC_SIG_LOCK; 708 709 // Initialize the number with enough space, using the correct 710 // BcNumBinaryOpReq function. This looks weird because it is executing an 711 // item of an array. Rest assured that item is a function. 712 bc_num_init(&res->d.n, bc_program_opReqs[idx](n1, n2, BC_PROG_SCALE(p))); 713 714 BC_SIG_UNLOCK; 715 716 assert(BC_NUM_RDX_VALID(n1)); 717 assert(BC_NUM_RDX_VALID(n2)); 718 719 // Run the operation. This also executes an item of an array. 720 bc_program_ops[idx](n1, n2, &res->d.n, BC_PROG_SCALE(p)); 721 722 bc_program_retire(p, 2); 723 } 724 725 /** 726 * Executes a read() or ? command. 727 * @param p The program. 728 */ 729 static void 730 bc_program_read(BcProgram* p) 731 { 732 BcStatus s; 733 BcInstPtr ip; 734 size_t i; 735 const char* file; 736 BcMode mode; 737 BcFunc* f = bc_vec_item(&p->fns, BC_PROG_READ); 738 739 // If we are already executing a read, that is an error. So look for a read 740 // and barf. 741 for (i = 0; i < p->stack.len; ++i) 742 { 743 BcInstPtr* ip_ptr = bc_vec_item(&p->stack, i); 744 if (ip_ptr->func == BC_PROG_READ) bc_err(BC_ERR_EXEC_REC_READ); 745 } 746 747 BC_SIG_LOCK; 748 749 // Save the filename because we are going to overwrite it. 750 file = vm->file; 751 mode = vm->mode; 752 753 // It is a parse error if there needs to be more than one line, so we unset 754 // this to tell the lexer to not request more. We set it back later. 755 vm->mode = BC_MODE_FILE; 756 757 if (!BC_PARSE_IS_INITED(&vm->read_prs, p)) 758 { 759 // We need to parse, but we don't want to use the existing parser 760 // because it has state it needs to keep. (It could have a partial parse 761 // state.) So we create a new parser. This parser is in the BcVm struct 762 // so that it is not local, which means that a longjmp() could change 763 // it. 764 bc_parse_init(&vm->read_prs, p, BC_PROG_READ); 765 766 // We need a separate input buffer; that's why it is also in the BcVm 767 // struct. 768 bc_vec_init(&vm->read_buf, sizeof(char), BC_DTOR_NONE); 769 } 770 else 771 { 772 // This needs to be updated because the parser could have been used 773 // somewhere else. 774 bc_parse_updateFunc(&vm->read_prs, BC_PROG_READ); 775 776 // The read buffer also needs to be emptied or else it will still 777 // contain previous read expressions. 778 bc_vec_empty(&vm->read_buf); 779 } 780 781 BC_SETJMP_LOCKED(vm, exec_err); 782 783 BC_SIG_UNLOCK; 784 785 // Set up the lexer and the read function. 786 bc_lex_file(&vm->read_prs.l, bc_program_stdin_name); 787 bc_vec_popAll(&f->code); 788 789 // Read a line. 790 if (!BC_R) s = bc_read_line(&vm->read_buf, ""); 791 else s = bc_read_line(&vm->read_buf, BC_VM_READ_PROMPT); 792 793 // We should *not* have run into EOF. 794 if (s == BC_STATUS_EOF) bc_err(BC_ERR_EXEC_READ_EXPR); 795 796 // Parse *one* expression, so mode should not be stdin. 797 bc_parse_text(&vm->read_prs, vm->read_buf.v, BC_MODE_FILE); 798 BC_SIG_LOCK; 799 vm->expr(&vm->read_prs, BC_PARSE_NOREAD | BC_PARSE_NEEDVAL); 800 BC_SIG_UNLOCK; 801 802 // We *must* have a valid expression. A semicolon cannot end an expression, 803 // although EOF can. 804 if (BC_ERR(vm->read_prs.l.t != BC_LEX_NLINE && 805 vm->read_prs.l.t != BC_LEX_EOF)) 806 { 807 bc_err(BC_ERR_EXEC_READ_EXPR); 808 } 809 810 #if BC_ENABLED 811 // Push on the globals stack if necessary. 812 if (BC_G) bc_program_prepGlobals(p); 813 #endif // BC_ENABLED 814 815 // Set up a new BcInstPtr. 816 ip.func = BC_PROG_READ; 817 ip.idx = 0; 818 ip.len = p->results.len; 819 820 // Update this pointer, just in case. 821 f = bc_vec_item(&p->fns, BC_PROG_READ); 822 823 // We want a return instruction to simplify things. 824 bc_vec_pushByte(&f->code, vm->read_ret); 825 826 // This lock is here to make sure dc's tail calls are the same length. 827 BC_SIG_LOCK; 828 bc_vec_push(&p->stack, &ip); 829 830 #if DC_ENABLED 831 // We need a new tail call entry for dc. 832 if (BC_IS_DC) 833 { 834 size_t temp = 0; 835 bc_vec_push(&p->tail_calls, &temp); 836 } 837 #endif // DC_ENABLED 838 839 exec_err: 840 BC_SIG_MAYLOCK; 841 vm->mode = (uchar) mode; 842 vm->file = file; 843 BC_LONGJMP_CONT(vm); 844 } 845 846 #if BC_ENABLE_EXTRA_MATH 847 848 /** 849 * Execute a rand(). 850 * @param p The program. 851 */ 852 static void 853 bc_program_rand(BcProgram* p) 854 { 855 BcRand rand = bc_rand_int(&p->rng); 856 857 bc_program_pushBigdig(p, (BcBigDig) rand, BC_RESULT_TEMP); 858 859 #if BC_DEBUG 860 // This is just to ensure that the generated number is correct. I also use 861 // braces because I declare every local at the top of the scope. 862 { 863 BcResult* r = bc_vec_top(&p->results); 864 assert(BC_NUM_RDX_VALID_NP(r->d.n)); 865 } 866 #endif // BC_DEBUG 867 } 868 #endif // BC_ENABLE_EXTRA_MATH 869 870 /** 871 * Prints a series of characters, without escapes. 872 * @param str The string (series of characters). 873 */ 874 static void 875 bc_program_printChars(const char* str) 876 { 877 const char* nl; 878 size_t len = vm->nchars + strlen(str); 879 sig_atomic_t lock; 880 881 BC_SIG_TRYLOCK(lock); 882 883 bc_file_puts(&vm->fout, bc_flush_save, str); 884 885 // We need to update the number of characters, so we find the last newline 886 // and set the characters accordingly. 887 nl = strrchr(str, '\n'); 888 889 if (nl != NULL) len = strlen(nl + 1); 890 891 vm->nchars = len > UINT16_MAX ? UINT16_MAX : (uint16_t) len; 892 893 BC_SIG_TRYUNLOCK(lock); 894 } 895 896 /** 897 * Prints a string with escapes. 898 * @param str The string. 899 */ 900 static void 901 bc_program_printString(const char* restrict str) 902 { 903 size_t i, len = strlen(str); 904 905 #if DC_ENABLED 906 // This is to ensure a nul byte is printed for dc's stream operation. 907 if (!len && BC_IS_DC) 908 { 909 bc_vm_putchar('\0', bc_flush_save); 910 return; 911 } 912 #endif // DC_ENABLED 913 914 // Loop over the characters, processing escapes and printing the rest. 915 for (i = 0; i < len; ++i) 916 { 917 int c = str[i]; 918 919 // If we have an escape... 920 if (c == '\\' && i != len - 1) 921 { 922 const char* ptr; 923 924 // Get the escape character and its companion. 925 c = str[++i]; 926 ptr = strchr(bc_program_esc_chars, c); 927 928 // If we have a companion character... 929 if (ptr != NULL) 930 { 931 // We need to specially handle a newline. 932 if (c == 'n') 933 { 934 BC_SIG_LOCK; 935 vm->nchars = UINT16_MAX; 936 BC_SIG_UNLOCK; 937 } 938 939 // Grab the actual character. 940 c = bc_program_esc_seqs[(size_t) (ptr - bc_program_esc_chars)]; 941 } 942 else 943 { 944 // Just print the backslash if there is no companion character. 945 // The following character will be printed later after the outer 946 // if statement. 947 bc_vm_putchar('\\', bc_flush_save); 948 } 949 } 950 951 bc_vm_putchar(c, bc_flush_save); 952 } 953 } 954 955 /** 956 * Executes a print. This function handles all printing except streaming. 957 * @param p The program. 958 * @param inst The instruction for the type of print we are doing. 959 * @param idx The index of the result that we are printing. 960 */ 961 static void 962 bc_program_print(BcProgram* p, uchar inst, size_t idx) 963 { 964 BcResult* r; 965 char* str; 966 BcNum* n; 967 bool pop = (inst != BC_INST_PRINT); 968 969 assert(p != NULL); 970 971 #ifndef BC_PROG_NO_STACK_CHECK 972 if (BC_IS_DC) 973 { 974 if (BC_ERR(!BC_PROG_STACK(&p->results, idx + 1))) 975 { 976 bc_err(BC_ERR_EXEC_STACK); 977 } 978 } 979 #endif // BC_PROG_NO_STACK_CHECK 980 981 assert(BC_PROG_STACK(&p->results, idx + 1)); 982 983 r = bc_vec_item_rev(&p->results, idx); 984 985 #if BC_ENABLED 986 // If we have a void value, that's not necessarily an error. It is if pop is 987 // true because that means that we are executing a print statement, but 988 // attempting to do a print on a lone void value is allowed because that's 989 // exactly how we want void values used. 990 if (r->t == BC_RESULT_VOID) 991 { 992 if (BC_ERR(pop)) bc_err(BC_ERR_EXEC_VOID_VAL); 993 bc_vec_pop(&p->results); 994 return; 995 } 996 #endif // BC_ENABLED 997 998 n = bc_program_num(p, r); 999 1000 // If we have a number... 1001 if (BC_PROG_NUM(r, n)) 1002 { 1003 #if BC_ENABLED 1004 assert(inst != BC_INST_PRINT_STR); 1005 #endif // BC_ENABLED 1006 1007 // Print the number. 1008 bc_num_print(n, BC_PROG_OBASE(p), !pop); 1009 1010 #if BC_ENABLED 1011 // Need to store the number in last. 1012 if (BC_IS_BC) bc_num_copy(&p->last, n); 1013 #endif // BC_ENABLED 1014 } 1015 else 1016 { 1017 // We want to flush any stuff in the stdout buffer first. 1018 bc_file_flush(&vm->fout, bc_flush_save); 1019 str = bc_program_string(p, n); 1020 1021 #if BC_ENABLED 1022 if (inst == BC_INST_PRINT_STR) bc_program_printChars(str); 1023 else 1024 #endif // BC_ENABLED 1025 { 1026 bc_program_printString(str); 1027 1028 // Need to print a newline only in this case. 1029 if (inst == BC_INST_PRINT) bc_vm_putchar('\n', bc_flush_err); 1030 } 1031 } 1032 1033 // bc always pops. This macro makes sure that happens. 1034 if (BC_PROGRAM_POP(pop)) bc_vec_pop(&p->results); 1035 } 1036 1037 void 1038 bc_program_negate(BcResult* r, BcNum* n) 1039 { 1040 bc_num_copy(&r->d.n, n); 1041 if (BC_NUM_NONZERO(&r->d.n)) BC_NUM_NEG_TGL_NP(r->d.n); 1042 } 1043 1044 void 1045 bc_program_not(BcResult* r, BcNum* n) 1046 { 1047 if (!bc_num_cmpZero(n)) bc_num_one(&r->d.n); 1048 } 1049 1050 #if BC_ENABLE_EXTRA_MATH 1051 void 1052 bc_program_trunc(BcResult* r, BcNum* n) 1053 { 1054 bc_num_copy(&r->d.n, n); 1055 bc_num_truncate(&r->d.n, n->scale); 1056 } 1057 #endif // BC_ENABLE_EXTRA_MATH 1058 1059 /** 1060 * Runs a unary operation. 1061 * @param p The program. 1062 * @param inst The unary operation. 1063 */ 1064 static void 1065 bc_program_unary(BcProgram* p, uchar inst) 1066 { 1067 BcResult* res; 1068 BcResult* ptr; 1069 BcNum* num; 1070 1071 res = bc_program_prepResult(p); 1072 1073 assert(p->nresults == 1); 1074 1075 bc_program_prep(p, &ptr, &num, 1); 1076 1077 BC_SIG_LOCK; 1078 1079 bc_num_init(&res->d.n, num->len); 1080 1081 BC_SIG_UNLOCK; 1082 1083 // This calls a function that is in an array. 1084 bc_program_unarys[inst - BC_INST_NEG](res, num); 1085 bc_program_retire(p, 1); 1086 } 1087 1088 /** 1089 * Executes a logical operator. 1090 * @param p The program. 1091 * @param inst The operator. 1092 */ 1093 static void 1094 bc_program_logical(BcProgram* p, uchar inst) 1095 { 1096 BcResult* opd1; 1097 BcResult* opd2; 1098 BcResult* res; 1099 BcNum* n1; 1100 BcNum* n2; 1101 bool cond = 0; 1102 ssize_t cmp; 1103 1104 res = bc_program_prepResult(p); 1105 1106 assert(p->nresults == 1); 1107 1108 // All logical operators (except boolean not, which is taken care of by 1109 // bc_program_unary()), are binary operators. 1110 bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2, 1); 1111 1112 // Boolean and and or are not short circuiting. This is why; they can be 1113 // implemented much easier this way. 1114 if (inst == BC_INST_BOOL_AND) 1115 { 1116 cond = (bc_num_cmpZero(n1) && bc_num_cmpZero(n2)); 1117 } 1118 else if (inst == BC_INST_BOOL_OR) 1119 { 1120 cond = (bc_num_cmpZero(n1) || bc_num_cmpZero(n2)); 1121 } 1122 else 1123 { 1124 // We have a relational operator, so do a comparison. 1125 cmp = bc_num_cmp(n1, n2); 1126 1127 switch (inst) 1128 { 1129 case BC_INST_REL_EQ: 1130 { 1131 cond = (cmp == 0); 1132 break; 1133 } 1134 1135 case BC_INST_REL_LE: 1136 { 1137 cond = (cmp <= 0); 1138 break; 1139 } 1140 1141 case BC_INST_REL_GE: 1142 { 1143 cond = (cmp >= 0); 1144 break; 1145 } 1146 1147 case BC_INST_REL_NE: 1148 { 1149 cond = (cmp != 0); 1150 break; 1151 } 1152 1153 case BC_INST_REL_LT: 1154 { 1155 cond = (cmp < 0); 1156 break; 1157 } 1158 1159 case BC_INST_REL_GT: 1160 { 1161 cond = (cmp > 0); 1162 break; 1163 } 1164 #if BC_DEBUG 1165 default: 1166 { 1167 // There is a bug if we get here. 1168 abort(); 1169 } 1170 #endif // BC_DEBUG 1171 } 1172 } 1173 1174 BC_SIG_LOCK; 1175 1176 bc_num_init(&res->d.n, BC_NUM_DEF_SIZE); 1177 1178 BC_SIG_UNLOCK; 1179 1180 if (cond) bc_num_one(&res->d.n); 1181 1182 bc_program_retire(p, 2); 1183 } 1184 1185 /** 1186 * Assigns a string to a variable. 1187 * @param p The program. 1188 * @param num The location of the string as a BcNum. 1189 * @param v The stack for the variable. 1190 * @param push Whether to push the string or not. To push means to move the 1191 * string from the results stack and push it onto the variable 1192 * stack. 1193 */ 1194 static void 1195 bc_program_assignStr(BcProgram* p, BcNum* num, BcVec* v, bool push) 1196 { 1197 BcNum* n; 1198 1199 assert(BC_PROG_STACK(&p->results, 1 + !push)); 1200 assert(num != NULL && num->num == NULL && num->cap == 0); 1201 1202 // If we are not pushing onto the variable stack, we need to replace the 1203 // top of the variable stack. 1204 if (!push) bc_vec_pop(v); 1205 1206 bc_vec_npop(&p->results, 1 + !push); 1207 1208 n = bc_vec_pushEmpty(v); 1209 1210 // We can just copy because the num should not have allocated anything. 1211 // NOLINTNEXTLINE 1212 memcpy(n, num, sizeof(BcNum)); 1213 } 1214 1215 /** 1216 * Copies a value to a variable. This is used for storing in dc as well as to 1217 * set function parameters to arguments in bc. 1218 * @param p The program. 1219 * @param idx The index of the variable or array to copy to. 1220 * @param t The type to copy to. This could be a variable or an array. 1221 */ 1222 static void 1223 bc_program_copyToVar(BcProgram* p, size_t idx, BcType t) 1224 { 1225 BcResult *ptr = NULL, r; 1226 BcVec* vec; 1227 BcNum* n = NULL; 1228 bool var = (t == BC_TYPE_VAR); 1229 1230 #if DC_ENABLED 1231 // Check the stack for dc. 1232 if (BC_IS_DC) 1233 { 1234 if (BC_ERR(!BC_PROG_STACK(&p->results, 1))) bc_err(BC_ERR_EXEC_STACK); 1235 } 1236 #endif 1237 1238 assert(BC_PROG_STACK(&p->results, 1)); 1239 1240 bc_program_operand(p, &ptr, &n, 0); 1241 1242 #if BC_ENABLED 1243 // Get the variable for a bc function call. 1244 if (BC_IS_BC) 1245 { 1246 // Type match the result. 1247 bc_program_type_match(ptr, t); 1248 } 1249 #endif // BC_ENABLED 1250 1251 vec = bc_program_vec(p, idx, t); 1252 1253 // We can shortcut in dc if it's assigning a string by using 1254 // bc_program_assignStr(). 1255 if (ptr->t == BC_RESULT_STR) 1256 { 1257 assert(BC_PROG_STR(n)); 1258 1259 if (BC_ERR(!var)) bc_err(BC_ERR_EXEC_TYPE); 1260 1261 bc_program_assignStr(p, n, vec, true); 1262 1263 return; 1264 } 1265 1266 BC_SIG_LOCK; 1267 1268 // Just create and copy for a normal variable. 1269 if (var) 1270 { 1271 if (BC_PROG_STR(n)) 1272 { 1273 // NOLINTNEXTLINE 1274 memcpy(&r.d.n, n, sizeof(BcNum)); 1275 } 1276 else bc_num_createCopy(&r.d.n, n); 1277 } 1278 else 1279 { 1280 // If we get here, we are handling an array. This is one place we need 1281 // to cast the number from bc_program_num() to a vector. 1282 BcVec* v = (BcVec*) n; 1283 BcVec* rv = &r.d.v; 1284 1285 #if BC_ENABLED 1286 1287 if (BC_IS_BC) 1288 { 1289 bool ref, ref_size; 1290 1291 // True if we are using a reference. 1292 ref = (v->size == sizeof(BcNum) && t == BC_TYPE_REF); 1293 1294 // True if we already have a reference vector. This is slightly 1295 // (okay, a lot; it just doesn't look that way) different from 1296 // above. The above means that we need to construct a reference 1297 // vector, whereas this means that we have one and we might have to 1298 // *dereference* it. 1299 ref_size = (v->size == sizeof(uchar)); 1300 1301 // If we *should* have a reference. 1302 if (ref || (ref_size && t == BC_TYPE_REF)) 1303 { 1304 // Create a new reference vector. 1305 bc_vec_init(rv, sizeof(uchar), BC_DTOR_NONE); 1306 1307 // If this is true, then we need to construct a reference. 1308 if (ref) 1309 { 1310 // Make sure the pointer was not invalidated. 1311 vec = bc_program_vec(p, idx, t); 1312 1313 // Push the indices onto the reference vector. This takes 1314 // care of last; it ensures the reference goes to the right 1315 // place. 1316 bc_vec_pushIndex(rv, ptr->d.loc.loc); 1317 bc_vec_pushIndex(rv, ptr->d.loc.stack_idx); 1318 } 1319 // If we get here, we are copying a ref to a ref. Just push a 1320 // copy of all of the bytes. 1321 else bc_vec_npush(rv, v->len * sizeof(uchar), v->v); 1322 1323 // Push the reference vector onto the array stack and pop the 1324 // source. 1325 bc_vec_push(vec, &r.d); 1326 bc_vec_pop(&p->results); 1327 1328 // We need to return early to avoid executing code that we must 1329 // not touch. 1330 BC_SIG_UNLOCK; 1331 return; 1332 } 1333 // If we get here, we have a reference, but we need an array, so 1334 // dereference the array. 1335 else if (ref_size && t != BC_TYPE_REF) 1336 { 1337 v = bc_program_dereference(p, v); 1338 } 1339 } 1340 #endif // BC_ENABLED 1341 1342 // If we get here, we need to copy the array because in bc, all 1343 // arguments are passed by value. Yes, this is expensive. 1344 bc_array_init(rv, true); 1345 bc_array_copy(rv, v); 1346 } 1347 1348 // Push the vector onto the array stack and pop the source. 1349 bc_vec_push(vec, &r.d); 1350 bc_vec_pop(&p->results); 1351 1352 BC_SIG_UNLOCK; 1353 } 1354 1355 void 1356 bc_program_assignBuiltin(BcProgram* p, bool scale, bool obase, BcBigDig val) 1357 { 1358 BcBigDig* ptr_t; 1359 BcBigDig max, min; 1360 #if BC_ENABLED 1361 BcVec* v; 1362 BcBigDig* ptr; 1363 #endif // BC_ENABLED 1364 1365 assert(!scale || !obase); 1366 1367 // Scale needs handling separate from ibase and obase. 1368 if (scale) 1369 { 1370 // Set the min and max. 1371 min = 0; 1372 max = vm->maxes[BC_PROG_GLOBALS_SCALE]; 1373 1374 #if BC_ENABLED 1375 // Get a pointer to the stack. 1376 v = p->globals_v + BC_PROG_GLOBALS_SCALE; 1377 #endif // BC_ENABLED 1378 1379 // Get a pointer to the current value. 1380 ptr_t = p->globals + BC_PROG_GLOBALS_SCALE; 1381 } 1382 else 1383 { 1384 // Set the min and max. 1385 min = BC_NUM_MIN_BASE; 1386 if (BC_ENABLE_EXTRA_MATH && obase && (BC_IS_DC || !BC_IS_POSIX)) 1387 { 1388 min = 0; 1389 } 1390 max = vm->maxes[obase + BC_PROG_GLOBALS_IBASE]; 1391 1392 #if BC_ENABLED 1393 // Get a pointer to the stack. 1394 v = p->globals_v + BC_PROG_GLOBALS_IBASE + obase; 1395 #endif // BC_ENABLED 1396 1397 // Get a pointer to the current value. 1398 ptr_t = p->globals + BC_PROG_GLOBALS_IBASE + obase; 1399 } 1400 1401 // Check for error. 1402 if (BC_ERR(val > max || val < min)) 1403 { 1404 BcErr e; 1405 1406 // This grabs the right error. 1407 if (scale) e = BC_ERR_EXEC_SCALE; 1408 else if (obase) e = BC_ERR_EXEC_OBASE; 1409 else e = BC_ERR_EXEC_IBASE; 1410 1411 bc_verr(e, min, max); 1412 } 1413 1414 #if BC_ENABLED 1415 // Set the top of the stack. 1416 ptr = bc_vec_top(v); 1417 *ptr = val; 1418 #endif // BC_ENABLED 1419 1420 // Set the actual global variable. 1421 *ptr_t = val; 1422 } 1423 1424 #if BC_ENABLE_EXTRA_MATH 1425 void 1426 bc_program_assignSeed(BcProgram* p, BcNum* val) 1427 { 1428 bc_num_rng(val, &p->rng); 1429 } 1430 #endif // BC_ENABLE_EXTRA_MATH 1431 1432 /** 1433 * Executes an assignment operator. 1434 * @param p The program. 1435 * @param inst The assignment operator to execute. 1436 */ 1437 static void 1438 bc_program_assign(BcProgram* p, uchar inst) 1439 { 1440 // The local use_val is true when the assigned value needs to be copied. 1441 BcResult* left; 1442 BcResult* right; 1443 BcResult res; 1444 BcNum* l; 1445 BcNum* r; 1446 bool ob, sc, use_val = BC_INST_USE_VAL(inst); 1447 1448 bc_program_assignPrep(p, &left, &l, &right, &r); 1449 1450 // Assigning to a string should be impossible simply because of the parse. 1451 assert(left->t != BC_RESULT_STR); 1452 1453 // If we are assigning a string... 1454 if (right->t == BC_RESULT_STR) 1455 { 1456 assert(BC_PROG_STR(r)); 1457 1458 #if BC_ENABLED 1459 if (inst != BC_INST_ASSIGN && inst != BC_INST_ASSIGN_NO_VAL) 1460 { 1461 bc_err(BC_ERR_EXEC_TYPE); 1462 } 1463 #endif // BC_ENABLED 1464 1465 // If we are assigning to an array element... 1466 if (left->t == BC_RESULT_ARRAY_ELEM) 1467 { 1468 BC_SIG_LOCK; 1469 1470 // We need to free the number and clear it. 1471 bc_num_free(l); 1472 1473 // NOLINTNEXTLINE 1474 memcpy(l, r, sizeof(BcNum)); 1475 1476 // Now we can pop the results. 1477 bc_vec_npop(&p->results, 2); 1478 1479 BC_SIG_UNLOCK; 1480 } 1481 else 1482 { 1483 // If we get here, we are assigning to a variable, which we can use 1484 // bc_program_assignStr() for. 1485 BcVec* v = bc_program_vec(p, left->d.loc.loc, BC_TYPE_VAR); 1486 bc_program_assignStr(p, r, v, false); 1487 } 1488 1489 #if BC_ENABLED 1490 1491 // If this is true, the value is going to be used again, so we want to 1492 // push a temporary with the string. 1493 if (inst == BC_INST_ASSIGN) 1494 { 1495 res.t = BC_RESULT_STR; 1496 // NOLINTNEXTLINE 1497 memcpy(&res.d.n, r, sizeof(BcNum)); 1498 bc_vec_push(&p->results, &res); 1499 } 1500 1501 #endif // BC_ENABLED 1502 1503 // By using bc_program_assignStr(), we short-circuited this, so return. 1504 return; 1505 } 1506 1507 // If we have a normal assignment operator, not a math one... 1508 if (BC_INST_IS_ASSIGN(inst)) 1509 { 1510 // Assigning to a variable that has a string here is fine because there 1511 // is no math done on it. 1512 1513 // BC_RESULT_TEMP, BC_RESULT_IBASE, BC_RESULT_OBASE, BC_RESULT_SCALE, 1514 // and BC_RESULT_SEED all have temporary copies. Because that's the 1515 // case, we can free the left and just move the value over. We set the 1516 // type of right to BC_RESULT_ZERO in order to prevent it from being 1517 // freed. We also don't have to worry about BC_RESULT_STR because it's 1518 // take care of above. 1519 if (right->t == BC_RESULT_TEMP || right->t >= BC_RESULT_IBASE) 1520 { 1521 BC_SIG_LOCK; 1522 1523 bc_num_free(l); 1524 // NOLINTNEXTLINE 1525 memcpy(l, r, sizeof(BcNum)); 1526 right->t = BC_RESULT_ZERO; 1527 1528 BC_SIG_UNLOCK; 1529 } 1530 // Copy over. 1531 else bc_num_copy(l, r); 1532 } 1533 #if BC_ENABLED 1534 else 1535 { 1536 // If we get here, we are doing a math assignment (+=, -=, etc.). So 1537 // we need to prepare for a binary operator. 1538 BcBigDig scale = BC_PROG_SCALE(p); 1539 1540 // At this point, the left side could still be a string because it could 1541 // be a variable that has the string. If that's the case, we have a type 1542 // error. 1543 if (BC_PROG_STR(l)) bc_err(BC_ERR_EXEC_TYPE); 1544 1545 // Get the right type of assignment operator, whether val is used or 1546 // NO_VAL for performance. 1547 if (!use_val) 1548 { 1549 inst -= (BC_INST_ASSIGN_POWER_NO_VAL - BC_INST_ASSIGN_POWER); 1550 } 1551 1552 assert(BC_NUM_RDX_VALID(l)); 1553 assert(BC_NUM_RDX_VALID(r)); 1554 1555 // Run the actual operation. We do not need worry about reallocating l 1556 // because bc_num_binary() does that behind the scenes for us. 1557 bc_program_ops[inst - BC_INST_ASSIGN_POWER](l, r, l, scale); 1558 } 1559 #endif // BC_ENABLED 1560 1561 ob = (left->t == BC_RESULT_OBASE); 1562 sc = (left->t == BC_RESULT_SCALE); 1563 1564 // The globals need special handling, especially the non-seed ones. The 1565 // first part of the if statement handles them. 1566 if (ob || sc || left->t == BC_RESULT_IBASE) 1567 { 1568 // Get the actual value. 1569 BcBigDig val = bc_num_bigdig(l); 1570 1571 bc_program_assignBuiltin(p, sc, ob, val); 1572 } 1573 #if BC_ENABLE_EXTRA_MATH 1574 // To assign to steed, let bc_num_rng() do its magic. 1575 else if (left->t == BC_RESULT_SEED) bc_program_assignSeed(p, l); 1576 #endif // BC_ENABLE_EXTRA_MATH 1577 1578 BC_SIG_LOCK; 1579 1580 // If we needed to use the value, then we need to copy it. Otherwise, we can 1581 // pop indiscriminately. Oh, and the copy should be a BC_RESULT_TEMP. 1582 if (use_val) 1583 { 1584 bc_num_createCopy(&res.d.n, l); 1585 res.t = BC_RESULT_TEMP; 1586 bc_vec_npop(&p->results, 2); 1587 bc_vec_push(&p->results, &res); 1588 } 1589 else bc_vec_npop(&p->results, 2); 1590 1591 BC_SIG_UNLOCK; 1592 } 1593 1594 /** 1595 * Pushes a variable's value onto the results stack. 1596 * @param p The program. 1597 * @param code The bytecode vector to pull the variable's index out of. 1598 * @param bgn An in/out parameter; the start of the index in the bytecode 1599 * vector, and will be updated to point after the index on return. 1600 * @param pop True if the variable's value should be popped off its stack. 1601 * This is only used in dc. 1602 * @param copy True if the variable's value should be copied to the results 1603 * stack. This is only used in dc. 1604 */ 1605 static void 1606 bc_program_pushVar(BcProgram* p, const char* restrict code, 1607 size_t* restrict bgn, bool pop, bool copy) 1608 { 1609 BcResult r; 1610 size_t idx = bc_program_index(code, bgn); 1611 BcVec* v; 1612 1613 // Set the result appropriately. 1614 r.t = BC_RESULT_VAR; 1615 r.d.loc.loc = idx; 1616 1617 // Get the stack for the variable. This is used in both bc and dc. 1618 v = bc_program_vec(p, idx, BC_TYPE_VAR); 1619 r.d.loc.stack_idx = v->len - 1; 1620 1621 #if DC_ENABLED 1622 // If this condition is true, then we have the hard case, where we have to 1623 // adjust dc registers. 1624 if (BC_IS_DC && (pop || copy)) 1625 { 1626 // Get the number at the top at the top of the stack. 1627 BcNum* num = bc_vec_top(v); 1628 1629 // Ensure there are enough elements on the stack. 1630 if (BC_ERR(!BC_PROG_STACK(v, 2 - copy))) 1631 { 1632 const char* name = bc_map_name(&p->var_map, idx); 1633 bc_verr(BC_ERR_EXEC_STACK_REGISTER, name); 1634 } 1635 1636 assert(BC_PROG_STACK(v, 2 - copy)); 1637 1638 // If the top of the stack is actually a number... 1639 if (!BC_PROG_STR(num)) 1640 { 1641 BC_SIG_LOCK; 1642 1643 // Create a copy to go onto the results stack as appropriate. 1644 r.t = BC_RESULT_TEMP; 1645 bc_num_createCopy(&r.d.n, num); 1646 1647 // If we are not actually copying, we need to do a replace, so pop. 1648 if (!copy) bc_vec_pop(v); 1649 1650 bc_vec_push(&p->results, &r); 1651 1652 BC_SIG_UNLOCK; 1653 1654 return; 1655 } 1656 else 1657 { 1658 // Set the string result. We can just memcpy because all of the 1659 // fields in the num should be cleared. 1660 // NOLINTNEXTLINE 1661 memcpy(&r.d.n, num, sizeof(BcNum)); 1662 r.t = BC_RESULT_STR; 1663 } 1664 1665 // If we are not actually copying, we need to do a replace, so pop. 1666 if (!copy) bc_vec_pop(v); 1667 } 1668 #endif // DC_ENABLED 1669 1670 bc_vec_push(&p->results, &r); 1671 } 1672 1673 /** 1674 * Pushes an array or an array element onto the results stack. 1675 * @param p The program. 1676 * @param code The bytecode vector to pull the variable's index out of. 1677 * @param bgn An in/out parameter; the start of the index in the bytecode 1678 * vector, and will be updated to point after the index on return. 1679 * @param inst The instruction; whether to push an array or an array element. 1680 */ 1681 static void 1682 bc_program_pushArray(BcProgram* p, const char* restrict code, 1683 size_t* restrict bgn, uchar inst) 1684 { 1685 BcResult r; 1686 BcResult* operand; 1687 BcNum* num; 1688 BcBigDig temp; 1689 BcVec* v; 1690 1691 // Get the index of the array. 1692 r.d.loc.loc = bc_program_index(code, bgn); 1693 1694 // We need the array to get its length. 1695 v = bc_program_vec(p, r.d.loc.loc, BC_TYPE_ARRAY); 1696 assert(v != NULL); 1697 1698 r.d.loc.stack_idx = v->len - 1; 1699 1700 // Doing an array is easy; just set the result type and finish. 1701 if (inst == BC_INST_ARRAY) 1702 { 1703 r.t = BC_RESULT_ARRAY; 1704 bc_vec_push(&p->results, &r); 1705 return; 1706 } 1707 1708 // Grab the top element of the results stack for the array index. 1709 bc_program_prep(p, &operand, &num, 0); 1710 temp = bc_num_bigdig(num); 1711 1712 // Set the result. 1713 r.t = BC_RESULT_ARRAY_ELEM; 1714 r.d.loc.idx = (size_t) temp; 1715 1716 BC_SIG_LOCK; 1717 1718 // Pop the index and push the element. 1719 bc_vec_pop(&p->results); 1720 bc_vec_push(&p->results, &r); 1721 1722 BC_SIG_UNLOCK; 1723 } 1724 1725 #if BC_ENABLED 1726 1727 /** 1728 * Executes an increment or decrement operator. This only handles postfix 1729 * inc/dec because the parser translates prefix inc/dec into an assignment where 1730 * the value is used. 1731 * @param p The program. 1732 * @param inst The instruction; whether to do an increment or decrement. 1733 */ 1734 static void 1735 bc_program_incdec(BcProgram* p, uchar inst) 1736 { 1737 BcResult *ptr, res, copy; 1738 BcNum* num; 1739 uchar inst2; 1740 1741 bc_program_prep(p, &ptr, &num, 0); 1742 1743 BC_SIG_LOCK; 1744 1745 // We need a copy from *before* the operation. 1746 copy.t = BC_RESULT_TEMP; 1747 bc_num_createCopy(©.d.n, num); 1748 1749 BC_SETJMP_LOCKED(vm, exit); 1750 1751 BC_SIG_UNLOCK; 1752 1753 // Create the proper assignment. 1754 res.t = BC_RESULT_ONE; 1755 inst2 = BC_INST_ASSIGN_PLUS_NO_VAL + (inst & 0x01); 1756 1757 bc_vec_push(&p->results, &res); 1758 bc_program_assign(p, inst2); 1759 1760 BC_SIG_LOCK; 1761 1762 bc_vec_push(&p->results, ©); 1763 1764 BC_UNSETJMP(vm); 1765 1766 BC_SIG_UNLOCK; 1767 1768 // No need to free the copy here because we pushed it onto the stack. 1769 return; 1770 1771 exit: 1772 BC_SIG_MAYLOCK; 1773 bc_num_free(©.d.n); 1774 BC_LONGJMP_CONT(vm); 1775 } 1776 1777 /** 1778 * Executes a function call for bc. 1779 * @param p The program. 1780 * @param code The bytecode vector to pull the number of arguments and the 1781 * function index out of. 1782 * @param bgn An in/out parameter; the start of the indices in the bytecode 1783 * vector, and will be updated to point after the indices on 1784 * return. 1785 */ 1786 static void 1787 bc_program_call(BcProgram* p, const char* restrict code, size_t* restrict bgn) 1788 { 1789 BcInstPtr ip; 1790 size_t i, nargs; 1791 BcFunc* f; 1792 BcVec* v; 1793 BcAuto* a; 1794 BcResult* arg; 1795 1796 // Pull the number of arguments out of the bytecode vector. 1797 nargs = bc_program_index(code, bgn); 1798 1799 // Set up instruction pointer. 1800 ip.idx = 0; 1801 ip.func = bc_program_index(code, bgn); 1802 f = bc_vec_item(&p->fns, ip.func); 1803 1804 // Error checking. 1805 if (BC_ERR(!f->code.len)) bc_verr(BC_ERR_EXEC_UNDEF_FUNC, f->name); 1806 if (BC_ERR(nargs != f->nparams)) 1807 { 1808 bc_verr(BC_ERR_EXEC_PARAMS, f->nparams, nargs); 1809 } 1810 1811 // Set the length of the results stack. We discount the argument, of course. 1812 ip.len = p->results.len - nargs; 1813 1814 assert(BC_PROG_STACK(&p->results, nargs)); 1815 1816 // Prepare the globals' stacks. 1817 if (BC_G) bc_program_prepGlobals(p); 1818 1819 // Push the arguments onto the stacks of their respective parameters. 1820 for (i = 0; i < nargs; ++i) 1821 { 1822 arg = bc_vec_top(&p->results); 1823 if (BC_ERR(arg->t == BC_RESULT_VOID)) bc_err(BC_ERR_EXEC_VOID_VAL); 1824 1825 // Get the corresponding parameter. 1826 a = bc_vec_item(&f->autos, nargs - 1 - i); 1827 1828 // Actually push the value onto the parameter's stack. 1829 bc_program_copyToVar(p, a->idx, a->type); 1830 } 1831 1832 BC_SIG_LOCK; 1833 1834 // Push zeroes onto the stacks of the auto variables. 1835 for (; i < f->autos.len; ++i) 1836 { 1837 // Get the auto and its stack. 1838 a = bc_vec_item(&f->autos, i); 1839 v = bc_program_vec(p, a->idx, a->type); 1840 1841 // If a variable, just push a 0; otherwise, push an array. 1842 if (a->type == BC_TYPE_VAR) 1843 { 1844 BcNum* n = bc_vec_pushEmpty(v); 1845 bc_num_init(n, BC_NUM_DEF_SIZE); 1846 } 1847 else 1848 { 1849 BcVec* v2; 1850 1851 assert(a->type == BC_TYPE_ARRAY); 1852 1853 v2 = bc_vec_pushEmpty(v); 1854 bc_array_init(v2, true); 1855 } 1856 } 1857 1858 // Push the instruction pointer onto the execution stack. 1859 bc_vec_push(&p->stack, &ip); 1860 1861 BC_SIG_UNLOCK; 1862 } 1863 1864 /** 1865 * Executes a return instruction. 1866 * @param p The program. 1867 * @param inst The return instruction. bc can return void, and we need to know 1868 * if it is. 1869 */ 1870 static void 1871 bc_program_return(BcProgram* p, uchar inst) 1872 { 1873 BcResult* res; 1874 BcFunc* f; 1875 BcInstPtr* ip; 1876 size_t i, nresults; 1877 1878 // Get the instruction pointer. 1879 ip = bc_vec_top(&p->stack); 1880 1881 // Get the difference between the actual number of results and the number of 1882 // results the caller expects. 1883 nresults = p->results.len - ip->len; 1884 1885 // If this isn't true, there was a missing call somewhere. 1886 assert(BC_PROG_STACK(&p->stack, 2)); 1887 1888 // If this isn't true, the parser screwed by giving us no value when we 1889 // expected one, or giving us a value when we expected none. 1890 assert(BC_PROG_STACK(&p->results, ip->len + (inst == BC_INST_RET))); 1891 1892 // Get the function we are returning from. 1893 f = bc_vec_item(&p->fns, ip->func); 1894 1895 res = bc_program_prepResult(p); 1896 1897 assert(p->nresults == 1); 1898 1899 // If we are returning normally... 1900 if (inst == BC_INST_RET) 1901 { 1902 BcNum* num; 1903 BcResult* operand; 1904 1905 // Prepare and copy the return value. 1906 bc_program_operand(p, &operand, &num, 1); 1907 1908 if (BC_PROG_STR(num)) 1909 { 1910 // We need to set this because otherwise, it will be a 1911 // BC_RESULT_TEMP, and BC_RESULT_TEMP needs an actual number to make 1912 // it easier to do type checking. 1913 res->t = BC_RESULT_STR; 1914 1915 // NOLINTNEXTLINE 1916 memcpy(&res->d.n, num, sizeof(BcNum)); 1917 } 1918 else 1919 { 1920 BC_SIG_LOCK; 1921 1922 bc_num_createCopy(&res->d.n, num); 1923 } 1924 } 1925 // Void is easy; set the result. 1926 else if (inst == BC_INST_RET_VOID) res->t = BC_RESULT_VOID; 1927 else 1928 { 1929 BC_SIG_LOCK; 1930 1931 // If we get here, the instruction is for returning a zero, so do that. 1932 bc_num_init(&res->d.n, BC_NUM_DEF_SIZE); 1933 } 1934 1935 BC_SIG_MAYUNLOCK; 1936 1937 // We need to pop items off of the stacks of arguments and autos as well. 1938 for (i = 0; i < f->autos.len; ++i) 1939 { 1940 BcAuto* a = bc_vec_item(&f->autos, i); 1941 BcVec* v = bc_program_vec(p, a->idx, a->type); 1942 1943 bc_vec_pop(v); 1944 } 1945 1946 BC_SIG_LOCK; 1947 1948 // When we retire, pop all of the unused results. 1949 bc_program_retire(p, nresults); 1950 1951 // Pop the globals, if necessary. 1952 if (BC_G) bc_program_popGlobals(p, false); 1953 1954 // Pop the stack. This is what causes the function to actually "return." 1955 bc_vec_pop(&p->stack); 1956 1957 BC_SIG_UNLOCK; 1958 } 1959 #endif // BC_ENABLED 1960 1961 /** 1962 * Executes a builtin function. 1963 * @param p The program. 1964 * @param inst The builtin to execute. 1965 */ 1966 static void 1967 bc_program_builtin(BcProgram* p, uchar inst) 1968 { 1969 BcResult* opd; 1970 BcResult* res; 1971 BcNum* num; 1972 bool len = (inst == BC_INST_LENGTH); 1973 1974 // Ensure we have a valid builtin. 1975 #if BC_ENABLE_EXTRA_MATH 1976 assert(inst >= BC_INST_LENGTH && inst <= BC_INST_IRAND); 1977 #else // BC_ENABLE_EXTRA_MATH 1978 assert(inst >= BC_INST_LENGTH && inst <= BC_INST_IS_STRING); 1979 #endif // BC_ENABLE_EXTRA_MATH 1980 1981 #ifndef BC_PROG_NO_STACK_CHECK 1982 // Check stack for dc. 1983 if (BC_IS_DC && BC_ERR(!BC_PROG_STACK(&p->results, 1))) 1984 { 1985 bc_err(BC_ERR_EXEC_STACK); 1986 } 1987 #endif // BC_PROG_NO_STACK_CHECK 1988 1989 assert(BC_PROG_STACK(&p->results, 1)); 1990 1991 res = bc_program_prepResult(p); 1992 1993 assert(p->nresults == 1); 1994 1995 bc_program_operand(p, &opd, &num, 1); 1996 1997 assert(num != NULL); 1998 1999 // We need to ensure that strings and arrays aren't passed to most builtins. 2000 // The scale function can take strings in dc. 2001 if (!len && (inst != BC_INST_SCALE_FUNC || BC_IS_BC) && 2002 inst != BC_INST_IS_NUMBER && inst != BC_INST_IS_STRING) 2003 { 2004 bc_program_type_num(opd, num); 2005 } 2006 2007 // Square root is easy. 2008 if (inst == BC_INST_SQRT) bc_num_sqrt(num, &res->d.n, BC_PROG_SCALE(p)); 2009 2010 // Absolute value is easy. 2011 else if (inst == BC_INST_ABS) 2012 { 2013 BC_SIG_LOCK; 2014 2015 bc_num_createCopy(&res->d.n, num); 2016 2017 BC_SIG_UNLOCK; 2018 2019 BC_NUM_NEG_CLR_NP(res->d.n); 2020 } 2021 2022 // Testing for number or string is easy. 2023 else if (inst == BC_INST_IS_NUMBER || inst == BC_INST_IS_STRING) 2024 { 2025 bool cond; 2026 bool is_str; 2027 2028 BC_SIG_LOCK; 2029 2030 bc_num_init(&res->d.n, BC_NUM_DEF_SIZE); 2031 2032 BC_SIG_UNLOCK; 2033 2034 // Test if the number is a string. 2035 is_str = BC_PROG_STR(num); 2036 2037 // This confusing condition simply means that the instruction must be 2038 // true if is_str is, or it must be false if is_str is. Otherwise, the 2039 // returned value is false (0). 2040 cond = ((inst == BC_INST_IS_STRING) == is_str); 2041 if (cond) bc_num_one(&res->d.n); 2042 } 2043 2044 #if BC_ENABLE_EXTRA_MATH 2045 2046 // irand() is easy. 2047 else if (inst == BC_INST_IRAND) 2048 { 2049 BC_SIG_LOCK; 2050 2051 bc_num_init(&res->d.n, num->len - BC_NUM_RDX_VAL(num)); 2052 2053 BC_SIG_UNLOCK; 2054 2055 bc_num_irand(num, &res->d.n, &p->rng); 2056 } 2057 2058 #endif // BC_ENABLE_EXTRA_MATH 2059 2060 // Everything else is...not easy. 2061 else 2062 { 2063 BcBigDig val = 0; 2064 2065 // Well, scale() is easy, but length() is not. 2066 if (len) 2067 { 2068 // If we are bc and we have an array... 2069 if (opd->t == BC_RESULT_ARRAY) 2070 { 2071 // Yes, this is one place where we need to cast the number from 2072 // bc_program_num() to a vector. 2073 BcVec* v = (BcVec*) num; 2074 2075 // XXX: If this is changed, you should also change the similar 2076 // code in bc_program_asciify(). 2077 2078 #if BC_ENABLED 2079 // Dereference the array, if necessary. 2080 if (BC_IS_BC && v->size == sizeof(uchar)) 2081 { 2082 v = bc_program_dereference(p, v); 2083 } 2084 #endif // BC_ENABLED 2085 2086 assert(v->size == sizeof(BcNum)); 2087 2088 val = (BcBigDig) v->len; 2089 } 2090 else 2091 { 2092 // If the item is a string... 2093 if (!BC_PROG_NUM(opd, num)) 2094 { 2095 char* str; 2096 2097 // Get the string, then get the length. 2098 str = bc_program_string(p, num); 2099 val = (BcBigDig) strlen(str); 2100 } 2101 else 2102 { 2103 // Calculate the length of the number. 2104 val = (BcBigDig) bc_num_len(num); 2105 } 2106 } 2107 } 2108 // Like I said; scale() is actually easy. It just also needs the integer 2109 // conversion that length() does. 2110 else if (BC_IS_BC || BC_PROG_NUM(opd, num)) 2111 { 2112 val = (BcBigDig) bc_num_scale(num); 2113 } 2114 2115 BC_SIG_LOCK; 2116 2117 // Create the result. 2118 bc_num_createFromBigdig(&res->d.n, val); 2119 2120 BC_SIG_UNLOCK; 2121 } 2122 2123 bc_program_retire(p, 1); 2124 } 2125 2126 /** 2127 * Executes a divmod. 2128 * @param p The program. 2129 */ 2130 static void 2131 bc_program_divmod(BcProgram* p) 2132 { 2133 BcResult* opd1; 2134 BcResult* opd2; 2135 BcResult* res; 2136 BcResult* res2; 2137 BcNum* n1; 2138 BcNum* n2; 2139 size_t req; 2140 2141 // We grow first to avoid pointer invalidation. 2142 bc_vec_grow(&p->results, 2); 2143 2144 // We don't need to update the pointer because 2145 // the capacity is enough due to the line above. 2146 res2 = bc_program_prepResult(p); 2147 res = bc_program_prepResult(p); 2148 assert(p->nresults == 2); 2149 2150 // Prepare the operands. 2151 bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2, 2); 2152 2153 req = bc_num_mulReq(n1, n2, BC_PROG_SCALE(p)); 2154 2155 BC_SIG_LOCK; 2156 2157 // Initialize the results. 2158 bc_num_init(&res->d.n, req); 2159 bc_num_init(&res2->d.n, req); 2160 2161 BC_SIG_UNLOCK; 2162 2163 // Execute. 2164 bc_num_divmod(n1, n2, &res2->d.n, &res->d.n, BC_PROG_SCALE(p)); 2165 2166 bc_program_retire(p, 2); 2167 } 2168 2169 /** 2170 * Executes modular exponentiation. 2171 * @param p The program. 2172 */ 2173 static void 2174 bc_program_modexp(BcProgram* p) 2175 { 2176 BcResult* r1; 2177 BcResult* r2; 2178 BcResult* r3; 2179 BcResult* res; 2180 BcNum* n1; 2181 BcNum* n2; 2182 BcNum* n3; 2183 2184 #if DC_ENABLED 2185 2186 // Check the stack. 2187 if (BC_IS_DC && BC_ERR(!BC_PROG_STACK(&p->results, 3))) 2188 { 2189 bc_err(BC_ERR_EXEC_STACK); 2190 } 2191 2192 #endif // DC_ENABLED 2193 2194 assert(BC_PROG_STACK(&p->results, 3)); 2195 2196 res = bc_program_prepResult(p); 2197 2198 assert(p->nresults == 1); 2199 2200 // Get the first operand and typecheck. 2201 bc_program_operand(p, &r1, &n1, 3); 2202 bc_program_type_num(r1, n1); 2203 2204 // Get the last two operands. 2205 bc_program_binOpPrep(p, &r2, &n2, &r3, &n3, 1); 2206 2207 // Make sure that the values have their pointers updated, if necessary. 2208 // Only array elements are possible because this is dc. 2209 if (r1->t == BC_RESULT_ARRAY_ELEM && (r1->t == r2->t || r1->t == r3->t)) 2210 { 2211 n1 = bc_program_num(p, r1); 2212 } 2213 2214 BC_SIG_LOCK; 2215 2216 bc_num_init(&res->d.n, n3->len); 2217 2218 BC_SIG_UNLOCK; 2219 2220 bc_num_modexp(n1, n2, n3, &res->d.n); 2221 2222 bc_program_retire(p, 3); 2223 } 2224 2225 /** 2226 * Asciifies a number for dc. This is a helper for bc_program_asciify(). 2227 * @param p The program. 2228 * @param n The number to asciify. 2229 */ 2230 static uchar 2231 bc_program_asciifyNum(BcProgram* p, BcNum* n) 2232 { 2233 bc_num_copy(&p->asciify, n); 2234 2235 // We want to clear the scale and sign for easy mod later. 2236 bc_num_truncate(&p->asciify, p->asciify.scale); 2237 BC_NUM_NEG_CLR(&p->asciify); 2238 2239 // This is guaranteed to not have a divide by 0 2240 // because strmb is equal to 256. 2241 bc_num_mod(&p->asciify, &p->strmb, &p->asciify, 0); 2242 2243 // This is also guaranteed to not error because num is in the range 2244 // [0, UCHAR_MAX], which is definitely in range for a BcBigDig. And 2245 // it is not negative. 2246 return (uchar) bc_num_bigdig2(&p->asciify); 2247 } 2248 2249 /** 2250 * Executes the "asciify" command in bc and dc. 2251 * @param p The program. 2252 */ 2253 static void 2254 bc_program_asciify(BcProgram* p) 2255 { 2256 BcResult *r, res; 2257 BcNum* n; 2258 uchar c; 2259 size_t idx; 2260 #if BC_ENABLED 2261 // This is in the outer scope because it has to be freed after a jump. 2262 char* temp_str; 2263 #endif // BC_ENABLED 2264 2265 // Check the stack. 2266 if (BC_ERR(!BC_PROG_STACK(&p->results, 1))) bc_err(BC_ERR_EXEC_STACK); 2267 2268 assert(BC_PROG_STACK(&p->results, 1)); 2269 2270 // Get the top of the results stack. 2271 bc_program_operand(p, &r, &n, 0); 2272 2273 assert(n != NULL); 2274 assert(BC_IS_BC || r->t != BC_RESULT_ARRAY); 2275 2276 #if BC_ENABLED 2277 // Handle arrays in bc specially. 2278 if (r->t == BC_RESULT_ARRAY) 2279 { 2280 // Yes, this is one place where we need to cast the number from 2281 // bc_program_num() to a vector. 2282 BcVec* v = (BcVec*) n; 2283 size_t i; 2284 2285 // XXX: If this is changed, you should also change the similar code in 2286 // bc_program_builtin(). 2287 2288 // Dereference the array, if necessary. 2289 if (v->size == sizeof(uchar)) 2290 { 2291 v = bc_program_dereference(p, v); 2292 } 2293 2294 assert(v->size == sizeof(BcNum)); 2295 2296 // Allocate the string and set the jump for it. 2297 BC_SIG_LOCK; 2298 temp_str = bc_vm_malloc(v->len + 1); 2299 BC_SETJMP_LOCKED(vm, exit); 2300 BC_SIG_UNLOCK; 2301 2302 // Convert the array. 2303 for (i = 0; i < v->len; ++i) 2304 { 2305 BcNum* num = (BcNum*) bc_vec_item(v, i); 2306 2307 if (BC_PROG_STR(num)) 2308 { 2309 temp_str[i] = (bc_program_string(p, num))[0]; 2310 } 2311 else 2312 { 2313 temp_str[i] = (char) bc_program_asciifyNum(p, num); 2314 } 2315 } 2316 2317 temp_str[v->len] = '\0'; 2318 2319 // Store the string in the slab and map, and free the temp string. 2320 BC_SIG_LOCK; 2321 idx = bc_program_addString(p, temp_str); 2322 free(temp_str); 2323 BC_UNSETJMP(vm); 2324 BC_SIG_UNLOCK; 2325 } 2326 else 2327 #endif // BC_ENABLED 2328 { 2329 char str[2]; 2330 char* str2; 2331 2332 // Asciify. 2333 if (BC_PROG_NUM(r, n)) c = bc_program_asciifyNum(p, n); 2334 else 2335 { 2336 // Get the string itself, then the first character. 2337 str2 = bc_program_string(p, n); 2338 c = (uchar) str2[0]; 2339 } 2340 2341 // Fill the resulting string. 2342 str[0] = (char) c; 2343 str[1] = '\0'; 2344 2345 // Add the string to the data structures. 2346 BC_SIG_LOCK; 2347 idx = bc_program_addString(p, str); 2348 BC_SIG_UNLOCK; 2349 } 2350 2351 // Set the result 2352 res.t = BC_RESULT_STR; 2353 bc_num_clear(&res.d.n); 2354 res.d.n.scale = idx; 2355 2356 // Pop and push. 2357 bc_vec_pop(&p->results); 2358 bc_vec_push(&p->results, &res); 2359 2360 return; 2361 2362 #if BC_ENABLED 2363 exit: 2364 free(temp_str); 2365 #endif // BC_ENABLED 2366 } 2367 2368 /** 2369 * Streams a number or a string to stdout. 2370 * @param p The program. 2371 */ 2372 static void 2373 bc_program_printStream(BcProgram* p) 2374 { 2375 BcResult* r; 2376 BcNum* n; 2377 2378 // Check the stack. 2379 if (BC_ERR(!BC_PROG_STACK(&p->results, 1))) bc_err(BC_ERR_EXEC_STACK); 2380 2381 assert(BC_PROG_STACK(&p->results, 1)); 2382 2383 // Get the top of the results stack. 2384 bc_program_operand(p, &r, &n, 0); 2385 2386 assert(n != NULL); 2387 2388 // Stream appropriately. 2389 if (BC_PROG_NUM(r, n)) bc_num_stream(n); 2390 else bc_program_printChars(bc_program_string(p, n)); 2391 2392 // Pop the operand. 2393 bc_vec_pop(&p->results); 2394 } 2395 2396 #if DC_ENABLED 2397 2398 /** 2399 * Gets the length of a register in dc and pushes it onto the results stack. 2400 * @param p The program. 2401 * @param code The bytecode vector to pull the register's index out of. 2402 * @param bgn An in/out parameter; the start of the index in the bytecode 2403 * vector, and will be updated to point after the index on return. 2404 */ 2405 static void 2406 bc_program_regStackLen(BcProgram* p, const char* restrict code, 2407 size_t* restrict bgn) 2408 { 2409 size_t idx = bc_program_index(code, bgn); 2410 BcVec* v = bc_program_vec(p, idx, BC_TYPE_VAR); 2411 2412 bc_program_pushBigdig(p, (BcBigDig) v->len, BC_RESULT_TEMP); 2413 } 2414 2415 /** 2416 * Pushes the length of the results stack onto the results stack. 2417 * @param p The program. 2418 */ 2419 static void 2420 bc_program_stackLen(BcProgram* p) 2421 { 2422 bc_program_pushBigdig(p, (BcBigDig) p->results.len, BC_RESULT_TEMP); 2423 } 2424 2425 /** 2426 * Pops a certain number of elements off the execution stack. 2427 * @param p The program. 2428 * @param inst The instruction to tell us how many. There is one to pop up to 2429 * 2, and one to pop the amount equal to the number at the top of 2430 * the results stack. 2431 */ 2432 static void 2433 bc_program_nquit(BcProgram* p, uchar inst) 2434 { 2435 BcResult* opnd; 2436 BcNum* num; 2437 BcBigDig val; 2438 size_t i; 2439 2440 // Ensure that the tail calls stack is correct. 2441 assert(p->stack.len == p->tail_calls.len); 2442 2443 // Get the number of executions to pop. 2444 if (inst == BC_INST_QUIT) val = 2; 2445 else 2446 { 2447 bc_program_prep(p, &opnd, &num, 0); 2448 val = bc_num_bigdig(num); 2449 2450 bc_vec_pop(&p->results); 2451 } 2452 2453 // Loop over the tail call stack and adjust the quit value appropriately. 2454 for (i = 0; val && i < p->tail_calls.len; ++i) 2455 { 2456 // Get the number of tail calls for this one. 2457 size_t calls = *((size_t*) bc_vec_item_rev(&p->tail_calls, i)) + 1; 2458 2459 // Adjust the value. 2460 if (calls >= val) val = 0; 2461 else val -= (BcBigDig) calls; 2462 } 2463 2464 // If we don't have enough executions, just quit. 2465 if (i == p->stack.len) 2466 { 2467 vm->status = BC_STATUS_QUIT; 2468 BC_JMP; 2469 } 2470 else 2471 { 2472 // We can always pop the last item we reached on the tail call stack 2473 // because these are for tail calls. That means that any executions that 2474 // we would not have quit in that position on the stack would have quit 2475 // anyway. 2476 BC_SIG_LOCK; 2477 bc_vec_npop(&p->stack, i); 2478 bc_vec_npop(&p->tail_calls, i); 2479 BC_SIG_UNLOCK; 2480 } 2481 } 2482 2483 /** 2484 * Pushes the depth of the execution stack onto the stack. 2485 * @param p The program. 2486 */ 2487 static void 2488 bc_program_execStackLen(BcProgram* p) 2489 { 2490 size_t i, amt, len = p->tail_calls.len; 2491 2492 amt = len; 2493 2494 for (i = 0; i < len; ++i) 2495 { 2496 amt += *((size_t*) bc_vec_item(&p->tail_calls, i)); 2497 } 2498 2499 bc_program_pushBigdig(p, (BcBigDig) amt, BC_RESULT_TEMP); 2500 } 2501 2502 /** 2503 * 2504 * @param p The program. 2505 * @param code The bytecode vector to pull the register's index out of. 2506 * @param bgn An in/out parameter; the start of the index in the bytecode 2507 * vector, and will be updated to point after the index on return. 2508 * @param cond True if the execution is conditional, false otherwise. 2509 * @param len The number of bytes in the bytecode vector. 2510 */ 2511 static void 2512 bc_program_execStr(BcProgram* p, const char* restrict code, 2513 size_t* restrict bgn, bool cond, size_t len) 2514 { 2515 BcResult* r; 2516 char* str; 2517 BcFunc* f; 2518 BcInstPtr ip; 2519 size_t fidx; 2520 BcNum* n; 2521 2522 assert(p->stack.len == p->tail_calls.len); 2523 2524 // Check the stack. 2525 if (BC_ERR(!BC_PROG_STACK(&p->results, 1))) bc_err(BC_ERR_EXEC_STACK); 2526 2527 assert(BC_PROG_STACK(&p->results, 1)); 2528 2529 // Get the operand. 2530 bc_program_operand(p, &r, &n, 0); 2531 2532 // If execution is conditional... 2533 if (cond) 2534 { 2535 bool exec; 2536 size_t then_idx; 2537 // These are volatile to quiet warnings on GCC about clobbering with 2538 // longjmp(). 2539 volatile size_t else_idx; 2540 volatile size_t idx; 2541 2542 // Get the index of the "then" var and "else" var. 2543 then_idx = bc_program_index(code, bgn); 2544 else_idx = bc_program_index(code, bgn); 2545 2546 // Figure out if we should execute. 2547 exec = (r->d.n.len != 0); 2548 2549 idx = exec ? then_idx : else_idx; 2550 2551 BC_SIG_LOCK; 2552 BC_SETJMP_LOCKED(vm, exit); 2553 2554 // If we are supposed to execute, execute. If else_idx == SIZE_MAX, that 2555 // means there was no else clause, so if execute is false and else does 2556 // not exist, we don't execute. The goto skips all of the setup for the 2557 // execution. 2558 if (exec || (else_idx != SIZE_MAX)) 2559 { 2560 n = bc_vec_top(bc_program_vec(p, idx, BC_TYPE_VAR)); 2561 } 2562 else goto exit; 2563 2564 if (BC_ERR(!BC_PROG_STR(n))) bc_err(BC_ERR_EXEC_TYPE); 2565 2566 BC_UNSETJMP(vm); 2567 BC_SIG_UNLOCK; 2568 } 2569 else 2570 { 2571 // In non-conditional situations, only the top of stack can be executed, 2572 // and in those cases, variables are not allowed to be "on the stack"; 2573 // they are only put on the stack to be assigned to. 2574 assert(r->t != BC_RESULT_VAR); 2575 2576 if (r->t != BC_RESULT_STR) return; 2577 } 2578 2579 assert(BC_PROG_STR(n)); 2580 2581 // Get the string. 2582 str = bc_program_string(p, n); 2583 2584 // Get the function index and function. 2585 BC_SIG_LOCK; 2586 fidx = bc_program_insertFunc(p, str); 2587 BC_SIG_UNLOCK; 2588 f = bc_vec_item(&p->fns, fidx); 2589 2590 // If the function has not been parsed yet... 2591 if (!f->code.len) 2592 { 2593 BC_SIG_LOCK; 2594 2595 if (!BC_PARSE_IS_INITED(&vm->read_prs, p)) 2596 { 2597 bc_parse_init(&vm->read_prs, p, fidx); 2598 2599 // Initialize this too because bc_vm_shutdown() expects them to be 2600 // initialized togther. 2601 bc_vec_init(&vm->read_buf, sizeof(char), BC_DTOR_NONE); 2602 } 2603 // This needs to be updated because the parser could have been used 2604 // somewhere else 2605 else bc_parse_updateFunc(&vm->read_prs, fidx); 2606 2607 bc_lex_file(&vm->read_prs.l, vm->file); 2608 2609 BC_SETJMP_LOCKED(vm, err); 2610 2611 BC_SIG_UNLOCK; 2612 2613 // Parse. Only one expression is needed, so stdin isn't used. 2614 bc_parse_text(&vm->read_prs, str, BC_MODE_FILE); 2615 2616 BC_SIG_LOCK; 2617 vm->expr(&vm->read_prs, BC_PARSE_NOCALL); 2618 2619 BC_UNSETJMP(vm); 2620 2621 // We can just assert this here because 2622 // dc should parse everything until EOF. 2623 assert(vm->read_prs.l.t == BC_LEX_EOF); 2624 2625 BC_SIG_UNLOCK; 2626 } 2627 2628 // Set the instruction pointer. 2629 ip.idx = 0; 2630 ip.len = p->results.len; 2631 ip.func = fidx; 2632 2633 BC_SIG_LOCK; 2634 2635 // Pop the operand. 2636 bc_vec_pop(&p->results); 2637 2638 // Tail call processing. This condition means that there is more on the 2639 // execution stack, and we are at the end of the bytecode vector, and the 2640 // last instruction is just a BC_INST_POP_EXEC, which would return. 2641 if (p->stack.len > 1 && *bgn == len - 1 && code[*bgn] == BC_INST_POP_EXEC) 2642 { 2643 size_t* call_ptr = bc_vec_top(&p->tail_calls); 2644 2645 // Add one to the tail call. 2646 *call_ptr += 1; 2647 2648 // Pop the execution stack before pushing the new instruction pointer 2649 // on. 2650 bc_vec_pop(&p->stack); 2651 } 2652 // If not a tail call, just push a new one. 2653 else bc_vec_push(&p->tail_calls, &ip.idx); 2654 2655 // Push the new function onto the execution stack and return. 2656 bc_vec_push(&p->stack, &ip); 2657 2658 BC_SIG_UNLOCK; 2659 2660 return; 2661 2662 err: 2663 BC_SIG_MAYLOCK; 2664 2665 f = bc_vec_item(&p->fns, fidx); 2666 2667 // Make sure to erase the bytecode vector so dc knows it is not parsed. 2668 bc_vec_popAll(&f->code); 2669 2670 exit: 2671 bc_vec_pop(&p->results); 2672 BC_LONGJMP_CONT(vm); 2673 } 2674 2675 /** 2676 * Prints every item on the results stack, one per line. 2677 * @param p The program. 2678 */ 2679 static void 2680 bc_program_printStack(BcProgram* p) 2681 { 2682 size_t idx; 2683 2684 for (idx = 0; idx < p->results.len; ++idx) 2685 { 2686 bc_program_print(p, BC_INST_PRINT, idx); 2687 } 2688 } 2689 #endif // DC_ENABLED 2690 2691 /** 2692 * Pushes the value of a global onto the results stack. 2693 * @param p The program. 2694 * @param inst Which global to push, as an instruction. 2695 */ 2696 static void 2697 bc_program_pushGlobal(BcProgram* p, uchar inst) 2698 { 2699 BcResultType t; 2700 2701 // Make sure the instruction is valid. 2702 assert(inst >= BC_INST_IBASE && inst <= BC_INST_SCALE); 2703 2704 // Push the global. 2705 t = inst - BC_INST_IBASE + BC_RESULT_IBASE; 2706 bc_program_pushBigdig(p, p->globals[inst - BC_INST_IBASE], t); 2707 } 2708 2709 /** 2710 * Pushes the value of a global setting onto the stack. 2711 * @param p The program. 2712 * @param inst Which global setting to push, as an instruction. 2713 */ 2714 static void 2715 bc_program_globalSetting(BcProgram* p, uchar inst) 2716 { 2717 BcBigDig val; 2718 2719 // Make sure the instruction is valid. 2720 #if DC_ENABLED 2721 assert((inst >= BC_INST_LINE_LENGTH && inst <= BC_INST_LEADING_ZERO) || 2722 (BC_IS_DC && inst == BC_INST_EXTENDED_REGISTERS)); 2723 #else // DC_ENABLED 2724 assert(inst >= BC_INST_LINE_LENGTH && inst <= BC_INST_LEADING_ZERO); 2725 #endif // DC_ENABLED 2726 2727 if (inst == BC_INST_LINE_LENGTH) 2728 { 2729 val = (BcBigDig) vm->line_len; 2730 } 2731 #if BC_ENABLED 2732 else if (inst == BC_INST_GLOBAL_STACKS) 2733 { 2734 val = (BC_G != 0); 2735 } 2736 #endif // BC_ENABLED 2737 #if DC_ENABLED 2738 else if (inst == BC_INST_EXTENDED_REGISTERS) 2739 { 2740 val = (DC_X != 0); 2741 } 2742 #endif // DC_ENABLED 2743 else val = (BC_Z != 0); 2744 2745 // Push the global. 2746 bc_program_pushBigdig(p, val, BC_RESULT_TEMP); 2747 } 2748 2749 #if BC_ENABLE_EXTRA_MATH 2750 2751 /** 2752 * Pushes the value of seed on the stack. 2753 * @param p The program. 2754 */ 2755 static void 2756 bc_program_pushSeed(BcProgram* p) 2757 { 2758 BcResult* res; 2759 2760 res = bc_program_prepResult(p); 2761 2762 assert(p->nresults == 1); 2763 2764 res->t = BC_RESULT_SEED; 2765 2766 BC_SIG_LOCK; 2767 2768 // We need 2*BC_RAND_NUM_SIZE because of the size of the state. 2769 bc_num_init(&res->d.n, 2 * BC_RAND_NUM_SIZE); 2770 2771 BC_SIG_UNLOCK; 2772 2773 bc_num_createFromRNG(&res->d.n, &p->rng); 2774 2775 // XXX: Clear the number of results. 2776 p->nresults = 0; 2777 } 2778 2779 #endif // BC_ENABLE_EXTRA_MATH 2780 2781 /** 2782 * Adds a function to the fns array. The function's ID must have already been 2783 * inserted into the map. 2784 * @param p The program. 2785 * @param id_ptr The ID of the function as inserted into the map. 2786 */ 2787 static void 2788 bc_program_addFunc(BcProgram* p, BcId* id_ptr) 2789 { 2790 BcFunc* f; 2791 2792 BC_SIG_ASSERT_LOCKED; 2793 2794 // Push and init. 2795 f = bc_vec_pushEmpty(&p->fns); 2796 bc_func_init(f, id_ptr->name); 2797 } 2798 2799 size_t 2800 bc_program_insertFunc(BcProgram* p, const char* name) 2801 { 2802 BcId* id_ptr; 2803 bool new; 2804 size_t idx; 2805 2806 BC_SIG_ASSERT_LOCKED; 2807 2808 assert(p != NULL && name != NULL); 2809 2810 // Insert into the map and get the resulting ID. 2811 new = bc_map_insert(&p->fn_map, name, p->fns.len, &idx); 2812 id_ptr = (BcId*) bc_vec_item(&p->fn_map, idx); 2813 idx = id_ptr->idx; 2814 2815 // If the function is new... 2816 if (new) 2817 { 2818 // Add the function to the fns array. 2819 bc_program_addFunc(p, id_ptr); 2820 } 2821 #if BC_ENABLED 2822 // bc has to reset the function because it's about to be redefined. 2823 else if (BC_IS_BC) 2824 { 2825 BcFunc* func = bc_vec_item(&p->fns, idx); 2826 bc_func_reset(func); 2827 } 2828 #endif // BC_ENABLED 2829 2830 return idx; 2831 } 2832 2833 #if BC_DEBUG || BC_ENABLE_MEMCHECK 2834 void 2835 bc_program_free(BcProgram* p) 2836 { 2837 #if BC_ENABLED 2838 size_t i; 2839 #endif // BC_ENABLED 2840 2841 BC_SIG_ASSERT_LOCKED; 2842 2843 assert(p != NULL); 2844 2845 #if BC_ENABLED 2846 // Free the globals stacks. 2847 for (i = 0; i < BC_PROG_GLOBALS_LEN; ++i) 2848 { 2849 bc_vec_free(p->globals_v + i); 2850 } 2851 #endif // BC_ENABLED 2852 2853 bc_vec_free(&p->fns); 2854 bc_vec_free(&p->fn_map); 2855 bc_vec_free(&p->vars); 2856 bc_vec_free(&p->var_map); 2857 bc_vec_free(&p->arrs); 2858 bc_vec_free(&p->arr_map); 2859 bc_vec_free(&p->results); 2860 bc_vec_free(&p->stack); 2861 bc_vec_free(&p->consts); 2862 bc_vec_free(&p->const_map); 2863 bc_vec_free(&p->strs); 2864 bc_vec_free(&p->str_map); 2865 2866 bc_num_free(&p->asciify); 2867 2868 #if BC_ENABLED 2869 if (BC_IS_BC) bc_num_free(&p->last); 2870 #endif // BC_ENABLED 2871 2872 #if BC_ENABLE_EXTRA_MATH 2873 bc_rand_free(&p->rng); 2874 #endif // BC_ENABLE_EXTRA_MATH 2875 2876 #if DC_ENABLED 2877 if (BC_IS_DC) bc_vec_free(&p->tail_calls); 2878 #endif // DC_ENABLED 2879 } 2880 #endif // BC_DEBUG || BC_ENABLE_MEMCHECK 2881 2882 void 2883 bc_program_init(BcProgram* p) 2884 { 2885 BcInstPtr ip; 2886 size_t i; 2887 2888 BC_SIG_ASSERT_LOCKED; 2889 2890 assert(p != NULL); 2891 2892 // We want this clear. 2893 // NOLINTNEXTLINE 2894 memset(&ip, 0, sizeof(BcInstPtr)); 2895 2896 // Setup the globals stacks and the current values. 2897 for (i = 0; i < BC_PROG_GLOBALS_LEN; ++i) 2898 { 2899 BcBigDig val = i == BC_PROG_GLOBALS_SCALE ? 0 : BC_BASE; 2900 2901 #if BC_ENABLED 2902 bc_vec_init(p->globals_v + i, sizeof(BcBigDig), BC_DTOR_NONE); 2903 bc_vec_push(p->globals_v + i, &val); 2904 #endif // BC_ENABLED 2905 2906 p->globals[i] = val; 2907 } 2908 2909 #if DC_ENABLED 2910 // dc-only setup. 2911 if (BC_IS_DC) 2912 { 2913 bc_vec_init(&p->tail_calls, sizeof(size_t), BC_DTOR_NONE); 2914 2915 // We want an item for the main function on the tail call stack. 2916 i = 0; 2917 bc_vec_push(&p->tail_calls, &i); 2918 } 2919 #endif // DC_ENABLED 2920 2921 bc_num_setup(&p->strmb, p->strmb_num, BC_NUM_BIGDIG_LOG10); 2922 bc_num_bigdig2num(&p->strmb, BC_NUM_STREAM_BASE); 2923 2924 bc_num_init(&p->asciify, BC_NUM_DEF_SIZE); 2925 2926 #if BC_ENABLE_EXTRA_MATH 2927 // We need to initialize srand() just in case /dev/urandom and /dev/random 2928 // are not available. 2929 srand((unsigned int) time(NULL)); 2930 bc_rand_init(&p->rng); 2931 #endif // BC_ENABLE_EXTRA_MATH 2932 2933 #if BC_ENABLED 2934 if (BC_IS_BC) bc_num_init(&p->last, BC_NUM_DEF_SIZE); 2935 #endif // BC_ENABLED 2936 2937 #if BC_DEBUG 2938 bc_vec_init(&p->fns, sizeof(BcFunc), BC_DTOR_FUNC); 2939 #else // BC_DEBUG 2940 bc_vec_init(&p->fns, sizeof(BcFunc), BC_DTOR_NONE); 2941 #endif // BC_DEBUG 2942 bc_map_init(&p->fn_map); 2943 bc_program_insertFunc(p, bc_func_main); 2944 bc_program_insertFunc(p, bc_func_read); 2945 2946 bc_vec_init(&p->vars, sizeof(BcVec), BC_DTOR_VEC); 2947 bc_map_init(&p->var_map); 2948 2949 bc_vec_init(&p->arrs, sizeof(BcVec), BC_DTOR_VEC); 2950 bc_map_init(&p->arr_map); 2951 2952 bc_vec_init(&p->results, sizeof(BcResult), BC_DTOR_RESULT); 2953 2954 // Push the first instruction pointer onto the execution stack. 2955 bc_vec_init(&p->stack, sizeof(BcInstPtr), BC_DTOR_NONE); 2956 bc_vec_push(&p->stack, &ip); 2957 2958 bc_vec_init(&p->consts, sizeof(BcConst), BC_DTOR_CONST); 2959 bc_map_init(&p->const_map); 2960 bc_vec_init(&p->strs, sizeof(char*), BC_DTOR_NONE); 2961 bc_map_init(&p->str_map); 2962 2963 // XXX: Clear the number of results. 2964 p->nresults = 0; 2965 } 2966 2967 void 2968 bc_program_printStackTrace(BcProgram* p) 2969 { 2970 size_t i, max_digits; 2971 2972 max_digits = bc_vm_numDigits(p->stack.len - 1); 2973 2974 for (i = 0; i < p->stack.len; ++i) 2975 { 2976 BcInstPtr* ip = bc_vec_item_rev(&p->stack, i); 2977 BcFunc* f = bc_vec_item(&p->fns, ip->func); 2978 size_t j, digits; 2979 2980 digits = bc_vm_numDigits(i); 2981 2982 bc_file_puts(&vm->ferr, bc_flush_none, " "); 2983 2984 for (j = 0; j < max_digits - digits; ++j) 2985 { 2986 bc_file_putchar(&vm->ferr, bc_flush_none, ' '); 2987 } 2988 2989 bc_file_printf(&vm->ferr, "%zu: %s", i, f->name); 2990 2991 #if BC_ENABLED 2992 if (BC_IS_BC && ip->func != BC_PROG_MAIN && ip->func != BC_PROG_READ) 2993 { 2994 bc_file_puts(&vm->ferr, bc_flush_none, "()"); 2995 } 2996 #endif // BC_ENABLED 2997 2998 bc_file_putchar(&vm->ferr, bc_flush_none, '\n'); 2999 } 3000 } 3001 3002 void 3003 bc_program_reset(BcProgram* p) 3004 { 3005 BcFunc* f; 3006 BcInstPtr* ip; 3007 3008 BC_SIG_ASSERT_LOCKED; 3009 3010 // Pop all but the last execution. 3011 bc_vec_npop(&p->stack, p->stack.len - 1); 3012 3013 #if DC_ENABLED 3014 // We need to pop tail calls too. 3015 if (BC_IS_DC) bc_vec_npop(&p->tail_calls, p->tail_calls.len - 1); 3016 #endif // DC_ENABLED 3017 3018 // Clear the stack if we are in bc. We have to do this in bc because bc's 3019 // stack is implicit. 3020 // 3021 // XXX: We don't do this in dc because other dc implementations don't. 3022 // However, we *MUST* pop the items for results that are not retired yet. 3023 if (BC_IS_DC && BC_I) bc_vec_npop(&p->results, p->nresults); 3024 else bc_vec_popAll(&p->results); 3025 3026 // Now clear how many results there are. 3027 p->nresults = 0; 3028 3029 #if BC_ENABLED 3030 // Clear the globals' stacks. 3031 if (BC_G) bc_program_popGlobals(p, true); 3032 #endif // BC_ENABLED 3033 3034 // Clear the bytecode vector of the main function. 3035 f = bc_vec_item(&p->fns, BC_PROG_MAIN); 3036 bc_vec_npop(&f->code, f->code.len); 3037 3038 // Reset the instruction pointer. 3039 ip = bc_vec_top(&p->stack); 3040 // NOLINTNEXTLINE 3041 memset(ip, 0, sizeof(BcInstPtr)); 3042 3043 if (BC_SIG_INTERRUPT(vm)) 3044 { 3045 // Write the ready message for a signal. 3046 bc_file_printf(&vm->fout, "%s", bc_program_ready_msg); 3047 bc_file_flush(&vm->fout, bc_flush_err); 3048 } 3049 3050 // Clear the signal. 3051 vm->sig = 0; 3052 } 3053 3054 void 3055 bc_program_exec(BcProgram* p) 3056 { 3057 size_t idx; 3058 BcResult r; 3059 BcResult* ptr; 3060 BcInstPtr* ip; 3061 BcFunc* func; 3062 char* code; 3063 bool cond = false; 3064 uchar inst; 3065 #if BC_ENABLED 3066 BcNum* num; 3067 #endif // BC_ENABLED 3068 #if !BC_HAS_COMPUTED_GOTO 3069 #if BC_DEBUG 3070 size_t jmp_bufs_len; 3071 #endif // BC_DEBUG 3072 #endif // !BC_HAS_COMPUTED_GOTO 3073 3074 #if BC_HAS_COMPUTED_GOTO 3075 3076 #if BC_GCC 3077 #pragma GCC diagnostic push 3078 #pragma GCC diagnostic ignored "-Wpedantic" 3079 #endif // BC_GCC 3080 3081 #if BC_CLANG 3082 #pragma clang diagnostic push 3083 #pragma clang diagnostic ignored "-Wgnu-label-as-value" 3084 #endif // BC_CLANG 3085 3086 BC_PROG_LBLS; 3087 BC_PROG_LBLS_ASSERT; 3088 3089 #if BC_CLANG 3090 #pragma clang diagnostic pop 3091 #endif // BC_CLANG 3092 3093 #if BC_GCC 3094 #pragma GCC diagnostic pop 3095 #endif // BC_GCC 3096 3097 // BC_INST_INVALID is a marker for the end so that we don't have to have an 3098 // execution loop. 3099 func = (BcFunc*) bc_vec_item(&p->fns, BC_PROG_MAIN); 3100 bc_vec_pushByte(&func->code, BC_INST_INVALID); 3101 #endif // BC_HAS_COMPUTED_GOTO 3102 3103 BC_SETJMP(vm, end); 3104 3105 ip = bc_vec_top(&p->stack); 3106 func = (BcFunc*) bc_vec_item(&p->fns, ip->func); 3107 code = func->code.v; 3108 3109 #if !BC_HAS_COMPUTED_GOTO 3110 3111 #if BC_DEBUG 3112 jmp_bufs_len = vm->jmp_bufs.len; 3113 #endif // BC_DEBUG 3114 3115 // This loop is the heart of the execution engine. It *is* the engine. For 3116 // computed goto, it is ignored. 3117 while (ip->idx < func->code.len) 3118 #endif // !BC_HAS_COMPUTED_GOTO 3119 { 3120 BC_SIG_ASSERT_NOT_LOCKED; 3121 3122 #if BC_HAS_COMPUTED_GOTO 3123 3124 #if BC_GCC 3125 #pragma GCC diagnostic push 3126 #pragma GCC diagnostic ignored "-Wpedantic" 3127 #endif // BC_GCC 3128 3129 #if BC_CLANG 3130 #pragma clang diagnostic push 3131 #pragma clang diagnostic ignored "-Wgnu-label-as-value" 3132 #endif // BC_CLANG 3133 3134 BC_PROG_JUMP(inst, code, ip); 3135 3136 #else // BC_HAS_COMPUTED_GOTO 3137 3138 // Get the next instruction and increment the index. 3139 inst = (uchar) code[(ip->idx)++]; 3140 3141 #endif // BC_HAS_COMPUTED_GOTO 3142 3143 #if BC_DEBUG_CODE 3144 bc_file_printf(&vm->ferr, "inst: %s\n", bc_inst_names[inst]); 3145 bc_file_flush(&vm->ferr, bc_flush_none); 3146 #endif // BC_DEBUG_CODE 3147 3148 #if !BC_HAS_COMPUTED_GOTO 3149 switch (inst) 3150 #endif // !BC_HAS_COMPUTED_GOTO 3151 { 3152 #if BC_ENABLED 3153 // This just sets up the condition for the unconditional jump below, 3154 // which checks the condition, if necessary. 3155 // clang-format off 3156 BC_PROG_LBL(BC_INST_JUMP_ZERO): 3157 // clang-format on 3158 { 3159 bc_program_prep(p, &ptr, &num, 0); 3160 3161 cond = !bc_num_cmpZero(num); 3162 bc_vec_pop(&p->results); 3163 3164 BC_PROG_DIRECT_JUMP(BC_INST_JUMP) 3165 } 3166 // Fallthrough. 3167 BC_PROG_FALLTHROUGH 3168 3169 // clang-format off 3170 BC_PROG_LBL(BC_INST_JUMP): 3171 // clang-format on 3172 { 3173 idx = bc_program_index(code, &ip->idx); 3174 3175 // If a jump is required... 3176 if (inst == BC_INST_JUMP || cond) 3177 { 3178 // Get the address to jump to. 3179 size_t* addr = bc_vec_item(&func->labels, idx); 3180 3181 // If this fails, then the parser failed to set up the 3182 // labels correctly. 3183 assert(*addr != SIZE_MAX); 3184 3185 // Set the new address. 3186 ip->idx = *addr; 3187 } 3188 3189 BC_PROG_JUMP(inst, code, ip); 3190 } 3191 3192 // clang-format off 3193 BC_PROG_LBL(BC_INST_CALL): 3194 // clang-format on 3195 { 3196 assert(BC_IS_BC); 3197 3198 bc_program_call(p, code, &ip->idx); 3199 3200 // Because we changed the execution stack and where we are 3201 // executing, we have to update all of this. 3202 BC_SIG_LOCK; 3203 ip = bc_vec_top(&p->stack); 3204 func = bc_vec_item(&p->fns, ip->func); 3205 code = func->code.v; 3206 BC_SIG_UNLOCK; 3207 3208 BC_PROG_JUMP(inst, code, ip); 3209 } 3210 3211 // clang-format off 3212 BC_PROG_LBL(BC_INST_INC): 3213 BC_PROG_LBL(BC_INST_DEC): 3214 // clang-format on 3215 { 3216 bc_program_incdec(p, inst); 3217 BC_PROG_JUMP(inst, code, ip); 3218 } 3219 3220 // clang-format off 3221 BC_PROG_LBL(BC_INST_HALT): 3222 // clang-format on 3223 { 3224 vm->status = BC_STATUS_QUIT; 3225 3226 // Just jump out. The jump series will take care of everything. 3227 BC_JMP; 3228 3229 BC_PROG_JUMP(inst, code, ip); 3230 } 3231 3232 // clang-format off 3233 BC_PROG_LBL(BC_INST_RET): 3234 BC_PROG_LBL(BC_INST_RET0): 3235 BC_PROG_LBL(BC_INST_RET_VOID): 3236 // clang-format on 3237 { 3238 bc_program_return(p, inst); 3239 3240 // Because we changed the execution stack and where we are 3241 // executing, we have to update all of this. 3242 BC_SIG_LOCK; 3243 ip = bc_vec_top(&p->stack); 3244 func = bc_vec_item(&p->fns, ip->func); 3245 code = func->code.v; 3246 BC_SIG_UNLOCK; 3247 3248 BC_PROG_JUMP(inst, code, ip); 3249 } 3250 #endif // BC_ENABLED 3251 3252 // clang-format off 3253 BC_PROG_LBL(BC_INST_BOOL_OR): 3254 BC_PROG_LBL(BC_INST_BOOL_AND): 3255 BC_PROG_LBL(BC_INST_REL_EQ): 3256 BC_PROG_LBL(BC_INST_REL_LE): 3257 BC_PROG_LBL(BC_INST_REL_GE): 3258 BC_PROG_LBL(BC_INST_REL_NE): 3259 BC_PROG_LBL(BC_INST_REL_LT): 3260 BC_PROG_LBL(BC_INST_REL_GT): 3261 // clang-format on 3262 { 3263 bc_program_logical(p, inst); 3264 BC_PROG_JUMP(inst, code, ip); 3265 } 3266 3267 // clang-format off 3268 BC_PROG_LBL(BC_INST_READ): 3269 // clang-format on 3270 { 3271 // We want to flush output before 3272 // this in case there is a prompt. 3273 bc_file_flush(&vm->fout, bc_flush_save); 3274 3275 bc_program_read(p); 3276 3277 // Because we changed the execution stack and where we are 3278 // executing, we have to update all of this. 3279 BC_SIG_LOCK; 3280 ip = bc_vec_top(&p->stack); 3281 func = bc_vec_item(&p->fns, ip->func); 3282 code = func->code.v; 3283 BC_SIG_UNLOCK; 3284 3285 BC_PROG_JUMP(inst, code, ip); 3286 } 3287 3288 #if BC_ENABLE_EXTRA_MATH 3289 // clang-format off 3290 BC_PROG_LBL(BC_INST_RAND): 3291 // clang-format on 3292 { 3293 bc_program_rand(p); 3294 BC_PROG_JUMP(inst, code, ip); 3295 } 3296 #endif // BC_ENABLE_EXTRA_MATH 3297 3298 // clang-format off 3299 BC_PROG_LBL(BC_INST_MAXIBASE): 3300 BC_PROG_LBL(BC_INST_MAXOBASE): 3301 BC_PROG_LBL(BC_INST_MAXSCALE): 3302 #if BC_ENABLE_EXTRA_MATH 3303 BC_PROG_LBL(BC_INST_MAXRAND): 3304 #endif // BC_ENABLE_EXTRA_MATH 3305 // clang-format on 3306 { 3307 BcBigDig dig = vm->maxes[inst - BC_INST_MAXIBASE]; 3308 bc_program_pushBigdig(p, dig, BC_RESULT_TEMP); 3309 BC_PROG_JUMP(inst, code, ip); 3310 } 3311 3312 // clang-format off 3313 BC_PROG_LBL(BC_INST_LINE_LENGTH): 3314 #if BC_ENABLED 3315 BC_PROG_LBL(BC_INST_GLOBAL_STACKS): 3316 #endif // BC_ENABLED 3317 #if DC_ENABLED 3318 BC_PROG_LBL(BC_INST_EXTENDED_REGISTERS): 3319 #endif // DC_ENABLE 3320 BC_PROG_LBL(BC_INST_LEADING_ZERO): 3321 // clang-format on 3322 { 3323 bc_program_globalSetting(p, inst); 3324 BC_PROG_JUMP(inst, code, ip); 3325 } 3326 3327 // clang-format off 3328 BC_PROG_LBL(BC_INST_VAR): 3329 // clang-format on 3330 { 3331 bc_program_pushVar(p, code, &ip->idx, false, false); 3332 BC_PROG_JUMP(inst, code, ip); 3333 } 3334 3335 // clang-format off 3336 BC_PROG_LBL(BC_INST_ARRAY_ELEM): 3337 BC_PROG_LBL(BC_INST_ARRAY): 3338 // clang-format on 3339 { 3340 bc_program_pushArray(p, code, &ip->idx, inst); 3341 BC_PROG_JUMP(inst, code, ip); 3342 } 3343 3344 // clang-format off 3345 BC_PROG_LBL(BC_INST_IBASE): 3346 BC_PROG_LBL(BC_INST_SCALE): 3347 BC_PROG_LBL(BC_INST_OBASE): 3348 // clang-format on 3349 { 3350 bc_program_pushGlobal(p, inst); 3351 BC_PROG_JUMP(inst, code, ip); 3352 } 3353 3354 #if BC_ENABLE_EXTRA_MATH 3355 // clang-format off 3356 BC_PROG_LBL(BC_INST_SEED): 3357 // clang-format on 3358 { 3359 bc_program_pushSeed(p); 3360 BC_PROG_JUMP(inst, code, ip); 3361 } 3362 #endif // BC_ENABLE_EXTRA_MATH 3363 3364 // clang-format off 3365 BC_PROG_LBL(BC_INST_LENGTH): 3366 BC_PROG_LBL(BC_INST_SCALE_FUNC): 3367 BC_PROG_LBL(BC_INST_SQRT): 3368 BC_PROG_LBL(BC_INST_ABS): 3369 BC_PROG_LBL(BC_INST_IS_NUMBER): 3370 BC_PROG_LBL(BC_INST_IS_STRING): 3371 #if BC_ENABLE_EXTRA_MATH 3372 BC_PROG_LBL(BC_INST_IRAND): 3373 #endif // BC_ENABLE_EXTRA_MATH 3374 // clang-format on 3375 { 3376 bc_program_builtin(p, inst); 3377 BC_PROG_JUMP(inst, code, ip); 3378 } 3379 3380 // clang-format off 3381 BC_PROG_LBL(BC_INST_ASCIIFY): 3382 // clang-format on 3383 { 3384 bc_program_asciify(p); 3385 3386 // Because we changed the execution stack and where we are 3387 // executing, we have to update all of this. 3388 BC_SIG_LOCK; 3389 ip = bc_vec_top(&p->stack); 3390 func = bc_vec_item(&p->fns, ip->func); 3391 code = func->code.v; 3392 BC_SIG_UNLOCK; 3393 3394 BC_PROG_JUMP(inst, code, ip); 3395 } 3396 3397 // clang-format off 3398 BC_PROG_LBL(BC_INST_NUM): 3399 // clang-format on 3400 { 3401 bc_program_const(p, code, &ip->idx); 3402 BC_PROG_JUMP(inst, code, ip); 3403 } 3404 3405 // clang-format off 3406 BC_PROG_LBL(BC_INST_ZERO): 3407 BC_PROG_LBL(BC_INST_ONE): 3408 #if BC_ENABLED 3409 BC_PROG_LBL(BC_INST_LAST): 3410 #endif // BC_ENABLED 3411 // clang-format on 3412 { 3413 r.t = BC_RESULT_ZERO + (inst - BC_INST_ZERO); 3414 bc_vec_push(&p->results, &r); 3415 BC_PROG_JUMP(inst, code, ip); 3416 } 3417 3418 // clang-format off 3419 BC_PROG_LBL(BC_INST_PRINT): 3420 BC_PROG_LBL(BC_INST_PRINT_POP): 3421 #if BC_ENABLED 3422 BC_PROG_LBL(BC_INST_PRINT_STR): 3423 #endif // BC_ENABLED 3424 // clang-format on 3425 { 3426 bc_program_print(p, inst, 0); 3427 3428 // We want to flush right away to save the output for history, 3429 // if history must preserve it when taking input. 3430 bc_file_flush(&vm->fout, bc_flush_save); 3431 3432 BC_PROG_JUMP(inst, code, ip); 3433 } 3434 3435 // clang-format off 3436 BC_PROG_LBL(BC_INST_STR): 3437 // clang-format on 3438 { 3439 // Set up the result and push. 3440 r.t = BC_RESULT_STR; 3441 bc_num_clear(&r.d.n); 3442 r.d.n.scale = bc_program_index(code, &ip->idx); 3443 bc_vec_push(&p->results, &r); 3444 BC_PROG_JUMP(inst, code, ip); 3445 } 3446 3447 // clang-format off 3448 BC_PROG_LBL(BC_INST_POWER): 3449 BC_PROG_LBL(BC_INST_MULTIPLY): 3450 BC_PROG_LBL(BC_INST_DIVIDE): 3451 BC_PROG_LBL(BC_INST_MODULUS): 3452 BC_PROG_LBL(BC_INST_PLUS): 3453 BC_PROG_LBL(BC_INST_MINUS): 3454 #if BC_ENABLE_EXTRA_MATH 3455 BC_PROG_LBL(BC_INST_PLACES): 3456 BC_PROG_LBL(BC_INST_LSHIFT): 3457 BC_PROG_LBL(BC_INST_RSHIFT): 3458 #endif // BC_ENABLE_EXTRA_MATH 3459 // clang-format on 3460 { 3461 bc_program_op(p, inst); 3462 BC_PROG_JUMP(inst, code, ip); 3463 } 3464 3465 // clang-format off 3466 BC_PROG_LBL(BC_INST_NEG): 3467 BC_PROG_LBL(BC_INST_BOOL_NOT): 3468 #if BC_ENABLE_EXTRA_MATH 3469 BC_PROG_LBL(BC_INST_TRUNC): 3470 #endif // BC_ENABLE_EXTRA_MATH 3471 // clang-format on 3472 { 3473 bc_program_unary(p, inst); 3474 BC_PROG_JUMP(inst, code, ip); 3475 } 3476 3477 // clang-format off 3478 #if BC_ENABLED 3479 BC_PROG_LBL(BC_INST_ASSIGN_POWER): 3480 BC_PROG_LBL(BC_INST_ASSIGN_MULTIPLY): 3481 BC_PROG_LBL(BC_INST_ASSIGN_DIVIDE): 3482 BC_PROG_LBL(BC_INST_ASSIGN_MODULUS): 3483 BC_PROG_LBL(BC_INST_ASSIGN_PLUS): 3484 BC_PROG_LBL(BC_INST_ASSIGN_MINUS): 3485 #if BC_ENABLE_EXTRA_MATH 3486 BC_PROG_LBL(BC_INST_ASSIGN_PLACES): 3487 BC_PROG_LBL(BC_INST_ASSIGN_LSHIFT): 3488 BC_PROG_LBL(BC_INST_ASSIGN_RSHIFT): 3489 #endif // BC_ENABLE_EXTRA_MATH 3490 BC_PROG_LBL(BC_INST_ASSIGN): 3491 BC_PROG_LBL(BC_INST_ASSIGN_POWER_NO_VAL): 3492 BC_PROG_LBL(BC_INST_ASSIGN_MULTIPLY_NO_VAL): 3493 BC_PROG_LBL(BC_INST_ASSIGN_DIVIDE_NO_VAL): 3494 BC_PROG_LBL(BC_INST_ASSIGN_MODULUS_NO_VAL): 3495 BC_PROG_LBL(BC_INST_ASSIGN_PLUS_NO_VAL): 3496 BC_PROG_LBL(BC_INST_ASSIGN_MINUS_NO_VAL): 3497 #if BC_ENABLE_EXTRA_MATH 3498 BC_PROG_LBL(BC_INST_ASSIGN_PLACES_NO_VAL): 3499 BC_PROG_LBL(BC_INST_ASSIGN_LSHIFT_NO_VAL): 3500 BC_PROG_LBL(BC_INST_ASSIGN_RSHIFT_NO_VAL): 3501 #endif // BC_ENABLE_EXTRA_MATH 3502 #endif // BC_ENABLED 3503 BC_PROG_LBL(BC_INST_ASSIGN_NO_VAL): 3504 // clang-format on 3505 { 3506 bc_program_assign(p, inst); 3507 BC_PROG_JUMP(inst, code, ip); 3508 } 3509 3510 // clang-format off 3511 BC_PROG_LBL(BC_INST_POP): 3512 // clang-format on 3513 { 3514 #ifndef BC_PROG_NO_STACK_CHECK 3515 // dc must do a stack check, but bc does not. 3516 if (BC_IS_DC) 3517 { 3518 if (BC_ERR(!BC_PROG_STACK(&p->results, 1))) 3519 { 3520 bc_err(BC_ERR_EXEC_STACK); 3521 } 3522 } 3523 #endif // BC_PROG_NO_STACK_CHECK 3524 3525 assert(BC_PROG_STACK(&p->results, 1)); 3526 3527 bc_vec_pop(&p->results); 3528 3529 BC_PROG_JUMP(inst, code, ip); 3530 } 3531 3532 // clang-format off 3533 BC_PROG_LBL(BC_INST_SWAP): 3534 // clang-format on 3535 { 3536 BcResult* ptr2; 3537 3538 // Check the stack. 3539 if (BC_ERR(!BC_PROG_STACK(&p->results, 2))) 3540 { 3541 bc_err(BC_ERR_EXEC_STACK); 3542 } 3543 3544 assert(BC_PROG_STACK(&p->results, 2)); 3545 3546 // Get the two items. 3547 ptr = bc_vec_item_rev(&p->results, 0); 3548 ptr2 = bc_vec_item_rev(&p->results, 1); 3549 3550 // Swap. It's just easiest to do it this way. 3551 // NOLINTNEXTLINE 3552 memcpy(&r, ptr, sizeof(BcResult)); 3553 // NOLINTNEXTLINE 3554 memcpy(ptr, ptr2, sizeof(BcResult)); 3555 // NOLINTNEXTLINE 3556 memcpy(ptr2, &r, sizeof(BcResult)); 3557 3558 BC_PROG_JUMP(inst, code, ip); 3559 } 3560 3561 // clang-format off 3562 BC_PROG_LBL(BC_INST_MODEXP): 3563 // clang-format on 3564 { 3565 bc_program_modexp(p); 3566 BC_PROG_JUMP(inst, code, ip); 3567 } 3568 3569 // clang-format off 3570 BC_PROG_LBL(BC_INST_DIVMOD): 3571 // clang-format on 3572 { 3573 bc_program_divmod(p); 3574 BC_PROG_JUMP(inst, code, ip); 3575 } 3576 3577 // clang-format off 3578 BC_PROG_LBL(BC_INST_PRINT_STREAM): 3579 // clang-format on 3580 { 3581 bc_program_printStream(p); 3582 BC_PROG_JUMP(inst, code, ip); 3583 } 3584 3585 #if DC_ENABLED 3586 // clang-format off 3587 BC_PROG_LBL(BC_INST_POP_EXEC): 3588 // clang-format on 3589 { 3590 // If this fails, the dc parser got something wrong. 3591 assert(BC_PROG_STACK(&p->stack, 2)); 3592 3593 // Pop the execution stack and tail call stack. 3594 bc_vec_pop(&p->stack); 3595 bc_vec_pop(&p->tail_calls); 3596 3597 // Because we changed the execution stack and where we are 3598 // executing, we have to update all of this. 3599 BC_SIG_LOCK; 3600 ip = bc_vec_top(&p->stack); 3601 func = bc_vec_item(&p->fns, ip->func); 3602 code = func->code.v; 3603 BC_SIG_UNLOCK; 3604 3605 BC_PROG_JUMP(inst, code, ip); 3606 } 3607 3608 // clang-format off 3609 BC_PROG_LBL(BC_INST_EXECUTE): 3610 BC_PROG_LBL(BC_INST_EXEC_COND): 3611 // clang-format on 3612 { 3613 cond = (inst == BC_INST_EXEC_COND); 3614 3615 bc_program_execStr(p, code, &ip->idx, cond, func->code.len); 3616 3617 // Because we changed the execution stack and where we are 3618 // executing, we have to update all of this. 3619 BC_SIG_LOCK; 3620 ip = bc_vec_top(&p->stack); 3621 func = bc_vec_item(&p->fns, ip->func); 3622 code = func->code.v; 3623 BC_SIG_UNLOCK; 3624 3625 BC_PROG_JUMP(inst, code, ip); 3626 } 3627 3628 // clang-format off 3629 BC_PROG_LBL(BC_INST_PRINT_STACK): 3630 // clang-format on 3631 { 3632 bc_program_printStack(p); 3633 BC_PROG_JUMP(inst, code, ip); 3634 } 3635 3636 // clang-format off 3637 BC_PROG_LBL(BC_INST_CLEAR_STACK): 3638 // clang-format on 3639 { 3640 bc_vec_popAll(&p->results); 3641 BC_PROG_JUMP(inst, code, ip); 3642 } 3643 3644 // clang-format off 3645 BC_PROG_LBL(BC_INST_REG_STACK_LEN): 3646 // clang-format on 3647 { 3648 bc_program_regStackLen(p, code, &ip->idx); 3649 BC_PROG_JUMP(inst, code, ip); 3650 } 3651 3652 // clang-format off 3653 BC_PROG_LBL(BC_INST_STACK_LEN): 3654 // clang-format on 3655 { 3656 bc_program_stackLen(p); 3657 BC_PROG_JUMP(inst, code, ip); 3658 } 3659 3660 // clang-format off 3661 BC_PROG_LBL(BC_INST_DUPLICATE): 3662 // clang-format on 3663 { 3664 // Check the stack. 3665 if (BC_ERR(!BC_PROG_STACK(&p->results, 1))) 3666 { 3667 bc_err(BC_ERR_EXEC_STACK); 3668 } 3669 3670 assert(BC_PROG_STACK(&p->results, 1)); 3671 3672 // Get the top of the stack. 3673 ptr = bc_vec_top(&p->results); 3674 3675 BC_SIG_LOCK; 3676 3677 // Copy and push. 3678 bc_result_copy(&r, ptr); 3679 bc_vec_push(&p->results, &r); 3680 3681 BC_SIG_UNLOCK; 3682 3683 BC_PROG_JUMP(inst, code, ip); 3684 } 3685 3686 // clang-format off 3687 BC_PROG_LBL(BC_INST_LOAD): 3688 BC_PROG_LBL(BC_INST_PUSH_VAR): 3689 // clang-format on 3690 { 3691 bool copy = (inst == BC_INST_LOAD); 3692 bc_program_pushVar(p, code, &ip->idx, true, copy); 3693 BC_PROG_JUMP(inst, code, ip); 3694 } 3695 3696 // clang-format off 3697 BC_PROG_LBL(BC_INST_PUSH_TO_VAR): 3698 // clang-format on 3699 { 3700 idx = bc_program_index(code, &ip->idx); 3701 bc_program_copyToVar(p, idx, BC_TYPE_VAR); 3702 BC_PROG_JUMP(inst, code, ip); 3703 } 3704 3705 // clang-format off 3706 BC_PROG_LBL(BC_INST_QUIT): 3707 BC_PROG_LBL(BC_INST_NQUIT): 3708 // clang-format on 3709 { 3710 bc_program_nquit(p, inst); 3711 3712 // Because we changed the execution stack and where we are 3713 // executing, we have to update all of this. 3714 BC_SIG_LOCK; 3715 ip = bc_vec_top(&p->stack); 3716 func = bc_vec_item(&p->fns, ip->func); 3717 code = func->code.v; 3718 BC_SIG_UNLOCK; 3719 3720 BC_PROG_JUMP(inst, code, ip); 3721 } 3722 3723 // clang-format off 3724 BC_PROG_LBL(BC_INST_EXEC_STACK_LEN): 3725 // clang-format on 3726 { 3727 bc_program_execStackLen(p); 3728 BC_PROG_JUMP(inst, code, ip); 3729 } 3730 #endif // DC_ENABLED 3731 3732 #if BC_HAS_COMPUTED_GOTO 3733 // clang-format off 3734 BC_PROG_LBL(BC_INST_INVALID): 3735 // clang-format on 3736 { 3737 goto end; 3738 } 3739 #else // BC_HAS_COMPUTED_GOTO 3740 default: 3741 { 3742 BC_UNREACHABLE 3743 #if BC_DEBUG && !BC_CLANG 3744 abort(); 3745 #endif // BC_DEBUG && !BC_CLANG 3746 } 3747 #endif // BC_HAS_COMPUTED_GOTO 3748 } 3749 3750 #if BC_HAS_COMPUTED_GOTO 3751 3752 #if BC_CLANG 3753 #pragma clang diagnostic pop 3754 #endif // BC_CLANG 3755 3756 #if BC_GCC 3757 #pragma GCC diagnostic pop 3758 #endif // BC_GCC 3759 3760 #else // BC_HAS_COMPUTED_GOTO 3761 3762 #if BC_DEBUG 3763 // This is to allow me to use a debugger to see the last instruction, 3764 // which will point to which function was the problem. But it's also a 3765 // good smoke test for error handling changes. 3766 assert(jmp_bufs_len == vm->jmp_bufs.len); 3767 #endif // BC_DEBUG 3768 3769 #endif // BC_HAS_COMPUTED_GOTO 3770 } 3771 3772 end: 3773 BC_SIG_MAYLOCK; 3774 3775 // This is here just to print a stack trace on interrupts. This is for 3776 // finding infinite loops. 3777 if (BC_SIG_INTERRUPT(vm)) 3778 { 3779 BcStatus s; 3780 3781 bc_file_putchar(&vm->ferr, bc_flush_none, '\n'); 3782 3783 bc_program_printStackTrace(p); 3784 3785 s = bc_file_flushErr(&vm->ferr, bc_flush_err); 3786 if (BC_ERR(s != BC_STATUS_SUCCESS && vm->status == BC_STATUS_SUCCESS)) 3787 { 3788 vm->status = (sig_atomic_t) s; 3789 } 3790 } 3791 3792 BC_LONGJMP_CONT(vm); 3793 } 3794 3795 #if BC_DEBUG_CODE 3796 #if BC_ENABLED && DC_ENABLED 3797 void 3798 bc_program_printStackDebug(BcProgram* p) 3799 { 3800 bc_file_puts(&vm->fout, bc_flush_err, "-------------- Stack ----------\n"); 3801 bc_program_printStack(p); 3802 bc_file_puts(&vm->fout, bc_flush_err, "-------------- Stack End ------\n"); 3803 } 3804 3805 static void 3806 bc_program_printIndex(const char* restrict code, size_t* restrict bgn) 3807 { 3808 uchar byte, i, bytes = (uchar) code[(*bgn)++]; 3809 ulong val = 0; 3810 3811 for (byte = 1, i = 0; byte && i < bytes; ++i) 3812 { 3813 byte = (uchar) code[(*bgn)++]; 3814 if (byte) val |= ((ulong) byte) << (CHAR_BIT * i); 3815 } 3816 3817 bc_vm_printf(" (%lu) ", val); 3818 } 3819 3820 static void 3821 bc_program_printStr(const BcProgram* p, const char* restrict code, 3822 size_t* restrict bgn) 3823 { 3824 size_t idx = bc_program_index(code, bgn); 3825 char* s; 3826 3827 s = *((char**) bc_vec_item(&p->strs, idx)); 3828 3829 bc_vm_printf(" (\"%s\") ", s); 3830 } 3831 3832 void 3833 bc_program_printInst(const BcProgram* p, const char* restrict code, 3834 size_t* restrict bgn) 3835 { 3836 uchar inst = (uchar) code[(*bgn)++]; 3837 3838 bc_vm_printf("Inst[%zu]: %s [%lu]; ", *bgn - 1, bc_inst_names[inst], 3839 (unsigned long) inst); 3840 3841 if (inst == BC_INST_VAR || inst == BC_INST_ARRAY_ELEM || 3842 inst == BC_INST_ARRAY) 3843 { 3844 bc_program_printIndex(code, bgn); 3845 } 3846 else if (inst == BC_INST_STR) bc_program_printStr(p, code, bgn); 3847 else if (inst == BC_INST_NUM) 3848 { 3849 size_t idx = bc_program_index(code, bgn); 3850 BcConst* c = bc_vec_item(&p->consts, idx); 3851 bc_vm_printf("(%s)", c->val); 3852 } 3853 else if (inst == BC_INST_CALL || 3854 (inst > BC_INST_STR && inst <= BC_INST_JUMP_ZERO)) 3855 { 3856 bc_program_printIndex(code, bgn); 3857 if (inst == BC_INST_CALL) bc_program_printIndex(code, bgn); 3858 } 3859 3860 bc_vm_putchar('\n', bc_flush_err); 3861 } 3862 3863 void 3864 bc_program_code(const BcProgram* p) 3865 { 3866 BcFunc* f; 3867 char* code; 3868 BcInstPtr ip; 3869 size_t i; 3870 3871 for (i = 0; i < p->fns.len; ++i) 3872 { 3873 ip.idx = ip.len = 0; 3874 ip.func = i; 3875 3876 f = bc_vec_item(&p->fns, ip.func); 3877 code = f->code.v; 3878 3879 bc_vm_printf("func[%zu]:\n", ip.func); 3880 while (ip.idx < f->code.len) 3881 { 3882 bc_program_printInst(p, code, &ip.idx); 3883 } 3884 bc_file_puts(&vm->fout, bc_flush_err, "\n\n"); 3885 } 3886 } 3887 #endif // BC_ENABLED && DC_ENABLED 3888 #endif // BC_DEBUG_CODE 3889