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