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