WIP to find crashing problem generating eturtle.exe
[hf86v099.git] / hf86ram.asm
1 TITLE hForth 8086 RAM Model\r
2 \r
3 PAGE 62,132     ;62 lines per page, 132 characters per line\r
4 \r
5 ;===============================================================\r
6 ;\r
7 ;       hForth 8086 RAM model v0.9.9 by Wonyong Koh, 1997\r
8 ;\r
9 ;\r
10 ; 1997. 7. 11.\r
11 ;       Fix SPACES. Thank Benjamin Hoyt.\r
12 ; 1997. 6. 23.\r
13 ;       Fix pack".\r
14 ; 1997. 2. 19.\r
15 ;       Split environmental variable systemID into CPU and Model.\r
16 ; 1997. 2. 6.\r
17 ;       Add Neal Crook's microdebugger and comments on assembly definitions.\r
18 ; 1997. 1. 25.\r
19 ;       Add $THROWMSG macro and revise accordingly.\r
20 ; 1997. 1. 18.\r
21 ;       Remove 'NullString' from assembly source.\r
22 ; 1996. 12. 18.\r
23 ;       Revise 'head,'.\r
24 ; 1996. 12. 3.\r
25 ;       Revise PICK to catch stack underflow.\r
26 ; 1996. 12. 1.\r
27 ;       Port from ROM Model v0.9.9.\r
28 ;\r
29 ; Changes from 0.9.7\r
30 ;\r
31 ;;      hForth RAM ¡¡\95I·e RAM e·i ³a\93e ¯¡¯aÉQµA  xÂ\81´á hForth ROM ¡¡\95I·i\r
32 ;;      \89¡Áa¬á  e\97i´ö¯s\93¡\94a.\r
33 ;;\r
34 ;;      hForth ROM ¡¡\95I\89Á \94a\9fe ¸ñ\97i·i ´a\9c\81µA ¸â´ö¯s\93¡\94a. ¡A¡¡\9f¡\9fi\r
35 ;;      ¸é´¢Ða\89¡ ­¢\95¡\9fi ¨a\9fa\89A Ða\9da\89¡ \8b¡\89\81´á ¸÷·\81\9fi ¡y \88\81 \94áÐa\89¡\r
36 ;;      \89¡Áv¯s\93¡\94a. ´á­Q§i\9f¡ ¤aÈw¥¥µA¬á  aÇa\9d¡µÁ °w¸ñ ¸÷·\81\9fi ¡y \88\81\r
37 ;;      ¤a\8e\81´ö¯s\93¡\94a.\r
38 ;;\r
39 ;;      1. ¬a¸å·\81 \8a\81¹¡\9fi ¤a\8e\81´ö¯s\93¡\94a. hForth ROM ¡¡\95IµA¬á\93e Å¡\97aµÁ ·¡\9fq\r
40 ;;         ¸a\9f¡\88a ´a\9c\81Àá\9cñ \90a\92á´á ·¶´ö»¡ e\r
41 ;;\r
42 ;;             ||Å¡\97a> ... <¯¡Ç±Îa|·µ\8b¡|·¡\9fq||\r
43 ;;\r
44 ;;         hForth RAM ¡¡\95IµA¬á\93e Å¡\97a, ·¡\9fq, ¸a\9ea ¸a\9f¡\88a ´a\9c\81Àá\9cñ ¡¡\96\81\r
45 ;;         ¬ãµa ·¶¯s\93¡\94a.\r
46 ;;\r
47 ;;             ||·µ\8b¡|·¡\9fq|·¡\9fq\88a\9f¡Ç±|Å¡\97a>\r
48 ;;\r
49 ;;         µa\8b¡¬á '¯¡Ç±Îa(xt)'\93e Å¡\97\81 ¯¡¸b º\81­¡·³\93¡\94a. $STRµÁ $CODEµÁ\r
50 ;;         $ENVIRµÁ $VALUE  aÇa\9d¡\9fi ¤a\8e\81´ö¯s\93¡\94a.\r
51 ;;\r
52 ;;      2. xt>name\89Á name>xt\9fi ¤a\8e\81´ö¯s\93¡\94a. hForth ROM ¡¡\95IµA¬á\93e ·¡\9fq\r
53 ;;         ¸a\9f¡µA xt\9f\88\81\9f¡Ð\81 \96\81´á¬á name>xt\88a ·¡ \88t·i \94ᣡµA\r
54 ;;         µ©\9dv¯s\93¡\94a. \8ba\9cá\90a Å¡\97a ¸a\9f¡\9fi ¸b¹A Ða\9da\89¡ Å¡\97a ¸a\9f¡µA\93e ·¡\9fq\r
55 ;;         ¸a\9f¡ \88a\9f¡Ç±\88t·i \90q\89\91½»¡ ´g´a¬á xt>name·¡ ·©Ã¡Ða\93e xt\9fi Àx·i\r
56 ;;         \98\81\8ca»¡ ·¡\9fq ¸a\9f¡\9f\94á\97q·i ®\81¤cµA ´ô´ö¯s\93¡\94a. hForth RAM\r
57 ;;         ¡¡\95IµA\93e ·¡\9f\81 \8f{µA¬á Å¡\97a\88a ¯¡¸bÐa\8b¡ \98\81¢\85µA 'name>xt'\9fi\r
58 ;;         ¶áÐ\81 \98a\9d¡ \88a\9f¡Ç±\88t·i \90q\89\91½·i Ï©¶a\88a ´ô¯s\93¡\94a. Ða»¡ e\r
59 ;;         xt>name\9fi ¶áÐ\81¬á xt ¤a\9d¡ ´|µA ·¡\9fq º\81­¡\9f\88a\9f¡Ç¡\93\88t·i \90q\8b©\r
60 ;;         Ï©¶a\88a ·¶¯s\93¡\94a. name>xt\88a ¤a\8eá´ö\8b¡ \98\81¢\85µA\r
61 ;;         (search-wordlist)·\81 \8b¡\89\81´á ¸÷·\81\9fi ¤a\8e\81´ö¯s\93¡\94a (°w¸ñ ¸÷·\81\93e\r
62 ;;         ¤a\8e\89 Ï©¶a\88a ´ô¯s\93¡\94a).\r
63 ;;\r
64 ;;      3. Å¡\97a, ·¡\9fq, ¸a\9ea ¸a\9f¡·\81 §¥ ¸a\9f¡\9f\90aÈa\90\81\93\88t\97i·¡ hForth RAM\r
65 ;;         ¡¡\95IµA¬á\93e ROM\89Á RAM ¸a\9f¡\9f\88a\9f¡Ç¡\93\88a\9f¡Ç±\88t\97i´á´¡ Ði Ï©¶a\88a\r
66 ;;         ´ô¯s\93¡\94a. ROMB, ROMT, RAMB, RAMT\9fi ¨\96¯s\93¡\94a. xhere\9fi ¡¡\96\81\r
67 ;          HERE\9d¡ ¤a\8e\81´ö¯s\93¡\94a. 'code,'\9fi ¡¡\96\81 ','\9d¡ ¤a\8e\81´ö¯s\93¡\94a.\r
68 ;;\r
69 ;;      4. head,\88a ¤a\8eá´ö\8b¡ \98\81¢\85µA :µÁ CONSTANTµÁ CREATEµÁ VARIABLEµÁ\r
70 ;;         VALUE\9f\89¡Áv¯s\93¡\94a. hForth ROM ¡¡\95IµA¬á\93e ·¡\9fq ¸a\9f¡\88a Å¡\97a\r
71 ;;         ¸a\9f¡µÁ \98é´á¹a ·¶´ö\8b¡ \98\81¢\85µA \90{ i·\81 ·¡\9fq·i ·¡\9fq ¸a\9f¡µA °á\r
72 ;;         \90ý\8b¡ ¸åµA head,\88a xt\9fi ´i ®\81 ·¶´ö¯s\93¡\94a. \8ba\9cá\90a hForth RAM\r
73 ;;         ¡¡\95IµA¬á\93e Å¡\97a ¸a\9f¡µÁ ·¡\9fq ¸a\9f¡\88a ÐsÁa¹v\8b¡ \98\81¢\85µA ·¡\9fq·i\r
74 ;;         °á \90ý\8b¡ ¸åµA head,\88a xt\9fi £¡\9f¡ ´i ®\81 ´ô¯s\93¡\94a.\r
75 ;;\r
76 ;;      5. Á¡\8b¡\88t·¡ Ï©¶aÐe ¯¡¯aÉQ ¢\81\9fe\88t\97i\89Á \94\85Ðe ¯¡¯aÉQ ¢\81\9fe\88t·i\r
77 ;;         \8a\81¦\85Ð\96¯s\93¡\94a. Á¡\8b¡\88t·¡ Ï©¶aÐe ¢\81\9fe\88t\97i·e doCONST\9fi °á¬á\r
78 ;;         \94ᣡµA \88\81 º\81­¡\9fi µ©\9f¡\89A Ða\89¡ Á¡\8b¡\88t·¡ Ï©¶a´ô\93e ¢\81\9fe\88t\97i·e\r
79 ;;         $VAR  aÇa\9d¡\9d¡ ¸÷·\81Ð\81¬á doVAR\9d¡ \88\81 º\81­¡\9f\94ᣡµA µ©\9f¡\89A\r
80 ;;         Ð\96¯s\93¡\94a. VARIABLE·¡ ³a\93\8b¡\89\81´á ¸÷·\81 doVAR\9f\94áÐ\96¯s\93¡\94a.\r
81 ;;\r
82 ;;      6. CREATEµÁ doCREATEµÁ >BODY·\81 ¸÷·\81\9fi ¤a\8e\81´ö¯s\93¡\94a.\r
83 ;;\r
84 ;;      7. RESET-SYSTEM·i ´ô´\96¯s\93¡\94a. COLDµÁ set-i/o\9f\89¡Áv¯s\93¡\94a.\r
85 ;;\r
86 ;;      8. PADSize\9f\96\81 ¤\81\9d¡ \93i\9dv¯s\93¡\94a.\r
87 ;;\r
88 ;;      9. ¡A¡¡\9f¡ e \90â\90âÐa\94a¡e wordlist·\81 ®\81µA ¹AÐe·¡ ´ô¯s\93¡\94a.\r
89 ;;\r
90 ;;      10. ¬a¶w \88a\93wÐe ¡A¡¡\9f¡·\81  \85 ¶á\9f\88a\9f¡Ç¡\93e ¢\81\9fe\88t memTop·i\r
91 ;;         \94áÐ\96¯s\93¡\94a.\r
92 ;;\r
93 ;;\r
94 ;       hForth RAM model is derived from hForth ROM model and adapted\r
95 ;       to RAM only system.\r
96 ;\r
97 ;       Differences from hForth ROM model are described below. One low\r
98 ;       level CODE definition is changed and only one is added for\r
99 ;       efficiency. Some macros in the assembler source and high level\r
100 ;       colon definitions are redefined.\r
101 ;\r
102 ;       1. The structure of the dictionary is changed. Code and name\r
103 ;          spaces are intermingled in hForth RAM model as below\r
104 ;\r
105 ;               ||link|name|pointer_to_name|code>\r
106 ;\r
107 ;          while they are separated in hForth ROM model as below.\r
108 ;\r
109 ;               ||code> ... <xt|link|name||\r
110 ;\r
111 ;          where xt is the starting address of code. $STR, $CODE, $ENVIR,\r
112 ;          and $VALUE macros are redefined in assembly source.\r
113 ;\r
114 ;       2. 'xt>name' and 'name>xt' are redefined. In hForth ROM model the\r
115 ;          xt of a definition is stored in name space which is used by\r
116 ;          'name>xt', however, the pointer to the name of a definition is\r
117 ;          not stored in code space to keep the code space as tight as\r
118 ;          possible. So 'xt>name' of hForth ROM model need to search the\r
119 ;          whole name space until it finds the matched xt. In hForth RAM\r
120 ;          model no pointer for 'name>xt' is necessary since code space\r
121 ;          starts at the end of the name, however, a pointer to the name\r
122 ;          of a definition is stored before the code of a definition for\r
123 ;          'xt>name'. CODE definition of '(search-wordlist)' is changed\r
124 ;          since 'name>xt' is redefined (although colon definition need\r
125 ;          not be changed at all).\r
126 ;\r
127 ;       3. Code, name and data pointers need not be vectored since the\r
128 ;          memory space is not split into separated ROM and RAM spaces.\r
129 ;          'ROMB', 'ROMT', 'RAMB' and 'RAMT' are deleted. Every 'xhere'\r
130 ;          was replaced with HERE. Every 'code,' was replaced with ','.\r
131 ;\r
132 ;       4. ':', 'CONSTANT', 'CREATE', 'VARIABLE', and 'VALUE' are\r
133 ;          redefined since 'head,' is redefined. In hForth ROM model\r
134 ;          name spaces are separated from code space and xt is given to\r
135 ;          'head,' before the name of a definition is compiled into the\r
136 ;          name space. However, in hForth RAM model code and name spaces\r
137 ;          are combined and xt can not be known to 'head,' until the\r
138 ;          name of a definition is compiled into the name space.\r
139 ;\r
140 ;       5. System variables are devided into initializable variables\r
141 ;          defined by $CONST which use doCONST to put a-addr on the\r
142 ;          stack and non-initialized ones defined by $VAR which use\r
143 ;          doVAR. CODE definition 'doVAR' is added and used by VARIABLE.\r
144 ;\r
145 ;       6. 'CREATE', 'doCREATE', and '>BODY' are redefined.\r
146 ;\r
147 ;       7. RESET-SYSTEM is deleted. COLD and 'set-i/o' are revised.\r
148 ;\r
149 ;       8. Increase PADSize twice.\r
150 ;\r
151 ;       9. Number of wordlists are only limited by available memory.\r
152 ;\r
153 ;       10. Variable 'memTop' is added, which points top of available\r
154 ;          memory.\r
155 ;\r
156 ;===============================================================\r
157 ;\r
158 ;       8086/8 register usages\r
159 ;       Single segment model. CS, DS and SS must be same.\r
160 ;       The direction bit must be cleared before returning to Forth\r
161 ;           interpreter(CLD).\r
162 ;       SP:     data stack pointer\r
163 ;       BP:     return stack pointer\r
164 ;       SI:     Forth virtual machine instruction pointer\r
165 ;       BX:     top of data stack item\r
166 ;       All other registers are free.\r
167 ;\r
168 ;       Structure of a task\r
169 ;       userP points follower.\r
170 ;       //userP//<return_stack//<data_stack//\r
171 ;       //user_area/user1/taskName/throwFrame/stackTop/status/follower/sp0/rp0\r
172 ;\r
173 ;===============================================================\r
174 \r
175 ;;;;;;;;;;;;;;;;\r
176 ; Assembly Constants\r
177 ;;;;;;;;;;;;;;;;\r
178 \r
179 TRUEE           EQU     -1\r
180 FALSEE          EQU     0\r
181 \r
182 CHARR           EQU     1               ;byte size of a character\r
183 CELLL           EQU     2               ;byte size of a cell\r
184 MaxChar         EQU     0FFh            ;Extended character set\r
185                                         ;  Use 07Fh for ASCII only\r
186 MaxSigned       EQU     07FFFh          ;max value of signed integer\r
187 MaxUnsigned     EQU     0FFFFh          ;max value of unsigned integer\r
188 MaxNegative     EQU     8000h           ;max value of negative integer\r
189                                         ;  Used in doDO\r
190 \r
191 PADSize         EQU     258             ;PAD area size\r
192 RTCells         EQU     64              ;return stack size\r
193 DTCells         EQU     256             ;data stack size\r
194 \r
195 BASEE           EQU     10              ;default radix\r
196 OrderDepth      EQU     10              ;depth of search order stack\r
197 \r
198 COMPO           EQU     020h            ;lexicon compile only bit\r
199 IMMED           EQU     040h            ;lexicon immediate bit\r
200 MASKK           EQU     1Fh             ;lexicon bit mask\r
201                                         ;extended character set\r
202                                         ;maximum name length = 1Fh\r
203 \r
204 BKSPP           EQU     8               ;backspace\r
205 TABB            EQU     9               ;tab\r
206 LFF             EQU     10              ;line feed\r
207 CRR             EQU     13              ;carriage return\r
208 DEL             EQU     127             ;delete\r
209 \r
210 CALLL           EQU     0E890h          ;NOP CALL opcodes\r
211 \r
212 ; Memory allocation\r
213 ;       RAMbottom||code/name/data>WORDworkarea|--//--|PAD|TIB||MemTop\r
214 \r
215 COLDD           EQU     00100h                  ;cold start vector\r
216 \r
217 ; Initialize assembly variables\r
218 \r
219 _SLINK  = 0                                     ;force a null link\r
220 _FLINK  = 0                                     ;force a null link\r
221 _ENVLINK = 0                                    ;farce a null link\r
222 _THROW  = 0                                     ;current throw str addr offset\r
223 \r
224 ;;;;;;;;;;;;;;;;\r
225 ; Assembly macros\r
226 ;;;;;;;;;;;;;;;;\r
227 \r
228 ;       Adjust an address to the next cell boundary.\r
229 \r
230 $ALIGN  MACRO\r
231         EVEN                                    ;for 16 bit systems\r
232         ENDM\r
233 \r
234 ;       Add a name to name space of dictionary.\r
235 \r
236 $STR    MACRO   LABEL,STRING\r
237 LABEL:\r
238         _LEN    = $\r
239         DB      0,STRING\r
240         _CODE   = $\r
241 ORG     _LEN\r
242         DB      _CODE-_LEN-1\r
243 ORG     _CODE\r
244         $ALIGN\r
245         ENDM\r
246 \r
247 ;       Add a THROW message in name space. THROW messages won't be\r
248 ;       needed if target system do not need names of Forth words.\r
249 \r
250 $THROWMSG MACRO STRING\r
251         _LEN    = $\r
252         DB      0,STRING\r
253         _CODE   = $\r
254 ORG     _LEN\r
255         DB      _CODE-_LEN-1\r
256         _THROW  = _THROW + CELLL\r
257 ORG     AddrTHROWMsgTbl - _THROW\r
258         DW      _LEN\r
259 ORG     _CODE\r
260         ENDM\r
261 \r
262 ;       Compile a code definition header.\r
263 \r
264 $CODE   MACRO   LEX,NAME,LABEL,LINK\r
265         $ALIGN                                  ;force to cell boundary\r
266         DW      LINK\r
267         _NAME   = $\r
268         LINK    = $                             ;link points to a name string\r
269         DB      LEX,NAME                        ;name string\r
270         $ALIGN\r
271         DW      _NAME\r
272 LABEL:                                          ;assembly label\r
273         ENDM\r
274 \r
275 ;       Compile a colon definition header.\r
276 \r
277 $COLON  MACRO   LEX,NAME,LABEL,LINK\r
278         $CODE   LEX,NAME,LABEL,LINK\r
279         NOP                                     ;align to cell boundary\r
280         CALL    DoLIST                          ;include CALL doLIST\r
281         ENDM\r
282 \r
283 ;       Compile a system CONSTANT header.\r
284 \r
285 $CONST  MACRO   LEX,NAME,LABEL,VALUE,LINK\r
286         $CODE   LEX,NAME,LABEL,LINK\r
287         NOP\r
288         CALL    DoCONST\r
289         DW      VALUE\r
290         ENDM\r
291 \r
292 ;       Compile a system VALUE header.\r
293 \r
294 $VALUE  MACRO   LEX,NAME,LABEL,VALUE,LINK\r
295         $CODE   LEX,NAME,LABEL,LINK\r
296         NOP\r
297         CALL    DoVALUE\r
298         DW      VALUE\r
299         ENDM\r
300 \r
301 ;       Compile a non-initialized system VARIABLE header.\r
302 \r
303 $VAR    MACRO   LEX,NAME,LABEL,N_CELLS,LINK\r
304         $CODE   LEX,NAME,LABEL,LINK\r
305         NOP\r
306         CALL    DoVAR\r
307         DW      N_CELLS DUP (?)\r
308         ENDM\r
309 \r
310 ;       Compile a system USER header.\r
311 \r
312 $USER   MACRO   LEX,NAME,LABEL,OFFSET,LINK\r
313         $CODE   LEX,NAME,LABEL,LINK\r
314         NOP\r
315         CALL    DoUSER\r
316         DW      OFFSET\r
317         ENDM\r
318 \r
319 ;       Compile an inline string.\r
320 \r
321 $INSTR  MACRO   STRNG\r
322         DW      DoLIT\r
323         _LEN    = $                             ;save address of count\r
324         DW      0                               ;count\r
325         DW      DoSQuote                        ;doS"\r
326         DB      STRNG                           ;store string\r
327         _CODE   = $                             ;save code pointer\r
328 ORG     _LEN                                    ;point to count byte\r
329         DW      _CODE-_LEN-2*CELLL              ;set count\r
330 ORG     _CODE                                   ;restore code pointer\r
331         $ALIGN\r
332         ENDM\r
333 \r
334 ;       Compile a environment query string header.\r
335 \r
336 $ENVIR  MACRO   LEX,NAME\r
337         $ALIGN                                  ;force to cell boundary\r
338         DW      _ENVLINK                        ;link\r
339         _ENVLINK = $                            ;link points to a name string\r
340         DB      LEX,NAME                        ;name string\r
341         $ALIGN\r
342         DW      _ENVLINK\r
343         NOP\r
344         CALL    DoLIST\r
345         ENDM\r
346 \r
347 ;       Assemble inline direct threaded code ending.\r
348 \r
349 $NEXT   MACRO\r
350 ;        JMP     uDebug                          ;activate to use microdebugger\r
351         LODSW                                   ;next code address into AX\r
352         JMP     AX                              ;jump directly to code address\r
353         $ALIGN\r
354         ENDM\r
355 \r
356 ;===============================================================\r
357 \r
358 ;;;;;;;;;;;;;;;;\r
359 ; Main entry points and COLD start data\r
360 ;;;;;;;;;;;;;;;;\r
361 \r
362 MAIN    SEGMENT\r
363 ASSUME  CS:MAIN,DS:MAIN,SS:MAIN\r
364 \r
365 ORG             COLDD                           ;beginning of cold boot\r
366 \r
367 ORIG:           CLD                             ;direction flag, increment\r
368                 MOV     WORD PTR AddrMemTop,SP  ;top of memory at 'memTop'\r
369                 MOV     AX,CS\r
370                 MOV     DS,AX                   ;DS is same as CS\r
371                 CLI                             ;disable interrupts, old 808x CPU bug\r
372                 MOV     SS,AX                   ;SS is same as CS\r
373                 MOV     SP,offset SPP           ;initialize SP\r
374                 STI                             ;enable interrupts\r
375                 MOV     BP,offset RPP           ;initialize RP\r
376 \r
377                 XOR     AX,AX                   ;MS-DOS only\r
378                 MOV     Redirect1stQ,AX         ;MS-DOS only\r
379 \r
380                 JMP     COLD                    ;to high level cold start\r
381 \r
382                 $ALIGN\r
383                 $STR    CPUStr,'8086'\r
384                 $STR    ModelStr,'RAM Model'\r
385                 $STR    VersionStr,'0.9.9'\r
386 \r
387 ; system variables.\r
388 \r
389                 $ALIGN                          ;align to cell boundary\r
390 ValueTickEKEYQ  EQU     RXQ                     ;'ekey?\r
391 ValueTickEKEY   EQU     RXFetch                 ;'ekey\r
392 ValueTickEMITQ  EQU     TXQ                     ;'emit?\r
393 ValueTickEMIT   EQU     TXStore                 ;'emit\r
394 ValueTickINIT_IO EQU    Set_IO                  ;'init-i/o\r
395 ValueTickPrompt EQU     DotOK                   ;'prompt\r
396 ValueTickBoot   EQU     HI                      ;'boot\r
397 ValueSOURCE_ID  EQU     0                       ;SOURCE-ID\r
398 ValueHERE       EQU     CTOP                    ;data space pointer\r
399 AddrTickDoWord  DW      OptiCOMPILEComma        ;nonimmediate word - compilation\r
400                 DW      EXECUTE                 ;nonimmediate word - interpretation\r
401                 DW      DoubleAlsoComma         ;not found word - compilateion\r
402                 DW      DoubleAlso              ;not found word - interpretation\r
403                 DW      EXECUTE                 ;immediate word - compilation\r
404                 DW      EXECUTE                 ;immediate word - interpretation\r
405 AddrBASE        DW      10                      ;BASE\r
406 AddrRakeVar     DW      0                       ;rakeVar\r
407 AddrNumberOrder DW      2                       ;#order\r
408                 DW      AddrFORTH_WORDLIST      ;search order stack\r
409                 DW      AddrNONSTANDARD_WORDLIST\r
410                 DW      (OrderDepth-2) DUP (0)\r
411 AddrCurrent     DW      AddrFORTH_WORDLIST      ;current pointer\r
412 AddrFORTH_WORDLIST DW   LASTFORTH               ;FORTH-WORDLIST\r
413                 DW      AddrNONSTANDARD_WORDLIST;wordlist link\r
414                 DW      FORTH_WORDLISTName      ;name of the WORDLIST\r
415 AddrNONSTANDARD_WORDLIST DW      LASTSYSTEM     ;NONSTANDARD-WORDLIST\r
416                 DW      0                       ;wordlist link\r
417                 DW      NONSTANDARD_WORDLISTName;name of the WORDLIST\r
418 AddrEnvQList    DW      LASTENV                 ;envQList\r
419 AddrUserP       DW      SysUserP                ;user pointer\r
420 SysTask         DW      SysUserP                ;system task's tid\r
421 SysUser1        DW      ?                       ;user1\r
422 SysTaskName     DW      SystemTaskName          ;taskName\r
423 SysThrowFrame   DW      ?                       ;throwFrame\r
424 SysStackTop     DW      ?                       ;stackTop\r
425 SysStatus       DW      Wake                    ;status\r
426 SysUserP:\r
427 SysFollower     DW      SysStatus               ;follower\r
428                 DW      SPP                     ;system task's sp0\r
429                 DW      RPP                     ;system task's rp0\r
430 \r
431 AddrNumberOrder0 DW     2                       ;#order\r
432                 DW      AddrFORTH_WORDLIST      ;search order stack\r
433                 DW      AddrNONSTANDARD_WORDLIST\r
434                 DW      (OrderDepth-2) DUP (0)\r
435 \r
436 RStack          DW      RTCells DUP (0AAAAh)    ;to see how deep stack grows\r
437 RPP             EQU     $-CELLL\r
438 DStack          DW      DTCells DUP (05555h)    ;to see how deep stack grows\r
439 SPP             EQU     $-CELLL\r
440 \r
441 ; THROW code messages\r
442 \r
443         DW      58 DUP (?)              ;number of throw messages = 58\r
444 AddrTHROWMsgTbl:\r
445                                                                     ;THROW code\r
446         $THROWMSG       'ABORT'                                         ;-01\r
447         $THROWMSG       'ABORT"'                                        ;-02\r
448         $THROWMSG       'stack overflow'                                ;-03\r
449         $THROWMSG       'stack underflow'                               ;-04\r
450         $THROWMSG       'return stack overflow'                         ;-05\r
451         $THROWMSG       'return stack underflow'                        ;-06\r
452         $THROWMSG       'do-loops nested too deeply during execution'   ;-07\r
453         $THROWMSG       'dictionary overflow'                           ;-08\r
454         $THROWMSG       'invalid memory address'                        ;-09\r
455         $THROWMSG       'division by zero'                              ;-10\r
456         $THROWMSG       'result out of range'                           ;-11\r
457         $THROWMSG       'argument type mismatch'                        ;-12\r
458         $THROWMSG       'undefined word'                                ;-13\r
459         $THROWMSG       'interpreting a compile-only word'              ;-14\r
460         $THROWMSG       'invalid FORGET'                                ;-15\r
461         $THROWMSG       'attempt to use zero-length string as a name'   ;-16\r
462         $THROWMSG       'pictured numeric output string overflow'       ;-17\r
463         $THROWMSG       'parsed string overflow'                        ;-18\r
464         $THROWMSG       'definition name too long'                      ;-19\r
465         $THROWMSG       'write to a read-only location'                 ;-20\r
466         $THROWMSG       'unsupported operation (e.g., AT-XY on a too-dumb terminal)' ;-21\r
467         $THROWMSG       'control structure mismatch'                    ;-22\r
468         $THROWMSG       'address alignment exception'                   ;-23\r
469         $THROWMSG       'invalid numeric argument'                      ;-24\r
470         $THROWMSG       'return stack imbalance'                        ;-25\r
471         $THROWMSG       'loop parameters unavailable'                   ;-26\r
472         $THROWMSG       'invalid recursion'                             ;-27\r
473         $THROWMSG       'user interrupt'                                ;-28\r
474         $THROWMSG       'compiler nesting'                              ;-29\r
475         $THROWMSG       'obsolescent feature'                           ;-30\r
476         $THROWMSG       '>BODY used on non-CREATEd definition'          ;-31\r
477         $THROWMSG       'invalid name argument (e.g., TO xxx)'          ;-32\r
478         $THROWMSG       'block read exception'                          ;-33\r
479         $THROWMSG       'block write exception'                         ;-34\r
480         $THROWMSG       'invalid block number'                          ;-35\r
481         $THROWMSG       'invalid file position'                         ;-36\r
482         $THROWMSG       'file I/O exception'                            ;-37\r
483         $THROWMSG       'non-existent file'                             ;-38\r
484         $THROWMSG       'unexpected end of file'                        ;-39\r
485         $THROWMSG       'invalid BASE for floating point conversion'    ;-40\r
486         $THROWMSG       'loss of precision'                             ;-41\r
487         $THROWMSG       'floating-point divide by zero'                 ;-42\r
488         $THROWMSG       'floating-point result out of range'            ;-43\r
489         $THROWMSG       'floating-point stack overflow'                 ;-44\r
490         $THROWMSG       'floating-point stack underflow'                ;-45\r
491         $THROWMSG       'floating-point invalid argument'               ;-46\r
492         $THROWMSG       'compilation word list deleted'                 ;-47\r
493         $THROWMSG       'invalid POSTPONE'                              ;-48\r
494         $THROWMSG       'search-order overflow'                         ;-49\r
495         $THROWMSG       'search-order underflow'                        ;-50\r
496         $THROWMSG       'compilation word list changed'                 ;-51\r
497         $THROWMSG       'control-flow stack overflow'                   ;-52\r
498         $THROWMSG       'exception stack overflow'                      ;-53\r
499         $THROWMSG       'floating-point underflow'                      ;-54\r
500         $THROWMSG       'floating-point unidentified fault'             ;-55\r
501         $THROWMSG       'QUIT'                                          ;-56\r
502         $THROWMSG       'exception in sending or receiving a character' ;-57\r
503         $THROWMSG       '[IF], [ELSE], or [THEN] exception'             ;-58\r
504 \r
505 ;;;;;;;;;;;;;;;;\r
506 ; System dependent words -- Must be re-definded for each system.\r
507 ;;;;;;;;;;;;;;;;\r
508 ; I/O words must be redefined if serial communication is used instead of\r
509 ; keyboard. Following words are for MS-DOS system.\r
510 \r
511 ;   RX?         ( -- flag )\r
512 ;               Return true if key is pressed.\r
513 \r
514                 $CODE   3,'RX?',RXQ,_SLINK\r
515                 PUSH    BX\r
516                 MOV     AH,0Bh                  ;get input status of STDIN\r
517                 INT     021h\r
518                 CBW\r
519                 MOV     BX,AX\r
520                 $NEXT\r
521 \r
522 ;   RX@         ( -- u )\r
523 ;               Receive one keyboard event u.\r
524 \r
525                 $CODE   3,'RX@',RXFetch,_SLINK\r
526                 PUSH    BX\r
527                 XOR     BX,BX\r
528                 MOV     AH,08h                  ;MS-DOS Read Keyboard\r
529                 INT     021h\r
530                 ADD     BL,AL                   ;MOV BL,AL and OR AL,AL\r
531                 JNZ     RXFET1                  ;extended character code?\r
532                 INT     021h\r
533                 MOV     BH,AL\r
534 RXFET1:         $NEXT\r
535 \r
536 ;   TX?         ( -- flag )\r
537 ;               Return true if output device is ready or device state is\r
538 ;               indeterminate.\r
539 \r
540                 $CONST  3,'TX?',TXQ,TRUEE,_SLINK ;always true for MS-DOS\r
541 \r
542 ;   TX!         ( u -- )\r
543 ;               Send char to the output device.\r
544 \r
545                 $CODE   3,'TX!',TXStore,_SLINK\r
546                 MOV     DX,BX                   ;char in DL\r
547                 MOV     AH,02h                  ;MS-DOS Display output\r
548                 INT     021H                    ;display character\r
549                 POP     BX\r
550                 $NEXT\r
551 \r
552 ;   CR          ( -- )                          \ CORE\r
553 ;               Carriage return and linefeed.\r
554 ;\r
555 ;   : CR        carriage-return-char EMIT  linefeed-char EMIT ;\r
556 \r
557                 $COLON  2,'CR',CR,_FLINK\r
558                 DW      DoLIT,CRR,EMIT,DoLIT,LFF,EMIT,EXIT\r
559 \r
560 ;   BYE         ( -- )                          \ TOOLS EXT\r
561 ;               Return control to the host operation system, if any.\r
562 \r
563                 $CODE   3,'BYE',BYE,_FLINK\r
564                 MOV     AX,04C00h               ;close all files and\r
565                 INT     021h                    ;  return to MS-DOS\r
566                 $ALIGN\r
567 \r
568 ;   hi          ( -- )\r
569 ;\r
570 ;   : hi        CR ." hForth "\r
571 ;               S" CPU" ENVIRONMENT? DROP TYPE SPACE\r
572 ;               S" model" ENVIRONMENT? DROP TYPE SPACE [CHAR] v EMIT\r
573 ;               S" version"  ENVIRONMENT? DROP TYPE\r
574 ;               ."  by Wonyong Koh, 1997" CR\r
575 ;               ." ALL noncommercial and commercial uses are granted." CR\r
576 ;               ." Please send comment, bug report and suggestions to:" CR\r
577 ;               ."   wykoh@pado.krict.re.kr or wykoh@hitel.kol.co.kr" CR ;\r
578 \r
579                 $COLON  2,'hi',HI,_SLINK\r
580                 DW      CR\r
581                 $INSTR  'hForth '\r
582                 DW      TYPEE\r
583                 $INSTR  'CPU'\r
584                 DW      ENVIRONMENTQuery,DROP,TYPEE,SPACE\r
585                 $INSTR  'model'\r
586                 DW      ENVIRONMENTQuery,DROP,TYPEE,SPACE,DoLIT,'v',EMIT\r
587                 $INSTR  'version'\r
588                 DW      ENVIRONMENTQuery,DROP,TYPEE\r
589                 $INSTR  ' by Wonyong Koh, 1997'\r
590                 DW      TYPEE,CR\r
591                 $INSTR  'All noncommercial and commercial uses are granted.'\r
592                 DW      TYPEE,CR\r
593                 $INSTR  'Please send comment, bug report and suggestions to:'\r
594                 DW      TYPEE,CR\r
595                 $INSTR  '  wykoh@pado.krict.re.kr or wykoh@hitel.kol.co.kr'\r
596                 DW      TYPEE,CR,EXIT\r
597 \r
598 ;   COLD        ( -- )\r
599 ;               The cold start sequence execution word.\r
600 ;\r
601 ;   : COLD      sp0 sp! rp0 rp!                 \ initialize stack\r
602 ;               'init-i/o EXECUTE\r
603 ;               'boot EXECUTE\r
604 ;               QUIT ;                          \ start interpretation\r
605 \r
606                 $COLON  4,'COLD',COLD,_SLINK\r
607                 DW      SPZero,SPStore,RPZero,RPStore\r
608                 DW      TickINIT_IO,EXECUTE,TickBoot,EXECUTE\r
609                 DW      QUIT\r
610 \r
611 ;   set-i/o ( -- )\r
612 ;               Set input/output device.\r
613 ;\r
614 ;   : set-i/o   S" CON" stdin ;                 \ MS-DOS only\r
615 \r
616                 $COLON  7,'set-i/o',Set_IO,_SLINK\r
617                 $INSTR  'CON'                   ;MS-DOS only\r
618                 DW      STDIN                   ;MS-DOS only\r
619                 DW      EXIT\r
620 \r
621 ;;;;;;;;;;;;;;;;\r
622 ; MS-DOS only words -- not necessary for other systems.\r
623 ;;;;;;;;;;;;;;;;\r
624 ; File input using MS-DOS redirection function without using FILE words.\r
625 \r
626 ;   redirect    ( c-addr -- flag )\r
627 ;               Redirect standard input from the device identified by ASCIIZ\r
628 ;               string stored at c-addr. Return error code.\r
629 \r
630                 $CODE   8,'redirect',Redirect,_SLINK\r
631                 MOV     DX,BX\r
632                 MOV     AX,Redirect1stQ\r
633                 OR      AX,AX\r
634                 JZ      REDIRECT2\r
635                 MOV     AH,03Eh\r
636                 MOV     BX,RedirHandle\r
637                 INT     021h            ; close previously opend file\r
638 REDIRECT2:      MOV     AX,03D00h       ; open file read-only\r
639                 MOV     Redirect1stQ,AX ; set Redirect1stQ true\r
640                 INT     021h\r
641                 JC      REDIRECT1       ; if error\r
642                 MOV     RedirHandle,AX\r
643                 XOR     CX,CX\r
644                 MOV     BX,AX\r
645                 MOV     AX,04600H\r
646                 INT     021H\r
647                 JC      REDIRECT1\r
648                 XOR     AX,AX\r
649 REDIRECT1:      MOV     BX,AX\r
650                 $NEXT\r
651 Redirect1stQ    DW      0               ; true after the first redirection\r
652 RedirHandle     DW      ?               ; redirect file handle\r
653 \r
654 ;   asciiz      ( ca1 u -- ca2 )\r
655 ;               Return ASCIIZ string.\r
656 ;\r
657 ;   : asciiz    HERE SWAP 2DUP + 0 SWAP C! CHARS MOVE HERE ;\r
658 \r
659                 $COLON  6,'asciiz',ASCIIZ,_SLINK\r
660                 DW      HERE,SWAP,TwoDUP,Plus,Zero\r
661                 DW      SWAP,CStore,CHARS,MOVE,HERE,EXIT\r
662 \r
663 ;   stdin       ( ca u -- )\r
664 ;\r
665 ;   : stdin     asciiz redirect ?DUP\r
666 ;               IF -38 THROW THEN ; COMPILE-ONLY\r
667 \r
668                 $COLON  5,'stdin',STDIN,_SLINK\r
669                 DW      ASCIIZ,Redirect,QuestionDUP,ZBranch,STDIN1\r
670                 DW      DoLIT,-38,THROW\r
671 STDIN1          DW      EXIT\r
672 \r
673 ;   <<          ( "<spaces>ccc" -- )\r
674 ;               Redirect input from the file 'ccc'. Should be used only in\r
675 ;               interpretation state.\r
676 ;\r
677 ;   : <<        STATE @ IF ." Do not use '<<' in a definition." ABORT THEN\r
678 ;               PARSE-WORD stdin SOURCE >IN !  DROP ; IMMEDIATE\r
679 \r
680                 $COLON  IMMED+2,'<<',FROM,_SLINK\r
681                 DW      STATE,Fetch,ZBranch,FROM1\r
682                 DW      CR\r
683                 $INSTR  'Do not use << in a definition.'\r
684                 DW      TYPEE,ABORT\r
685 FROM1           DW      PARSE_WORD,STDIN,SOURCE,ToIN,Store,DROP,EXIT\r
686 \r
687 ;;;;;;;;;;;;;;;;\r
688 ; Non-Standard words - Processor-dependent definitions\r
689 ;       16 bit Forth for 8086/8\r
690 ;;;;;;;;;;;;;;;;\r
691 \r
692 ; microdebugger for debugging new hForth ports by NAC.\r
693 ;\r
694 ; The major problem with debugging Forth code at the assembler level is that\r
695 ; most of the definitions are lists of execution tokens that get interpreted\r
696 ; (using doLIST) rather than executed directly. As far as the native processor\r
697 ; is concerned, these xt are data, and a debugger cannot be set to trap on\r
698 ; them.\r
699 ;\r
700 ; The solution to that problem would seem to be to trap on the native-machine\r
701 ; 'call' instruction at the start of each definition. However, the threaded\r
702 ; nature of the code makes it very difficult to follow a particular definition\r
703 ; through: many definitions are used repeatedly through the code. Simply\r
704 ; trapping on the 'call' leads to multiple unwanted traps.\r
705 ;\r
706 ; Consider, for example, the code for doS" --\r
707 ;\r
708 ;          DW      RFrom,SWAP,TwoDUP,Plus,ALIGNED,ToR,EXIT\r
709 ;\r
710 ; It would be useful to run each word in turn; at the end of each word the\r
711 ; effect upon the stacks could be checked until the faulty word is found.\r
712 ;\r
713 ; This technique allows you to do exactly that.\r
714 ;\r
715 ; All definitions end with $NEXT -- either directly (code definitions) or\r
716 ; indirectly (colon definitions terminating in EXIT, which is itself a code\r
717 ; definition). The action of $NEXT is to use the fpc for the next word to\r
718 ; fetch the xt and jumps to it.\r
719 ;\r
720 ; To use the udebug routine, replace the $NEXT expansion with a jump (not a\r
721 ; call) to the routine udebug (this requires you to reassemble the code)\r
722 ;\r
723 ; When you want to debug a word, trap at the CALL doLIST at the start of the\r
724 ; word and then load the location trapfpc with the address of the first xt\r
725 ; of the word. Make your debugger trap when you execute the final instruction\r
726 ; in the udebug routine. Now execute your code and your debugger will trap\r
727 ; after the completion of the first xt in the definition. To stop debugging,\r
728 ; simply set trapfpc to 0.\r
729 ;\r
730 ; This technique has a number of limitations:\r
731 ; - It is an assumption that an xt of 0 is illegal\r
732 ; - You cannot automatically debug a code stream that includes inline string\r
733 ;   definitions, or any other kind of inline literal. You must step into the\r
734 ;   word that includes the definition then hand-edit the appropriate new value\r
735 ;   into trapfpc\r
736 ; Clearly, you could overcome these limitations by making udebug more\r
737 ; complex -- but then you run the risk of introducing bugs in that code.\r
738 \r
739 uDebug:         MOV     AX,trapfpc\r
740                 CMP     AX,SI           ; compare the stored address with\r
741                                         ; the address we're about to get the\r
742                                         ; next xt from\r
743                 JNE     uDebug1         ; not the trap address, so we're done\r
744                 ADD     AX,CELLL        ; next time trap on the next xt\r
745                 MOV     trapfpc,AX\r
746                 NOP                     ; make debugger TRAP at this address\r
747 uDebug1:        LODSW\r
748                 JMP     AX\r
749                 $ALIGN\r
750 \r
751 trapfpc         DW      0\r
752 \r
753 ;   same?       ( c-addr1 c-addr2 u -- -1|0|1 )\r
754 ;               Return 0 if two strings, ca1 u and ca2 u, are same; -1 if\r
755 ;               string, ca1 u is smaller than ca2 u; 1 otherwise. Used by\r
756 ;               '(search-wordlist)'. Code definition is preferred to speed up\r
757 ;               interpretation. Colon definition is shown below.\r
758 ;\r
759 ;   : same?     ?DUP IF         \ null strings are always same\r
760 ;                  0 DO OVER C@ OVER C@ XOR\r
761 ;                       IF UNLOOP C@ SWAP C@ > 2* 1+ EXIT THEN\r
762 ;                       CHAR+ SWAP CHAR+ SWAP\r
763 ;                  LOOP\r
764 ;               THEN 2DROP 0 ;\r
765 ;\r
766 ;                 $COLON  5,'same?',SameQ,_SLINK\r
767 ;                 DW      QuestionDUP,ZBranch,SAMEQ4\r
768 ;                 DW      Zero,DoDO\r
769 ; SAMEQ3          DW      OVER,CFetch,OVER,CFetch,XORR,ZBranch,SAMEQ2\r
770 ;                 DW      UNLOOP,CFetch,SWAP,CFetch,GreaterThan\r
771 ;                 DW      TwoStar,OnePlus,EXIT\r
772 ; SAMEQ2          DW      CHARPlus,SWAP,CHARPlus\r
773 ;                 DW      DoLOOP,SAMEQ3\r
774 ; SAMEQ4          DW      TwoDROP,Zero,EXIT\r
775 \r
776                 $CODE   5,'same?',SameQ,_SLINK\r
777                 MOV     CX,BX\r
778                 MOV     AX,DS\r
779                 MOV     ES,AX\r
780                 MOV     DX,SI           ;save SI\r
781                 MOV     BX,-1\r
782                 POP     DI\r
783                 POP     SI\r
784                 OR      CX,CX\r
785                 JZ      SAMEQ5\r
786                 REPE CMPSB\r
787                 JL      SAMEQ1\r
788                 JZ      SAMEQ5\r
789                 INC     BX\r
790 SAMEQ5:         INC     BX\r
791 SAMEQ1:         MOV     SI,DX\r
792                 $NEXT\r
793 \r
794 ;   (search-wordlist)   ( c-addr u wid -- 0 | xt f 1 | xt f -1)\r
795 ;               Search word list for a match with the given name.\r
796 ;               Return execution token and not-compile-only flag and\r
797 ;               -1 or 1 ( IMMEDIATE) if found. Return 0 if not found.\r
798 ;\r
799 ;               format is: wid---->[   a    ]\r
800 ;                                      |\r
801 ;                            +---------+\r
802 ;                            V\r
803 ;               [   a'   ][ccbbaann][ggffeedd]...\r
804 ;                   |\r
805 ;                   +--------+\r
806 ;                            V\r
807 ;               [   a''  ][ccbbaann][ggffeedd]...\r
808 ;\r
809 ;               a, a' etc. point to the cell that contains the name of the\r
810 ;               word. The length is in the low byte of the cell (little byte\r
811 ;               for little-endian, big byte for big-endian).\r
812 ;               Eventually, a''' contains 0 to indicate the end of the wordlist\r
813 ;               (oldest entry). a=0 indicates an empty wordlist.\r
814 ;               xt is the xt of the word. aabbccddeedd etc. is the name of\r
815 ;               the word, packed into cells.\r
816 ;\r
817 ;   : (search-wordlist)\r
818 ;               ROT >R SWAP DUP 0= IF -16 THROW THEN\r
819 ;                               \ attempt to use zero-length string as a name\r
820 ;               >R              \ wid  R: ca1 u\r
821 ;               BEGIN @         \ ca2  R: ca1 u\r
822 ;                  DUP 0= IF R> R> 2DROP EXIT THEN      \ not found\r
823 ;                  DUP COUNT [ =MASK ] LITERAL AND R@ = \ ca2 ca2+char f\r
824 ;                     IF   R> R@ SWAP DUP >R            \ ca2 ca2+char ca1 u\r
825 ;                          same?                        \ ca2 flag\r
826 ;                   \ ELSE DROP -1      \ unnecessary since ca2+char is not 0.\r
827 ;                     THEN\r
828 ;               WHILE cell-             \ pointer to next word in wordlist\r
829 ;               REPEAT\r
830 ;               R> R> 2DROP DUP name>xt SWAP            \ xt ca2\r
831 ;               C@ DUP [ =COMP ] LITERAL AND 0= SWAP\r
832 ;               [ =IMED ] LITERAL AND 0= 2* 1+ ;\r
833 ;\r
834 ;                 $COLON  17,'(search-wordlist)',ParenSearch_Wordlist,_SLINK\r
835 ;                 DW      ROT,ToR,SWAP,DUPP,ZBranch,PSRCH6\r
836 ;                 DW      ToR\r
837 ; PSRCH1          DW      Fetch\r
838 ;                 DW      DUPP,ZBranch,PSRCH9\r
839 ;                 DW      DUPP,COUNT,DoLIT,MASKK,ANDD,RFetch,Equals\r
840 ;                 DW      ZBranch,PSRCH5\r
841 ;                 DW      RFrom,RFetch,SWAP,DUPP,ToR,SameQ\r
842 ; PSRCH5          DW      ZBranch,PSRCH3\r
843 ;                 DW      CellMinus,Branch,PSRCH1\r
844 ; PSRCH3          DW      RFrom,RFrom,TwoDROP,DUPP,NameToXT,SWAP\r
845 ;                 DW      CFetch,DUPP,DoLIT,COMPO,ANDD,ZeroEquals,SWAP\r
846 ;                 DW      DoLIT,IMMED,ANDD,ZeroEquals,TwoStar,OnePlus,EXIT\r
847 ; PSRCH9          DW      RFrom,RFrom,TwoDROP,EXIT\r
848 ; PSRCH6          DW      DoLIT,-16,THROW\r
849 \r
850                 $CODE   17,'(search-wordlist)',ParenSearch_Wordlist,_SLINK\r
851                 POP     AX      ;u\r
852                 POP     DX      ;c-addr\r
853                 OR      AX,AX\r
854                 JZ      PSRCH1\r
855                 PUSH    SI\r
856                 MOV     CX,DS\r
857                 MOV     ES,CX\r
858                 SUB     CX,CX\r
859 PSRCH2:         MOV     BX,[BX]\r
860                 OR      BX,BX\r
861                 JZ      PSRCH4          ; end of wordlist?\r
862                 MOV     CL,[BX]\r
863                 SUB     BX,CELLL        ;pointer to nextword\r
864                 AND     CL,MASKK        ;max name length = MASKK\r
865                 CMP     CL,AL\r
866                 JNZ     PSRCH2\r
867                 MOV     SI,DX\r
868                 MOV     DI,BX\r
869                 ADD     DI,CELLL+CHARR\r
870                 REPE CMPSB\r
871                 JNZ     PSRCH2\r
872                 POP     SI\r
873                 ADD     DI,3            ;add 1 CELLS + 1\r
874                 AND     DI,0FFFEh       ;align\r
875                 PUSH    DI\r
876                 MOV     CL,[BX+CELLL]\r
877                 XOR     DX,DX\r
878                 TEST    CL,COMPO\r
879                 JNZ     PSRCH5\r
880                 DEC     DX\r
881 PSRCH5:         PUSH    DX\r
882                 TEST    CL,IMMED\r
883                 MOV     BX,-1\r
884                 JZ      PSRCH3\r
885                 NEG     BX\r
886 PSRCH3:         $NEXT\r
887 PSRCH1:         MOV     BX,-16  ;attempt to use zero-length string as a name\r
888                 JMP     THROW\r
889 PSRCH4:         POP     SI\r
890                 $NEXT\r
891 \r
892 ;   ?call       ( xt1 -- xt1 0 | a-addr xt2 )\r
893 ;               Return xt of the CALLed run-time word if xt starts with machine\r
894 ;               CALL instruction and leaves the next cell address after the\r
895 ;               CALL instruction. Otherwise leaves the original xt1 and zero.\r
896 ;\r
897 ;   : ?call     DUP @ call-code =\r
898 ;               IF   CELL+ DUP @ SWAP CELL+ DUP ROT + EXIT THEN\r
899 ;                       \ Direct Threaded Code 8086 relative call\r
900 ;               0 ;\r
901 \r
902                 $COLON  5,'?call',QCall,_SLINK\r
903                 DW      DUPP,Fetch,DoLIT,CALLL,Equals,ZBranch,QCALL1\r
904                 DW      CELLPlus,DUPP,Fetch,SWAP,CELLPlus,DUPP,ROT,Plus,EXIT\r
905 QCALL1          DW      Zero,EXIT\r
906 \r
907 ;   xt,         ( xt1 -- xt2 )\r
908 ;               Take a run-time word xt1 for :NONAME , CONSTANT , VARIABLE and\r
909 ;               CREATE . Return xt2 of current definition.\r
910 ;\r
911 ;   : xt,       HERE ALIGNED DUP TO HERE SWAP\r
912 ;               call-code ,             \ Direct Threaded Code\r
913 ;               HERE CELL+ - , ;        \ 8086 relative call\r
914 \r
915                 $COLON  3,'xt,',xtComma,_SLINK\r
916                 DW      HERE,ALIGNED,DUPP,DoTO,AddrHERE,SWAP\r
917                 DW      DoLIT,CALLL,Comma,HERE,CELLPlus,Minus,Comma,EXIT\r
918 \r
919 ;   doLIT       ( -- x )\r
920 ;               Push an inline literal. The inline literal is at the current\r
921 ;               value of the fpc, so put it onto the stack and point past it.\r
922 \r
923                 $CODE   COMPO+5,'doLIT',DoLIT,_SLINK\r
924                 PUSH    BX\r
925                 LODSW\r
926                 MOV     BX,AX\r
927                 $NEXT\r
928 \r
929 ;   doCONST     ( -- x )\r
930 ;               Run-time routine of CONSTANT. When you quote a constant you\r
931 ;               execute its code, which consists of a call to here, followed\r
932 ;               by an inline literal. Although you come here as the result of\r
933 ;               a native machine call, you never go back to the return address\r
934 ;               -- you jump back up a level by continuing at the new fpc\r
935 ;               value. For 8086, Z80 the inline literal is at the return\r
936 ;               address stored on the top of the hardware stack.\r
937 \r
938                 $CODE   COMPO+7,'doCONST',DoCONST,_SLINK\r
939                 MOV     DI,SP\r
940                 XCHG    BX,[DI]\r
941                 MOV     BX,[BX]\r
942                 $NEXT\r
943 \r
944 ;   doVALUE     ( -- x )\r
945 ;               Run-time routine of VALUE. Same as doCONSTANT. Used as a\r
946 ;               marker for TO.\r
947 \r
948                 $CODE   COMPO+7,'doVALUE',DoVALUE,_SLINK\r
949                 MOV     DI,SP\r
950                 XCHG    BX,[DI]\r
951                 MOV     BX,[BX]\r
952                 $NEXT\r
953 \r
954 ;   doVAR       ( -- x )\r
955 ;               Run-time routine of VARIABLE. When you quote a variable you\r
956 ;               execute its code, which consists of a call to here, followed\r
957 ;               by an inline literal. The literal is the address at which a\r
958 ;               VARIABLE's value is stored. Although you come here as the\r
959 ;               result of a native machine call, you never go back to the\r
960 ;               return address -- you jump back up a level by continuing at\r
961 ;               the new fpc value. For 8086, Z80 the inline literal is at\r
962 ;               the return address stored on the top of the hardware stack.\r
963 \r
964                 $CODE   COMPO+5,'doVAR',DoVAR,_SLINK\r
965                 MOV     DI,SP\r
966                 XCHG    BX,[DI]\r
967                 $NEXT\r
968 \r
969 ;   doCREATE    ( -- a-addr )\r
970 ;               Run-time routine of CREATE. For CREATEd words with an\r
971 ;               associated DOES>, get the address of the CREATEd word's data\r
972 ;               space and execute the DOES> actions. For CREATEd word without\r
973 ;               an associated DOES>, return the address of the CREATE'd word's\r
974 ;               data space. A CREATEd word starts its execution through this\r
975 ;               routine in exactly the same way as a colon definition uses\r
976 ;               doLIST. In other words, we come here through a native machine\r
977 ;               branch.\r
978 ;\r
979 ;               Structure of CREATEd word:\r
980 ;                   | call-doCREATE | 0 or DOES> code addr | >BODY points here\r
981 ;\r
982 ;               The DOES> address holds a native call to doLIST. This routine\r
983 ;               doesn't alter the fpc. We never come back *here* so we never\r
984 ;               need to preserve an address that would bring us back *here*.\r
985 ;\r
986 ;               Example : myVARIABLE CREATE , DOES> ;\r
987 ;               56 myVARIABLE JIM\r
988 ;               JIM \ stacks the address of the data cell that contains 56\r
989 ;\r
990 ;   : doCREATE    SWAP            \ switch BX and top of 8086 stack item\r
991 ;                 DUP CELL+ SWAP @ ?DUP IF EXECUTE THEN ; COMPILE-ONLY\r
992 ;\r
993 ;                 $COLON  COMPO+8,'doCREATE',DoCREATE,_SLINK\r
994 ;                 DW      SWAP,DUPP,CELLPlus,SWAP,Fetch,QuestionDUP\r
995 ;                 DW      ZBranch,DOCREAT1\r
996 ;                 DW      EXECUTE\r
997 ; DOCREAT1        DW      EXIT\r
998 \r
999                 $CODE   COMPO+8,'doCREATE',DoCREATE,_SLINK\r
1000                 MOV     DI,SP\r
1001                 XCHG    BX,[DI]\r
1002                 MOV     AX,[BX]\r
1003                 ADD     BX,CELLL\r
1004                 OR      AX,AX\r
1005                 JNZ     DOCREAT1\r
1006                 $NEXT\r
1007 DOCREAT1:       JMP     AX\r
1008                 $ALIGN\r
1009 \r
1010 ;   doTO        ( x -- )\r
1011 ;               Run-time routine of TO. Store x at the address in the\r
1012 ;               following cell. The inline literal holds the address\r
1013 ;               to be modified.\r
1014 \r
1015                 $CODE   COMPO+4,'doTO',DoTO,_SLINK\r
1016                 LODSW\r
1017                 XCHG    BX,AX\r
1018                 MOV     [BX],AX\r
1019                 POP     BX\r
1020                 $NEXT\r
1021 \r
1022 ;   doUSER      ( -- a-addr )\r
1023 ;               Run-time routine of USER. Return address of data space.\r
1024 ;               This is like doCONST but a variable offset is added to the\r
1025 ;               result. By changing the value at AddrUserP (which happens\r
1026 ;               on a taskswap) the whole set of user variables is switched\r
1027 ;               to the set for the new task.\r
1028 \r
1029                 $CODE   COMPO+6,'doUSER',DoUSER,_SLINK\r
1030                 MOV     DI,SP\r
1031                 XCHG    BX,[DI]\r
1032                 MOV     BX,[BX]\r
1033                 ADD     BX,AddrUserP\r
1034                 $NEXT\r
1035 \r
1036 ;   doLIST      ( -- ) ( R: -- nest-sys )\r
1037 ;               Process colon list.\r
1038 ;               The first word of a definition (the xt for the word) is a\r
1039 ;               native machine-code instruction for the target machine. For\r
1040 ;               high-level definitions, that code is emitted by xt, and\r
1041 ;               performs a call to doLIST. doLIST executes the list of xt that\r
1042 ;               make up the definition. The final xt in the definition is EXIT.\r
1043 ;               The address of the first xt to be executed is passed to doLIST\r
1044 ;               in a target-specific way. Two examples:\r
1045 ;               Z80, 8086: native machine call, leaves the return address on\r
1046 ;               the hardware stack pointer, which is used for the data stack.\r
1047 \r
1048                 $CODE   COMPO+6,'doLIST',DoLIST,_SLINK\r
1049                 SUB     BP,2\r
1050                 MOV     [BP],SI                 ;push return stack\r
1051                 POP     SI                      ;new list address\r
1052                 $NEXT\r
1053 \r
1054 ;   doLOOP      ( -- ) ( R: loop-sys1 -- | loop-sys2 )\r
1055 ;               Run time routine for LOOP.\r
1056 \r
1057                 $CODE   COMPO+6,'doLOOP',DoLOOP,_SLINK\r
1058                 INC     WORD PTR [BP]           ;increase loop count\r
1059                 JO      DoLOOP1                 ;?loop end\r
1060                 MOV     SI,[SI]                 ;no, go back\r
1061                 $NEXT\r
1062 DoLOOP1:        ADD     SI,CELLL                ;yes, continue past the branch offset\r
1063                 ADD     BP,2*CELLL              ;clear return stack\r
1064                 $NEXT\r
1065 \r
1066 ;   do+LOOP     ( n -- ) ( R: loop-sys1 -- | loop-sys2 )\r
1067 ;               Run time routine for +LOOP.\r
1068 \r
1069                 $CODE   COMPO+7,'do+LOOP',DoPLOOP,_SLINK\r
1070                 ADD     WORD PTR [BP],BX        ;increase loop count\r
1071                 JO      DoPLOOP1                ;?loop end\r
1072                 MOV     SI,[SI]                 ;no, go back\r
1073                 POP     BX\r
1074                 $NEXT\r
1075 DoPLOOP1:       ADD     SI,CELLL                ;yes, continue past the branch offset\r
1076                 ADD     BP,2*CELLL              ;clear return stack\r
1077                 POP     BX\r
1078                 $NEXT\r
1079 \r
1080 ;   0branch     ( flag -- )\r
1081 ;               Branch if flag is zero.\r
1082 \r
1083                 $CODE   COMPO+7,'0branch',ZBranch,_SLINK\r
1084                 OR      BX,BX                   ;?flag=0\r
1085                 JZ      ZBRAN1                  ;yes, so branch\r
1086                 ADD     SI,CELLL                ;point IP to next cell\r
1087                 POP     BX\r
1088                 $NEXT\r
1089 ZBRAN1:         MOV     SI,[SI]                 ;IP:=(IP)\r
1090                 POP     BX\r
1091                 $NEXT\r
1092 \r
1093 ;   branch      ( -- )\r
1094 ;               Branch to an inline address.\r
1095 \r
1096                 $CODE   COMPO+6,'branch',Branch,_SLINK\r
1097                 MOV     SI,[SI]                 ;IP:=(IP)\r
1098                 $NEXT\r
1099 \r
1100 ;   rp@         ( -- a-addr )\r
1101 ;               Push the current RP to the data stack.\r
1102 \r
1103                 $CODE   COMPO+3,'rp@',RPFetch,_SLINK\r
1104                 PUSH    BX\r
1105                 MOV     BX,BP\r
1106                 $NEXT\r
1107 \r
1108 ;   rp!         ( a-addr -- )\r
1109 ;               Set the return stack pointer.\r
1110 \r
1111                 $CODE   COMPO+3,'rp!',RPStore,_SLINK\r
1112                 MOV     BP,BX\r
1113                 POP     BX\r
1114                 $NEXT\r
1115 \r
1116 ;   sp@         ( -- a-addr )\r
1117 ;               Push the current data stack pointer.\r
1118 \r
1119                 $CODE   3,'sp@',SPFetch,_SLINK\r
1120                 PUSH    BX\r
1121                 MOV     BX,SP\r
1122                 $NEXT\r
1123 \r
1124 ;   sp!         ( a-addr -- )\r
1125 ;               Set the data stack pointer.\r
1126 \r
1127                 $CODE   3,'sp!',SPStore,_SLINK\r
1128                 MOV     SP,BX\r
1129                 POP     BX\r
1130                 $NEXT\r
1131 \r
1132 ;   um+         ( u1 u2 -- u3 1|0 )\r
1133 ;               Add two unsigned numbers, return the sum and carry.\r
1134 \r
1135                 $CODE   3,'um+',UMPlus,_SLINK\r
1136                 XOR     CX,CX\r
1137                 POP     AX\r
1138                 ADD     BX,AX\r
1139                 PUSH    BX                      ;push sum\r
1140                 RCL     CX,1                    ;get carry\r
1141                 MOV     BX,CX\r
1142                 $NEXT\r
1143 \r
1144 ;   1chars/     ( n1 -- n2 )\r
1145 ;               Calculate number of chars for n1 address units.\r
1146 ;\r
1147 ;   : 1chars/   1 CHARS / ;     \ slow, very portable\r
1148 ;   : 1chars/   ;               \ fast, must be redefined for each system\r
1149 \r
1150                 $COLON  7,'1chars/',OneCharsSlash,_SLINK\r
1151                 DW      EXIT\r
1152 \r
1153 ;;;;;;;;;;;;;;;;\r
1154 ; Standard words - Processor-dependent definitions\r
1155 ;       16 bit Forth for 8086/8\r
1156 ;;;;;;;;;;;;;;;;\r
1157 \r
1158 ;   ALIGN       ( -- )                          \ CORE\r
1159 ;               Align the data space pointer.\r
1160 ;\r
1161 ;   : ALIGN     HERE ALIGNED TO HERE ;\r
1162 \r
1163                 $COLON  5,'ALIGN',ALIGNN,_FLINK\r
1164                 DW      HERE,ALIGNED,DoTO,AddrHERE,EXIT\r
1165 \r
1166 ;   ALIGNED     ( addr -- a-addr )              \ CORE\r
1167 ;               Align address to the cell boundary.\r
1168 ;\r
1169 ;   : ALIGNED   DUP 0 cell-size UM/MOD DROP DUP\r
1170 ;               IF cell-size SWAP - THEN + ;    \ slow, very portable\r
1171 ;\r
1172 ;                 $COLON  7,'ALIGNED',ALIGNED,_FLINK\r
1173 ;                 DW      DUPP,Zero,DoLIT,CELLL\r
1174 ;                 DW      UMSlashMOD,DROP,DUPP\r
1175 ;                 DW      ZBranch,ALGN1\r
1176 ;                 DW      DoLIT,CELLL,SWAP,Minus\r
1177 ; ALGN1           DW      Plus,EXIT\r
1178 \r
1179                 $CODE   7,'ALIGNED',ALIGNED,_FLINK\r
1180                 INC     BX\r
1181                 AND     BX,0FFFEh\r
1182                 $NEXT\r
1183 \r
1184 ;   CELLS       ( n1 -- n2 )                    \ CORE\r
1185 ;               Calculate number of address units for n1 cells.\r
1186 ;\r
1187 ;   : CELLS     cell-size * ;   \ slow, very portable\r
1188 ;   : CELLS     2* ;            \ fast, must be redefined for each system\r
1189 \r
1190                 $COLON  5,'CELLS',CELLS,_FLINK\r
1191                 DW      TwoStar,EXIT\r
1192 \r
1193 ;   CHARS       ( n1 -- n2 )                    \ CORE\r
1194 ;               Calculate number of address units for n1 characters.\r
1195 ;\r
1196 ;   : CHARS     char-size * ;   \ slow, very portable\r
1197 ;   : CHARS     ;               \ fast, must be redefined for each system\r
1198 \r
1199                 $COLON  5,'CHARS',CHARS,_FLINK\r
1200                 DW      EXIT\r
1201 \r
1202 ;   !           ( x a-addr -- )                 \ CORE\r
1203 ;               Store x at a aligned address.\r
1204 \r
1205                 $CODE   1,'!',Store,_FLINK\r
1206                 POP     [BX]\r
1207                 POP     BX\r
1208                 $NEXT\r
1209 \r
1210 ;   0<          ( n -- flag )                   \ CORE\r
1211 ;               Return true if n is negative.\r
1212 \r
1213                 $CODE   2,'0<',ZeroLess,_FLINK\r
1214                 MOV     AX,BX\r
1215                 CWD             ;sign extend\r
1216                 MOV     BX,DX\r
1217                 $NEXT\r
1218 \r
1219 ;   0=          ( x -- flag )                   \ CORE\r
1220 ;               Return true if x is zero.\r
1221 \r
1222                 $CODE   2,'0=',ZeroEquals,_FLINK\r
1223                 OR      BX,BX\r
1224                 MOV     BX,TRUEE\r
1225                 JZ      ZEQUAL1\r
1226                 INC     BX\r
1227 ZEQUAL1:        $NEXT\r
1228 \r
1229 ;   2*          ( x1 -- x2 )                    \ CORE\r
1230 ;               Bit-shift left, filling the least significant bit with 0.\r
1231 \r
1232                 $CODE   2,'2*',TwoStar,_FLINK\r
1233                 SHL     BX,1\r
1234                 $NEXT\r
1235 \r
1236 ;   2/          ( x1 -- x2 )                    \ CORE\r
1237 ;               Bit-shift right, leaving the most significant bit unchanged.\r
1238 \r
1239                 $CODE   2,'2/',TwoSlash,_FLINK\r
1240                 SAR     BX,1\r
1241                 $NEXT\r
1242 \r
1243 ;   >R          ( x -- ) ( R: -- x )            \ CORE\r
1244 ;               Move top of the data stack item to the return stack.\r
1245 \r
1246                 $CODE   COMPO+2,'>R',ToR,_FLINK\r
1247                 SUB     BP,CELLL                ;adjust RP\r
1248                 MOV     [BP],BX\r
1249                 POP     BX\r
1250                 $NEXT\r
1251 \r
1252 ;   @           ( a-addr -- x )                 \ CORE\r
1253 ;               Push the contents at a-addr to the data stack.\r
1254 \r
1255                 $CODE   1,'@',Fetch,_FLINK\r
1256                 MOV     BX,[BX]\r
1257                 $NEXT\r
1258 \r
1259 ;   AND         ( x1 x2 -- x3 )                 \ CORE\r
1260 ;               Bitwise AND.\r
1261 \r
1262                 $CODE   3,'AND',ANDD,_FLINK\r
1263                 POP     AX\r
1264                 AND     BX,AX\r
1265                 $NEXT\r
1266 \r
1267 ;   C!          ( char c-addr -- )              \ CORE\r
1268 ;               Store char at c-addr.\r
1269 \r
1270                 $CODE   2,'C!',CStore,_FLINK\r
1271                 POP     AX\r
1272                 MOV     [BX],AL\r
1273                 POP     BX\r
1274                 $NEXT\r
1275 \r
1276 ;   C@          ( c-addr -- char )              \ CORE\r
1277 ;               Fetch the character stored at c-addr.\r
1278 \r
1279                 $CODE   2,'C@',CFetch,_FLINK\r
1280                 MOV     BL,[BX]\r
1281                 XOR     BH,BH\r
1282                 $NEXT\r
1283 \r
1284 ;   DROP        ( x -- )                        \ CORE\r
1285 ;               Discard top stack item.\r
1286 \r
1287                 $CODE   4,'DROP',DROP,_FLINK\r
1288                 POP     BX\r
1289                 $NEXT\r
1290 \r
1291 ;   DUP         ( x -- x x )                    \ CORE\r
1292 ;               Duplicate the top stack item.\r
1293 \r
1294                 $CODE   3,'DUP',DUPP,_FLINK\r
1295                 PUSH    BX\r
1296                 $NEXT\r
1297 \r
1298 ;   EXECUTE     ( i*x xt -- j*x )               \ CORE\r
1299 ;               Perform the semantics indentified by execution token, xt.\r
1300 \r
1301                 $CODE   7,'EXECUTE',EXECUTE,_FLINK\r
1302                 MOV     AX,BX\r
1303                 POP     BX\r
1304                 JMP     AX                      ;jump to the code address\r
1305                 $ALIGN\r
1306 \r
1307 ;   EXIT        ( -- ) ( R: nest-sys -- )       \ CORE\r
1308 ;               Return control to the calling definition.\r
1309 \r
1310                 $CODE   COMPO+4,'EXIT',EXIT,_FLINK\r
1311                 XCHG    BP,SP                   ;exchange pointers\r
1312                 POP     SI                      ;pop return stack\r
1313                 XCHG    BP,SP                   ;restore the pointers\r
1314                 $NEXT\r
1315 \r
1316 ;   MOVE        ( addr1 addr2 u -- )            \ CORE\r
1317 ;               Copy u address units from addr1 to addr2 if u is greater\r
1318 ;               than zero. This word is CODE defined since no other Standard\r
1319 ;               words can handle address unit directly.\r
1320 \r
1321                 $CODE   4,'MOVE',MOVE,_FLINK\r
1322                 POP     DI\r
1323                 POP     DX\r
1324                 OR      BX,BX\r
1325                 JZ      MOVE2\r
1326                 MOV     CX,BX\r
1327                 XCHG    DX,SI                   ;save SI\r
1328                 MOV     AX,DS\r
1329                 MOV     ES,AX                   ;set ES same as DS\r
1330                 CMP     SI,DI\r
1331                 JC      MOVE1\r
1332                 REP MOVSB\r
1333                 MOV     SI,DX\r
1334 MOVE2:          POP     BX\r
1335                 $NEXT\r
1336 MOVE1:          STD\r
1337                 ADD     DI,CX\r
1338                 DEC     DI\r
1339                 ADD     SI,CX\r
1340                 DEC     SI\r
1341                 REP MOVSB\r
1342                 CLD\r
1343                 MOV     SI,DX\r
1344                 POP     BX\r
1345                 $NEXT\r
1346 \r
1347 ;   OR          ( x1 x2 -- x3 )                 \ CORE\r
1348 ;               Return bitwise inclusive-or of x1 with x2.\r
1349 \r
1350                 $CODE   2,'OR',ORR,_FLINK\r
1351                 POP     AX\r
1352                 OR      BX,AX\r
1353                 $NEXT\r
1354 \r
1355 ;   OVER        ( x1 x2 -- x1 x2 x1 )           \ CORE\r
1356 ;               Copy second stack item to top of the stack.\r
1357 \r
1358                 $CODE   4,'OVER',OVER,_FLINK\r
1359                 MOV     DI,SP\r
1360                 PUSH    BX\r
1361                 MOV     BX,[DI]\r
1362                 $NEXT\r
1363 \r
1364 ;   R>          ( -- x ) ( R: x -- )            \ CORE\r
1365 ;               Move x from the return stack to the data stack.\r
1366 \r
1367                 $CODE   COMPO+2,'R>',RFrom,_FLINK\r
1368                 PUSH    BX\r
1369                 MOV     BX,[BP]\r
1370                 ADD     BP,CELLL                ;adjust RP\r
1371                 $NEXT\r
1372 \r
1373 ;   R@          ( -- x ) ( R: x -- x )          \ CORE\r
1374 ;               Copy top of return stack to the data stack.\r
1375 \r
1376                 $CODE   COMPO+2,'R@',RFetch,_FLINK\r
1377                 PUSH    BX\r
1378                 MOV     BX,[BP]\r
1379                 $NEXT\r
1380 \r
1381 ;   SWAP        ( x1 x2 -- x2 x1 )              \ CORE\r
1382 ;               Exchange top two stack items.\r
1383 \r
1384                 $CODE   4,'SWAP',SWAP,_FLINK\r
1385                 MOV     DI,SP\r
1386                 XCHG    BX,[DI]\r
1387                 $NEXT\r
1388 \r
1389 ;   XOR         ( x1 x2 -- x3 )                 \ CORE\r
1390 ;               Bitwise exclusive OR.\r
1391 \r
1392                 $CODE   3,'XOR',XORR,_FLINK\r
1393                 POP     AX\r
1394                 XOR     BX,AX\r
1395                 $NEXT\r
1396 \r
1397 ;;;;;;;;;;;;;;;;\r
1398 ; System constants and variables\r
1399 ;;;;;;;;;;;;;;;;\r
1400 \r
1401 ;   #order0     ( -- a-addr )\r
1402 ;               Start address of default search order.\r
1403 \r
1404                 $CONST  7,'#order0',NumberOrder0,AddrNumberOrder0,_SLINK\r
1405 \r
1406 ;   'ekey?      ( -- a-addr )\r
1407 ;               Execution vector of EKEY?.\r
1408 \r
1409                 $VALUE  6,"'ekey?",TickEKEYQ,ValueTickEKEYQ,_SLINK\r
1410 \r
1411 ;   'ekey       ( -- a-addr )\r
1412 ;               Execution vector of EKEY.\r
1413 \r
1414                 $VALUE  5,"'ekey",TickEKEY,ValueTickEKEY,_SLINK\r
1415 \r
1416 ;   'emit?      ( -- a-addr )\r
1417 ;               Execution vector of EMIT?.\r
1418 \r
1419                 $VALUE  6,"'emit?",TickEMITQ,ValueTickEMITQ,_SLINK\r
1420 \r
1421 ;   'emit       ( -- a-addr )\r
1422 ;               Execution vector of EMIT.\r
1423 \r
1424                 $VALUE  5,"'emit",TickEMIT,ValueTickEMIT,_SLINK\r
1425 \r
1426 ;   'init-i/o   ( -- a-addr )\r
1427 ;               Execution vector to initialize input/output devices.\r
1428 \r
1429                 $VALUE  9,"'init-i/o",TickINIT_IO,ValueTickINIT_IO,_SLINK\r
1430 \r
1431 ;   'prompt     ( -- a-addr )\r
1432 ;               Execution vector of '.prompt'.\r
1433 \r
1434                 $VALUE  7,"'prompt",TickPrompt,ValueTickPrompt,_SLINK\r
1435 \r
1436 ;   'boot       ( -- a-addr )\r
1437 ;               Execution vector of COLD.\r
1438 \r
1439                 $VALUE  5,"'boot",TickBoot,ValueTickBoot,_SLINK\r
1440 \r
1441 ;   SOURCE-ID   ( -- 0 | -1 )                   \ CORE EXT\r
1442 ;               Identify the input source. -1 for string (via EVALUATE) and\r
1443 ;               0 for user input device.\r
1444 \r
1445                 $VALUE  9,'SOURCE-ID',SOURCE_ID,ValueSOURCE_ID,_FLINK\r
1446 AddrSOURCE_ID   EQU     $-CELLL\r
1447 \r
1448 ;   HERE        ( -- addr )                     \ CORE\r
1449 ;               Return data space pointer.\r
1450 \r
1451                 $VALUE  4,'HERE',HERE,ValueHERE,_FLINK\r
1452 AddrHERE        EQU     $-CELLL\r
1453 \r
1454 ;   'doWord     ( -- a-addr )\r
1455 ;               Execution vectors for 'interpret'.\r
1456 \r
1457                 $CONST  7,"'doWord",TickDoWord,AddrTickDoWord,_SLINK\r
1458 \r
1459 ;   BASE        ( -- a-addr )                   \ CORE\r
1460 ;               Return the address of the radix base for numeric I/O.\r
1461 \r
1462                 $CONST  4,'BASE',BASE,AddrBASE,_FLINK\r
1463 \r
1464 ;   THROWMsgTbl ( -- a-addr )                   \ CORE\r
1465 ;               Return the address of the THROW message table.\r
1466 \r
1467                 $CONST  11,'THROWMsgTbl',THROWMsgTbl,AddrTHROWMsgTbl,_SLINK\r
1468 \r
1469 ;   memTop      ( -- a-addr )\r
1470 ;               Top of free RAM area.\r
1471 \r
1472                 $VALUE  6,'memTop',MemTop,?,_SLINK\r
1473 AddrMemTop      EQU     $-CELLL\r
1474 \r
1475 ;   bal         ( -- n )\r
1476 ;               Return the depth of control-flow stack.\r
1477 \r
1478                 $VALUE  3,'bal',Bal,?,_SLINK\r
1479 AddrBal         EQU     $-CELLL\r
1480 \r
1481 ;   notNONAME?  ( -- f )\r
1482 ;               Used by ';' whether to do 'linkLast' or not\r
1483 \r
1484                 $VALUE  10,'notNONAME?',NotNONAMEQ,?,_SLINK\r
1485 AddrNotNONAMEQ  EQU     $-CELLL\r
1486 \r
1487 ;   rakeVar     ( -- a-addr )\r
1488 ;               Used by 'rake' to gather LEAVE.\r
1489 \r
1490                 $CONST  7,'rakeVar',RakeVar,AddrRakeVar,_SLINK\r
1491 \r
1492 ;   #order      ( -- a-addr )\r
1493 ;               Hold the search order stack depth.\r
1494 \r
1495                 $CONST  6,'#order',NumberOrder,AddrNumberOrder,_SLINK\r
1496 \r
1497 ;   current     ( -- a-addr )\r
1498 ;               Point to the wordlist to be extended.\r
1499 \r
1500                 $CONST  7,'current',Current,AddrCurrent,_SLINK\r
1501 \r
1502 ;   FORTH-WORDLIST   ( -- wid )                 \ SEARCH\r
1503 ;               Return wid of Forth wordlist.\r
1504 \r
1505                 $CONST  14,'FORTH-WORDLIST',FORTH_WORDLIST,AddrFORTH_WORDLIST,_FLINK\r
1506 FORTH_WORDLISTName      EQU     _NAME-0\r
1507 \r
1508 ;   NONSTANDARD-WORDLIST   ( -- wid )\r
1509 ;               Return wid of non-standard wordlist.\r
1510 \r
1511                 $CONST  20,'NONSTANDARD-WORDLIST',NONSTANDARD_WORDLIST,AddrNONSTANDARD_WORDLIST,_FLINK\r
1512 NONSTANDARD_WORDLISTName EQU    _NAME-0\r
1513 \r
1514 ;   envQList    ( -- wid )\r
1515 ;               Return wid of ENVIRONMENT? string list. Never put this wid in\r
1516 ;               search-order. It should be used only by SET-CURRENT to add new\r
1517 ;               environment query string after addition of a complete wordset.\r
1518 \r
1519                 $CONST  8,'envQList',EnvQList,AddrEnvQList,_SLINK\r
1520 \r
1521 ;   userP       ( -- a-addr )\r
1522 ;               Return address of USER variable area of current task.\r
1523 \r
1524                 $CONST  5,'userP',UserP,AddrUserP,_SLINK\r
1525 \r
1526 ;   SystemTask  ( -- a-addr )\r
1527 ;               Return system task's tid.\r
1528 \r
1529                 $CONST  10,'SystemTask',SystemTask,SysTask,_SLINK\r
1530 SystemTaskName  EQU     _NAME-0\r
1531 \r
1532 ;   follower    ( -- a-addr )\r
1533 ;               Point next task's 'status' USER variable.\r
1534 \r
1535                 $USER   8,'follower',Follower,SysFollower-SysUserP,_SLINK\r
1536 \r
1537 ;   status      ( -- a-addr )\r
1538 ;               Status of current task. Point 'pass' or 'wake'.\r
1539 \r
1540                 $USER   6,'status',Status,SysStatus-SysUserP,_SLINK\r
1541 \r
1542 ;   stackTop    ( -- a-addr )\r
1543 ;               Store current task's top of stack position.\r
1544 \r
1545                 $USER   8,'stackTop',StackTop,SysStackTop-SysUserP,_SLINK\r
1546 \r
1547 ;   throwFrame  ( -- a-addr )\r
1548 ;               THROW frame for CATCH and THROW need to be saved for eack task.\r
1549 \r
1550                 $USER   10,'throwFrame',ThrowFrame,SysThrowFrame-SysUserP,_SLINK\r
1551 \r
1552 ;   taskName    ( -- a-addr )\r
1553 ;               Current task's task ID.\r
1554 \r
1555                 $USER   8,'taskName',TaskName,SysTaskName-SysUserP,_SLINK\r
1556 \r
1557 ;   user1       ( -- a-addr )\r
1558 ;               One free USER variable for each task.\r
1559 \r
1560                 $USER   5,'user1',User1,SysUser1-SysUserP,_SLINK\r
1561 \r
1562 ; ENVIRONMENT? strings can be searched using SEARCH-WORDLIST and can be\r
1563 ; EXECUTEd. This wordlist is completely hidden to Forth system except\r
1564 ; ENVIRONMENT? .\r
1565 \r
1566                 $ENVIR  3,'CPU'\r
1567                 DW      DoLIT,CPUStr,COUNT,EXIT\r
1568 \r
1569                 $ENVIR  5,'model'\r
1570                 DW      DoLIT,ModelStr,COUNT,EXIT\r
1571 \r
1572                 $ENVIR  7,'version'\r
1573                 DW      DoLIT,VersionStr,COUNT,EXIT\r
1574 \r
1575                 $ENVIR  15,'/COUNTED-STRING'\r
1576                 DW      DoLIT,MaxChar,EXIT\r
1577 \r
1578                 $ENVIR  5,'/HOLD'\r
1579                 DW      DoLIT,PADSize,EXIT\r
1580 \r
1581                 $ENVIR  4,'/PAD'\r
1582                 DW      DoLIT,PADSize,EXIT\r
1583 \r
1584                 $ENVIR  17,'ADDRESS-UNIT-BITS'\r
1585                 DW      DoLIT,8,EXIT\r
1586 \r
1587                 $ENVIR  4,'CORE'\r
1588                 DW      DoLIT,TRUEE,EXIT\r
1589 \r
1590                 $ENVIR  7,'FLOORED'\r
1591                 DW      DoLIT,TRUEE,EXIT\r
1592 \r
1593                 $ENVIR  8,'MAX-CHAR'\r
1594                 DW      DoLIT,MaxChar,EXIT      ;max value of character set\r
1595 \r
1596                 $ENVIR  5,'MAX-D'\r
1597                 DW      DoLIT,MaxUnsigned,DoLIT,MaxSigned,EXIT\r
1598 \r
1599                 $ENVIR  5,'MAX-N'\r
1600                 DW      DoLIT,MaxSigned,EXIT\r
1601 \r
1602                 $ENVIR  5,'MAX-U'\r
1603                 DW      DoLIT,MaxUnsigned,EXIT\r
1604 \r
1605                 $ENVIR  6,'MAX-UD'\r
1606                 DW      DoLIT,MaxUnsigned,DoLIT,MaxUnsigned,EXIT\r
1607 \r
1608                 $ENVIR  18,'RETURN-STACK-CELLS'\r
1609                 DW      DoLIT,RTCells,EXIT\r
1610 \r
1611                 $ENVIR  11,'STACK-CELLS'\r
1612                 DW      DoLIT,DTCells,EXIT\r
1613 \r
1614                 $ENVIR  9,'EXCEPTION'\r
1615                 DW      DoLIT,TRUEE,EXIT\r
1616 \r
1617                 $ENVIR  13,'EXCEPTION-EXT'\r
1618                 DW      DoLIT,TRUEE,EXIT\r
1619 \r
1620                 $ENVIR  9,'WORDLISTS'\r
1621                 DW      DoLIT,OrderDepth,EXIT\r
1622 \r
1623 ;;;;;;;;;;;;;;;;\r
1624 ; Non-Standard words - Colon definitions\r
1625 ;;;;;;;;;;;;;;;;\r
1626 \r
1627 ;   (')         ( "<spaces>name" -- xt 1 | xt -1 )\r
1628 ;               Parse a name, find it and return execution token and\r
1629 ;               -1 or 1 ( IMMEDIATE) if found\r
1630 ;\r
1631 ;   : (')       PARSE-WORD search-word ?DUP IF NIP EXIT THEN\r
1632 ;               errWord 2!      \ if not found error\r
1633 ;               -13 THROW ;     \ undefined word\r
1634 \r
1635                 $COLON  3,"(')",ParenTick,_SLINK\r
1636                 DW      PARSE_WORD,Search_word,QuestionDUP,ZBranch,PTICK1\r
1637                 DW      NIP,EXIT\r
1638 PTICK1          DW      ErrWord,TwoStore,DoLIT,-13,THROW\r
1639 \r
1640 ;   (d.)        ( d -- c-addr u )\r
1641 ;               Convert a double number to a string.\r
1642 ;\r
1643 ;   : (d.)      SWAP OVER  DUP 0< IF  DNEGATE  THEN\r
1644 ;               <#  #S ROT SIGN  #> ;\r
1645 \r
1646                 $COLON  4,'(d.)',ParenDDot,_SLINK\r
1647                 DW      SWAP,OVER,DUPP,ZeroLess,ZBranch,PARDD1\r
1648                 DW      DNEGATE\r
1649 PARDD1          DW      LessNumberSign,NumberSignS,ROT\r
1650                 DW      SIGN,NumberSignGreater,EXIT\r
1651 \r
1652 ;   .ok         ( -- )\r
1653 ;               Display 'ok'.\r
1654 ;\r
1655 ;   : .ok       ." ok" ;\r
1656 \r
1657                 $COLON  3,'.ok',DotOK,_SLINK\r
1658                 $INSTR  'ok'\r
1659                 DW      TYPEE,EXIT\r
1660 \r
1661 ;   .prompt         ( -- )\r
1662 ;               Disply Forth prompt. This word is vectored.\r
1663 ;\r
1664 ;   : .prompt   'prompt EXECUTE ;\r
1665 \r
1666                 $COLON  7,'.prompt',DotPrompt,_SLINK\r
1667                 DW      TickPrompt,EXECUTE,EXIT\r
1668 \r
1669 ;   0           ( -- 0 )\r
1670 ;               Return zero.\r
1671 \r
1672                 $CONST  1,'0',Zero,0,_SLINK\r
1673 \r
1674 ;   1           ( -- 1 )\r
1675 ;               Return one.\r
1676 \r
1677                 $CONST  1,'1',One,1,_SLINK\r
1678 \r
1679 ;   -1          ( -- -1 )\r
1680 ;               Return -1.\r
1681 \r
1682                 $CONST  2,'-1',MinusOne,-1,_SLINK\r
1683 \r
1684 ;   abort"msg   ( -- a-addr )\r
1685 ;               Abort" error message string address.\r
1686 \r
1687                 $VAR    9,'abort"msg',AbortQMsg,2,_SLINK\r
1688 \r
1689 ;   bal+        ( -- )\r
1690 ;               Increase bal by 1.\r
1691 ;\r
1692 ;   : bal+      bal 1+ TO bal ;\r
1693 \r
1694                 $COLON  4,'bal+',BalPlus,_SLINK\r
1695                 DW      Bal,OnePlus,DoTO,AddrBal,EXIT\r
1696 \r
1697 ;   bal-        ( -- )\r
1698 ;               Decrease bal by 1.\r
1699 ;\r
1700 ;   : bal-      bal 1- TO bal ;\r
1701 \r
1702                 $COLON  4,'bal-',BalMinus,_SLINK\r
1703                 DW      Bal,OneMinus,DoTO,AddrBal,EXIT\r
1704 \r
1705 ;   cell-       ( a-addr1 -- a-addr2 )\r
1706 ;               Return previous aligned cell address.\r
1707 ;\r
1708 ;   : cell-     -(cell-size) + ;\r
1709 \r
1710                 $COLON  5,'cell-',CellMinus,_SLINK\r
1711                 DW      DoLIT,0-CELLL,Plus,EXIT\r
1712 \r
1713 ;   COMPILE-ONLY   ( -- )\r
1714 ;               Make the most recent definition an compile-only word.\r
1715 ;\r
1716 ;   : COMPILE-ONLY   lastName [ =comp ] LITERAL OVER @ OR SWAP ! ;\r
1717 \r
1718                 $COLON  12,'COMPILE-ONLY',COMPILE_ONLY,_SLINK\r
1719                 DW      LastName,DoLIT,COMPO,OVER,Fetch,ORR,SWAP,Store,EXIT\r
1720 \r
1721 ;   doS"        ( u -- c-addr u )\r
1722 ;               Run-time function of S" .\r
1723 ;\r
1724 ;   : doS"      R> SWAP 2DUP + ALIGNED >R ; COMPILE-ONLY\r
1725 \r
1726                 $COLON  COMPO+4,'doS"',DoSQuote,_SLINK\r
1727                 DW      RFrom,SWAP,TwoDUP,Plus,ALIGNED,ToR,EXIT\r
1728 \r
1729 ;   doDO        ( n1|u1 n2|u2 -- ) ( R: -- n1 n2-n1-max_negative )\r
1730 ;               Run-time funtion of DO.\r
1731 ;\r
1732 ;   : doDO      >R max-negative + R> OVER - SWAP R> SWAP >R SWAP >R >R ;\r
1733 \r
1734                 $COLON  COMPO+4,'doDO',DoDO,_SLINK\r
1735                 DW      ToR,DoLIT,MaxNegative,Plus,RFrom\r
1736                 DW      OVER,Minus,SWAP,RFrom,SWAP,ToR,SWAP,ToR,ToR,EXIT\r
1737 \r
1738 ;   errWord     ( -- a-addr )\r
1739 ;               Last found word. To be used to display the word causing error.\r
1740 \r
1741                 $VAR    7,'errWord',ErrWord,2,_SLINK\r
1742 \r
1743 ;   head,       ( "<spaces>name" -- )\r
1744 ;               Parse a word and build a dictionary entry using a name.\r
1745 ;\r
1746 ;   : head,     PARSE-WORD DUP 0=\r
1747 ;               IF errWord 2! -16 THROW THEN\r
1748 ;                               \ attempt to use zero-length string as a name\r
1749 ;               DUP =mask > IF -19 THROW THEN   \ definition name too long\r
1750 ;               2DUP GET-CURRENT SEARCH-WORDLIST  \ name exist?\r
1751 ;               IF DROP ." redefine " 2DUP TYPE SPACE THEN \ warn if redefined\r
1752 ;               HERE ALIGNED TO HERE            \ align\r
1753 ;               GET-CURRENT @ ,                 \ build wordlist link\r
1754 ;               HERE DUP >R pack" TO HERE R>    \ pack the name in dictionary\r
1755 ;               DUP , TO lastName ;\r
1756 \r
1757                 $COLON  5,'head,',HeadComma,_SLINK\r
1758                 DW      PARSE_WORD,DUPP,ZBranch,HEADC1\r
1759                 DW      DUPP,DoLIT,MASKK,GreaterThan,ZBranch,HEADC3\r
1760                 DW      DoLIT,-19,THROW\r
1761 HEADC3          DW      TwoDUP,GET_CURRENT,SEARCH_WORDLIST,ZBranch,HEADC2\r
1762                 DW      DROP\r
1763                 $INSTR  'redefine '\r
1764                 DW      TYPEE,TwoDUP,TYPEE,SPACE\r
1765 HEADC2          DW      HERE,ALIGNED,DoTO,AddrHERE\r
1766                 DW      GET_CURRENT,Fetch,Comma\r
1767                 DW      HERE,DUPP,ToR,PackQuote,DoTO,AddrHERE,RFrom\r
1768                 DW      DUPP,Comma,DoTO,AddrLastName,EXIT\r
1769 HEADC1          DW      ErrWord,TwoStore,DoLIT,-16,THROW\r
1770 \r
1771 ;   hld         ( -- a-addr )\r
1772 ;               Hold a pointer in building a numeric output string.\r
1773 \r
1774                 $VAR    3,'hld',HLD,1,_SLINK\r
1775 \r
1776 ;   interpret   ( i*x -- j*x )\r
1777 ;               Intrepret input string.\r
1778 ;\r
1779 ;   : interpret BEGIN  DEPTH 0< IF -4 THROW THEN        \ stack underflow\r
1780 ;                      PARSE-WORD DUP\r
1781 ;               WHILE  2DUP errWord 2!\r
1782 ;                      search-word          \ ca u 0 | xt f -1 | xt f 1\r
1783 ;                      DUP IF\r
1784 ;                        SWAP STATE @ OR 0= \ compile-only in interpretation\r
1785 ;                        IF -14 THROW THEN  \ interpreting a compile-only word\r
1786 ;                      THEN\r
1787 ;                      1+ 2* STATE @ 1+ + CELLS 'doWord + @ EXECUTE\r
1788 ;               REPEAT 2DROP ;\r
1789 \r
1790                 $COLON  9,'interpret',Interpret,_SLINK\r
1791 INTERP1         DW      DEPTH,ZeroLess,ZBranch,INTERP2\r
1792                 DW      DoLIT,-4,THROW\r
1793 INTERP2         DW      PARSE_WORD,DUPP,ZBranch,INTERP3\r
1794                 DW      TwoDUP,ErrWord,TwoStore\r
1795                 DW      Search_word,DUPP,ZBranch,INTERP5\r
1796                 DW      SWAP,STATE,Fetch,ORR,ZBranch,INTERP4\r
1797 INTERP5         DW      OnePlus,TwoStar,STATE,Fetch,OnePlus,Plus,CELLS\r
1798                 DW      TickDoWord,Plus,Fetch,EXECUTE\r
1799                 DW      Branch,INTERP1\r
1800 INTERP3         DW      TwoDROP,EXIT\r
1801 INTERP4         DW      DoLIT,-14,THROW\r
1802 \r
1803 ;   optiCOMPILE, ( xt -- )\r
1804 ;               Optimized COMPILE, . Reduce doLIST ... EXIT sequence if\r
1805 ;               xt is COLON definition which contains less than two words.\r
1806 ;\r
1807 ;   : optiCOMPILE,\r
1808 ;               DUP ?call ['] doLIST = IF\r
1809 ;                   DUP @ ['] EXIT = IF         \ if first word is EXIT\r
1810 ;                     2DROP EXIT THEN\r
1811 ;                   DUP CELL+ @ ['] EXIT = IF   \ if second word is EXIT\r
1812 ;                     @ DUP ['] doLIT XOR  \ make sure it is not literal value\r
1813 ;                     IF SWAP THEN THEN\r
1814 ;               THEN THEN DROP COMPILE, ;\r
1815 \r
1816                 $COLON  12,'optiCOMPILE,',OptiCOMPILEComma,_SLINK\r
1817                 DW      DUPP,QCall,DoLIT,DoLIST,Equals,ZBranch,OPTC2\r
1818                 DW      DUPP,Fetch,DoLIT,EXIT,Equals,ZBranch,OPTC1\r
1819                 DW      TwoDROP,EXIT\r
1820 OPTC1           DW      DUPP,CELLPlus,Fetch,DoLIT,EXIT,Equals,ZBranch,OPTC2\r
1821                 DW      Fetch,DUPP,DoLIT,DoLIT,XORR,ZBranch,OPTC2\r
1822                 DW      SWAP\r
1823 OPTC2           DW      DROP,COMPILEComma,EXIT\r
1824 \r
1825 ;   singleOnly  ( c-addr u -- x )\r
1826 ;               Handle the word not found in the search-order. If the string\r
1827 ;               is legal, leave a single cell number in interpretation state.\r
1828 ;\r
1829 ;   : singleOnly\r
1830 ;               0 DUP 2SWAP OVER C@ [CHAR] -\r
1831 ;               = DUP >R IF 1 /STRING THEN\r
1832 ;               >NUMBER IF -13 THROW THEN       \ undefined word\r
1833 ;               2DROP R> IF NEGATE THEN ;\r
1834 \r
1835                 $COLON  10,'singleOnly',SingleOnly,_SLINK\r
1836                 DW      Zero,DUPP,TwoSWAP,OVER,CFetch,DoLIT,'-'\r
1837                 DW      Equals,DUPP,ToR,ZBranch,SINGLEO4\r
1838                 DW      One,SlashSTRING\r
1839 SINGLEO4        DW      ToNUMBER,ZBranch,SINGLEO1\r
1840                 DW      DoLIT,-13,THROW\r
1841 SINGLEO1        DW      TwoDROP,RFrom,ZBranch,SINGLEO2\r
1842                 DW      NEGATE\r
1843 SINGLEO2        DW      EXIT\r
1844 \r
1845 ;   singleOnly, ( c-addr u -- )\r
1846 ;               Handle the word not found in the search-order. Compile a\r
1847 ;               single cell number in compilation state.\r
1848 ;\r
1849 ;   : singleOnly,\r
1850 ;               singleOnly LITERAL ;\r
1851 \r
1852                 $COLON  11,'singleOnly,',SingleOnlyComma,_SLINK\r
1853                 DW      SingleOnly,LITERAL,EXIT\r
1854 \r
1855 ;   (doubleAlso) ( c-addr u -- x 1 | x x 2 )\r
1856 ;               If the string is legal, leave a single or double cell number\r
1857 ;               and size of the number.\r
1858 ;\r
1859 ;   : (doubleAlso)\r
1860 ;               0 DUP 2SWAP OVER C@ [CHAR] -\r
1861 ;               = DUP >R IF 1 /STRING THEN\r
1862 ;               >NUMBER ?DUP\r
1863 ;               IF   1- IF -13 THROW THEN     \ more than one char is remained\r
1864 ;                    DUP C@ [CHAR] . XOR      \ last char is not '.'\r
1865 ;                    IF -13 THROW THEN        \ undefined word\r
1866 ;                    R> IF DNEGATE THEN\r
1867 ;                    2 EXIT               THEN\r
1868 ;               2DROP R> IF NEGATE THEN       \ single number\r
1869 ;               1 ;\r
1870 \r
1871                 $COLON  12,'(doubleAlso)',ParenDoubleAlso,_SLINK\r
1872                 DW      Zero,DUPP,TwoSWAP,OVER,CFetch,DoLIT,'-'\r
1873                 DW      Equals,DUPP,ToR,ZBranch,DOUBLEA1\r
1874                 DW      One,SlashSTRING\r
1875 DOUBLEA1        DW      ToNUMBER,QuestionDUP,ZBranch,DOUBLEA4\r
1876                 DW      OneMinus,ZBranch,DOUBLEA3\r
1877 DOUBLEA2        DW      DoLIT,-13,THROW\r
1878 DOUBLEA3        DW      CFetch,DoLIT,'.',Equals,ZBranch,DOUBLEA2\r
1879                 DW      RFrom,ZBranch,DOUBLEA5\r
1880                 DW      DNEGATE\r
1881 DOUBLEA5        DW      DoLIT,2,EXIT\r
1882 DOUBLEA4        DW      TwoDROP,RFrom,ZBranch,DOUBLEA6\r
1883                 DW      NEGATE\r
1884 DOUBLEA6        DW      One,EXIT\r
1885 \r
1886 ;   doubleAlso  ( c-addr u -- x | x x )\r
1887 ;               Handle the word not found in the search-order. If the string\r
1888 ;               is legal, leave a single or double cell number in\r
1889 ;               interpretation state.\r
1890 ;\r
1891 ;   : doubleAlso\r
1892 ;               (doubleAlso) DROP ;\r
1893 \r
1894                 $COLON  10,'doubleAlso',DoubleAlso,_SLINK\r
1895                 DW      ParenDoubleAlso,DROP,EXIT\r
1896 \r
1897 ;   doubleAlso, ( c-addr u -- )\r
1898 ;               Handle the word not found in the search-order. If the string\r
1899 ;               is legal, compile a single or double cell number in\r
1900 ;               compilation state.\r
1901 ;\r
1902 ;   : doubleAlso,\r
1903 ;               (doubleAlso) 1- IF SWAP LITERAL THEN LITERAL ;\r
1904 \r
1905                 $COLON  11,'doubleAlso,',DoubleAlsoComma,_SLINK\r
1906                 DW      ParenDoubleAlso,OneMinus,ZBranch,DOUBC1\r
1907                 DW      SWAP,LITERAL\r
1908 DOUBC1          DW      LITERAL,EXIT\r
1909 \r
1910 ;   -.          ( -- )\r
1911 ;               You don't need this word unless you care that '-.' returns\r
1912 ;               double cell number 0. Catching illegal number '-.' in this way\r
1913 ;               is easier than make 'interpret' catch this exception.\r
1914 ;\r
1915 ;   : -.        -13 THROW ; IMMEDIATE   \ undefined word\r
1916 \r
1917                 $COLON  IMMED+2,'-.',MinusDot,_SLINK\r
1918                 DW      DoLIT,-13,THROW\r
1919 \r
1920 ;   lastName    ( -- c-addr )\r
1921 ;               Return the address of the last definition name.\r
1922 \r
1923                 $VALUE  8,'lastName',LastName,?,_SLINK\r
1924 AddrLastName    EQU     $-CELLL\r
1925 \r
1926 ;   linkLast    ( -- )\r
1927 ;               Link the word being defined to the current wordlist.\r
1928 ;               Do nothing if the last definition is made by :NONAME .\r
1929 ;\r
1930 ;   : linkLast  lastName GET-CURRENT ! ;\r
1931 \r
1932                 $COLON  8,'linkLast',LinkLast,_SLINK\r
1933                 DW      LastName,GET_CURRENT,Store,EXIT\r
1934 \r
1935 ;   name>xt     ( c-addr -- xt )\r
1936 ;               Return execution token using counted string at c-addr.\r
1937 ;\r
1938 ;   : name>xt   COUNT [ =MASK ] LITERAL AND + ALIGNED CELL+ ;\r
1939 \r
1940                 $COLON  7,'name>xt',NameToXT,_SLINK\r
1941                 DW      COUNT,DoLIT,MASKK,ANDD,Plus,ALIGNED,CELLPlus,EXIT\r
1942 \r
1943 ;   pack"       ( c-addr u a-addr -- a-addr2 )\r
1944 ;               Place a string c-addr u at a-addr and gives the next\r
1945 ;               cell-aligned address. Fill the rest of the last cell with\r
1946 ;               null character.\r
1947 ;\r
1948 ;   : pack"     2DUP SWAP CHARS + CHAR+ DUP >R  \ ca u aa aa+u+1\r
1949 ;               ALIGNED cell- 0 SWAP !          \ fill 0 at the end of string\r
1950 ;               2DUP C! CHAR+ SWAP              \ c-addr a-addr+1 u\r
1951 ;               CHARS MOVE R> ALIGNED ; COMPILE-ONLY\r
1952 \r
1953                 $COLON  5,'pack"',PackQuote,_SLINK\r
1954                 DW      TwoDUP,SWAP,CHARS,Plus,CHARPlus,DUPP,ToR\r
1955                 DW      ALIGNED,CellMinus,Zero,SWAP,Store\r
1956                 DW      TwoDUP,CStore,CHARPlus,SWAP\r
1957                 DW      CHARS,MOVE,RFrom,ALIGNED,EXIT\r
1958 \r
1959 ;   PARSE-WORD  ( "<spaces>ccc<space>" -- c-addr u )\r
1960 ;               Skip leading spaces and parse a word. Return the name.\r
1961 ;\r
1962 ;   : PARSE-WORD   BL skipPARSE ;\r
1963 \r
1964                 $COLON  10,'PARSE-WORD',PARSE_WORD,_SLINK\r
1965                 DW      BLank,SkipPARSE,EXIT\r
1966 \r
1967 ;   pipe        ( -- ) ( R: xt -- )\r
1968 ;               Connect most recently defined word to code following DOES>.\r
1969 ;               Structure of CREATEd word:\r
1970 ;                   | call-doCREATE | 0 or DOES> code addr | >BODY points here\r
1971 ;\r
1972 ;   : pipe      lastName name>xt ?call DUP IF   \ code-addr xt2\r
1973 ;                   ['] doCREATE = IF\r
1974 ;                   R> SWAP !           \ change DOES> code of CREATEd word\r
1975 ;                   EXIT\r
1976 ;               THEN THEN\r
1977 ;               -32 THROW       \ invalid name argument, no-CREATEd last name\r
1978 ;               ; COMPILE-ONLY\r
1979 \r
1980                 $COLON  COMPO+4,'pipe',Pipe,_SLINK\r
1981                 DW      LastName,NameToXT,QCall,DUPP,ZBranch,PIPE1\r
1982                 DW      DoLIT,DoCREATE,Equals,ZBranch,PIPE1\r
1983                 DW      RFrom,SWAP,Store,EXIT\r
1984 PIPE1           DW      DoLIT,-32,THROW\r
1985 \r
1986 ;   skipPARSE   ( char "<chars>ccc<char>" -- c-addr u )\r
1987 ;               Skip leading chars and parse a word using char as a\r
1988 ;               delimeter. Return the name.\r
1989 ;\r
1990 ;   : skipPARSE\r
1991 ;               >R SOURCE >IN @ /STRING    \ c_addr u  R: char\r
1992 ;               DUP IF\r
1993 ;                  BEGIN  OVER C@ R@ =\r
1994 ;                  WHILE  1- SWAP CHAR+ SWAP DUP 0=\r
1995 ;                  UNTIL  R> DROP EXIT\r
1996 ;                  ELSE THEN\r
1997 ;                  DROP SOURCE DROP - 1chars/ >IN ! R> PARSE EXIT\r
1998 ;               THEN R> DROP ;\r
1999 \r
2000                 $COLON  9,'skipPARSE',SkipPARSE,_SLINK\r
2001                 DW      ToR,SOURCE,ToIN,Fetch,SlashSTRING\r
2002                 DW      DUPP,ZBranch,SKPAR1\r
2003 SKPAR2          DW      OVER,CFetch,RFetch,Equals,ZBranch,SKPAR3\r
2004                 DW      OneMinus,SWAP,CHARPlus,SWAP\r
2005                 DW      DUPP,ZeroEquals,ZBranch,SKPAR2\r
2006                 DW      RFrom,DROP,EXIT\r
2007 SKPAR3          DW      DROP,SOURCE,DROP,Minus,OneCharsSlash\r
2008                 DW      ToIN,Store,RFrom,PARSE,EXIT\r
2009 SKPAR1          DW      RFrom,DROP,EXIT\r
2010 \r
2011 ;   rake        ( C: do-sys -- )\r
2012 ;               Gathers LEAVEs.\r
2013 ;\r
2014 ;   : rake      DUP , rakeVar @\r
2015 ;               BEGIN  2DUP U<\r
2016 ;               WHILE  DUP @ HERE ROT !\r
2017 ;               REPEAT rakeVar ! DROP\r
2018 ;               ?DUP IF                 \ check for ?DO\r
2019 ;                  1 bal+ POSTPONE THEN \ orig type is 1\r
2020 ;               THEN bal- ; COMPILE-ONLY\r
2021 \r
2022                 $COLON  COMPO+4,'rake',rake,_SLINK\r
2023                 DW      DUPP,Comma,RakeVar,Fetch\r
2024 RAKE1           DW      TwoDUP,ULess,ZBranch,RAKE2\r
2025                 DW      DUPP,Fetch,HERE,ROT,Store,Branch,RAKE1\r
2026 RAKE2           DW      RakeVar,Store,DROP\r
2027                 DW      QuestionDUP,ZBranch,RAKE3\r
2028                 DW      One,BalPlus,THENN\r
2029 RAKE3           DW      BalMinus,EXIT\r
2030 \r
2031 ;   rp0         ( -- a-addr )\r
2032 ;               Pointer to bottom of the return stack.\r
2033 ;\r
2034 ;   : rp0       userP @ CELL+ CELL+ @ ;\r
2035 \r
2036                 $COLON  3,'rp0',RPZero,_SLINK\r
2037                 DW      UserP,Fetch,CELLPlus,CELLPlus,Fetch,EXIT\r
2038 \r
2039 ;   search-word ( c-addr u -- c-addr u 0 | xt f 1 | xt f -1)\r
2040 ;               Search dictionary for a match with the given name. Return\r
2041 ;               execution token, not-compile-only flag and -1 or 1\r
2042 ;               ( IMMEDIATE) if found; c-addr u 0 if not.\r
2043 ;\r
2044 ;   : search-word\r
2045 ;               #order @ DUP                    \ not found if #order is 0\r
2046 ;               IF 0\r
2047 ;                  DO 2DUP                      \ ca u ca u\r
2048 ;                     I CELLS #order CELL+ + @  \ ca u ca u wid\r
2049 ;                     (search-wordlist)         \ ca u; 0 | w f 1 | w f -1\r
2050 ;                     ?DUP IF                   \ ca u; 0 | w f 1 | w f -1\r
2051 ;                        >R 2SWAP 2DROP R> UNLOOP EXIT \ xt f 1 | xt f -1\r
2052 ;                     THEN                      \ ca u\r
2053 ;                  LOOP 0                       \ ca u 0\r
2054 ;               THEN ;\r
2055 \r
2056                 $COLON  11,'search-word',Search_word,_SLINK\r
2057                 DW      NumberOrder,Fetch,DUPP,ZBranch,SEARCH1\r
2058                 DW      Zero,DoDO\r
2059 SEARCH2         DW      TwoDUP,I,CELLS,NumberOrder,CELLPlus,Plus,Fetch\r
2060                 DW      ParenSearch_Wordlist,QuestionDUP,ZBranch,SEARCH3\r
2061                 DW      ToR,TwoSWAP,TwoDROP,RFrom,UNLOOP,EXIT\r
2062 SEARCH3         DW      DoLOOP,SEARCH2\r
2063                 DW      Zero\r
2064 SEARCH1         DW      EXIT\r
2065 \r
2066 ;   sourceVar   ( -- a-addr )\r
2067 ;               Hold the current count and address of the terminal input buffer.\r
2068 \r
2069                 $VAR    9,'sourceVar',SourceVar,2,_SLINK\r
2070 \r
2071 ;   sp0         ( -- a-addr )\r
2072 ;               Pointer to bottom of the data stack.\r
2073 ;\r
2074 ;   : sp0       userP @ CELL+ @ ;\r
2075 \r
2076                 $COLON  3,'sp0',SPZero,_SLINK\r
2077                 DW      UserP,Fetch,CELLPlus,Fetch,EXIT\r
2078 \r
2079 ;\r
2080 ; Words for multitasking\r
2081 ;\r
2082 \r
2083 ;   PAUSE       ( -- )\r
2084 ;               Stop current task and transfer control to the task of which\r
2085 ;               'status' USER variable is stored in 'follower' USER variable\r
2086 ;               of current task.\r
2087 ;\r
2088 ;   : PAUSE     rp@ sp@ stackTop !  follower @ >R ; COMPILE-ONLY\r
2089 \r
2090                 $COLON  COMPO+5,'PAUSE',PAUSE,_SLINK\r
2091                 DW      RPFetch,SPFetch,StackTop,Store,Follower,Fetch,ToR,EXIT\r
2092 \r
2093 ;   wake        ( -- )\r
2094 ;               Wake current task.\r
2095 ;\r
2096 ;   : wake      R> userP !      \ userP points 'follower' of current task\r
2097 ;               stackTop @ sp!          \ set data stack\r
2098 ;               rp! ; COMPILE-ONLY      \ set return stack\r
2099 \r
2100                 $COLON  COMPO+4,'wake',Wake,_SLINK\r
2101                 DW      RFrom,UserP,Store,StackTop,Fetch,SPStore,RPStore,EXIT\r
2102 \r
2103 ;;;;;;;;;;;;;;;;\r
2104 ; Essential Standard words - Colon definitions\r
2105 ;;;;;;;;;;;;;;;;\r
2106 \r
2107 ;   #           ( ud1 -- ud2 )                  \ CORE\r
2108 ;               Extract one digit from ud1 and append the digit to\r
2109 ;               pictured numeric output string. ( ud2 = ud1 / BASE )\r
2110 ;\r
2111 ;   : #         0 BASE @ UM/MOD >R BASE @ UM/MOD SWAP\r
2112 ;               9 OVER < [ CHAR A CHAR 9 1 + - ] LITERAL AND +\r
2113 ;               [ CHAR 0 ] LITERAL + HOLD R> ;\r
2114 \r
2115                 $COLON  1,'#',NumberSign,_FLINK\r
2116                 DW      Zero,BASE,Fetch,UMSlashMOD,ToR,BASE,Fetch,UMSlashMOD\r
2117                 DW      SWAP,DoLIT,9,OVER,LessThan,DoLIT,'A'-'9'-1,ANDD,Plus\r
2118                 DW      DoLIT,'0',Plus,HOLD,RFrom,EXIT\r
2119 \r
2120 ;   #>          ( xd -- c-addr u )              \ CORE\r
2121 ;               Prepare the output string to be TYPE'd.\r
2122 ;               ||HERE>WORD/#-work-area|\r
2123 ;\r
2124 ;   : #>        2DROP hld @ HERE size-of-PAD + OVER - 1chars/ ;\r
2125 \r
2126                 $COLON  2,'#>',NumberSignGreater,_FLINK\r
2127                 DW      TwoDROP,HLD,Fetch,HERE,DoLIT,PADSize*CHARR,Plus\r
2128                 DW      OVER,Minus,OneCharsSlash,EXIT\r
2129 \r
2130 ;   #S          ( ud -- 0 0 )                   \ CORE\r
2131 ;               Convert ud until all digits are added to the output string.\r
2132 ;\r
2133 ;   : #S        BEGIN # 2DUP OR 0= UNTIL ;\r
2134 \r
2135                 $COLON  2,'#S',NumberSignS,_FLINK\r
2136 NUMSS1          DW      NumberSign,TwoDUP,ORR\r
2137                 DW      ZeroEquals,ZBranch,NUMSS1\r
2138                 DW      EXIT\r
2139 \r
2140 ;   '           ( "<spaces>name" -- xt )        \ CORE\r
2141 ;               Parse a name, find it and return xt.\r
2142 ;\r
2143 ;   : '         (') DROP ;\r
2144 \r
2145                 $COLON  1,"'",Tick,_FLINK\r
2146                 DW      ParenTick,DROP,EXIT\r
2147 \r
2148 ;   +           ( n1|u1 n2|u2 -- n3|u3 )        \ CORE\r
2149 ;               Add top two items and gives the sum.\r
2150 ;\r
2151 ;   : +         um+ DROP ;\r
2152 \r
2153                 $COLON  1,'+',Plus,_FLINK\r
2154                 DW      UMPlus,DROP,EXIT\r
2155 \r
2156 ;   +!          ( n|u a-addr -- )               \ CORE\r
2157 ;               Add n|u to the contents at a-addr.\r
2158 ;\r
2159 ;   : +!        SWAP OVER @ + SWAP ! ;\r
2160 \r
2161                 $COLON  2,'+!',PlusStore,_FLINK\r
2162                 DW      SWAP,OVER,Fetch,Plus\r
2163                 DW      SWAP,Store,EXIT\r
2164 \r
2165 ;   ,           ( x -- )                        \ CORE\r
2166 ;               Reserve one cell in data space and store x in it.\r
2167 ;\r
2168 ;   : ,         HERE DUP CELL+ TO HERE ! ;\r
2169 \r
2170                 $COLON  1,',',Comma,_FLINK\r
2171                 DW      HERE,DUPP,CELLPlus,DoTO,AddrHERE,Store,EXIT\r
2172 \r
2173 ;   -           ( n1|u1 n2|u2 -- n3|u3 )        \ CORE\r
2174 ;               Subtract n2|u2 from n1|u1, giving the difference n3|u3.\r
2175 ;\r
2176 ;   : -         NEGATE + ;\r
2177 \r
2178                 $COLON  1,'-',Minus,_FLINK\r
2179                 DW      NEGATE,Plus,EXIT\r
2180 \r
2181 ;   .           ( n -- )                        \ CORE\r
2182 ;               Display a signed number followed by a space.\r
2183 ;\r
2184 ;   : .         S>D D. ;\r
2185 \r
2186                 $COLON  1,'.',Dot,_FLINK\r
2187                 DW      SToD,DDot,EXIT\r
2188 \r
2189 ;   /           ( n1 n2 -- n3 )                 \ CORE\r
2190 ;               Divide n1 by n2, giving single-cell quotient n3.\r
2191 ;\r
2192 ;   : /         /MOD NIP ;\r
2193 \r
2194                 $COLON  1,'/',Slash,_FLINK\r
2195                 DW      SlashMOD,NIP,EXIT\r
2196 \r
2197 ;   /MOD        ( n1 n2 -- n3 n4 )              \ CORE\r
2198 ;               Divide n1 by n2, giving single-cell remainder n3 and\r
2199 ;               single-cell quotient n4.\r
2200 ;\r
2201 ;   : /MOD      >R S>D R> FM/MOD ;\r
2202 \r
2203                 $COLON  4,'/MOD',SlashMOD,_FLINK\r
2204                 DW      ToR,SToD,RFrom,FMSlashMOD,EXIT\r
2205 \r
2206 ;   /STRING     ( c-addr1 u1 n -- c-addr2 u2 )  \ STRING\r
2207 ;               Adjust the char string at c-addr1 by n chars.\r
2208 ;\r
2209 ;   : /STRING   DUP >R - SWAP R> CHARS + SWAP ;\r
2210 \r
2211                 $COLON  7,'/STRING',SlashSTRING,_FLINK\r
2212                 DW      DUPP,ToR,Minus,SWAP,RFrom,CHARS,Plus,SWAP,EXIT\r
2213 \r
2214 ;   1+          ( n1|u1 -- n2|u2 )              \ CORE\r
2215 ;               Increase top of the stack item by 1.\r
2216 ;\r
2217 ;   : 1+        1 + ;\r
2218 \r
2219                 $COLON  2,'1+',OnePlus,_FLINK\r
2220                 DW      One,Plus,EXIT\r
2221 \r
2222 ;   1-          ( n1|u1 -- n2|u2 )              \ CORE\r
2223 ;               Decrease top of the stack item by 1.\r
2224 ;\r
2225 ;   : 1-        -1 + ;\r
2226 \r
2227                 $COLON  2,'1-',OneMinus,_FLINK\r
2228                 DW      MinusOne,Plus,EXIT\r
2229 \r
2230 ;   2!          ( x1 x2 a-addr -- )             \ CORE\r
2231 ;               Store the cell pare x1 x2 at a-addr, with x2 at a-addr and\r
2232 ;               x1 at the next consecutive cell.\r
2233 ;\r
2234 ;   : 2!        SWAP OVER ! CELL+ ! ;\r
2235 \r
2236                 $COLON  2,'2!',TwoStore,_FLINK\r
2237                 DW      SWAP,OVER,Store,CELLPlus,Store,EXIT\r
2238 \r
2239 ;   2@          ( a-addr -- x1 x2 )             \ CORE\r
2240 ;               Fetch the cell pair stored at a-addr. x2 is stored at a-addr\r
2241 ;               and x1 at the next consecutive cell.\r
2242 ;\r
2243 ;   : 2@        DUP CELL+ @ SWAP @ ;\r
2244 \r
2245                 $COLON  2,'2@',TwoFetch,_FLINK\r
2246                 DW      DUPP,CELLPlus,Fetch,SWAP,Fetch,EXIT\r
2247 \r
2248 ;   2DROP       ( x1 x2 -- )                    \ CORE\r
2249 ;               Drop cell pair x1 x2 from the stack.\r
2250 \r
2251                 $COLON  5,'2DROP',TwoDROP,_FLINK\r
2252                 DW      DROP,DROP,EXIT\r
2253 \r
2254 ;   2DUP        ( x1 x2 -- x1 x2 x1 x2 )        \ CORE\r
2255 ;               Duplicate cell pair x1 x2.\r
2256 \r
2257                 $COLON  4,'2DUP',TwoDUP,_FLINK\r
2258                 DW      OVER,OVER,EXIT\r
2259 \r
2260 ;   2SWAP       ( x1 x2 x3 x4 -- x3 x4 x1 x2 )  \ CORE\r
2261 ;               Exchange the top two cell pairs.\r
2262 ;\r
2263 ;   : 2SWAP     ROT >R ROT R> ;\r
2264 \r
2265                 $COLON  5,'2SWAP',TwoSWAP,_FLINK\r
2266                 DW      ROT,ToR,ROT,RFrom,EXIT\r
2267 \r
2268 ;   :           ( "<spaces>name" -- colon-sys ) \ CORE\r
2269 ;               Start a new colon definition using next word as its name.\r
2270 ;\r
2271 ;   : :         head, :NONAME ROT DROP  -1 TO notNONAME? ;\r
2272 \r
2273                 $COLON  1,':',COLON,_FLINK\r
2274                 DW      HeadComma,ColonNONAME,ROT,DROP\r
2275                 DW      DoLIT,-1,DoTO,AddrNotNONAMEQ,EXIT\r
2276 \r
2277 ;   :NONAME     ( -- xt colon-sys )             \ CORE EXT\r
2278 ;               Create an execution token xt, enter compilation state and\r
2279 ;               start the current definition.\r
2280 ;\r
2281 ;   : :NONAME   bal IF -29 THROW THEN           \ compiler nesting\r
2282 ;               ['] doLIST xt, DUP -1\r
2283 ;               0 TO notNONAME?  1 TO bal  ] ;\r
2284 \r
2285                 $COLON  7,':NONAME',ColonNONAME,_FLINK\r
2286                 DW      Bal,ZBranch,NONAME1\r
2287                 DW      DoLIT,-29,THROW\r
2288 NONAME1         DW      DoLIT,DoLIST,xtComma,DUPP,DoLIT,-1\r
2289                 DW      Zero,DoTO,AddrNotNONAMEQ\r
2290                 DW      One,DoTO,AddrBal,RightBracket,EXIT\r
2291 \r
2292 ;   ;           ( colon-sys -- )                \ CORE\r
2293 ;               Terminate a colon definition.\r
2294 ;\r
2295 ;   : ;         bal 1- IF -22 THROW THEN        \ control structure mismatch\r
2296 ;               NIP 1+ IF -22 THROW THEN        \ colon-sys type is -1\r
2297 ;               notNONAME? IF   \ if the last definition is not created by ':'\r
2298 ;                 linkLast  0 TO notNONAME?     \ link the word to wordlist\r
2299 ;               THEN  POSTPONE EXIT     \ add EXIT at the end of the definition\r
2300 ;               0 TO bal  POSTPONE [ ; COMPILE-ONLY IMMEDIATE\r
2301 \r
2302                 $COLON  IMMED+COMPO+1,';',Semicolon,_FLINK\r
2303                 DW      Bal,OneMinus,ZBranch,SEMI1\r
2304                 DW      DoLIT,-22,THROW\r
2305 SEMI1           DW      NIP,OnePlus,ZBranch,SEMI2\r
2306                 DW      DoLIT,-22,THROW\r
2307 SEMI2           DW      NotNONAMEQ,ZBranch,SEMI3\r
2308                 DW      LinkLast,Zero,DoTO,AddrNotNONAMEQ\r
2309 SEMI3           DW      DoLIT,EXIT,COMPILEComma\r
2310                 DW      Zero,DoTO,AddrBal,LeftBracket,EXIT\r
2311 \r
2312 ;   <           ( n1 n2 -- flag )               \ CORE\r
2313 ;               Returns true if n1 is less than n2.\r
2314 ;\r
2315 ;   : <         2DUP XOR 0<             \ same sign?\r
2316 ;               IF DROP 0< EXIT THEN    \ different signs, true if n1 <0\r
2317 ;               - 0< ;                  \ same signs, true if n1-n2 <0\r
2318 \r
2319                 $COLON  1,'<',LessThan,_FLINK\r
2320                 DW      TwoDUP,XORR,ZeroLess,ZBranch,LESS1\r
2321                 DW      DROP,ZeroLess,EXIT\r
2322 LESS1           DW      Minus,ZeroLess,EXIT\r
2323 \r
2324 ;   <#          ( -- )                          \ CORE\r
2325 ;               Initiate the numeric output conversion process.\r
2326 ;               ||HERE>WORD/#-work-area|\r
2327 ;\r
2328 ;   : <#        HERE size-of-PAD + hld ! ;\r
2329 \r
2330                 $COLON  2,'<#',LessNumberSign,_FLINK\r
2331                 DW      HERE,DoLIT,PADSize*CHARR,Plus,HLD,Store,EXIT\r
2332 \r
2333 ;   =           ( x1 x2 -- flag )               \ CORE\r
2334 ;               Return true if top two are equal.\r
2335 ;\r
2336 ;   : =         XORR 0= ;\r
2337 \r
2338                 $COLON  1,'=',Equals,_FLINK\r
2339                 DW      XORR,ZeroEquals,EXIT\r
2340 \r
2341 ;   >           ( n1 n2 -- flag )               \ CORE\r
2342 ;               Returns true if n1 is greater than n2.\r
2343 ;\r
2344 ;   : >         SWAP < ;\r
2345 \r
2346                 $COLON  1,'>',GreaterThan,_FLINK\r
2347                 DW      SWAP,LessThan,EXIT\r
2348 \r
2349 ;   >IN         ( -- a-addr )\r
2350 ;               Hold the character pointer while parsing input stream.\r
2351 \r
2352                 $VAR    3,'>IN',ToIN,1,_FLINK\r
2353 \r
2354 ;   >NUMBER     ( ud1 c-addr1 u1 -- ud2 c-addr2 u2 )    \ CORE\r
2355 ;               Add number string's value to ud1. Leaves string of any\r
2356 ;               unconverted chars.\r
2357 ;\r
2358 ;   : >NUMBER   BEGIN  DUP\r
2359 ;               WHILE  >R  DUP >R C@                    \ ud char  R: u c-addr\r
2360 ;                      DUP [ CHAR 9 1+ ] LITERAL [CHAR] A WITHIN\r
2361 ;                          IF DROP R> R> EXIT THEN\r
2362 ;                      [ CHAR 0 ] LITERAL - 9 OVER <\r
2363 ;                      [ CHAR A CHAR 9 1 + - ] LITERAL AND -\r
2364 ;                      DUP 0 BASE @ WITHIN\r
2365 ;               WHILE  SWAP BASE @ UM* DROP ROT BASE @ UM* D+ R> R> 1 /STRING\r
2366 ;               REPEAT DROP R> R>\r
2367 ;               THEN ;\r
2368 \r
2369                 $COLON  7,'>NUMBER',ToNUMBER,_FLINK\r
2370 TONUM1          DW      DUPP,ZBranch,TONUM3\r
2371                 DW      ToR,DUPP,ToR,CFetch,DUPP\r
2372                 DW      DoLIT,'9'+1,DoLIT,'A',WITHIN,ZeroEquals,ZBranch,TONUM2\r
2373                 DW      DoLIT,'0',Minus,DoLIT,9,OVER,LessThan\r
2374                 DW      DoLIT,'A'-'9'-1,ANDD,Minus,DUPP\r
2375                 DW      Zero,BASE,Fetch,WITHIN,ZBranch,TONUM2\r
2376                 DW      SWAP,BASE,Fetch,UMStar,DROP,ROT,BASE,Fetch\r
2377                 DW      UMStar,DPlus,RFrom,RFrom,One,SlashSTRING\r
2378                 DW      Branch,TONUM1\r
2379 TONUM2          DW      DROP,RFrom,RFrom\r
2380 TONUM3          DW      EXIT\r
2381 \r
2382 ;   ?DUP        ( x -- x x | 0 )                \ CORE\r
2383 ;               Duplicate top of the stack if it is not zero.\r
2384 ;\r
2385 ;   : ?DUP      DUP IF DUP THEN ;\r
2386 \r
2387                 $COLON  4,'?DUP',QuestionDUP,_FLINK\r
2388                 DW      DUPP,ZBranch,QDUP1\r
2389                 DW      DUPP\r
2390 QDUP1           DW      EXIT\r
2391 \r
2392 ;   ABORT       ( i*x -- ) ( R: j*x -- )        \ EXCEPTION EXT\r
2393 ;               Reset data stack and jump to QUIT.\r
2394 ;\r
2395 ;   : ABORT     -1 THROW ;\r
2396 \r
2397                 $COLON  5,'ABORT',ABORT,_FLINK\r
2398                 DW      MinusOne,THROW\r
2399 \r
2400 ;   ACCEPT      ( c-addr +n1 -- +n2 )           \ CORE\r
2401 ;               Accept a string of up to +n1 chars. Return with actual count.\r
2402 ;               Implementation-defined editing. Stops at EOL# .\r
2403 ;               Supports backspace and delete editing.\r
2404 ;\r
2405 ;   : ACCEPT    >R 0\r
2406 ;               BEGIN  DUP R@ <                 \ ca n2 f  R: n1\r
2407 ;               WHILE  EKEY max-char AND\r
2408 ;                      DUP BL <\r
2409 ;                      IF   DUP  cr# = IF ROT 2DROP R> DROP EXIT THEN\r
2410 ;                           DUP  tab# =\r
2411 ;                           IF   DROP 2DUP + BL DUP EMIT SWAP C! 1+\r
2412 ;                           ELSE DUP  bsp# =\r
2413 ;                                SWAP del# = OR\r
2414 ;                                IF DROP DUP\r
2415 ;                                       \ discard the last char if not 1st char\r
2416 ;                                IF 1- bsp# EMIT BL EMIT bsp# EMIT THEN THEN\r
2417 ;                           THEN\r
2418 ;                      ELSE >R 2DUP CHARS + R> DUP EMIT SWAP C! 1+  THEN\r
2419 ;                      THEN\r
2420 ;               REPEAT SWAP  R> 2DROP ;\r
2421 \r
2422                 $COLON  6,'ACCEPT',ACCEPT,_FLINK\r
2423                 DW      ToR,Zero\r
2424 ACCPT1          DW      DUPP,RFetch,LessThan,ZBranch,ACCPT5\r
2425                 DW      EKEY,DoLIT,MaxChar,ANDD\r
2426                 DW      DUPP,BLank,LessThan,ZBranch,ACCPT3\r
2427                 DW      DUPP,DoLIT,CRR,Equals,ZBranch,ACCPT4\r
2428                 DW      ROT,TwoDROP,RFrom,DROP,EXIT\r
2429 ACCPT4          DW      DUPP,DoLIT,TABB,Equals,ZBranch,ACCPT6\r
2430                 DW      DROP,TwoDUP,Plus,BLank,DUPP,EMIT,SWAP,CStore,OnePlus\r
2431                 DW      Branch,ACCPT1\r
2432 ACCPT6          DW      DUPP,DoLIT,BKSPP,Equals\r
2433                 DW      SWAP,DoLIT,DEL,Equals,ORR,ZBranch,ACCPT1\r
2434                 DW      DUPP,ZBranch,ACCPT1\r
2435                 DW      OneMinus,DoLIT,BKSPP,EMIT,BLank,EMIT,DoLIT,BKSPP,EMIT\r
2436                 DW      Branch,ACCPT1\r
2437 ACCPT3          DW      ToR,TwoDUP,CHARS,Plus,RFrom,DUPP,EMIT,SWAP,CStore\r
2438                 DW      OnePlus,Branch,ACCPT1\r
2439 ACCPT5          DW      SWAP,RFrom,TwoDROP,EXIT\r
2440 \r
2441 ;   AGAIN       ( C: dest -- )                  \ CORE EXT\r
2442 ;               Resolve backward reference dest. Typically used as\r
2443 ;               BEGIN ... AGAIN . Move control to the location specified by\r
2444 ;               dest on execution.\r
2445 ;\r
2446 ;   : AGAIN     IF -22 THROW THEN  \ control structure mismatch; dest type is 0\r
2447 ;               POSTPONE branch , bal- ; COMPILE-ONLY IMMEDIATE\r
2448 \r
2449                 $COLON  IMMED+COMPO+5,'AGAIN',AGAIN,_FLINK\r
2450                 DW      ZBranch,AGAIN1\r
2451                 DW      DoLIT,-22,THROW\r
2452 AGAIN1          DW      DoLIT,Branch,COMPILEComma,Comma,BalMinus,EXIT\r
2453 \r
2454 ;   AHEAD       ( C: -- orig )                  \ TOOLS EXT\r
2455 ;               Put the location of a new unresolved forward reference onto\r
2456 ;               control-flow stack.\r
2457 ;\r
2458 ;   : AHEAD     POSTPONE branch  HERE 0 ,\r
2459 ;               1 bal+          \ orig type is 1\r
2460 ;               ; COMPILE-ONLY IMMEDIATE\r
2461 \r
2462                 $COLON  IMMED+COMPO+5,'AHEAD',AHEAD,_FLINK\r
2463                 DW      DoLIT,Branch,COMPILEComma,HERE,Zero,Comma\r
2464                 DW      One,BalPlus,EXIT\r
2465 \r
2466 ;   BL          ( -- char )                     \ CORE\r
2467 ;               Return the value of the blank character.\r
2468 ;\r
2469 ;   : BL        blank-char-value EXIT ;\r
2470 \r
2471                 $CONST  2,'BL',BLank,' ',_FLINK\r
2472 \r
2473 ;   CATCH       ( i*x xt -- j*x 0 | i*x n )     \ EXCEPTION\r
2474 ;               Push an exception frame on the exception stack and then execute\r
2475 ;               the execution token xt in such a way that control can be\r
2476 ;               transferred to a point just after CATCH if THROW is executed\r
2477 ;               during the execution of xt.\r
2478 ;\r
2479 ;   : CATCH     sp@ >R throwFrame @ >R          \ save error frame\r
2480 ;               rp@ throwFrame !  EXECUTE       \ execute\r
2481 ;               R> throwFrame !                 \ restore error frame\r
2482 ;               R> DROP  0 ;                    \ no error\r
2483 \r
2484                 $COLON  5,'CATCH',CATCH,_FLINK\r
2485                 DW      SPFetch,ToR,ThrowFrame,Fetch,ToR\r
2486                 DW      RPFetch,ThrowFrame,Store,EXECUTE\r
2487                 DW      RFrom,ThrowFrame,Store\r
2488                 DW      RFrom,DROP,Zero,EXIT\r
2489 \r
2490 ;   CELL+       ( a-addr1 -- a-addr2 )          \ CORE\r
2491 ;               Return next aligned cell address.\r
2492 ;\r
2493 ;   : CELL+     cell-size + ;\r
2494 \r
2495                 $COLON  5,'CELL+',CELLPlus,_FLINK\r
2496                 DW      DoLIT,CELLL,Plus,EXIT\r
2497 \r
2498 ;   CHAR+       ( c-addr1 -- c-addr2 )          \ CORE\r
2499 ;               Returns next character-aligned address.\r
2500 ;\r
2501 ;   : CHAR+     char-size + ;\r
2502 \r
2503                 $COLON  5,'CHAR+',CHARPlus,_FLINK\r
2504                 DW      DoLIT,CHARR,Plus,EXIT\r
2505 \r
2506 ;   COMPILE,    ( xt -- )                       \ CORE EXT\r
2507 ;               Compile the execution token on data stack into current\r
2508 ;               colon definition.\r
2509 ;\r
2510 ;   : COMPILE,  , ; COMPILE-ONLY\r
2511 \r
2512                 $COLON  COMPO+8,'COMPILE,',COMPILEComma,_FLINK\r
2513                 DW      Comma,EXIT\r
2514 \r
2515 ;   CONSTANT    ( x "<spaces>name" -- )         \ CORE\r
2516 ;               name Execution: ( -- x )\r
2517 ;               Create a definition for name which pushes x on the stack on\r
2518 ;               execution.\r
2519 ;\r
2520 ;   : CONSTANT  bal IF -29 THROW THEN           \ compiler nesting\r
2521 ;               head,  ['] doCONST xt, DROP  ,  linkLast ;\r
2522 \r
2523                 $COLON  8,'CONSTANT',CONSTANT,_FLINK\r
2524                 DW      Bal,ZBranch,CONST1\r
2525                 DW      DoLIT,-29,THROW\r
2526 CONST1          DW      HeadComma,DoLIT,DoCONST,xtComma,DROP,Comma\r
2527                 DW      LinkLast,EXIT\r
2528 \r
2529 ;   COUNT       ( c-addr1 -- c-addr2 u )        \ CORE\r
2530 ;               Convert counted string to string specification. c-addr2 is\r
2531 ;               the next char-aligned address after c-addr1 and u is the\r
2532 ;               contents at c-addr1.\r
2533 ;\r
2534 ;   : COUNT     DUP CHAR+ SWAP C@ ;\r
2535 \r
2536                 $COLON  5,'COUNT',COUNT,_FLINK\r
2537                 DW      DUPP,CHARPlus,SWAP,CFetch,EXIT\r
2538 \r
2539 ;   CREATE      ( "<spaces>name" -- )           \ CORE\r
2540 ;               name Execution: ( -- a-addr )\r
2541 ;               Create a data object in data space, which return data\r
2542 ;               object address on execution\r
2543 ;               Structure of CREATEd word:\r
2544 ;                   | call-doCREATE | 0 or DOES> code addr | >BODY points here\r
2545 ;\r
2546 ;   : CREATE    bal IF -29 THROW THEN           \ compiler nesting\r
2547 ;               head,  ['] doCREATE xt, DROP\r
2548 ;               HERE DUP CELL+ TO HERE          \ reserve a cell\r
2549 ;               0 SWAP !                \ no DOES> code yet\r
2550 ;               linkLast ;              \ link CREATEd word to current wordlist\r
2551 \r
2552                 $COLON  6,'CREATE',CREATE,_FLINK\r
2553                 DW      Bal,ZBranch,CREAT1\r
2554                 DW      DoLIT,-29,THROW\r
2555 CREAT1          DW      HeadComma,DoLIT,DoCREATE,xtComma,DROP\r
2556                 DW      HERE,DUPP,CELLPlus,DoTO,AddrHERE\r
2557                 DW      Zero,SWAP,Store,LinkLast,EXIT\r
2558 \r
2559 ;   D+          ( d1|ud1 d2|ud2 -- d3|ud3 )     \ DOUBLE\r
2560 ;               Add double-cell numbers.\r
2561 ;\r
2562 ;   : D+        >R SWAP >R um+ R> R> + + ;\r
2563 \r
2564                 $COLON  2,'D+',DPlus,_FLINK\r
2565                 DW      ToR,SWAP,ToR,UMPlus\r
2566                 DW      RFrom,RFrom,Plus,Plus,EXIT\r
2567 \r
2568 ;   D.          ( d -- )                        \ DOUBLE\r
2569 ;               Display d in free field format followed by a space.\r
2570 ;\r
2571 ;   : D.        (d.) TYPE SPACE ;\r
2572 \r
2573                 $COLON  2,'D.',DDot,_FLINK\r
2574                 DW      ParenDDot,TYPEE,SPACE,EXIT\r
2575 \r
2576 ;   DECIMAL     ( -- )                          \ CORE\r
2577 ;               Set the numeric conversion radix to decimal 10.\r
2578 ;\r
2579 ;   : DECIMAL   10 BASE ! ;\r
2580 \r
2581                 $COLON  7,'DECIMAL',DECIMAL,_FLINK\r
2582                 DW      DoLIT,10,BASE,Store,EXIT\r
2583 \r
2584 ;   DEPTH       ( -- +n )                       \ CORE\r
2585 ;               Return the depth of the data stack.\r
2586 ;\r
2587 ;   : DEPTH     sp@ sp0 SWAP - cell-size / ;\r
2588 \r
2589                 $COLON  5,'DEPTH',DEPTH,_FLINK\r
2590                 DW      SPFetch,SPZero,SWAP,Minus\r
2591                 DW      DoLIT,CELLL,Slash,EXIT\r
2592 \r
2593 ;   DNEGATE     ( d1 -- d2 )                    \ DOUBLE\r
2594 ;               Two's complement of double-cell number.\r
2595 ;\r
2596 ;   : DNEGATE   INVERT >R INVERT 1 um+ R> + ;\r
2597 \r
2598                 $COLON  7,'DNEGATE',DNEGATE,_FLINK\r
2599                 DW      INVERT,ToR,INVERT\r
2600                 DW      One,UMPlus\r
2601                 DW      RFrom,Plus,EXIT\r
2602 \r
2603 ;   EKEY        ( -- u )                        \ FACILITY EXT\r
2604 ;               Receive one keyboard event u.\r
2605 ;\r
2606 ;   : EKEY      BEGIN PAUSE EKEY? UNTIL 'ekey EXECUTE ;\r
2607 \r
2608                 $COLON  4,'EKEY',EKEY,_FLINK\r
2609 EKEY1           DW      PAUSE,EKEYQuestion,ZBranch,EKEY1\r
2610                 DW      TickEKEY,EXECUTE,EXIT\r
2611 \r
2612 ;   EMIT        ( x -- )                        \ CORE\r
2613 ;               Send a character to the output device.\r
2614 ;\r
2615 ;   : EMIT      'emit EXECUTE ;\r
2616 \r
2617                 $COLON  4,'EMIT',EMIT,_FLINK\r
2618                 DW      TickEMIT,EXECUTE,EXIT\r
2619 \r
2620 ;   FM/MOD      ( d n1 -- n2 n3 )               \ CORE\r
2621 ;               Signed floored divide of double by single. Return mod n2\r
2622 ;               and quotient n3.\r
2623 ;\r
2624 ;   : FM/MOD    DUP >R 2DUP XOR >R >R DUP 0< IF DNEGATE THEN\r
2625 ;               R@ ABS UM/MOD\r
2626 ;               R> 0< IF SWAP NEGATE SWAP THEN\r
2627 ;               R> 0< IF NEGATE         \ negative quotient\r
2628 ;                   OVER IF R@ ROT - SWAP 1- THEN\r
2629 ;                   R> DROP\r
2630 ;                   0 OVER < IF -11 THROW THEN          \ result out of range\r
2631 ;                   EXIT                        THEN\r
2632 ;               R> DROP  DUP 0< IF -11 THROW THEN ;     \ result out of range\r
2633 \r
2634                 $COLON  6,'FM/MOD',FMSlashMOD,_FLINK\r
2635                 DW      DUPP,ToR,TwoDUP,XORR,ToR,ToR,DUPP,ZeroLess\r
2636                 DW      ZBranch,FMMOD1\r
2637                 DW      DNEGATE\r
2638 FMMOD1          DW      RFetch,ABSS,UMSlashMOD\r
2639                 DW      RFrom,ZeroLess,ZBranch,FMMOD2\r
2640                 DW      SWAP,NEGATE,SWAP\r
2641 FMMOD2          DW      RFrom,ZeroLess,ZBranch,FMMOD3\r
2642                 DW      NEGATE,OVER,ZBranch,FMMOD4\r
2643                 DW      RFetch,ROT,Minus,SWAP,OneMinus\r
2644 FMMOD4          DW      RFrom,DROP\r
2645                 DW      DoLIT,0,OVER,LessThan,ZBranch,FMMOD6\r
2646                 DW      DoLIT,-11,THROW\r
2647 FMMOD6          DW      EXIT\r
2648 FMMOD3          DW      RFrom,DROP,DUPP,ZeroLess,ZBranch,FMMOD6\r
2649                 DW      DoLIT,-11,THROW\r
2650 \r
2651 ;   GET-CURRENT   ( -- wid )                    \ SEARCH\r
2652 ;               Return the indentifier of the compilation wordlist.\r
2653 ;\r
2654 ;   : GET-CURRENT   current @ ;\r
2655 \r
2656                 $COLON  11,'GET-CURRENT',GET_CURRENT,_FLINK\r
2657                 DW      Current,Fetch,EXIT\r
2658 \r
2659 ;   HOLD        ( char -- )                     \ CORE\r
2660 ;               Add char to the beginning of pictured numeric output string.\r
2661 ;\r
2662 ;   : HOLD      hld @  1 CHARS - DUP hld ! C! ;\r
2663 \r
2664                 $COLON  4,'HOLD',HOLD,_FLINK\r
2665                 DW      HLD,Fetch,DoLIT,0-CHARR,Plus\r
2666                 DW      DUPP,HLD,Store,CStore,EXIT\r
2667 \r
2668 ;   I           ( -- n|u ) ( R: loop-sys -- loop-sys )  \ CORE\r
2669 ;               Push the innermost loop index.\r
2670 ;\r
2671 ;   : I         rp@ [ 1 CELLS ] LITERAL + @\r
2672 ;               rp@ [ 2 CELLS ] LITERAL + @  +  ; COMPILE-ONLY\r
2673 \r
2674                 $COLON  COMPO+1,'I',I,_FLINK\r
2675                 DW      RPFetch,DoLIT,CELLL,Plus,Fetch\r
2676                 DW      RPFetch,DoLIT,2*CELLL,Plus,Fetch,Plus,EXIT\r
2677 \r
2678 ;   IF          Compilation: ( C: -- orig )             \ CORE\r
2679 ;               Run-time: ( x -- )\r
2680 ;               Put the location of a new unresolved forward reference orig\r
2681 ;               onto the control flow stack. On execution jump to location\r
2682 ;               specified by the resolution of orig if x is zero.\r
2683 ;\r
2684 ;   : IF        POSTPONE 0branch  HERE 0 ,\r
2685 ;               1 bal+          \ orig type is 1\r
2686 ;               ; COMPILE-ONLY IMMEDIATE\r
2687 \r
2688                 $COLON  IMMED+COMPO+2,'IF',IFF,_FLINK\r
2689                 DW      DoLIT,ZBranch,COMPILEComma,HERE,Zero,Comma\r
2690                 DW      One,BalPlus,EXIT\r
2691 \r
2692 ;   INVERT      ( x1 -- x2 )                    \ CORE\r
2693 ;               Return one's complement of x1.\r
2694 ;\r
2695 ;   : INVERT    -1 XOR ;\r
2696 \r
2697                 $COLON  6,'INVERT',INVERT,_FLINK\r
2698                 DW      MinusOne,XORR,EXIT\r
2699 \r
2700 ;   KEY         ( -- char )                     \ CORE\r
2701 ;               Receive a character. Do not display char.\r
2702 ;\r
2703 ;   : KEY       EKEY max-char AND ;\r
2704 \r
2705                 $COLON  3,'KEY',KEY,_FLINK\r
2706                 DW      EKEY,DoLIT,MaxChar,ANDD,EXIT\r
2707 \r
2708 ;   LITERAL     Compilation: ( x -- )           \ CORE\r
2709 ;               Run-time: ( -- x )\r
2710 ;               Append following run-time semantics. Put x on the stack on\r
2711 ;               execution\r
2712 ;\r
2713 ;   : LITERAL   POSTPONE doLIT , ; COMPILE-ONLY IMMEDIATE\r
2714 \r
2715                 $COLON  IMMED+COMPO+7,'LITERAL',LITERAL,_FLINK\r
2716                 DW      DoLIT,DoLIT,COMPILEComma,Comma,EXIT\r
2717 \r
2718 ;   NEGATE      ( n1 -- n2 )                    \ CORE\r
2719 ;               Return two's complement of n1.\r
2720 ;\r
2721 ;   : NEGATE    INVERT 1+ ;\r
2722 \r
2723                 $COLON  6,'NEGATE',NEGATE,_FLINK\r
2724                 DW      INVERT,OnePlus,EXIT\r
2725 \r
2726 ;   NIP         ( n1 n2 -- n2 )                 \ CORE EXT\r
2727 ;               Discard the second stack item.\r
2728 ;\r
2729 ;   : NIP       SWAP DROP ;\r
2730 \r
2731                 $COLON  3,'NIP',NIP,_FLINK\r
2732                 DW      SWAP,DROP,EXIT\r
2733 \r
2734 ;   PARSE       ( char "ccc<char>"-- c-addr u )         \ CORE EXT\r
2735 ;               Scan input stream and return counted string delimited by char.\r
2736 ;\r
2737 ;   : PARSE     >R  SOURCE >IN @ /STRING        \ c-addr u  R: char\r
2738 ;               DUP IF\r
2739 ;                  OVER CHARS + OVER       \ c-addr c-addr+u c-addr  R: char\r
2740 ;                  BEGIN  DUP C@ R@ XOR\r
2741 ;                  WHILE  CHAR+ 2DUP =\r
2742 ;                  UNTIL  DROP OVER - 1chars/ DUP\r
2743 ;                  ELSE   NIP  OVER - 1chars/ DUP CHAR+\r
2744 ;                  THEN   >IN +!\r
2745 ;               THEN   R> DROP EXIT ;\r
2746 \r
2747                 $COLON  5,'PARSE',PARSE,_FLINK\r
2748                 DW      ToR,SOURCE,ToIN,Fetch,SlashSTRING\r
2749                 DW      DUPP,ZBranch,PARSE4\r
2750                 DW      OVER,CHARS,Plus,OVER\r
2751 PARSE1          DW      DUPP,CFetch,RFetch,XORR,ZBranch,PARSE3\r
2752                 DW      CHARPlus,TwoDUP,Equals,ZBranch,PARSE1\r
2753 PARSE2          DW      DROP,OVER,Minus,DUPP,OneCharsSlash,Branch,PARSE5\r
2754 PARSE3          DW      NIP,OVER,Minus,DUPP,OneCharsSlash,CHARPlus\r
2755 PARSE5          DW      ToIN,PlusStore\r
2756 PARSE4          DW      RFrom,DROP,EXIT\r
2757 \r
2758 ;   QUIT        ( -- ) ( R: i*x -- )            \ CORE\r
2759 ;               Empty the return stack, store zero in SOURCE-ID, make the user\r
2760 ;               input device the input source, and start text interpreter.\r
2761 ;\r
2762 ;   : QUIT      BEGIN\r
2763 ;                 rp0 rp!  0 TO SOURCE-ID  0 TO bal  POSTPONE [\r
2764 ;                 BEGIN CR REFILL DROP SPACE    \ REFILL returns always true\r
2765 ;                       ['] interpret CATCH ?DUP 0=\r
2766 ;                 WHILE STATE @ 0= IF .prompt THEN\r
2767 ;                 REPEAT\r
2768 ;                 DUP -1 XOR IF                                 \ ABORT\r
2769 ;                 DUP -2 = IF SPACE abort"msg 2@ TYPE    ELSE   \ ABORT"\r
2770 ;                 SPACE errWord 2@ TYPE\r
2771 ;                 SPACE [CHAR] ? EMIT SPACE\r
2772 ;                 DUP -1 -58 WITHIN IF ." Exception # " . ELSE \ undefined exception\r
2773 ;                 CELLS THROWMsgTbl + @ COUNT TYPE       THEN THEN THEN\r
2774 ;                 sp0 sp!\r
2775 ;               AGAIN ;\r
2776 \r
2777                 $COLON  4,'QUIT',QUIT,_FLINK\r
2778 QUIT1           DW      RPZero,RPStore,Zero,DoTO,AddrSOURCE_ID\r
2779                 DW      Zero,DoTO,AddrBal,LeftBracket\r
2780 QUIT2           DW      CR,REFILL,DROP,SPACE\r
2781                 DW      DoLIT,Interpret,CATCH,QuestionDUP,ZeroEquals\r
2782                 DW      ZBranch,QUIT3\r
2783                 DW      STATE,Fetch,ZeroEquals,ZBranch,QUIT2\r
2784                 DW      DotPrompt,Branch,QUIT2\r
2785 QUIT3           DW      DUPP,MinusOne,XORR,ZBranch,QUIT5\r
2786                 DW      DUPP,DoLIT,-2,Equals,ZBranch,QUIT4\r
2787                 DW      SPACE,AbortQMsg,TwoFetch,TYPEE,Branch,QUIT5\r
2788 QUIT4           DW      SPACE,ErrWord,TwoFetch,TYPEE\r
2789                 DW      SPACE,DoLIT,'?',EMIT,SPACE\r
2790                 DW      DUPP,MinusOne,DoLIT,-58,WITHIN,ZBranch,QUIT7\r
2791                 $INSTR  ' Exception # '\r
2792                 DW      TYPEE,Dot,Branch,QUIT5\r
2793 QUIT7           DW      CELLS,THROWMsgTbl,Plus,Fetch,COUNT,TYPEE\r
2794 QUIT5           DW      SPZero,SPStore,Branch,QUIT1\r
2795 \r
2796 ;   REFILL      ( -- flag )                     \ CORE EXT\r
2797 ;               Attempt to fill the input buffer from the input source. Make\r
2798 ;               the result the input buffer, set >IN to zero, and return true\r
2799 ;               if successful. Return false if the input source is a string\r
2800 ;               from EVALUATE.\r
2801 ;\r
2802 ;   : REFILL    SOURCE-ID IF 0 EXIT THEN\r
2803 ;               memTop [ size-of-PAD CHARS ] LITERAL - DUP\r
2804 ;               size-of-PAD ACCEPT sourceVar 2!\r
2805 ;               0 >IN ! -1 ;\r
2806 \r
2807                 $COLON  6,'REFILL',REFILL,_FLINK\r
2808                 DW      SOURCE_ID,ZBranch,REFIL1\r
2809                 DW      Zero,EXIT\r
2810 REFIL1          DW      MemTop,DoLIT,0-PADSize*CHARR,Plus,DUPP\r
2811                 DW      DoLIT,PADSize*CHARR,ACCEPT,SourceVar,TwoStore\r
2812                 DW      Zero,ToIN,Store,MinusOne,EXIT\r
2813 \r
2814 ;   ROT         ( x1 x2 x3 -- x2 x3 x1 )        \ CORE\r
2815 ;               Rotate the top three data stack items.\r
2816 ;\r
2817 ;   : ROT       >R SWAP R> SWAP ;\r
2818 \r
2819                 $COLON  3,'ROT',ROT,_FLINK\r
2820                 DW      ToR,SWAP,RFrom,SWAP,EXIT\r
2821 \r
2822 ;   S>D         ( n -- d )                      \ CORE\r
2823 ;               Convert a single-cell number n to double-cell number.\r
2824 ;\r
2825 ;   : S>D       DUP 0< ;\r
2826 \r
2827                 $COLON  3,'S>D',SToD,_FLINK\r
2828                 DW      DUPP,ZeroLess,EXIT\r
2829 \r
2830 ;   SEARCH-WORDLIST     ( c-addr u wid -- 0 | xt 1 | xt -1)     \ SEARCH\r
2831 ;               Search word list for a match with the given name.\r
2832 ;               Return execution token and -1 or 1 ( IMMEDIATE) if found.\r
2833 ;               Return 0 if not found.\r
2834 ;\r
2835 ;   : SEARCH-WORDLIST\r
2836 ;               (search-wordlist) DUP IF NIP THEN ;\r
2837 \r
2838                 $COLON  15,'SEARCH-WORDLIST',SEARCH_WORDLIST,_FLINK\r
2839                 DW      ParenSearch_Wordlist,DUPP,ZBranch,SRCHW1\r
2840                 DW      NIP\r
2841 SRCHW1          DW      EXIT\r
2842 \r
2843 ;   SIGN        ( n -- )                        \ CORE\r
2844 ;               Add a minus sign to the numeric output string if n is negative.\r
2845 ;\r
2846 ;   : SIGN      0< IF [CHAR] - HOLD THEN ;\r
2847 \r
2848                 $COLON  4,'SIGN',SIGN,_FLINK\r
2849                 DW      ZeroLess,ZBranch,SIGN1\r
2850                 DW      DoLIT,'-',HOLD\r
2851 SIGN1           DW      EXIT\r
2852 \r
2853 ;   SOURCE      ( -- c-addr u )                 \ CORE\r
2854 ;               Return input buffer string.\r
2855 ;\r
2856 ;   : SOURCE    sourceVar 2@ ;\r
2857 \r
2858                 $COLON  6,'SOURCE',SOURCE,_FLINK\r
2859                 DW      SourceVar,TwoFetch,EXIT\r
2860 \r
2861 ;   SPACE       ( -- )                          \ CORE\r
2862 ;               Send the blank character to the output device.\r
2863 ;\r
2864 ;   : SPACE     32 EMIT ;\r
2865 \r
2866                 $COLON  5,'SPACE',SPACE,_FLINK\r
2867                 DW      BLank,EMIT,EXIT\r
2868 \r
2869 ;   STATE       ( -- a-addr )                   \ CORE\r
2870 ;               Return the address of a cell containing compilation-state flag\r
2871 ;               which is true in compilation state or false otherwise.\r
2872 \r
2873                 $VAR    5,'STATE',STATE,1,_FLINK\r
2874 \r
2875 ;   THEN        Compilation: ( C: orig -- )     \ CORE\r
2876 ;               Run-time: ( -- )\r
2877 ;               Resolve the forward reference orig.\r
2878 ;\r
2879 ;   : THEN      1- IF -22 THROW THEN    \ control structure mismatch\r
2880 ;                                       \ orig type is 1\r
2881 ;               HERE SWAP ! bal- ; COMPILE-ONLY IMMEDIATE\r
2882 \r
2883                 $COLON  IMMED+COMPO+4,'THEN',THENN,_FLINK\r
2884                 DW      OneMinus,ZBranch,THEN1\r
2885                 DW      DoLIT,-22,THROW\r
2886 THEN1           DW      HERE,SWAP,Store,BalMinus,EXIT\r
2887 \r
2888 ;   THROW       ( k*x n -- k*x | i*x n )        \ EXCEPTION\r
2889 ;               If n is not zero, pop the topmost exception frame from the\r
2890 ;               exception stack, along with everything on the return stack\r
2891 ;               above the frame. Then restore the condition before CATCH and\r
2892 ;               transfer control just after the CATCH that pushed that\r
2893 ;               exception frame.\r
2894 ;\r
2895 ;   : THROW     ?DUP\r
2896 ;               IF   throwFrame @ rp!   \ restore return stack\r
2897 ;                    R> throwFrame !    \ restore THROW frame\r
2898 ;                    R> SWAP >R sp!     \ restore data stack\r
2899 ;                    DROP R>\r
2900 ;                    'init-i/o EXECUTE\r
2901 ;               THEN ;\r
2902 \r
2903                 $COLON  5,'THROW',THROW,_FLINK\r
2904                 DW      QuestionDUP,ZBranch,THROW1\r
2905                 DW      ThrowFrame,Fetch,RPStore,RFrom,ThrowFrame,Store\r
2906                 DW      RFrom,SWAP,ToR,SPStore,DROP,RFrom\r
2907                 DW      TickINIT_IO,EXECUTE\r
2908 THROW1          DW      EXIT\r
2909 \r
2910 ;   TYPE        ( c-addr u -- )                 \ CORE\r
2911 ;               Display the character string if u is greater than zero.\r
2912 ;\r
2913 ;   : TYPE      ?DUP IF 0 DO DUP C@ EMIT CHAR+ LOOP THEN DROP ;\r
2914 \r
2915                 $COLON  4,'TYPE',TYPEE,_FLINK\r
2916                 DW      QuestionDUP,ZBranch,TYPE2\r
2917                 DW      Zero,DoDO\r
2918 TYPE1           DW      DUPP,CFetch,EMIT,CHARPlus,DoLOOP,TYPE1\r
2919 TYPE2           DW      DROP,EXIT\r
2920 \r
2921 ;   U<          ( u1 u2 -- flag )               \ CORE\r
2922 ;               Unsigned compare of top two items. True if u1 < u2.\r
2923 ;\r
2924 ;   : U<        2DUP XOR 0< IF NIP 0< EXIT THEN - 0< ;\r
2925 \r
2926                 $COLON  2,'U<',ULess,_FLINK\r
2927                 DW      TwoDUP,XORR,ZeroLess\r
2928                 DW      ZBranch,ULES1\r
2929                 DW      NIP,ZeroLess,EXIT\r
2930 ULES1           DW      Minus,ZeroLess,EXIT\r
2931 \r
2932 ;   UM*         ( u1 u2 -- ud )                 \ CORE\r
2933 ;               Unsigned multiply. Return double-cell product.\r
2934 ;\r
2935 ;   : UM*       0 SWAP cell-size-in-bits 0 DO\r
2936 ;                  DUP um+ >R >R DUP um+ R> +\r
2937 ;                  R> IF >R OVER um+ R> + THEN     \ if carry\r
2938 ;               LOOP ROT DROP ;\r
2939 \r
2940                 $COLON  3,'UM*',UMStar,_FLINK\r
2941                 DW      Zero,SWAP,DoLIT,CELLL*8,Zero,DoDO\r
2942 UMST1           DW      DUPP,UMPlus,ToR,ToR\r
2943                 DW      DUPP,UMPlus,RFrom,Plus,RFrom\r
2944                 DW      ZBranch,UMST2\r
2945                 DW      ToR,OVER,UMPlus,RFrom,Plus\r
2946 UMST2           DW      DoLOOP,UMST1\r
2947                 DW      ROT,DROP,EXIT\r
2948 \r
2949 ;   UM/MOD      ( ud u1 -- u2 u3 )              \ CORE\r
2950 ;               Unsigned division of a double-cell number ud by a single-cell\r
2951 ;               number u1. Return remainder u2 and quotient u3.\r
2952 ;\r
2953 ;   : UM/MOD    DUP 0= IF -10 THROW THEN        \ divide by zero\r
2954 ;               2DUP U< IF\r
2955 ;                  NEGATE cell-size-in-bits 0\r
2956 ;                  DO   >R DUP um+ >R >R DUP um+ R> + DUP\r
2957 ;                       R> R@ SWAP >R um+ R> OR\r
2958 ;                       IF >R DROP 1+ R> THEN\r
2959 ;                       ELSE DROP THEN\r
2960 ;                       R>\r
2961 ;                  LOOP DROP SWAP EXIT\r
2962 ;               ELSE -11 THROW          \ result out of range\r
2963 ;               THEN ;\r
2964 \r
2965                 $COLON  6,'UM/MOD',UMSlashMOD,_FLINK\r
2966                 DW      DUPP,ZBranch,UMM5\r
2967                 DW      TwoDUP,ULess,ZBranch,UMM4\r
2968                 DW      NEGATE,DoLIT,CELLL*8,Zero,DoDO\r
2969 UMM1            DW      ToR,DUPP,UMPlus,ToR,ToR,DUPP,UMPlus,RFrom,Plus,DUPP\r
2970                 DW      RFrom,RFetch,SWAP,ToR,UMPlus,RFrom,ORR,ZBranch,UMM2\r
2971                 DW      ToR,DROP,OnePlus,RFrom,Branch,UMM3\r
2972 UMM2            DW      DROP\r
2973 UMM3            DW      RFrom,DoLOOP,UMM1\r
2974                 DW      DROP,SWAP,EXIT\r
2975 UMM5            DW      DoLIT,-10,THROW\r
2976 UMM4            DW      DoLIT,-11,THROW\r
2977 \r
2978 ;   UNLOOP      ( -- ) ( R: loop-sys -- )       \ CORE\r
2979 ;               Discard loop-control parameters for the current nesting level.\r
2980 ;               An UNLOOP is required for each nesting level before the\r
2981 ;               definition may be EXITed.\r
2982 ;\r
2983 ;   : UNLOOP    R> R> R> 2DROP >R ;\r
2984 \r
2985                 $COLON  COMPO+6,'UNLOOP',UNLOOP,_FLINK\r
2986                 DW      RFrom,RFrom,RFrom,TwoDROP,ToR,EXIT\r
2987 \r
2988 ;   WITHIN      ( n1|u1 n2|n2 n3|u3 -- flag )   \ CORE EXT\r
2989 ;               Return true if (n2|u2<=n1|u1 and n1|u1<n3|u3) or\r
2990 ;               (n2|u2>n3|u3 and (n2|u2<=n1|u1 or n1|u1<n3|u3)).\r
2991 ;\r
2992 ;   : WITHIN    OVER - >R - R> U< ;\r
2993 \r
2994                 $COLON  6,'WITHIN',WITHIN,_FLINK\r
2995                 DW      OVER,Minus,ToR                  ;ul <= u < uh\r
2996                 DW      Minus,RFrom,ULess,EXIT\r
2997 \r
2998 ;   [           ( -- )                          \ CORE\r
2999 ;               Enter interpretation state.\r
3000 ;\r
3001 ;   : [         0 STATE ! ; COMPILE-ONLY IMMEDIATE\r
3002 \r
3003                 $COLON  IMMED+COMPO+1,'[',LeftBracket,_FLINK\r
3004                 DW      Zero,STATE,Store,EXIT\r
3005 \r
3006 ;   ]           ( -- )                          \ CORE\r
3007 ;               Enter compilation state.\r
3008 ;\r
3009 ;   : ]         -1 STATE ! ;\r
3010 \r
3011                 $COLON  1,']',RightBracket,_FLINK\r
3012                 DW      MinusOne,STATE,Store,EXIT\r
3013 \r
3014 ;;;;;;;;;;;;;;;;\r
3015 ; Rest of CORE words and two facility words, EKEY? and EMIT?\r
3016 ;;;;;;;;;;;;;;;;\r
3017 ;       Following definitions can be removed from assembler source and\r
3018 ;       can be colon-defined later.\r
3019 \r
3020 ;   (           ( "ccc<)>" -- )                 \ CORE\r
3021 ;               Ignore following string up to next ) . A comment.\r
3022 ;\r
3023 ;   : (         [CHAR] ) PARSE 2DROP ;\r
3024 \r
3025                 $COLON  IMMED+1,'(',Paren,_FLINK\r
3026                 DW      DoLIT,')',PARSE,TwoDROP,EXIT\r
3027 \r
3028 ;   *           ( n1|u1 n2|u2 -- n3|u3 )        \ CORE\r
3029 ;               Multiply n1|u1 by n2|u2 giving a single product.\r
3030 ;\r
3031 ;   : *         UM* DROP ;\r
3032 \r
3033                 $COLON  1,'*',Star,_FLINK\r
3034                 DW      UMStar,DROP,EXIT\r
3035 \r
3036 ;   */          ( n1 n2 n3 -- n4 )              \ CORE\r
3037 ;               Multiply n1 by n2 producing double-cell intermediate,\r
3038 ;               then divide it by n3. Return single-cell quotient.\r
3039 ;\r
3040 ;   : */        */MOD NIP ;\r
3041 \r
3042                 $COLON  2,'*/',StarSlash,_FLINK\r
3043                 DW      StarSlashMOD,NIP,EXIT\r
3044 \r
3045 ;   */MOD       ( n1 n2 n3 -- n4 n5 )           \ CORE\r
3046 ;               Multiply n1 by n2 producing double-cell intermediate,\r
3047 ;               then divide it by n3. Return single-cell remainder and\r
3048 ;               single-cell quotient.\r
3049 ;\r
3050 ;   : */MOD     >R M* R> FM/MOD ;\r
3051 \r
3052                 $COLON  5,'*/MOD',StarSlashMOD,_FLINK\r
3053                 DW      ToR,MStar,RFrom,FMSlashMOD,EXIT\r
3054 \r
3055 ;   +LOOP       Compilation: ( C: do-sys -- )   \ CORE\r
3056 ;               Run-time: ( n -- ) ( R: loop-sys1 -- | loop-sys2 )\r
3057 ;               Terminate a DO-+LOOP structure. Resolve the destination of all\r
3058 ;               unresolved occurences of LEAVE.\r
3059 ;               On execution add n to the loop index. If loop index did not\r
3060 ;               cross the boundary between loop_limit-1 and loop_limit,\r
3061 ;               continue execution at the beginning of the loop. Otherwise,\r
3062 ;               finish the loop.\r
3063 ;\r
3064 ;   : +LOOP     POSTPONE do+LOOP  rake ; COMPILE-ONLY IMMEDIATE\r
3065 \r
3066                 $COLON  IMMED+COMPO+5,'+LOOP',PlusLOOP,_FLINK\r
3067                 DW      DoLIT,DoPLOOP,COMPILEComma,rake,EXIT\r
3068 \r
3069 ;   ."          ( "ccc<">" -- )                 \ CORE\r
3070 ;               Run-time ( -- )\r
3071 ;               Compile an inline string literal to be typed out at run time.\r
3072 ;\r
3073 ;   : ."        POSTPONE S" POSTPONE TYPE ; COMPILE-ONLY IMMEDIATE\r
3074 \r
3075                 $COLON  IMMED+COMPO+2,'."',DotQuote,_FLINK\r
3076                 DW      SQuote,DoLIT,TYPEE,COMPILEComma,EXIT\r
3077 \r
3078 ;   2OVER       ( x1 x2 x3 x4 -- x1 x2 x3 x4 x1 x2 )      \ CORE\r
3079 ;               Copy cell pair x1 x2 to the top of the stack.\r
3080 ;\r
3081 ;   : 2OVER     >R >R 2DUP R> R> 2SWAP ;\r
3082 \r
3083                 $COLON  5,'2OVER',TwoOVER,_FLINK\r
3084                 DW      ToR,ToR,TwoDUP,RFrom,RFrom,TwoSWAP,EXIT\r
3085 \r
3086 ;   >BODY       ( xt -- a-addr )                \ CORE\r
3087 ;               Push data field address of CREATEd word.\r
3088 ;               Structure of CREATEd word:\r
3089 ;                   | call-doCREATE | 0 or DOES> code addr | >BODY points here\r
3090 ;\r
3091 ;   : >BODY     ?call DUP IF                    \ code-addr xt2\r
3092 ;                   ['] doCREATE = IF           \ should be call-doCREATE\r
3093 ;                   CELL+ EXIT\r
3094 ;               THEN THEN\r
3095 ;               -31 THROW ;             \ >BODY used on non-CREATEd definition\r
3096 \r
3097                 $COLON  5,'>BODY',ToBODY,_FLINK\r
3098                 DW      QCall,DUPP,ZBranch,TBODY1\r
3099                 DW      DoLIT,DoCREATE,Equals,ZBranch,TBODY1\r
3100                 DW      CELLPlus,EXIT\r
3101 TBODY1          DW      DoLIT,-31,THROW\r
3102 \r
3103 ;   ABORT"      ( "ccc<">" -- )                 \ EXCEPTION EXT\r
3104 ;               Run-time ( i*x x1 -- | i*x ) ( R: j*x -- | j*x )\r
3105 ;               Conditional abort with an error message.\r
3106 ;\r
3107 ;   : ABORT"    S" POSTPONE ROT\r
3108 ;               POSTPONE IF POSTPONE abort"msg POSTPONE 2!\r
3109 ;               -2 POSTPONE LITERAL POSTPONE THROW\r
3110 ;               POSTPONE ELSE POSTPONE 2DROP POSTPONE THEN\r
3111 ;               ;  COMPILE-ONLY IMMEDIATE\r
3112 \r
3113                 $COLON  IMMED+COMPO+6,'ABORT"',ABORTQuote,_FLINK\r
3114                 DW      SQuote,DoLIT,ROT,COMPILEComma\r
3115                 DW      IFF,DoLIT,AbortQMsg,COMPILEComma ; IF is immediate\r
3116                 DW      DoLIT,TwoStore,COMPILEComma\r
3117                 DW      DoLIT,-2,LITERAL                 ; LITERAL is immediate\r
3118                 DW      DoLIT,THROW,COMPILEComma\r
3119                 DW      ELSEE,DoLIT,TwoDROP,COMPILEComma ; ELSE and THEN are\r
3120                 DW      THENN,EXIT                       ; immediate\r
3121 \r
3122 ;   ABS         ( n -- u )                      \ CORE\r
3123 ;               Return the absolute value of n.\r
3124 ;\r
3125 ;   : ABS       DUP 0< IF NEGATE THEN ;\r
3126 \r
3127                 $COLON  3,'ABS',ABSS,_FLINK\r
3128                 DW      DUPP,ZeroLess,ZBranch,ABS1\r
3129                 DW      NEGATE\r
3130 ABS1            DW      EXIT\r
3131 \r
3132 ;   ALLOT       ( n -- )                        \ CORE\r
3133 ;               Allocate n address units in data space.\r
3134 ;\r
3135 ;   : ALLOT     HERE + TO HERE ;\r
3136 \r
3137                 $COLON  5,'ALLOT',ALLOT,_FLINK\r
3138                 DW      HERE,Plus,DoTO,AddrHERE,EXIT\r
3139 \r
3140 ;   BEGIN       ( C: -- dest )                  \ CORE\r
3141 ;               Start an infinite or indefinite loop structure. Put the next\r
3142 ;               location for a transfer of control, dest, onto the data\r
3143 ;               control stack.\r
3144 ;\r
3145 ;   : BEGIN     HERE 0 bal+             \ dest type is 0\r
3146 ;               ; COMPILE-ONLY IMMDEDIATE\r
3147 \r
3148                 $COLON  IMMED+COMPO+5,'BEGIN',BEGIN,_FLINK\r
3149                 DW      HERE,Zero,BalPlus,EXIT\r
3150 \r
3151 ;   C,          ( char -- )                     \ CORE\r
3152 ;               Compile a character into data space.\r
3153 ;\r
3154 ;   : C,        HERE C!  HERE CHAR+ TO HERE ;\r
3155 \r
3156                 $COLON  2,'C,',CComma,_FLINK\r
3157                 DW      HERE,CStore,HERE,CHARPlus,DoTO,AddrHERE,EXIT\r
3158 \r
3159 ;   CHAR        ( "<spaces>ccc" -- char )       \ CORE\r
3160 ;               Parse next word and return the value of first character.\r
3161 ;\r
3162 ;   : CHAR      PARSE-WORD DROP C@ ;\r
3163 \r
3164                 $COLON  4,'CHAR',CHAR,_FLINK\r
3165                 DW      PARSE_WORD,DROP,CFetch,EXIT\r
3166 \r
3167 ;   DO          Compilation: ( C: -- do-sys )   \ CORE\r
3168 ;               Run-time: ( n1|u1 n2|u2 -- ) ( R: -- loop-sys )\r
3169 ;               Start a DO-LOOP structure in a colon definition. Place do-sys\r
3170 ;               on control-flow stack, which will be resolved by LOOP or +LOOP.\r
3171 ;\r
3172 ;   : DO        0 rakeVar !  0                  \ ?DO-orig is 0 for DO\r
3173 ;               POSTPONE doDO  HERE  bal+       \ DO-dest\r
3174 ;               ; COMPILE-ONLY IMMEDIATE\r
3175 \r
3176                 $COLON  IMMED+COMPO+2,'DO',DO,_FLINK\r
3177                 DW      Zero,RakeVar,Store,Zero\r
3178                 DW      DoLIT,DoDO,COMPILEComma,HERE,BalPlus,EXIT\r
3179 \r
3180 ;   DOES>       ( C: colon-sys1 -- colon-sys2 ) \ CORE\r
3181 ;               Build run time code of the data object CREATEd.\r
3182 ;\r
3183 ;   : DOES>     bal 1- IF -22 THROW THEN        \ control structure mismatch\r
3184 ;               NIP 1+ IF -22 THROW THEN        \ colon-sys type is -1\r
3185 ;               POSTPONE pipe ['] doLIST xt, -1 ; COMPILE-ONLY IMMEDIATE\r
3186 \r
3187                 $COLON  IMMED+COMPO+5,'DOES>',DOESGreater,_FLINK\r
3188                 DW      Bal,OneMinus,ZBranch,DOES1\r
3189                 DW      DoLIT,-22,THROW\r
3190 DOES1           DW      NIP,OnePlus,ZBranch,DOES2\r
3191                 DW      DoLIT,-22,THROW\r
3192 DOES2           DW      DoLIT,Pipe,COMPILEComma\r
3193                 DW      DoLIT,DoLIST,xtComma,DoLIT,-1,EXIT\r
3194 \r
3195 ;   ELSE        Compilation: ( C: orig1 -- orig2 )      \ CORE\r
3196 ;               Run-time: ( -- )\r
3197 ;               Start the false clause in an IF-ELSE-THEN structure.\r
3198 ;               Put the location of new unresolved forward reference orig2\r
3199 ;               onto control-flow stack.\r
3200 ;\r
3201 ;   : ELSE      POSTPONE AHEAD 2SWAP POSTPONE THEN ; COMPILE-ONLY IMMDEDIATE\r
3202 \r
3203                 $COLON  IMMED+COMPO+4,'ELSE',ELSEE,_FLINK\r
3204                 DW      AHEAD,TwoSWAP,THENN,EXIT\r
3205 \r
3206 ;   ENVIRONMENT?   ( c-addr u -- false | i*x true )     \ CORE\r
3207 ;               Environment query.\r
3208 ;\r
3209 ;   : ENVIRONMENT?\r
3210 ;               envQList SEARCH-WORDLIST\r
3211 ;               DUP >R IF EXECUTE THEN R> ;\r
3212 \r
3213                 $COLON  12,'ENVIRONMENT?',ENVIRONMENTQuery,_FLINK\r
3214                 DW      EnvQList,SEARCH_WORDLIST\r
3215                 DW      DUPP,ToR,ZBranch,ENVRN1\r
3216                 DW      EXECUTE\r
3217 ENVRN1          DW      RFrom,EXIT\r
3218 \r
3219 ;   EVALUATE    ( i*x c-addr u -- j*x )         \ CORE\r
3220 ;               Evaluate the string. Save the input source specification.\r
3221 ;               Store -1 in SOURCE-ID.\r
3222 ;\r
3223 ;   : EVALUATE  SOURCE >R >R >IN @ >R  SOURCE-ID >R\r
3224 ;               -1 TO SOURCE-ID\r
3225 ;               sourceVar 2!  0 >IN !  interpret\r
3226 ;               R> TO SOURCE-ID\r
3227 ;               R> >IN ! R> R> sourceVar 2! ;\r
3228 \r
3229                 $COLON  8,'EVALUATE',EVALUATE,_FLINK\r
3230                 DW      SOURCE,ToR,ToR,ToIN,Fetch,ToR,SOURCE_ID,ToR\r
3231                 DW      MinusOne,DoTO,AddrSOURCE_ID\r
3232                 DW      SourceVar,TwoStore,Zero,ToIN,Store,Interpret\r
3233                 DW      RFrom,DoTO,AddrSOURCE_ID\r
3234                 DW      RFrom,ToIN,Store,RFrom,RFrom,SourceVar,TwoStore,EXIT\r
3235 \r
3236 ;   FILL        ( c-addr u char -- )            \ CORE\r
3237 ;               Store char in each of u consecutive characters of memory\r
3238 ;               beginning at c-addr.\r
3239 ;\r
3240 ;   : FILL      ROT ROT ?DUP IF 0 DO 2DUP C! CHAR+ LOOP THEN 2DROP ;\r
3241 \r
3242                 $COLON  4,'FILL',FILL,_FLINK\r
3243                 DW      ROT,ROT,QuestionDUP,ZBranch,FILL2\r
3244                 DW      Zero,DoDO\r
3245 FILL1           DW      TwoDUP,CStore,CHARPlus,DoLOOP,FILL1\r
3246 FILL2           DW      TwoDROP,EXIT\r
3247 \r
3248 ;   FIND        ( c-addr -- c-addr 0 | xt 1 | xt -1)     \ SEARCH\r
3249 ;               Search dictionary for a match with the given counted name.\r
3250 ;               Return execution token and -1 or 1 ( IMMEDIATE) if found;\r
3251 ;               c-addr 0 if not found.\r
3252 ;\r
3253 ;   : FIND      DUP COUNT search-word ?DUP IF NIP ROT DROP EXIT THEN\r
3254 ;               2DROP 0 ;\r
3255 \r
3256                 $COLON  4,'FIND',FIND,_FLINK\r
3257                 DW      DUPP,COUNT,Search_word,QuestionDUP,ZBranch,FIND1\r
3258                 DW      NIP,ROT,DROP,EXIT\r
3259 FIND1           DW      TwoDROP,Zero,EXIT\r
3260 \r
3261 ;   IMMEDIATE   ( -- )                          \ CORE\r
3262 ;               Make the most recent definition an immediate word.\r
3263 ;\r
3264 ;   : IMMEDIATE   lastName [ =imed ] LITERAL OVER @ OR SWAP ! ;\r
3265 \r
3266                 $COLON  9,'IMMEDIATE',IMMEDIATE,_FLINK\r
3267                 DW      LastName,DoLIT,IMMED,OVER,Fetch,ORR,SWAP,Store,EXIT\r
3268 \r
3269 ;   J           ( -- n|u ) ( R: loop-sys -- loop-sys )  \ CORE\r
3270 ;               Push the index of next outer loop.\r
3271 ;\r
3272 ;   : J         rp@ [ 3 CELLS ] LITERAL + @\r
3273 ;               rp@ [ 4 CELLS ] LITERAL + @  +  ; COMPILE-ONLY\r
3274 \r
3275                 $COLON  COMPO+1,'J',J,_FLINK\r
3276                 DW      RPFetch,DoLIT,3*CELLL,Plus,Fetch\r
3277                 DW      RPFetch,DoLIT,4*CELLL,Plus,Fetch,Plus,EXIT\r
3278 \r
3279 ;   LEAVE       ( -- ) ( R: loop-sys -- )       \ CORE\r
3280 ;               Terminate definite loop, DO|?DO  ... LOOP|+LOOP, immediately.\r
3281 ;\r
3282 ;   : LEAVE     POSTPONE UNLOOP POSTPONE branch\r
3283 ;               HERE rakeVar DUP @ , ! ; COMPILE-ONLY IMMEDIATE\r
3284 \r
3285                 $COLON  IMMED+COMPO+5,'LEAVE',LEAVEE,_FLINK\r
3286                 DW      DoLIT,UNLOOP,COMPILEComma,DoLIT,Branch,COMPILEComma\r
3287                 DW      HERE,RakeVar,DUPP,Fetch,Comma,Store,EXIT\r
3288 \r
3289 ;   LOOP        Compilation: ( C: do-sys -- )   \ CORE\r
3290 ;               Run-time: ( -- ) ( R: loop-sys1 -- loop-sys2 )\r
3291 ;               Terminate a DO|?DO ... LOOP structure. Resolve the destination\r
3292 ;               of all unresolved occurences of LEAVE.\r
3293 ;\r
3294 ;   : LOOP      POSTPONE doLOOP  rake ; COMPILE-ONLY IMMEDIATE\r
3295 \r
3296                 $COLON  IMMED+COMPO+4,'LOOP',LOOPP,_FLINK\r
3297                 DW      DoLIT,DoLOOP,COMPILEComma,rake,EXIT\r
3298 \r
3299 ;   LSHIFT      ( x1 u -- x2 )                  \ CORE\r
3300 ;               Perform a logical left shift of u bit-places on x1, giving x2.\r
3301 ;               Put 0 into the least significant bits vacated by the shift.\r
3302 ;\r
3303 ;   : LSHIFT    ?DUP IF 0 DO 2* LOOP THEN ;\r
3304 \r
3305                 $COLON  6,'LSHIFT',LSHIFT,_FLINK\r
3306                 DW      QuestionDUP,ZBranch,LSHIFT2\r
3307                 DW      Zero,DoDO\r
3308 LSHIFT1         DW      TwoStar,DoLOOP,LSHIFT1\r
3309 LSHIFT2         DW      EXIT\r
3310 \r
3311 ;   M*          ( n1 n2 -- d )                  \ CORE\r
3312 ;               Signed multiply. Return double product.\r
3313 ;\r
3314 ;   : M*        2DUP XOR 0< >R ABS SWAP ABS UM* R> IF DNEGATE THEN ;\r
3315 \r
3316                 $COLON  2,'M*',MStar,_FLINK\r
3317                 DW      TwoDUP,XORR,ZeroLess,ToR,ABSS,SWAP,ABSS\r
3318                 DW      UMStar,RFrom,ZBranch,MSTAR1\r
3319                 DW      DNEGATE\r
3320 MSTAR1          DW      EXIT\r
3321 \r
3322 ;   MAX         ( n1 n2 -- n3 )                 \ CORE\r
3323 ;               Return the greater of two top stack items.\r
3324 ;\r
3325 ;   : MAX       2DUP < IF SWAP THEN DROP ;\r
3326 \r
3327                 $COLON  3,'MAX',MAX,_FLINK\r
3328                 DW      TwoDUP,LessThan,ZBranch,MAX1\r
3329                 DW      SWAP\r
3330 MAX1            DW      DROP,EXIT\r
3331 \r
3332 ;   MIN         ( n1 n2 -- n3 )                 \ CORE\r
3333 ;               Return the smaller of top two stack items.\r
3334 ;\r
3335 ;   : MIN       2DUP > IF SWAP THEN DROP ;\r
3336 \r
3337                 $COLON  3,'MIN',MIN,_FLINK\r
3338                 DW      TwoDUP,GreaterThan,ZBranch,MIN1\r
3339                 DW      SWAP\r
3340 MIN1            DW      DROP,EXIT\r
3341 \r
3342 ;   MOD         ( n1 n2 -- n3 )                 \ CORE\r
3343 ;               Divide n1 by n2, giving the single cell remainder n3.\r
3344 ;               Returns modulo of floored division in this implementation.\r
3345 ;\r
3346 ;   : MOD       /MOD DROP ;\r
3347 \r
3348                 $COLON  3,'MOD',MODD,_FLINK\r
3349                 DW      SlashMOD,DROP,EXIT\r
3350 \r
3351 ;   PICK        ( x_u ... x1 x0 u -- x_u ... x1 x0 x_u )        \ CORE EXT\r
3352 ;               Remove u and copy the uth stack item to top of the stack. An\r
3353 ;               ambiguous condition exists if there are less than u+2 items\r
3354 ;               on the stack before PICK is executed.\r
3355 ;\r
3356 ;   : PICK      DEPTH DUP 2 < IF -4 THROW THEN    \ stack underflow\r
3357 ;               2 - OVER U< IF -4 THROW THEN\r
3358 ;               1+ CELLS sp@ + @ ;\r
3359 \r
3360                 $COLON  4,'PICK',PICK,_FLINK\r
3361                 DW      DEPTH,DUPP,DoLIT,2,LessThan,ZBranch,PICK1\r
3362                 DW      DoLIT,-4,THROW\r
3363 PICK1           DW      DoLIT,2,Minus,OVER,ULess,ZBranch,PICK2\r
3364                 DW      DoLIT,-4,THROW\r
3365 PICK2           DW      OnePlus,CELLS,SPFetch,Plus,Fetch,EXIT\r
3366 \r
3367 ;   POSTPONE    ( "<spaces>name" -- )           \ CORE\r
3368 ;               Parse name and find it. Append compilation semantics of name\r
3369 ;               to current definition.\r
3370 ;\r
3371 ;   : POSTPONE  (') 0< IF POSTPONE LITERAL\r
3372 ;                         POSTPONE COMPILE, EXIT THEN   \ non-IMMEDIATE\r
3373 ;               COMPILE, ; COMPILE-ONLY IMMEDIATE       \ IMMEDIATE\r
3374 \r
3375                 $COLON  IMMED+COMPO+8,'POSTPONE',POSTPONE,_FLINK\r
3376                 DW      ParenTick,ZeroLess,ZBranch,POSTP1\r
3377                 DW      LITERAL,DoLIT,COMPILEComma\r
3378 POSTP1          DW      COMPILEComma,EXIT\r
3379 \r
3380 ;   RECURSE     ( -- )                          \ CORE\r
3381 ;               Append the execution semactics of the current definition to\r
3382 ;               the current definition.\r
3383 ;\r
3384 ;   : RECURSE   bal 1- 2* PICK 1+ IF -22 THROW THEN\r
3385 ;                       \ control structure mismatch; colon-sys type is -1\r
3386 ;               bal 1- 2* 1+ PICK       \ xt of current definition\r
3387 ;               COMPILE, ; COMPILE-ONLY IMMEDIATE\r
3388 \r
3389                 $COLON  IMMED+COMPO+7,'RECURSE',RECURSE,_FLINK\r
3390                 DW      Bal,OneMinus,TwoStar,PICK,OnePlus,ZBranch,RECUR1\r
3391                 DW      DoLIT,-22,THROW\r
3392 RECUR1          DW      Bal,OneMinus,TwoStar,OnePlus,PICK\r
3393                 DW      COMPILEComma,EXIT\r
3394 \r
3395 ;   REPEAT      ( C: orig dest -- )             \ CORE\r
3396 ;               Terminate a BEGIN-WHILE-REPEAT indefinite loop. Resolve\r
3397 ;               backward reference dest and forward reference orig.\r
3398 ;\r
3399 ;   : REPEAT    AGAIN THEN ; COMPILE-ONLY IMMEDIATE\r
3400 \r
3401                 $COLON  IMMED+COMPO+6,'REPEAT',REPEATT,_FLINK\r
3402                 DW      AGAIN,THENN,EXIT\r
3403 \r
3404 ;   RSHIFT      ( x1 u -- x2 )                  \ CORE\r
3405 ;               Perform a logical right shift of u bit-places on x1, giving x2.\r
3406 ;               Put 0 into the most significant bits vacated by the shift.\r
3407 ;\r
3408 ;   : RSHIFT    ?DUP IF\r
3409 ;                       0 SWAP  cell-size-in-bits SWAP -\r
3410 ;                       0 DO  2DUP D+  LOOP\r
3411 ;                       NIP\r
3412 ;                    THEN ;\r
3413 \r
3414                 $COLON  6,'RSHIFT',RSHIFT,_FLINK\r
3415                 DW      QuestionDUP,ZBranch,RSHIFT2\r
3416                 DW      Zero,SWAP,DoLIT,CELLL*8,SWAP,Minus,Zero,DoDO\r
3417 RSHIFT1         DW      TwoDUP,DPlus,DoLOOP,RSHIFT1\r
3418                 DW      NIP\r
3419 RSHIFT2         DW      EXIT\r
3420 \r
3421 ;   SLITERAL    ( c-addr1 u -- )                \ STRING\r
3422 ;               Run-time ( -- c-addr2 u )\r
3423 ;               Compile a string literal. Return the string on execution.\r
3424 ;\r
3425 ;   : SLITERAL  DUP LITERAL POSTPONE doS"\r
3426 ;               CHARS HERE 2DUP + ALIGNED TO HERE\r
3427 ;               SWAP MOVE ; COMPILE-ONLY IMMEDIATE\r
3428 \r
3429                 $COLON  IMMED+COMPO+8,'SLITERAL',SLITERAL,_FLINK\r
3430                 DW      DUPP,LITERAL,DoLIT,DoSQuote,COMPILEComma\r
3431                 DW      CHARS,HERE,TwoDUP,Plus,ALIGNED,DoTO,AddrHERE\r
3432                 DW      SWAP,MOVE,EXIT\r
3433 \r
3434 ;   S"          Compilation: ( "ccc<">" -- )    \ CORE\r
3435 ;               Run-time: ( -- c-addr u )\r
3436 ;               Parse ccc delimetered by " . Return the string specification\r
3437 ;               c-addr u on execution.\r
3438 ;\r
3439 ;   : S"        [CHAR] " PARSE POSTPONE SLITERAL ; COMPILE-ONLY IMMEDIATE\r
3440 \r
3441                 $COLON  IMMED+COMPO+2,'S"',SQuote,_FLINK\r
3442                 DW      DoLIT,'"',PARSE,SLITERAL,EXIT\r
3443 \r
3444 ;   SM/REM      ( d n1 -- n2 n3 )               \ CORE\r
3445 ;               Symmetric divide of double by single. Return remainder n2\r
3446 ;               and quotient n3.\r
3447 ;\r
3448 ;   : SM/REM    2DUP XOR >R OVER >R >R DUP 0< IF DNEGATE THEN\r
3449 ;               R> ABS UM/MOD\r
3450 ;               R> 0< IF SWAP NEGATE SWAP THEN\r
3451 ;               R> 0< IF        \ negative quotient\r
3452 ;                   NEGATE 0 OVER < 0= IF EXIT THEN\r
3453 ;                   -11 THROW                   THEN    \ result out of range\r
3454 ;               DUP 0< IF -11 THROW THEN ;              \ result out of range\r
3455 \r
3456                 $COLON  6,'SM/REM',SMSlashREM,_FLINK\r
3457                 DW      TwoDUP,XORR,ToR,OVER,ToR,ToR,DUPP,ZeroLess\r
3458                 DW      ZBranch,SMREM1\r
3459                 DW      DNEGATE\r
3460 SMREM1          DW      RFrom,ABSS,UMSlashMOD\r
3461                 DW      RFrom,ZeroLess,ZBranch,SMREM2\r
3462                 DW      SWAP,NEGATE,SWAP\r
3463 SMREM2          DW      RFrom,ZeroLess,ZBranch,SMREM3\r
3464                 DW      NEGATE,DoLIT,0,OVER,LessThan,ZeroEquals,ZBranch,SMREM4\r
3465 SMREM5          DW      EXIT\r
3466 SMREM3          DW      DUPP,ZeroLess,ZBranch,SMREM5\r
3467 SMREM4          DW      DoLIT,-11,THROW\r
3468 \r
3469 ;   SPACES      ( n -- )                        \ CORE\r
3470 ;               Send n spaces to the output device if n is greater than zero.\r
3471 ;\r
3472 ;   : SPACES    DUP 0 > IF 0 DO SPACE LOOP EXIT THEN  DROP;\r
3473 \r
3474                 $COLON  6,'SPACES',SPACES,_FLINK\r
3475                 DW      DUPP,Zero,GreaterThan,ZBranch,SPACES1\r
3476                 DW      Zero,DoDO\r
3477 SPACES2         DW      SPACE,DoLOOP,SPACES2\r
3478                 DW      EXIT\r
3479 SPACES1         DW      DROP,EXIT\r
3480 \r
3481 ;   TO          Interpretation: ( x "<spaces>name" -- ) \ CORE EXT\r
3482 ;               Compilation:    ( "<spaces>name" -- )\r
3483 ;               Run-time:       ( x -- )\r
3484 ;               Store x in name.\r
3485 ;\r
3486 ;   : TO        ' ?call DUP IF          \ should be call-doCONST\r
3487 ;                 ['] doVALUE =         \ verify VALUE marker\r
3488 ;                 IF STATE @\r
3489 ;                    IF POSTPONE doTO , EXIT THEN\r
3490 ;                    ! EXIT\r
3491 ;                    THEN THEN\r
3492 ;               -32 THROW ; IMMEDIATE   \ invalid name argument (e.g. TO xxx)\r
3493 \r
3494                 $COLON  IMMED+2,'TO',TO,_FLINK\r
3495                 DW      Tick,QCall,DUPP,ZBranch,TO1\r
3496                 DW      DoLIT,DoVALUE,Equals,ZBranch,TO1\r
3497                 DW      STATE,Fetch,ZBranch,TO2\r
3498                 DW      DoLIT,DoTO,COMPILEComma,Comma,EXIT\r
3499 TO2             DW      Store,EXIT\r
3500 TO1             DW      DoLIT,-32,THROW\r
3501 \r
3502 ;   U.          ( u -- )                        \ CORE\r
3503 ;               Display u in free field format followed by space.\r
3504 ;\r
3505 ;   : U.        0 D. ;\r
3506 \r
3507                 $COLON  2,'U.',UDot,_FLINK\r
3508                 DW      Zero,DDot,EXIT\r
3509 \r
3510 ;   UNTIL       ( C: dest -- )                  \ CORE\r
3511 ;               Terminate a BEGIN-UNTIL indefinite loop structure.\r
3512 ;\r
3513 ;   : UNTIL     IF -22 THROW THEN  \ control structure mismatch; dest type is 0\r
3514 ;               POSTPONE 0branch , bal- ; COMPILE-ONLY IMMEDIATE\r
3515 \r
3516                 $COLON  IMMED+COMPO+5,'UNTIL',UNTIL,_FLINK\r
3517                 DW      ZBranch,UNTIL1\r
3518                 DW      DoLIT,-22,THROW\r
3519 UNTIL1          DW      DoLIT,ZBranch,COMPILEComma,Comma,BalMinus,EXIT\r
3520 \r
3521 ;   VALUE       ( x "<spaces>name" -- )         \ CORE EXT\r
3522 ;               name Execution: ( -- x )\r
3523 ;               Create a value object with initial value x.\r
3524 ;\r
3525 ;   : VALUE     bal IF -29 THROW THEN           \ compiler nesting\r
3526 ;               head,  ['] doVALUE xt, DROP\r
3527 ;               , linkLast ; \ store x and link VALUE word to current wordlist\r
3528 \r
3529                 $COLON  5,'VALUE',VALUE,_FLINK\r
3530                 DW      Bal,ZBranch,VALUE1\r
3531                 DW      DoLIT,-29,THROW\r
3532 VALUE1          DW      HeadComma,DoLIT,DoVALUE,xtComma,DROP\r
3533                 DW      Comma,LinkLast,EXIT\r
3534 \r
3535 ;   VARIABLE    ( "<spaces>name" -- )           \ CORE\r
3536 ;               name Execution: ( -- a-addr )\r
3537 ;               Parse a name and create a variable with the name.\r
3538 ;               Resolve one cell of data space at an aligned address.\r
3539 ;               Return the address on execution.\r
3540 ;\r
3541 ;   : VARIABLE  bal IF -29 THROW THEN           \ compiler nesting\r
3542 ;               head,  ['] doVAR xt, DROP\r
3543 ;               HERE CELL+ TO HERE  linkLast ;\r
3544 \r
3545                 $COLON  8,'VARIABLE',VARIABLE,_FLINK\r
3546                 DW      Bal,ZBranch,VARIA1\r
3547                 DW      DoLIT,-29,THROW\r
3548 VARIA1          DW      HeadComma,DoLIT,DoVAR,xtComma,DROP\r
3549                 DW      HERE,CELLPlus,DoTO,AddrHERE,LinkLast,EXIT\r
3550 \r
3551 ;   WHILE       ( C: dest -- orig dest )        \ CORE\r
3552 ;               Put the location of a new unresolved forward reference orig\r
3553 ;               onto the control flow stack under the existing dest. Typically\r
3554 ;               used in BEGIN ... WHILE ... REPEAT structure.\r
3555 ;\r
3556 ;   : WHILE     POSTPONE IF 2SWAP ; COMPILE-ONLY IMMEDIATE\r
3557 \r
3558                 $COLON  IMMED+COMPO+5,'WHILE',WHILEE,_FLINK\r
3559                 DW      IFF,TwoSWAP,EXIT\r
3560 \r
3561 ;   WORD        ( char "<chars>ccc<char>" -- c-addr )   \ CORE\r
3562 ;               Skip leading delimeters and parse a word. Return the address\r
3563 ;               of a transient region containing the word as counted string.\r
3564 ;\r
3565 ;   : WORD      skipPARSE HERE pack" DROP HERE ;\r
3566 \r
3567                 $COLON  4,'WORD',WORDD,_FLINK\r
3568                 DW      SkipPARSE,HERE,PackQuote,DROP,HERE,EXIT\r
3569 \r
3570 ;   [']         Compilation: ( "<spaces>name" -- )      \ CORE\r
3571 ;               Run-time: ( -- xt )\r
3572 ;               Parse name. Return the execution token of name on execution.\r
3573 ;\r
3574 ;   : [']       ' POSTPONE LITERAL ; COMPILE-ONLY IMMEDIATE\r
3575 \r
3576                 $COLON  IMMED+COMPO+3,"[']",BracketTick,_FLINK\r
3577                 DW      Tick,LITERAL,EXIT\r
3578 \r
3579 ;   [CHAR]      Compilation: ( "<spaces>name" -- )      \ CORE\r
3580 ;               Run-time: ( -- char )\r
3581 ;               Parse name. Return the value of the first character of name\r
3582 ;               on execution.\r
3583 ;\r
3584 ;   : [CHAR]    CHAR POSTPONE LITERAL ; COMPILE-ONLY IMMEDIATE\r
3585 \r
3586                 $COLON  IMMED+COMPO+6,'[CHAR]',BracketCHAR,_FLINK\r
3587                 DW      CHAR,LITERAL,EXIT\r
3588 \r
3589 ;   \           ( "ccc<eol>" -- )               \ CORE EXT\r
3590 ;               Parse and discard the remainder of the parse area.\r
3591 ;\r
3592 ;   : \         SOURCE >IN ! DROP ; IMMEDIATE\r
3593 \r
3594                 $COLON  IMMED+1,'\',Backslash,_FLINK\r
3595                 DW      SOURCE,ToIN,Store,DROP,EXIT\r
3596 \r
3597 ; Optional Facility words\r
3598 \r
3599 ;   EKEY?       ( -- flag )                     \ FACILITY EXT\r
3600 ;               If a keyboard event is available, return true.\r
3601 ;\r
3602 ;   : EKEY?     'ekey? EXECUTE ;\r
3603 \r
3604                 $COLON  5,'EKEY?',EKEYQuestion,_FLINK\r
3605                 DW      TickEKEYQ,EXECUTE,EXIT\r
3606 \r
3607 ;   EMIT?       ( -- flag )                     \ FACILITY EXT\r
3608 ;               flag is true if the user output device is ready to accept data\r
3609 ;               and the execution of EMIT in place of EMIT? would not have\r
3610 ;               suffered an indefinite delay. If device state is indeterminate,\r
3611 ;               flag is true.\r
3612 ;\r
3613 ;   : EMIT?     'emit? EXECUTE ;\r
3614 \r
3615                 $COLON  5,'EMIT?',EMITQuestion,_FLINK\r
3616                 DW      TickEMITQ,EXECUTE,EXIT\r
3617 \r
3618 ;===============================================================\r
3619 \r
3620 LASTENV         EQU     _ENVLINK-0\r
3621 LASTSYSTEM      EQU     _SLINK-0        ;last SYSTEM word name address\r
3622 LASTFORTH       EQU     _FLINK-0        ;last FORTH word name address\r
3623 \r
3624 CTOP            EQU     $-0             ;next available memory in dictionary\r
3625 \r
3626 MAIN    ENDS\r
3627 END     ORIG\r
3628 \r
3629 ;===============================================================\r