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