1 /* 2 * w o r d s . c 3 * Forth Inspired Command Language 4 * ANS Forth CORE word-set written in C 5 * Author: John Sadler (john_sadler@alum.mit.edu) 6 * Created: 19 July 1997 7 * $Id: primitives.c,v 1.4 2010/09/13 18:43:04 asau Exp $ 8 */ 9 /* 10 * Copyright (c) 1997-2001 John Sadler (john_sadler@alum.mit.edu) 11 * All rights reserved. 12 * 13 * Get the latest Ficl release at http://ficl.sourceforge.net 14 * 15 * I am interested in hearing from anyone who uses Ficl. If you have 16 * a problem, a success story, a defect, an enhancement request, or 17 * if you would like to contribute to the Ficl release, please 18 * contact me by email at the address above. 19 * 20 * L I C E N S E and D I S C L A I M E R 21 * 22 * Redistribution and use in source and binary forms, with or without 23 * modification, are permitted provided that the following conditions 24 * are met: 25 * 1. Redistributions of source code must retain the above copyright 26 * notice, this list of conditions and the following disclaimer. 27 * 2. Redistributions in binary form must reproduce the above copyright 28 * notice, this list of conditions and the following disclaimer in the 29 * documentation and/or other materials provided with the distribution. 30 * 31 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 32 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 33 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 34 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 35 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 39 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 40 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 41 * SUCH DAMAGE. 42 */ 43 44 #include "ficl.h" 45 #include <limits.h> 46 47 /* 48 * Control structure building words use these 49 * strings' addresses as markers on the stack to 50 * check for structure completion. 51 */ 52 static char doTag[] = "do"; 53 static char colonTag[] = "colon"; 54 static char leaveTag[] = "leave"; 55 56 static char destTag[] = "target"; 57 static char origTag[] = "origin"; 58 59 static char caseTag[] = "case"; 60 static char ofTag[] = "of"; 61 static char fallthroughTag[] = "fallthrough"; 62 63 /* 64 * C O N T R O L S T R U C T U R E B U I L D E R S 65 * 66 * Push current dictionary location for later branch resolution. 67 * The location may be either a branch target or a patch address... 68 */ 69 static void 70 markBranch(ficlDictionary *dictionary, ficlVm *vm, char *tag) 71 { 72 ficlStackPushPointer(vm->dataStack, dictionary->here); 73 ficlStackPushPointer(vm->dataStack, tag); 74 } 75 76 static void 77 markControlTag(ficlVm *vm, char *tag) 78 { 79 ficlStackPushPointer(vm->dataStack, tag); 80 } 81 82 static void 83 matchControlTag(ficlVm *vm, char *wantTag) 84 { 85 char *tag; 86 87 FICL_STACK_CHECK(vm->dataStack, 1, 0); 88 89 tag = (char *)ficlStackPopPointer(vm->dataStack); 90 91 /* 92 * Changed the code below to compare the pointers first 93 * (by popular demand) 94 */ 95 if ((tag != wantTag) && strcmp(tag, wantTag)) { 96 ficlVmThrowError(vm, 97 "Error -- unmatched control structure \"%s\"", wantTag); 98 } 99 } 100 101 /* 102 * Expect a branch target address on the param stack, 103 * FICL_VM_STATE_COMPILE a literal offset from the current dictionary location 104 * to the target address 105 */ 106 static void 107 resolveBackBranch(ficlDictionary *dictionary, ficlVm *vm, char *tag) 108 { 109 ficlCell *patchAddr, c; 110 111 matchControlTag(vm, tag); 112 113 FICL_STACK_CHECK(vm->dataStack, 1, 0); 114 115 patchAddr = (ficlCell *)ficlStackPopPointer(vm->dataStack); 116 c.i = patchAddr - dictionary->here; 117 118 ficlDictionaryAppendCell(dictionary, c); 119 } 120 121 /* 122 * Expect a branch patch address on the param stack, 123 * FICL_VM_STATE_COMPILE a literal offset from the patch location 124 * to the current dictionary location 125 */ 126 static void 127 resolveForwardBranch(ficlDictionary *dictionary, ficlVm *vm, char *tag) 128 { 129 ficlInteger offset; 130 ficlCell *patchAddr; 131 132 matchControlTag(vm, tag); 133 134 FICL_STACK_CHECK(vm->dataStack, 1, 0); 135 136 patchAddr = (ficlCell *)ficlStackPopPointer(vm->dataStack); 137 offset = dictionary->here - patchAddr; 138 (*patchAddr).i = offset; 139 } 140 141 /* 142 * Match the tag to the top of the stack. If success, 143 * sopy "here" address into the ficlCell whose address is next 144 * on the stack. Used by do..leave..loop. 145 */ 146 static void 147 resolveAbsBranch(ficlDictionary *dictionary, ficlVm *vm, char *wantTag) 148 { 149 ficlCell *patchAddr; 150 char *tag; 151 152 FICL_STACK_CHECK(vm->dataStack, 2, 0); 153 154 tag = ficlStackPopPointer(vm->dataStack); 155 156 /* 157 * Changed the comparison below to compare the pointers first 158 * (by popular demand) 159 */ 160 if ((tag != wantTag) && strcmp(tag, wantTag)) { 161 ficlVmTextOut(vm, "Warning -- Unmatched control word: "); 162 ficlVmTextOut(vm, wantTag); 163 ficlVmTextOut(vm, "\n"); 164 } 165 166 patchAddr = (ficlCell *)ficlStackPopPointer(vm->dataStack); 167 (*patchAddr).p = dictionary->here; 168 } 169 170 /* 171 * c o l o n d e f i n i t i o n s 172 * Code to begin compiling a colon definition 173 * This function sets the state to FICL_VM_STATE_COMPILE, then creates a 174 * new word whose name is the next word in the input stream 175 * and whose code is colonParen. 176 */ 177 static void 178 ficlPrimitiveColon(ficlVm *vm) 179 { 180 ficlDictionary *dictionary = ficlVmGetDictionary(vm); 181 ficlString name = ficlVmGetWord(vm); 182 183 vm->state = FICL_VM_STATE_COMPILE; 184 markControlTag(vm, colonTag); 185 (void) ficlDictionaryAppendWord(dictionary, name, 186 (ficlPrimitive)ficlInstructionColonParen, 187 FICL_WORD_DEFAULT | FICL_WORD_SMUDGED); 188 189 #if FICL_WANT_LOCALS 190 vm->callback.system->localsCount = 0; 191 #endif 192 } 193 194 static void 195 ficlPrimitiveSemicolonCoIm(ficlVm *vm) 196 { 197 ficlDictionary *dictionary = ficlVmGetDictionary(vm); 198 199 matchControlTag(vm, colonTag); 200 201 #if FICL_WANT_LOCALS 202 if (vm->callback.system->localsCount > 0) { 203 ficlDictionary *locals; 204 locals = ficlSystemGetLocals(vm->callback.system); 205 ficlDictionaryEmpty(locals, locals->forthWordlist->size); 206 ficlDictionaryAppendUnsigned(dictionary, 207 ficlInstructionUnlinkParen); 208 } 209 vm->callback.system->localsCount = 0; 210 #endif 211 212 ficlDictionaryAppendUnsigned(dictionary, ficlInstructionSemiParen); 213 vm->state = FICL_VM_STATE_INTERPRET; 214 ficlDictionaryUnsmudge(dictionary); 215 } 216 217 /* 218 * e x i t 219 * CORE 220 * This function simply pops the previous instruction 221 * pointer and returns to the "next" loop. Used for exiting from within 222 * a definition. Note that exitParen is identical to semiParen - they 223 * are in two different functions so that "see" can correctly identify 224 * the end of a colon definition, even if it uses "exit". 225 */ 226 static void 227 ficlPrimitiveExitCoIm(ficlVm *vm) 228 { 229 ficlDictionary *dictionary = ficlVmGetDictionary(vm); 230 FICL_IGNORE(vm); 231 232 #if FICL_WANT_LOCALS 233 if (vm->callback.system->localsCount > 0) { 234 ficlDictionaryAppendUnsigned(dictionary, 235 ficlInstructionUnlinkParen); 236 } 237 #endif 238 ficlDictionaryAppendUnsigned(dictionary, ficlInstructionExitParen); 239 } 240 241 /* 242 * c o n s t a n t 243 * IMMEDIATE 244 * Compiles a constant into the dictionary. Constants return their 245 * value when invoked. Expects a value on top of the parm stack. 246 */ 247 static void 248 ficlPrimitiveConstant(ficlVm *vm) 249 { 250 ficlDictionary *dictionary = ficlVmGetDictionary(vm); 251 ficlString name = ficlVmGetWord(vm); 252 253 FICL_STACK_CHECK(vm->dataStack, 1, 0); 254 255 (void) ficlDictionaryAppendConstantInstruction(dictionary, name, 256 ficlInstructionConstantParen, ficlStackPopInteger(vm->dataStack)); 257 } 258 259 static void 260 ficlPrimitive2Constant(ficlVm *vm) 261 { 262 ficlDictionary *dictionary = ficlVmGetDictionary(vm); 263 ficlString name = ficlVmGetWord(vm); 264 265 FICL_STACK_CHECK(vm->dataStack, 2, 0); 266 267 (void) ficlDictionaryAppend2ConstantInstruction(dictionary, name, 268 ficlInstruction2ConstantParen, ficlStackPop2Integer(vm->dataStack)); 269 } 270 271 /* 272 * d i s p l a y C e l l 273 * Drop and print the contents of the ficlCell at the top of the param 274 * stack 275 */ 276 static void 277 ficlPrimitiveDot(ficlVm *vm) 278 { 279 ficlCell c; 280 281 FICL_STACK_CHECK(vm->dataStack, 1, 0); 282 283 c = ficlStackPop(vm->dataStack); 284 (void) ficlLtoa((c).i, vm->pad, vm->base); 285 (void) strcat(vm->pad, " "); 286 ficlVmTextOut(vm, vm->pad); 287 } 288 289 static void 290 ficlPrimitiveUDot(ficlVm *vm) 291 { 292 ficlUnsigned u; 293 294 FICL_STACK_CHECK(vm->dataStack, 1, 0); 295 296 u = ficlStackPopUnsigned(vm->dataStack); 297 (void) ficlUltoa(u, vm->pad, vm->base); 298 (void) strcat(vm->pad, " "); 299 ficlVmTextOut(vm, vm->pad); 300 } 301 302 static void 303 ficlPrimitiveHexDot(ficlVm *vm) 304 { 305 ficlUnsigned u; 306 307 FICL_STACK_CHECK(vm->dataStack, 1, 0); 308 309 u = ficlStackPopUnsigned(vm->dataStack); 310 (void) ficlUltoa(u, vm->pad, 16); 311 (void) strcat(vm->pad, " "); 312 ficlVmTextOut(vm, vm->pad); 313 } 314 315 /* 316 * s t r l e n 317 * Ficl ( c-string -- length ) 318 * 319 * Returns the length of a C-style (zero-terminated) string. 320 * 321 * --lch 322 */ 323 static void 324 ficlPrimitiveStrlen(ficlVm *vm) 325 { 326 char *address = (char *)ficlStackPopPointer(vm->dataStack); 327 ficlStackPushInteger(vm->dataStack, strlen(address)); 328 } 329 330 /* 331 * s p r i n t f 332 * Ficl ( i*x c-addr-fmt u-fmt c-addr-buffer u-buffer -- 333 * c-addr-buffer u-written success-flag ) 334 * Similar to the C sprintf() function. It formats into a buffer based on 335 * a "format" string. Each character in the format string is copied verbatim 336 * to the output buffer, until SPRINTF encounters a percent sign ("%"). 337 * SPRINTF then skips the percent sign, and examines the next character 338 * (the "format character"). Here are the valid format characters: 339 * s - read a C-ADDR U-LENGTH string from the stack and copy it to 340 * the buffer 341 * d - read a ficlCell from the stack, format it as a string (base-10, 342 * signed), and copy it to the buffer 343 * x - same as d, except in base-16 344 * u - same as d, but unsigned 345 * % - output a literal percent-sign to the buffer 346 * SPRINTF returns the c-addr-buffer argument unchanged, the number of bytes 347 * written, and a flag indicating whether or not it ran out of space while 348 * writing to the output buffer (FICL_TRUE if it ran out of space). 349 * 350 * If SPRINTF runs out of space in the buffer to store the formatted string, 351 * it still continues parsing, in an effort to preserve your stack (otherwise 352 * it might leave uneaten arguments behind). 353 * 354 * --lch 355 */ 356 static void 357 ficlPrimitiveSprintf(ficlVm *vm) 358 { 359 int bufferLength = ficlStackPopInteger(vm->dataStack); 360 char *buffer = (char *)ficlStackPopPointer(vm->dataStack); 361 char *bufferStart = buffer; 362 363 int formatLength = ficlStackPopInteger(vm->dataStack); 364 char *format = (char *)ficlStackPopPointer(vm->dataStack); 365 char *formatStop = format + formatLength; 366 367 int base = 10; 368 int unsignedInteger = 0; /* false */ 369 370 int append = 1; /* true */ 371 372 while (format < formatStop) { 373 char scratch[64]; 374 char *source; 375 int actualLength; 376 int desiredLength; 377 int leadingZeroes; 378 379 if (*format != '%') { 380 source = format; 381 actualLength = desiredLength = 1; 382 leadingZeroes = 0; 383 } else { 384 format++; 385 if (format == formatStop) 386 break; 387 388 leadingZeroes = (*format == '0'); 389 if (leadingZeroes) { 390 format++; 391 if (format == formatStop) 392 break; 393 } 394 395 desiredLength = isdigit((unsigned char)*format); 396 if (desiredLength) { 397 desiredLength = strtoul(format, &format, 10); 398 if (format == formatStop) 399 break; 400 } else if (*format == '*') { 401 desiredLength = 402 ficlStackPopInteger(vm->dataStack); 403 404 format++; 405 if (format == formatStop) 406 break; 407 } 408 409 switch (*format) { 410 case 's': 411 case 'S': 412 actualLength = 413 ficlStackPopInteger(vm->dataStack); 414 source = (char *) 415 ficlStackPopPointer(vm->dataStack); 416 break; 417 case 'x': 418 case 'X': 419 base = 16; 420 /* FALLTHROUGH */ 421 case 'u': 422 case 'U': 423 unsignedInteger = 1; /* true */ 424 /* FALLTHROUGH */ 425 case 'd': 426 case 'D': { 427 int integer; 428 integer = ficlStackPopInteger(vm->dataStack); 429 if (unsignedInteger) 430 (void) ficlUltoa(integer, scratch, 431 base); 432 else 433 (void) ficlLtoa(integer, scratch, base); 434 base = 10; 435 unsignedInteger = 0; /* false */ 436 source = scratch; 437 actualLength = strlen(scratch); 438 break; 439 } 440 case '%': 441 source = format; 442 actualLength = 1; 443 /* FALLTHROUGH */ 444 default: 445 continue; 446 } 447 } 448 449 if (append) { 450 if (!desiredLength) 451 desiredLength = actualLength; 452 if (desiredLength > bufferLength) { 453 append = 0; /* false */ 454 desiredLength = bufferLength; 455 } 456 while (desiredLength > actualLength) { 457 *buffer++ = (char)((leadingZeroes) ? '0' : ' '); 458 bufferLength--; 459 desiredLength--; 460 } 461 memcpy(buffer, source, actualLength); 462 buffer += actualLength; 463 bufferLength -= actualLength; 464 } 465 466 format++; 467 } 468 469 ficlStackPushPointer(vm->dataStack, bufferStart); 470 ficlStackPushInteger(vm->dataStack, buffer - bufferStart); 471 ficlStackPushInteger(vm->dataStack, FICL_BOOL(!append)); 472 } 473 474 /* 475 * d u p & f r i e n d s 476 */ 477 static void 478 ficlPrimitiveDepth(ficlVm *vm) 479 { 480 int i; 481 482 FICL_STACK_CHECK(vm->dataStack, 0, 1); 483 484 i = ficlStackDepth(vm->dataStack); 485 ficlStackPushInteger(vm->dataStack, i); 486 } 487 488 /* 489 * e m i t & f r i e n d s 490 */ 491 static void 492 ficlPrimitiveEmit(ficlVm *vm) 493 { 494 char buffer[2]; 495 int i; 496 497 FICL_STACK_CHECK(vm->dataStack, 1, 0); 498 499 i = ficlStackPopInteger(vm->dataStack); 500 buffer[0] = (char)i; 501 buffer[1] = '\0'; 502 ficlVmTextOut(vm, buffer); 503 } 504 505 static void 506 ficlPrimitiveCR(ficlVm *vm) 507 { 508 ficlVmTextOut(vm, "\n"); 509 } 510 511 static void 512 ficlPrimitiveBackslash(ficlVm *vm) 513 { 514 char *trace = ficlVmGetInBuf(vm); 515 char *stop = ficlVmGetInBufEnd(vm); 516 char c = *trace; 517 518 while ((trace != stop) && (c != '\r') && (c != '\n')) { 519 c = *++trace; 520 } 521 522 /* 523 * Cope with DOS or UNIX-style EOLs - 524 * Check for /r, /n, /r/n, or /n/r end-of-line sequences, 525 * and point trace to next char. If EOL is \0, we're done. 526 */ 527 if (trace != stop) { 528 trace++; 529 530 if ((trace != stop) && (c != *trace) && 531 ((*trace == '\r') || (*trace == '\n'))) 532 trace++; 533 } 534 535 ficlVmUpdateTib(vm, trace); 536 } 537 538 /* 539 * paren CORE 540 * Compilation: Perform the execution semantics given below. 541 * Execution: ( "ccc<paren>" -- ) 542 * Parse ccc delimited by ) (right parenthesis). ( is an immediate word. 543 * The number of characters in ccc may be zero to the number of characters 544 * in the parse area. 545 */ 546 static void 547 ficlPrimitiveParenthesis(ficlVm *vm) 548 { 549 (void) ficlVmParseStringEx(vm, ')', 0); 550 } 551 552 /* 553 * F E T C H & S T O R E 554 */ 555 556 /* 557 * i f C o I m 558 * IMMEDIATE 559 * Compiles code for a conditional branch into the dictionary 560 * and pushes the branch patch address on the stack for later 561 * patching by ELSE or THEN/ENDIF. 562 */ 563 static void 564 ficlPrimitiveIfCoIm(ficlVm *vm) 565 { 566 ficlDictionary *dictionary = ficlVmGetDictionary(vm); 567 568 ficlDictionaryAppendUnsigned(dictionary, 569 ficlInstructionBranch0ParenWithCheck); 570 markBranch(dictionary, vm, origTag); 571 ficlDictionaryAppendUnsigned(dictionary, 1); 572 } 573 574 /* 575 * e l s e C o I m 576 * 577 * IMMEDIATE -- compiles an "else"... 578 * 1) FICL_VM_STATE_COMPILE a branch and a patch address; 579 * the address gets patched 580 * by "endif" to point past the "else" code. 581 * 2) Pop the the "if" patch address 582 * 3) Patch the "if" branch to point to the current FICL_VM_STATE_COMPILE 583 * address. 584 * 4) Push the "else" patch address. ("endif" patches this to jump past 585 * the "else" code. 586 */ 587 static void 588 ficlPrimitiveElseCoIm(ficlVm *vm) 589 { 590 ficlCell *patchAddr; 591 ficlInteger offset; 592 ficlDictionary *dictionary = ficlVmGetDictionary(vm); 593 594 /* (1) FICL_VM_STATE_COMPILE branch runtime */ 595 ficlDictionaryAppendUnsigned(dictionary, 596 ficlInstructionBranchParenWithCheck); 597 598 matchControlTag(vm, origTag); 599 /* (2) pop "if" patch addr */ 600 patchAddr = (ficlCell *)ficlStackPopPointer(vm->dataStack); 601 markBranch(dictionary, vm, origTag); /* (4) push "else" patch addr */ 602 603 /* (1) FICL_VM_STATE_COMPILE patch placeholder */ 604 ficlDictionaryAppendUnsigned(dictionary, 1); 605 offset = dictionary->here - patchAddr; 606 (*patchAddr).i = offset; /* (3) Patch "if" */ 607 } 608 609 /* 610 * e n d i f C o I m 611 */ 612 static void 613 ficlPrimitiveEndifCoIm(ficlVm *vm) 614 { 615 ficlDictionary *dictionary = ficlVmGetDictionary(vm); 616 resolveForwardBranch(dictionary, vm, origTag); 617 } 618 619 /* 620 * c a s e C o I m 621 * IMMEDIATE FICL_VM_STATE_COMPILE-ONLY 622 * 623 * 624 * At FICL_VM_STATE_COMPILE-time, a CASE-SYS (see DPANS94 6.2.0873) looks 625 * like this: 626 * i*addr i caseTag 627 * and an OF-SYS (see DPANS94 6.2.1950) looks like this: 628 * i*addr i caseTag addr ofTag 629 * The integer under caseTag is the count of fixup addresses that branch 630 * to ENDCASE. 631 */ 632 static void 633 ficlPrimitiveCaseCoIm(ficlVm *vm) 634 { 635 FICL_STACK_CHECK(vm->dataStack, 0, 2); 636 637 ficlStackPushUnsigned(vm->dataStack, 0); 638 markControlTag(vm, caseTag); 639 } 640 641 /* 642 * e n d c a s eC o I m 643 * IMMEDIATE FICL_VM_STATE_COMPILE-ONLY 644 */ 645 static void 646 ficlPrimitiveEndcaseCoIm(ficlVm *vm) 647 { 648 ficlUnsigned fixupCount; 649 ficlDictionary *dictionary; 650 ficlCell *patchAddr; 651 ficlInteger offset; 652 653 /* 654 * if the last OF ended with FALLTHROUGH, 655 * just add the FALLTHROUGH fixup to the 656 * ENDOF fixups 657 */ 658 if (ficlStackGetTop(vm->dataStack).p == fallthroughTag) { 659 matchControlTag(vm, fallthroughTag); 660 patchAddr = ficlStackPopPointer(vm->dataStack); 661 matchControlTag(vm, caseTag); 662 fixupCount = ficlStackPopUnsigned(vm->dataStack); 663 ficlStackPushPointer(vm->dataStack, patchAddr); 664 ficlStackPushUnsigned(vm->dataStack, fixupCount + 1); 665 markControlTag(vm, caseTag); 666 } 667 668 matchControlTag(vm, caseTag); 669 670 FICL_STACK_CHECK(vm->dataStack, 1, 0); 671 672 fixupCount = ficlStackPopUnsigned(vm->dataStack); 673 FICL_STACK_CHECK(vm->dataStack, fixupCount, 0); 674 675 dictionary = ficlVmGetDictionary(vm); 676 677 ficlDictionaryAppendUnsigned(dictionary, ficlInstructionDrop); 678 679 while (fixupCount--) { 680 patchAddr = (ficlCell *)ficlStackPopPointer(vm->dataStack); 681 offset = dictionary->here - patchAddr; 682 (*patchAddr).i = offset; 683 } 684 } 685 686 /* 687 * o f C o I m 688 * IMMEDIATE FICL_VM_STATE_COMPILE-ONLY 689 */ 690 static void 691 ficlPrimitiveOfCoIm(ficlVm *vm) 692 { 693 ficlDictionary *dictionary = ficlVmGetDictionary(vm); 694 ficlCell *fallthroughFixup = NULL; 695 696 FICL_STACK_CHECK(vm->dataStack, 1, 3); 697 698 if (ficlStackGetTop(vm->dataStack).p == fallthroughTag) { 699 matchControlTag(vm, fallthroughTag); 700 fallthroughFixup = ficlStackPopPointer(vm->dataStack); 701 } 702 703 matchControlTag(vm, caseTag); 704 705 markControlTag(vm, caseTag); 706 707 ficlDictionaryAppendUnsigned(dictionary, ficlInstructionOfParen); 708 markBranch(dictionary, vm, ofTag); 709 ficlDictionaryAppendUnsigned(dictionary, 2); 710 711 if (fallthroughFixup != NULL) { 712 ficlInteger offset = dictionary->here - fallthroughFixup; 713 (*fallthroughFixup).i = offset; 714 } 715 } 716 717 /* 718 * e n d o f C o I m 719 * IMMEDIATE FICL_VM_STATE_COMPILE-ONLY 720 */ 721 static void 722 ficlPrimitiveEndofCoIm(ficlVm *vm) 723 { 724 ficlCell *patchAddr; 725 ficlUnsigned fixupCount; 726 ficlInteger offset; 727 ficlDictionary *dictionary = ficlVmGetDictionary(vm); 728 729 FICL_STACK_CHECK(vm->dataStack, 4, 3); 730 731 /* ensure we're in an OF, */ 732 matchControlTag(vm, ofTag); 733 734 /* grab the address of the branch location after the OF */ 735 patchAddr = (ficlCell *)ficlStackPopPointer(vm->dataStack); 736 /* ensure we're also in a "case" */ 737 matchControlTag(vm, caseTag); 738 /* grab the current number of ENDOF fixups */ 739 fixupCount = ficlStackPopUnsigned(vm->dataStack); 740 741 /* FICL_VM_STATE_COMPILE branch runtime */ 742 ficlDictionaryAppendUnsigned(dictionary, 743 ficlInstructionBranchParenWithCheck); 744 745 /* 746 * push a new ENDOF fixup, the updated count of ENDOF fixups, 747 * and the caseTag 748 */ 749 ficlStackPushPointer(vm->dataStack, dictionary->here); 750 ficlStackPushUnsigned(vm->dataStack, fixupCount + 1); 751 markControlTag(vm, caseTag); 752 753 /* reserve space for the ENDOF fixup */ 754 ficlDictionaryAppendUnsigned(dictionary, 2); 755 756 /* and patch the original OF */ 757 offset = dictionary->here - patchAddr; 758 (*patchAddr).i = offset; 759 } 760 761 /* 762 * f a l l t h r o u g h C o I m 763 * IMMEDIATE FICL_VM_STATE_COMPILE-ONLY 764 */ 765 static void 766 ficlPrimitiveFallthroughCoIm(ficlVm *vm) 767 { 768 ficlCell *patchAddr; 769 ficlInteger offset; 770 ficlDictionary *dictionary = ficlVmGetDictionary(vm); 771 772 FICL_STACK_CHECK(vm->dataStack, 4, 3); 773 774 /* ensure we're in an OF, */ 775 matchControlTag(vm, ofTag); 776 /* grab the address of the branch location after the OF */ 777 patchAddr = (ficlCell *)ficlStackPopPointer(vm->dataStack); 778 /* ensure we're also in a "case" */ 779 matchControlTag(vm, caseTag); 780 781 /* okay, here we go. put the case tag back. */ 782 markControlTag(vm, caseTag); 783 784 /* FICL_VM_STATE_COMPILE branch runtime */ 785 ficlDictionaryAppendUnsigned(dictionary, 786 ficlInstructionBranchParenWithCheck); 787 788 /* push a new FALLTHROUGH fixup and the fallthroughTag */ 789 ficlStackPushPointer(vm->dataStack, dictionary->here); 790 markControlTag(vm, fallthroughTag); 791 792 /* reserve space for the FALLTHROUGH fixup */ 793 ficlDictionaryAppendUnsigned(dictionary, 2); 794 795 /* and patch the original OF */ 796 offset = dictionary->here - patchAddr; 797 (*patchAddr).i = offset; 798 } 799 800 /* 801 * h a s h 802 * hash ( c-addr u -- code) 803 * calculates hashcode of specified string and leaves it on the stack 804 */ 805 static void 806 ficlPrimitiveHash(ficlVm *vm) 807 { 808 ficlString s; 809 810 FICL_STRING_SET_LENGTH(s, ficlStackPopUnsigned(vm->dataStack)); 811 FICL_STRING_SET_POINTER(s, ficlStackPopPointer(vm->dataStack)); 812 ficlStackPushUnsigned(vm->dataStack, ficlHashCode(s)); 813 } 814 815 /* 816 * i n t e r p r e t 817 * This is the "user interface" of a Forth. It does the following: 818 * while there are words in the VM's Text Input Buffer 819 * Copy next word into the pad (ficlVmGetWord) 820 * Attempt to find the word in the dictionary (ficlDictionaryLookup) 821 * If successful, execute the word. 822 * Otherwise, attempt to convert the word to a number (isNumber) 823 * If successful, push the number onto the parameter stack. 824 * Otherwise, print an error message and exit loop... 825 * End Loop 826 * 827 * From the standard, section 3.4 828 * Text interpretation (see 6.1.1360 EVALUATE and 6.1.2050 QUIT) shall 829 * repeat the following steps until either the parse area is empty or an 830 * ambiguous condition exists: 831 * a) Skip leading spaces and parse a name (see 3.4.1); 832 */ 833 static void 834 ficlPrimitiveInterpret(ficlVm *vm) 835 { 836 ficlString s; 837 int i; 838 ficlSystem *system; 839 840 FICL_VM_ASSERT(vm, vm); 841 842 system = vm->callback.system; 843 s = ficlVmGetWord0(vm); 844 845 /* 846 * Get next word...if out of text, we're done. 847 */ 848 if (s.length == 0) { 849 ficlVmThrow(vm, FICL_VM_STATUS_OUT_OF_TEXT); 850 } 851 852 /* 853 * Run the parse chain against the incoming token until somebody 854 * eats it. Otherwise emit an error message and give up. 855 */ 856 for (i = 0; i < FICL_MAX_PARSE_STEPS; i++) { 857 ficlWord *word = system->parseList[i]; 858 859 if (word == NULL) 860 break; 861 862 if (word->code == ficlPrimitiveParseStepParen) { 863 ficlParseStep pStep; 864 pStep = (ficlParseStep)(word->param->fn); 865 if ((*pStep)(vm, s)) 866 return; 867 } else { 868 ficlStackPushPointer(vm->dataStack, 869 FICL_STRING_GET_POINTER(s)); 870 ficlStackPushUnsigned(vm->dataStack, 871 FICL_STRING_GET_LENGTH(s)); 872 (void) ficlVmExecuteXT(vm, word); 873 if (ficlStackPopInteger(vm->dataStack)) 874 return; 875 } 876 } 877 878 ficlVmThrowError(vm, "%.*s not found", FICL_STRING_GET_LENGTH(s), 879 FICL_STRING_GET_POINTER(s)); 880 /* back to inner interpreter */ 881 } 882 883 /* 884 * Surrogate precompiled parse step for ficlParseWord 885 * (this step is hard coded in FICL_VM_STATE_INTERPRET) 886 */ 887 static void 888 ficlPrimitiveLookup(ficlVm *vm) 889 { 890 ficlString name; 891 FICL_STRING_SET_LENGTH(name, ficlStackPopUnsigned(vm->dataStack)); 892 FICL_STRING_SET_POINTER(name, ficlStackPopPointer(vm->dataStack)); 893 ficlStackPushInteger(vm->dataStack, ficlVmParseWord(vm, name)); 894 } 895 896 /* 897 * p a r e n P a r s e S t e p 898 * (parse-step) ( c-addr u -- flag ) 899 * runtime for a precompiled parse step - pop a counted string off the 900 * stack, run the parse step against it, and push the result flag (FICL_TRUE 901 * if success, FICL_FALSE otherwise). 902 */ 903 void 904 ficlPrimitiveParseStepParen(ficlVm *vm) 905 { 906 ficlString s; 907 ficlWord *word = vm->runningWord; 908 ficlParseStep pStep = (ficlParseStep)(word->param->fn); 909 910 FICL_STRING_SET_LENGTH(s, ficlStackPopInteger(vm->dataStack)); 911 FICL_STRING_SET_POINTER(s, ficlStackPopPointer(vm->dataStack)); 912 913 ficlStackPushInteger(vm->dataStack, (*pStep)(vm, s)); 914 } 915 916 static void 917 ficlPrimitiveAddParseStep(ficlVm *vm) 918 { 919 ficlWord *pStep; 920 ficlDictionary *dictionary = ficlVmGetDictionary(vm); 921 922 FICL_STACK_CHECK(vm->dataStack, 1, 0); 923 924 pStep = (ficlWord *)(ficlStackPop(vm->dataStack).p); 925 if ((pStep != NULL) && ficlDictionaryIsAWord(dictionary, pStep)) 926 (void) ficlSystemAddParseStep(vm->callback.system, pStep); 927 } 928 929 /* 930 * l i t e r a l I m 931 * 932 * IMMEDIATE code for "literal". This function gets a value from the stack 933 * and compiles it into the dictionary preceded by the code for "(literal)". 934 * IMMEDIATE 935 */ 936 void 937 ficlPrimitiveLiteralIm(ficlVm *vm) 938 { 939 ficlDictionary *dictionary = ficlVmGetDictionary(vm); 940 ficlInteger value; 941 942 value = ficlStackPopInteger(vm->dataStack); 943 944 switch (value) { 945 case 1: 946 case 2: 947 case 3: 948 case 4: 949 case 5: 950 case 6: 951 case 7: 952 case 8: 953 case 9: 954 case 10: 955 case 11: 956 case 12: 957 case 13: 958 case 14: 959 case 15: 960 case 16: 961 ficlDictionaryAppendUnsigned(dictionary, value); 962 break; 963 964 case 0: 965 case -1: 966 case -2: 967 case -3: 968 case -4: 969 case -5: 970 case -6: 971 case -7: 972 case -8: 973 case -9: 974 case -10: 975 case -11: 976 case -12: 977 case -13: 978 case -14: 979 case -15: 980 case -16: 981 ficlDictionaryAppendUnsigned(dictionary, 982 ficlInstruction0 - value); 983 break; 984 985 default: 986 ficlDictionaryAppendUnsigned(dictionary, 987 ficlInstructionLiteralParen); 988 ficlDictionaryAppendUnsigned(dictionary, value); 989 break; 990 } 991 } 992 993 static void 994 ficlPrimitive2LiteralIm(ficlVm *vm) 995 { 996 ficlDictionary *dictionary = ficlVmGetDictionary(vm); 997 998 ficlDictionaryAppendUnsigned(dictionary, ficlInstruction2LiteralParen); 999 ficlDictionaryAppendCell(dictionary, ficlStackPop(vm->dataStack)); 1000 ficlDictionaryAppendCell(dictionary, ficlStackPop(vm->dataStack)); 1001 } 1002 1003 /* 1004 * D o / L o o p 1005 * do -- IMMEDIATE FICL_VM_STATE_COMPILE ONLY 1006 * Compiles code to initialize a loop: FICL_VM_STATE_COMPILE (do), 1007 * allot space to hold the "leave" address, push a branch 1008 * target address for the loop. 1009 * (do) -- runtime for "do" 1010 * pops index and limit from the p stack and moves them 1011 * to the r stack, then skips to the loop body. 1012 * loop -- IMMEDIATE FICL_VM_STATE_COMPILE ONLY 1013 * +loop 1014 * Compiles code for the test part of a loop: 1015 * FICL_VM_STATE_COMPILE (loop), resolve forward branch from "do", and 1016 * copy "here" address to the "leave" address allotted by "do" 1017 * i,j,k -- FICL_VM_STATE_COMPILE ONLY 1018 * Runtime: Push loop indices on param stack (i is innermost loop...) 1019 * Note: each loop has three values on the return stack: 1020 * ( R: leave limit index ) 1021 * "leave" is the absolute address of the next ficlCell after the loop 1022 * limit and index are the loop control variables. 1023 * leave -- FICL_VM_STATE_COMPILE ONLY 1024 * Runtime: pop the loop control variables, then pop the 1025 * "leave" address and jump (absolute) there. 1026 */ 1027 static void 1028 ficlPrimitiveDoCoIm(ficlVm *vm) 1029 { 1030 ficlDictionary *dictionary = ficlVmGetDictionary(vm); 1031 1032 ficlDictionaryAppendUnsigned(dictionary, ficlInstructionDoParen); 1033 /* 1034 * Allot space for a pointer to the end 1035 * of the loop - "leave" uses this... 1036 */ 1037 markBranch(dictionary, vm, leaveTag); 1038 ficlDictionaryAppendUnsigned(dictionary, 0); 1039 /* 1040 * Mark location of head of loop... 1041 */ 1042 markBranch(dictionary, vm, doTag); 1043 } 1044 1045 static void 1046 ficlPrimitiveQDoCoIm(ficlVm *vm) 1047 { 1048 ficlDictionary *dictionary = ficlVmGetDictionary(vm); 1049 1050 ficlDictionaryAppendUnsigned(dictionary, ficlInstructionQDoParen); 1051 /* 1052 * Allot space for a pointer to the end 1053 * of the loop - "leave" uses this... 1054 */ 1055 markBranch(dictionary, vm, leaveTag); 1056 ficlDictionaryAppendUnsigned(dictionary, 0); 1057 /* 1058 * Mark location of head of loop... 1059 */ 1060 markBranch(dictionary, vm, doTag); 1061 } 1062 1063 1064 static void 1065 ficlPrimitiveLoopCoIm(ficlVm *vm) 1066 { 1067 ficlDictionary *dictionary = ficlVmGetDictionary(vm); 1068 1069 ficlDictionaryAppendUnsigned(dictionary, ficlInstructionLoopParen); 1070 resolveBackBranch(dictionary, vm, doTag); 1071 resolveAbsBranch(dictionary, vm, leaveTag); 1072 } 1073 1074 static void 1075 ficlPrimitivePlusLoopCoIm(ficlVm *vm) 1076 { 1077 ficlDictionary *dictionary = ficlVmGetDictionary(vm); 1078 1079 ficlDictionaryAppendUnsigned(dictionary, ficlInstructionPlusLoopParen); 1080 resolveBackBranch(dictionary, vm, doTag); 1081 resolveAbsBranch(dictionary, vm, leaveTag); 1082 } 1083 1084 /* 1085 * v a r i a b l e 1086 */ 1087 static void 1088 ficlPrimitiveVariable(ficlVm *vm) 1089 { 1090 ficlDictionary *dictionary = ficlVmGetDictionary(vm); 1091 ficlString name = ficlVmGetWord(vm); 1092 1093 (void) ficlDictionaryAppendWord(dictionary, name, 1094 (ficlPrimitive)ficlInstructionVariableParen, FICL_WORD_DEFAULT); 1095 ficlVmDictionaryAllotCells(vm, dictionary, 1); 1096 } 1097 1098 static void 1099 ficlPrimitive2Variable(ficlVm *vm) 1100 { 1101 ficlDictionary *dictionary = ficlVmGetDictionary(vm); 1102 ficlString name = ficlVmGetWord(vm); 1103 1104 (void) ficlDictionaryAppendWord(dictionary, name, 1105 (ficlPrimitive)ficlInstructionVariableParen, FICL_WORD_DEFAULT); 1106 ficlVmDictionaryAllotCells(vm, dictionary, 2); 1107 } 1108 1109 /* 1110 * b a s e & f r i e n d s 1111 */ 1112 static void 1113 ficlPrimitiveBase(ficlVm *vm) 1114 { 1115 ficlCell *pBase, c; 1116 1117 FICL_STACK_CHECK(vm->dataStack, 0, 1); 1118 1119 pBase = (ficlCell *)(&vm->base); 1120 c.p = pBase; 1121 ficlStackPush(vm->dataStack, c); 1122 } 1123 1124 static void 1125 ficlPrimitiveDecimal(ficlVm *vm) 1126 { 1127 vm->base = 10; 1128 } 1129 1130 1131 static void 1132 ficlPrimitiveHex(ficlVm *vm) 1133 { 1134 vm->base = 16; 1135 } 1136 1137 /* 1138 * a l l o t & f r i e n d s 1139 */ 1140 static void 1141 ficlPrimitiveAllot(ficlVm *vm) 1142 { 1143 ficlDictionary *dictionary; 1144 ficlInteger i; 1145 1146 FICL_STACK_CHECK(vm->dataStack, 1, 0); 1147 1148 dictionary = ficlVmGetDictionary(vm); 1149 i = ficlStackPopInteger(vm->dataStack); 1150 1151 FICL_VM_DICTIONARY_CHECK(vm, dictionary, i); 1152 1153 ficlVmDictionaryAllot(vm, dictionary, i); 1154 } 1155 1156 static void 1157 ficlPrimitiveHere(ficlVm *vm) 1158 { 1159 ficlDictionary *dictionary; 1160 1161 FICL_STACK_CHECK(vm->dataStack, 0, 1); 1162 1163 dictionary = ficlVmGetDictionary(vm); 1164 ficlStackPushPointer(vm->dataStack, dictionary->here); 1165 } 1166 1167 /* 1168 * t i c k 1169 * tick CORE ( "<spaces>name" -- xt ) 1170 * Skip leading space delimiters. Parse name delimited by a space. Find 1171 * name and return xt, the execution token for name. An ambiguous condition 1172 * exists if name is not found. 1173 */ 1174 void 1175 ficlPrimitiveTick(ficlVm *vm) 1176 { 1177 ficlWord *word = NULL; 1178 ficlString name = ficlVmGetWord(vm); 1179 1180 FICL_STACK_CHECK(vm->dataStack, 0, 1); 1181 1182 word = ficlDictionaryLookup(ficlVmGetDictionary(vm), name); 1183 if (!word) 1184 ficlVmThrowError(vm, "%.*s not found", 1185 FICL_STRING_GET_LENGTH(name), 1186 FICL_STRING_GET_POINTER(name)); 1187 ficlStackPushPointer(vm->dataStack, word); 1188 } 1189 1190 static void 1191 ficlPrimitiveBracketTickCoIm(ficlVm *vm) 1192 { 1193 ficlPrimitiveTick(vm); 1194 ficlPrimitiveLiteralIm(vm); 1195 } 1196 1197 /* 1198 * p o s t p o n e 1199 * Lookup the next word in the input stream and FICL_VM_STATE_COMPILE code to 1200 * insert it into definitions created by the resulting word 1201 * (defers compilation, even of immediate words) 1202 */ 1203 static void 1204 ficlPrimitivePostponeCoIm(ficlVm *vm) 1205 { 1206 ficlDictionary *dictionary = ficlVmGetDictionary(vm); 1207 ficlWord *word; 1208 ficlWord *pComma = ficlSystemLookup(vm->callback.system, ","); 1209 ficlCell c; 1210 1211 FICL_VM_ASSERT(vm, pComma); 1212 1213 ficlPrimitiveTick(vm); 1214 word = ficlStackGetTop(vm->dataStack).p; 1215 if (ficlWordIsImmediate(word)) { 1216 ficlDictionaryAppendCell(dictionary, 1217 ficlStackPop(vm->dataStack)); 1218 } else { 1219 ficlPrimitiveLiteralIm(vm); 1220 c.p = pComma; 1221 ficlDictionaryAppendCell(dictionary, c); 1222 } 1223 } 1224 1225 /* 1226 * e x e c u t e 1227 * Pop an execution token (pointer to a word) off the stack and 1228 * run it 1229 */ 1230 static void 1231 ficlPrimitiveExecute(ficlVm *vm) 1232 { 1233 ficlWord *word; 1234 1235 FICL_STACK_CHECK(vm->dataStack, 1, 0); 1236 1237 word = ficlStackPopPointer(vm->dataStack); 1238 ficlVmExecuteWord(vm, word); 1239 } 1240 1241 /* 1242 * i m m e d i a t e 1243 * Make the most recently compiled word IMMEDIATE -- it executes even 1244 * in FICL_VM_STATE_COMPILE state (most often used for control compiling words 1245 * such as IF, THEN, etc) 1246 */ 1247 static void 1248 ficlPrimitiveImmediate(ficlVm *vm) 1249 { 1250 FICL_IGNORE(vm); 1251 ficlDictionarySetImmediate(ficlVmGetDictionary(vm)); 1252 } 1253 1254 static void 1255 ficlPrimitiveCompileOnly(ficlVm *vm) 1256 { 1257 FICL_IGNORE(vm); 1258 ficlDictionarySetFlags(ficlVmGetDictionary(vm), FICL_WORD_COMPILE_ONLY); 1259 } 1260 1261 static void 1262 ficlPrimitiveSetObjectFlag(ficlVm *vm) 1263 { 1264 FICL_IGNORE(vm); 1265 ficlDictionarySetFlags(ficlVmGetDictionary(vm), FICL_WORD_OBJECT); 1266 } 1267 1268 static void 1269 ficlPrimitiveIsObject(ficlVm *vm) 1270 { 1271 ficlInteger flag; 1272 ficlWord *word = (ficlWord *)ficlStackPopPointer(vm->dataStack); 1273 1274 flag = ((word != NULL) && (word->flags & FICL_WORD_OBJECT))? 1275 FICL_TRUE : FICL_FALSE; 1276 1277 ficlStackPushInteger(vm->dataStack, flag); 1278 } 1279 1280 static void 1281 ficlPrimitiveCountedStringQuoteIm(ficlVm *vm) 1282 { 1283 ficlDictionary *dictionary = ficlVmGetDictionary(vm); 1284 1285 if (vm->state == FICL_VM_STATE_INTERPRET) { 1286 ficlCountedString *counted = (ficlCountedString *) 1287 dictionary->here; 1288 1289 (void) ficlVmGetString(vm, counted, '\"'); 1290 ficlStackPushPointer(vm->dataStack, counted); 1291 1292 /* 1293 * move HERE past string so it doesn't get overwritten. --lch 1294 */ 1295 ficlVmDictionaryAllot(vm, dictionary, 1296 counted->length + sizeof (ficlUnsigned8)); 1297 } else { /* FICL_VM_STATE_COMPILE state */ 1298 ficlDictionaryAppendUnsigned(dictionary, 1299 ficlInstructionCStringLiteralParen); 1300 dictionary->here = 1301 FICL_POINTER_TO_CELL(ficlVmGetString(vm, 1302 (ficlCountedString *)dictionary->here, '\"')); 1303 ficlDictionaryAlign(dictionary); 1304 } 1305 } 1306 1307 /* 1308 * d o t Q u o t e 1309 * IMMEDIATE word that compiles a string literal for later display 1310 * FICL_VM_STATE_COMPILE fiStringLiteralParen, then copy the bytes of the 1311 * string from the 1312 * TIB to the dictionary. Backpatch the count byte and align the dictionary. 1313 */ 1314 static void 1315 ficlPrimitiveDotQuoteCoIm(ficlVm *vm) 1316 { 1317 ficlDictionary *dictionary = ficlVmGetDictionary(vm); 1318 ficlWord *pType = ficlSystemLookup(vm->callback.system, "type"); 1319 ficlCell c; 1320 1321 FICL_VM_ASSERT(vm, pType); 1322 1323 ficlDictionaryAppendUnsigned(dictionary, 1324 ficlInstructionStringLiteralParen); 1325 dictionary->here = 1326 FICL_POINTER_TO_CELL(ficlVmGetString(vm, 1327 (ficlCountedString *)dictionary->here, '\"')); 1328 ficlDictionaryAlign(dictionary); 1329 c.p = pType; 1330 ficlDictionaryAppendCell(dictionary, c); 1331 } 1332 1333 static void 1334 ficlPrimitiveDotParen(ficlVm *vm) 1335 { 1336 char *from = ficlVmGetInBuf(vm); 1337 char *stop = ficlVmGetInBufEnd(vm); 1338 char *to = vm->pad; 1339 char c; 1340 1341 /* 1342 * Note: the standard does not want leading spaces skipped. 1343 */ 1344 for (c = *from; (from != stop) && (c != ')'); c = *++from) 1345 *to++ = c; 1346 1347 *to = '\0'; 1348 if ((from != stop) && (c == ')')) 1349 from++; 1350 1351 ficlVmTextOut(vm, vm->pad); 1352 ficlVmUpdateTib(vm, from); 1353 } 1354 1355 /* 1356 * s l i t e r a l 1357 * STRING 1358 * Interpretation: Interpretation semantics for this word are undefined. 1359 * Compilation: ( c-addr1 u -- ) 1360 * Append the run-time semantics given below to the current definition. 1361 * Run-time: ( -- c-addr2 u ) 1362 * Return c-addr2 u describing a string consisting of the characters 1363 * specified by c-addr1 u during compilation. A program shall not alter 1364 * the returned string. 1365 */ 1366 static void ficlPrimitiveSLiteralCoIm(ficlVm *vm) 1367 { 1368 ficlDictionary *dictionary; 1369 char *from; 1370 char *to; 1371 ficlUnsigned length; 1372 1373 FICL_STACK_CHECK(vm->dataStack, 2, 0); 1374 1375 dictionary = ficlVmGetDictionary(vm); 1376 length = ficlStackPopUnsigned(vm->dataStack); 1377 from = ficlStackPopPointer(vm->dataStack); 1378 1379 ficlDictionaryAppendUnsigned(dictionary, 1380 ficlInstructionStringLiteralParen); 1381 to = (char *)dictionary->here; 1382 *to++ = (char)length; 1383 1384 for (; length > 0; --length) { 1385 *to++ = *from++; 1386 } 1387 1388 *to++ = 0; 1389 dictionary->here = FICL_POINTER_TO_CELL(ficlAlignPointer(to)); 1390 } 1391 1392 /* 1393 * s t a t e 1394 * Return the address of the VM's state member (must be sized the 1395 * same as a ficlCell for this reason) 1396 */ 1397 static void ficlPrimitiveState(ficlVm *vm) 1398 { 1399 FICL_STACK_CHECK(vm->dataStack, 0, 1); 1400 ficlStackPushPointer(vm->dataStack, &vm->state); 1401 } 1402 1403 /* 1404 * c r e a t e . . . d o e s > 1405 * Make a new word in the dictionary with the run-time effect of 1406 * a variable (push my address), but with extra space allotted 1407 * for use by does> . 1408 */ 1409 static void 1410 ficlPrimitiveCreate(ficlVm *vm) 1411 { 1412 ficlDictionary *dictionary = ficlVmGetDictionary(vm); 1413 ficlString name = ficlVmGetWord(vm); 1414 1415 (void) ficlDictionaryAppendWord(dictionary, name, 1416 (ficlPrimitive)ficlInstructionCreateParen, FICL_WORD_DEFAULT); 1417 ficlVmDictionaryAllotCells(vm, dictionary, 1); 1418 } 1419 1420 static void 1421 ficlPrimitiveDoesCoIm(ficlVm *vm) 1422 { 1423 ficlDictionary *dictionary = ficlVmGetDictionary(vm); 1424 #if FICL_WANT_LOCALS 1425 if (vm->callback.system->localsCount > 0) { 1426 ficlDictionary *locals = 1427 ficlSystemGetLocals(vm->callback.system); 1428 ficlDictionaryEmpty(locals, locals->forthWordlist->size); 1429 ficlDictionaryAppendUnsigned(dictionary, 1430 ficlInstructionUnlinkParen); 1431 } 1432 1433 vm->callback.system->localsCount = 0; 1434 #endif 1435 FICL_IGNORE(vm); 1436 1437 ficlDictionaryAppendUnsigned(dictionary, ficlInstructionDoesParen); 1438 } 1439 1440 /* 1441 * t o b o d y 1442 * to-body CORE ( xt -- a-addr ) 1443 * a-addr is the data-field address corresponding to xt. An ambiguous 1444 * condition exists if xt is not for a word defined via CREATE. 1445 */ 1446 static void 1447 ficlPrimitiveToBody(ficlVm *vm) 1448 { 1449 ficlWord *word; 1450 FICL_STACK_CHECK(vm->dataStack, 1, 1); 1451 1452 word = ficlStackPopPointer(vm->dataStack); 1453 ficlStackPushPointer(vm->dataStack, word->param + 1); 1454 } 1455 1456 /* 1457 * from-body Ficl ( a-addr -- xt ) 1458 * Reverse effect of >body 1459 */ 1460 static void 1461 ficlPrimitiveFromBody(ficlVm *vm) 1462 { 1463 char *ptr; 1464 FICL_STACK_CHECK(vm->dataStack, 1, 1); 1465 1466 ptr = (char *)ficlStackPopPointer(vm->dataStack) - sizeof (ficlWord); 1467 ficlStackPushPointer(vm->dataStack, ptr); 1468 } 1469 1470 /* 1471 * >name Ficl ( xt -- c-addr u ) 1472 * Push the address and length of a word's name given its address 1473 * xt. 1474 */ 1475 static void 1476 ficlPrimitiveToName(ficlVm *vm) 1477 { 1478 ficlWord *word; 1479 1480 FICL_STACK_CHECK(vm->dataStack, 1, 2); 1481 1482 word = ficlStackPopPointer(vm->dataStack); 1483 ficlStackPushPointer(vm->dataStack, word->name); 1484 ficlStackPushUnsigned(vm->dataStack, word->length); 1485 } 1486 1487 static void 1488 ficlPrimitiveLastWord(ficlVm *vm) 1489 { 1490 ficlDictionary *dictionary = ficlVmGetDictionary(vm); 1491 ficlWord *wp = dictionary->smudge; 1492 ficlCell c; 1493 1494 FICL_VM_ASSERT(vm, wp); 1495 1496 c.p = wp; 1497 ficlVmPush(vm, c); 1498 } 1499 1500 /* 1501 * l b r a c k e t e t c 1502 */ 1503 static void 1504 ficlPrimitiveLeftBracketCoIm(ficlVm *vm) 1505 { 1506 vm->state = FICL_VM_STATE_INTERPRET; 1507 } 1508 1509 static void 1510 ficlPrimitiveRightBracket(ficlVm *vm) 1511 { 1512 vm->state = FICL_VM_STATE_COMPILE; 1513 } 1514 1515 /* 1516 * p i c t u r e d n u m e r i c w o r d s 1517 * 1518 * less-number-sign CORE ( -- ) 1519 * Initialize the pictured numeric output conversion process. 1520 * (clear the pad) 1521 */ 1522 static void 1523 ficlPrimitiveLessNumberSign(ficlVm *vm) 1524 { 1525 ficlCountedString *counted = FICL_POINTER_TO_COUNTED_STRING(vm->pad); 1526 counted->length = 0; 1527 } 1528 1529 /* 1530 * number-sign CORE ( ud1 -- ud2 ) 1531 * Divide ud1 by the number in BASE giving the quotient ud2 and the remainder 1532 * n. (n is the least-significant digit of ud1.) Convert n to external form 1533 * and add the resulting character to the beginning of the pictured numeric 1534 * output string. An ambiguous condition exists if # executes outside of a 1535 * <# #> delimited number conversion. 1536 */ 1537 static void 1538 ficlPrimitiveNumberSign(ficlVm *vm) 1539 { 1540 ficlCountedString *counted; 1541 ficl2Unsigned u; 1542 ficl2UnsignedQR uqr; 1543 1544 FICL_STACK_CHECK(vm->dataStack, 2, 2); 1545 1546 counted = FICL_POINTER_TO_COUNTED_STRING(vm->pad); 1547 u = ficlStackPop2Unsigned(vm->dataStack); 1548 uqr = ficl2UnsignedDivide(u, (ficlUnsigned16)(vm->base)); 1549 counted->text[counted->length++] = ficlDigitToCharacter(uqr.remainder); 1550 ficlStackPush2Unsigned(vm->dataStack, uqr.quotient); 1551 } 1552 1553 /* 1554 * number-sign-greater CORE ( xd -- c-addr u ) 1555 * Drop xd. Make the pictured numeric output string available as a character 1556 * string. c-addr and u specify the resulting character string. A program 1557 * may replace characters within the string. 1558 */ 1559 static void 1560 ficlPrimitiveNumberSignGreater(ficlVm *vm) 1561 { 1562 ficlCountedString *counted; 1563 1564 FICL_STACK_CHECK(vm->dataStack, 2, 2); 1565 1566 counted = FICL_POINTER_TO_COUNTED_STRING(vm->pad); 1567 counted->text[counted->length] = 0; 1568 (void) ficlStringReverse(counted->text); 1569 ficlStackDrop(vm->dataStack, 2); 1570 ficlStackPushPointer(vm->dataStack, counted->text); 1571 ficlStackPushUnsigned(vm->dataStack, counted->length); 1572 } 1573 1574 /* 1575 * number-sign-s CORE ( ud1 -- ud2 ) 1576 * Convert one digit of ud1 according to the rule for #. Continue conversion 1577 * until the quotient is zero. ud2 is zero. An ambiguous condition exists if 1578 * #S executes outside of a <# #> delimited number conversion. 1579 * TO DO: presently does not use ud1 hi ficlCell - use it! 1580 */ 1581 static void 1582 ficlPrimitiveNumberSignS(ficlVm *vm) 1583 { 1584 ficlCountedString *counted; 1585 ficl2Unsigned u; 1586 ficl2UnsignedQR uqr; 1587 1588 FICL_STACK_CHECK(vm->dataStack, 2, 2); 1589 1590 counted = FICL_POINTER_TO_COUNTED_STRING(vm->pad); 1591 u = ficlStackPop2Unsigned(vm->dataStack); 1592 1593 do { 1594 uqr = ficl2UnsignedDivide(u, (ficlUnsigned16)(vm->base)); 1595 counted->text[counted->length++] = 1596 ficlDigitToCharacter(uqr.remainder); 1597 u = uqr.quotient; 1598 } while (FICL_2UNSIGNED_NOT_ZERO(u)); 1599 1600 ficlStackPush2Unsigned(vm->dataStack, u); 1601 } 1602 1603 /* 1604 * HOLD CORE ( char -- ) 1605 * Add char to the beginning of the pictured numeric output string. 1606 * An ambiguous condition exists if HOLD executes outside of a <# #> 1607 * delimited number conversion. 1608 */ 1609 static void 1610 ficlPrimitiveHold(ficlVm *vm) 1611 { 1612 ficlCountedString *counted; 1613 int i; 1614 1615 FICL_STACK_CHECK(vm->dataStack, 1, 0); 1616 1617 counted = FICL_POINTER_TO_COUNTED_STRING(vm->pad); 1618 i = ficlStackPopInteger(vm->dataStack); 1619 counted->text[counted->length++] = (char)i; 1620 } 1621 1622 /* 1623 * SIGN CORE ( n -- ) 1624 * If n is negative, add a minus sign to the beginning of the pictured 1625 * numeric output string. An ambiguous condition exists if SIGN 1626 * executes outside of a <# #> delimited number conversion. 1627 */ 1628 static void 1629 ficlPrimitiveSign(ficlVm *vm) 1630 { 1631 ficlCountedString *counted; 1632 int i; 1633 1634 FICL_STACK_CHECK(vm->dataStack, 1, 0); 1635 1636 counted = FICL_POINTER_TO_COUNTED_STRING(vm->pad); 1637 i = ficlStackPopInteger(vm->dataStack); 1638 if (i < 0) 1639 counted->text[counted->length++] = '-'; 1640 } 1641 1642 /* 1643 * t o N u m b e r 1644 * to-number CORE ( ud1 c-addr1 u1 -- ud2 c-addr2 u2 ) 1645 * ud2 is the unsigned result of converting the characters within the 1646 * string specified by c-addr1 u1 into digits, using the number in BASE, 1647 * and adding each into ud1 after multiplying ud1 by the number in BASE. 1648 * Conversion continues left-to-right until a character that is not 1649 * convertible, including any + or -, is encountered or the string is 1650 * entirely converted. c-addr2 is the location of the first unconverted 1651 * character or the first character past the end of the string if the string 1652 * was entirely converted. u2 is the number of unconverted characters in the 1653 * string. An ambiguous condition exists if ud2 overflows during the 1654 * conversion. 1655 */ 1656 static void 1657 ficlPrimitiveToNumber(ficlVm *vm) 1658 { 1659 ficlUnsigned length; 1660 char *trace; 1661 ficl2Unsigned accumulator; 1662 ficlUnsigned base = vm->base; 1663 ficlUnsigned c; 1664 ficlUnsigned digit; 1665 1666 FICL_STACK_CHECK(vm->dataStack, 4, 4); 1667 1668 length = ficlStackPopUnsigned(vm->dataStack); 1669 trace = (char *)ficlStackPopPointer(vm->dataStack); 1670 accumulator = ficlStackPop2Unsigned(vm->dataStack); 1671 1672 for (c = *trace; length > 0; c = *++trace, length--) { 1673 if (c < '0') 1674 break; 1675 1676 digit = c - '0'; 1677 1678 if (digit > 9) 1679 digit = tolower(c) - 'a' + 10; 1680 /* 1681 * Note: following test also catches chars between 9 and a 1682 * because 'digit' is unsigned! 1683 */ 1684 if (digit >= base) 1685 break; 1686 1687 accumulator = ficl2UnsignedMultiplyAccumulate(accumulator, 1688 base, digit); 1689 } 1690 1691 ficlStackPush2Unsigned(vm->dataStack, accumulator); 1692 ficlStackPushPointer(vm->dataStack, trace); 1693 ficlStackPushUnsigned(vm->dataStack, length); 1694 } 1695 1696 /* 1697 * q u i t & a b o r t 1698 * quit CORE ( -- ) ( R: i*x -- ) 1699 * Empty the return stack, store zero in SOURCE-ID if it is present, make 1700 * the user input device the input source, and enter interpretation state. 1701 * Do not display a message. Repeat the following: 1702 * 1703 * Accept a line from the input source into the input buffer, set >IN to 1704 * zero, and FICL_VM_STATE_INTERPRET. 1705 * Display the implementation-defined system prompt if in 1706 * interpretation state, all processing has been completed, and no 1707 * ambiguous condition exists. 1708 */ 1709 static void 1710 ficlPrimitiveQuit(ficlVm *vm) 1711 { 1712 ficlVmThrow(vm, FICL_VM_STATUS_QUIT); 1713 } 1714 1715 static void 1716 ficlPrimitiveAbort(ficlVm *vm) 1717 { 1718 ficlVmThrow(vm, FICL_VM_STATUS_ABORT); 1719 } 1720 1721 /* 1722 * a c c e p t 1723 * accept CORE ( c-addr +n1 -- +n2 ) 1724 * Receive a string of at most +n1 characters. An ambiguous condition 1725 * exists if +n1 is zero or greater than 32,767. Display graphic characters 1726 * as they are received. A program that depends on the presence or absence 1727 * of non-graphic characters in the string has an environmental dependency. 1728 * The editing functions, if any, that the system performs in order to 1729 * construct the string are implementation-defined. 1730 * 1731 * (Although the standard text doesn't say so, I assume that the intent 1732 * of 'accept' is to store the string at the address specified on 1733 * the stack.) 1734 * 1735 * NOTE: getchar() is used there as its present both in loader and 1736 * userland; however, the more correct solution would be to set 1737 * terminal to raw mode for userland. 1738 */ 1739 static void 1740 ficlPrimitiveAccept(ficlVm *vm) 1741 { 1742 ficlUnsigned size; 1743 char *address; 1744 int c; 1745 ficlUnsigned length = 0; 1746 1747 FICL_STACK_CHECK(vm->dataStack, 2, 1); 1748 1749 size = ficlStackPopInteger(vm->dataStack); 1750 address = ficlStackPopPointer(vm->dataStack); 1751 1752 while (size != length) { 1753 c = getchar(); 1754 if (c == '\n' || c == '\r') 1755 break; 1756 address[length++] = c; 1757 } 1758 ficlStackPushInteger(vm->dataStack, length); 1759 } 1760 1761 /* 1762 * a l i g n 1763 * 6.1.0705 ALIGN CORE ( -- ) 1764 * If the data-space pointer is not aligned, reserve enough space to 1765 * align it. 1766 */ 1767 static void 1768 ficlPrimitiveAlign(ficlVm *vm) 1769 { 1770 ficlDictionary *dictionary = ficlVmGetDictionary(vm); 1771 FICL_IGNORE(vm); 1772 ficlDictionaryAlign(dictionary); 1773 } 1774 1775 /* 1776 * a l i g n e d 1777 */ 1778 static void 1779 ficlPrimitiveAligned(ficlVm *vm) 1780 { 1781 void *addr; 1782 1783 FICL_STACK_CHECK(vm->dataStack, 1, 1); 1784 1785 addr = ficlStackPopPointer(vm->dataStack); 1786 ficlStackPushPointer(vm->dataStack, ficlAlignPointer(addr)); 1787 } 1788 1789 /* 1790 * b e g i n & f r i e n d s 1791 * Indefinite loop control structures 1792 * A.6.1.0760 BEGIN 1793 * Typical use: 1794 * : X ... BEGIN ... test UNTIL ; 1795 * or 1796 * : X ... BEGIN ... test WHILE ... REPEAT ; 1797 */ 1798 static void 1799 ficlPrimitiveBeginCoIm(ficlVm *vm) 1800 { 1801 ficlDictionary *dictionary = ficlVmGetDictionary(vm); 1802 markBranch(dictionary, vm, destTag); 1803 } 1804 1805 static void 1806 ficlPrimitiveUntilCoIm(ficlVm *vm) 1807 { 1808 ficlDictionary *dictionary = ficlVmGetDictionary(vm); 1809 1810 ficlDictionaryAppendUnsigned(dictionary, 1811 ficlInstructionBranch0ParenWithCheck); 1812 resolveBackBranch(dictionary, vm, destTag); 1813 } 1814 1815 static void 1816 ficlPrimitiveWhileCoIm(ficlVm *vm) 1817 { 1818 ficlDictionary *dictionary = ficlVmGetDictionary(vm); 1819 1820 FICL_STACK_CHECK(vm->dataStack, 2, 5); 1821 1822 ficlDictionaryAppendUnsigned(dictionary, 1823 ficlInstructionBranch0ParenWithCheck); 1824 markBranch(dictionary, vm, origTag); 1825 1826 /* equivalent to 2swap */ 1827 ficlStackRoll(vm->dataStack, 3); 1828 ficlStackRoll(vm->dataStack, 3); 1829 1830 ficlDictionaryAppendUnsigned(dictionary, 1); 1831 } 1832 1833 static void 1834 ficlPrimitiveRepeatCoIm(ficlVm *vm) 1835 { 1836 ficlDictionary *dictionary = ficlVmGetDictionary(vm); 1837 1838 ficlDictionaryAppendUnsigned(dictionary, 1839 ficlInstructionBranchParenWithCheck); 1840 /* expect "begin" branch marker */ 1841 resolveBackBranch(dictionary, vm, destTag); 1842 /* expect "while" branch marker */ 1843 resolveForwardBranch(dictionary, vm, origTag); 1844 } 1845 1846 static void 1847 ficlPrimitiveAgainCoIm(ficlVm *vm) 1848 { 1849 ficlDictionary *dictionary = ficlVmGetDictionary(vm); 1850 1851 ficlDictionaryAppendUnsigned(dictionary, 1852 ficlInstructionBranchParenWithCheck); 1853 /* expect "begin" branch marker */ 1854 resolveBackBranch(dictionary, vm, destTag); 1855 } 1856 1857 /* 1858 * c h a r & f r i e n d s 1859 * 6.1.0895 CHAR CORE ( "<spaces>name" -- char ) 1860 * Skip leading space delimiters. Parse name delimited by a space. 1861 * Put the value of its first character onto the stack. 1862 * 1863 * bracket-char CORE 1864 * Interpretation: Interpretation semantics for this word are undefined. 1865 * Compilation: ( "<spaces>name" -- ) 1866 * Skip leading space delimiters. Parse name delimited by a space. 1867 * Append the run-time semantics given below to the current definition. 1868 * Run-time: ( -- char ) 1869 * Place char, the value of the first character of name, on the stack. 1870 */ 1871 static void 1872 ficlPrimitiveChar(ficlVm *vm) 1873 { 1874 ficlString s; 1875 1876 FICL_STACK_CHECK(vm->dataStack, 0, 1); 1877 1878 s = ficlVmGetWord(vm); 1879 ficlStackPushUnsigned(vm->dataStack, (ficlUnsigned)(s.text[0])); 1880 } 1881 1882 static void 1883 ficlPrimitiveCharCoIm(ficlVm *vm) 1884 { 1885 ficlPrimitiveChar(vm); 1886 ficlPrimitiveLiteralIm(vm); 1887 } 1888 1889 /* 1890 * c h a r P l u s 1891 * char-plus CORE ( c-addr1 -- c-addr2 ) 1892 * Add the size in address units of a character to c-addr1, giving c-addr2. 1893 */ 1894 static void 1895 ficlPrimitiveCharPlus(ficlVm *vm) 1896 { 1897 char *p; 1898 1899 FICL_STACK_CHECK(vm->dataStack, 1, 1); 1900 1901 p = ficlStackPopPointer(vm->dataStack); 1902 ficlStackPushPointer(vm->dataStack, p + 1); 1903 } 1904 1905 /* 1906 * c h a r s 1907 * chars CORE ( n1 -- n2 ) 1908 * n2 is the size in address units of n1 characters. 1909 * For most processors, this function can be a no-op. To guarantee 1910 * portability, we'll multiply by sizeof (char). 1911 */ 1912 #if defined(_M_IX86) 1913 #pragma warning(disable: 4127) 1914 #endif 1915 static void 1916 ficlPrimitiveChars(ficlVm *vm) 1917 { 1918 if (sizeof (char) > 1) { 1919 ficlInteger i; 1920 1921 FICL_STACK_CHECK(vm->dataStack, 1, 1); 1922 1923 i = ficlStackPopInteger(vm->dataStack); 1924 ficlStackPushInteger(vm->dataStack, i * sizeof (char)); 1925 } 1926 /* otherwise no-op! */ 1927 } 1928 #if defined(_M_IX86) 1929 #pragma warning(default: 4127) 1930 #endif 1931 1932 /* 1933 * c o u n t 1934 * COUNT CORE ( c-addr1 -- c-addr2 u ) 1935 * Return the character string specification for the counted string stored 1936 * at c-addr1. c-addr2 is the address of the first character after c-addr1. 1937 * u is the contents of the character at c-addr1, which is the length in 1938 * characters of the string at c-addr2. 1939 */ 1940 static void 1941 ficlPrimitiveCount(ficlVm *vm) 1942 { 1943 ficlCountedString *counted; 1944 1945 FICL_STACK_CHECK(vm->dataStack, 1, 2); 1946 1947 counted = ficlStackPopPointer(vm->dataStack); 1948 ficlStackPushPointer(vm->dataStack, counted->text); 1949 ficlStackPushUnsigned(vm->dataStack, counted->length); 1950 } 1951 1952 /* 1953 * e n v i r o n m e n t ? 1954 * environment-query CORE ( c-addr u -- FICL_FALSE | i*x FICL_TRUE ) 1955 * c-addr is the address of a character string and u is the string's 1956 * character count. u may have a value in the range from zero to an 1957 * implementation-defined maximum which shall not be less than 31. The 1958 * character string should contain a keyword from 3.2.6 Environmental 1959 * queries or the optional word sets to be checked for correspondence 1960 * with an attribute of the present environment. If the system treats the 1961 * attribute as unknown, the returned flag is FICL_FALSE; otherwise, the flag 1962 * is FICL_TRUE and the i*x returned is of the type specified in the table for 1963 * the attribute queried. 1964 */ 1965 static void 1966 ficlPrimitiveEnvironmentQ(ficlVm *vm) 1967 { 1968 ficlDictionary *environment; 1969 ficlWord *word; 1970 ficlString name; 1971 1972 FICL_STACK_CHECK(vm->dataStack, 2, 1); 1973 1974 environment = vm->callback.system->environment; 1975 name.length = ficlStackPopUnsigned(vm->dataStack); 1976 name.text = ficlStackPopPointer(vm->dataStack); 1977 1978 word = ficlDictionaryLookup(environment, name); 1979 1980 if (word != NULL) { 1981 ficlVmExecuteWord(vm, word); 1982 ficlStackPushInteger(vm->dataStack, FICL_TRUE); 1983 } else { 1984 ficlStackPushInteger(vm->dataStack, FICL_FALSE); 1985 } 1986 } 1987 1988 /* 1989 * e v a l u a t e 1990 * EVALUATE CORE ( i*x c-addr u -- j*x ) 1991 * Save the current input source specification. Store minus-one (-1) in 1992 * SOURCE-ID if it is present. Make the string described by c-addr and u 1993 * both the input source and input buffer, set >IN to zero, and 1994 * FICL_VM_STATE_INTERPRET. 1995 * When the parse area is empty, restore the prior input source 1996 * specification. Other stack effects are due to the words EVALUATEd. 1997 */ 1998 static void 1999 ficlPrimitiveEvaluate(ficlVm *vm) 2000 { 2001 ficlCell id; 2002 int result; 2003 ficlString string; 2004 2005 FICL_STACK_CHECK(vm->dataStack, 2, 0); 2006 2007 FICL_STRING_SET_LENGTH(string, ficlStackPopUnsigned(vm->dataStack)); 2008 FICL_STRING_SET_POINTER(string, ficlStackPopPointer(vm->dataStack)); 2009 2010 id = vm->sourceId; 2011 vm->sourceId.i = -1; 2012 result = ficlVmExecuteString(vm, string); 2013 vm->sourceId = id; 2014 if (result != FICL_VM_STATUS_OUT_OF_TEXT) 2015 ficlVmThrow(vm, result); 2016 } 2017 2018 /* 2019 * s t r i n g q u o t e 2020 * Interpreting: get string delimited by a quote from the input stream, 2021 * copy to a scratch area, and put its count and address on the stack. 2022 * Compiling: FICL_VM_STATE_COMPILE code to push the address and count 2023 * of a string literal, FICL_VM_STATE_COMPILE the string from the input 2024 * stream, and align the dictionary pointer. 2025 */ 2026 static void 2027 ficlPrimitiveStringQuoteIm(ficlVm *vm) 2028 { 2029 ficlDictionary *dictionary = ficlVmGetDictionary(vm); 2030 2031 if (vm->state == FICL_VM_STATE_INTERPRET) { 2032 ficlCountedString *counted; 2033 counted = (ficlCountedString *)dictionary->here; 2034 (void) ficlVmGetString(vm, counted, '\"'); 2035 ficlStackPushPointer(vm->dataStack, counted->text); 2036 ficlStackPushUnsigned(vm->dataStack, counted->length); 2037 } else { /* FICL_VM_STATE_COMPILE state */ 2038 ficlDictionaryAppendUnsigned(dictionary, 2039 ficlInstructionStringLiteralParen); 2040 dictionary->here = FICL_POINTER_TO_CELL( 2041 ficlVmGetString(vm, (ficlCountedString *)dictionary->here, 2042 '\"')); 2043 ficlDictionaryAlign(dictionary); 2044 } 2045 } 2046 2047 /* 2048 * t y p e 2049 * Pop count and char address from stack and print the designated string. 2050 */ 2051 static void 2052 ficlPrimitiveType(ficlVm *vm) 2053 { 2054 ficlUnsigned length; 2055 char *s; 2056 2057 FICL_STACK_CHECK(vm->dataStack, 2, 0); 2058 2059 length = ficlStackPopUnsigned(vm->dataStack); 2060 s = ficlStackPopPointer(vm->dataStack); 2061 2062 if ((s == NULL) || (length == 0)) 2063 return; 2064 2065 /* 2066 * Since we don't have an output primitive for a counted string 2067 * (oops), make sure the string is null terminated. If not, copy 2068 * and terminate it. 2069 */ 2070 if (s[length] != 0) { 2071 char *here = (char *)ficlVmGetDictionary(vm)->here; 2072 if (s != here) 2073 (void) strncpy(here, s, length); 2074 2075 here[length] = '\0'; 2076 s = here; 2077 } 2078 2079 ficlVmTextOut(vm, s); 2080 } 2081 2082 /* 2083 * w o r d 2084 * word CORE ( char "<chars>ccc<char>" -- c-addr ) 2085 * Skip leading delimiters. Parse characters ccc delimited by char. An 2086 * ambiguous condition exists if the length of the parsed string is greater 2087 * than the implementation-defined length of a counted string. 2088 * 2089 * c-addr is the address of a transient region containing the parsed word 2090 * as a counted string. If the parse area was empty or contained no 2091 * characters other than the delimiter, the resulting string has a zero 2092 * length. A space, not included in the length, follows the string. A 2093 * program may replace characters within the string. 2094 * NOTE! Ficl also NULL-terminates the dest string. 2095 */ 2096 static void 2097 ficlPrimitiveWord(ficlVm *vm) 2098 { 2099 ficlCountedString *counted; 2100 char delim; 2101 ficlString name; 2102 2103 FICL_STACK_CHECK(vm->dataStack, 1, 1); 2104 2105 counted = (ficlCountedString *)vm->pad; 2106 delim = (char)ficlStackPopInteger(vm->dataStack); 2107 name = ficlVmParseStringEx(vm, delim, 1); 2108 2109 if (FICL_STRING_GET_LENGTH(name) > FICL_PAD_SIZE - 1) 2110 FICL_STRING_SET_LENGTH(name, FICL_PAD_SIZE - 1); 2111 2112 counted->length = (ficlUnsigned8)FICL_STRING_GET_LENGTH(name); 2113 (void) strncpy(counted->text, FICL_STRING_GET_POINTER(name), 2114 FICL_STRING_GET_LENGTH(name)); 2115 2116 /* 2117 * store an extra space at the end of the primitive... 2118 * why? dunno yet. Guy Carver did it. 2119 */ 2120 counted->text[counted->length] = ' '; 2121 counted->text[counted->length + 1] = 0; 2122 2123 ficlStackPushPointer(vm->dataStack, counted); 2124 } 2125 2126 /* 2127 * p a r s e - w o r d 2128 * Ficl PARSE-WORD ( <spaces>name -- c-addr u ) 2129 * Skip leading spaces and parse name delimited by a space. c-addr is the 2130 * address within the input buffer and u is the length of the selected 2131 * string. If the parse area is empty, the resulting string has a zero length. 2132 */ 2133 static void ficlPrimitiveParseNoCopy(ficlVm *vm) 2134 { 2135 ficlString s; 2136 2137 FICL_STACK_CHECK(vm->dataStack, 0, 2); 2138 2139 s = ficlVmGetWord0(vm); 2140 ficlStackPushPointer(vm->dataStack, FICL_STRING_GET_POINTER(s)); 2141 ficlStackPushUnsigned(vm->dataStack, FICL_STRING_GET_LENGTH(s)); 2142 } 2143 2144 /* 2145 * p a r s e 2146 * CORE EXT ( char "ccc<char>" -- c-addr u ) 2147 * Parse ccc delimited by the delimiter char. 2148 * c-addr is the address (within the input buffer) and u is the length of 2149 * the parsed string. If the parse area was empty, the resulting string has 2150 * a zero length. 2151 * NOTE! PARSE differs from WORD: it does not skip leading delimiters. 2152 */ 2153 static void 2154 ficlPrimitiveParse(ficlVm *vm) 2155 { 2156 ficlString s; 2157 char delim; 2158 2159 FICL_STACK_CHECK(vm->dataStack, 1, 2); 2160 2161 delim = (char)ficlStackPopInteger(vm->dataStack); 2162 2163 s = ficlVmParseStringEx(vm, delim, 0); 2164 ficlStackPushPointer(vm->dataStack, FICL_STRING_GET_POINTER(s)); 2165 ficlStackPushUnsigned(vm->dataStack, FICL_STRING_GET_LENGTH(s)); 2166 } 2167 2168 /* 2169 * f i n d 2170 * FIND CORE ( c-addr -- c-addr 0 | xt 1 | xt -1 ) 2171 * Find the definition named in the counted string at c-addr. If the 2172 * definition is not found, return c-addr and zero. If the definition is 2173 * found, return its execution token xt. If the definition is immediate, 2174 * also return one (1), otherwise also return minus-one (-1). For a given 2175 * string, the values returned by FIND while compiling may differ from 2176 * those returned while not compiling. 2177 */ 2178 static void 2179 do_find(ficlVm *vm, ficlString name, void *returnForFailure) 2180 { 2181 ficlWord *word; 2182 2183 word = ficlDictionaryLookup(ficlVmGetDictionary(vm), name); 2184 if (word) { 2185 ficlStackPushPointer(vm->dataStack, word); 2186 ficlStackPushInteger(vm->dataStack, 2187 (ficlWordIsImmediate(word) ? 1 : -1)); 2188 } else { 2189 ficlStackPushPointer(vm->dataStack, returnForFailure); 2190 ficlStackPushUnsigned(vm->dataStack, 0); 2191 } 2192 } 2193 2194 /* 2195 * f i n d 2196 * FIND CORE ( c-addr -- c-addr 0 | xt 1 | xt -1 ) 2197 * Find the definition named in the counted string at c-addr. If the 2198 * definition is not found, return c-addr and zero. If the definition is 2199 * found, return its execution token xt. If the definition is immediate, 2200 * also return one (1), otherwise also return minus-one (-1). For a given 2201 * string, the values returned by FIND while compiling may differ from 2202 * those returned while not compiling. 2203 */ 2204 static void 2205 ficlPrimitiveCFind(ficlVm *vm) 2206 { 2207 ficlCountedString *counted; 2208 ficlString name; 2209 2210 FICL_STACK_CHECK(vm->dataStack, 1, 2); 2211 2212 counted = ficlStackPopPointer(vm->dataStack); 2213 FICL_STRING_SET_FROM_COUNTED_STRING(name, *counted); 2214 do_find(vm, name, counted); 2215 } 2216 2217 /* 2218 * s f i n d 2219 * Ficl ( c-addr u -- 0 0 | xt 1 | xt -1 ) 2220 * Like FIND, but takes "c-addr u" for the string. 2221 */ 2222 static void 2223 ficlPrimitiveSFind(ficlVm *vm) 2224 { 2225 ficlString name; 2226 2227 FICL_STACK_CHECK(vm->dataStack, 2, 2); 2228 2229 name.length = ficlStackPopInteger(vm->dataStack); 2230 name.text = ficlStackPopPointer(vm->dataStack); 2231 2232 do_find(vm, name, NULL); 2233 } 2234 2235 /* 2236 * r e c u r s e 2237 */ 2238 static void 2239 ficlPrimitiveRecurseCoIm(ficlVm *vm) 2240 { 2241 ficlDictionary *dictionary = ficlVmGetDictionary(vm); 2242 ficlCell c; 2243 2244 FICL_IGNORE(vm); 2245 c.p = dictionary->smudge; 2246 ficlDictionaryAppendCell(dictionary, c); 2247 } 2248 2249 /* 2250 * s o u r c e 2251 * CORE ( -- c-addr u ) 2252 * c-addr is the address of, and u is the number of characters in, the 2253 * input buffer. 2254 */ 2255 static void 2256 ficlPrimitiveSource(ficlVm *vm) 2257 { 2258 FICL_STACK_CHECK(vm->dataStack, 0, 2); 2259 2260 ficlStackPushPointer(vm->dataStack, vm->tib.text); 2261 ficlStackPushInteger(vm->dataStack, ficlVmGetInBufLen(vm)); 2262 } 2263 2264 /* 2265 * v e r s i o n 2266 * non-standard... 2267 */ 2268 static void 2269 ficlPrimitiveVersion(ficlVm *vm) 2270 { 2271 ficlVmTextOut(vm, "Ficl version " FICL_VERSION "\n"); 2272 } 2273 2274 /* 2275 * t o I n 2276 * to-in CORE 2277 */ 2278 static void 2279 ficlPrimitiveToIn(ficlVm *vm) 2280 { 2281 FICL_STACK_CHECK(vm->dataStack, 0, 1); 2282 2283 ficlStackPushPointer(vm->dataStack, &vm->tib.index); 2284 } 2285 2286 /* 2287 * c o l o n N o N a m e 2288 * CORE EXT ( C: -- colon-sys ) ( S: -- xt ) 2289 * Create an unnamed colon definition and push its address. 2290 * Change state to FICL_VM_STATE_COMPILE. 2291 */ 2292 static void 2293 ficlPrimitiveColonNoName(ficlVm *vm) 2294 { 2295 ficlDictionary *dictionary = ficlVmGetDictionary(vm); 2296 ficlWord *word; 2297 ficlString name; 2298 2299 FICL_STRING_SET_LENGTH(name, 0); 2300 FICL_STRING_SET_POINTER(name, NULL); 2301 2302 vm->state = FICL_VM_STATE_COMPILE; 2303 word = ficlDictionaryAppendWord(dictionary, name, 2304 (ficlPrimitive)ficlInstructionColonParen, 2305 FICL_WORD_DEFAULT | FICL_WORD_SMUDGED); 2306 2307 ficlStackPushPointer(vm->dataStack, word); 2308 markControlTag(vm, colonTag); 2309 } 2310 2311 /* 2312 * u s e r V a r i a b l e 2313 * user ( u -- ) "<spaces>name" 2314 * Get a name from the input stream and create a user variable 2315 * with the name and the index supplied. The run-time effect 2316 * of a user variable is to push the address of the indexed ficlCell 2317 * in the running vm's user array. 2318 * 2319 * User variables are vm local cells. Each vm has an array of 2320 * FICL_USER_CELLS of them when FICL_WANT_USER is nonzero. 2321 * Ficl's user facility is implemented with two primitives, 2322 * "user" and "(user)", a variable ("nUser") (in softcore.c) that 2323 * holds the index of the next free user ficlCell, and a redefinition 2324 * (also in softcore) of "user" that defines a user word and increments 2325 * nUser. 2326 */ 2327 #if FICL_WANT_USER 2328 static void 2329 ficlPrimitiveUser(ficlVm *vm) 2330 { 2331 ficlDictionary *dictionary = ficlVmGetDictionary(vm); 2332 ficlString name = ficlVmGetWord(vm); 2333 ficlCell c; 2334 2335 c = ficlStackPop(vm->dataStack); 2336 if (c.i >= FICL_USER_CELLS) { 2337 ficlVmThrowError(vm, "Error - out of user space"); 2338 } 2339 2340 (void) ficlDictionaryAppendWord(dictionary, name, 2341 (ficlPrimitive)ficlInstructionUserParen, FICL_WORD_DEFAULT); 2342 ficlDictionaryAppendCell(dictionary, c); 2343 } 2344 #endif 2345 2346 #if FICL_WANT_LOCALS 2347 /* 2348 * Each local is recorded in a private locals dictionary as a 2349 * word that does doLocalIm at runtime. DoLocalIm compiles code 2350 * into the client definition to fetch the value of the 2351 * corresponding local variable from the return stack. 2352 * The private dictionary gets initialized at the end of each block 2353 * that uses locals (in ; and does> for example). 2354 */ 2355 void 2356 ficlLocalParenIm(ficlVm *vm, int isDouble, int isFloat) 2357 { 2358 ficlDictionary *dictionary = ficlVmGetDictionary(vm); 2359 ficlInteger nLocal = vm->runningWord->param[0].i; 2360 2361 #if !FICL_WANT_FLOAT 2362 FICL_VM_ASSERT(vm, !isFloat); 2363 /* get rid of unused parameter warning */ 2364 isFloat = 0; 2365 #endif /* FICL_WANT_FLOAT */ 2366 2367 if (vm->state == FICL_VM_STATE_INTERPRET) { 2368 ficlStack *stack; 2369 #if FICL_WANT_FLOAT 2370 if (isFloat) 2371 stack = vm->floatStack; 2372 else 2373 #endif /* FICL_WANT_FLOAT */ 2374 stack = vm->dataStack; 2375 2376 ficlStackPush(stack, vm->returnStack->frame[nLocal]); 2377 if (isDouble) 2378 ficlStackPush(stack, vm->returnStack->frame[nLocal+1]); 2379 } else { 2380 ficlInstruction instruction; 2381 ficlInteger appendLocalOffset; 2382 #if FICL_WANT_FLOAT 2383 if (isFloat) { 2384 instruction = 2385 (isDouble) ? ficlInstructionGetF2LocalParen : 2386 ficlInstructionGetFLocalParen; 2387 appendLocalOffset = FICL_TRUE; 2388 } else 2389 #endif /* FICL_WANT_FLOAT */ 2390 if (nLocal == 0) { 2391 instruction = (isDouble) ? ficlInstructionGet2Local0 : 2392 ficlInstructionGetLocal0; 2393 appendLocalOffset = FICL_FALSE; 2394 } else if ((nLocal == 1) && !isDouble) { 2395 instruction = ficlInstructionGetLocal1; 2396 appendLocalOffset = FICL_FALSE; 2397 } else { 2398 instruction = 2399 (isDouble) ? ficlInstructionGet2LocalParen : 2400 ficlInstructionGetLocalParen; 2401 appendLocalOffset = FICL_TRUE; 2402 } 2403 2404 ficlDictionaryAppendUnsigned(dictionary, instruction); 2405 if (appendLocalOffset) 2406 ficlDictionaryAppendUnsigned(dictionary, nLocal); 2407 } 2408 } 2409 2410 static void 2411 ficlPrimitiveDoLocalIm(ficlVm *vm) 2412 { 2413 ficlLocalParenIm(vm, 0, 0); 2414 } 2415 2416 static void 2417 ficlPrimitiveDo2LocalIm(ficlVm *vm) 2418 { 2419 ficlLocalParenIm(vm, 1, 0); 2420 } 2421 2422 #if FICL_WANT_FLOAT 2423 static void 2424 ficlPrimitiveDoFLocalIm(ficlVm *vm) 2425 { 2426 ficlLocalParenIm(vm, 0, 1); 2427 } 2428 2429 static void 2430 ficlPrimitiveDoF2LocalIm(ficlVm *vm) 2431 { 2432 ficlLocalParenIm(vm, 1, 1); 2433 } 2434 #endif /* FICL_WANT_FLOAT */ 2435 2436 /* 2437 * l o c a l P a r e n 2438 * paren-local-paren LOCAL 2439 * Interpretation: Interpretation semantics for this word are undefined. 2440 * Execution: ( c-addr u -- ) 2441 * When executed during compilation, (LOCAL) passes a message to the 2442 * system that has one of two meanings. If u is non-zero, 2443 * the message identifies a new local whose definition name is given by 2444 * the string of characters identified by c-addr u. If u is zero, 2445 * the message is last local and c-addr has no significance. 2446 * 2447 * The result of executing (LOCAL) during compilation of a definition is 2448 * to create a set of named local identifiers, each of which is 2449 * a definition name, that only have execution semantics within the scope 2450 * of that definition's source. 2451 * 2452 * local Execution: ( -- x ) 2453 * 2454 * Push the local's value, x, onto the stack. The local's value is 2455 * initialized as described in 13.3.3 Processing locals and may be 2456 * changed by preceding the local's name with TO. An ambiguous condition 2457 * exists when local is executed while in interpretation state. 2458 */ 2459 void 2460 ficlLocalParen(ficlVm *vm, int isDouble, int isFloat) 2461 { 2462 ficlDictionary *dictionary; 2463 ficlString name; 2464 2465 FICL_STACK_CHECK(vm->dataStack, 2, 0); 2466 2467 dictionary = ficlVmGetDictionary(vm); 2468 FICL_STRING_SET_LENGTH(name, ficlStackPopUnsigned(vm->dataStack)); 2469 FICL_STRING_SET_POINTER(name, 2470 (char *)ficlStackPopPointer(vm->dataStack)); 2471 2472 if (FICL_STRING_GET_LENGTH(name) > 0) { 2473 /* 2474 * add a local to the **locals** dictionary and 2475 * update localsCount 2476 */ 2477 ficlPrimitive code; 2478 ficlInstruction instruction; 2479 ficlDictionary *locals; 2480 2481 locals = ficlSystemGetLocals(vm->callback.system); 2482 if (vm->callback.system->localsCount >= FICL_MAX_LOCALS) { 2483 ficlVmThrowError(vm, "Error: out of local space"); 2484 } 2485 2486 #if !FICL_WANT_FLOAT 2487 FICL_VM_ASSERT(vm, !isFloat); 2488 /* get rid of unused parameter warning */ 2489 isFloat = 0; 2490 #else /* FICL_WANT_FLOAT */ 2491 if (isFloat) { 2492 if (isDouble) { 2493 code = ficlPrimitiveDoF2LocalIm; 2494 instruction = ficlInstructionToF2LocalParen; 2495 } else { 2496 code = ficlPrimitiveDoFLocalIm; 2497 instruction = ficlInstructionToFLocalParen; 2498 } 2499 } else 2500 #endif /* FICL_WANT_FLOAT */ 2501 if (isDouble) { 2502 code = ficlPrimitiveDo2LocalIm; 2503 instruction = ficlInstructionTo2LocalParen; 2504 } else { 2505 code = ficlPrimitiveDoLocalIm; 2506 instruction = ficlInstructionToLocalParen; 2507 } 2508 2509 (void) ficlDictionaryAppendWord(locals, name, code, 2510 FICL_WORD_COMPILE_ONLY_IMMEDIATE); 2511 ficlDictionaryAppendUnsigned(locals, 2512 vm->callback.system->localsCount); 2513 2514 if (vm->callback.system->localsCount == 0) { 2515 /* 2516 * FICL_VM_STATE_COMPILE code to create a local 2517 * stack frame 2518 */ 2519 ficlDictionaryAppendUnsigned(dictionary, 2520 ficlInstructionLinkParen); 2521 2522 /* save location in dictionary for #locals */ 2523 vm->callback.system->localsFixup = dictionary->here; 2524 ficlDictionaryAppendUnsigned(dictionary, 2525 vm->callback.system->localsCount); 2526 } 2527 2528 ficlDictionaryAppendUnsigned(dictionary, instruction); 2529 ficlDictionaryAppendUnsigned(dictionary, 2530 vm->callback.system->localsCount); 2531 2532 vm->callback.system->localsCount += (isDouble) ? 2 : 1; 2533 } else if (vm->callback.system->localsCount > 0) { 2534 /* write localsCount to (link) param area in dictionary */ 2535 *(ficlInteger *)(vm->callback.system->localsFixup) = 2536 vm->callback.system->localsCount; 2537 } 2538 } 2539 2540 static void 2541 ficlPrimitiveLocalParen(ficlVm *vm) 2542 { 2543 ficlLocalParen(vm, 0, 0); 2544 } 2545 2546 static void 2547 ficlPrimitive2LocalParen(ficlVm *vm) 2548 { 2549 ficlLocalParen(vm, 1, 0); 2550 } 2551 #endif /* FICL_WANT_LOCALS */ 2552 2553 /* 2554 * t o V a l u e 2555 * CORE EXT 2556 * Interpretation: ( x "<spaces>name" -- ) 2557 * Skip leading spaces and parse name delimited by a space. Store x in 2558 * name. An ambiguous condition exists if name was not defined by VALUE. 2559 * NOTE: In Ficl, VALUE is an alias of CONSTANT 2560 */ 2561 static void 2562 ficlPrimitiveToValue(ficlVm *vm) 2563 { 2564 ficlString name = ficlVmGetWord(vm); 2565 ficlDictionary *dictionary = ficlVmGetDictionary(vm); 2566 ficlWord *word; 2567 ficlInstruction instruction = 0; 2568 ficlStack *stack; 2569 ficlInteger isDouble; 2570 #if FICL_WANT_LOCALS 2571 ficlInteger nLocal; 2572 ficlInteger appendLocalOffset; 2573 ficlInteger isFloat; 2574 #endif /* FICL_WANT_LOCALS */ 2575 2576 #if FICL_WANT_LOCALS 2577 if ((vm->callback.system->localsCount > 0) && 2578 (vm->state == FICL_VM_STATE_COMPILE)) { 2579 ficlDictionary *locals; 2580 2581 locals = ficlSystemGetLocals(vm->callback.system); 2582 word = ficlDictionaryLookup(locals, name); 2583 if (!word) 2584 goto TO_GLOBAL; 2585 2586 if (word->code == ficlPrimitiveDoLocalIm) { 2587 instruction = ficlInstructionToLocalParen; 2588 isDouble = isFloat = FICL_FALSE; 2589 } else if (word->code == ficlPrimitiveDo2LocalIm) { 2590 instruction = ficlInstructionTo2LocalParen; 2591 isDouble = FICL_TRUE; 2592 isFloat = FICL_FALSE; 2593 } 2594 #if FICL_WANT_FLOAT 2595 else if (word->code == ficlPrimitiveDoFLocalIm) { 2596 instruction = ficlInstructionToFLocalParen; 2597 isDouble = FICL_FALSE; 2598 isFloat = FICL_TRUE; 2599 } else if (word->code == ficlPrimitiveDoF2LocalIm) { 2600 instruction = ficlInstructionToF2LocalParen; 2601 isDouble = isFloat = FICL_TRUE; 2602 } 2603 #endif /* FICL_WANT_FLOAT */ 2604 else { 2605 ficlVmThrowError(vm, 2606 "to %.*s : local is of unknown type", 2607 FICL_STRING_GET_LENGTH(name), 2608 FICL_STRING_GET_POINTER(name)); 2609 } 2610 2611 nLocal = word->param[0].i; 2612 appendLocalOffset = FICL_TRUE; 2613 2614 #if FICL_WANT_FLOAT 2615 if (!isFloat) { 2616 #endif /* FICL_WANT_FLOAT */ 2617 if (nLocal == 0) { 2618 instruction = 2619 (isDouble) ? ficlInstructionTo2Local0 : 2620 ficlInstructionToLocal0; 2621 appendLocalOffset = FICL_FALSE; 2622 } else if ((nLocal == 1) && !isDouble) { 2623 instruction = ficlInstructionToLocal1; 2624 appendLocalOffset = FICL_FALSE; 2625 } 2626 #if FICL_WANT_FLOAT 2627 } 2628 #endif /* FICL_WANT_FLOAT */ 2629 2630 ficlDictionaryAppendUnsigned(dictionary, instruction); 2631 if (appendLocalOffset) 2632 ficlDictionaryAppendUnsigned(dictionary, nLocal); 2633 return; 2634 } 2635 #endif 2636 2637 #if FICL_WANT_LOCALS 2638 TO_GLOBAL: 2639 #endif /* FICL_WANT_LOCALS */ 2640 word = ficlDictionaryLookup(dictionary, name); 2641 if (!word) 2642 ficlVmThrowError(vm, "%.*s not found", 2643 FICL_STRING_GET_LENGTH(name), 2644 FICL_STRING_GET_POINTER(name)); 2645 2646 switch ((ficlInstruction)word->code) { 2647 case ficlInstructionConstantParen: 2648 instruction = ficlInstructionStore; 2649 stack = vm->dataStack; 2650 isDouble = FICL_FALSE; 2651 break; 2652 case ficlInstruction2ConstantParen: 2653 instruction = ficlInstruction2Store; 2654 stack = vm->dataStack; 2655 isDouble = FICL_TRUE; 2656 break; 2657 #if FICL_WANT_FLOAT 2658 case ficlInstructionFConstantParen: 2659 instruction = ficlInstructionFStore; 2660 stack = vm->floatStack; 2661 isDouble = FICL_FALSE; 2662 break; 2663 case ficlInstructionF2ConstantParen: 2664 instruction = ficlInstructionF2Store; 2665 stack = vm->floatStack; 2666 isDouble = FICL_TRUE; 2667 break; 2668 #endif /* FICL_WANT_FLOAT */ 2669 default: 2670 ficlVmThrowError(vm, 2671 "to %.*s : value/constant is of unknown type", 2672 FICL_STRING_GET_LENGTH(name), 2673 FICL_STRING_GET_POINTER(name)); 2674 break; 2675 } 2676 2677 if (vm->state == FICL_VM_STATE_INTERPRET) { 2678 word->param[0] = ficlStackPop(stack); 2679 if (isDouble) 2680 word->param[1] = ficlStackPop(stack); 2681 } else { 2682 /* FICL_VM_STATE_COMPILE code to store to word's param */ 2683 ficlStackPushPointer(vm->dataStack, &word->param[0]); 2684 ficlPrimitiveLiteralIm(vm); 2685 ficlDictionaryAppendUnsigned(dictionary, instruction); 2686 } 2687 } 2688 2689 /* 2690 * f m S l a s h M o d 2691 * f-m-slash-mod CORE ( d1 n1 -- n2 n3 ) 2692 * Divide d1 by n1, giving the floored quotient n3 and the remainder n2. 2693 * Input and output stack arguments are signed. An ambiguous condition 2694 * exists if n1 is zero or if the quotient lies outside the range of a 2695 * single-ficlCell signed integer. 2696 */ 2697 static void 2698 ficlPrimitiveFMSlashMod(ficlVm *vm) 2699 { 2700 ficl2Integer d1; 2701 ficlInteger n1; 2702 ficl2IntegerQR qr; 2703 2704 FICL_STACK_CHECK(vm->dataStack, 3, 2); 2705 2706 n1 = ficlStackPopInteger(vm->dataStack); 2707 d1 = ficlStackPop2Integer(vm->dataStack); 2708 qr = ficl2IntegerDivideFloored(d1, n1); 2709 ficlStackPushInteger(vm->dataStack, qr.remainder); 2710 ficlStackPushInteger(vm->dataStack, 2711 FICL_2UNSIGNED_GET_LOW(qr.quotient)); 2712 } 2713 2714 /* 2715 * s m S l a s h R e m 2716 * s-m-slash-remainder CORE ( d1 n1 -- n2 n3 ) 2717 * Divide d1 by n1, giving the symmetric quotient n3 and the remainder n2. 2718 * Input and output stack arguments are signed. An ambiguous condition 2719 * exists if n1 is zero or if the quotient lies outside the range of a 2720 * single-ficlCell signed integer. 2721 */ 2722 static void 2723 ficlPrimitiveSMSlashRem(ficlVm *vm) 2724 { 2725 ficl2Integer d1; 2726 ficlInteger n1; 2727 ficl2IntegerQR qr; 2728 2729 FICL_STACK_CHECK(vm->dataStack, 3, 2); 2730 2731 n1 = ficlStackPopInteger(vm->dataStack); 2732 d1 = ficlStackPop2Integer(vm->dataStack); 2733 qr = ficl2IntegerDivideSymmetric(d1, n1); 2734 ficlStackPushInteger(vm->dataStack, qr.remainder); 2735 ficlStackPushInteger(vm->dataStack, 2736 FICL_2UNSIGNED_GET_LOW(qr.quotient)); 2737 } 2738 2739 static void 2740 ficlPrimitiveMod(ficlVm *vm) 2741 { 2742 ficl2Integer d1; 2743 ficlInteger n1; 2744 ficlInteger i; 2745 ficl2IntegerQR qr; 2746 FICL_STACK_CHECK(vm->dataStack, 2, 1); 2747 2748 n1 = ficlStackPopInteger(vm->dataStack); 2749 i = ficlStackPopInteger(vm->dataStack); 2750 FICL_INTEGER_TO_2INTEGER(i, d1); 2751 qr = ficl2IntegerDivideSymmetric(d1, n1); 2752 ficlStackPushInteger(vm->dataStack, qr.remainder); 2753 } 2754 2755 /* 2756 * u m S l a s h M o d 2757 * u-m-slash-mod CORE ( ud u1 -- u2 u3 ) 2758 * Divide ud by u1, giving the quotient u3 and the remainder u2. 2759 * All values and arithmetic are unsigned. An ambiguous condition 2760 * exists if u1 is zero or if the quotient lies outside the range of a 2761 * single-ficlCell unsigned integer. 2762 */ 2763 static void 2764 ficlPrimitiveUMSlashMod(ficlVm *vm) 2765 { 2766 ficl2Unsigned ud; 2767 ficlUnsigned u1; 2768 ficl2UnsignedQR uqr; 2769 2770 u1 = ficlStackPopUnsigned(vm->dataStack); 2771 ud = ficlStackPop2Unsigned(vm->dataStack); 2772 uqr = ficl2UnsignedDivide(ud, u1); 2773 ficlStackPushUnsigned(vm->dataStack, uqr.remainder); 2774 ficlStackPushUnsigned(vm->dataStack, 2775 FICL_2UNSIGNED_GET_LOW(uqr.quotient)); 2776 } 2777 2778 /* 2779 * m S t a r 2780 * m-star CORE ( n1 n2 -- d ) 2781 * d is the signed product of n1 times n2. 2782 */ 2783 static void 2784 ficlPrimitiveMStar(ficlVm *vm) 2785 { 2786 ficlInteger n2; 2787 ficlInteger n1; 2788 ficl2Integer d; 2789 FICL_STACK_CHECK(vm->dataStack, 2, 2); 2790 2791 n2 = ficlStackPopInteger(vm->dataStack); 2792 n1 = ficlStackPopInteger(vm->dataStack); 2793 2794 d = ficl2IntegerMultiply(n1, n2); 2795 ficlStackPush2Integer(vm->dataStack, d); 2796 } 2797 2798 static void 2799 ficlPrimitiveUMStar(ficlVm *vm) 2800 { 2801 ficlUnsigned u2; 2802 ficlUnsigned u1; 2803 ficl2Unsigned ud; 2804 FICL_STACK_CHECK(vm->dataStack, 2, 2); 2805 2806 u2 = ficlStackPopUnsigned(vm->dataStack); 2807 u1 = ficlStackPopUnsigned(vm->dataStack); 2808 2809 ud = ficl2UnsignedMultiply(u1, u2); 2810 ficlStackPush2Unsigned(vm->dataStack, ud); 2811 } 2812 2813 /* 2814 * 2 r o t 2815 * DOUBLE ( d1 d2 d3 -- d2 d3 d1 ) 2816 */ 2817 static void 2818 ficlPrimitive2Rot(ficlVm *vm) 2819 { 2820 ficl2Integer d1, d2, d3; 2821 FICL_STACK_CHECK(vm->dataStack, 6, 6); 2822 2823 d3 = ficlStackPop2Integer(vm->dataStack); 2824 d2 = ficlStackPop2Integer(vm->dataStack); 2825 d1 = ficlStackPop2Integer(vm->dataStack); 2826 ficlStackPush2Integer(vm->dataStack, d2); 2827 ficlStackPush2Integer(vm->dataStack, d3); 2828 ficlStackPush2Integer(vm->dataStack, d1); 2829 } 2830 2831 /* 2832 * p a d 2833 * CORE EXT ( -- c-addr ) 2834 * c-addr is the address of a transient region that can be used to hold 2835 * data for intermediate processing. 2836 */ 2837 static void 2838 ficlPrimitivePad(ficlVm *vm) 2839 { 2840 ficlStackPushPointer(vm->dataStack, vm->pad); 2841 } 2842 2843 /* 2844 * s o u r c e - i d 2845 * CORE EXT, FILE ( -- 0 | -1 | fileid ) 2846 * Identifies the input source as follows: 2847 * 2848 * SOURCE-ID Input source 2849 * --------- ------------ 2850 * fileid Text file fileid 2851 * -1 String (via EVALUATE) 2852 * 0 User input device 2853 */ 2854 static void 2855 ficlPrimitiveSourceID(ficlVm *vm) 2856 { 2857 ficlStackPushInteger(vm->dataStack, vm->sourceId.i); 2858 } 2859 2860 /* 2861 * r e f i l l 2862 * CORE EXT ( -- flag ) 2863 * Attempt to fill the input buffer from the input source, returning 2864 * a FICL_TRUE flag if successful. 2865 * When the input source is the user input device, attempt to receive input 2866 * into the terminal input buffer. If successful, make the result the input 2867 * buffer, set >IN to zero, and return FICL_TRUE. Receipt of a line containing 2868 * no characters is considered successful. If there is no input available from 2869 * the current input source, return FICL_FALSE. 2870 * When the input source is a string from EVALUATE, return FICL_FALSE and 2871 * perform no other action. 2872 */ 2873 static void 2874 ficlPrimitiveRefill(ficlVm *vm) 2875 { 2876 ficlInteger ret = (vm->sourceId.i == -1) ? FICL_FALSE : FICL_TRUE; 2877 if (ret && (vm->restart == 0)) 2878 ficlVmThrow(vm, FICL_VM_STATUS_RESTART); 2879 2880 ficlStackPushInteger(vm->dataStack, ret); 2881 } 2882 2883 /* 2884 * freebsd exception handling words 2885 * Catch, from ANS Forth standard. Installs a safety net, then EXECUTE 2886 * the word in ToS. If an exception happens, restore the state to what 2887 * it was before, and pushes the exception value on the stack. If not, 2888 * push zero. 2889 * 2890 * Notice that Catch implements an inner interpreter. This is ugly, 2891 * but given how Ficl works, it cannot be helped. The problem is that 2892 * colon definitions will be executed *after* the function returns, 2893 * while "code" definitions will be executed immediately. I considered 2894 * other solutions to this problem, but all of them shared the same 2895 * basic problem (with added disadvantages): if Ficl ever changes it's 2896 * inner thread modus operandi, one would have to fix this word. 2897 * 2898 * More comments can be found throughout catch's code. 2899 * 2900 * Daniel C. Sobral Jan 09/1999 2901 * sadler may 2000 -- revised to follow ficl.c:ficlExecXT. 2902 */ 2903 static void 2904 ficlPrimitiveCatch(ficlVm *vm) 2905 { 2906 int except; 2907 jmp_buf vmState; 2908 ficlVm vmCopy; 2909 ficlStack dataStackCopy; 2910 ficlStack returnStackCopy; 2911 ficlWord *word; 2912 2913 FICL_VM_ASSERT(vm, vm); 2914 FICL_VM_ASSERT(vm, vm->callback.system->exitInnerWord); 2915 2916 /* 2917 * Get xt. 2918 * We need this *before* we save the stack pointer, or 2919 * we'll have to pop one element out of the stack after 2920 * an exception. I prefer to get done with it up front. :-) 2921 */ 2922 2923 FICL_STACK_CHECK(vm->dataStack, 1, 0); 2924 2925 word = ficlStackPopPointer(vm->dataStack); 2926 2927 /* 2928 * Save vm's state -- a catch will not back out environmental 2929 * changes. 2930 * 2931 * We are *not* saving dictionary state, since it is 2932 * global instead of per vm, and we are not saving 2933 * stack contents, since we are not required to (and, 2934 * thus, it would be useless). We save vm, and vm 2935 * "stacks" (a structure containing general information 2936 * about it, including the current stack pointer). 2937 */ 2938 memcpy((void*)&vmCopy, (void*)vm, sizeof (ficlVm)); 2939 memcpy((void*)&dataStackCopy, (void*)vm->dataStack, sizeof (ficlStack)); 2940 memcpy((void*)&returnStackCopy, (void*)vm->returnStack, 2941 sizeof (ficlStack)); 2942 2943 /* 2944 * Give vm a jmp_buf 2945 */ 2946 vm->exceptionHandler = &vmState; 2947 2948 /* 2949 * Safety net 2950 */ 2951 except = setjmp(vmState); 2952 2953 switch (except) { 2954 /* 2955 * Setup condition - push poison pill so that the VM throws 2956 * VM_INNEREXIT if the XT terminates normally, then execute 2957 * the XT 2958 */ 2959 case 0: 2960 /* Open mouth, insert emetic */ 2961 ficlVmPushIP(vm, &(vm->callback.system->exitInnerWord)); 2962 ficlVmExecuteWord(vm, word); 2963 ficlVmInnerLoop(vm, 0); 2964 break; 2965 2966 /* 2967 * Normal exit from XT - lose the poison pill, 2968 * restore old setjmp vector and push a zero. 2969 */ 2970 case FICL_VM_STATUS_INNER_EXIT: 2971 ficlVmPopIP(vm); /* Gack - hurl poison pill */ 2972 /* Restore just the setjmp vector */ 2973 vm->exceptionHandler = vmCopy.exceptionHandler; 2974 /* Push 0 -- everything is ok */ 2975 ficlStackPushInteger(vm->dataStack, 0); 2976 break; 2977 2978 /* 2979 * Some other exception got thrown - restore pre-existing VM state 2980 * and push the exception code 2981 */ 2982 default: 2983 /* Restore vm's state */ 2984 memcpy((void*)vm, (void*)&vmCopy, sizeof (ficlVm)); 2985 memcpy((void*)vm->dataStack, (void*)&dataStackCopy, 2986 sizeof (ficlStack)); 2987 memcpy((void*)vm->returnStack, (void*)&returnStackCopy, 2988 sizeof (ficlStack)); 2989 2990 ficlStackPushInteger(vm->dataStack, except); /* Push error */ 2991 break; 2992 } 2993 } 2994 2995 /* 2996 * t h r o w 2997 * EXCEPTION 2998 * Throw -- From ANS Forth standard. 2999 * 3000 * Throw takes the ToS and, if that's different from zero, 3001 * returns to the last executed catch context. Further throws will 3002 * unstack previously executed "catches", in LIFO mode. 3003 * 3004 * Daniel C. Sobral Jan 09/1999 3005 */ 3006 static void 3007 ficlPrimitiveThrow(ficlVm *vm) 3008 { 3009 int except; 3010 3011 except = ficlStackPopInteger(vm->dataStack); 3012 3013 if (except) 3014 ficlVmThrow(vm, except); 3015 } 3016 3017 /* 3018 * a l l o c a t e 3019 * MEMORY 3020 */ 3021 static void 3022 ficlPrimitiveAllocate(ficlVm *vm) 3023 { 3024 size_t size; 3025 void *p; 3026 3027 size = ficlStackPopInteger(vm->dataStack); 3028 p = ficlMalloc(size); 3029 ficlStackPushPointer(vm->dataStack, p); 3030 if (p != NULL) 3031 ficlStackPushInteger(vm->dataStack, 0); 3032 else 3033 ficlStackPushInteger(vm->dataStack, 1); 3034 } 3035 3036 /* 3037 * f r e e 3038 * MEMORY 3039 */ 3040 static void 3041 ficlPrimitiveFree(ficlVm *vm) 3042 { 3043 void *p; 3044 3045 p = ficlStackPopPointer(vm->dataStack); 3046 ficlFree(p); 3047 ficlStackPushInteger(vm->dataStack, 0); 3048 } 3049 3050 /* 3051 * r e s i z e 3052 * MEMORY 3053 */ 3054 static void 3055 ficlPrimitiveResize(ficlVm *vm) 3056 { 3057 size_t size; 3058 void *new, *old; 3059 3060 size = ficlStackPopInteger(vm->dataStack); 3061 old = ficlStackPopPointer(vm->dataStack); 3062 new = ficlRealloc(old, size); 3063 3064 if (new) { 3065 ficlStackPushPointer(vm->dataStack, new); 3066 ficlStackPushInteger(vm->dataStack, 0); 3067 } else { 3068 ficlStackPushPointer(vm->dataStack, old); 3069 ficlStackPushInteger(vm->dataStack, 1); 3070 } 3071 } 3072 3073 /* 3074 * e x i t - i n n e r 3075 * Signals execXT that an inner loop has completed 3076 */ 3077 static void 3078 ficlPrimitiveExitInner(ficlVm *vm) 3079 { 3080 ficlVmThrow(vm, FICL_VM_STATUS_INNER_EXIT); 3081 } 3082 3083 #if 0 3084 static void 3085 ficlPrimitiveName(ficlVm *vm) 3086 { 3087 FICL_IGNORE(vm); 3088 } 3089 #endif 3090 3091 /* 3092 * f i c l C o m p i l e C o r e 3093 * Builds the primitive wordset and the environment-query namespace. 3094 */ 3095 void 3096 ficlSystemCompileCore(ficlSystem *system) 3097 { 3098 ficlWord *interpret; 3099 ficlDictionary *dictionary = ficlSystemGetDictionary(system); 3100 ficlDictionary *environment = ficlSystemGetEnvironment(system); 3101 3102 FICL_SYSTEM_ASSERT(system, dictionary); 3103 FICL_SYSTEM_ASSERT(system, environment); 3104 3105 #define FICL_TOKEN(token, description) 3106 #define FICL_INSTRUCTION_TOKEN(token, description, flags) \ 3107 (void) ficlDictionarySetInstruction(dictionary, description, token, \ 3108 flags); 3109 #include "ficltokens.h" 3110 #undef FICL_TOKEN 3111 #undef FICL_INSTRUCTION_TOKEN 3112 3113 /* 3114 * The Core word set 3115 * see softcore.c for definitions of: abs bl space spaces abort" 3116 */ 3117 (void) ficlDictionarySetPrimitive(dictionary, "#", 3118 ficlPrimitiveNumberSign, FICL_WORD_DEFAULT); 3119 (void) ficlDictionarySetPrimitive(dictionary, "#>", 3120 ficlPrimitiveNumberSignGreater, FICL_WORD_DEFAULT); 3121 (void) ficlDictionarySetPrimitive(dictionary, "#s", 3122 ficlPrimitiveNumberSignS, FICL_WORD_DEFAULT); 3123 (void) ficlDictionarySetPrimitive(dictionary, "\'", 3124 ficlPrimitiveTick, FICL_WORD_DEFAULT); 3125 (void) ficlDictionarySetPrimitive(dictionary, "(", 3126 ficlPrimitiveParenthesis, FICL_WORD_IMMEDIATE); 3127 (void) ficlDictionarySetPrimitive(dictionary, "+loop", 3128 ficlPrimitivePlusLoopCoIm, FICL_WORD_COMPILE_ONLY_IMMEDIATE); 3129 (void) ficlDictionarySetPrimitive(dictionary, ".", 3130 ficlPrimitiveDot, FICL_WORD_DEFAULT); 3131 (void) ficlDictionarySetPrimitive(dictionary, ".\"", 3132 ficlPrimitiveDotQuoteCoIm, FICL_WORD_COMPILE_ONLY_IMMEDIATE); 3133 (void) ficlDictionarySetPrimitive(dictionary, ":", 3134 ficlPrimitiveColon, FICL_WORD_DEFAULT); 3135 (void) ficlDictionarySetPrimitive(dictionary, ";", 3136 ficlPrimitiveSemicolonCoIm, FICL_WORD_COMPILE_ONLY_IMMEDIATE); 3137 (void) ficlDictionarySetPrimitive(dictionary, "<#", 3138 ficlPrimitiveLessNumberSign, FICL_WORD_DEFAULT); 3139 (void) ficlDictionarySetPrimitive(dictionary, ">body", 3140 ficlPrimitiveToBody, FICL_WORD_DEFAULT); 3141 (void) ficlDictionarySetPrimitive(dictionary, ">in", 3142 ficlPrimitiveToIn, FICL_WORD_DEFAULT); 3143 (void) ficlDictionarySetPrimitive(dictionary, ">number", 3144 ficlPrimitiveToNumber, FICL_WORD_DEFAULT); 3145 (void) ficlDictionarySetPrimitive(dictionary, "abort", 3146 ficlPrimitiveAbort, FICL_WORD_DEFAULT); 3147 (void) ficlDictionarySetPrimitive(dictionary, "accept", 3148 ficlPrimitiveAccept, FICL_WORD_DEFAULT); 3149 (void) ficlDictionarySetPrimitive(dictionary, "align", 3150 ficlPrimitiveAlign, FICL_WORD_DEFAULT); 3151 (void) ficlDictionarySetPrimitive(dictionary, "aligned", 3152 ficlPrimitiveAligned, FICL_WORD_DEFAULT); 3153 (void) ficlDictionarySetPrimitive(dictionary, "allot", 3154 ficlPrimitiveAllot, FICL_WORD_DEFAULT); 3155 (void) ficlDictionarySetPrimitive(dictionary, "base", 3156 ficlPrimitiveBase, FICL_WORD_DEFAULT); 3157 (void) ficlDictionarySetPrimitive(dictionary, "begin", 3158 ficlPrimitiveBeginCoIm, FICL_WORD_COMPILE_ONLY_IMMEDIATE); 3159 (void) ficlDictionarySetPrimitive(dictionary, "case", 3160 ficlPrimitiveCaseCoIm, FICL_WORD_COMPILE_ONLY_IMMEDIATE); 3161 (void) ficlDictionarySetPrimitive(dictionary, "char", 3162 ficlPrimitiveChar, FICL_WORD_DEFAULT); 3163 (void) ficlDictionarySetPrimitive(dictionary, "char+", 3164 ficlPrimitiveCharPlus, FICL_WORD_DEFAULT); 3165 (void) ficlDictionarySetPrimitive(dictionary, "chars", 3166 ficlPrimitiveChars, FICL_WORD_DEFAULT); 3167 (void) ficlDictionarySetPrimitive(dictionary, "constant", 3168 ficlPrimitiveConstant, FICL_WORD_DEFAULT); 3169 (void) ficlDictionarySetPrimitive(dictionary, "count", 3170 ficlPrimitiveCount, FICL_WORD_DEFAULT); 3171 (void) ficlDictionarySetPrimitive(dictionary, "cr", 3172 ficlPrimitiveCR, FICL_WORD_DEFAULT); 3173 (void) ficlDictionarySetPrimitive(dictionary, "create", 3174 ficlPrimitiveCreate, FICL_WORD_DEFAULT); 3175 (void) ficlDictionarySetPrimitive(dictionary, "decimal", 3176 ficlPrimitiveDecimal, FICL_WORD_DEFAULT); 3177 (void) ficlDictionarySetPrimitive(dictionary, "depth", 3178 ficlPrimitiveDepth, FICL_WORD_DEFAULT); 3179 (void) ficlDictionarySetPrimitive(dictionary, "do", 3180 ficlPrimitiveDoCoIm, FICL_WORD_COMPILE_ONLY_IMMEDIATE); 3181 (void) ficlDictionarySetPrimitive(dictionary, "does>", 3182 ficlPrimitiveDoesCoIm, FICL_WORD_COMPILE_ONLY_IMMEDIATE); 3183 (void) ficlDictionarySetPrimitive(dictionary, "else", 3184 ficlPrimitiveElseCoIm, FICL_WORD_COMPILE_ONLY_IMMEDIATE); 3185 (void) ficlDictionarySetPrimitive(dictionary, "emit", 3186 ficlPrimitiveEmit, FICL_WORD_DEFAULT); 3187 (void) ficlDictionarySetPrimitive(dictionary, "endcase", 3188 ficlPrimitiveEndcaseCoIm, FICL_WORD_COMPILE_ONLY_IMMEDIATE); 3189 (void) ficlDictionarySetPrimitive(dictionary, "endof", 3190 ficlPrimitiveEndofCoIm, FICL_WORD_COMPILE_ONLY_IMMEDIATE); 3191 (void) ficlDictionarySetPrimitive(dictionary, "environment?", 3192 ficlPrimitiveEnvironmentQ, FICL_WORD_DEFAULT); 3193 (void) ficlDictionarySetPrimitive(dictionary, "evaluate", 3194 ficlPrimitiveEvaluate, FICL_WORD_DEFAULT); 3195 (void) ficlDictionarySetPrimitive(dictionary, "execute", 3196 ficlPrimitiveExecute, FICL_WORD_DEFAULT); 3197 (void) ficlDictionarySetPrimitive(dictionary, "exit", 3198 ficlPrimitiveExitCoIm, FICL_WORD_COMPILE_ONLY_IMMEDIATE); 3199 (void) ficlDictionarySetPrimitive(dictionary, "fallthrough", 3200 ficlPrimitiveFallthroughCoIm, FICL_WORD_COMPILE_ONLY_IMMEDIATE); 3201 (void) ficlDictionarySetPrimitive(dictionary, "find", 3202 ficlPrimitiveCFind, FICL_WORD_DEFAULT); 3203 (void) ficlDictionarySetPrimitive(dictionary, "fm/mod", 3204 ficlPrimitiveFMSlashMod, FICL_WORD_DEFAULT); 3205 (void) ficlDictionarySetPrimitive(dictionary, "here", 3206 ficlPrimitiveHere, FICL_WORD_DEFAULT); 3207 (void) ficlDictionarySetPrimitive(dictionary, "hold", 3208 ficlPrimitiveHold, FICL_WORD_DEFAULT); 3209 (void) ficlDictionarySetPrimitive(dictionary, "if", 3210 ficlPrimitiveIfCoIm, FICL_WORD_COMPILE_ONLY_IMMEDIATE); 3211 (void) ficlDictionarySetPrimitive(dictionary, "immediate", 3212 ficlPrimitiveImmediate, FICL_WORD_DEFAULT); 3213 (void) ficlDictionarySetPrimitive(dictionary, "literal", 3214 ficlPrimitiveLiteralIm, FICL_WORD_IMMEDIATE); 3215 (void) ficlDictionarySetPrimitive(dictionary, "loop", 3216 ficlPrimitiveLoopCoIm, FICL_WORD_COMPILE_ONLY_IMMEDIATE); 3217 (void) ficlDictionarySetPrimitive(dictionary, "m*", 3218 ficlPrimitiveMStar, FICL_WORD_DEFAULT); 3219 (void) ficlDictionarySetPrimitive(dictionary, "mod", 3220 ficlPrimitiveMod, FICL_WORD_DEFAULT); 3221 (void) ficlDictionarySetPrimitive(dictionary, "of", 3222 ficlPrimitiveOfCoIm, FICL_WORD_COMPILE_ONLY_IMMEDIATE); 3223 (void) ficlDictionarySetPrimitive(dictionary, "postpone", 3224 ficlPrimitivePostponeCoIm, FICL_WORD_COMPILE_ONLY_IMMEDIATE); 3225 (void) ficlDictionarySetPrimitive(dictionary, "quit", 3226 ficlPrimitiveQuit, FICL_WORD_DEFAULT); 3227 (void) ficlDictionarySetPrimitive(dictionary, "recurse", 3228 ficlPrimitiveRecurseCoIm, FICL_WORD_COMPILE_ONLY_IMMEDIATE); 3229 (void) ficlDictionarySetPrimitive(dictionary, "repeat", 3230 ficlPrimitiveRepeatCoIm, FICL_WORD_COMPILE_ONLY_IMMEDIATE); 3231 (void) ficlDictionarySetPrimitive(dictionary, "s\"", 3232 ficlPrimitiveStringQuoteIm, FICL_WORD_IMMEDIATE); 3233 (void) ficlDictionarySetPrimitive(dictionary, "sign", 3234 ficlPrimitiveSign, FICL_WORD_DEFAULT); 3235 (void) ficlDictionarySetPrimitive(dictionary, "sm/rem", 3236 ficlPrimitiveSMSlashRem, FICL_WORD_DEFAULT); 3237 (void) ficlDictionarySetPrimitive(dictionary, "source", 3238 ficlPrimitiveSource, FICL_WORD_DEFAULT); 3239 (void) ficlDictionarySetPrimitive(dictionary, "state", 3240 ficlPrimitiveState, FICL_WORD_DEFAULT); 3241 (void) ficlDictionarySetPrimitive(dictionary, "then", 3242 ficlPrimitiveEndifCoIm, FICL_WORD_COMPILE_ONLY_IMMEDIATE); 3243 (void) ficlDictionarySetPrimitive(dictionary, "type", 3244 ficlPrimitiveType, FICL_WORD_DEFAULT); 3245 (void) ficlDictionarySetPrimitive(dictionary, "u.", 3246 ficlPrimitiveUDot, FICL_WORD_DEFAULT); 3247 (void) ficlDictionarySetPrimitive(dictionary, "um*", 3248 ficlPrimitiveUMStar, FICL_WORD_DEFAULT); 3249 (void) ficlDictionarySetPrimitive(dictionary, "um/mod", 3250 ficlPrimitiveUMSlashMod, FICL_WORD_DEFAULT); 3251 (void) ficlDictionarySetPrimitive(dictionary, "until", 3252 ficlPrimitiveUntilCoIm, FICL_WORD_COMPILE_ONLY_IMMEDIATE); 3253 (void) ficlDictionarySetPrimitive(dictionary, "variable", 3254 ficlPrimitiveVariable, FICL_WORD_DEFAULT); 3255 (void) ficlDictionarySetPrimitive(dictionary, "while", 3256 ficlPrimitiveWhileCoIm, FICL_WORD_COMPILE_ONLY_IMMEDIATE); 3257 (void) ficlDictionarySetPrimitive(dictionary, "word", 3258 ficlPrimitiveWord, FICL_WORD_DEFAULT); 3259 (void) ficlDictionarySetPrimitive(dictionary, "[", 3260 ficlPrimitiveLeftBracketCoIm, FICL_WORD_COMPILE_ONLY_IMMEDIATE); 3261 (void) ficlDictionarySetPrimitive(dictionary, "[\']", 3262 ficlPrimitiveBracketTickCoIm, FICL_WORD_COMPILE_ONLY_IMMEDIATE); 3263 (void) ficlDictionarySetPrimitive(dictionary, "[char]", 3264 ficlPrimitiveCharCoIm, FICL_WORD_COMPILE_ONLY_IMMEDIATE); 3265 (void) ficlDictionarySetPrimitive(dictionary, "]", 3266 ficlPrimitiveRightBracket, FICL_WORD_DEFAULT); 3267 /* 3268 * The Core Extensions word set... 3269 * see softcore.fr for other definitions 3270 */ 3271 /* "#tib" */ 3272 (void) ficlDictionarySetPrimitive(dictionary, ".(", 3273 ficlPrimitiveDotParen, FICL_WORD_IMMEDIATE); 3274 /* ".r" is in softcore */ 3275 (void) ficlDictionarySetPrimitive(dictionary, ":noname", 3276 ficlPrimitiveColonNoName, FICL_WORD_DEFAULT); 3277 (void) ficlDictionarySetPrimitive(dictionary, "?do", 3278 ficlPrimitiveQDoCoIm, FICL_WORD_COMPILE_ONLY_IMMEDIATE); 3279 (void) ficlDictionarySetPrimitive(dictionary, "again", 3280 ficlPrimitiveAgainCoIm, FICL_WORD_COMPILE_ONLY_IMMEDIATE); 3281 (void) ficlDictionarySetPrimitive(dictionary, "c\"", 3282 ficlPrimitiveCountedStringQuoteIm, FICL_WORD_IMMEDIATE); 3283 (void) ficlDictionarySetPrimitive(dictionary, "hex", 3284 ficlPrimitiveHex, FICL_WORD_DEFAULT); 3285 (void) ficlDictionarySetPrimitive(dictionary, "pad", 3286 ficlPrimitivePad, FICL_WORD_DEFAULT); 3287 (void) ficlDictionarySetPrimitive(dictionary, "parse", 3288 ficlPrimitiveParse, FICL_WORD_DEFAULT); 3289 3290 /* 3291 * query restore-input save-input tib u.r u> unused 3292 * [FICL_VM_STATE_COMPILE] 3293 */ 3294 (void) ficlDictionarySetPrimitive(dictionary, "refill", 3295 ficlPrimitiveRefill, FICL_WORD_DEFAULT); 3296 (void) ficlDictionarySetPrimitive(dictionary, "source-id", 3297 ficlPrimitiveSourceID, FICL_WORD_DEFAULT); 3298 (void) ficlDictionarySetPrimitive(dictionary, "to", 3299 ficlPrimitiveToValue, FICL_WORD_IMMEDIATE); 3300 (void) ficlDictionarySetPrimitive(dictionary, "value", 3301 ficlPrimitiveConstant, FICL_WORD_DEFAULT); 3302 (void) ficlDictionarySetPrimitive(dictionary, "\\", 3303 ficlPrimitiveBackslash, FICL_WORD_IMMEDIATE); 3304 3305 /* 3306 * Environment query values for the Core word set 3307 */ 3308 (void) ficlDictionarySetConstant(environment, "/counted-string", 3309 FICL_COUNTED_STRING_MAX); 3310 (void) ficlDictionarySetConstant(environment, "/hold", FICL_PAD_SIZE); 3311 (void) ficlDictionarySetConstant(environment, "/pad", FICL_PAD_SIZE); 3312 (void) ficlDictionarySetConstant(environment, "address-unit-bits", 8); 3313 (void) ficlDictionarySetConstant(environment, "core", FICL_TRUE); 3314 (void) ficlDictionarySetConstant(environment, "core-ext", FICL_FALSE); 3315 (void) ficlDictionarySetConstant(environment, "floored", FICL_FALSE); 3316 (void) ficlDictionarySetConstant(environment, "max-char", UCHAR_MAX); 3317 (void) ficlDictionarySetConstant(environment, "max-n", LONG_MAX); 3318 (void) ficlDictionarySetConstant(environment, "max-u", ULONG_MAX); 3319 3320 { 3321 ficl2Integer id; 3322 ficlInteger low, high; 3323 3324 low = ULONG_MAX; 3325 high = LONG_MAX; 3326 FICL_2INTEGER_SET(high, low, id); 3327 (void) ficlDictionarySet2Constant(environment, "max-d", id); 3328 high = ULONG_MAX; 3329 FICL_2INTEGER_SET(high, low, id); 3330 (void) ficlDictionarySet2Constant(environment, "max-ud", id); 3331 } 3332 3333 (void) ficlDictionarySetConstant(environment, "return-stack-cells", 3334 FICL_DEFAULT_STACK_SIZE); 3335 (void) ficlDictionarySetConstant(environment, "stack-cells", 3336 FICL_DEFAULT_STACK_SIZE); 3337 3338 /* 3339 * The optional Double-Number word set (partial) 3340 */ 3341 (void) ficlDictionarySetPrimitive(dictionary, "2constant", 3342 ficlPrimitive2Constant, FICL_WORD_IMMEDIATE); 3343 (void) ficlDictionarySetPrimitive(dictionary, "2literal", 3344 ficlPrimitive2LiteralIm, FICL_WORD_IMMEDIATE); 3345 (void) ficlDictionarySetPrimitive(dictionary, "2variable", 3346 ficlPrimitive2Variable, FICL_WORD_IMMEDIATE); 3347 /* 3348 * D+ D- D. D.R D0< D0= D2* D2/ in softcore 3349 * D< D= D>S DABS DMAX DMIN DNEGATE in softcore 3350 * m-star-slash is TODO 3351 * M+ in softcore 3352 */ 3353 3354 /* 3355 * DOUBLE EXT 3356 */ 3357 (void) ficlDictionarySetPrimitive(dictionary, "2rot", 3358 ficlPrimitive2Rot, FICL_WORD_DEFAULT); 3359 (void) ficlDictionarySetPrimitive(dictionary, "2value", 3360 ficlPrimitive2Constant, FICL_WORD_IMMEDIATE); 3361 /* du< in softcore */ 3362 /* 3363 * The optional Exception and Exception Extensions word set 3364 */ 3365 (void) ficlDictionarySetPrimitive(dictionary, "catch", 3366 ficlPrimitiveCatch, FICL_WORD_DEFAULT); 3367 (void) ficlDictionarySetPrimitive(dictionary, "throw", 3368 ficlPrimitiveThrow, FICL_WORD_DEFAULT); 3369 3370 (void) ficlDictionarySetConstant(environment, "exception", FICL_TRUE); 3371 (void) ficlDictionarySetConstant(environment, "exception-ext", 3372 FICL_TRUE); 3373 3374 /* 3375 * The optional Locals and Locals Extensions word set 3376 * see softcore.c for implementation of locals| 3377 */ 3378 #if FICL_WANT_LOCALS 3379 (void) ficlDictionarySetPrimitive(dictionary, "doLocal", 3380 ficlPrimitiveDoLocalIm, FICL_WORD_COMPILE_ONLY_IMMEDIATE); 3381 (void) ficlDictionarySetPrimitive(dictionary, "(local)", 3382 ficlPrimitiveLocalParen, FICL_WORD_COMPILE_ONLY); 3383 (void) ficlDictionarySetPrimitive(dictionary, "(2local)", 3384 ficlPrimitive2LocalParen, FICL_WORD_COMPILE_ONLY); 3385 3386 (void) ficlDictionarySetConstant(environment, "locals", FICL_TRUE); 3387 (void) ficlDictionarySetConstant(environment, "locals-ext", FICL_TRUE); 3388 (void) ficlDictionarySetConstant(environment, "#locals", 3389 FICL_MAX_LOCALS); 3390 #endif 3391 3392 /* 3393 * The optional Memory-Allocation word set 3394 */ 3395 3396 (void) ficlDictionarySetPrimitive(dictionary, "allocate", 3397 ficlPrimitiveAllocate, FICL_WORD_DEFAULT); 3398 (void) ficlDictionarySetPrimitive(dictionary, "free", 3399 ficlPrimitiveFree, FICL_WORD_DEFAULT); 3400 (void) ficlDictionarySetPrimitive(dictionary, "resize", 3401 ficlPrimitiveResize, FICL_WORD_DEFAULT); 3402 3403 (void) ficlDictionarySetConstant(environment, "memory-alloc", 3404 FICL_TRUE); 3405 3406 /* 3407 * The optional Search-Order word set 3408 */ 3409 ficlSystemCompileSearch(system); 3410 3411 /* 3412 * The optional Programming-Tools and Programming-Tools 3413 * Extensions word set 3414 */ 3415 ficlSystemCompileTools(system); 3416 3417 /* 3418 * The optional File-Access and File-Access Extensions word set 3419 */ 3420 #if FICL_WANT_FILE 3421 ficlSystemCompileFile(system); 3422 #endif 3423 3424 /* 3425 * Ficl extras 3426 */ 3427 (void) ficlDictionarySetPrimitive(dictionary, ".ver", 3428 ficlPrimitiveVersion, FICL_WORD_DEFAULT); 3429 (void) ficlDictionarySetPrimitive(dictionary, ">name", 3430 ficlPrimitiveToName, FICL_WORD_DEFAULT); 3431 (void) ficlDictionarySetPrimitive(dictionary, "add-parse-step", 3432 ficlPrimitiveAddParseStep, FICL_WORD_DEFAULT); 3433 (void) ficlDictionarySetPrimitive(dictionary, "body>", 3434 ficlPrimitiveFromBody, FICL_WORD_DEFAULT); 3435 (void) ficlDictionarySetPrimitive(dictionary, "compile-only", 3436 ficlPrimitiveCompileOnly, FICL_WORD_DEFAULT); 3437 (void) ficlDictionarySetPrimitive(dictionary, "endif", 3438 ficlPrimitiveEndifCoIm, FICL_WORD_COMPILE_ONLY_IMMEDIATE); 3439 (void) ficlDictionarySetPrimitive(dictionary, "last-word", 3440 ficlPrimitiveLastWord, FICL_WORD_DEFAULT); 3441 (void) ficlDictionarySetPrimitive(dictionary, "hash", 3442 ficlPrimitiveHash, FICL_WORD_DEFAULT); 3443 (void) ficlDictionarySetPrimitive(dictionary, "objectify", 3444 ficlPrimitiveSetObjectFlag, FICL_WORD_DEFAULT); 3445 (void) ficlDictionarySetPrimitive(dictionary, "?object", 3446 ficlPrimitiveIsObject, FICL_WORD_DEFAULT); 3447 (void) ficlDictionarySetPrimitive(dictionary, "parse-word", 3448 ficlPrimitiveParseNoCopy, FICL_WORD_DEFAULT); 3449 (void) ficlDictionarySetPrimitive(dictionary, "sfind", 3450 ficlPrimitiveSFind, FICL_WORD_DEFAULT); 3451 (void) ficlDictionarySetPrimitive(dictionary, "sliteral", 3452 ficlPrimitiveSLiteralCoIm, FICL_WORD_COMPILE_ONLY_IMMEDIATE); 3453 (void) ficlDictionarySetPrimitive(dictionary, "sprintf", 3454 ficlPrimitiveSprintf, FICL_WORD_DEFAULT); 3455 (void) ficlDictionarySetPrimitive(dictionary, "strlen", 3456 ficlPrimitiveStrlen, FICL_WORD_DEFAULT); 3457 (void) ficlDictionarySetPrimitive(dictionary, "x.", 3458 ficlPrimitiveHexDot, FICL_WORD_DEFAULT); 3459 #if FICL_WANT_USER 3460 (void) ficlDictionarySetPrimitive(dictionary, "user", 3461 ficlPrimitiveUser, FICL_WORD_DEFAULT); 3462 #endif 3463 3464 /* 3465 * internal support words 3466 */ 3467 interpret = ficlDictionarySetPrimitive(dictionary, "interpret", 3468 ficlPrimitiveInterpret, FICL_WORD_DEFAULT); 3469 (void) ficlDictionarySetPrimitive(dictionary, "lookup", 3470 ficlPrimitiveLookup, FICL_WORD_DEFAULT); 3471 (void) ficlDictionarySetPrimitive(dictionary, "(parse-step)", 3472 ficlPrimitiveParseStepParen, FICL_WORD_DEFAULT); 3473 system->exitInnerWord = ficlDictionarySetPrimitive(dictionary, 3474 "exit-inner", ficlPrimitiveExitInner, FICL_WORD_DEFAULT); 3475 3476 /* 3477 * Set constants representing the internal instruction words 3478 * If you want all of 'em, turn that "#if 0" to "#if 1". 3479 * By default you only get the numbers (fi0, fiNeg1, etc). 3480 */ 3481 #define FICL_TOKEN(token, description) \ 3482 (void) ficlDictionarySetConstant(dictionary, #token, token); 3483 #if 0 3484 #define FICL_INSTRUCTION_TOKEN(token, description, flags) \ 3485 ficlDictionarySetConstant(dictionary, #token, token); 3486 #else 3487 #define FICL_INSTRUCTION_TOKEN(token, description, flags) 3488 #endif /* 0 */ 3489 #include "ficltokens.h" 3490 #undef FICL_TOKEN 3491 #undef FICL_INSTRUCTION_TOKEN 3492 3493 /* 3494 * Set up system's outer interpreter loop - maybe this should 3495 * be in initSystem? 3496 */ 3497 system->interpreterLoop[0] = interpret; 3498 system->interpreterLoop[1] = (ficlWord *)ficlInstructionBranchParen; 3499 system->interpreterLoop[2] = (ficlWord *)(void *)(-2); 3500 3501 FICL_SYSTEM_ASSERT(system, 3502 ficlDictionaryCellsAvailable(dictionary) > 0); 3503 } 3504