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