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