Reimplement CONSTANT, VARIABLE, VALUE using DOES>
[forth.jl.git] / src / lib.4th
1 : \ IMMEDIATE
2         #TIB @ >IN !
3 ; \ We can now comment!
4
5 \ BASIC DEFINITIONS  ----------------------------------------------------------------------
6
7 : / /MOD SWAP DROP ;
8 : MOD /MOD DROP ;
9 : */ -ROT * SWAP / ;
10
11 : NEGATE 0 SWAP - ;
12
13 : TRUE -1 ;
14 : FALSE 0 ;
15 : NOT 0= ;
16
17 \ Translate a number of cells into memory units
18 \ (in our case 1 cell = 1 memory unit)
19 : CELLS ;
20
21 \ Since the smallest unit of memory in our system is 64 bits and since strings
22 \ are stored as arrays of 64 bit integers, the character store/fetch words are
23 \ just aliases of the standard store/fetch words.
24 : C! ! ;
25 : C@ @ ;
26 : C, , ;
27
28 : DEPTH PSP@ PSP0 - ;
29
30 : '\n' 10 ;
31 : BL 32 ;
32
33 : LITERAL IMMEDIATE ['] LIT , , ;
34
35 : ' BL WORD FIND >CFA ;
36
37 : CHAR BL WORD 1+ @ ;
38 : [CHAR] IMMEDIATE
39     CHAR
40     ['] LIT , ,
41 ;
42
43 : CR '\n' emit ;
44 : SPACE BL emit ;
45
46 : [COMPILE] IMMEDIATE
47         BL WORD         \ get the next word
48         FIND            \ find it in the dictionary
49         >CFA            \ get its codeword
50         ,               \ and compile that
51 ;
52
53 : RECURSE IMMEDIATE
54         LATEST @        \ LATEST points to the word being compiled at the moment
55         >CFA            \ get the codeword
56         ,               \ compile it
57 ;
58
59 \ CONTROL STRUCTURES ----------------------------------------------------------------------
60
61 : IF IMMEDIATE
62         ['] 0BRANCH ,     \ compile 0BRANCH
63         HERE          \ save location of the offset on the stack
64         0 ,             \ compile a dummy offset
65 ;
66
67 : THEN IMMEDIATE
68         DUP
69         HERE SWAP -   \ calculate the offset from the address saved on the stack
70         SWAP !          \ store the offset in the back-filled location
71 ;
72
73 : ELSE IMMEDIATE
74         ['] BRANCH ,      \ definite branch to just over the false-part
75         HERE          \ save location of the offset on the stack
76         0 ,             \ compile a dummy offset
77         SWAP            \ now back-fill the original (IF) offset
78         DUP             \ same as for THEN word above
79         HERE SWAP -
80         SWAP !
81 ;
82
83 : BEGIN IMMEDIATE
84         HERE          \ save location on the stack
85 ;
86
87 : UNTIL IMMEDIATE
88         ['] 0BRANCH ,     \ compile 0BRANCH
89         HERE -        \ calculate the offset from the address saved on the stack
90         ,               \ compile the offset here
91 ;
92
93 : AGAIN IMMEDIATE
94         ['] BRANCH ,      \ compile BRANCH
95         HERE -        \ calculate the offset back
96         ,               \ compile the offset here
97 ;
98
99 : WHILE IMMEDIATE
100         ['] 0BRANCH ,     \ compile 0BRANCH
101         HERE          \ save location of the offset2 on the stack
102         0 ,             \ compile a dummy offset2
103 ;
104
105 : REPEAT IMMEDIATE
106         ['] BRANCH ,      \ compile BRANCH
107         SWAP            \ get the original offset (from BEGIN)
108         HERE - ,      \ and compile it after BRANCH
109         DUP
110         HERE SWAP -   \ calculate the offset2
111         SWAP !          \ and back-fill it in the original location
112 ;
113
114 : UNLESS IMMEDIATE
115         ['] NOT ,         \ compile NOT (to reverse the test)
116         [COMPILE] IF    \ continue by calling the normal IF
117 ;
118
119 : DO IMMEDIATE
120         ['] LIT , -1 , [COMPILE] IF
121         ['] >R , ['] >R ,
122         ['] LIT , HERE 0 , ['] >R ,
123         HERE
124 ;
125
126 : ?DO IMMEDIATE
127         ['] 2DUP , ['] - , [COMPILE] IF
128         ['] >R , ['] >R ,
129         ['] LIT , HERE 0 , ['] >R ,
130         HERE
131 ;
132
133 : I RSP@ 3 - @ ;
134
135 : J RSP@ 6 - @ ;
136
137 : ?LEAVE IMMEDIATE
138         ['] 0BRANCH , 13 ,
139         ['] R> , ['] RDROP , ['] RDROP ,
140         ['] LIT ,  HERE 7 + , ['] DUP , ['] -ROT , ['] - , ['] SWAP , ['] ! ,
141         ['] BRANCH ,
142         0 ,
143 ;
144
145 : LEAVE IMMEDIATE
146         ['] LIT , -1 ,
147         [COMPILE] ?LEAVE
148 ;
149
150 : +LOOP IMMEDIATE
151
152         ['] DUP , \ Store copy of increment
153
154         ['] R> , ['] SWAP , ['] R> , ['] SWAP , ['] R> , ['] SWAP , ['] + , ['] 2DUP , ['] - ,
155         ['] SWAP , ['] >R , ['] SWAP , ['] >R , ['] SWAP , ['] >R ,
156
157         \ Condition differently depending on sign of increment
158         ['] SWAP , ['] 0>= , [COMPILE] IF
159             ['] 0<= ,
160         [COMPILE] ELSE
161             ['] 0> ,
162         [COMPILE] THEN
163
164         \ Branch back to begining of loop kernel
165         ['] 0BRANCH , HERE - ,
166
167         \ Clean up
168         ['] RDROP , ['] RDROP , ['] RDROP ,
169
170         \ Record address of loop end for any LEAVEs to use
171         HERE SWAP !
172
173         [COMPILE] ELSE
174             ['] 2DROP , \ Clean up if loop was entirely skipped (?DO)
175         [COMPILE] THEN
176 ;
177
178 : LOOP IMMEDIATE
179         ['] LIT , 1 ,
180         [COMPILE] +LOOP
181 ;
182
183
184 \ CASE ------------------------------------------------------------------------
185
186 : CASE IMMEDIATE
187         0               \ push 0 to mark the bottom of the stack
188 ;
189
190 : OF IMMEDIATE
191         ['] OVER ,        \ compile OVER
192         ['] = ,           \ compile =
193         [COMPILE] IF      \ compile IF
194         ['] DROP ,        \ compile DROP
195 ;
196
197 : ENDOF IMMEDIATE
198         [COMPILE] ELSE    \ ENDOF is the same as ELSE
199 ;
200
201 : ENDCASE IMMEDIATE
202         ['] DROP ,        \ compile DROP
203
204         \ keep compiling THEN until we get to our zero marker
205         BEGIN
206                 ?DUP
207         WHILE
208                 [COMPILE] THEN
209         REPEAT
210 ;
211
212
213 \ COMMENTS ----------------------------------------------------------------------
214
215 : ( IMMEDIATE
216         1               \ allowed nested parens by keeping track of depth
217         BEGIN
218                 >IN @ #TIB @ >= IF      \ End of TIB?
219                         QUERY       \ Get next line
220                 THEN
221
222                 TIB >IN @ + @ 1 >IN +!
223                 DUP [CHAR] ( = IF    \ open paren?
224                         DROP            \ drop the open paren
225                         1+              \ depth increases
226                 ELSE
227                         [CHAR] ) = IF        \ close paren?
228                                 1-              \ depth decreases
229                         THEN
230                 THEN
231         DUP 0= UNTIL            \ continue until we reach matching close paren, depth 0
232         DROP            \ drop the depth counter
233 ;
234
235 ( Some more complicated stack examples, showing the stack notation. )
236 : NIP ( x y -- y ) SWAP DROP ;
237 : TUCK ( x y -- y x y ) DUP -ROT ;
238 : PICK ( x_u ... x_1 x_0 u -- x_u ... x_1 x_0 x_u )
239         1+              ( add one because of 'u' on the stack )
240         PSP@ SWAP -     ( add to the stack pointer )
241         @               ( and fetch )
242 ;
243 : ROLL ( x_u x_u-1... x_0 u -- x_u-1 ... x_0 x_u )
244         1+ DUP PICK SWAP    ( x_u x_u-1 ... x_0 x_u u+1 )
245         PSP@ 1- SWAP - PSP@ 2- SWAP
246         DO
247             i 1+ @ i !
248         LOOP
249         SWAP DROP
250 ;
251
252 ( With the looping constructs, we can now write SPACES, which writes n spaces to stdout. )
253 : SPACES        ( n -- )
254         DUP 0> IF
255             0 DO SPACE LOOP
256         ELSE
257             DROP
258         THEN
259 ;
260
261 ( Standard words for manipulating BASE. )
262 : DECIMAL ( -- ) 10 BASE ! ;
263 : HEX ( -- ) 16 BASE ! ;
264
265 ( Compute absolute value. )
266 : ABS           ( n -- |n| )
267         dup 0< if
268                 negate
269         then
270 ;
271
272 : MAX           ( n m -- max )
273         2dup - 0< if
274                 swap drop
275         else
276                 drop
277         then
278 ;
279
280 : MIN           ( n m -- max )
281         2dup - 0> if
282                 swap drop
283         else
284                 drop
285         then
286 ;
287
288 ( PRINTING NUMBERS ---------------------------------------------------------------------- )
289
290 ( This is the underlying recursive definition of U. )
291 : U.            ( u -- )
292         BASE @ /MOD     ( width rem quot )
293         ?DUP IF                 ( if quotient <> 0 then )
294                 RECURSE         ( print the quotient )
295         THEN
296
297         ( print the remainder )
298         DUP 10 < IF
299                 [CHAR] 0             ( decimal digits 0..9 )
300         ELSE
301                 10 -            ( hex and beyond digits A..Z )
302                 [CHAR] A
303         THEN
304         +
305         EMIT
306 ;
307
308 ( This word returns the width (in characters) of an unsigned number in the current base )
309 : UWIDTH        ( u -- width )
310         BASE @ /        ( rem quot )
311         ?DUP IF         ( if quotient <> 0 then )
312                 RECURSE 1+      ( return 1+recursive call )
313         ELSE
314                 1               ( return 1 )
315         THEN
316 ;
317
318 : U.R           ( u width -- )
319         SWAP            ( width u )
320         DUP             ( width u u )
321         UWIDTH          ( width u uwidth )
322         ROT            ( u uwidth width )
323         SWAP -          ( u width-uwidth )
324         ( At this point if the requested width is narrower, we'll have a negative number on the stack.
325           Otherwise the number on the stack is the number of spaces to print.  But SPACES won't print
326           a negative number of spaces anyway, so it's now safe to call SPACES ... )
327         SPACES
328         ( ... and then call the underlying implementation of U. )
329         U.
330 ;
331
332 : .R            ( n width -- )
333         SWAP            ( width n )
334         DUP 0< IF
335                 NEGATE          ( width u )
336                 1               ( save a flag to remember that it was negative | width n 1 )
337                 -ROT             ( 1 width u )
338                 SWAP            ( 1 u width )
339                 1-              ( 1 u width-1 )
340         ELSE
341                 0               ( width u 0 )
342                 -ROT             ( 0 width u )
343                 SWAP            ( 0 u width )
344         THEN
345         SWAP            ( flag width u )
346         DUP             ( flag width u u )
347         UWIDTH          ( flag width u uwidth )
348         ROT            ( flag u uwidth width )
349         SWAP -          ( flag u width-uwidth )
350
351         SPACES          ( flag u )
352         SWAP            ( u flag )
353
354         IF                      ( was it negative? print the - character )
355                 [CHAR] - EMIT
356         THEN
357
358         U.
359 ;
360
361 : . 0 .R SPACE ;
362
363 : .S            ( -- )
364         [CHAR] < EMIT DEPTH U. [CHAR] > EMIT SPACE
365         PSP0 1+
366         BEGIN
367                 DUP PSP@ 2 - <=
368         WHILE
369                 DUP @ .
370                 1+
371         REPEAT
372         DROP
373 ;
374
375 : U. U. SPACE ;
376
377 ( ? fetches the integer at an address and prints it. )
378 : ? ( addr -- ) @ . ;
379
380 ( c a b WITHIN returns true if a <= c and c < b )
381 : WITHIN
382         -ROT             ( b c a )
383         OVER            ( b c a c )
384         <= IF
385                 > IF            ( b c -- )
386                         TRUE
387                 ELSE
388                         FALSE
389                 THEN
390         ELSE
391                 2DROP           ( b c -- )
392                 FALSE
393         THEN
394 ;
395
396
397 ( STRINGS ---------------------------------------------------------------------- )
398
399
400 ( Block copy, however, is important and novel: )
401 : CMOVE ( src dest length -- )
402
403         DUP 0<= IF
404                 EXIT
405         THEN
406
407         -ROT OVER -         ( length src (dest-src) )
408         -ROT DUP ROT + SWAP ( (dest-src) (src+length) src )
409     
410         DO
411                 I @         ( (dest-src) i@ )
412                 OVER I +    ( (dest-src) i@ (dest-src+i) )
413                 !           ( (dest-src) )
414         LOOP
415
416         DROP
417 ;
418
419 ( C, appends a byte to the current compiled word. )
420 : C,
421         HERE C!
422         1 H +!
423 ;
424
425 : S" IMMEDIATE          ( -- addr len )
426         STATE @ IF      ( compiling? )
427                 ['] LITSTRING ,   ( compile LITSTRING )
428                 HERE          ( save the address of the length word on the stack )
429                 0 ,             ( dummy length - we don't know what it is yet )
430
431                 BEGIN
432                         >IN @ #TIB @ >= IF      \ End of TIB?
433                                 QUERY           \ Get next line
434                         THEN
435
436                         TIB >IN @ + @ 1 >IN +!  \ Get char from TIB
437
438                         DUP [CHAR] " <>
439                 WHILE
440                         C,              ( copy character )
441                 REPEAT
442                 DROP            ( drop the double quote character at the end )
443                 DUP             ( get the saved address of the length word )
444                 HERE SWAP -   ( calculate the length )
445                 1-              ( subtract 1 (because we measured from the start of the length word) )
446                 SWAP !          ( and back-fill the length location )
447         ELSE            ( immediate mode )
448                 HERE          ( get the start address of the temporary space )
449                 
450                 BEGIN
451                         >IN @ #TIB @ >= IF      \ End of TIB?
452                                 QUERY           \ Get next line
453                         THEN
454
455                         TIB >IN @ + @ 1 >IN +!  \ Get char from TIB
456
457                         DUP [CHAR] " <>
458                 WHILE
459                         OVER C!         ( save next character )
460                         1+              ( increment address )
461                 REPEAT
462                 DROP            ( drop the final " character )
463                 HERE -        ( calculate the length )
464                 HERE          ( push the start address )
465                 SWAP            ( addr len )
466         THEN
467 ;
468
469 : ." IMMEDIATE          ( -- )
470         [COMPILE] S"    ( read the string, and compile LITSTRING, etc. )
471         ['] TYPE ,      ( compile the final TYPE )
472 ;
473
474 : .( 
475         BEGIN
476                 >IN @ #TIB @ >= IF      \ End of TIB?
477                         QUERY           \ Get next line
478                 THEN
479
480                 TIB >IN @ + @ 1 >IN +!  \ Get char from TIB
481
482                 DUP [CHAR] ) = IF
483                         DROP    ( drop the double quote character )
484                         EXIT    ( return from this function )
485                 THEN
486                 EMIT
487         AGAIN
488 ;
489
490 ( Converts address of counted string into address of
491   start of string and length of string. )
492 : COUNT ( addr1 -- addr2 n )
493         DUP 1+ SWAP @ ;
494
495
496 ( CONSTANTS AND VARIABLES ------------------------------------------------------ )
497
498 : CONSTANT
499         CREATE ,
500 DOES>   @
501 ;
502
503 : ALLOT         ( n -- )
504         H +!         ( adds n to H, after this the old value of H is still on the stack )
505 ;
506
507 : VARIABLE
508         CREATE
509         1 CELLS ALLOT   ( allocate 1 cell of memory, push the pointer to this memory )
510 ;
511
512 : VALUE         ( n -- )
513         CREATE ,
514 DOES>   @
515 ;
516
517 : TO IMMEDIATE  ( n -- )
518         BL WORD         ( get the name of the value )
519         FIND            ( look it up in the dictionary )
520         >PFA            ( get a pointer to the first data field (the 'LIT') )
521         STATE @ IF      ( compiling? )
522                 ['] LIT ,         ( compile LIT )
523                 ,               ( compile the address of the value )
524                 ['] ! ,           ( compile ! )
525         ELSE            ( immediate mode )
526                 !               ( update it straightaway )
527         THEN
528 ;
529
530 ( x +TO VAL adds x to VAL )
531 : +TO IMMEDIATE
532         BL WORD         ( get the name of the value )
533         FIND            ( look it up in the dictionary )
534         >PFA            ( get a pointer to the first data field (the 'LIT') )
535         STATE @ IF      ( compiling? )
536                 ['] LIT ,         ( compile LIT )
537                 ,               ( compile the address of the value )
538                 ['] +! ,          ( compile +! )
539         ELSE            ( immediate mode )
540                 +!              ( update it straightaway )
541         THEN
542 ;
543
544 ( Fill u ints, starting at a, with the value b )
545 : FILL          ( a u b -- )
546         -ROT OVER + SWAP ?DO
547                 DUP I !
548         LOOP
549         DROP
550 ;
551
552 : ERASE         ( a u -- )
553         0 FILL
554 ;
555
556 ( PRINTING THE DICTIONARY ------------------------------------------------------ )
557
558 : ID.
559         1+              ( skip over the link pointer )
560         DUP @           ( get the flags/length byte )
561         F_LENMASK AND   ( mask out the flags - just want the length )
562
563         BEGIN
564                 DUP 0>          ( length > 0? )
565         WHILE
566                 SWAP 1+         ( addr len -- len addr+1 )
567                 DUP @           ( len addr -- len addr char | get the next character)
568                 DUP 32 >= OVER 127 <= AND IF
569                         EMIT    ( len addr char -- len addr | and print it)
570                 ELSE
571                         BASE @ SWAP HEX
572                         ." \x" 0 .R
573                         BASE !
574                 THEN
575                 SWAP 1-         ( len addr -- addr len-1    | subtract one from length )
576         REPEAT
577         2DROP           ( len addr -- )
578 ;
579
580 : ?HIDDEN
581         1+              ( skip over the link pointer )
582         @               ( get the flags/length byte )
583         F_HIDDEN AND    ( mask the F_HIDDEN flag and return it (as a truth value) )
584 ;
585 : ?IMMEDIATE
586         1+              ( skip over the link pointer )
587         @               ( get the flags/length byte )
588         F_IMMED AND     ( mask the F_IMMED flag and return it (as a truth value) )
589 ;
590
591 : WORDS
592         LATEST @        ( start at LATEST dictionary entry )
593         BEGIN
594                 ?DUP            ( while link pointer is not null )
595         WHILE
596                 DUP ?HIDDEN NOT IF      ( ignore hidden words )
597                         DUP ID.         ( but if not hidden, print the word )
598                         SPACE
599                 THEN
600                 @               ( dereference the link pointer - go to previous word )
601         REPEAT
602         CR
603 ;
604
605
606 ( FORGET ---------------------------------------------------------------------- )
607
608 : FORGET
609         BL WORD FIND    ( find the word, gets the dictionary entry address )
610         DUP @ LATEST !  ( set LATEST to point to the previous word )
611         H !          ( and store H with the dictionary address )
612 ;
613
614 ( DUMP ------------------------------------------------------------------------ )
615
616 \ TODO!
617
618
619 ( DECOMPILER ------------------------------------------------------------------ )
620
621 : CFA>
622         LATEST @        ( start at LATEST dictionary entry )
623         BEGIN
624                 ?DUP            ( while link pointer is not null )
625         WHILE
626                 2DUP SWAP       ( cfa curr curr cfa )
627                 < IF            ( current dictionary entry < cfa? )
628                         NIP             ( leave curr dictionary entry on the stack )
629                         EXIT
630                 THEN
631                 @               ( follow link pointer back )
632         REPEAT
633         DROP            ( restore stack )
634         0               ( sorry, nothing found )
635 ;
636
637 : SEE
638         BL WORD DUP FIND     ( find the dictionary entry to decompile )
639
640         ?DUP 0= IF
641                 ." Word '" COUNT TYPE ." ' not found in dictionary."
642                 EXIT
643         THEN
644
645         SWAP DROP
646
647         ( Now we search again, looking for the next word in the dictionary.  This gives us
648           the length of the word that we will be decompiling.  (Well, mostly it does). )
649         HERE          ( address of the end of the last compiled word )
650         LATEST @        ( word last curr )
651         BEGIN
652                 2 PICK          ( word last curr word )
653                 OVER            ( word last curr word curr )
654                 <>              ( word last curr word<>curr? )
655         WHILE                   ( word last curr )
656                 NIP             ( word curr )
657                 DUP @           ( word curr prev (which becomes: word last curr) )
658         REPEAT
659
660         DROP            ( at this point, the stack is: start-of-word end-of-word )
661         SWAP            ( end-of-word start-of-word )
662
663         DUP >CFA @ CASE
664                 DOCOL OF
665                         \ Colon definition
666                         [CHAR] : EMIT SPACE DUP ID. SPACE
667                         DUP ?IMMEDIATE IF ." IMMEDIATE " THEN CR
668                 ENDOF
669                 DOVAR OF
670                         \ Variable definition
671                         ." Variable " DUP ID. CR
672                         2DROP EXIT
673                 ENDOF
674                 DOCON OF
675                         \ Constant definition
676                         ." Constant " DUP ID. CR
677                         2DROP EXIT
678                 ENDOF
679
680                 \ Unknown codeword
681                 ." Primitive or word with unrecognized codeword." CR 
682                 DROP 2DROP EXIT
683         ENDCASE
684
685         ( begin the definition with : NAME [IMMEDIATE] )
686         ( [CHAR] : EMIT SPACE DUP ID. SPACE
687         DUP ?IMMEDIATE IF ." IMMEDIATE " THEN CR 4 )
688
689         4 SPACES
690
691         >PFA            ( get the data address, ie. points after DOCOL | end-of-word start-of-data )
692
693         ( now we start decompiling until we hit the end of the word )
694         BEGIN           ( end start )
695                 2DUP >
696         WHILE
697                 DUP @           ( end start codeword )
698
699                 CASE
700                 ['] LIT OF                ( is it LIT ? )
701                         1+ DUP @                ( get next word which is the integer constant )
702                         .                       ( and print it )
703                 ENDOF
704                 ['] LITSTRING OF          ( is it LITSTRING ? )
705                         [CHAR] S EMIT [CHAR] " EMIT SPACE ( print S"<space> )
706                         1+ DUP @                ( get the length word )
707                         SWAP 1+ SWAP            ( end start+1 length )
708                         2DUP TYPE               ( print the string )
709                         [CHAR] " EMIT SPACE          ( finish the string with a final quote )
710                         +                       ( end start+1+len, aligned )
711                         1-                     ( because we're about to add 4 below )
712                 ENDOF
713                 ['] 0BRANCH OF            ( is it 0BRANCH ? )
714                         ." 0BRANCH ( "
715                         1+ DUP @               ( print the offset )
716                         .
717                         ." ) "
718                 ENDOF
719                 ['] BRANCH OF             ( is it BRANCH ? )
720                         ." BRANCH ( "
721                         1+ DUP @               ( print the offset )
722                         .
723                         ." ) "
724                 ENDOF
725                 ['] ['] OF                  ( is it ['] ? )
726                         ." ['] "
727                         1+ DUP @               ( get the next codeword )
728                         CFA>                    ( and force it to be printed as a dictionary entry )
729                         ID. SPACE
730                 ENDOF
731                 ['] EXIT OF               ( is it EXIT? )
732                         ( We expect the last word to be EXIT, and if it is then we don't print it
733                           because EXIT is normally implied by ;.  EXIT can also appear in the middle
734                           of words, and then it needs to be printed. )
735                         2DUP                    ( end start end start )
736                         1+                     ( end start end start+1 )
737                         <> IF                   ( end start | we're not at the end )
738                                 ." EXIT "
739                         THEN
740                 ENDOF
741                                         ( default case: )
742                         DUP                     ( in the default case we always need to DUP before using )
743                         CFA>                    ( look up the codeword to get the dictionary entry )
744                         ID. SPACE               ( and print it )
745                 ENDCASE
746
747                 1+             ( end start+1 )
748         REPEAT
749
750         [CHAR] ; EMIT CR
751
752         2DROP           ( restore stack )
753 ;
754
755
756 ( MEMORY  ------------------------------------------------------------------ )
757
758 : UNUSED  ( -- cells )
759         MEMSIZE HERE - ;