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 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 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 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 ficlLtoa((c).i, vm->pad, vm->base); 285 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 ficlUltoa(u, vm->pad, vm->base); 298 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 ficlUltoa(u, vm->pad, 16); 311 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 ficlUltoa(integer, scratch, base); 431 else 432 ficlLtoa(integer, scratch, base); 433 base = 10; 434 unsignedInteger = 0; /* false */ 435 source = scratch; 436 actualLength = strlen(scratch); 437 break; 438 } 439 case '%': 440 source = format; 441 actualLength = 1; 442 /* FALLTHROUGH */ 443 default: 444 continue; 445 } 446 } 447 448 if (append) { 449 if (!desiredLength) 450 desiredLength = actualLength; 451 if (desiredLength > bufferLength) { 452 append = 0; /* false */ 453 desiredLength = bufferLength; 454 } 455 while (desiredLength > actualLength) { 456 *buffer++ = (char)((leadingZeroes) ? '0' : ' '); 457 bufferLength--; 458 desiredLength--; 459 } 460 memcpy(buffer, source, actualLength); 461 buffer += actualLength; 462 bufferLength -= actualLength; 463 } 464 465 format++; 466 } 467 468 ficlStackPushPointer(vm->dataStack, bufferStart); 469 ficlStackPushInteger(vm->dataStack, buffer - bufferStart); 470 ficlStackPushInteger(vm->dataStack, FICL_BOOL(!append)); 471 } 472 473 /* 474 * d u p & f r i e n d s 475 */ 476 static void 477 ficlPrimitiveDepth(ficlVm *vm) 478 { 479 int i; 480 481 FICL_STACK_CHECK(vm->dataStack, 0, 1); 482 483 i = ficlStackDepth(vm->dataStack); 484 ficlStackPushInteger(vm->dataStack, i); 485 } 486 487 /* 488 * e m i t & f r i e n d s 489 */ 490 static void 491 ficlPrimitiveEmit(ficlVm *vm) 492 { 493 char buffer[2]; 494 int i; 495 496 FICL_STACK_CHECK(vm->dataStack, 1, 0); 497 498 i = ficlStackPopInteger(vm->dataStack); 499 buffer[0] = (char)i; 500 buffer[1] = '\0'; 501 ficlVmTextOut(vm, buffer); 502 } 503 504 static void 505 ficlPrimitiveCR(ficlVm *vm) 506 { 507 ficlVmTextOut(vm, "\n"); 508 } 509 510 static void 511 ficlPrimitiveBackslash(ficlVm *vm) 512 { 513 char *trace = ficlVmGetInBuf(vm); 514 char *stop = ficlVmGetInBufEnd(vm); 515 char c = *trace; 516 517 while ((trace != stop) && (c != '\r') && (c != '\n')) { 518 c = *++trace; 519 } 520 521 /* 522 * Cope with DOS or UNIX-style EOLs - 523 * Check for /r, /n, /r/n, or /n/r end-of-line sequences, 524 * and point trace to next char. If EOL is \0, we're done. 525 */ 526 if (trace != stop) { 527 trace++; 528 529 if ((trace != stop) && (c != *trace) && 530 ((*trace == '\r') || (*trace == '\n'))) 531 trace++; 532 } 533 534 ficlVmUpdateTib(vm, trace); 535 } 536 537 /* 538 * paren CORE 539 * Compilation: Perform the execution semantics given below. 540 * Execution: ( "ccc<paren>" -- ) 541 * Parse ccc delimited by ) (right parenthesis). ( is an immediate word. 542 * The number of characters in ccc may be zero to the number of characters 543 * in the parse area. 544 */ 545 static void 546 ficlPrimitiveParenthesis(ficlVm *vm) 547 { 548 ficlVmParseStringEx(vm, ')', 0); 549 } 550 551 /* 552 * F E T C H & S T O R E 553 */ 554 555 /* 556 * i f C o I m 557 * IMMEDIATE 558 * Compiles code for a conditional branch into the dictionary 559 * and pushes the branch patch address on the stack for later 560 * patching by ELSE or THEN/ENDIF. 561 */ 562 static void 563 ficlPrimitiveIfCoIm(ficlVm *vm) 564 { 565 ficlDictionary *dictionary = ficlVmGetDictionary(vm); 566 567 ficlDictionaryAppendUnsigned(dictionary, 568 ficlInstructionBranch0ParenWithCheck); 569 markBranch(dictionary, vm, origTag); 570 ficlDictionaryAppendUnsigned(dictionary, 1); 571 } 572 573 /* 574 * e l s e C o I m 575 * 576 * IMMEDIATE -- compiles an "else"... 577 * 1) FICL_VM_STATE_COMPILE a branch and a patch address; 578 * the address gets patched 579 * by "endif" to point past the "else" code. 580 * 2) Pop the the "if" patch address 581 * 3) Patch the "if" branch to point to the current FICL_VM_STATE_COMPILE 582 * address. 583 * 4) Push the "else" patch address. ("endif" patches this to jump past 584 * the "else" code. 585 */ 586 static void 587 ficlPrimitiveElseCoIm(ficlVm *vm) 588 { 589 ficlCell *patchAddr; 590 ficlInteger offset; 591 ficlDictionary *dictionary = ficlVmGetDictionary(vm); 592 593 /* (1) FICL_VM_STATE_COMPILE branch runtime */ 594 ficlDictionaryAppendUnsigned(dictionary, 595 ficlInstructionBranchParenWithCheck); 596 597 matchControlTag(vm, origTag); 598 /* (2) pop "if" patch addr */ 599 patchAddr = (ficlCell *)ficlStackPopPointer(vm->dataStack); 600 markBranch(dictionary, vm, origTag); /* (4) push "else" patch addr */ 601 602 /* (1) FICL_VM_STATE_COMPILE patch placeholder */ 603 ficlDictionaryAppendUnsigned(dictionary, 1); 604 offset = dictionary->here - patchAddr; 605 (*patchAddr).i = offset; /* (3) Patch "if" */ 606 } 607 608 /* 609 * e n d i f C o I m 610 */ 611 static void 612 ficlPrimitiveEndifCoIm(ficlVm *vm) 613 { 614 ficlDictionary *dictionary = ficlVmGetDictionary(vm); 615 resolveForwardBranch(dictionary, vm, origTag); 616 } 617 618 /* 619 * c a s e C o I m 620 * IMMEDIATE FICL_VM_STATE_COMPILE-ONLY 621 * 622 * 623 * At FICL_VM_STATE_COMPILE-time, a CASE-SYS (see DPANS94 6.2.0873) looks 624 * like this: 625 * i*addr i caseTag 626 * and an OF-SYS (see DPANS94 6.2.1950) looks like this: 627 * i*addr i caseTag addr ofTag 628 * The integer under caseTag is the count of fixup addresses that branch 629 * to ENDCASE. 630 */ 631 static void 632 ficlPrimitiveCaseCoIm(ficlVm *vm) 633 { 634 FICL_STACK_CHECK(vm->dataStack, 0, 2); 635 636 ficlStackPushUnsigned(vm->dataStack, 0); 637 markControlTag(vm, caseTag); 638 } 639 640 /* 641 * e n d c a s eC o I m 642 * IMMEDIATE FICL_VM_STATE_COMPILE-ONLY 643 */ 644 static void 645 ficlPrimitiveEndcaseCoIm(ficlVm *vm) 646 { 647 ficlUnsigned fixupCount; 648 ficlDictionary *dictionary; 649 ficlCell *patchAddr; 650 ficlInteger offset; 651 652 /* 653 * if the last OF ended with FALLTHROUGH, 654 * just add the FALLTHROUGH fixup to the 655 * ENDOF fixups 656 */ 657 if (ficlStackGetTop(vm->dataStack).p == fallthroughTag) { 658 matchControlTag(vm, fallthroughTag); 659 patchAddr = ficlStackPopPointer(vm->dataStack); 660 matchControlTag(vm, caseTag); 661 fixupCount = ficlStackPopUnsigned(vm->dataStack); 662 ficlStackPushPointer(vm->dataStack, patchAddr); 663 ficlStackPushUnsigned(vm->dataStack, fixupCount + 1); 664 markControlTag(vm, caseTag); 665 } 666 667 matchControlTag(vm, caseTag); 668 669 FICL_STACK_CHECK(vm->dataStack, 1, 0); 670 671 fixupCount = ficlStackPopUnsigned(vm->dataStack); 672 FICL_STACK_CHECK(vm->dataStack, fixupCount, 0); 673 674 dictionary = ficlVmGetDictionary(vm); 675 676 ficlDictionaryAppendUnsigned(dictionary, ficlInstructionDrop); 677 678 while (fixupCount--) { 679 patchAddr = (ficlCell *)ficlStackPopPointer(vm->dataStack); 680 offset = dictionary->here - patchAddr; 681 (*patchAddr).i = offset; 682 } 683 } 684 685 /* 686 * o f C o I m 687 * IMMEDIATE FICL_VM_STATE_COMPILE-ONLY 688 */ 689 static void 690 ficlPrimitiveOfCoIm(ficlVm *vm) 691 { 692 ficlDictionary *dictionary = ficlVmGetDictionary(vm); 693 ficlCell *fallthroughFixup = NULL; 694 695 FICL_STACK_CHECK(vm->dataStack, 1, 3); 696 697 if (ficlStackGetTop(vm->dataStack).p == fallthroughTag) { 698 matchControlTag(vm, fallthroughTag); 699 fallthroughFixup = ficlStackPopPointer(vm->dataStack); 700 } 701 702 matchControlTag(vm, caseTag); 703 704 markControlTag(vm, caseTag); 705 706 ficlDictionaryAppendUnsigned(dictionary, ficlInstructionOfParen); 707 markBranch(dictionary, vm, ofTag); 708 ficlDictionaryAppendUnsigned(dictionary, 2); 709 710 if (fallthroughFixup != NULL) { 711 ficlInteger offset = dictionary->here - fallthroughFixup; 712 (*fallthroughFixup).i = offset; 713 } 714 } 715 716 /* 717 * e n d o f C o I m 718 * IMMEDIATE FICL_VM_STATE_COMPILE-ONLY 719 */ 720 static void 721 ficlPrimitiveEndofCoIm(ficlVm *vm) 722 { 723 ficlCell *patchAddr; 724 ficlUnsigned fixupCount; 725 ficlInteger offset; 726 ficlDictionary *dictionary = ficlVmGetDictionary(vm); 727 728 FICL_STACK_CHECK(vm->dataStack, 4, 3); 729 730 /* ensure we're in an OF, */ 731 matchControlTag(vm, ofTag); 732 733 /* grab the address of the branch location after the OF */ 734 patchAddr = (ficlCell *)ficlStackPopPointer(vm->dataStack); 735 /* ensure we're also in a "case" */ 736 matchControlTag(vm, caseTag); 737 /* grab the current number of ENDOF fixups */ 738 fixupCount = ficlStackPopUnsigned(vm->dataStack); 739 740 /* FICL_VM_STATE_COMPILE branch runtime */ 741 ficlDictionaryAppendUnsigned(dictionary, 742 ficlInstructionBranchParenWithCheck); 743 744 /* 745 * push a new ENDOF fixup, the updated count of ENDOF fixups, 746 * and the caseTag 747 */ 748 ficlStackPushPointer(vm->dataStack, dictionary->here); 749 ficlStackPushUnsigned(vm->dataStack, fixupCount + 1); 750 markControlTag(vm, caseTag); 751 752 /* reserve space for the ENDOF fixup */ 753 ficlDictionaryAppendUnsigned(dictionary, 2); 754 755 /* and patch the original OF */ 756 offset = dictionary->here - patchAddr; 757 (*patchAddr).i = offset; 758 } 759 760 /* 761 * f a l l t h r o u g h C o I m 762 * IMMEDIATE FICL_VM_STATE_COMPILE-ONLY 763 */ 764 static void 765 ficlPrimitiveFallthroughCoIm(ficlVm *vm) 766 { 767 ficlCell *patchAddr; 768 ficlInteger offset; 769 ficlDictionary *dictionary = ficlVmGetDictionary(vm); 770 771 FICL_STACK_CHECK(vm->dataStack, 4, 3); 772 773 /* ensure we're in an OF, */ 774 matchControlTag(vm, ofTag); 775 /* grab the address of the branch location after the OF */ 776 patchAddr = (ficlCell *)ficlStackPopPointer(vm->dataStack); 777 /* ensure we're also in a "case" */ 778 matchControlTag(vm, caseTag); 779 780 /* okay, here we go. put the case tag back. */ 781 markControlTag(vm, caseTag); 782 783 /* FICL_VM_STATE_COMPILE branch runtime */ 784 ficlDictionaryAppendUnsigned(dictionary, 785 ficlInstructionBranchParenWithCheck); 786 787 /* push a new FALLTHROUGH fixup and the fallthroughTag */ 788 ficlStackPushPointer(vm->dataStack, dictionary->here); 789 markControlTag(vm, fallthroughTag); 790 791 /* reserve space for the FALLTHROUGH fixup */ 792 ficlDictionaryAppendUnsigned(dictionary, 2); 793 794 /* and patch the original OF */ 795 offset = dictionary->here - patchAddr; 796 (*patchAddr).i = offset; 797 } 798 799 /* 800 * h a s h 801 * hash ( c-addr u -- code) 802 * calculates hashcode of specified string and leaves it on the stack 803 */ 804 static void 805 ficlPrimitiveHash(ficlVm *vm) 806 { 807 ficlString s; 808 809 FICL_STRING_SET_LENGTH(s, ficlStackPopUnsigned(vm->dataStack)); 810 FICL_STRING_SET_POINTER(s, ficlStackPopPointer(vm->dataStack)); 811 ficlStackPushUnsigned(vm->dataStack, ficlHashCode(s)); 812 } 813 814 /* 815 * i n t e r p r e t 816 * This is the "user interface" of a Forth. It does the following: 817 * while there are words in the VM's Text Input Buffer 818 * Copy next word into the pad (ficlVmGetWord) 819 * Attempt to find the word in the dictionary (ficlDictionaryLookup) 820 * If successful, execute the word. 821 * Otherwise, attempt to convert the word to a number (isNumber) 822 * If successful, push the number onto the parameter stack. 823 * Otherwise, print an error message and exit loop... 824 * End Loop 825 * 826 * From the standard, section 3.4 827 * Text interpretation (see 6.1.1360 EVALUATE and 6.1.2050 QUIT) shall 828 * repeat the following steps until either the parse area is empty or an 829 * ambiguous condition exists: 830 * a) Skip leading spaces and parse a name (see 3.4.1); 831 */ 832 static void 833 ficlPrimitiveInterpret(ficlVm *vm) 834 { 835 ficlString s; 836 int i; 837 ficlSystem *system; 838 839 FICL_VM_ASSERT(vm, vm); 840 841 system = vm->callback.system; 842 s = ficlVmGetWord0(vm); 843 844 /* 845 * Get next word...if out of text, we're done. 846 */ 847 if (s.length == 0) { 848 ficlVmThrow(vm, FICL_VM_STATUS_OUT_OF_TEXT); 849 } 850 851 /* 852 * Run the parse chain against the incoming token until somebody 853 * eats it. Otherwise emit an error message and give up. 854 */ 855 for (i = 0; i < FICL_MAX_PARSE_STEPS; i++) { 856 ficlWord *word = system->parseList[i]; 857 858 if (word == NULL) 859 break; 860 861 if (word->code == ficlPrimitiveParseStepParen) { 862 ficlParseStep pStep; 863 pStep = (ficlParseStep)(word->param->fn); 864 if ((*pStep)(vm, s)) 865 return; 866 } else { 867 ficlStackPushPointer(vm->dataStack, 868 FICL_STRING_GET_POINTER(s)); 869 ficlStackPushUnsigned(vm->dataStack, 870 FICL_STRING_GET_LENGTH(s)); 871 ficlVmExecuteXT(vm, word); 872 if (ficlStackPopInteger(vm->dataStack)) 873 return; 874 } 875 } 876 877 ficlVmThrowError(vm, "%.*s not found", FICL_STRING_GET_LENGTH(s), 878 FICL_STRING_GET_POINTER(s)); 879 /* back to inner interpreter */ 880 } 881 882 /* 883 * Surrogate precompiled parse step for ficlParseWord 884 * (this step is hard coded in FICL_VM_STATE_INTERPRET) 885 */ 886 static void 887 ficlPrimitiveLookup(ficlVm *vm) 888 { 889 ficlString name; 890 FICL_STRING_SET_LENGTH(name, ficlStackPopUnsigned(vm->dataStack)); 891 FICL_STRING_SET_POINTER(name, ficlStackPopPointer(vm->dataStack)); 892 ficlStackPushInteger(vm->dataStack, ficlVmParseWord(vm, name)); 893 } 894 895 /* 896 * p a r e n P a r s e S t e p 897 * (parse-step) ( c-addr u -- flag ) 898 * runtime for a precompiled parse step - pop a counted string off the 899 * stack, run the parse step against it, and push the result flag (FICL_TRUE 900 * if success, FICL_FALSE otherwise). 901 */ 902 void 903 ficlPrimitiveParseStepParen(ficlVm *vm) 904 { 905 ficlString s; 906 ficlWord *word = vm->runningWord; 907 ficlParseStep pStep = (ficlParseStep)(word->param->fn); 908 909 FICL_STRING_SET_LENGTH(s, ficlStackPopInteger(vm->dataStack)); 910 FICL_STRING_SET_POINTER(s, ficlStackPopPointer(vm->dataStack)); 911 912 ficlStackPushInteger(vm->dataStack, (*pStep)(vm, s)); 913 } 914 915 static void 916 ficlPrimitiveAddParseStep(ficlVm *vm) 917 { 918 ficlWord *pStep; 919 ficlDictionary *dictionary = ficlVmGetDictionary(vm); 920 921 FICL_STACK_CHECK(vm->dataStack, 1, 0); 922 923 pStep = (ficlWord *)(ficlStackPop(vm->dataStack).p); 924 if ((pStep != NULL) && ficlDictionaryIsAWord(dictionary, pStep)) 925 ficlSystemAddParseStep(vm->callback.system, pStep); 926 } 927 928 /* 929 * l i t e r a l I m 930 * 931 * IMMEDIATE code for "literal". This function gets a value from the stack 932 * and compiles it into the dictionary preceded by the code for "(literal)". 933 * IMMEDIATE 934 */ 935 void 936 ficlPrimitiveLiteralIm(ficlVm *vm) 937 { 938 ficlDictionary *dictionary = ficlVmGetDictionary(vm); 939 ficlInteger value; 940 941 value = ficlStackPopInteger(vm->dataStack); 942 943 switch (value) { 944 case 1: 945 case 2: 946 case 3: 947 case 4: 948 case 5: 949 case 6: 950 case 7: 951 case 8: 952 case 9: 953 case 10: 954 case 11: 955 case 12: 956 case 13: 957 case 14: 958 case 15: 959 case 16: 960 ficlDictionaryAppendUnsigned(dictionary, value); 961 break; 962 963 case 0: 964 case -1: 965 case -2: 966 case -3: 967 case -4: 968 case -5: 969 case -6: 970 case -7: 971 case -8: 972 case -9: 973 case -10: 974 case -11: 975 case -12: 976 case -13: 977 case -14: 978 case -15: 979 case -16: 980 ficlDictionaryAppendUnsigned(dictionary, 981 ficlInstruction0 - value); 982 break; 983 984 default: 985 ficlDictionaryAppendUnsigned(dictionary, 986 ficlInstructionLiteralParen); 987 ficlDictionaryAppendUnsigned(dictionary, value); 988 break; 989 } 990 } 991 992 static void 993 ficlPrimitive2LiteralIm(ficlVm *vm) 994 { 995 ficlDictionary *dictionary = ficlVmGetDictionary(vm); 996 997 ficlDictionaryAppendUnsigned(dictionary, ficlInstruction2LiteralParen); 998 ficlDictionaryAppendCell(dictionary, ficlStackPop(vm->dataStack)); 999 ficlDictionaryAppendCell(dictionary, ficlStackPop(vm->dataStack)); 1000 } 1001 1002 /* 1003 * D o / L o o p 1004 * do -- IMMEDIATE FICL_VM_STATE_COMPILE ONLY 1005 * Compiles code to initialize a loop: FICL_VM_STATE_COMPILE (do), 1006 * allot space to hold the "leave" address, push a branch 1007 * target address for the loop. 1008 * (do) -- runtime for "do" 1009 * pops index and limit from the p stack and moves them 1010 * to the r stack, then skips to the loop body. 1011 * loop -- IMMEDIATE FICL_VM_STATE_COMPILE ONLY 1012 * +loop 1013 * Compiles code for the test part of a loop: 1014 * FICL_VM_STATE_COMPILE (loop), resolve forward branch from "do", and 1015 * copy "here" address to the "leave" address allotted by "do" 1016 * i,j,k -- FICL_VM_STATE_COMPILE ONLY 1017 * Runtime: Push loop indices on param stack (i is innermost loop...) 1018 * Note: each loop has three values on the return stack: 1019 * ( R: leave limit index ) 1020 * "leave" is the absolute address of the next ficlCell after the loop 1021 * limit and index are the loop control variables. 1022 * leave -- FICL_VM_STATE_COMPILE ONLY 1023 * Runtime: pop the loop control variables, then pop the 1024 * "leave" address and jump (absolute) there. 1025 */ 1026 static void 1027 ficlPrimitiveDoCoIm(ficlVm *vm) 1028 { 1029 ficlDictionary *dictionary = ficlVmGetDictionary(vm); 1030 1031 ficlDictionaryAppendUnsigned(dictionary, ficlInstructionDoParen); 1032 /* 1033 * Allot space for a pointer to the end 1034 * of the loop - "leave" uses this... 1035 */ 1036 markBranch(dictionary, vm, leaveTag); 1037 ficlDictionaryAppendUnsigned(dictionary, 0); 1038 /* 1039 * Mark location of head of loop... 1040 */ 1041 markBranch(dictionary, vm, doTag); 1042 } 1043 1044 static void 1045 ficlPrimitiveQDoCoIm(ficlVm *vm) 1046 { 1047 ficlDictionary *dictionary = ficlVmGetDictionary(vm); 1048 1049 ficlDictionaryAppendUnsigned(dictionary, ficlInstructionQDoParen); 1050 /* 1051 * Allot space for a pointer to the end 1052 * of the loop - "leave" uses this... 1053 */ 1054 markBranch(dictionary, vm, leaveTag); 1055 ficlDictionaryAppendUnsigned(dictionary, 0); 1056 /* 1057 * Mark location of head of loop... 1058 */ 1059 markBranch(dictionary, vm, doTag); 1060 } 1061 1062 1063 static void 1064 ficlPrimitiveLoopCoIm(ficlVm *vm) 1065 { 1066 ficlDictionary *dictionary = ficlVmGetDictionary(vm); 1067 1068 ficlDictionaryAppendUnsigned(dictionary, ficlInstructionLoopParen); 1069 resolveBackBranch(dictionary, vm, doTag); 1070 resolveAbsBranch(dictionary, vm, leaveTag); 1071 } 1072 1073 static void 1074 ficlPrimitivePlusLoopCoIm(ficlVm *vm) 1075 { 1076 ficlDictionary *dictionary = ficlVmGetDictionary(vm); 1077 1078 ficlDictionaryAppendUnsigned(dictionary, ficlInstructionPlusLoopParen); 1079 resolveBackBranch(dictionary, vm, doTag); 1080 resolveAbsBranch(dictionary, vm, leaveTag); 1081 } 1082 1083 /* 1084 * v a r i a b l e 1085 */ 1086 static void 1087 ficlPrimitiveVariable(ficlVm *vm) 1088 { 1089 ficlDictionary *dictionary = ficlVmGetDictionary(vm); 1090 ficlString name = ficlVmGetWord(vm); 1091 1092 ficlDictionaryAppendWord(dictionary, name, 1093 (ficlPrimitive)ficlInstructionVariableParen, FICL_WORD_DEFAULT); 1094 ficlVmDictionaryAllotCells(vm, dictionary, 1); 1095 } 1096 1097 static void 1098 ficlPrimitive2Variable(ficlVm *vm) 1099 { 1100 ficlDictionary *dictionary = ficlVmGetDictionary(vm); 1101 ficlString name = ficlVmGetWord(vm); 1102 1103 ficlDictionaryAppendWord(dictionary, name, 1104 (ficlPrimitive)ficlInstructionVariableParen, FICL_WORD_DEFAULT); 1105 ficlVmDictionaryAllotCells(vm, dictionary, 2); 1106 } 1107 1108 /* 1109 * b a s e & f r i e n d s 1110 */ 1111 static void 1112 ficlPrimitiveBase(ficlVm *vm) 1113 { 1114 ficlCell *pBase, c; 1115 1116 FICL_STACK_CHECK(vm->dataStack, 0, 1); 1117 1118 pBase = (ficlCell *)(&vm->base); 1119 c.p = pBase; 1120 ficlStackPush(vm->dataStack, c); 1121 } 1122 1123 static void 1124 ficlPrimitiveDecimal(ficlVm *vm) 1125 { 1126 vm->base = 10; 1127 } 1128 1129 1130 static void 1131 ficlPrimitiveHex(ficlVm *vm) 1132 { 1133 vm->base = 16; 1134 } 1135 1136 /* 1137 * a l l o t & f r i e n d s 1138 */ 1139 static void 1140 ficlPrimitiveAllot(ficlVm *vm) 1141 { 1142 ficlDictionary *dictionary; 1143 ficlInteger i; 1144 1145 FICL_STACK_CHECK(vm->dataStack, 1, 0); 1146 1147 dictionary = ficlVmGetDictionary(vm); 1148 i = ficlStackPopInteger(vm->dataStack); 1149 1150 FICL_VM_DICTIONARY_CHECK(vm, dictionary, i); 1151 1152 ficlVmDictionaryAllot(vm, dictionary, i); 1153 } 1154 1155 static void 1156 ficlPrimitiveHere(ficlVm *vm) 1157 { 1158 ficlDictionary *dictionary; 1159 1160 FICL_STACK_CHECK(vm->dataStack, 0, 1); 1161 1162 dictionary = ficlVmGetDictionary(vm); 1163 ficlStackPushPointer(vm->dataStack, dictionary->here); 1164 } 1165 1166 /* 1167 * t i c k 1168 * tick CORE ( "<spaces>name" -- xt ) 1169 * Skip leading space delimiters. Parse name delimited by a space. Find 1170 * name and return xt, the execution token for name. An ambiguous condition 1171 * exists if name is not found. 1172 */ 1173 void 1174 ficlPrimitiveTick(ficlVm *vm) 1175 { 1176 ficlWord *word = NULL; 1177 ficlString name = ficlVmGetWord(vm); 1178 1179 FICL_STACK_CHECK(vm->dataStack, 0, 1); 1180 1181 word = ficlDictionaryLookup(ficlVmGetDictionary(vm), name); 1182 if (!word) 1183 ficlVmThrowError(vm, "%.*s not found", 1184 FICL_STRING_GET_LENGTH(name), 1185 FICL_STRING_GET_POINTER(name)); 1186 ficlStackPushPointer(vm->dataStack, word); 1187 } 1188 1189 static void 1190 ficlPrimitiveBracketTickCoIm(ficlVm *vm) 1191 { 1192 ficlPrimitiveTick(vm); 1193 ficlPrimitiveLiteralIm(vm); 1194 } 1195 1196 /* 1197 * p o s t p o n e 1198 * Lookup the next word in the input stream and FICL_VM_STATE_COMPILE code to 1199 * insert it into definitions created by the resulting word 1200 * (defers compilation, even of immediate words) 1201 */ 1202 static void 1203 ficlPrimitivePostponeCoIm(ficlVm *vm) 1204 { 1205 ficlDictionary *dictionary = ficlVmGetDictionary(vm); 1206 ficlWord *word; 1207 ficlWord *pComma = ficlSystemLookup(vm->callback.system, ","); 1208 ficlCell c; 1209 1210 FICL_VM_ASSERT(vm, pComma); 1211 1212 ficlPrimitiveTick(vm); 1213 word = ficlStackGetTop(vm->dataStack).p; 1214 if (ficlWordIsImmediate(word)) { 1215 ficlDictionaryAppendCell(dictionary, 1216 ficlStackPop(vm->dataStack)); 1217 } else { 1218 ficlPrimitiveLiteralIm(vm); 1219 c.p = pComma; 1220 ficlDictionaryAppendCell(dictionary, c); 1221 } 1222 } 1223 1224 /* 1225 * e x e c u t e 1226 * Pop an execution token (pointer to a word) off the stack and 1227 * run it 1228 */ 1229 static void 1230 ficlPrimitiveExecute(ficlVm *vm) 1231 { 1232 ficlWord *word; 1233 1234 FICL_STACK_CHECK(vm->dataStack, 1, 0); 1235 1236 word = ficlStackPopPointer(vm->dataStack); 1237 ficlVmExecuteWord(vm, word); 1238 } 1239 1240 /* 1241 * i m m e d i a t e 1242 * Make the most recently compiled word IMMEDIATE -- it executes even 1243 * in FICL_VM_STATE_COMPILE state (most often used for control compiling words 1244 * such as IF, THEN, etc) 1245 */ 1246 static void 1247 ficlPrimitiveImmediate(ficlVm *vm) 1248 { 1249 FICL_IGNORE(vm); 1250 ficlDictionarySetImmediate(ficlVmGetDictionary(vm)); 1251 } 1252 1253 static void 1254 ficlPrimitiveCompileOnly(ficlVm *vm) 1255 { 1256 FICL_IGNORE(vm); 1257 ficlDictionarySetFlags(ficlVmGetDictionary(vm), FICL_WORD_COMPILE_ONLY); 1258 } 1259 1260 static void 1261 ficlPrimitiveSetObjectFlag(ficlVm *vm) 1262 { 1263 FICL_IGNORE(vm); 1264 ficlDictionarySetFlags(ficlVmGetDictionary(vm), FICL_WORD_OBJECT); 1265 } 1266 1267 static void 1268 ficlPrimitiveIsObject(ficlVm *vm) 1269 { 1270 ficlInteger flag; 1271 ficlWord *word = (ficlWord *)ficlStackPopPointer(vm->dataStack); 1272 1273 flag = ((word != NULL) && (word->flags & FICL_WORD_OBJECT))? 1274 FICL_TRUE : FICL_FALSE; 1275 1276 ficlStackPushInteger(vm->dataStack, flag); 1277 } 1278 1279 static void 1280 ficlPrimitiveCountedStringQuoteIm(ficlVm *vm) 1281 { 1282 ficlDictionary *dictionary = ficlVmGetDictionary(vm); 1283 1284 if (vm->state == FICL_VM_STATE_INTERPRET) { 1285 ficlCountedString *counted = (ficlCountedString *) 1286 dictionary->here; 1287 1288 ficlVmGetString(vm, counted, '\"'); 1289 ficlStackPushPointer(vm->dataStack, counted); 1290 1291 /* 1292 * move HERE past string so it doesn't get overwritten. --lch 1293 */ 1294 ficlVmDictionaryAllot(vm, dictionary, 1295 counted->length + sizeof (ficlUnsigned8)); 1296 } else { /* FICL_VM_STATE_COMPILE state */ 1297 ficlDictionaryAppendUnsigned(dictionary, 1298 ficlInstructionCStringLiteralParen); 1299 dictionary->here = 1300 FICL_POINTER_TO_CELL(ficlVmGetString(vm, 1301 (ficlCountedString *)dictionary->here, '\"')); 1302 ficlDictionaryAlign(dictionary); 1303 } 1304 } 1305 1306 /* 1307 * d o t Q u o t e 1308 * IMMEDIATE word that compiles a string literal for later display 1309 * FICL_VM_STATE_COMPILE fiStringLiteralParen, then copy the bytes of the 1310 * string from the 1311 * TIB to the dictionary. Backpatch the count byte and align the dictionary. 1312 */ 1313 static void 1314 ficlPrimitiveDotQuoteCoIm(ficlVm *vm) 1315 { 1316 ficlDictionary *dictionary = ficlVmGetDictionary(vm); 1317 ficlWord *pType = ficlSystemLookup(vm->callback.system, "type"); 1318 ficlCell c; 1319 1320 FICL_VM_ASSERT(vm, pType); 1321 1322 ficlDictionaryAppendUnsigned(dictionary, 1323 ficlInstructionStringLiteralParen); 1324 dictionary->here = 1325 FICL_POINTER_TO_CELL(ficlVmGetString(vm, 1326 (ficlCountedString *)dictionary->here, '\"')); 1327 ficlDictionaryAlign(dictionary); 1328 c.p = pType; 1329 ficlDictionaryAppendCell(dictionary, c); 1330 } 1331 1332 static void 1333 ficlPrimitiveDotParen(ficlVm *vm) 1334 { 1335 char *from = ficlVmGetInBuf(vm); 1336 char *stop = ficlVmGetInBufEnd(vm); 1337 char *to = vm->pad; 1338 char c; 1339 1340 /* 1341 * Note: the standard does not want leading spaces skipped. 1342 */ 1343 for (c = *from; (from != stop) && (c != ')'); c = *++from) 1344 *to++ = c; 1345 1346 *to = '\0'; 1347 if ((from != stop) && (c == ')')) 1348 from++; 1349 1350 ficlVmTextOut(vm, vm->pad); 1351 ficlVmUpdateTib(vm, from); 1352 } 1353 1354 /* 1355 * s l i t e r a l 1356 * STRING 1357 * Interpretation: Interpretation semantics for this word are undefined. 1358 * Compilation: ( c-addr1 u -- ) 1359 * Append the run-time semantics given below to the current definition. 1360 * Run-time: ( -- c-addr2 u ) 1361 * Return c-addr2 u describing a string consisting of the characters 1362 * specified by c-addr1 u during compilation. A program shall not alter 1363 * the returned string. 1364 */ 1365 static void ficlPrimitiveSLiteralCoIm(ficlVm *vm) 1366 { 1367 ficlDictionary *dictionary; 1368 char *from; 1369 char *to; 1370 ficlUnsigned length; 1371 1372 FICL_STACK_CHECK(vm->dataStack, 2, 0); 1373 1374 dictionary = ficlVmGetDictionary(vm); 1375 length = ficlStackPopUnsigned(vm->dataStack); 1376 from = ficlStackPopPointer(vm->dataStack); 1377 1378 ficlDictionaryAppendUnsigned(dictionary, 1379 ficlInstructionStringLiteralParen); 1380 to = (char *)dictionary->here; 1381 *to++ = (char)length; 1382 1383 for (; length > 0; --length) { 1384 *to++ = *from++; 1385 } 1386 1387 *to++ = 0; 1388 dictionary->here = FICL_POINTER_TO_CELL(ficlAlignPointer(to)); 1389 } 1390 1391 /* 1392 * s t a t e 1393 * Return the address of the VM's state member (must be sized the 1394 * same as a ficlCell for this reason) 1395 */ 1396 static void ficlPrimitiveState(ficlVm *vm) 1397 { 1398 FICL_STACK_CHECK(vm->dataStack, 0, 1); 1399 ficlStackPushPointer(vm->dataStack, &vm->state); 1400 } 1401 1402 /* 1403 * c r e a t e . . . d o e s > 1404 * Make a new word in the dictionary with the run-time effect of 1405 * a variable (push my address), but with extra space allotted 1406 * for use by does> . 1407 */ 1408 static void 1409 ficlPrimitiveCreate(ficlVm *vm) 1410 { 1411 ficlDictionary *dictionary = ficlVmGetDictionary(vm); 1412 ficlString name = ficlVmGetWord(vm); 1413 1414 ficlDictionaryAppendWord(dictionary, name, 1415 (ficlPrimitive)ficlInstructionCreateParen, FICL_WORD_DEFAULT); 1416 ficlVmDictionaryAllotCells(vm, dictionary, 1); 1417 } 1418 1419 static void 1420 ficlPrimitiveDoesCoIm(ficlVm *vm) 1421 { 1422 ficlDictionary *dictionary = ficlVmGetDictionary(vm); 1423 #if FICL_WANT_LOCALS 1424 if (vm->callback.system->localsCount > 0) { 1425 ficlDictionary *locals = 1426 ficlSystemGetLocals(vm->callback.system); 1427 ficlDictionaryEmpty(locals, locals->forthWordlist->size); 1428 ficlDictionaryAppendUnsigned(dictionary, 1429 ficlInstructionUnlinkParen); 1430 } 1431 1432 vm->callback.system->localsCount = 0; 1433 #endif 1434 FICL_IGNORE(vm); 1435 1436 ficlDictionaryAppendUnsigned(dictionary, ficlInstructionDoesParen); 1437 } 1438 1439 /* 1440 * t o b o d y 1441 * to-body CORE ( xt -- a-addr ) 1442 * a-addr is the data-field address corresponding to xt. An ambiguous 1443 * condition exists if xt is not for a word defined via CREATE. 1444 */ 1445 static void 1446 ficlPrimitiveToBody(ficlVm *vm) 1447 { 1448 ficlWord *word; 1449 FICL_STACK_CHECK(vm->dataStack, 1, 1); 1450 1451 word = ficlStackPopPointer(vm->dataStack); 1452 ficlStackPushPointer(vm->dataStack, word->param + 1); 1453 } 1454 1455 /* 1456 * from-body Ficl ( a-addr -- xt ) 1457 * Reverse effect of >body 1458 */ 1459 static void 1460 ficlPrimitiveFromBody(ficlVm *vm) 1461 { 1462 char *ptr; 1463 FICL_STACK_CHECK(vm->dataStack, 1, 1); 1464 1465 ptr = (char *)ficlStackPopPointer(vm->dataStack) - sizeof (ficlWord); 1466 ficlStackPushPointer(vm->dataStack, ptr); 1467 } 1468 1469 /* 1470 * >name Ficl ( xt -- c-addr u ) 1471 * Push the address and length of a word's name given its address 1472 * xt. 1473 */ 1474 static void 1475 ficlPrimitiveToName(ficlVm *vm) 1476 { 1477 ficlWord *word; 1478 1479 FICL_STACK_CHECK(vm->dataStack, 1, 2); 1480 1481 word = ficlStackPopPointer(vm->dataStack); 1482 ficlStackPushPointer(vm->dataStack, word->name); 1483 ficlStackPushUnsigned(vm->dataStack, word->length); 1484 } 1485 1486 static void 1487 ficlPrimitiveLastWord(ficlVm *vm) 1488 { 1489 ficlDictionary *dictionary = ficlVmGetDictionary(vm); 1490 ficlWord *wp = dictionary->smudge; 1491 ficlCell c; 1492 1493 FICL_VM_ASSERT(vm, wp); 1494 1495 c.p = wp; 1496 ficlVmPush(vm, c); 1497 } 1498 1499 /* 1500 * l b r a c k e t e t c 1501 */ 1502 static void 1503 ficlPrimitiveLeftBracketCoIm(ficlVm *vm) 1504 { 1505 vm->state = FICL_VM_STATE_INTERPRET; 1506 } 1507 1508 static void 1509 ficlPrimitiveRightBracket(ficlVm *vm) 1510 { 1511 vm->state = FICL_VM_STATE_COMPILE; 1512 } 1513 1514 /* 1515 * p i c t u r e d n u m e r i c w o r d s 1516 * 1517 * less-number-sign CORE ( -- ) 1518 * Initialize the pictured numeric output conversion process. 1519 * (clear the pad) 1520 */ 1521 static void 1522 ficlPrimitiveLessNumberSign(ficlVm *vm) 1523 { 1524 ficlCountedString *counted = FICL_POINTER_TO_COUNTED_STRING(vm->pad); 1525 counted->length = 0; 1526 } 1527 1528 /* 1529 * number-sign CORE ( ud1 -- ud2 ) 1530 * Divide ud1 by the number in BASE giving the quotient ud2 and the remainder 1531 * n. (n is the least-significant digit of ud1.) Convert n to external form 1532 * and add the resulting character to the beginning of the pictured numeric 1533 * output string. An ambiguous condition exists if # executes outside of a 1534 * <# #> delimited number conversion. 1535 */ 1536 static void 1537 ficlPrimitiveNumberSign(ficlVm *vm) 1538 { 1539 ficlCountedString *counted; 1540 ficl2Unsigned u; 1541 ficl2UnsignedQR uqr; 1542 1543 FICL_STACK_CHECK(vm->dataStack, 2, 2); 1544 1545 counted = FICL_POINTER_TO_COUNTED_STRING(vm->pad); 1546 u = ficlStackPop2Unsigned(vm->dataStack); 1547 uqr = ficl2UnsignedDivide(u, (ficlUnsigned16)(vm->base)); 1548 counted->text[counted->length++] = ficlDigitToCharacter(uqr.remainder); 1549 ficlStackPush2Unsigned(vm->dataStack, uqr.quotient); 1550 } 1551 1552 /* 1553 * number-sign-greater CORE ( xd -- c-addr u ) 1554 * Drop xd. Make the pictured numeric output string available as a character 1555 * string. c-addr and u specify the resulting character string. A program 1556 * may replace characters within the string. 1557 */ 1558 static void 1559 ficlPrimitiveNumberSignGreater(ficlVm *vm) 1560 { 1561 ficlCountedString *counted; 1562 1563 FICL_STACK_CHECK(vm->dataStack, 2, 2); 1564 1565 counted = FICL_POINTER_TO_COUNTED_STRING(vm->pad); 1566 counted->text[counted->length] = 0; 1567 ficlStringReverse(counted->text); 1568 ficlStackDrop(vm->dataStack, 2); 1569 ficlStackPushPointer(vm->dataStack, counted->text); 1570 ficlStackPushUnsigned(vm->dataStack, counted->length); 1571 } 1572 1573 /* 1574 * number-sign-s CORE ( ud1 -- ud2 ) 1575 * Convert one digit of ud1 according to the rule for #. Continue conversion 1576 * until the quotient is zero. ud2 is zero. An ambiguous condition exists if 1577 * #S executes outside of a <# #> delimited number conversion. 1578 * TO DO: presently does not use ud1 hi ficlCell - use it! 1579 */ 1580 static void 1581 ficlPrimitiveNumberSignS(ficlVm *vm) 1582 { 1583 ficlCountedString *counted; 1584 ficl2Unsigned u; 1585 ficl2UnsignedQR uqr; 1586 1587 FICL_STACK_CHECK(vm->dataStack, 2, 2); 1588 1589 counted = FICL_POINTER_TO_COUNTED_STRING(vm->pad); 1590 u = ficlStackPop2Unsigned(vm->dataStack); 1591 1592 do { 1593 uqr = ficl2UnsignedDivide(u, (ficlUnsigned16)(vm->base)); 1594 counted->text[counted->length++] = 1595 ficlDigitToCharacter(uqr.remainder); 1596 u = uqr.quotient; 1597 } while (FICL_2UNSIGNED_NOT_ZERO(u)); 1598 1599 ficlStackPush2Unsigned(vm->dataStack, u); 1600 } 1601 1602 /* 1603 * HOLD CORE ( char -- ) 1604 * Add char to the beginning of the pictured numeric output string. 1605 * An ambiguous condition exists if HOLD executes outside of a <# #> 1606 * delimited number conversion. 1607 */ 1608 static void 1609 ficlPrimitiveHold(ficlVm *vm) 1610 { 1611 ficlCountedString *counted; 1612 int i; 1613 1614 FICL_STACK_CHECK(vm->dataStack, 1, 0); 1615 1616 counted = FICL_POINTER_TO_COUNTED_STRING(vm->pad); 1617 i = ficlStackPopInteger(vm->dataStack); 1618 counted->text[counted->length++] = (char)i; 1619 } 1620 1621 /* 1622 * SIGN CORE ( n -- ) 1623 * If n is negative, add a minus sign to the beginning of the pictured 1624 * numeric output string. An ambiguous condition exists if SIGN 1625 * executes outside of a <# #> delimited number conversion. 1626 */ 1627 static void 1628 ficlPrimitiveSign(ficlVm *vm) 1629 { 1630 ficlCountedString *counted; 1631 int i; 1632 1633 FICL_STACK_CHECK(vm->dataStack, 1, 0); 1634 1635 counted = FICL_POINTER_TO_COUNTED_STRING(vm->pad); 1636 i = ficlStackPopInteger(vm->dataStack); 1637 if (i < 0) 1638 counted->text[counted->length++] = '-'; 1639 } 1640 1641 /* 1642 * t o N u m b e r 1643 * to-number CORE ( ud1 c-addr1 u1 -- ud2 c-addr2 u2 ) 1644 * ud2 is the unsigned result of converting the characters within the 1645 * string specified by c-addr1 u1 into digits, using the number in BASE, 1646 * and adding each into ud1 after multiplying ud1 by the number in BASE. 1647 * Conversion continues left-to-right until a character that is not 1648 * convertible, including any + or -, is encountered or the string is 1649 * entirely converted. c-addr2 is the location of the first unconverted 1650 * character or the first character past the end of the string if the string 1651 * was entirely converted. u2 is the number of unconverted characters in the 1652 * string. An ambiguous condition exists if ud2 overflows during the 1653 * conversion. 1654 */ 1655 static void 1656 ficlPrimitiveToNumber(ficlVm *vm) 1657 { 1658 ficlUnsigned length; 1659 char *trace; 1660 ficl2Unsigned accumulator; 1661 ficlUnsigned base = vm->base; 1662 ficlUnsigned c; 1663 ficlUnsigned digit; 1664 1665 FICL_STACK_CHECK(vm->dataStack, 4, 4); 1666 1667 length = ficlStackPopUnsigned(vm->dataStack); 1668 trace = (char *)ficlStackPopPointer(vm->dataStack); 1669 accumulator = ficlStackPop2Unsigned(vm->dataStack); 1670 1671 for (c = *trace; length > 0; c = *++trace, length--) { 1672 if (c < '0') 1673 break; 1674 1675 digit = c - '0'; 1676 1677 if (digit > 9) 1678 digit = tolower(c) - 'a' + 10; 1679 /* 1680 * Note: following test also catches chars between 9 and a 1681 * because 'digit' is unsigned! 1682 */ 1683 if (digit >= base) 1684 break; 1685 1686 accumulator = ficl2UnsignedMultiplyAccumulate(accumulator, 1687 base, digit); 1688 } 1689 1690 ficlStackPush2Unsigned(vm->dataStack, accumulator); 1691 ficlStackPushPointer(vm->dataStack, trace); 1692 ficlStackPushUnsigned(vm->dataStack, length); 1693 } 1694 1695 /* 1696 * q u i t & a b o r t 1697 * quit CORE ( -- ) ( R: i*x -- ) 1698 * Empty the return stack, store zero in SOURCE-ID if it is present, make 1699 * the user input device the input source, and enter interpretation state. 1700 * Do not display a message. Repeat the following: 1701 * 1702 * Accept a line from the input source into the input buffer, set >IN to 1703 * zero, and FICL_VM_STATE_INTERPRET. 1704 * Display the implementation-defined system prompt if in 1705 * interpretation state, all processing has been completed, and no 1706 * ambiguous condition exists. 1707 */ 1708 static void 1709 ficlPrimitiveQuit(ficlVm *vm) 1710 { 1711 ficlVmThrow(vm, FICL_VM_STATUS_QUIT); 1712 } 1713 1714 static void 1715 ficlPrimitiveAbort(ficlVm *vm) 1716 { 1717 ficlVmThrow(vm, FICL_VM_STATUS_ABORT); 1718 } 1719 1720 /* 1721 * a c c e p t 1722 * accept CORE ( c-addr +n1 -- +n2 ) 1723 * Receive a string of at most +n1 characters. An ambiguous condition 1724 * exists if +n1 is zero or greater than 32,767. Display graphic characters 1725 * as they are received. A program that depends on the presence or absence 1726 * of non-graphic characters in the string has an environmental dependency. 1727 * The editing functions, if any, that the system performs in order to 1728 * construct the string are implementation-defined. 1729 * 1730 * (Although the standard text doesn't say so, I assume that the intent 1731 * of 'accept' is to store the string at the address specified on 1732 * the stack.) 1733 * 1734 * NOTE: getchar() is used there as its present both in loader and 1735 * userland; however, the more correct solution would be to set 1736 * terminal to raw mode for userland. 1737 */ 1738 static void 1739 ficlPrimitiveAccept(ficlVm *vm) 1740 { 1741 ficlUnsigned size; 1742 char *address; 1743 int c; 1744 ficlUnsigned length = 0; 1745 1746 FICL_STACK_CHECK(vm->dataStack, 2, 1); 1747 1748 size = ficlStackPopInteger(vm->dataStack); 1749 address = ficlStackPopPointer(vm->dataStack); 1750 1751 while (size != length) { 1752 c = getchar(); 1753 if (c == '\n' || c == '\r') 1754 break; 1755 address[length++] = c; 1756 } 1757 ficlStackPushInteger(vm->dataStack, length); 1758 } 1759 1760 /* 1761 * a l i g n 1762 * 6.1.0705 ALIGN CORE ( -- ) 1763 * If the data-space pointer is not aligned, reserve enough space to 1764 * align it. 1765 */ 1766 static void 1767 ficlPrimitiveAlign(ficlVm *vm) 1768 { 1769 ficlDictionary *dictionary = ficlVmGetDictionary(vm); 1770 FICL_IGNORE(vm); 1771 ficlDictionaryAlign(dictionary); 1772 } 1773 1774 /* 1775 * a l i g n e d 1776 */ 1777 static void 1778 ficlPrimitiveAligned(ficlVm *vm) 1779 { 1780 void *addr; 1781 1782 FICL_STACK_CHECK(vm->dataStack, 1, 1); 1783 1784 addr = ficlStackPopPointer(vm->dataStack); 1785 ficlStackPushPointer(vm->dataStack, ficlAlignPointer(addr)); 1786 } 1787 1788 /* 1789 * b e g i n & f r i e n d s 1790 * Indefinite loop control structures 1791 * A.6.1.0760 BEGIN 1792 * Typical use: 1793 * : X ... BEGIN ... test UNTIL ; 1794 * or 1795 * : X ... BEGIN ... test WHILE ... REPEAT ; 1796 */ 1797 static void 1798 ficlPrimitiveBeginCoIm(ficlVm *vm) 1799 { 1800 ficlDictionary *dictionary = ficlVmGetDictionary(vm); 1801 markBranch(dictionary, vm, destTag); 1802 } 1803 1804 static void 1805 ficlPrimitiveUntilCoIm(ficlVm *vm) 1806 { 1807 ficlDictionary *dictionary = ficlVmGetDictionary(vm); 1808 1809 ficlDictionaryAppendUnsigned(dictionary, 1810 ficlInstructionBranch0ParenWithCheck); 1811 resolveBackBranch(dictionary, vm, destTag); 1812 } 1813 1814 static void 1815 ficlPrimitiveWhileCoIm(ficlVm *vm) 1816 { 1817 ficlDictionary *dictionary = ficlVmGetDictionary(vm); 1818 1819 FICL_STACK_CHECK(vm->dataStack, 2, 5); 1820 1821 ficlDictionaryAppendUnsigned(dictionary, 1822 ficlInstructionBranch0ParenWithCheck); 1823 markBranch(dictionary, vm, origTag); 1824 1825 /* equivalent to 2swap */ 1826 ficlStackRoll(vm->dataStack, 3); 1827 ficlStackRoll(vm->dataStack, 3); 1828 1829 ficlDictionaryAppendUnsigned(dictionary, 1); 1830 } 1831 1832 static void 1833 ficlPrimitiveRepeatCoIm(ficlVm *vm) 1834 { 1835 ficlDictionary *dictionary = ficlVmGetDictionary(vm); 1836 1837 ficlDictionaryAppendUnsigned(dictionary, 1838 ficlInstructionBranchParenWithCheck); 1839 /* expect "begin" branch marker */ 1840 resolveBackBranch(dictionary, vm, destTag); 1841 /* expect "while" branch marker */ 1842 resolveForwardBranch(dictionary, vm, origTag); 1843 } 1844 1845 static void 1846 ficlPrimitiveAgainCoIm(ficlVm *vm) 1847 { 1848 ficlDictionary *dictionary = ficlVmGetDictionary(vm); 1849 1850 ficlDictionaryAppendUnsigned(dictionary, 1851 ficlInstructionBranchParenWithCheck); 1852 /* expect "begin" branch marker */ 1853 resolveBackBranch(dictionary, vm, destTag); 1854 } 1855 1856 /* 1857 * c h a r & f r i e n d s 1858 * 6.1.0895 CHAR CORE ( "<spaces>name" -- char ) 1859 * Skip leading space delimiters. Parse name delimited by a space. 1860 * Put the value of its first character onto the stack. 1861 * 1862 * bracket-char CORE 1863 * Interpretation: Interpretation semantics for this word are undefined. 1864 * Compilation: ( "<spaces>name" -- ) 1865 * Skip leading space delimiters. Parse name delimited by a space. 1866 * Append the run-time semantics given below to the current definition. 1867 * Run-time: ( -- char ) 1868 * Place char, the value of the first character of name, on the stack. 1869 */ 1870 static void 1871 ficlPrimitiveChar(ficlVm *vm) 1872 { 1873 ficlString s; 1874 1875 FICL_STACK_CHECK(vm->dataStack, 0, 1); 1876 1877 s = ficlVmGetWord(vm); 1878 ficlStackPushUnsigned(vm->dataStack, (ficlUnsigned)(s.text[0])); 1879 } 1880 1881 static void 1882 ficlPrimitiveCharCoIm(ficlVm *vm) 1883 { 1884 ficlPrimitiveChar(vm); 1885 ficlPrimitiveLiteralIm(vm); 1886 } 1887 1888 /* 1889 * c h a r P l u s 1890 * char-plus CORE ( c-addr1 -- c-addr2 ) 1891 * Add the size in address units of a character to c-addr1, giving c-addr2. 1892 */ 1893 static void 1894 ficlPrimitiveCharPlus(ficlVm *vm) 1895 { 1896 char *p; 1897 1898 FICL_STACK_CHECK(vm->dataStack, 1, 1); 1899 1900 p = ficlStackPopPointer(vm->dataStack); 1901 ficlStackPushPointer(vm->dataStack, p + 1); 1902 } 1903 1904 /* 1905 * c h a r s 1906 * chars CORE ( n1 -- n2 ) 1907 * n2 is the size in address units of n1 characters. 1908 * For most processors, this function can be a no-op. To guarantee 1909 * portability, we'll multiply by sizeof (char). 1910 */ 1911 #if defined(_M_IX86) 1912 #pragma warning(disable: 4127) 1913 #endif 1914 static void 1915 ficlPrimitiveChars(ficlVm *vm) 1916 { 1917 if (sizeof (char) > 1) { 1918 ficlInteger i; 1919 1920 FICL_STACK_CHECK(vm->dataStack, 1, 1); 1921 1922 i = ficlStackPopInteger(vm->dataStack); 1923 ficlStackPushInteger(vm->dataStack, i * sizeof (char)); 1924 } 1925 /* otherwise no-op! */ 1926 } 1927 #if defined(_M_IX86) 1928 #pragma warning(default: 4127) 1929 #endif 1930 1931 /* 1932 * c o u n t 1933 * COUNT CORE ( c-addr1 -- c-addr2 u ) 1934 * Return the character string specification for the counted string stored 1935 * at c-addr1. c-addr2 is the address of the first character after c-addr1. 1936 * u is the contents of the character at c-addr1, which is the length in 1937 * characters of the string at c-addr2. 1938 */ 1939 static void 1940 ficlPrimitiveCount(ficlVm *vm) 1941 { 1942 ficlCountedString *counted; 1943 1944 FICL_STACK_CHECK(vm->dataStack, 1, 2); 1945 1946 counted = ficlStackPopPointer(vm->dataStack); 1947 ficlStackPushPointer(vm->dataStack, counted->text); 1948 ficlStackPushUnsigned(vm->dataStack, counted->length); 1949 } 1950 1951 /* 1952 * e n v i r o n m e n t ? 1953 * environment-query CORE ( c-addr u -- FICL_FALSE | i*x FICL_TRUE ) 1954 * c-addr is the address of a character string and u is the string's 1955 * character count. u may have a value in the range from zero to an 1956 * implementation-defined maximum which shall not be less than 31. The 1957 * character string should contain a keyword from 3.2.6 Environmental 1958 * queries or the optional word sets to be checked for correspondence 1959 * with an attribute of the present environment. If the system treats the 1960 * attribute as unknown, the returned flag is FICL_FALSE; otherwise, the flag 1961 * is FICL_TRUE and the i*x returned is of the type specified in the table for 1962 * the attribute queried. 1963 */ 1964 static void 1965 ficlPrimitiveEnvironmentQ(ficlVm *vm) 1966 { 1967 ficlDictionary *environment; 1968 ficlWord *word; 1969 ficlString name; 1970 1971 FICL_STACK_CHECK(vm->dataStack, 2, 1); 1972 1973 environment = vm->callback.system->environment; 1974 name.length = ficlStackPopUnsigned(vm->dataStack); 1975 name.text = ficlStackPopPointer(vm->dataStack); 1976 1977 word = ficlDictionaryLookup(environment, name); 1978 1979 if (word != NULL) { 1980 ficlVmExecuteWord(vm, word); 1981 ficlStackPushInteger(vm->dataStack, FICL_TRUE); 1982 } else { 1983 ficlStackPushInteger(vm->dataStack, FICL_FALSE); 1984 } 1985 } 1986 1987 /* 1988 * e v a l u a t e 1989 * EVALUATE CORE ( i*x c-addr u -- j*x ) 1990 * Save the current input source specification. Store minus-one (-1) in 1991 * SOURCE-ID if it is present. Make the string described by c-addr and u 1992 * both the input source and input buffer, set >IN to zero, and 1993 * FICL_VM_STATE_INTERPRET. 1994 * When the parse area is empty, restore the prior input source 1995 * specification. Other stack effects are due to the words EVALUATEd. 1996 */ 1997 static void 1998 ficlPrimitiveEvaluate(ficlVm *vm) 1999 { 2000 ficlCell id; 2001 int result; 2002 ficlString string; 2003 2004 FICL_STACK_CHECK(vm->dataStack, 2, 0); 2005 2006 FICL_STRING_SET_LENGTH(string, ficlStackPopUnsigned(vm->dataStack)); 2007 FICL_STRING_SET_POINTER(string, ficlStackPopPointer(vm->dataStack)); 2008 2009 id = vm->sourceId; 2010 vm->sourceId.i = -1; 2011 result = ficlVmExecuteString(vm, string); 2012 vm->sourceId = id; 2013 if (result != FICL_VM_STATUS_OUT_OF_TEXT) 2014 ficlVmThrow(vm, result); 2015 } 2016 2017 /* 2018 * s t r i n g q u o t e 2019 * Interpreting: get string delimited by a quote from the input stream, 2020 * copy to a scratch area, and put its count and address on the stack. 2021 * Compiling: FICL_VM_STATE_COMPILE code to push the address and count 2022 * of a string literal, FICL_VM_STATE_COMPILE the string from the input 2023 * stream, and align the dictionary pointer. 2024 */ 2025 static void 2026 ficlPrimitiveStringQuoteIm(ficlVm *vm) 2027 { 2028 ficlDictionary *dictionary = ficlVmGetDictionary(vm); 2029 2030 if (vm->state == FICL_VM_STATE_INTERPRET) { 2031 ficlCountedString *counted; 2032 counted = (ficlCountedString *)dictionary->here; 2033 ficlVmGetString(vm, counted, '\"'); 2034 ficlStackPushPointer(vm->dataStack, counted->text); 2035 ficlStackPushUnsigned(vm->dataStack, counted->length); 2036 } else { /* FICL_VM_STATE_COMPILE state */ 2037 ficlDictionaryAppendUnsigned(dictionary, 2038 ficlInstructionStringLiteralParen); 2039 dictionary->here = FICL_POINTER_TO_CELL( 2040 ficlVmGetString(vm, (ficlCountedString *)dictionary->here, 2041 '\"')); 2042 ficlDictionaryAlign(dictionary); 2043 } 2044 } 2045 2046 /* 2047 * t y p e 2048 * Pop count and char address from stack and print the designated string. 2049 */ 2050 static void 2051 ficlPrimitiveType(ficlVm *vm) 2052 { 2053 ficlUnsigned length; 2054 char *s; 2055 2056 FICL_STACK_CHECK(vm->dataStack, 2, 0); 2057 2058 length = ficlStackPopUnsigned(vm->dataStack); 2059 s = ficlStackPopPointer(vm->dataStack); 2060 2061 if ((s == NULL) || (length == 0)) 2062 return; 2063 2064 /* 2065 * Since we don't have an output primitive for a counted string 2066 * (oops), make sure the string is null terminated. If not, copy 2067 * and terminate it. 2068 */ 2069 if (s[length] != 0) { 2070 char *here = (char *)ficlVmGetDictionary(vm)->here; 2071 if (s != here) 2072 strncpy(here, s, length); 2073 2074 here[length] = '\0'; 2075 s = here; 2076 } 2077 2078 ficlVmTextOut(vm, s); 2079 } 2080 2081 /* 2082 * w o r d 2083 * word CORE ( char "<chars>ccc<char>" -- c-addr ) 2084 * Skip leading delimiters. Parse characters ccc delimited by char. An 2085 * ambiguous condition exists if the length of the parsed string is greater 2086 * than the implementation-defined length of a counted string. 2087 * 2088 * c-addr is the address of a transient region containing the parsed word 2089 * as a counted string. If the parse area was empty or contained no 2090 * characters other than the delimiter, the resulting string has a zero 2091 * length. A space, not included in the length, follows the string. A 2092 * program may replace characters within the string. 2093 * NOTE! Ficl also NULL-terminates the dest string. 2094 */ 2095 static void 2096 ficlPrimitiveWord(ficlVm *vm) 2097 { 2098 ficlCountedString *counted; 2099 char delim; 2100 ficlString name; 2101 2102 FICL_STACK_CHECK(vm->dataStack, 1, 1); 2103 2104 counted = (ficlCountedString *)vm->pad; 2105 delim = (char)ficlStackPopInteger(vm->dataStack); 2106 name = ficlVmParseStringEx(vm, delim, 1); 2107 2108 if (FICL_STRING_GET_LENGTH(name) > FICL_PAD_SIZE - 1) 2109 FICL_STRING_SET_LENGTH(name, FICL_PAD_SIZE - 1); 2110 2111 counted->length = (ficlUnsigned8)FICL_STRING_GET_LENGTH(name); 2112 strncpy(counted->text, FICL_STRING_GET_POINTER(name), 2113 FICL_STRING_GET_LENGTH(name)); 2114 2115 /* 2116 * store an extra space at the end of the primitive... 2117 * why? dunno yet. Guy Carver did it. 2118 */ 2119 counted->text[counted->length] = ' '; 2120 counted->text[counted->length + 1] = 0; 2121 2122 ficlStackPushPointer(vm->dataStack, counted); 2123 } 2124 2125 /* 2126 * p a r s e - w o r d 2127 * Ficl PARSE-WORD ( <spaces>name -- c-addr u ) 2128 * Skip leading spaces and parse name delimited by a space. c-addr is the 2129 * address within the input buffer and u is the length of the selected 2130 * string. If the parse area is empty, the resulting string has a zero length. 2131 */ 2132 static void ficlPrimitiveParseNoCopy(ficlVm *vm) 2133 { 2134 ficlString s; 2135 2136 FICL_STACK_CHECK(vm->dataStack, 0, 2); 2137 2138 s = ficlVmGetWord0(vm); 2139 ficlStackPushPointer(vm->dataStack, FICL_STRING_GET_POINTER(s)); 2140 ficlStackPushUnsigned(vm->dataStack, FICL_STRING_GET_LENGTH(s)); 2141 } 2142 2143 /* 2144 * p a r s e 2145 * CORE EXT ( char "ccc<char>" -- c-addr u ) 2146 * Parse ccc delimited by the delimiter char. 2147 * c-addr is the address (within the input buffer) and u is the length of 2148 * the parsed string. If the parse area was empty, the resulting string has 2149 * a zero length. 2150 * NOTE! PARSE differs from WORD: it does not skip leading delimiters. 2151 */ 2152 static void 2153 ficlPrimitiveParse(ficlVm *vm) 2154 { 2155 ficlString s; 2156 char delim; 2157 2158 FICL_STACK_CHECK(vm->dataStack, 1, 2); 2159 2160 delim = (char)ficlStackPopInteger(vm->dataStack); 2161 2162 s = ficlVmParseStringEx(vm, delim, 0); 2163 ficlStackPushPointer(vm->dataStack, FICL_STRING_GET_POINTER(s)); 2164 ficlStackPushUnsigned(vm->dataStack, FICL_STRING_GET_LENGTH(s)); 2165 } 2166 2167 /* 2168 * f i n d 2169 * FIND CORE ( c-addr -- c-addr 0 | xt 1 | xt -1 ) 2170 * Find the definition named in the counted string at c-addr. If the 2171 * definition is not found, return c-addr and zero. If the definition is 2172 * found, return its execution token xt. If the definition is immediate, 2173 * also return one (1), otherwise also return minus-one (-1). For a given 2174 * string, the values returned by FIND while compiling may differ from 2175 * those returned while not compiling. 2176 */ 2177 static void 2178 do_find(ficlVm *vm, ficlString name, void *returnForFailure) 2179 { 2180 ficlWord *word; 2181 2182 word = ficlDictionaryLookup(ficlVmGetDictionary(vm), name); 2183 if (word) { 2184 ficlStackPushPointer(vm->dataStack, word); 2185 ficlStackPushInteger(vm->dataStack, 2186 (ficlWordIsImmediate(word) ? 1 : -1)); 2187 } else { 2188 ficlStackPushPointer(vm->dataStack, returnForFailure); 2189 ficlStackPushUnsigned(vm->dataStack, 0); 2190 } 2191 } 2192 2193 /* 2194 * f i n d 2195 * FIND CORE ( c-addr -- c-addr 0 | xt 1 | xt -1 ) 2196 * Find the definition named in the counted string at c-addr. If the 2197 * definition is not found, return c-addr and zero. If the definition is 2198 * found, return its execution token xt. If the definition is immediate, 2199 * also return one (1), otherwise also return minus-one (-1). For a given 2200 * string, the values returned by FIND while compiling may differ from 2201 * those returned while not compiling. 2202 */ 2203 static void 2204 ficlPrimitiveCFind(ficlVm *vm) 2205 { 2206 ficlCountedString *counted; 2207 ficlString name; 2208 2209 FICL_STACK_CHECK(vm->dataStack, 1, 2); 2210 2211 counted = ficlStackPopPointer(vm->dataStack); 2212 FICL_STRING_SET_FROM_COUNTED_STRING(name, *counted); 2213 do_find(vm, name, counted); 2214 } 2215 2216 /* 2217 * s f i n d 2218 * Ficl ( c-addr u -- 0 0 | xt 1 | xt -1 ) 2219 * Like FIND, but takes "c-addr u" for the string. 2220 */ 2221 static void 2222 ficlPrimitiveSFind(ficlVm *vm) 2223 { 2224 ficlString name; 2225 2226 FICL_STACK_CHECK(vm->dataStack, 2, 2); 2227 2228 name.length = ficlStackPopInteger(vm->dataStack); 2229 name.text = ficlStackPopPointer(vm->dataStack); 2230 2231 do_find(vm, name, NULL); 2232 } 2233 2234 /* 2235 * r e c u r s e 2236 */ 2237 static void 2238 ficlPrimitiveRecurseCoIm(ficlVm *vm) 2239 { 2240 ficlDictionary *dictionary = ficlVmGetDictionary(vm); 2241 ficlCell c; 2242 2243 FICL_IGNORE(vm); 2244 c.p = dictionary->smudge; 2245 ficlDictionaryAppendCell(dictionary, c); 2246 } 2247 2248 /* 2249 * s o u r c e 2250 * CORE ( -- c-addr u ) 2251 * c-addr is the address of, and u is the number of characters in, the 2252 * input buffer. 2253 */ 2254 static void 2255 ficlPrimitiveSource(ficlVm *vm) 2256 { 2257 FICL_STACK_CHECK(vm->dataStack, 0, 2); 2258 2259 ficlStackPushPointer(vm->dataStack, vm->tib.text); 2260 ficlStackPushInteger(vm->dataStack, ficlVmGetInBufLen(vm)); 2261 } 2262 2263 /* 2264 * v e r s i o n 2265 * non-standard... 2266 */ 2267 static void 2268 ficlPrimitiveVersion(ficlVm *vm) 2269 { 2270 ficlVmTextOut(vm, "Ficl version " FICL_VERSION "\n"); 2271 } 2272 2273 /* 2274 * t o I n 2275 * to-in CORE 2276 */ 2277 static void 2278 ficlPrimitiveToIn(ficlVm *vm) 2279 { 2280 FICL_STACK_CHECK(vm->dataStack, 0, 1); 2281 2282 ficlStackPushPointer(vm->dataStack, &vm->tib.index); 2283 } 2284 2285 /* 2286 * c o l o n N o N a m e 2287 * CORE EXT ( C: -- colon-sys ) ( S: -- xt ) 2288 * Create an unnamed colon definition and push its address. 2289 * Change state to FICL_VM_STATE_COMPILE. 2290 */ 2291 static void 2292 ficlPrimitiveColonNoName(ficlVm *vm) 2293 { 2294 ficlDictionary *dictionary = ficlVmGetDictionary(vm); 2295 ficlWord *word; 2296 ficlString name; 2297 2298 FICL_STRING_SET_LENGTH(name, 0); 2299 FICL_STRING_SET_POINTER(name, NULL); 2300 2301 vm->state = FICL_VM_STATE_COMPILE; 2302 word = ficlDictionaryAppendWord(dictionary, name, 2303 (ficlPrimitive)ficlInstructionColonParen, 2304 FICL_WORD_DEFAULT | FICL_WORD_SMUDGED); 2305 2306 ficlStackPushPointer(vm->dataStack, word); 2307 markControlTag(vm, colonTag); 2308 } 2309 2310 /* 2311 * u s e r V a r i a b l e 2312 * user ( u -- ) "<spaces>name" 2313 * Get a name from the input stream and create a user variable 2314 * with the name and the index supplied. The run-time effect 2315 * of a user variable is to push the address of the indexed ficlCell 2316 * in the running vm's user array. 2317 * 2318 * User variables are vm local cells. Each vm has an array of 2319 * FICL_USER_CELLS of them when FICL_WANT_USER is nonzero. 2320 * Ficl's user facility is implemented with two primitives, 2321 * "user" and "(user)", a variable ("nUser") (in softcore.c) that 2322 * holds the index of the next free user ficlCell, and a redefinition 2323 * (also in softcore) of "user" that defines a user word and increments 2324 * nUser. 2325 */ 2326 #if FICL_WANT_USER 2327 static void 2328 ficlPrimitiveUser(ficlVm *vm) 2329 { 2330 ficlDictionary *dictionary = ficlVmGetDictionary(vm); 2331 ficlString name = ficlVmGetWord(vm); 2332 ficlCell c; 2333 2334 c = ficlStackPop(vm->dataStack); 2335 if (c.i >= FICL_USER_CELLS) { 2336 ficlVmThrowError(vm, "Error - out of user space"); 2337 } 2338 2339 ficlDictionaryAppendWord(dictionary, name, 2340 (ficlPrimitive)ficlInstructionUserParen, FICL_WORD_DEFAULT); 2341 ficlDictionaryAppendCell(dictionary, c); 2342 } 2343 #endif 2344 2345 #if FICL_WANT_LOCALS 2346 /* 2347 * Each local is recorded in a private locals dictionary as a 2348 * word that does doLocalIm at runtime. DoLocalIm compiles code 2349 * into the client definition to fetch the value of the 2350 * corresponding local variable from the return stack. 2351 * The private dictionary gets initialized at the end of each block 2352 * that uses locals (in ; and does> for example). 2353 */ 2354 void 2355 ficlLocalParenIm(ficlVm *vm, int isDouble, int isFloat) 2356 { 2357 ficlDictionary *dictionary = ficlVmGetDictionary(vm); 2358 ficlInteger nLocal = vm->runningWord->param[0].i; 2359 2360 #if !FICL_WANT_FLOAT 2361 FICL_VM_ASSERT(vm, !isFloat); 2362 /* get rid of unused parameter warning */ 2363 isFloat = 0; 2364 #endif /* FICL_WANT_FLOAT */ 2365 2366 if (vm->state == FICL_VM_STATE_INTERPRET) { 2367 ficlStack *stack; 2368 #if FICL_WANT_FLOAT 2369 if (isFloat) 2370 stack = vm->floatStack; 2371 else 2372 #endif /* FICL_WANT_FLOAT */ 2373 stack = vm->dataStack; 2374 2375 ficlStackPush(stack, vm->returnStack->frame[nLocal]); 2376 if (isDouble) 2377 ficlStackPush(stack, vm->returnStack->frame[nLocal+1]); 2378 } else { 2379 ficlInstruction instruction; 2380 ficlInteger appendLocalOffset; 2381 #if FICL_WANT_FLOAT 2382 if (isFloat) { 2383 instruction = 2384 (isDouble) ? ficlInstructionGetF2LocalParen : 2385 ficlInstructionGetFLocalParen; 2386 appendLocalOffset = FICL_TRUE; 2387 } else 2388 #endif /* FICL_WANT_FLOAT */ 2389 if (nLocal == 0) { 2390 instruction = (isDouble) ? ficlInstructionGet2Local0 : 2391 ficlInstructionGetLocal0; 2392 appendLocalOffset = FICL_FALSE; 2393 } else if ((nLocal == 1) && !isDouble) { 2394 instruction = ficlInstructionGetLocal1; 2395 appendLocalOffset = FICL_FALSE; 2396 } else { 2397 instruction = 2398 (isDouble) ? ficlInstructionGet2LocalParen : 2399 ficlInstructionGetLocalParen; 2400 appendLocalOffset = FICL_TRUE; 2401 } 2402 2403 ficlDictionaryAppendUnsigned(dictionary, instruction); 2404 if (appendLocalOffset) 2405 ficlDictionaryAppendUnsigned(dictionary, nLocal); 2406 } 2407 } 2408 2409 static void 2410 ficlPrimitiveDoLocalIm(ficlVm *vm) 2411 { 2412 ficlLocalParenIm(vm, 0, 0); 2413 } 2414 2415 static void 2416 ficlPrimitiveDo2LocalIm(ficlVm *vm) 2417 { 2418 ficlLocalParenIm(vm, 1, 0); 2419 } 2420 2421 #if FICL_WANT_FLOAT 2422 static void 2423 ficlPrimitiveDoFLocalIm(ficlVm *vm) 2424 { 2425 ficlLocalParenIm(vm, 0, 1); 2426 } 2427 2428 static void 2429 ficlPrimitiveDoF2LocalIm(ficlVm *vm) 2430 { 2431 ficlLocalParenIm(vm, 1, 1); 2432 } 2433 #endif /* FICL_WANT_FLOAT */ 2434 2435 /* 2436 * l o c a l P a r e n 2437 * paren-local-paren LOCAL 2438 * Interpretation: Interpretation semantics for this word are undefined. 2439 * Execution: ( c-addr u -- ) 2440 * When executed during compilation, (LOCAL) passes a message to the 2441 * system that has one of two meanings. If u is non-zero, 2442 * the message identifies a new local whose definition name is given by 2443 * the string of characters identified by c-addr u. If u is zero, 2444 * the message is last local and c-addr has no significance. 2445 * 2446 * The result of executing (LOCAL) during compilation of a definition is 2447 * to create a set of named local identifiers, each of which is 2448 * a definition name, that only have execution semantics within the scope 2449 * of that definition's source. 2450 * 2451 * local Execution: ( -- x ) 2452 * 2453 * Push the local's value, x, onto the stack. The local's value is 2454 * initialized as described in 13.3.3 Processing locals and may be 2455 * changed by preceding the local's name with TO. An ambiguous condition 2456 * exists when local is executed while in interpretation state. 2457 */ 2458 void 2459 ficlLocalParen(ficlVm *vm, int isDouble, int isFloat) 2460 { 2461 ficlDictionary *dictionary; 2462 ficlString name; 2463 2464 FICL_STACK_CHECK(vm->dataStack, 2, 0); 2465 2466 dictionary = ficlVmGetDictionary(vm); 2467 FICL_STRING_SET_LENGTH(name, ficlStackPopUnsigned(vm->dataStack)); 2468 FICL_STRING_SET_POINTER(name, 2469 (char *)ficlStackPopPointer(vm->dataStack)); 2470 2471 if (FICL_STRING_GET_LENGTH(name) > 0) { 2472 /* 2473 * add a local to the **locals** dictionary and 2474 * update localsCount 2475 */ 2476 ficlPrimitive code; 2477 ficlInstruction instruction; 2478 ficlDictionary *locals; 2479 2480 locals = ficlSystemGetLocals(vm->callback.system); 2481 if (vm->callback.system->localsCount >= FICL_MAX_LOCALS) { 2482 ficlVmThrowError(vm, "Error: out of local space"); 2483 } 2484 2485 #if !FICL_WANT_FLOAT 2486 FICL_VM_ASSERT(vm, !isFloat); 2487 /* get rid of unused parameter warning */ 2488 isFloat = 0; 2489 #else /* FICL_WANT_FLOAT */ 2490 if (isFloat) { 2491 if (isDouble) { 2492 code = ficlPrimitiveDoF2LocalIm; 2493 instruction = ficlInstructionToF2LocalParen; 2494 } else { 2495 code = ficlPrimitiveDoFLocalIm; 2496 instruction = ficlInstructionToFLocalParen; 2497 } 2498 } else 2499 #endif /* FICL_WANT_FLOAT */ 2500 if (isDouble) { 2501 code = ficlPrimitiveDo2LocalIm; 2502 instruction = ficlInstructionTo2LocalParen; 2503 } else { 2504 code = ficlPrimitiveDoLocalIm; 2505 instruction = ficlInstructionToLocalParen; 2506 } 2507 2508 ficlDictionaryAppendWord(locals, name, code, 2509 FICL_WORD_COMPILE_ONLY_IMMEDIATE); 2510 ficlDictionaryAppendUnsigned(locals, 2511 vm->callback.system->localsCount); 2512 2513 if (vm->callback.system->localsCount == 0) { 2514 /* 2515 * FICL_VM_STATE_COMPILE code to create a local 2516 * stack frame 2517 */ 2518 ficlDictionaryAppendUnsigned(dictionary, 2519 ficlInstructionLinkParen); 2520 2521 /* save location in dictionary for #locals */ 2522 vm->callback.system->localsFixup = dictionary->here; 2523 ficlDictionaryAppendUnsigned(dictionary, 2524 vm->callback.system->localsCount); 2525 } 2526 2527 ficlDictionaryAppendUnsigned(dictionary, instruction); 2528 ficlDictionaryAppendUnsigned(dictionary, 2529 vm->callback.system->localsCount); 2530 2531 vm->callback.system->localsCount += (isDouble) ? 2 : 1; 2532 } else if (vm->callback.system->localsCount > 0) { 2533 /* write localsCount to (link) param area in dictionary */ 2534 *(ficlInteger *)(vm->callback.system->localsFixup) = 2535 vm->callback.system->localsCount; 2536 } 2537 } 2538 2539 static void 2540 ficlPrimitiveLocalParen(ficlVm *vm) 2541 { 2542 ficlLocalParen(vm, 0, 0); 2543 } 2544 2545 static void 2546 ficlPrimitive2LocalParen(ficlVm *vm) 2547 { 2548 ficlLocalParen(vm, 1, 0); 2549 } 2550 #endif /* FICL_WANT_LOCALS */ 2551 2552 /* 2553 * t o V a l u e 2554 * CORE EXT 2555 * Interpretation: ( x "<spaces>name" -- ) 2556 * Skip leading spaces and parse name delimited by a space. Store x in 2557 * name. An ambiguous condition exists if name was not defined by VALUE. 2558 * NOTE: In Ficl, VALUE is an alias of CONSTANT 2559 */ 2560 static void 2561 ficlPrimitiveToValue(ficlVm *vm) 2562 { 2563 ficlString name = ficlVmGetWord(vm); 2564 ficlDictionary *dictionary = ficlVmGetDictionary(vm); 2565 ficlWord *word; 2566 ficlInstruction instruction = 0; 2567 ficlStack *stack; 2568 ficlInteger isDouble; 2569 #if FICL_WANT_LOCALS 2570 ficlInteger nLocal; 2571 ficlInteger appendLocalOffset; 2572 ficlInteger isFloat; 2573 #endif /* FICL_WANT_LOCALS */ 2574 2575 #if FICL_WANT_LOCALS 2576 if ((vm->callback.system->localsCount > 0) && 2577 (vm->state == FICL_VM_STATE_COMPILE)) { 2578 ficlDictionary *locals; 2579 2580 locals = ficlSystemGetLocals(vm->callback.system); 2581 word = ficlDictionaryLookup(locals, name); 2582 if (!word) 2583 goto TO_GLOBAL; 2584 2585 if (word->code == ficlPrimitiveDoLocalIm) { 2586 instruction = ficlInstructionToLocalParen; 2587 isDouble = isFloat = FICL_FALSE; 2588 } else if (word->code == ficlPrimitiveDo2LocalIm) { 2589 instruction = ficlInstructionTo2LocalParen; 2590 isDouble = FICL_TRUE; 2591 isFloat = FICL_FALSE; 2592 } 2593 #if FICL_WANT_FLOAT 2594 else if (word->code == ficlPrimitiveDoFLocalIm) { 2595 instruction = ficlInstructionToFLocalParen; 2596 isDouble = FICL_FALSE; 2597 isFloat = FICL_TRUE; 2598 } else if (word->code == ficlPrimitiveDoF2LocalIm) { 2599 instruction = ficlInstructionToF2LocalParen; 2600 isDouble = isFloat = FICL_TRUE; 2601 } 2602 #endif /* FICL_WANT_FLOAT */ 2603 else { 2604 ficlVmThrowError(vm, 2605 "to %.*s : local is of unknown type", 2606 FICL_STRING_GET_LENGTH(name), 2607 FICL_STRING_GET_POINTER(name)); 2608 return; 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 return; 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 ficlDictionarySetInstruction(dictionary, description, token, flags); 3108 #include "ficltokens.h" 3109 #undef FICL_TOKEN 3110 #undef FICL_INSTRUCTION_TOKEN 3111 3112 /* 3113 * The Core word set 3114 * see softcore.c for definitions of: abs bl space spaces abort" 3115 */ 3116 ficlDictionarySetPrimitive(dictionary, "#", ficlPrimitiveNumberSign, 3117 FICL_WORD_DEFAULT); 3118 ficlDictionarySetPrimitive(dictionary, "#>", 3119 ficlPrimitiveNumberSignGreater, FICL_WORD_DEFAULT); 3120 ficlDictionarySetPrimitive(dictionary, "#s", ficlPrimitiveNumberSignS, 3121 FICL_WORD_DEFAULT); 3122 ficlDictionarySetPrimitive(dictionary, "\'", ficlPrimitiveTick, 3123 FICL_WORD_DEFAULT); 3124 ficlDictionarySetPrimitive(dictionary, "(", ficlPrimitiveParenthesis, 3125 FICL_WORD_IMMEDIATE); 3126 ficlDictionarySetPrimitive(dictionary, "+loop", 3127 ficlPrimitivePlusLoopCoIm, FICL_WORD_COMPILE_ONLY_IMMEDIATE); 3128 ficlDictionarySetPrimitive(dictionary, ".", ficlPrimitiveDot, 3129 FICL_WORD_DEFAULT); 3130 ficlDictionarySetPrimitive(dictionary, ".\"", 3131 ficlPrimitiveDotQuoteCoIm, FICL_WORD_COMPILE_ONLY_IMMEDIATE); 3132 ficlDictionarySetPrimitive(dictionary, ":", ficlPrimitiveColon, 3133 FICL_WORD_DEFAULT); 3134 ficlDictionarySetPrimitive(dictionary, ";", ficlPrimitiveSemicolonCoIm, 3135 FICL_WORD_COMPILE_ONLY_IMMEDIATE); 3136 ficlDictionarySetPrimitive(dictionary, "<#", 3137 ficlPrimitiveLessNumberSign, FICL_WORD_DEFAULT); 3138 ficlDictionarySetPrimitive(dictionary, ">body", ficlPrimitiveToBody, 3139 FICL_WORD_DEFAULT); 3140 ficlDictionarySetPrimitive(dictionary, ">in", ficlPrimitiveToIn, 3141 FICL_WORD_DEFAULT); 3142 ficlDictionarySetPrimitive(dictionary, ">number", ficlPrimitiveToNumber, 3143 FICL_WORD_DEFAULT); 3144 ficlDictionarySetPrimitive(dictionary, "abort", ficlPrimitiveAbort, 3145 FICL_WORD_DEFAULT); 3146 ficlDictionarySetPrimitive(dictionary, "accept", ficlPrimitiveAccept, 3147 FICL_WORD_DEFAULT); 3148 ficlDictionarySetPrimitive(dictionary, "align", ficlPrimitiveAlign, 3149 FICL_WORD_DEFAULT); 3150 ficlDictionarySetPrimitive(dictionary, "aligned", ficlPrimitiveAligned, 3151 FICL_WORD_DEFAULT); 3152 ficlDictionarySetPrimitive(dictionary, "allot", ficlPrimitiveAllot, 3153 FICL_WORD_DEFAULT); 3154 ficlDictionarySetPrimitive(dictionary, "base", ficlPrimitiveBase, 3155 FICL_WORD_DEFAULT); 3156 ficlDictionarySetPrimitive(dictionary, "begin", ficlPrimitiveBeginCoIm, 3157 FICL_WORD_COMPILE_ONLY_IMMEDIATE); 3158 ficlDictionarySetPrimitive(dictionary, "case", ficlPrimitiveCaseCoIm, 3159 FICL_WORD_COMPILE_ONLY_IMMEDIATE); 3160 ficlDictionarySetPrimitive(dictionary, "char", ficlPrimitiveChar, 3161 FICL_WORD_DEFAULT); 3162 ficlDictionarySetPrimitive(dictionary, "char+", ficlPrimitiveCharPlus, 3163 FICL_WORD_DEFAULT); 3164 ficlDictionarySetPrimitive(dictionary, "chars", ficlPrimitiveChars, 3165 FICL_WORD_DEFAULT); 3166 ficlDictionarySetPrimitive(dictionary, "constant", 3167 ficlPrimitiveConstant, FICL_WORD_DEFAULT); 3168 ficlDictionarySetPrimitive(dictionary, "count", ficlPrimitiveCount, 3169 FICL_WORD_DEFAULT); 3170 ficlDictionarySetPrimitive(dictionary, "cr", ficlPrimitiveCR, 3171 FICL_WORD_DEFAULT); 3172 ficlDictionarySetPrimitive(dictionary, "create", ficlPrimitiveCreate, 3173 FICL_WORD_DEFAULT); 3174 ficlDictionarySetPrimitive(dictionary, "decimal", ficlPrimitiveDecimal, 3175 FICL_WORD_DEFAULT); 3176 ficlDictionarySetPrimitive(dictionary, "depth", ficlPrimitiveDepth, 3177 FICL_WORD_DEFAULT); 3178 ficlDictionarySetPrimitive(dictionary, "do", ficlPrimitiveDoCoIm, 3179 FICL_WORD_COMPILE_ONLY_IMMEDIATE); 3180 ficlDictionarySetPrimitive(dictionary, "does>", ficlPrimitiveDoesCoIm, 3181 FICL_WORD_COMPILE_ONLY_IMMEDIATE); 3182 ficlDictionarySetPrimitive(dictionary, "else", ficlPrimitiveElseCoIm, 3183 FICL_WORD_COMPILE_ONLY_IMMEDIATE); 3184 ficlDictionarySetPrimitive(dictionary, "emit", ficlPrimitiveEmit, 3185 FICL_WORD_DEFAULT); 3186 ficlDictionarySetPrimitive(dictionary, "endcase", 3187 ficlPrimitiveEndcaseCoIm, FICL_WORD_COMPILE_ONLY_IMMEDIATE); 3188 ficlDictionarySetPrimitive(dictionary, "endof", ficlPrimitiveEndofCoIm, 3189 FICL_WORD_COMPILE_ONLY_IMMEDIATE); 3190 ficlDictionarySetPrimitive(dictionary, "environment?", 3191 ficlPrimitiveEnvironmentQ, FICL_WORD_DEFAULT); 3192 ficlDictionarySetPrimitive(dictionary, "evaluate", 3193 ficlPrimitiveEvaluate, FICL_WORD_DEFAULT); 3194 ficlDictionarySetPrimitive(dictionary, "execute", ficlPrimitiveExecute, 3195 FICL_WORD_DEFAULT); 3196 ficlDictionarySetPrimitive(dictionary, "exit", ficlPrimitiveExitCoIm, 3197 FICL_WORD_COMPILE_ONLY_IMMEDIATE); 3198 ficlDictionarySetPrimitive(dictionary, "fallthrough", 3199 ficlPrimitiveFallthroughCoIm, FICL_WORD_COMPILE_ONLY_IMMEDIATE); 3200 ficlDictionarySetPrimitive(dictionary, "find", ficlPrimitiveCFind, 3201 FICL_WORD_DEFAULT); 3202 ficlDictionarySetPrimitive(dictionary, "fm/mod", 3203 ficlPrimitiveFMSlashMod, FICL_WORD_DEFAULT); 3204 ficlDictionarySetPrimitive(dictionary, "here", ficlPrimitiveHere, 3205 FICL_WORD_DEFAULT); 3206 ficlDictionarySetPrimitive(dictionary, "hold", ficlPrimitiveHold, 3207 FICL_WORD_DEFAULT); 3208 ficlDictionarySetPrimitive(dictionary, "if", ficlPrimitiveIfCoIm, 3209 FICL_WORD_COMPILE_ONLY_IMMEDIATE); 3210 ficlDictionarySetPrimitive(dictionary, "immediate", 3211 ficlPrimitiveImmediate, FICL_WORD_DEFAULT); 3212 ficlDictionarySetPrimitive(dictionary, "literal", 3213 ficlPrimitiveLiteralIm, FICL_WORD_IMMEDIATE); 3214 ficlDictionarySetPrimitive(dictionary, "loop", ficlPrimitiveLoopCoIm, 3215 FICL_WORD_COMPILE_ONLY_IMMEDIATE); 3216 ficlDictionarySetPrimitive(dictionary, "m*", ficlPrimitiveMStar, 3217 FICL_WORD_DEFAULT); 3218 ficlDictionarySetPrimitive(dictionary, "mod", ficlPrimitiveMod, 3219 FICL_WORD_DEFAULT); 3220 ficlDictionarySetPrimitive(dictionary, "of", ficlPrimitiveOfCoIm, 3221 FICL_WORD_COMPILE_ONLY_IMMEDIATE); 3222 ficlDictionarySetPrimitive(dictionary, "postpone", 3223 ficlPrimitivePostponeCoIm, FICL_WORD_COMPILE_ONLY_IMMEDIATE); 3224 ficlDictionarySetPrimitive(dictionary, "quit", ficlPrimitiveQuit, 3225 FICL_WORD_DEFAULT); 3226 ficlDictionarySetPrimitive(dictionary, "recurse", 3227 ficlPrimitiveRecurseCoIm, FICL_WORD_COMPILE_ONLY_IMMEDIATE); 3228 ficlDictionarySetPrimitive(dictionary, "repeat", 3229 ficlPrimitiveRepeatCoIm, FICL_WORD_COMPILE_ONLY_IMMEDIATE); 3230 ficlDictionarySetPrimitive(dictionary, "s\"", 3231 ficlPrimitiveStringQuoteIm, FICL_WORD_IMMEDIATE); 3232 ficlDictionarySetPrimitive(dictionary, "sign", ficlPrimitiveSign, 3233 FICL_WORD_DEFAULT); 3234 ficlDictionarySetPrimitive(dictionary, "sm/rem", 3235 ficlPrimitiveSMSlashRem, FICL_WORD_DEFAULT); 3236 ficlDictionarySetPrimitive(dictionary, "source", ficlPrimitiveSource, 3237 FICL_WORD_DEFAULT); 3238 ficlDictionarySetPrimitive(dictionary, "state", ficlPrimitiveState, 3239 FICL_WORD_DEFAULT); 3240 ficlDictionarySetPrimitive(dictionary, "then", ficlPrimitiveEndifCoIm, 3241 FICL_WORD_COMPILE_ONLY_IMMEDIATE); 3242 ficlDictionarySetPrimitive(dictionary, "type", ficlPrimitiveType, 3243 FICL_WORD_DEFAULT); 3244 ficlDictionarySetPrimitive(dictionary, "u.", ficlPrimitiveUDot, 3245 FICL_WORD_DEFAULT); 3246 ficlDictionarySetPrimitive(dictionary, "um*", ficlPrimitiveUMStar, 3247 FICL_WORD_DEFAULT); 3248 ficlDictionarySetPrimitive(dictionary, "um/mod", 3249 ficlPrimitiveUMSlashMod, FICL_WORD_DEFAULT); 3250 ficlDictionarySetPrimitive(dictionary, "until", 3251 ficlPrimitiveUntilCoIm, FICL_WORD_COMPILE_ONLY_IMMEDIATE); 3252 ficlDictionarySetPrimitive(dictionary, "variable", 3253 ficlPrimitiveVariable, FICL_WORD_DEFAULT); 3254 ficlDictionarySetPrimitive(dictionary, "while", 3255 ficlPrimitiveWhileCoIm, FICL_WORD_COMPILE_ONLY_IMMEDIATE); 3256 ficlDictionarySetPrimitive(dictionary, "word", ficlPrimitiveWord, 3257 FICL_WORD_DEFAULT); 3258 ficlDictionarySetPrimitive(dictionary, "[", 3259 ficlPrimitiveLeftBracketCoIm, FICL_WORD_COMPILE_ONLY_IMMEDIATE); 3260 ficlDictionarySetPrimitive(dictionary, "[\']", 3261 ficlPrimitiveBracketTickCoIm, FICL_WORD_COMPILE_ONLY_IMMEDIATE); 3262 ficlDictionarySetPrimitive(dictionary, "[char]", ficlPrimitiveCharCoIm, 3263 FICL_WORD_COMPILE_ONLY_IMMEDIATE); 3264 ficlDictionarySetPrimitive(dictionary, "]", ficlPrimitiveRightBracket, 3265 FICL_WORD_DEFAULT); 3266 /* 3267 * The Core Extensions word set... 3268 * see softcore.fr for other definitions 3269 */ 3270 /* "#tib" */ 3271 ficlDictionarySetPrimitive(dictionary, ".(", ficlPrimitiveDotParen, 3272 FICL_WORD_IMMEDIATE); 3273 /* ".r" is in softcore */ 3274 ficlDictionarySetPrimitive(dictionary, ":noname", 3275 ficlPrimitiveColonNoName, FICL_WORD_DEFAULT); 3276 ficlDictionarySetPrimitive(dictionary, "?do", ficlPrimitiveQDoCoIm, 3277 FICL_WORD_COMPILE_ONLY_IMMEDIATE); 3278 ficlDictionarySetPrimitive(dictionary, "again", ficlPrimitiveAgainCoIm, 3279 FICL_WORD_COMPILE_ONLY_IMMEDIATE); 3280 ficlDictionarySetPrimitive(dictionary, "c\"", 3281 ficlPrimitiveCountedStringQuoteIm, FICL_WORD_IMMEDIATE); 3282 ficlDictionarySetPrimitive(dictionary, "hex", ficlPrimitiveHex, 3283 FICL_WORD_DEFAULT); 3284 ficlDictionarySetPrimitive(dictionary, "pad", ficlPrimitivePad, 3285 FICL_WORD_DEFAULT); 3286 ficlDictionarySetPrimitive(dictionary, "parse", ficlPrimitiveParse, 3287 FICL_WORD_DEFAULT); 3288 3289 /* 3290 * query restore-input save-input tib u.r u> unused 3291 * [FICL_VM_STATE_COMPILE] 3292 */ 3293 ficlDictionarySetPrimitive(dictionary, "refill", ficlPrimitiveRefill, 3294 FICL_WORD_DEFAULT); 3295 ficlDictionarySetPrimitive(dictionary, "source-id", 3296 ficlPrimitiveSourceID, FICL_WORD_DEFAULT); 3297 ficlDictionarySetPrimitive(dictionary, "to", ficlPrimitiveToValue, 3298 FICL_WORD_IMMEDIATE); 3299 ficlDictionarySetPrimitive(dictionary, "value", ficlPrimitiveConstant, 3300 FICL_WORD_DEFAULT); 3301 ficlDictionarySetPrimitive(dictionary, "\\", ficlPrimitiveBackslash, 3302 FICL_WORD_IMMEDIATE); 3303 3304 /* 3305 * Environment query values for the Core word set 3306 */ 3307 ficlDictionarySetConstant(environment, "/counted-string", 3308 FICL_COUNTED_STRING_MAX); 3309 ficlDictionarySetConstant(environment, "/hold", FICL_PAD_SIZE); 3310 ficlDictionarySetConstant(environment, "/pad", FICL_PAD_SIZE); 3311 ficlDictionarySetConstant(environment, "address-unit-bits", 8); 3312 ficlDictionarySetConstant(environment, "core", FICL_TRUE); 3313 ficlDictionarySetConstant(environment, "core-ext", FICL_FALSE); 3314 ficlDictionarySetConstant(environment, "floored", FICL_FALSE); 3315 ficlDictionarySetConstant(environment, "max-char", UCHAR_MAX); 3316 ficlDictionarySetConstant(environment, "max-n", LONG_MAX); 3317 ficlDictionarySetConstant(environment, "max-u", ULONG_MAX); 3318 3319 { 3320 ficl2Integer id; 3321 ficlInteger low, high; 3322 3323 low = ULONG_MAX; 3324 high = LONG_MAX; 3325 FICL_2INTEGER_SET(high, low, id); 3326 ficlDictionarySet2Constant(environment, "max-d", id); 3327 high = ULONG_MAX; 3328 FICL_2INTEGER_SET(high, low, id); 3329 ficlDictionarySet2Constant(environment, "max-ud", id); 3330 } 3331 3332 ficlDictionarySetConstant(environment, "return-stack-cells", 3333 FICL_DEFAULT_STACK_SIZE); 3334 ficlDictionarySetConstant(environment, "stack-cells", 3335 FICL_DEFAULT_STACK_SIZE); 3336 3337 /* 3338 * The optional Double-Number word set (partial) 3339 */ 3340 ficlDictionarySetPrimitive(dictionary, "2constant", 3341 ficlPrimitive2Constant, FICL_WORD_IMMEDIATE); 3342 ficlDictionarySetPrimitive(dictionary, "2literal", 3343 ficlPrimitive2LiteralIm, FICL_WORD_IMMEDIATE); 3344 ficlDictionarySetPrimitive(dictionary, "2variable", 3345 ficlPrimitive2Variable, FICL_WORD_IMMEDIATE); 3346 /* 3347 * D+ D- D. D.R D0< D0= D2* D2/ in softcore 3348 * D< D= D>S DABS DMAX DMIN DNEGATE in softcore 3349 * m-star-slash is TODO 3350 * M+ in softcore 3351 */ 3352 3353 /* 3354 * DOUBLE EXT 3355 */ 3356 ficlDictionarySetPrimitive(dictionary, "2rot", 3357 ficlPrimitive2Rot, FICL_WORD_DEFAULT); 3358 ficlDictionarySetPrimitive(dictionary, "2value", 3359 ficlPrimitive2Constant, FICL_WORD_IMMEDIATE); 3360 /* du< in softcore */ 3361 /* 3362 * The optional Exception and Exception Extensions word set 3363 */ 3364 ficlDictionarySetPrimitive(dictionary, "catch", ficlPrimitiveCatch, 3365 FICL_WORD_DEFAULT); 3366 ficlDictionarySetPrimitive(dictionary, "throw", ficlPrimitiveThrow, 3367 FICL_WORD_DEFAULT); 3368 3369 ficlDictionarySetConstant(environment, "exception", FICL_TRUE); 3370 ficlDictionarySetConstant(environment, "exception-ext", FICL_TRUE); 3371 3372 /* 3373 * The optional Locals and Locals Extensions word set 3374 * see softcore.c for implementation of locals| 3375 */ 3376 #if FICL_WANT_LOCALS 3377 ficlDictionarySetPrimitive(dictionary, "doLocal", 3378 ficlPrimitiveDoLocalIm, FICL_WORD_COMPILE_ONLY_IMMEDIATE); 3379 ficlDictionarySetPrimitive(dictionary, "(local)", 3380 ficlPrimitiveLocalParen, FICL_WORD_COMPILE_ONLY); 3381 ficlDictionarySetPrimitive(dictionary, "(2local)", 3382 ficlPrimitive2LocalParen, FICL_WORD_COMPILE_ONLY); 3383 3384 ficlDictionarySetConstant(environment, "locals", FICL_TRUE); 3385 ficlDictionarySetConstant(environment, "locals-ext", FICL_TRUE); 3386 ficlDictionarySetConstant(environment, "#locals", FICL_MAX_LOCALS); 3387 #endif 3388 3389 /* 3390 * The optional Memory-Allocation word set 3391 */ 3392 3393 ficlDictionarySetPrimitive(dictionary, "allocate", 3394 ficlPrimitiveAllocate, FICL_WORD_DEFAULT); 3395 ficlDictionarySetPrimitive(dictionary, "free", ficlPrimitiveFree, 3396 FICL_WORD_DEFAULT); 3397 ficlDictionarySetPrimitive(dictionary, "resize", ficlPrimitiveResize, 3398 FICL_WORD_DEFAULT); 3399 3400 ficlDictionarySetConstant(environment, "memory-alloc", FICL_TRUE); 3401 3402 /* 3403 * The optional Search-Order word set 3404 */ 3405 ficlSystemCompileSearch(system); 3406 3407 /* 3408 * The optional Programming-Tools and Programming-Tools 3409 * Extensions word set 3410 */ 3411 ficlSystemCompileTools(system); 3412 3413 /* 3414 * The optional File-Access and File-Access Extensions word set 3415 */ 3416 #if FICL_WANT_FILE 3417 ficlSystemCompileFile(system); 3418 #endif 3419 3420 /* 3421 * Ficl extras 3422 */ 3423 ficlDictionarySetPrimitive(dictionary, ".ver", ficlPrimitiveVersion, 3424 FICL_WORD_DEFAULT); 3425 ficlDictionarySetPrimitive(dictionary, ">name", ficlPrimitiveToName, 3426 FICL_WORD_DEFAULT); 3427 ficlDictionarySetPrimitive(dictionary, "add-parse-step", 3428 ficlPrimitiveAddParseStep, FICL_WORD_DEFAULT); 3429 ficlDictionarySetPrimitive(dictionary, "body>", ficlPrimitiveFromBody, 3430 FICL_WORD_DEFAULT); 3431 ficlDictionarySetPrimitive(dictionary, "compile-only", 3432 ficlPrimitiveCompileOnly, FICL_WORD_DEFAULT); 3433 ficlDictionarySetPrimitive(dictionary, "endif", ficlPrimitiveEndifCoIm, 3434 FICL_WORD_COMPILE_ONLY_IMMEDIATE); 3435 ficlDictionarySetPrimitive(dictionary, "last-word", 3436 ficlPrimitiveLastWord, FICL_WORD_DEFAULT); 3437 ficlDictionarySetPrimitive(dictionary, "hash", ficlPrimitiveHash, 3438 FICL_WORD_DEFAULT); 3439 ficlDictionarySetPrimitive(dictionary, "objectify", 3440 ficlPrimitiveSetObjectFlag, FICL_WORD_DEFAULT); 3441 ficlDictionarySetPrimitive(dictionary, "?object", 3442 ficlPrimitiveIsObject, FICL_WORD_DEFAULT); 3443 ficlDictionarySetPrimitive(dictionary, "parse-word", 3444 ficlPrimitiveParseNoCopy, FICL_WORD_DEFAULT); 3445 ficlDictionarySetPrimitive(dictionary, "sfind", ficlPrimitiveSFind, 3446 FICL_WORD_DEFAULT); 3447 ficlDictionarySetPrimitive(dictionary, "sliteral", 3448 ficlPrimitiveSLiteralCoIm, FICL_WORD_COMPILE_ONLY_IMMEDIATE); 3449 ficlDictionarySetPrimitive(dictionary, "sprintf", ficlPrimitiveSprintf, 3450 FICL_WORD_DEFAULT); 3451 ficlDictionarySetPrimitive(dictionary, "strlen", ficlPrimitiveStrlen, 3452 FICL_WORD_DEFAULT); 3453 ficlDictionarySetPrimitive(dictionary, "x.", ficlPrimitiveHexDot, 3454 FICL_WORD_DEFAULT); 3455 #if FICL_WANT_USER 3456 ficlDictionarySetPrimitive(dictionary, "user", ficlPrimitiveUser, 3457 FICL_WORD_DEFAULT); 3458 #endif 3459 3460 /* 3461 * internal support words 3462 */ 3463 interpret = ficlDictionarySetPrimitive(dictionary, "interpret", 3464 ficlPrimitiveInterpret, FICL_WORD_DEFAULT); 3465 ficlDictionarySetPrimitive(dictionary, "lookup", ficlPrimitiveLookup, 3466 FICL_WORD_DEFAULT); 3467 ficlDictionarySetPrimitive(dictionary, "(parse-step)", 3468 ficlPrimitiveParseStepParen, FICL_WORD_DEFAULT); 3469 system->exitInnerWord = ficlDictionarySetPrimitive(dictionary, 3470 "exit-inner", ficlPrimitiveExitInner, FICL_WORD_DEFAULT); 3471 3472 /* 3473 * Set constants representing the internal instruction words 3474 * If you want all of 'em, turn that "#if 0" to "#if 1". 3475 * By default you only get the numbers (fi0, fiNeg1, etc). 3476 */ 3477 #define FICL_TOKEN(token, description) \ 3478 ficlDictionarySetConstant(dictionary, #token, token); 3479 #if 0 3480 #define FICL_INSTRUCTION_TOKEN(token, description, flags) \ 3481 ficlDictionarySetConstant(dictionary, #token, token); 3482 #else 3483 #define FICL_INSTRUCTION_TOKEN(token, description, flags) 3484 #endif /* 0 */ 3485 #include "ficltokens.h" 3486 #undef FICL_TOKEN 3487 #undef FICL_INSTRUCTION_TOKEN 3488 3489 /* 3490 * Set up system's outer interpreter loop - maybe this should 3491 * be in initSystem? 3492 */ 3493 system->interpreterLoop[0] = interpret; 3494 system->interpreterLoop[1] = (ficlWord *)ficlInstructionBranchParen; 3495 system->interpreterLoop[2] = (ficlWord *)(void *)(-2); 3496 3497 FICL_SYSTEM_ASSERT(system, 3498 ficlDictionaryCellsAvailable(dictionary) > 0); 3499 } 3500