|
|
1.1 ! root 1: \ tag: bootstrap of basic forth words ! 2: \ ! 3: \ Copyright (C) 2003-2005 Stefan Reinauer, Patrick Mauritz ! 4: \ ! 5: \ See the file "COPYING" for further information about ! 6: \ the copyright and warranty status of this work. ! 7: \ ! 8: ! 9: \ ! 10: \ this file contains almost all forth words described ! 11: \ by the open firmware user interface. Some more complex ! 12: \ parts are found in seperate files (memory management, ! 13: \ vocabulary support) ! 14: \ ! 15: ! 16: \ ! 17: \ often used constants (reduces dictionary size) ! 18: \ ! 19: ! 20: 1 constant 1 ! 21: 2 constant 2 ! 22: 3 constant 3 ! 23: -1 constant -1 ! 24: 0 constant 0 ! 25: ! 26: 0 value my-self ! 27: ! 28: \ ! 29: \ 7.3.5.1 Numeric-base control ! 30: \ ! 31: ! 32: : decimal 10 base ! ; ! 33: : hex 16 base ! ; ! 34: : octal 8 base ! ; ! 35: hex ! 36: ! 37: \ ! 38: \ vocabulary words ! 39: \ ! 40: ! 41: variable current forth-last current ! ! 42: ! 43: : last ! 44: current @ ! 45: ; ! 46: ! 47: variable #order 0 #order ! ! 48: ! 49: defer context ! 50: 0 value vocabularies? ! 51: ! 52: \ ! 53: \ 7.3.7 Flag constants ! 54: \ ! 55: ! 56: 1 1 = constant true ! 57: 0 1 = constant false ! 58: ! 59: \ ! 60: \ 7.3.9.2.2 Immediate words (part 1) ! 61: \ ! 62: ! 63: : (immediate) ( xt -- ) ! 64: 1 - dup c@ 1 or swap c! ! 65: ; ! 66: ! 67: : (compile-only) ! 68: 1 - dup c@ 2 or swap c! ! 69: ; ! 70: ! 71: : immediate ! 72: last @ (immediate) ! 73: ; ! 74: ! 75: : compile-only ! 76: last @ (compile-only) ! 77: ; ! 78: ! 79: : flags? ( xt -- flags ) ! 80: /n /c + - c@ 7f and ! 81: ; ! 82: ! 83: : immediate? ( xt -- true|false ) ! 84: flags? 1 and 1 = ! 85: ; ! 86: ! 87: : compile-only? ( xt -- true|false ) ! 88: flags? 2 and 2 = ! 89: ; ! 90: ! 91: : [ 0 state ! ; compile-only ! 92: : ] -1 state ! ; ! 93: ! 94: ! 95: ! 96: \ ! 97: \ 7.3.9.2.1 Data space allocation ! 98: \ ! 99: ! 100: : allot here + here! ; ! 101: : , here /n allot ! ; ! 102: : c, here /c allot c! ; ! 103: ! 104: : align ! 105: /n here /n 1 - and - \ how many bytes to next alignment ! 106: /n 1 - and allot \ mask out everything that is bigger ! 107: ; \ than cellsize-1 ! 108: ! 109: : null-align ! 110: here dup align here swap - 0 fill ! 111: ; ! 112: ! 113: : w, ! 114: here 1 and allot \ if here is not even, we have to align. ! 115: here /w allot w! ! 116: ; ! 117: ! 118: : l, ! 119: /l here /l 1 - and - \ same as in align, with /l ! 120: /l 1 - and \ if it's /l we are already aligned. ! 121: allot ! 122: here /l allot l! ! 123: ; ! 124: ! 125: ! 126: \ ! 127: \ 7.3.6 comparison operators (part 1) ! 128: \ ! 129: ! 130: : <> = invert ; ! 131: ! 132: ! 133: \ ! 134: \ 7.3.9.2.4 Miscellaneous dictionary (part 1) ! 135: \ ! 136: ! 137: : (to) ( xt-new xt-defer -- ) ! 138: /n + ! ! 139: ; ! 140: ! 141: : >body ( xt -- a-addr ) /n 1 lshift + ; ! 142: : body> ( a-addr -- xt ) /n 1 lshift - ; ! 143: ! 144: : reveal latest @ last ! ; ! 145: : recursive reveal ; immediate ! 146: : recurse latest @ /n + , ; immediate ! 147: ! 148: : noop ; ! 149: ! 150: defer environment? ! 151: : no-environment? ! 152: 2drop false ! 153: ; ! 154: ! 155: ['] no-environment? ['] environment? (to) ! 156: ! 157: ! 158: \ ! 159: \ 7.3.8.1 Conditional branches ! 160: \ ! 161: ! 162: \ A control stack entry is implemented using 2 data stack items ! 163: \ of the form ( addr type ). type can be one of the ! 164: \ following: ! 165: \ 0 - orig ! 166: \ 1 - dest ! 167: \ 2 - do-sys ! 168: ! 169: : resolve-orig here nip over /n + - swap ! ; ! 170: : (if) ['] do?branch , here 0 0 , ; compile-only ! 171: : (then) resolve-orig ; compile-only ! 172: ! 173: variable tmp-comp-depth -1 tmp-comp-depth ! ! 174: variable tmp-comp-buf 0 tmp-comp-buf ! ! 175: ! 176: : setup-tmp-comp ( -- ) ! 177: state @ 0 = (if) ! 178: here tmp-comp-buf @ here! , \ save here and switch to tmp directory ! 179: 1 , \ DOCOL ! 180: depth tmp-comp-depth ! \ save control depth ! 181: ] ! 182: (then) ! 183: ; ! 184: ! 185: : execute-tmp-comp ( -- ) ! 186: depth tmp-comp-depth @ = ! 187: (if) ! 188: -1 tmp-comp-depth ! ! 189: ['] (semis) , ! 190: tmp-comp-buf @ ! 191: dup @ here! ! 192: 0 state ! ! 193: /n + execute ! 194: (then) ! 195: ; ! 196: ! 197: : if setup-tmp-comp ['] do?branch , here 0 0 , ; immediate ! 198: : then resolve-orig execute-tmp-comp ; compile-only ! 199: : else ['] dobranch , here 0 0 , 2swap resolve-orig ; compile-only ! 200: ! 201: \ ! 202: \ 7.3.8.3 Conditional loops ! 203: \ ! 204: ! 205: \ some dummy words for see ! 206: : (begin) ; ! 207: : (again) ; ! 208: : (until) ; ! 209: : (while) ; ! 210: : (repeat) ; ! 211: ! 212: \ resolve-dest requires a loop... ! 213: : (resolve-dest) here /n + nip - , ; ! 214: : (resolve-begin) setup-tmp-comp ['] (begin) , here 1 ; immediate ! 215: : (resolve-until) ['] (until) , ['] do?branch , (resolve-dest) execute-tmp-comp ; compile-only ! 216: ! 217: : resolve-dest ( dest origN ... orig ) ! 218: 2 >r ! 219: (resolve-begin) ! 220: \ Find topmost control stack entry with a type of 1 (dest) ! 221: r> dup dup pick 1 = if ! 222: \ Move it to the top ! 223: roll ! 224: swap 1 - roll ! 225: \ Resolve it ! 226: (resolve-dest) ! 227: 1 \ force exit ! 228: else ! 229: drop ! 230: 2 + >r ! 231: 0 ! 232: then ! 233: (resolve-until) ! 234: ; ! 235: ! 236: : begin ! 237: setup-tmp-comp ! 238: ['] (begin) , ! 239: here ! 240: 1 ! 241: ; immediate ! 242: ! 243: : again ! 244: ['] (again) , ! 245: ['] dobranch , ! 246: resolve-dest ! 247: execute-tmp-comp ! 248: ; compile-only ! 249: ! 250: : until ! 251: ['] (until) , ! 252: ['] do?branch , ! 253: resolve-dest ! 254: execute-tmp-comp ! 255: ; compile-only ! 256: ! 257: : while ! 258: setup-tmp-comp ! 259: ['] (while) , ! 260: ['] do?branch , ! 261: here 0 0 , 2swap ! 262: ; immediate ! 263: ! 264: : repeat ! 265: ['] (repeat) , ! 266: ['] dobranch , ! 267: resolve-dest resolve-orig ! 268: execute-tmp-comp ! 269: ; compile-only ! 270: ! 271: ! 272: \ ! 273: \ 7.3.8.4 Counted loops ! 274: \ ! 275: ! 276: variable leaves 0 leaves ! ! 277: ! 278: : resolve-loop ! 279: leaves @ ! 280: begin ! 281: ?dup ! 282: while ! 283: dup @ \ leaves -- leaves *leaves ) ! 284: swap \ -- *leaves leaves ) ! 285: here over - \ -- *leaves leaves here-leaves ! 286: swap ! \ -- *leaves ! 287: repeat ! 288: here nip - , ! 289: leaves ! ! 290: ; ! 291: ! 292: : do ! 293: setup-tmp-comp ! 294: leaves @ ! 295: here 2 ! 296: ['] (do) , ! 297: 0 leaves ! ! 298: ; immediate ! 299: ! 300: : ?do ! 301: setup-tmp-comp ! 302: leaves @ ! 303: ['] (?do) , ! 304: here 2 ! 305: here leaves ! ! 306: 0 , ! 307: ; immediate ! 308: ! 309: : loop ! 310: ['] (loop) , ! 311: resolve-loop ! 312: execute-tmp-comp ! 313: ; immediate ! 314: ! 315: : +loop ! 316: ['] (+loop) , ! 317: resolve-loop ! 318: execute-tmp-comp ! 319: ; immediate ! 320: ! 321: ! 322: \ Using primitive versions of i and j ! 323: \ speeds up loops by 300% ! 324: \ : i r> r@ swap >r ; ! 325: \ : j r> r> r> r@ -rot >r >r swap >r ; ! 326: ! 327: : unloop r> r> r> 2drop >r ; ! 328: ! 329: : leave ! 330: ['] unloop , ! 331: ['] dobranch , ! 332: leaves @ ! 333: here leaves ! ! 334: , ! 335: ; immediate ! 336: ! 337: : ?leave if leave then ; ! 338: ! 339: \ ! 340: \ 7.3.8.2 Case statement ! 341: \ ! 342: ! 343: : case ! 344: setup-tmp-comp ! 345: 0 ! 346: ; immediate ! 347: ! 348: : endcase ! 349: ['] drop , ! 350: 0 ?do ! 351: ['] then execute ! 352: loop ! 353: execute-tmp-comp ! 354: ; immediate ! 355: ! 356: : of ! 357: 1 + >r ! 358: ['] over , ! 359: ['] = , ! 360: ['] if execute ! 361: ['] drop , ! 362: r> ! 363: ; immediate ! 364: ! 365: : endof ! 366: >r ! 367: ['] else execute ! 368: r> ! 369: ; immediate ! 370: ! 371: \ ! 372: \ 7.3.8.5 Other control flow commands ! 373: \ ! 374: ! 375: : exit r> drop ; ! 376: ! 377: ! 378: \ ! 379: \ 7.3.4.3 ASCII constants (part 1) ! 380: \ ! 381: ! 382: 20 constant bl ! 383: 07 constant bell ! 384: 08 constant bs ! 385: 0d constant carret ! 386: 0a constant linefeed ! 387: ! 388: ! 389: \ ! 390: \ 7.3.1.1 - stack duplication ! 391: \ ! 392: : tuck swap over ; ! 393: : 3dup 2 pick 2 pick 2 pick ; ! 394: ! 395: \ ! 396: \ 7.3.1.2 - stack removal ! 397: \ ! 398: : clear 0 depth! ; ! 399: : 3drop 2drop drop ; ! 400: ! 401: \ ! 402: \ 7.3.1.3 - stack rearrangement ! 403: \ ! 404: ! 405: : 2rot >r >r 2swap r> r> 2swap ; ! 406: ! 407: \ ! 408: \ 7.3.1.4 - return stack ! 409: \ ! 410: ! 411: \ Note: these words are not part of the official OF specification, however ! 412: \ they are part of the ANSI DPANS94 core extensions (see section 6.2) and ! 413: \ so this seems an appropriate place for them. ! 414: : 2>r r> -rot swap >r >r >r ; ! 415: : 2r> r> r> r> rot >r swap ; ! 416: : 2r@ r> r> r> 2dup >r >r rot >r swap ; ! 417: ! 418: \ ! 419: \ 7.3.2.1 - single precision integer arithmetic (part 1) ! 420: \ ! 421: ! 422: : u/mod 0 swap mu/mod drop ; ! 423: : 1+ 1 + ; ! 424: : 1- 1 - ; ! 425: : 2+ 2 + ; ! 426: : 2- 2 - ; ! 427: : even 1+ -2 and ; ! 428: : bounds over + swap ; ! 429: ! 430: \ ! 431: \ 7.3.2.2 bitwise logical operators ! 432: \ ! 433: : << lshift ; ! 434: : >> rshift ; ! 435: : 2* 1 lshift ; ! 436: : u2/ 1 rshift ; ! 437: : 2/ 1 >>a ; ! 438: : not invert ; ! 439: ! 440: \ ! 441: \ 7.3.2.3 double number arithmetic ! 442: \ ! 443: ! 444: : s>d dup 0 < ; ! 445: : dnegate 0 0 2swap d- ; ! 446: : dabs dup 0 < if dnegate then ; ! 447: : um/mod mu/mod drop ; ! 448: ! 449: \ symmetric division ! 450: : sm/rem ( d n -- rem quot ) ! 451: over >r >r dabs r@ abs um/mod r> 0 < ! 452: if ! 453: negate ! 454: then ! 455: r> 0 < if ! 456: negate swap negate swap ! 457: then ! 458: ; ! 459: ! 460: \ floored division ! 461: : fm/mod ( d n -- rem quot ) ! 462: dup >r 2dup xor 0 < >r sm/rem over 0 <> r> and if ! 463: 1 - swap r> + swap exit ! 464: then ! 465: r> drop ! 466: ; ! 467: ! 468: \ ! 469: \ 7.3.2.1 - single precision integer arithmetic (part 2) ! 470: \ ! 471: ! 472: : */mod ( n1 n2 n3 -- quot rem ) >r m* r> fm/mod ; ! 473: : */ ( n1 n2 n3 -- n1*n2/n3 ) */mod nip ; ! 474: : /mod >r s>d r> fm/mod ; ! 475: : mod /mod drop ; ! 476: : / /mod nip ; ! 477: ! 478: ! 479: \ ! 480: \ 7.3.2.4 Data type conversion ! 481: \ ! 482: ! 483: : lwsplit ( quad -- w.lo w.hi ) ! 484: dup ffff and swap 10 rshift ffff and ! 485: ; ! 486: ! 487: : wbsplit ( word -- b.lo b.hi ) ! 488: dup ff and swap 8 rshift ff and ! 489: ; ! 490: ! 491: : lbsplit ( quad -- b.lo b2 b3 b.hi ) ! 492: lwsplit swap wbsplit rot wbsplit ! 493: ; ! 494: ! 495: : bwjoin ( b.lo b.hi -- word ) ! 496: ff and 8 lshift swap ff and or ! 497: ; ! 498: ! 499: : wljoin ( w.lo w.hi -- quad ) ! 500: ffff and 10 lshift swap ffff and or ! 501: ; ! 502: ! 503: : bljoin ( b.lo b2 b3 b.hi -- quad ) ! 504: bwjoin -rot bwjoin swap wljoin ! 505: ; ! 506: ! 507: : wbflip ( word -- word ) \ flips bytes in a word ! 508: dup 8 rshift ff and swap ff and bwjoin ! 509: ; ! 510: ! 511: : lwflip ( q1 -- q2 ) ! 512: dup 10 rshift ffff and swap ffff and wljoin ! 513: ; ! 514: ! 515: : lbflip ( q1 -- q2 ) ! 516: dup 10 rshift ffff and wbflip swap ffff and wbflip wljoin ! 517: ; ! 518: ! 519: \ ! 520: \ 7.3.2.5 address arithmetic ! 521: \ ! 522: ! 523: : /c* /c * ; ! 524: : /w* /w * ; ! 525: : /l* /l * ; ! 526: : /n* /n * ; ! 527: : ca+ /c* + ; ! 528: : wa+ /w* + ; ! 529: : la+ /l* + ; ! 530: : na+ /n* + ; ! 531: : ca1+ /c + ; ! 532: : wa1+ /w + ; ! 533: : la1+ /l + ; ! 534: : na1+ /n + ; ! 535: : aligned /n 1- + /n negate and ; ! 536: : char+ ca1+ ; ! 537: : cell+ na1+ ; ! 538: : chars /c* ; ! 539: : cells /n* ; ! 540: /n constant cell ! 541: ! 542: \ ! 543: \ 7.3.6 Comparison operators ! 544: \ ! 545: ! 546: : <= > not ; ! 547: : >= < not ; ! 548: : 0= 0 = ; ! 549: : 0<= 0 <= ; ! 550: : 0< 0 < ; ! 551: : 0<> 0 <> ; ! 552: : 0> 0 > ; ! 553: : 0>= 0 >= ; ! 554: : u<= u> not ; ! 555: : u>= u< not ; ! 556: : within >r over > swap r> >= or not ; ! 557: : between 1 + within ; ! 558: ! 559: \ ! 560: \ 7.3.3.1 Memory access ! 561: \ ! 562: ! 563: : 2@ dup cell+ @ swap @ ; ! 564: : 2! dup >r ! r> cell+ ! ; ! 565: ! 566: : <w@ w@ dup 8000 >= if 10000 - then ; ! 567: ! 568: : comp ( str1 str2 len -- 0|1|-1 ) ! 569: >r 0 -rot r> ! 570: bounds ?do ! 571: dup c@ i c@ - dup if ! 572: < if 1 else -1 then swap leave ! 573: then ! 574: drop ca1+ ! 575: loop ! 576: drop ! 577: ; ! 578: ! 579: \ compare two string ! 580: ! 581: : $= ( str1 len1 str2 len2 -- true|false ) ! 582: rot ( str1 str2 len2 len1 ) ! 583: over ( str1 str2 len2 len1 len2 ) ! 584: <> if ( str1 str2 len2 ) ! 585: 3drop ! 586: false ! 587: else ( str1 str2 len2 ) ! 588: comp ! 589: 0= ! 590: then ! 591: ; ! 592: ! 593: \ : +! tuck @ + swap ! ; ! 594: : off false swap ! ; ! 595: : on true swap ! ; ! 596: : blank bl fill ; ! 597: : erase 0 fill ; ! 598: : wbflips ( waddr len -- ) ! 599: bounds do i w@ wbflip i w! /w +loop ! 600: ; ! 601: ! 602: : lwflips ( qaddr len -- ) ! 603: bounds do i l@ lwflip i l! /l +loop ! 604: ; ! 605: ! 606: : lbflips ( qaddr len -- ) ! 607: bounds do i l@ lbflip i l! /l +loop ! 608: ; ! 609: ! 610: ! 611: \ ! 612: \ 7.3.8.6 Error handling (part 1) ! 613: \ ! 614: ! 615: variable catchframe ! 616: 0 catchframe ! ! 617: ! 618: : catch ! 619: my-self >r ! 620: depth >r ! 621: catchframe @ >r ! 622: rdepth catchframe ! ! 623: execute ! 624: r> catchframe ! ! 625: r> r> 2drop 0 ! 626: ; ! 627: ! 628: : throw ! 629: ?dup if ! 630: catchframe @ rdepth! ! 631: r> catchframe ! ! 632: r> swap >r depth! ! 633: drop r> ! 634: r> ['] my-self (to) ! 635: then ! 636: ; ! 637: ! 638: \ ! 639: \ 7.3.3.2 memory allocation ! 640: \ ! 641: ! 642: include memory.fs ! 643: ! 644: ! 645: \ ! 646: \ 7.3.4.4 Console output (part 1) ! 647: \ ! 648: ! 649: defer emit ! 650: ! 651: : type bounds ?do i c@ emit loop ; ! 652: ! 653: \ this one obviously only works when called ! 654: \ with a forth string as count fetches addr-1. ! 655: \ openfirmware has no such req. therefore it has to go: ! 656: ! 657: \ : type 0 do count emit loop drop ; ! 658: ! 659: ! 660: \ ! 661: \ 7.3.4.1 Text Input ! 662: \ ! 663: ! 664: 0 value source-id ! 665: 0 value ib ! 666: variable #ib 0 #ib ! ! 667: variable >in 0 >in ! ! 668: ! 669: : source ( -- addr len ) ! 670: ib #ib @ ! 671: ; ! 672: ! 673: : /string ( c-addr1 u1 n -- c-addr2 u2 ) ! 674: tuck - -rot + swap ! 675: ; ! 676: ! 677: ! 678: \ ! 679: \ pockets implementation for 7.3.4.1 ! 680: ! 681: 100 constant pocketsize ! 682: 4 constant numpockets ! 683: variable pockets 0 pockets ! ! 684: variable whichpocket 0 whichpocket ! ! 685: ! 686: \ allocate 4 pockets to begin with ! 687: : init-pockets ( -- ) ! 688: pocketsize numpockets * alloc-mem pockets ! ! 689: ; ! 690: ! 691: : pocket ( ?? -- ?? ) ! 692: pocketsize whichpocket @ * ! 693: pockets @ + ! 694: whichpocket @ 1 + numpockets mod ! 695: whichpocket ! ! 696: ; ! 697: ! 698: \ span variable from 7.3.4.2 ! 699: variable span 0 span ! ! 700: ! 701: \ if char is bl then any control character is matched ! 702: : findchar ( str len char -- offs true | false ) ! 703: swap 0 do ! 704: over i + c@ ! 705: over dup bl = if <= else = then if ! 706: 2drop i dup dup leave ! 707: \ i nip nip true exit \ replaces above ! 708: then ! 709: loop ! 710: = ! 711: \ drop drop false ! 712: ; ! 713: ! 714: : parse ( delim text<delim> -- str len ) ! 715: >r \ save delimiter ! 716: ib >in @ + ! 717: span @ >in @ - \ ib+offs len-offset. ! 718: dup 0 < if \ if we are already at the end of the string, return an empty string ! 719: + 0 \ move to end of input string ! 720: r> drop ! 721: exit ! 722: then ! 723: 2dup r> \ ib+offs len-offset ib+offs len-offset delim ! 724: findchar if \ look for the delimiter. ! 725: nip dup 1+ ! 726: else ! 727: dup ! 728: then ! 729: >in +! ! 730: \ dup -1 = if drop 0 then \ workaround for negative length ! 731: ; ! 732: ! 733: : skipws ( -- ) ! 734: ib span @ ( -- ib recvchars ) ! 735: begin ! 736: dup >in @ > if ( -- recvchars>offs ) ! 737: over >in @ + ! 738: c@ bl <= ! 739: else ! 740: false ! 741: then ! 742: while ! 743: 1 >in +! ! 744: repeat ! 745: 2drop ! 746: ; ! 747: ! 748: : parse-word ( < >text< > -- str len ) ! 749: skipws bl parse ! 750: ; ! 751: ! 752: : word ( delim <delims>text<delim> -- pstr ) ! 753: pocket >r parse dup r@ c! bounds r> dup 2swap ! 754: do ! 755: char+ i c@ over c! ! 756: loop ! 757: drop ! 758: ; ! 759: ! 760: : ( 29 parse 2drop ; immediate ! 761: : \ span @ >in ! ; immediate ! 762: ! 763: ! 764: ! 765: \ ! 766: \ 7.3.4.7 String literals ! 767: \ ! 768: ! 769: : ", ! 770: bounds ?do ! 771: i c@ c, ! 772: loop ! 773: ; ! 774: ! 775: : (") ( -- addr len ) ! 776: r> dup ! 777: 2 cells + ( r-addr addr ) ! 778: over cell+ @ ( r-addr addr len ) ! 779: rot over + aligned cell+ >r ( addr len R: r-addr ) ! 780: ; ! 781: ! 782: : handle-text ( temp-addr len -- addr len ) ! 783: state @ if ! 784: ['] (") , dup , ", null-align ! 785: else ! 786: pocket swap ! 787: dup >r ! 788: 0 ?do ! 789: over i + c@ over i + c! ! 790: loop ! 791: nip r> ! 792: then ! 793: ; ! 794: ! 795: : s" ! 796: 22 parse handle-text ! 797: ; immediate ! 798: ! 799: ! 800: ! 801: \ ! 802: \ 7.3.4.4 Console output (part 2) ! 803: \ ! 804: ! 805: : ." ! 806: 22 parse handle-text ! 807: ['] type ! 808: state @ if ! 809: , ! 810: else ! 811: execute ! 812: then ! 813: ; immediate ! 814: ! 815: : .( ! 816: 29 parse handle-text ! 817: ['] type ! 818: state @ if ! 819: , ! 820: else ! 821: execute ! 822: then ! 823: ; immediate ! 824: ! 825: ! 826: ! 827: \ ! 828: \ 7.3.4.8 String manipulation ! 829: \ ! 830: ! 831: : count ( pstr -- str len ) 1+ dup 1- c@ ; ! 832: ! 833: : pack ( str len addr -- pstr ) ! 834: 2dup c! \ store len ! 835: 1+ swap 0 ?do ! 836: over i + c@ over i + c! ! 837: loop nip 1- ! 838: ; ! 839: ! 840: : lcc ( char1 -- char2 ) dup 41 5a between if 20 + then ; ! 841: : upc ( char1 -- char2 ) dup 61 7a between if 20 - then ; ! 842: ! 843: : -trailing ( str len1 -- str len2 ) ! 844: begin ! 845: dup 0<> if \ len != 0 ? ! 846: 2dup 1- + ! 847: c@ bl = ! 848: else ! 849: false ! 850: then ! 851: while ! 852: 1- ! 853: repeat ! 854: ; ! 855: ! 856: ! 857: \ ! 858: \ 7.3.4.5 Output formatting ! 859: \ ! 860: ! 861: : cr linefeed emit ; ! 862: : (cr carret emit ; ! 863: : space bl emit ; ! 864: : spaces 0 ?do space loop ; ! 865: variable #line 0 #line ! ! 866: variable #out 0 #out ! ! 867: ! 868: ! 869: \ ! 870: \ 7.3.9.2.3 Dictionary search ! 871: \ ! 872: ! 873: \ helper functions ! 874: ! 875: : lfa2name ( lfa -- name len ) ! 876: 1- \ skip flag byte ! 877: begin \ skip 0 padding ! 878: 1- dup c@ ?dup ! 879: until ! 880: 7f and \ clear high bit in length ! 881: ! 882: tuck - swap ( ptr-to-len len - name len ) ! 883: ; ! 884: ! 885: : comp-nocase ( str1 str2 len -- true|false ) ! 886: 0 do ! 887: 2dup i + c@ upc ( str1 str2 byteX ) ! 888: swap i + c@ upc ( str1 str2 byte1 byte2 ) ! 889: <> if ! 890: 0 leave ! 891: then ! 892: loop ! 893: if -1 else drop 0 then ! 894: swap drop ! 895: ; ! 896: ! 897: : comp-word ( b-str len lfa -- true | false ) ! 898: lfa2name ( str len str len -- ) ! 899: >r swap r> ( str str len len ) ! 900: over = if ( str str len ) ! 901: comp-nocase ! 902: else ! 903: drop drop drop false \ if len does not match, string does not match ! 904: then ! 905: ; ! 906: ! 907: \ $find is an fcode word, but we place it here since we use it for find. ! 908: ! 909: : find-wordlist ( name-str name-len last -- xt true | name-str name-len false ) ! 910: ! 911: @ >r ! 912: ! 913: begin ! 914: 2dup r@ dup if comp-word dup false = then ! 915: while ! 916: r> @ >r drop ! 917: repeat ! 918: ! 919: r@ if \ successful? ! 920: -rot 2drop r> cell+ swap ! 921: else ! 922: r> drop drop drop false ! 923: then ! 924: ! 925: ; ! 926: ! 927: : $find ( name-str name-len -- xt true | name-str name-len false ) ! 928: vocabularies? if ! 929: #order @ 0 ?do ! 930: i cells context + @ ! 931: find-wordlist ! 932: ?dup if ! 933: unloop exit ! 934: then ! 935: loop ! 936: false ! 937: else ! 938: forth-last find-wordlist ! 939: then ! 940: ; ! 941: ! 942: \ look up a word in the current wordlist ! 943: : $find1 ( name-str name-len -- xt true | name-str name-len false ) ! 944: vocabularies? if ! 945: current @ ! 946: else ! 947: forth-last ! 948: then ! 949: find-wordlist ! 950: ; ! 951: ! 952: ! 953: : ' ! 954: parse-word $find 0= if ! 955: type 3a emit -13 throw ! 956: then ! 957: ; ! 958: ! 959: : ['] ! 960: parse-word $find 0= if ! 961: type 3a emit -13 throw ! 962: then ! 963: state @ if ! 964: ['] (lit) , , ! 965: then ! 966: ; immediate ! 967: ! 968: : find ( pstr -- xt n | pstr false ) ! 969: dup count $find \ pstr xt true | pstr name-str name-len false ! 970: if ! 971: nip true ! 972: over immediate? if ! 973: negate \ immediate returns 1 ! 974: then ! 975: else ! 976: 2drop false ! 977: then ! 978: ; ! 979: ! 980: ! 981: \ ! 982: \ 7.3.9.2.2 Immediate words (part 2) ! 983: \ ! 984: ! 985: : literal ['] (lit) , , ; immediate ! 986: : compile, , ; immediate ! 987: : compile r> cell+ dup @ , >r ; ! 988: : [compile] ['] ' execute , ; immediate ! 989: ! 990: : postpone ! 991: parse-word $find if ! 992: dup immediate? not if ! 993: ['] (lit) , , ['] , ! 994: then ! 995: , ! 996: else ! 997: s" undefined word " type type cr ! 998: then ! 999: ; immediate ! 1000: ! 1001: ! 1002: \ ! 1003: \ 7.3.9.2.4 Miscellaneous dictionary (part 2) ! 1004: \ ! 1005: ! 1006: variable #instance ! 1007: ! 1008: : instance ( -- ) ! 1009: true #instance ! ! 1010: ; ! 1011: ! 1012: : #instance-base ! 1013: my-self dup if @ then ! 1014: ; ! 1015: ! 1016: : #instance-offs ! 1017: my-self dup if na1+ then ! 1018: ; ! 1019: ! 1020: \ the following instance words are used internally ! 1021: \ to implement variable instantiation. ! 1022: ! 1023: : instance-cfa? ( cfa -- true | false ) ! 1024: b e within \ b,c and d are instance defining words ! 1025: ; ! 1026: ! 1027: : behavior ( xt-defer -- xt ) ! 1028: dup @ instance-cfa? if ! 1029: #instance-base ?dup if ! 1030: swap na1+ @ + @ ! 1031: else ! 1032: 3 /n* + @ ! 1033: then ! 1034: else ! 1035: na1+ @ ! 1036: then ! 1037: ; ! 1038: ! 1039: : (ito) ( xt-new xt-defer -- ) ! 1040: #instance-base ?dup if ! 1041: swap na1+ @ + ! ! 1042: else ! 1043: 3 /n* + ! ! 1044: then ! 1045: ; ! 1046: ! 1047: : to ! 1048: ['] ' execute ! 1049: dup @ instance-cfa? ! 1050: state @ if ! 1051: swap ['] (lit) , , if ['] (ito) else ['] (to) then , ! 1052: else ! 1053: if (ito) else /n + ! then ! 1054: then ! 1055: ; immediate ! 1056: ! 1057: : is ( xt "wordname<>" -- ) ! 1058: parse-word $find if ! 1059: (to) ! 1060: else ! 1061: s" could not find " type type ! 1062: then ! 1063: ; ! 1064: ! 1065: \ ! 1066: \ 7.3.4.2 Console Input ! 1067: \ ! 1068: ! 1069: defer key? ! 1070: defer key ! 1071: ! 1072: : accept ( addr len -- len2 ) ! 1073: tuck 0 do ! 1074: key ! 1075: dup linefeed = if ! 1076: space drop drop drop i 0 leave ! 1077: then ! 1078: dup emit over c! 1 + ! 1079: loop ! 1080: drop ( cr ) ! 1081: ; ! 1082: ! 1083: : expect ( addr len -- ) ! 1084: accept span ! ! 1085: ; ! 1086: ! 1087: ! 1088: \ ! 1089: \ 7.3.4.3 ASCII constants (part 2) ! 1090: \ ! 1091: ! 1092: : handle-lit ! 1093: state @ if ! 1094: 2 = if ! 1095: ['] (lit) , , ! 1096: then ! 1097: ['] (lit) , , ! 1098: else ! 1099: drop ! 1100: then ! 1101: ; ! 1102: ! 1103: : char ! 1104: parse-word 0<> if c@ else s" Unexpected EOL." type cr then ; ! 1105: ; ! 1106: ! 1107: : ascii char 1 handle-lit ; immediate ! 1108: : [char] char 1 handle-lit ; immediate ! 1109: ! 1110: : control ! 1111: char bl 1- and 1 handle-lit ! 1112: ; immediate ! 1113: ! 1114: ! 1115: ! 1116: \ ! 1117: \ 7.3.8.6 Error handling (part 2) ! 1118: \ ! 1119: ! 1120: : abort ! 1121: -1 throw ! 1122: ; ! 1123: ! 1124: : abort" ! 1125: ['] if execute ! 1126: 22 parse handle-text ! 1127: ['] type , ! 1128: ['] (lit) , ! 1129: -2 , ! 1130: ['] throw , ! 1131: ['] then execute ! 1132: ; compile-only ! 1133: ! 1134: \ ! 1135: \ 7.5.3.1 Dictionary search ! 1136: \ ! 1137: ! 1138: \ this does not belong here, but its nice for testing ! 1139: ! 1140: : words ( -- ) ! 1141: last ! 1142: begin @ ! 1143: ?dup while ! 1144: dup lfa2name ! 1145: ! 1146: \ Don't print spaces for headerless words ! 1147: dup if ! 1148: type space ! 1149: else ! 1150: type ! 1151: then ! 1152: ! 1153: repeat ! 1154: cr ! 1155: ; ! 1156: ! 1157: \ ! 1158: \ 7.3.5.4 Numeric output primitives ! 1159: \ ! 1160: ! 1161: false value capital-hex? ! 1162: ! 1163: : pad ( -- addr ) here 100 + aligned ; ! 1164: ! 1165: : todigit ( num -- ascii ) ! 1166: dup 9 > if ! 1167: capital-hex? not if ! 1168: 20 + ! 1169: then ! 1170: 7 + ! 1171: then ! 1172: 30 + ! 1173: ; ! 1174: ! 1175: : <# pad dup ! ; ! 1176: : hold pad dup @ 1- tuck swap ! c! ; ! 1177: : sign ! 1178: 0< if ! 1179: 2d hold ! 1180: then ! 1181: ; ! 1182: ! 1183: : # base @ mu/mod rot todigit hold ; ! 1184: : #s begin # 2dup or 0= until ; ! 1185: : #> 2drop pad dup @ tuck - ; ! 1186: : (.) <# dup >r abs 0 #s r> sign #> ; ! 1187: ! 1188: : u# base @ u/mod swap todigit hold ; ! 1189: : u#s begin u# dup 0= until ; ! 1190: : u#> 0 #> ; ! 1191: : (u.) <# u#s u#> ; ! 1192: ! 1193: \ ! 1194: \ 7.3.5.3 Numeric output ! 1195: \ ! 1196: ! 1197: : . (.) type space ; ! 1198: : s. . ; ! 1199: : u. (u.) type space ; ! 1200: : .r swap (.) rot 2dup < if over - spaces else drop then type ; ! 1201: : u.r swap (u.) rot 2dup < if over - spaces else drop then type ; ! 1202: : .d base @ swap decimal . base ! ; ! 1203: : .h base @ swap hex . base ! ; ! 1204: ! 1205: : .s ! 1206: 3c emit depth dup (.) type 3e emit space ! 1207: 0 ! 1208: ?do ! 1209: depth i - 1- pick . ! 1210: loop ! 1211: cr ! 1212: ; ! 1213: ! 1214: \ ! 1215: \ 7.3.5.2 Numeric input ! 1216: \ ! 1217: ! 1218: : digit ( char base -- n true | char false ) ! 1219: swap dup upc dup ! 1220: 41 5a ( A - Z ) between if ! 1221: 7 - ! 1222: else ! 1223: dup 39 > if \ protect from : and ; ! 1224: -rot 2drop false exit ! 1225: then ! 1226: then ! 1227: ! 1228: 30 ( number 0 ) - rot over swap 0 swap within if ! 1229: nip true ! 1230: else ! 1231: drop false ! 1232: then ! 1233: ; ! 1234: ! 1235: : >number ! 1236: begin ! 1237: dup ! 1238: while ! 1239: over c@ base @ digit 0= if ! 1240: drop exit ! 1241: then >r 2swap r> swap base @ um* drop rot base @ um* d+ 2swap ! 1242: 1 /string ! 1243: repeat ! 1244: ; ! 1245: ! 1246: : numdelim? ! 1247: dup 2e = swap 2c = or ! 1248: ; ! 1249: ! 1250: ! 1251: : $dnumber? ! 1252: 0 0 2swap dup 0= if ! 1253: 2drop 2drop 0 exit ! 1254: then over c@ 2d = dup >r negate /string begin ! 1255: >number dup 1 > ! 1256: while ! 1257: over c@ numdelim? 0= if ! 1258: 2drop 2drop r> drop 0 exit ! 1259: then 1 /string ! 1260: repeat if ! 1261: c@ 2e = if ! 1262: true ! 1263: else ! 1264: 2drop r> drop 0 exit ! 1265: then ! 1266: else ! 1267: drop false ! 1268: then over or if ! 1269: r> if ! 1270: dnegate ! 1271: then 2 ! 1272: else ! 1273: drop r> if ! 1274: negate ! 1275: then 1 ! 1276: then ! 1277: ; ! 1278: ! 1279: ! 1280: : $number ( ) ! 1281: $dnumber? ! 1282: case ! 1283: 0 of true endof ! 1284: 1 of false endof ! 1285: 2 of drop false endof ! 1286: endcase ! 1287: ; ! 1288: ! 1289: : d# ! 1290: parse-word ! 1291: base @ >r ! 1292: ! 1293: decimal ! 1294: ! 1295: $number if ! 1296: s" illegal number" type cr 0 ! 1297: then ! 1298: r> base ! ! 1299: 1 handle-lit ! 1300: ; immediate ! 1301: ! 1302: : h# ! 1303: parse-word ! 1304: base @ >r ! 1305: ! 1306: hex ! 1307: ! 1308: $number if ! 1309: s" illegal number" type cr 0 ! 1310: then ! 1311: r> base ! ! 1312: 1 handle-lit ! 1313: ; immediate ! 1314: ! 1315: : o# ! 1316: parse-word ! 1317: base @ >r ! 1318: ! 1319: octal ! 1320: ! 1321: $number if ! 1322: s" illegal number" type cr 0 ! 1323: then ! 1324: r> base ! ! 1325: 1 handle-lit ! 1326: ; immediate ! 1327: ! 1328: ! 1329: \ ! 1330: \ 7.3.4.7 String Literals (part 2) ! 1331: \ ! 1332: ! 1333: : " ! 1334: pocket dup ! 1335: begin ! 1336: span @ >in @ > if ! 1337: 22 parse >r ( pocket pocket str R: len ) ! 1338: over r@ move \ copy string ! 1339: r> + ( pocket nextdest ) ! 1340: ib >in @ + c@ ( pocket nextdest nexchar ) ! 1341: 1 >in +! ! 1342: 28 = \ is nextchar a parenthesis? ! 1343: span @ >in @ > \ more input? ! 1344: and ! 1345: else ! 1346: false ! 1347: then ! 1348: while ! 1349: 29 parse \ parse everything up to the next ')' ! 1350: bounds ?do ! 1351: i c@ 10 digit if ! 1352: i 1+ c@ 10 digit if ! 1353: swap 4 lshift or ! 1354: else ! 1355: drop ! 1356: then ! 1357: over c! 1+ ! 1358: 2 ! 1359: else ! 1360: drop 1 ! 1361: then ! 1362: +loop ! 1363: repeat ! 1364: over - ! 1365: handle-text ! 1366: ; immediate ! 1367: ! 1368: ! 1369: \ ! 1370: \ 7.3.3.1 Memory Access (part 2) ! 1371: \ ! 1372: ! 1373: : dump ( addr len -- ) ! 1374: over + swap ! 1375: cr ! 1376: do i u. space ! 1377: 10 0 do ! 1378: j i + c@ ! 1379: dup 10 / todigit emit ! 1380: 10 mod todigit emit ! 1381: space ! 1382: i 7 = if space then ! 1383: loop ! 1384: 3 spaces ! 1385: 10 0 do ! 1386: j i + c@ ! 1387: dup 20 < if drop 2e then \ non-printables as dots? ! 1388: emit ! 1389: loop ! 1390: cr ! 1391: 10 +loop ! 1392: ; ! 1393: ! 1394: ! 1395: ! 1396: \ ! 1397: \ 7.3.9.1 Defining words ! 1398: \ ! 1399: ! 1400: : header ( name len -- ) ! 1401: dup if \ might be a noname... ! 1402: 2dup $find1 if ! 1403: drop 2dup type s" isn't unique." type cr ! 1404: else ! 1405: 2drop ! 1406: then ! 1407: then ! 1408: null-align ! 1409: dup -rot ", 80 or c, \ write name and len ! 1410: here /n 1- and 0= if 0 c, then \ pad and space for flags ! 1411: null-align ! 1412: 80 here 1- c! \ write flags byte ! 1413: here last @ , latest ! \ write backlink and set latest ! 1414: ; ! 1415: ! 1416: ! 1417: : : ! 1418: parse-word header ! 1419: 1 , ] ! 1420: ; ! 1421: ! 1422: : :noname ! 1423: 0 0 header ! 1424: here ! 1425: 1 , ] ! 1426: ; ! 1427: ! 1428: : ; ! 1429: ['] (semis) , reveal ['] [ execute ! 1430: ; immediate ! 1431: ! 1432: : constant ! 1433: parse-word header ! 1434: 3 , , \ compile DOCON and value ! 1435: reveal ! 1436: ; ! 1437: ! 1438: 0 value active-package ! 1439: : instance, ( size -- ) ! 1440: \ first word of the device node holds the instance size ! 1441: dup active-package @ dup rot + active-package ! ! 1442: , , \ offset size ! 1443: ; ! 1444: ! 1445: : instance? ( -- flag ) ! 1446: #instance @ dup if ! 1447: false #instance ! ! 1448: then ! 1449: ; ! 1450: ! 1451: : value ! 1452: parse-word header ! 1453: instance? if ! 1454: /n b , instance, , \ DOIVAL ! 1455: else ! 1456: 3 , , ! 1457: then ! 1458: reveal ! 1459: ; ! 1460: ! 1461: : variable ! 1462: parse-word header ! 1463: instance? if ! 1464: /n c , instance, 0 , ! 1465: else ! 1466: 4 , 0 , ! 1467: then ! 1468: reveal ! 1469: ; ! 1470: ! 1471: : $buffer: ( size str len -- where ) ! 1472: header ! 1473: instance? if ! 1474: /n over /n 1- and - /n 1- and + \ align buffer size ! 1475: dup c , instance, \ DOIVAR ! 1476: else ! 1477: 4 , ! 1478: then ! 1479: here swap ! 1480: 2dup 0 fill \ zerofill ! 1481: allot ! 1482: reveal ! 1483: ; ! 1484: ! 1485: : buffer: ( size -- ) ! 1486: parse-word $buffer: drop ! 1487: ; ! 1488: ! 1489: : (undefined-defer) ( -- ) ! 1490: \ XXX: this does not work with behavior ... execute ! 1491: r@ 2 cells - lfa2name ! 1492: s" undefined defer word " type type cr ; ! 1493: ! 1494: : (undefined-idefer) ( -- ) ! 1495: s" undefined idefer word " type cr ; ! 1496: ! 1497: : defer ( new-name< > -- ) ! 1498: parse-word header ! 1499: instance? if ! 1500: 2 /n* d , instance, \ DOIDEFER ! 1501: ['] (undefined-idefer) ! 1502: else ! 1503: 5 , ! 1504: ['] (undefined-defer) ! 1505: then ! 1506: , ! 1507: ['] (semis) , ! 1508: reveal ! 1509: ; ! 1510: ! 1511: : alias ( new-name< >old-name< > -- ) ! 1512: parse-word ! 1513: parse-word $find if ! 1514: -rot \ move xt behind. ! 1515: header ! 1516: 1 , \ fixme we want our own cfa here. ! 1517: , \ compile old name xt ! 1518: ['] (semis) , ! 1519: reveal ! 1520: else ! 1521: s" undefined word " type type space ! 1522: 2drop ! 1523: then ! 1524: ; ! 1525: ! 1526: : $create ! 1527: header 6 , ! 1528: ['] noop , ! 1529: reveal ! 1530: ; ! 1531: ! 1532: : create ! 1533: parse-word $create ! 1534: ; ! 1535: ! 1536: : (does>) ! 1537: r> cell+ \ get address of code to execute ! 1538: latest @ \ backlink of just "create"d word ! 1539: cell+ cell+ ! \ write code to execute after the ! 1540: \ new word's CFA ! 1541: ; ! 1542: ! 1543: : does> ! 1544: ['] (does>) , \ compile does handling ! 1545: 1 , \ compile docol ! 1546: ; immediate ! 1547: ! 1548: 0 constant struct ! 1549: ! 1550: : field ! 1551: create ! 1552: over , ! 1553: + ! 1554: does> ! 1555: @ + ! 1556: ; ! 1557: ! 1558: : 2constant ! 1559: create , , ! 1560: does> 2@ reveal ! 1561: ; ! 1562: ! 1563: \ ! 1564: \ initializer for the temporary compile buffer ! 1565: \ ! 1566: ! 1567: : init-tmp-comp ! 1568: here 200 allot tmp-comp-buf ! ! 1569: ; ! 1570: ! 1571: \ the end
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.