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