Annotation of qemu/roms/openbios/forth/bootstrap/bootstrap.fs, revision 1.1.1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.