1 // and now for something completely different...
2 // UrAsm built-in Forth Engine!
5 //#define UFE_DSFORTH_CONFORMANT_LOOPS
7 static uint32_t ufeAfterTrace
= 0;
9 typedef struct UForthWord_t UForthWord
;
13 void (*cfa
) (UForthWord
*self
); // `self` may be NULL if called from the internal code
14 uint32_t cfaidx
; // in `ufeForthCFAs`
15 uint32_t pfa
; // pointer to image
19 static UForthWord
*ufeForthDict
= NULL
;
21 #define UFE_MAX_WORDS (65536u)
22 static UForthWord
**ufeForthCFAs
= NULL
;
23 static unsigned ufeCFAsUsed
= 0;
25 #define UFE_ZX_ADDR_BIT (1u<<30)
26 #define UFE_ZX_ADDR_MASK (0xffffU)
28 static uint32_t *ufeImage
= NULL
;
29 static uint32_t ufeImageSize
= 0;
30 static uint32_t ufeImageUsed
= 0;
32 static uint32_t ufeIP
= 0; // in image
33 static uint32_t ufeSP
= 0;
34 static uint32_t ufeRP
= 0;
36 // the compiler works in two modes
37 // first mode is "native"
38 // only forth variables are allowed, and they're leaving ZX addresses
39 // second mode is "zx"
40 // in this mode, various creation words will create things in ZX memory.
41 // note that in interpret mode it is still possible to perform various
42 // native calculations, and call native words.
43 // but calling native word while compiling ZX code is possible only if it
44 // is an immediate one.
47 UFE_MODE_ZX
= 1, // if STATE is not zero, we're compiling
49 static uint32_t ufeMode
= UFE_MODE_NATIVE
;
52 static ForthWord
*ufeNFindZXWordResult
= NULL
;
53 static UForthWord
*ufeNFindNativeWordResult
= NULL
;
55 // hack for `IMMEDIATE`
57 // only one of those can be set! (invariant)
58 static ForthWord
*ufeLastDefinedZXWord
= NULL
;
59 static UForthWord
*ufeLastDefinedNativeWord
= NULL
;
61 #define UFE_DSTACK_SIZE (8192)
62 #define UFE_RSTACK_SIZE (8192)
63 static uint32_t *ufeDStack
= NULL
;
64 static uint32_t *ufeRStack
= NULL
;
66 // dynamically allocated text input buffer
67 // always ends with zero (this is word name too)
68 // first 512 cells of image is TIB
69 static uint32_t ufeTIBAreaSize
= 512;
71 static uint32_t ufeTIB
= 0; // TIB; 0 means "in TIB area", otherwise in the dictionary
72 static uint32_t ufeIN
= 0; // >IN
74 static uint32_t ufeBASEaddr
; // address of "BASE" variable
75 static uint32_t ufeSTATEaddr
; // address of "STATE" variable
76 static uint32_t ufeStopVM
;
78 #define UFE_PAD_OFFSET (2048u)
79 #define UFE_PAD1_OFFSET (4096u)
81 typedef struct UFEInFileStack_t
{
85 struct UFEInFileStack_t
*prev
;
88 static UFEInFileStack
*ufeFileStack
= NULL
;
90 static FILE *ufeInFile
= NULL
;
91 static char *ufeInFileName
= NULL
;
92 static int ufeInFileLine
= 0;
93 static jmp_buf ufeEOFJP
;
95 static UrLabelInfo
*zxlblLastByte
= NULL
;
97 static int ufeLastEmitWasCR
= 1;
98 static uint32_t ufeCSP
= 0;
99 static int ufeInCondIf
= 0;
102 // ////////////////////////////////////////////////////////////////////////// //
103 static void ufeDbgDeinit (void);
104 static void ufeRunVM (void);
106 static char *ufeZXWORD (char delim
);
107 // returns dynalloced string
108 static char *ufePopStrLit (void);
110 static void ufeDoConditional (unsigned type
, int skipword
);
111 static void ufeCompileNativeWord (const char *wname
);
114 // ////////////////////////////////////////////////////////////////////////// //
115 /* returns malloced string */
116 static char *ufeCreateIncludeName (const char *fname
, int assystem
) {
117 if (!fname
|| !fname
[0]) return strdup("");
118 //char *incdir = extractFileDir(ufeInFileName);
121 if (!assystem
&& stat(fname
, &st
) == 0) return strdup(fname
);
123 if (fname
[0] == '/') return strdup(fname
);
127 incdir
= (sysIncludeDir
&& sysIncludeDir
[0] ? strprintf("%s/ufe", sysIncludeDir
) : strdup("."));
129 incdir
= extractFileDir(ufeInFileName
);
131 char *res
= strprintf("%s/%s", incdir
, fname
);
133 //fprintf(stderr, "000: **** <%s> : <%s> : <%s>\n", fname, incdir, res);
134 if (stat(res
, &st
) == 0) return res
;
136 return strdup(fname
);
140 static void ufePushInFile (void) {
141 UFEInFileStack
*stk
= malloc(sizeof(UFEInFileStack
));
143 stk
->fname
= ufeInFileName
;
144 stk
->fline
= ufeInFileLine
;
145 stk
->prev
= ufeFileStack
;
148 ufeInFileName
= NULL
;
153 static void ufePopInFile (void) {
154 if (ufeInFileName
) free(ufeInFileName
);
155 if (ufeInFile
) fclose(ufeInFile
);
156 UFEInFileStack
*stk
= ufeFileStack
;
157 ufeFileStack
= stk
->prev
;
159 ufeInFileName
= stk
->fname
;
160 ufeInFileLine
= stk
->fline
;
165 // ////////////////////////////////////////////////////////////////////////// //
166 static void ufeErrorWriteFile (FILE *fo
) {
168 fprintf(fo
, "UFE ERROR at file %s, line %d: ", ufeInFileName
, ufeInFileLine
);
170 fprintf(fo
, "UFE ERROR somewhere in time: ");
174 static void ufeErrorMsgV (const char *fmt
, va_list ap
) {
175 ufeErrorWriteFile(stderr
);
176 vfprintf(stderr
, fmt
, ap
);
182 static void __attribute__((noreturn
)) __attribute__((format(printf
, 1, 2))) ufeFatal (const char *fmt
, ...) {
185 ufeErrorMsgV(fmt
, ap
);
190 // ////////////////////////////////////////////////////////////////////////// //
191 static void ufeDeinit (void) {
193 if (ufeInFileName
) free(ufeInFileName
);
194 ufeInFileName
= NULL
;
197 while (ufeForthDict
) {
198 UForthWord
*fw
= ufeForthDict
;
199 ufeForthDict
= fw
->prev
;
216 ufeMode
= UFE_MODE_NATIVE
;
226 zxlblLastByte
= NULL
;
228 ufeNFindZXWordResult
= NULL
;
229 ufeNFindNativeWordResult
= NULL
;
231 ufeLastDefinedZXWord
= NULL
;
232 ufeLastDefinedNativeWord
= NULL
;
234 ufeLastEmitWasCR
= 1;
242 // ////////////////////////////////////////////////////////////////////////// //
243 // working with the zx image
245 static __attribute__((unused
)) inline uint32_t ufeZXGetU16 (uint32_t addr
) {
247 return getWord(addr
);
250 static __attribute__((unused
)) inline void ufeZXPutU16 (uint32_t addr
, uint32_t v
) {
256 static __attribute__((unused
)) inline void ufeZXEmitU8 (uint32_t v
) {
257 //if (!zxlblLastByte) ufeFatal("label 'latest_byte' not found");
259 if (zxlblLastByte
) zxlblLastByte
->value
= disp
;
262 static __attribute__((unused
)) inline void ufeZXEmitU16 (uint32_t v
) {
263 //if (!zxlblLastByte) ufeFatal("label 'latest_byte' not found");
265 if (zxlblLastByte
) zxlblLastByte
->value
= disp
;
269 // ////////////////////////////////////////////////////////////////////////// //
270 // working with the image
272 static __attribute__((unused
)) inline void ufeImgEnsure (uint32_t addr
) {
273 if ((addr
&UFE_ZX_ADDR_BIT
) == 0) {
274 if (addr
+8192u > ufeImageSize
) {
275 const uint32_t osz
= ufeImageSize
;
276 while (addr
+8192u > ufeImageSize
) {
277 if (ufeImageSize
>= 1024u*1024u*8u) ufeFatal("UFE image grown too big");
278 ufeImageSize
+= 1024u*1024u;
280 ufeImage
= realloc(ufeImage
, ufeImageSize
*sizeof(ufeImage
[0]));
281 memset(ufeImage
+osz
, 0, (ufeImageSize
-osz
)*sizeof(ufeImage
[0]));
286 static __attribute__((unused
)) inline void ufeImgPutU8 (uint32_t addr
, uint32_t value
) {
287 if (addr
&UFE_ZX_ADDR_BIT
) {
288 addr
&= UFE_ZX_ADDR_MASK
;
289 putByte(addr
, value
&0xffU
);
291 if (addr
>= ufeImageSize
) ufeFatal("UFE write violation (%u)", addr
);
292 ufeImage
[addr
] = value
;
296 static __attribute__((unused
)) inline void ufeImgPutU32 (uint32_t addr
, uint32_t value
) {
297 if (addr
&UFE_ZX_ADDR_BIT
) {
298 addr
&= UFE_ZX_ADDR_MASK
;
299 putWord(addr
, value
&0xffffU
);
301 if (addr
>= ufeImageSize
) ufeFatal("UFE write violation (%u)", addr
);
302 ufeImage
[addr
] = value
;
306 static __attribute__((unused
)) inline void ufeImgEmitU32 (uint32_t value
) {
307 ufeImgEnsure(ufeImageUsed
);
308 ufeImgPutU32(ufeImageUsed
, value
);
313 static __attribute__((unused
)) inline uint32_t ufeImgGetU8 (uint32_t addr
) {
314 if (addr
&UFE_ZX_ADDR_BIT
) {
315 addr
&= UFE_ZX_ADDR_MASK
;
316 return getByte(addr
);
318 if (addr
>= ufeImageSize
) ufeFatal("UFE read violation (%u)", addr
);
319 return ufeImage
[addr
];
324 static __attribute__((unused
)) inline uint32_t ufeImgGetU32 (uint32_t addr
) {
325 if (addr
&UFE_ZX_ADDR_BIT
) {
326 addr
&= UFE_ZX_ADDR_MASK
;
327 return getWord(addr
);
329 if (addr
>= ufeImageSize
) ufeFatal("UFE read violation (%u)", addr
);
330 return ufeImage
[addr
];
335 // 32 for native address, 8 for zx address
336 static __attribute__((unused
)) inline uint32_t ufeImgGetCounter (uint32_t addr
) {
337 if (addr
&UFE_ZX_ADDR_BIT
) {
338 return ufeImgGetU8(addr
);
340 return ufeImgGetU32(addr
);
345 // ////////////////////////////////////////////////////////////////////////// //
346 static inline int ufeGetState (void) { return (int)ufeImgGetU32(ufeSTATEaddr
); }
347 static inline void ufeSetState (int v
) { ufeImgPutU32(ufeSTATEaddr
, (uint32_t)v
); }
350 // ////////////////////////////////////////////////////////////////////////// //
351 static UForthWord
*ufeFindWord (const char *wname
) {
352 if (!wname
) wname
= "";
353 for (UForthWord
*fw
= ufeForthDict
; fw
; fw
= fw
->prev
) {
354 if (strcasecmp(fw
->name
, wname
) == 0) return fw
;
360 static inline UForthWord
*ufeAlwaysWord (const char *wname
) {
361 UForthWord
*fw
= ufeFindWord(wname
);
362 if (!fw
) ufeFatal("UFE word `%s` not found", (wname
[0] ? wname
: "~"));
367 static UForthWord
*ufeNFind (uint32_t addr
, uint32_t count
) {
370 if (count
> 127) return NULL
; // too long
372 for (uint32_t n
= 0; n
< count
; ++n
) {
373 const uint8_t ch
= ufeImgGetU8(addr
+n
)&0xffU
;
374 if (!ch
) return NULL
; // word name cannot contain 0 byte
375 wbuf
[n
] = toUpper((char)(ch
));
379 // ignore words with no CFA: those are not finished yet
380 for (UForthWord
*fw
= ufeForthDict
; fw
; fw
= fw
->prev
) {
381 if (fw
->cfa
&& strcasecmp(fw
->name
, wbuf
) == 0) return fw
;
387 static ForthWord
*ufeNFindZX (uint32_t addr
, uint32_t count
) {
390 if (count
> 31) return NULL
; // too long
392 for (uint32_t n
= 0; n
< count
; ++n
) {
393 const uint8_t ch
= ufeImgGetU8(addr
+n
)&0xffU
;
394 if (!ch
) return NULL
; // word name cannot contain 0 byte
395 wbuf
[n
] = toUpper((char)(ch
));
399 // ignore last word if we're in compiling mode (it is not finished yet)
400 return findForthWordEx(wbuf
, (ufeMode
== UFE_MODE_ZX
&& ufeGetState()));
404 // ////////////////////////////////////////////////////////////////////////// //
405 // load next file line into TIV
406 // return zero on success, -1 on EOF, -2 on error
407 static char ufeCurrFileLine
[520];
409 static int ufeLoadNextLine (void) {
412 if (!ufeInFile
) return -2;
413 if (!fgets(ufeCurrFileLine
, 510, ufeInFile
)) {
414 if (!ufeFileStack
) return -1;
416 return ufeLoadNextLine();
422 ufeImgPutU32(f
, (uint8_t)(ufeCurrFileLine
[f
]&0xff));
423 } while (ufeCurrFileLine
[f
++]);
424 //fprintf(stderr, "---\n%s", ufeCurrFileLine);
429 // ////////////////////////////////////////////////////////////////////////// //
430 // working with the stacks
431 static __attribute__((unused
)) inline void ufePush (uint32_t v
) { if (ufeSP
>= UFE_DSTACK_SIZE
) ufeFatal("UFE data stack overflow"); ufeDStack
[ufeSP
++] = v
; }
432 static __attribute__((unused
)) inline void ufeDrop (void) { if (ufeSP
== 0) ufeFatal("UFE data stack underflow"); --ufeSP
; }
433 static __attribute__((unused
)) inline uint32_t ufePop (void) { if (ufeSP
== 0) ufeFatal("UFE data stack underflow"); return ufeDStack
[--ufeSP
]; }
434 static __attribute__((unused
)) inline uint32_t ufePeek (void) { if (ufeSP
== 0) ufeFatal("UFE data stack underflow"); return ufeDStack
[ufeSP
-1u]; }
435 static __attribute__((unused
)) inline void ufeDup (void) { if (ufeSP
== 0) ufeFatal("UFE data stack underflow"); ufePush(ufeDStack
[ufeSP
-1u]); }
436 static __attribute__((unused
)) inline void ufeOver (void) { if (ufeSP
< 2u) ufeFatal("UFE data stack underflow"); ufePush(ufeDStack
[ufeSP
-2u]); }
437 static __attribute__((unused
)) inline void ufeSwap (void) { if (ufeSP
< 2u) ufeFatal("UFE data stack underflow"); const uint32_t t
= ufeDStack
[ufeSP
-1u]; ufeDStack
[ufeSP
-1u] = ufeDStack
[ufeSP
-2u]; ufeDStack
[ufeSP
-2u] = t
; }
438 static __attribute__((unused
)) inline void ufeRot (void) { if (ufeSP
< 3u) ufeFatal("UFE data stack underflow"); const uint32_t t
= ufeDStack
[ufeSP
-3u]; ufeDStack
[ufeSP
-3u] = ufeDStack
[ufeSP
-2u]; ufeDStack
[ufeSP
-2u] = ufeDStack
[ufeSP
-1u]; ufeDStack
[ufeSP
-1u] = t
; }
439 static __attribute__((unused
)) inline void ufeNRot (void) { if (ufeSP
< 3u) ufeFatal("UFE data stack underflow"); const uint32_t t
= ufeDStack
[ufeSP
-1u]; ufeDStack
[ufeSP
-1u] = ufeDStack
[ufeSP
-2u]; ufeDStack
[ufeSP
-2u] = ufeDStack
[ufeSP
-3u]; ufeDStack
[ufeSP
-3u] = t
; }
441 static __attribute__((unused
)) inline void ufe2Dup (void) { ufeOver(); ufeOver(); }
442 static __attribute__((unused
)) inline void ufe2Drop (void) { ufeDrop(); ufeDrop(); }
443 static __attribute__((unused
)) inline void ufe2Over (void) { if (ufeSP
< 4u) ufeFatal("UFE data stack underflow"); const uint32_t n0
= ufeDStack
[ufeSP
-4u]; const uint32_t n1
= ufeDStack
[ufeSP
-3u]; ufePush(n0
); ufePush(n1
); }
444 static __attribute__((unused
)) inline void ufe2Swap (void) { if (ufeSP
< 4u) ufeFatal("UFE data stack underflow"); const uint32_t n0
= ufeDStack
[ufeSP
-4u]; const uint32_t n1
= ufeDStack
[ufeSP
-3u]; ufeDStack
[ufeSP
-4u] = ufeDStack
[ufeSP
-2u]; ufeDStack
[ufeSP
-3u] = ufeDStack
[ufeSP
-1u]; ufeDStack
[ufeSP
-2u] = n0
; ufeDStack
[ufeSP
-1u] = n1
; }
446 static __attribute__((unused
)) inline void ufeRPush (uint32_t v
) { if (ufeRP
>= UFE_RSTACK_SIZE
) ufeFatal("UFE return stack overflow"); ufeRStack
[ufeRP
++] = v
; }
447 static __attribute__((unused
)) inline void ufeRDrop (void) { if (ufeRP
== 0) ufeFatal("UFE return stack underflow"); --ufeRP
; }
448 static __attribute__((unused
)) inline uint32_t ufeRPop (void) { if (ufeRP
== 0) ufeFatal("UFE return stack underflow"); return ufeRStack
[--ufeRP
]; }
449 static __attribute__((unused
)) inline uint32_t ufeRPeek (void) { if (ufeRP
== 0) ufeFatal("UFE return stack underflow"); return ufeRStack
[ufeRP
-1u]; }
450 static __attribute__((unused
)) inline void ufeRDup (void) { if (ufeRP
== 0) ufeFatal("UFE return stack underflow"); ufePush(ufeRStack
[ufeRP
-1u]); }
451 static __attribute__((unused
)) inline void ufeROver (void) { if (ufeRP
< 2u) ufeFatal("UFE return stack underflow"); ufePush(ufeRStack
[ufeRP
-2u]); }
452 static __attribute__((unused
)) inline void ufeRSwap (void) { if (ufeRP
< 2u) ufeFatal("UFE return stack underflow"); const uint32_t t
= ufeRStack
[ufeRP
-1u]; ufeRStack
[ufeRP
-1u] = ufeRStack
[ufeRP
-2u]; ufeRStack
[ufeRP
-2u] = t
; }
453 static __attribute__((unused
)) inline void ufeRRot (void) { if (ufeRP
< 3u) ufeFatal("UFE return stack underflow"); const uint32_t t
= ufeRStack
[ufeRP
-3u]; ufeRStack
[ufeRP
-3u] = ufeRStack
[ufeRP
-2u]; ufeRStack
[ufeRP
-2u] = ufeRStack
[ufeRP
-1u]; ufeRStack
[ufeRP
-1u] = t
; }
454 static __attribute__((unused
)) inline void ufeRNRot (void) { if (ufeRP
< 3u) ufeFatal("UFE return stack underflow"); const uint32_t t
= ufeRStack
[ufeRP
-1u]; ufeRStack
[ufeRP
-1u] = ufeRStack
[ufeRP
-2u]; ufeRStack
[ufeRP
-2u] = ufeRStack
[ufeRP
-3u]; ufeRStack
[ufeRP
-3u] = t
; }
457 // ////////////////////////////////////////////////////////////////////////// //
458 #define UFWORD(name_) \
459 static void ufeWord_##name_ (UForthWord *self)
461 #define UFCALL(name_) ufeWord_##name_(NULL)
464 static void ufeDoForth (UForthWord
*self
) {
465 //fprintf(stderr, "ufeDoForth: <%s>; ip=%u; pfa=%u; HERE=%u\n", self->name, ufeIP, self->pfa, ufeImageUsed);
471 // ////////////////////////////////////////////////////////////////////////// //
484 ufePush(ufeBASEaddr
);
489 ufePush(ufeSTATEaddr
);
494 const uint32_t addr
= ufePop();
495 ufePush(ufeImgGetU32(addr
));
500 const uint32_t addr
= ufePop();
501 ufePush(ufeImgGetU8(addr
)&0xffU
);
506 const uint32_t addr
= ufePop();
507 ufePush(ufeImgGetU32(addr
)&0xffffU
);
513 const uint32_t addr
= ufePop();
514 const uint32_t val
= ufePop();
515 ufeImgPutU32(addr
, val
);
521 const uint32_t addr
= ufePop();
522 const uint32_t val
= ufePop();
523 ufeImgPutU8(addr
, val
&0xffU
);
529 const uint32_t addr
= ufePop();
530 const uint32_t val
= ufePop();
531 ufeImgPutU32(addr
, val
&0xffffU
);
536 // puts byte to native/zx dictionary, according to the current mode
538 const uint32_t val
= ufePop()&0xffU
;
539 if (ufeMode
== UFE_MODE_ZX
) {
548 // puts uint/word to native/zx dictionary, according to the current mode
550 const uint32_t val
= ufePop();
551 if (ufeMode
== UFE_MODE_ZX
) {
552 ufeZXEmitU16(val
&0xffffU
);
560 // is address a ZX Spectrum mmaped address?
562 const uint32_t addr
= ufePop();
563 ufePush(addr
&UFE_ZX_ADDR_BIT
? 1u : 0u);
568 // convert address to ZX Spectrum mmaped address
570 const uint32_t addr
= ufePop();
571 ufePush((addr
&UFE_ZX_ADDR_MASK
)|UFE_ZX_ADDR_BIT
);
576 // convert address to ZX Spectrum mmaped address
578 if (ufeMode
== UFE_MODE_NATIVE
) {
580 ufeCompileNativeWord("(TOZX)");
589 // convert address from ZX Spectrum mmaped address
591 const uint32_t addr
= ufePop();
592 ufePush(addr
&UFE_ZX_ADDR_MASK
);
597 // convert address from ZX Spectrum mmaped address
599 if (ufeMode
== UFE_MODE_NATIVE
) {
601 ufeCompileNativeWord("(FROMZX)");
610 const uint32_t v
= ufeImgGetU32(ufeIP
++);
616 ufeIP
= ufeImgGetU32(ufeIP
);
622 ufeIP
= ufeImgGetU32(ufeIP
);
631 ufeIP
= ufeImgGetU32(ufeIP
);
638 // ( limit start -- | limit counter )
639 // loops from start to limit-1
646 // ( -- | limit counter )
647 static void ufePLoopCommon (int32_t add
) {
648 const int32_t n
= (int32_t)ufeRPop();
649 const int32_t lim
= (int32_t)ufeRPeek();
650 const int32_t newn
= n
+add
;
651 // this is how dsForth does it
652 if ((newn
< 0 ? lim
-newn
: newn
-lim
) < 0) {
654 ufeIP
= ufeImgGetU32(ufeIP
);
662 // ( -- | limit counter )
663 // loops from start to limit-1
669 // ( n -- | limit counter )
670 // loops from start to limit-1
671 UFWORD(PLOOP_PAREN
) {
672 const int32_t add
= (int32_t)ufePop();
680 const int32_t add = (int32_t)ufePop();
681 int32_t n = (int32_t)ufeRPop();
682 const int32_t lim = (int32_t)ufeRPeek();
683 if ((n < lim && n+add >= lim) || (n > lim && n+add <= lim)) {
688 ufeIP = ufeImgGetU32(ufeIP);
694 // ( counter -- | limit counter )
700 // ( limit -- | limit counter )
702 const uint32_t c
= ufeRPop();
709 const uint32_t c0
= ufeRPop();
710 const uint32_t c1
= ufeRPop();
718 const uint32_t c0
= ufeRPop();
719 const uint32_t c1
= ufeRPop();
720 const uint32_t c2
= ufeRPop();
729 const uint32_t cfa
= ufePop();
730 if (cfa
>= ufeCFAsUsed
) ufeFatal("calling invalid UFE word with EXECUTE (%u)", cfa
);
731 //ufeForthCFAs[cfa]->cfa(ufeForthCFAs[cfa]);
732 UForthWord
*fw
= ufeForthCFAs
[cfa
];
733 //fprintf(stderr, "[E:%s] ", fw->name);
734 if (fw
->cfa
== &ufeDoForth
) {
736 ufeRPush(0xbec0ffeeU
);
745 UFWORD(DUP
) { ufeDup(); }
746 // ?DUP ( n -- n n ) | ( 0 -- 0 )
747 UFWORD(QDUP
) { if (ufePeek()) ufeDup(); }
748 // 2DUP ( n0 n1 -- n0 n1 n0 n1 ) | ( 0 -- 0 )
749 UFWORD(DDUP
) { ufe2Dup(); }
751 UFWORD(DROP
) { ufeDrop(); }
753 UFWORD(DDROP
) { ufe2Drop(); }
754 // SWAP ( n0 n1 -- n1 n0 )
755 UFWORD(SWAP
) { ufeSwap(); }
756 // 2SWAP ( n0 n1 -- n1 n0 )
757 UFWORD(DSWAP
) { ufe2Swap(); }
758 // OVER ( n0 n1 -- n0 n1 n0 )
759 UFWORD(OVER
) { ufeOver(); }
760 // 2OVER ( n0 n1 -- n0 n1 n0 )
761 UFWORD(DOVER
) { ufe2Over(); }
762 // ROT ( n0 n1 n2 -- n1 n2 n0 )
763 UFWORD(ROT
) { ufeRot(); }
764 // NROT ( n0 n1 n2 -- n2 n0 n1 )
765 UFWORD(NROT
) { ufeNRot(); }
768 UFWORD(RDUP
) { ufeRDup(); }
770 UFWORD(RDROP
) { ufeRDrop(); }
771 // RSWAP ( n0 n1 -- n1 n0 )
772 UFWORD(RSWAP
) { ufeRSwap(); }
773 // ROVER ( n0 n1 -- n0 n1 n0 )
774 UFWORD(ROVER
) { ufeROver(); }
775 // RROT ( n0 n1 n2 -- n1 n2 n0 )
776 UFWORD(RROT
) { ufeRRot(); }
777 // RNROT ( n0 n1 n2 -- n2 n0 n1 )
778 UFWORD(RNROT
) { ufeRNRot(); }
781 UFWORD(DTOR
) { ufeRPush(ufePop()); }
782 // R> ( -- n | n-removed )
783 UFWORD(RTOD
) { ufePush(ufeRPop()); }
784 // R@ ( -- n | n-removed )
785 UFWORD(RPEEK
) { ufePush(ufeRPeek()); }
789 // ( src dest count -- )
791 uint32_t count
= ufePop();
792 uint32_t dest
= ufePop();
793 uint32_t src
= ufePop();
794 if (count
== 0 || count
> 0x1fffffffU
|| dest
== src
) return;
800 const uint32_t v
= (src
&UFE_ZX_ADDR_BIT
? getByte(src
&UFE_ZX_ADDR_MASK
) : ufeImgGetU32(src
));
801 if (dest
&UFE_ZX_ADDR_BIT
) putByte(dest
&UFE_ZX_ADDR_MASK
, (uint8_t)v
&0xffU
); else ufeImgPutU32(dest
, v
);
806 // ( src dest count -- )
808 uint32_t count
= ufePop();
809 uint32_t dest
= ufePop();
810 uint32_t src
= ufePop();
811 if (count
== 0 || count
> 0x1fffffffU
|| dest
== src
) return;
813 const uint32_t v
= (src
&UFE_ZX_ADDR_BIT
? getByte(src
&UFE_ZX_ADDR_MASK
) : ufeImgGetU32(src
));
814 if (dest
&UFE_ZX_ADDR_BIT
) putByte(dest
&UFE_ZX_ADDR_MASK
, (uint8_t)v
&0xffU
); else ufeImgPutU32(dest
, v
);
821 // ( src dest count -- )
823 uint32_t count
= ufePop();
824 uint32_t dest
= ufePop();
825 uint32_t src
= ufePop();
829 if (dest
< src
) UFCALL(CMOVE_BACK
); else UFCALL(CMOVE_FWD
);
834 // ( addr1 count1 addr2 count2 -- flag )
836 uint32_t count2
= ufePop();
837 uint32_t addr2
= ufePop();
838 uint32_t count1
= ufePop();
839 uint32_t addr1
= ufePop();
840 if (count2
!= count1
) { ufePush(0); return; }
842 uint8_t c0
= ufeImgGetU8(addr1
++);
843 uint8_t c1
= ufeImgGetU8(addr2
++);
844 if (c0
!= c1
) { ufePush(0); return; }
850 // ( addr1 count1 addr2 count2 -- flag )
852 uint32_t count2
= ufePop();
853 uint32_t addr2
= ufePop();
854 uint32_t count1
= ufePop();
855 uint32_t addr1
= ufePop();
856 if (count2
!= count1
) { ufePush(0); return; }
858 uint8_t c0
= (uint8_t)(toUpper((char)ufeImgGetU8(addr1
++)));
859 uint8_t c1
= (uint8_t)(toUpper((char)ufeImgGetU8(addr2
++)));
860 if (c0
!= c1
) { ufePush(0); return; }
866 // ////////////////////////////////////////////////////////////////////////// //
867 // text input buffer parsing
869 static inline char ufePeekInChar (void) {
870 uint32_t taddr
= ufeTIB
;
871 if (taddr
< ufeImageSize
&& taddr
+ufeIN
< ufeImageSize
) {
872 return ufeImgGetU32(taddr
+ufeIN
)&0xffU
;
878 static inline char ufeGetInChar (void) {
879 const char ch
= ufePeekInChar();
885 // parse word from TIB, put it to HERE as counted string
886 // always puts trailing zero to the buffer
887 // WORD ( delim -- addr )
889 const uint8_t delim
= ufePop()&0xffU
;
890 // put counter (to be fixed later)
891 ufeImgEnsure(ufeImageUsed
);
892 ufeImgPutU32(ufeImageUsed
, 0);
894 uint32_t taddr
= ufeTIB
;
895 if (taddr
< ufeImageSize
&& taddr
+ufeIN
< ufeImageSize
) {
897 uint32_t daddr
= ufeImageUsed
+1u;
899 // skip leading blanks
902 uint8_t ch
= ufeImgGetU32(taddr
+ufeIN
)&0xffU
;
903 if (!ch
) break; // no more
904 if (ch
!= delim
) break;
909 uint8_t ch
= ufeImgGetU32(taddr
+ufeIN
)&0xffU
;
910 if (!ch
) break; // no more
912 if (delim
== 32 && ch
<= 32) ch
= 32;
913 if ((delim
== 13 || delim
== 10) && (ch
== 13 || ch
== 10)) ch
= delim
;
914 if (ch
== delim
) { ++ufeIN
; break; } // skip delimiter
916 ufeImgPutU32(daddr
, ch
);
922 ufeImgPutU32(ufeImageUsed
, count
);
924 ufeImgEnsure(ufeImageUsed
+1u+count
);
925 ufeImgPutU32(ufeImageUsed
+1u+count
, 0);
928 ufeImgEnsure(ufeImageUsed
+1u);
929 ufeImgPutU32(ufeImageUsed
+1u, 0);
931 ufePush(ufeImageUsed
);
935 // ////////////////////////////////////////////////////////////////////////// //
941 uint32_t addr
= ufePop();
942 uint32_t len
= ufeImgGetCounter(addr
);
950 uint32_t ch
= ufePop()&0xffU
;
951 if (ch
< 32 || ch
== 127) {
952 if (ch
!= 10 && ch
!= 13 && ch
!= 9) { printf("?"); return; }
954 ufeLastEmitWasCR
= (ch
== 10);
955 if (ch
== 10) printf("\n"); else printf("%c", (char)ch
);
961 uint32_t ch
= ufePop()&0xffU
;
962 printf("%c", (ch
< 32 || ch
== 127 ? '?' : (char)ch
));
963 ufeLastEmitWasCR
= 0;
970 ufeLastEmitWasCR
= 1;
977 ufeLastEmitWasCR
= 0;
983 int32_t n
= (int32_t)ufePop();
984 while (n
-- > 0) printf(" ");
985 ufeLastEmitWasCR
= 0;
991 if (!ufeLastEmitWasCR
) {
993 ufeLastEmitWasCR
= 1;
1000 int32_t count
= (int32_t)ufePop();
1001 uint32_t addr
= ufePop();
1002 while (count
-- > 0) {
1003 const uint8_t ch
= ufeImgGetU8(addr
++)&0xffU
;
1010 // ( addr count -- )
1012 int32_t count
= (int32_t)ufePop();
1013 uint32_t addr
= ufePop();
1014 while (count
-- > 0) {
1015 const uint8_t ch
= ufeImgGetU8(addr
++)&0xffU
;
1022 UFWORD(STRQ_PAREN
) {
1023 const uint32_t count
= ufeImgGetU32(ufeIP
++);
1025 if (count
> 0x7fffffffU
) ufePush(0); else ufePush(count
);
1030 UFWORD(STRDOTQ_PAREN
) {
1031 const uint32_t count
= ufeImgGetU32(ufeIP
++);
1039 // ////////////////////////////////////////////////////////////////////////// //
1042 static char *ufePrintNumber (uint32_t v
, int sign
) {
1043 static char buf
[64];
1044 size_t bufpos
= sizeof(buf
);
1046 int64_t n
= (sign
? (int64_t)(int32_t)v
: (int64_t)(uint32_t)v
);
1047 const char sch
= (n
< 0 ? '-' : 0);
1049 int base
= ufeImgGetU32(ufeBASEaddr
);
1050 if (base
< 2 || base
> 36) { snprintf(buf
, sizeof(buf
), "%s", "invalid-base"); return buf
; }
1052 if (bufpos
== 0) ufeFatal("number too long");
1053 char ch
= '0'+(char)(n
%base
);
1054 if (ch
> '9') ch
+= 7;
1056 } while ((n
/= base
) != 0);
1057 if (bufpos
!= 0 && sch
) buf
[--bufpos
] = sch
;
1065 int32_t v
= (int32_t)ufePop();
1066 printf("%s ", ufePrintNumber(v
, 1));
1072 uint32_t v
= ufePop();
1073 printf("%s ", ufePrintNumber(v
, 0));
1079 int32_t wdt
= (int32_t)ufePop();
1080 int32_t v
= (int32_t)ufePop();
1081 char *s
= ufePrintNumber(v
, 1);
1082 int32_t slen
= (int32_t)strlen(s
);
1083 while (slen
< wdt
) { printf(" "); ++slen
; }
1090 int32_t wdt
= (int32_t)ufePop();
1091 int32_t v
= (int32_t)ufePop();
1092 char *s
= ufePrintNumber(v
, 0);
1093 int32_t slen
= (int32_t)strlen(s
);
1094 while (slen
< wdt
) { printf(" "); ++slen
; }
1099 // ////////////////////////////////////////////////////////////////////////// //
1105 const uint32_t a
= ufePop();
1112 const uint32_t b
= ufePop();
1113 const uint32_t a
= ufePop();
1120 const uint32_t b
= ufePop();
1121 const uint32_t a
= ufePop();
1128 const int32_t b
= (int32_t)ufePop();
1129 const int32_t a
= (int32_t)ufePop();
1130 ufePush((uint32_t)(a
*b
));
1136 const uint32_t b
= ufePop();
1137 const uint32_t a
= ufePop();
1138 ufePush((uint32_t)(a
*b
));
1144 const int32_t b
= (int32_t)ufePop();
1145 const int32_t a
= (int32_t)ufePop();
1146 if (b
== 0) ufeFatal("UFE division by zero");
1147 ufePush((uint32_t)(a
/b
));
1153 const uint32_t b
= ufePop();
1154 const uint32_t a
= ufePop();
1155 if (b
== 0) ufeFatal("UFE division by zero");
1156 ufePush((uint32_t)(a
/b
));
1162 const int32_t b
= (int32_t)ufePop();
1163 const int32_t a
= (int32_t)ufePop();
1164 if (b
== 0) ufeFatal("UFE division by zero");
1165 ufePush((uint32_t)(a
%b
));
1171 const uint32_t b
= ufePop();
1172 const uint32_t a
= ufePop();
1173 if (b
== 0) ufeFatal("UFE division by zero");
1174 ufePush((uint32_t)(a
%b
));
1178 // ( a b -- a/b, a%b )
1180 const int32_t b
= (int32_t)ufePop();
1181 const int32_t a
= (int32_t)ufePop();
1182 if (b
== 0) ufeFatal("UFE division by zero");
1183 ufePush((uint32_t)(a
/b
));
1184 ufePush((uint32_t)(a
%b
));
1188 // ( a b -- a/b, a%b )
1190 const uint32_t b
= ufePop();
1191 const uint32_t a
= ufePop();
1192 if (b
== 0) ufeFatal("UFE division by zero");
1193 ufePush((uint32_t)(a
/b
));
1194 ufePush((uint32_t)(a
%b
));
1198 // ////////////////////////////////////////////////////////////////////////// //
1204 const int32_t b
= (int32_t)ufePop();
1205 const int32_t a
= (int32_t)ufePop();
1206 ufePush(a
< b
? 1u : 0u);
1212 const int32_t b
= (int32_t)ufePop();
1213 const int32_t a
= (int32_t)ufePop();
1214 ufePush(a
> b
? 1u : 0u);
1220 const int32_t b
= (int32_t)ufePop();
1221 const int32_t a
= (int32_t)ufePop();
1222 ufePush(a
<= b
? 1u : 0u);
1228 const int32_t b
= (int32_t)ufePop();
1229 const int32_t a
= (int32_t)ufePop();
1230 ufePush(a
>= b
? 1u : 0u);
1236 const uint32_t b
= ufePop();
1237 const uint32_t a
= ufePop();
1238 ufePush(a
< b
? 1u : 0u);
1244 const uint32_t b
= ufePop();
1245 const uint32_t a
= ufePop();
1246 ufePush(a
> b
? 1u : 0u);
1252 const uint32_t b
= ufePop();
1253 const uint32_t a
= ufePop();
1254 ufePush(a
<= b
? 1u : 0u);
1260 const uint32_t b
= ufePop();
1261 const uint32_t a
= ufePop();
1262 ufePush(a
>= b
? 1u : 0u);
1268 const uint32_t b
= ufePop();
1269 const uint32_t a
= ufePop();
1270 ufePush(a
== b
? 1u : 0u);
1276 const uint32_t b
= ufePop();
1277 const uint32_t a
= ufePop();
1278 ufePush(a
!= b
? 1u : 0u);
1284 const uint32_t a
= ufePop();
1285 ufePush(a
? 0u : 1u);
1291 const uint32_t a
= ufePop();
1292 ufePush(a
? 1u : 0u);
1298 const uint32_t b
= ufePop();
1299 const uint32_t a
= ufePop();
1300 ufePush(a
&& b
? 1u : 0u);
1306 const uint32_t b
= ufePop();
1307 const uint32_t a
= ufePop();
1308 ufePush(a
|| b
? 1u : 0u);
1314 const uint32_t b
= ufePop();
1315 const uint32_t a
= ufePop();
1322 const uint32_t b
= ufePop();
1323 const uint32_t a
= ufePop();
1330 const uint32_t b
= ufePop();
1331 const uint32_t a
= ufePop();
1338 const uint32_t a
= ufePop();
1342 UFWORD(ONEPLUS
) { uint32_t n
= ufePop(); ufePush(n
+1u); }
1343 UFWORD(ONEMINUS
) { uint32_t n
= ufePop(); ufePush(n
-1u); }
1344 UFWORD(TWOPLUS
) { uint32_t n
= ufePop(); ufePush(n
+2u); }
1345 UFWORD(TWOMINUS
) { uint32_t n
= ufePop(); ufePush(n
-2u); }
1346 UFWORD(THREEPLUS
) { uint32_t n
= ufePop(); ufePush(n
+3u); }
1347 UFWORD(THREEMINUS
) { uint32_t n
= ufePop(); ufePush(n
-3u); }
1348 UFWORD(FOURPLUS
) { uint32_t n
= ufePop(); ufePush(n
+4u); }
1349 UFWORD(FOURMINUS
) { uint32_t n
= ufePop(); ufePush(n
-4u); }
1350 UFWORD(ONESHL
) { uint32_t n
= ufePop(); ufePush(n
*2u); }
1351 UFWORD(ONESHR
) { uint32_t n
= ufePop(); ufePush(n
/2u); }
1353 UFWORD(SHL
) { uint32_t c
= ufePop(); uint32_t n
= ufePop(); n
= (c
> 31u ? 0u : n
<<c
); ufePush(n
); }
1354 UFWORD(SHR
) { uint32_t c
= ufePop(); uint32_t n
= ufePop(); n
= (c
> 31u ? 0u : n
>>c
); ufePush(n
); }
1358 // ////////////////////////////////////////////////////////////////////////// //
1361 static void ufeCompileZXWord (const char *wname
) {
1362 if (!wname
) wname
= "";
1363 ForthWord
*fw
= findForthWord(wname
);
1364 if (!fw
) ufeFatal("ZX Forth word `%s` not found", (wname
[0] ? wname
: "~"));
1365 ufeZXEmitU16(fw
->cfa
);
1368 static void ufeCompileNativeWord (const char *wname
) {
1369 if (!wname
) wname
= "";
1370 UForthWord
*fw
= ufeAlwaysWord(wname
);
1371 ufeImgEmitU32(fw
->cfaidx
);
1374 // either ZX or native
1375 static void ufeCompileWord (const char *wname
) {
1376 //fprintf(stderr, "+++ <%s>\n", wname);
1377 if (ufeMode
== UFE_MODE_ZX
) {
1379 ufeCompileZXWord(wname
);
1381 ufeCompileNativeWord(wname
);
1385 static void ufeCompileZXLiteral (uint16_t value
) {
1386 ufeCompileZXWord("LIT");
1387 ufeZXEmitU16(value
);
1390 static void ufeCompileNativeLiteral (uint32_t value
) {
1391 ufeCompileNativeWord("LIT");
1392 ufeImgEmitU32(value
);
1395 static void ufeCompileLiteral (uint32_t value
) {
1396 if (ufeMode
== UFE_MODE_ZX
) {
1398 ufeCompileZXLiteral(value
);
1400 ufeCompileNativeLiteral(value
);
1408 if (ufeGetState()) {
1409 if (ufeMode
== UFE_MODE_ZX
) {
1411 ufeCompileZXLiteral(ufePop()&0xffffU
);
1414 ufeCompileLiteral(ufePop());
1420 // ( addr count -- addr count )
1421 UFWORD(UNESCAPE_PAREN
) {
1422 int32_t count
= (int32_t)ufePop();
1423 uint32_t addr
= ufePeek();
1424 if (count
< 0) { ufePush(0); return; }
1425 uint32_t caddr
= addr
;
1426 while (count
-- > 0) {
1427 uint8_t ch
= ufeImgGetU8(caddr
)&0xffU
;
1428 if (count
&& ch
== '\\') {
1430 ch
= ufeImgGetU8(caddr
+1)&0xffU
;
1433 case 'r': ufeImgPutU8(caddr
, '\r'); break;
1434 case 'n': ufeImgPutU8(caddr
, '\r'); ufeImgPutU8(caddr
+1, '\n'); xlen
= 2; break;
1435 case 't': ufeImgPutU8(caddr
, '\t'); break;
1436 case '`': ufeImgPutU8(caddr
, '"'); break;
1437 case '"': ufeImgPutU8(caddr
, '"'); break;
1438 case '\'': ufeImgPutU8(caddr
, '\''); break;
1439 case '\\': ufeImgPutU8(caddr
, '\\'); break;
1442 const int dg0
= digitInBase((char)(ufeImgGetU8(caddr
+2)&0xff), 16);
1443 const int dg1
= (count
> 3 ? digitInBase((char)(ufeImgGetU8(caddr
+3)&0xff), 16) : -1);
1444 if (dg0
< 0) ufeFatal("invalid UFE hex string escape");
1445 ch
= (dg1
< 0 ? (uint32_t)dg0
: ((uint32_t)dg0
)*16u+(uint32_t)dg1
);
1447 ufeFatal("invalid UFE hex string escape");
1450 default: xlen
= 0; break;
1453 if (xlen
> count
) ufeFatal("invalid UFE string escape");
1454 for (uint32_t n
= xlen
; n
< count
; ++n
) ufeImgPutU8(n
-xlen
, ufeImgGetU8(n
));
1459 ufeFatal("invalid UFE string escape");
1464 ufePush(caddr
-addr
);
1468 // I:( addr -- addr count )
1469 // R:( -- addr count )
1471 // addr *MUST* be HERE
1472 UFWORD(STRLITERAL
) {
1473 UFCALL(COUNT
); // ( addr+1 count )
1474 UFCALL(UNESCAPE_PAREN
);
1475 if (ufeGetState()) {
1476 uint32_t count
= ufePop();
1477 uint32_t addr
= ufePop();
1478 if (ufeMode
== UFE_MODE_ZX
) {
1480 if (count
> 255) ufeFatal("UFE ZX string too long");
1481 ufeZXEmitU8(count
&0xffU
);
1482 for (uint32_t n
= 0; n
< count
; ++n
) {
1483 uint8_t ch
= ufeImgGetU8(addr
+n
);
1484 ufeZXEmitU8(ch
&0xffU
);
1488 if (count
> 0xffffU
) ufeFatal("UFE string too long");
1489 if (addr
-1 != ufeImageUsed
) ufeFatal("invalid call to UFE word 'STRLITERAL'");
1490 ufeImgPutU32(addr
-1, count
);
1491 ufeImageUsed
+= count
+1;
1492 ufeImgEnsure(ufeImageUsed
);
1499 UFWORD(NATIVE_HERE
) {
1500 ufeImgEnsure(ufeImageUsed
);
1501 ufePush(ufeImageUsed
);
1506 UFWORD(NATIVE_PAD
) {
1507 ufeImgEnsure(ufeImageUsed
+1024);
1508 ufePush(ufeImageUsed
+1024);
1513 if (ufeGetState()) ufeCompileWord("(\")");
1514 ufePush(34); UFCALL(WORD
);
1516 if (/*ufeMode == UFE_MODE_NATIVE &&*/ !ufeGetState()) {
1519 uint32_t dest
= ufePop();
1520 uint32_t count
= ufePop();
1521 uint32_t src
= ufePop();
1522 if (count
> 0xffffU
) ufeFatal("UFE string too long");
1523 ufeImgEnsure(dest
+count
+2);
1524 for (uint32_t n
= 0; n
< count
; ++n
) ufeImgPutU32(dest
+n
, ufeImgGetU32(src
+n
));
1532 if (ufeGetState()) ufeCompileWord("(.\")");
1533 ufePush(34); UFCALL(WORD
);
1535 if (!ufeGetState()) {
1541 // ////////////////////////////////////////////////////////////////////////// //
1545 UFWORD(COMMENTPAREN
) {
1546 ufePush(')'); UFCALL(WORD
);
1551 UFWORD(COMMENTEOL
) {
1552 ufePush(10); UFCALL(WORD
);
1556 // NFIND ( addr count onlynativeimmflag -- cfa 1 | 0 )
1557 // find native/zx word
1558 // onlynativeimmflag:
1559 // 0: look for ZX word only if native word not found
1560 // !0: look for ZX word only if native word not found, or if it is not immediate
1561 // 666: prefer ZX words (used in `COMPILE`)
1562 // returned ZX CFA has `UFE_ZX_ADDR_BIT` set
1565 // look for native word
1566 // if there is none, look for zx word
1568 // look for native word
1569 // STATE == 0: (interpreting)
1570 // if there is none, look for zx word
1571 // STATE != 0: (compiling)
1572 // if no native word, or native word is not immediate, look for zx word
1574 uint32_t onlynativeimmflag
= ufePop();
1575 const uint32_t count
= ufePop();
1576 const uint32_t addr
= ufePop();
1577 ufeNFindZXWordResult
= NULL
;
1578 ufeNFindNativeWordResult
= NULL
;
1580 if (onlynativeimmflag
== 666) {
1582 ForthWord
*zxfw
= ufeNFindZX(addr
, count
);
1584 ufeNFindZXWordResult
= zxfw
;
1585 ufePush(zxfw
->cfa
|UFE_ZX_ADDR_BIT
);
1589 onlynativeimmflag
= 0;
1591 // look for native word
1592 UForthWord
*fw
= ufeNFind(addr
, count
);
1595 fprintf(stderr, "::%u:", count); for (uint32_t n = 0; n < count; ++n) fprintf(stderr, "%c", ufeImgGetU8(addr+n)); fprintf(stderr, "\n");
1597 fprintf(stderr, "::FOUND::%u:(%u:%u:%u)", count, onlynativeimmflag, fw->immediate, ufeMode); for (uint32_t n = 0; n < count; ++n) fprintf(stderr, "%c", ufeImgGetU8(addr+n)); fprintf(stderr, "\n");
1600 if (fw
&& (!onlynativeimmflag
|| fw
->immediate
)) {
1601 // native words allowed, or immediate native words allowed and it is immediate
1602 //fprintf(stderr, " !!\n");
1603 ufeNFindNativeWordResult
= fw
;
1604 ufePush(fw
->cfaidx
);
1609 ForthWord
*zxfw
= ufeNFindZX(addr
, count
);
1611 ufeNFindZXWordResult
= zxfw
;
1612 ufePush(zxfw
->cfa
|UFE_ZX_ADDR_BIT
);
1620 // convert number from addrl+1
1621 // returns address of the first inconvertable char
1622 // (XNUMBER) ( n1 addrl -- n2 addr2 )
1624 uint32_t addr
= ufePop()+1;
1625 uint32_t n
= ufePop();
1627 // special-based numbers
1628 if (ufeImgGetU8(addr
) == '0') {
1629 switch (ufeImgGetU8(addr
+1)) {
1630 case 'x': case 'X': base
= 16; break;
1631 case 'o': case 'O': base
= 8; break;
1632 case 'b': case 'B': base
= 2; break;
1633 case 'd': case 'D': base
= 10; break;
1636 if (base
&& digitInBase(ufeImgGetU8(addr
+2), base
) >= 0) {
1641 if (!base
) base
= (int)ufeImgGetU8(ufeBASEaddr
);
1642 if (base
> 0 && base
<= 36) {
1643 while (addr
< ufeImageSize
) {
1644 const uint32_t ch
= ufeImgGetU8(addr
)&0xffU
;
1646 const int dig
= digitInBase((char)ch
, (int)base
);
1648 n
= n
*(unsigned)base
+(unsigned)dig
;
1660 ufePush(32); UFCALL(WORD
); // ( addr )
1662 //ufe2Dup(); printf("WORD: %u %u [", ufePop(), ufePop()); ufe2Dup(); UFCALL(XTYPE); printf("]"); UFCALL(CR);
1663 uint32_t len
= ufePop();
1664 uint32_t addr
= ufePop();
1666 // end of input buffer; read next line
1667 const int rd
= ufeLoadNextLine();
1668 //printf("rd=%d\n", rd);
1669 if (rd
< -1) ufeFatal("error reading UFE input buffer");
1670 if (rd
== -1) longjmp(ufeEOFJP
, 666); // EOF
1674 ufePush(addr
); ufePush(len
);
1675 ufePush(ufeMode
== UFE_MODE_ZX
&& ufeGetState()); // if compiling for ZX, allow only immediate native words
1676 UFCALL(NFIND
); // ( cfa 1 ) | ( 0 )
1678 // word found, compile/execute
1679 uint32_t cfa
= ufePop();
1680 //printf("FOUND; cfa=0x%08x: ", cfa); ufePush(addr); ufePush(len); UFCALL(XTYPE); UFCALL(CR);
1682 if (cfa
&UFE_ZX_ADDR_BIT
) {
1684 cfa
&= UFE_ZX_ADDR_MASK
; // convert to real ZX address
1685 // if we're not compiling for ZX, only variables are allowed
1686 if (ufeMode
== UFE_MODE_ZX
) {
1688 if (ufeGetState()) {
1689 // any ZX word is allowed, compile it
1693 // only ZX variables are allowed
1694 if (ufeNFindZXWordResult
->wtype
== FWT_VAR
) {
1696 ufePush((cfa
+3)|UFE_ZX_ADDR_BIT
);
1699 // fallback to number parsing
1703 // only ZX variables are allowed
1704 if (ufeNFindZXWordResult
->wtype
== FWT_VAR
) {
1705 ufePush((cfa
+3)|UFE_ZX_ADDR_BIT
);
1709 // fallback to number parsing
1713 if (cfa
>= ufeCFAsUsed
) abort(); // assertion, the thing that should not be
1714 UForthWord
*fw
= ufeForthCFAs
[cfa
];
1715 //fprintf(stderr, " W:<%s>; cfa=0x%08x; state=%d\n", fw->name, cfa, ufeGetState());
1716 if (!fw
->immediate
&& ufeGetState()) {
1717 //fprintf(stderr, " [C:%s:%u:%s]\n", fw->name, fw->cfaidx, ufeForthCFAs[fw->cfaidx]->name);
1719 ufeImgEmitU32(fw
->cfaidx
);
1722 ufePush(fw
->cfaidx
);
1729 // word not found, try to parse a number
1731 if (ufeImgGetU8(addr
) == '-') { neg
= 1; ++addr
; --len
; }
1732 ufePush(0); // number
1733 ufePush(addr
-1u); // address
1735 // check if parsed successfully
1736 uint32_t eaddr
= ufePop();
1737 uint32_t n
= ufePop();
1738 //printf("addr=%u; n=%u; neg=%u\n", eaddr, n, neg); abort();
1739 if (eaddr
== addr
+len
) {
1741 //printf("addr=%u; n=%u; neg=%u\n", eaddr, n, neg); abort();
1742 if (neg
) n
= (~n
)+1u;
1743 //printf("addr=%u; n=%d; neg=%u\n", eaddr, (int32_t)n, neg); abort();
1748 // something wicked this way comes
1749 if (neg
) { --addr
; ++len
; }
1750 UFCALL(SPACE
); ufePush(addr
); ufePush(len
); UFCALL(XTYPE
);
1752 ufeFatal("unknown %s word", (ufeMode
== UFE_MODE_NATIVE
? "UFE" : "ZX"));
1757 // ////////////////////////////////////////////////////////////////////////// //
1758 // more compiler words
1762 if (ufeGetState()) ufeFatal("UFE: expecting execution mode");
1767 if (!ufeGetState()) ufeFatal("UFE: expecting compilation mode");
1771 // ( ocond cond -- )
1773 if (!ufeGetState()) ufeFatal("UFE: expecting compilation mode");
1774 const uint32_t cond
= ufePop();
1775 const uint32_t ocond
= ufePop();
1776 if (cond
!= ocond
) ufeFatal("UFE: unbalanced structured code");
1780 UFWORD(COMPILE_IMM
) {
1781 if (ufeGetState() == 0) ufeFatal("cannot call `COMPILE` from interpreter");
1782 ufePush(32); UFCALL(WORD
);
1784 ufePush(ufeMode
== UFE_MODE_ZX
? 666u : 0u); // for ZX mode, prefer ZX words
1785 UFCALL(NFIND
); // ( cfa 1 ) | ( 0 )
1787 uint32_t cfa
= ufePop();
1788 // for ZX mode, compile ZX code
1789 if (ufeMode
== UFE_MODE_ZX
) {
1790 if ((cfa
&UFE_ZX_ADDR_BIT
) == 0) ufeFatal("cannot `COMPILE` native word");
1791 cfa
&= UFE_ZX_ADDR_MASK
; // we need normal address here
1793 if (cfa
&UFE_ZX_ADDR_BIT
) ufeFatal("cannot `COMPILE` ZX word");
1795 ufeCompileLiteral(cfa
);
1796 ufeCompileWord(",");
1798 UFCALL(NATIVE_HERE
); UFCALL(COUNT
); UFCALL(SPACE
); UFCALL(XTYPE
);
1799 printf("?"); UFCALL(CR
);
1800 ufeFatal("UFE: unknown word");
1805 UFWORD(XCOMPILE_IMM
) {
1806 if (ufeGetState() == 0) ufeFatal("cannot call `[COMPILE]` from interpreter");
1807 ufePush(32); UFCALL(WORD
);
1809 ufePush(ufeMode
== UFE_MODE_ZX
? 666u : 0u); // for ZX mode, prefer ZX words
1810 UFCALL(NFIND
); // ( cfa 1 ) | ( 0 )
1812 uint32_t cfa
= ufePop();
1813 // for ZX mode, compile ZX code
1814 if (ufeMode
== UFE_MODE_ZX
) {
1815 if ((cfa
&UFE_ZX_ADDR_BIT
) == 0) ufeFatal("cannot `[COMPILE]` native word");
1816 cfa
&= UFE_ZX_ADDR_MASK
; // we need normal address here
1819 if (cfa
&UFE_ZX_ADDR_BIT
) ufeFatal("cannot `[COMPILE]` ZX word");
1823 UFCALL(NATIVE_HERE
); UFCALL(COUNT
); UFCALL(SPACE
); UFCALL(XTYPE
);
1824 printf("?"); UFCALL(CR
);
1825 ufeFatal("UFE: unknown word");
1832 if (ufeMode
== UFE_MODE_ZX
) {
1833 ufeZXEmitU16(ufePop());
1835 ufeImgEmitU32(ufePop());
1841 // calculate the forward branch offset from addr to HERE and put it into the addr
1843 if (ufeMode
== UFE_MODE_ZX
) {
1844 const uint32_t here
= disp
;
1845 const uint32_t addr
= ufePop();
1846 ufeZXPutU16(addr
, here
);
1848 UFCALL(NATIVE_HERE
);
1849 const uint32_t here
= ufePop();
1850 const uint32_t addr
= ufePop();
1851 ufeImgPutU32(addr
, here
);
1858 if (ufeIP
== 0xbec0ffeeU
) {
1859 if (ufeRP
) ufeIP
= ufeRPop();
1867 if (ufeMode
== UFE_MODE_ZX
) {
1870 UFCALL(NATIVE_HERE
);
1885 if (ufeMode
== UFE_MODE_ZX
) {
1886 ufeCompileZXWord("(DO)");
1889 UForthWord
*fw
= ufeAlwaysWord("(DO)");
1890 ufeImgEmitU32(fw
->cfaidx
);
1891 UFCALL(NATIVE_HERE
);
1901 if (ufeMode
== UFE_MODE_ZX
) {
1902 ufeCompileZXWord("(LOOP)");
1904 UForthWord
*fw
= ufeAlwaysWord("(LOOP)");
1905 ufeImgEmitU32(fw
->cfaidx
);
1915 if (ufeMode
== UFE_MODE_ZX
) {
1916 ufeCompileZXWord("(+LOOP)");
1918 UForthWord
*fw
= ufeAlwaysWord("(+LOOP)");
1919 ufeImgEmitU32(fw
->cfaidx
);
1929 if (ufeMode
== UFE_MODE_ZX
) {
1930 ufeCompileZXWord("0BRANCH");
1932 UForthWord
*fw
= ufeAlwaysWord("0BRANCH");
1933 ufeImgEmitU32(fw
->cfaidx
);
1943 if (ufeMode
== UFE_MODE_ZX
) {
1944 ufeCompileZXWord("BRANCH");
1946 UForthWord
*fw
= ufeAlwaysWord("BRANCH");
1947 ufeImgEmitU32(fw
->cfaidx
);
1954 const uint32_t n0
= ufePop();
1955 const uint32_t n1
= ufePop();
1959 ufePush(ufePop()-2u);
1966 if (ufeMode
== UFE_MODE_ZX
) {
1967 ufeCompileZXWord("0BRANCH");
1971 UForthWord
*fw
= ufeAlwaysWord("0BRANCH");
1972 ufeImgEmitU32(fw
->cfaidx
);
1973 UFCALL(NATIVE_HERE
);
1982 if (ufeMode
== UFE_MODE_ZX
) {
1983 ufeCompileZXWord("TBRANCH");
1987 UForthWord
*fw
= ufeAlwaysWord("TBRANCH");
1988 ufeImgEmitU32(fw
->cfaidx
);
1989 UFCALL(NATIVE_HERE
);
2000 if (ufeMode
== UFE_MODE_ZX
) {
2001 ufeCompileZXWord("BRANCH");
2005 UForthWord
*fw
= ufeAlwaysWord("BRANCH");
2006 ufeImgEmitU32(fw
->cfaidx
);
2007 UFCALL(NATIVE_HERE
);
2019 ufePush(ufePop()+2u);
2025 ufePush(ufeCSP
); ufeCSP
= ufeSP
; //CSP @ !CSP
2029 static void ufeXOF (const char *cmpwname
, int doswap
) {
2033 ufeCompileWord("OVER");
2034 if (doswap
) ufeCompileWord("SWAP");
2035 ufeCompileWord(cmpwname
);
2036 ufeCompileWord("0BRANCH");
2038 if (ufeMode
== UFE_MODE_ZX
) {
2042 UFCALL(NATIVE_HERE
);
2045 ufeCompileWord("DROP");
2064 ufeCompileWord("BRANCH");
2066 if (ufeMode
== UFE_MODE_ZX
) {
2070 UFCALL(NATIVE_HERE
);
2090 if (ufePeek() != 6) {
2093 ufeCompileWord("DROP");
2097 //fprintf(stderr, "SP=%u; csp=%u\n", ufeSP, ufeCSP);
2098 if (ufeSP
< ufeCSP
) ufeFatal("ENDCASE compiler error");
2099 while (ufeSP
> ufeCSP
) {
2103 ufeCSP
= ufePop(); //CSP !
2107 // ////////////////////////////////////////////////////////////////////////// //
2108 // define Forth words
2110 // 32 for native address, 8 for zx address
2111 static char *ufeZXWORD (char delim
) {
2112 static char buf
[257];
2115 uint32_t addr
= ufePop();
2116 uint32_t count
= ufeImgGetCounter(addr
++);
2117 if (count
> 255) ufeFatal("zx forth line too long");
2118 for (uint32_t n
= 0; n
< count
; ++n
) buf
[n
] = ufeImgGetU8(addr
+n
);
2120 if (delim
== 32) for (char *s
= buf
; *s
; ++s
) *s
= toUpper(*s
);
2125 // returns dynalloced string
2126 static char *ufePopStrLit (void) {
2127 uint32_t count
= ufePop();
2128 uint32_t addr
= ufePop();
2129 if (count
> 4096) ufeFatal("UFE string literal too long");
2130 char *res
= malloc(count
+1);
2131 for (uint32_t n
= 0; n
< count
; ++n
) res
[n
] = ufeImgGetU8(addr
+n
);
2136 // returns VM address of counted string
2137 static uint32_t ufePutTempStrLiteral (const char *s
, uint32_t destofs
) {
2139 uint32_t staddr
= ufeImageUsed
+destofs
;
2140 ufeImgEnsure(staddr
);
2141 const size_t slen
= strlen(s
);
2142 if (slen
> 1024*1024) ufeFatal("temp string too long");
2143 uint32_t addr
= staddr
;
2144 ufeImgPutU32(addr
++, (uint32_t)slen
);
2145 for (size_t f
= 0; f
< slen
; ++f
) {
2146 ufeImgPutU32(addr
++, (uint8_t)(s
[0]&0xffU
));
2153 static UForthWord
*ufeRegisterWord (const char *wname
, void (*cfa
) (UForthWord
*self
), int imm
) {
2154 if (!wname
) wname
= "";
2155 if (strlen(wname
) > 127) ufeFatal("too long UFE builtin word name '%s'", wname
);
2156 UForthWord
*fw
= ufeFindWord(wname
);
2157 if (fw
) ufeFatal("cannot redefine builtin UFE word '%s'", wname
);
2158 fw
= calloc(1, sizeof(UForthWord
));
2159 fw
->name
= strdup(wname
);
2160 for (char *s
= fw
->name
; *s
; ++s
) *s
= toUpper(*s
);
2162 fw
->prev
= ufeForthDict
;
2163 fw
->cfaidx
= ufeCFAsUsed
;
2164 fw
->immediate
= imm
;
2165 fw
->pfa
= 0xffffffffu
; //ufeImageUsed;
2167 if (ufeCFAsUsed
>= UFE_MAX_WORDS
) ufeFatal("too many UFE words");
2168 ufeForthCFAs
[ufeCFAsUsed
++] = fw
;
2169 //fprintf(stderr, "***NEW WORD #%u: <%s> at 0x%08x\n", ufeCFAsUsed-1u, ufeForthCFAs[ufeCFAsUsed-1u]->name, fw->pfa);
2174 static UForthWord
*ufeCreateNamelessForthWord (void) {
2175 UForthWord
*fw
= calloc(1, sizeof(UForthWord
));
2176 fw
->name
= strdup("\x01 - - - \x01");
2177 fw
->cfa
= &ufeDoForth
;
2178 fw
->cfaidx
= ufeCFAsUsed
;
2180 fw
->pfa
= 0xffffffffu
; //ufeImageUsed;
2181 //HACK: link it to the very bottom of the list
2182 UForthWord
*ww
= ufeForthDict
;
2187 while (ww
->prev
) ww
= ww
->prev
;
2191 if (ufeCFAsUsed
>= UFE_MAX_WORDS
) ufeFatal("too many UFE words");
2192 ufeForthCFAs
[ufeCFAsUsed
++] = fw
;
2197 static UForthWord
*doNativeCreate (void) {
2198 ufePush(32); UFCALL(WORD
);
2200 uint32_t len
= ufePop();
2201 uint32_t addr
= ufePop();
2202 if (len
< 1 || len
> 31) ufeFatal("UFE new word name is too long");
2204 for (uint32_t n
= 0; n
< len
; ++n
) wname
[n
] = ufeImgGetU8(addr
+n
);
2206 if (ufeFindWord(wname
)) {
2207 printf("'%s' redefined\n", wname
);
2208 ufeLastEmitWasCR
= 1;
2210 UForthWord
*fw
= ufeRegisterWord(wname
, NULL
, 0);
2211 fw
->pfa
= ufeImageUsed
;
2215 static void doNativeColon (void) {
2216 UForthWord
*fw
= doNativeCreate();
2217 fw
->cfa
= NULL
; // for now
2218 ufeSetState(1); // compiling
2219 //fprintf(stderr, "compiling native <%s>\n", wname);
2220 // always remember old mode
2222 ufePush(0xdeadbeefU
); // just a flag
2223 ufeMode
= UFE_MODE_NATIVE
;
2226 static void doZXColon (void) {
2227 const char *wname
= ufeZXWORD(' ');
2228 if (!wname
) ufeFatal("forth word name expected");
2229 //fprintf(stderr, "NFA OF <%s> = #%04X\n", wname, disp);
2230 /*ForthWord *nw =*/ forthWordHead(wname
, 0, FWT_FORTH
);
2232 forthEmitCallToLabel("_doforth");
2233 //fprintf(stderr, "compiling ZX <%s>\n", wname);
2234 ufeSetState(1); // compiling
2235 // always remember old mode
2237 ufePush(0xdeadbeefU
); // just a flag
2238 ufeMode
= UFE_MODE_ZX
;
2242 // either native, or ZX, depending of the current mode
2244 if (ufeGetState()) ufeFatal("already compiling");
2245 if (ufeMode
== UFE_MODE_ZX
) doZXColon(); else doNativeColon();
2250 if (ufeGetState()) ufeFatal("already compiling");
2251 doZXColon(); // this forces ZX mode
2255 static __attribute__((unused
)) void ufeDecompileForth (UForthWord
*fw
) {
2257 fprintf(stderr
, "====: %s\n", fw
->name
);
2258 uint32_t addr
= fw
->pfa
;
2259 while (addr
< ufeImageUsed
) {
2260 uint32_t cfaidx
= ufeImgGetU32(addr
);
2261 if (cfaidx
>= ufeCFAsUsed
) abort();
2262 UForthWord
*fw
= ufeForthCFAs
[cfaidx
];
2263 fprintf(stderr
, "%8u: %s", addr
, fw
->name
);
2265 if (strcasecmp(fw
->name
, "BRANCH") == 0 ||
2266 strcasecmp(fw
->name
, "0BRANCH") == 0 ||
2267 strcasecmp(fw
->name
, "TBRANCH") == 0 ||
2268 strcasecmp(fw
->name
, "(LOOP)") == 0 ||
2269 strcasecmp(fw
->name
, "(+LOOP)") == 0)
2271 uint32_t jaddr
= ufeImgGetU32(addr
++);
2272 fprintf(stderr
, " %u", jaddr
);
2273 } else if (strcasecmp(fw
->name
, "LIT") == 0) {
2274 uint32_t n
= ufeImgGetU32(addr
++);
2275 fprintf(stderr
, " %u", n
);
2276 } else if (strcasecmp(fw
->name
, "(\")") == 0 || strcasecmp(fw
->name
, "(.\")") == 0) {
2277 uint32_t count
= ufeImgGetU32(addr
++);
2278 fprintf(stderr
, " cnt=%u; ~", count
);
2280 uint8_t ch
= ufeImgGetU32(addr
++)&0xffU
;
2281 if (ch
== '\r') fprintf(stderr
, "\\r");
2282 else if (ch
== '\n') fprintf(stderr
, "\\n");
2283 else if (ch
== '\t') fprintf(stderr
, "\\t");
2284 else if (ch
== '\\') fprintf(stderr
, "\\\\");
2285 else if (ch
== '"') fprintf(stderr
, "\\`");
2286 else if (ch
< 32 || ch
== 127) fprintf(stderr
, "\\x%02x", ch
);
2287 else fprintf(stderr
, "%c", (char)ch
);
2289 fprintf(stderr
, "~");
2291 fprintf(stderr
, "\n");
2293 fprintf(stderr
, "----\n");
2299 if (!ufeGetState()) ufeFatal("not compiling");
2300 ufeLastDefinedZXWord
= NULL
;
2301 ufeLastDefinedNativeWord
= NULL
;
2304 if (ufePop() != 0xdeadbeefU
) ufeFatal("UFE finishing word primary magic imbalance!");
2305 // compile finishing word
2306 if (ufeMode
== UFE_MODE_ZX
) {
2307 ufeCompileZXWord(";S");
2308 ufeLastDefinedZXWord
= forthWordListTail
;
2310 if (!ufeForthDict
|| ufeForthDict
->cfa
) ufeFatal("UFE ';' without ':'");
2311 if (ufeForthDict
->pfa
== 0xffffffffU
) abort();
2312 ufeForthDict
->cfa
= &ufeDoForth
;
2313 ufeCompileNativeWord("EXIT");
2314 //ufeDecompileForth(ufeForthDict);
2315 ufeLastDefinedNativeWord
= ufeForthDict
;
2317 ufeSetState(0); // interpreting
2320 if (ufeMode
!= UFE_MODE_NATIVE
&& ufeMode
!= UFE_MODE_ZX
) ufeFatal("UFE finishing word primary mode imbalance!");
2321 // stack must be empty
2322 //if (ufeSP) ufeFatal("UFE finishing word primary imbalance!");
2323 // call optimiser if there is any
2324 UForthWord
*ofw
= ufeFindWord(ufeLastDefinedZXWord
? "OPTIMISE-ZX-WORD" : "OPTIMISE-NATIVE-WORD");
2325 if (ofw
&& ofw
!= ufeLastDefinedNativeWord
) {
2326 //if (ufeMode == UFE_MODE_ZX) fprintf(stderr, "**********000: #%04X\n", disp);
2327 uint32_t nnbuf
= ufeImageUsed
+8192;
2328 const char *wname
= (ufeLastDefinedZXWord
? ufeLastDefinedZXWord
->name
: ufeLastDefinedNativeWord
->name
);
2329 size_t slen
= strlen(wname
);
2330 ufeImgEnsure(nnbuf
+(uint32_t)slen
+2);
2331 ufeImgPutU32(nnbuf
, (uint32_t)slen
); // counter
2332 for (size_t n
= 0; n
< slen
; ++n
) ufeImgPutU8(nnbuf
+(uint32_t)n
+1u, (uint8_t)(wname
[n
]&0xffU
));
2333 ufeImgPutU8(nnbuf
+(uint32_t)slen
+1u, 0u);
2335 ufePush((uint32_t)slen
);
2336 ufePush(ufeLastDefinedZXWord
? (ufeLastDefinedZXWord
->cfa
+3u)|UFE_ZX_ADDR_BIT
: ufeLastDefinedNativeWord
->pfa
);
2337 ufePush(ofw
->cfaidx
);
2338 //if (ufeMode == UFE_MODE_ZX) fprintf(stderr, "**********001: #%04X\n", disp);
2339 // temporarily switch to native mode
2340 const uint32_t oldmode
= ufeMode
;
2341 ufeMode
= UFE_MODE_NATIVE
;
2345 // stack must be empty
2346 //if (ufeSP) ufeFatal("UFE finishing word primary imbalance!");
2351 if (ufeLastDefinedZXWord
) {
2352 // toggle IMM bit (bit 6)
2353 uint8_t b
= getByte(ufeLastDefinedZXWord
->nfa
);
2355 putByte(ufeLastDefinedZXWord
->nfa
, b
);
2356 } else if (ufeLastDefinedNativeWord
) {
2357 ufeForthDict
->immediate
= !ufeForthDict
->immediate
;
2359 ufeFatal("UFE: wtf in `IMMEDIATE`");
2363 UFWORD(RECURSE_IMM
) {
2365 //if (!ufeGetState()) ufeFatal("not compiling");
2366 if (ufeMode
== UFE_MODE_ZX
) {
2367 ufeZXEmitU16(forthWordListTail
->cfa
);
2369 ufeImgEmitU32(ufeForthDict
->cfaidx
);
2374 // ////////////////////////////////////////////////////////////////////////// //
2377 // (CODEBLOCK) ( -- )
2379 // current IP is "jump over" destination
2380 // next IP is cfaidx
2381 ufePush(ufeImgGetU32(ufeIP
+1u)); // push cfa
2382 ufeIP
= ufeImgGetU32(ufeIP
); // branch over the code block
2385 // [[ -- start code block
2386 UFWORD(CODEBLOCK_START_IMM
) {
2388 if (ufeMode
== UFE_MODE_ZX
) {
2389 ufeCompileZXWord("(CODEBLOCK)");
2391 emitWord(0); // jump destination
2392 // emit forth word cfa
2393 UrLabelInfo
*lbl
= findLabel("_doforth");
2394 if (!lbl
) ufeFatal("'_doforth' label not found");
2395 emitWord(lbl
->value
); // cfa
2397 UForthWord
*fw
= ufeAlwaysWord("(CODEBLOCK)");
2398 ufeImgEmitU32(fw
->cfaidx
);
2399 UFCALL(NATIVE_HERE
);
2400 ufeImgEmitU32(0); // jump over
2401 // create nameless word
2402 fw
= ufeCreateNamelessForthWord();
2403 ufeImgEmitU32(fw
->cfaidx
); // cfaidx
2404 fw
->pfa
= ufeImageUsed
;
2409 // ]] -- end code block
2410 UFWORD(CODEBLOCK_END_IMM
) {
2414 ufeCompileWord("EXIT"); // finish code block
2419 // ////////////////////////////////////////////////////////////////////////// //
2424 ufeMode
= UFE_MODE_ZX
;
2428 UFWORD(NATIVE_MODE
) {
2429 ufeMode
= UFE_MODE_NATIVE
;
2439 const uint32_t m
= ufePop();
2440 if (m
!= UFE_MODE_NATIVE
&& m
!= UFE_MODE_ZX
) ufeFatal("invalid ufe mode %u", m
);
2445 UFWORD(ZX_START_WORD
) {
2446 const char *wname
= ufeZXWORD(' ');
2447 if (!wname
) ufeFatal("forth word name expected");
2448 ForthWord
*fw
= findForthWord(wname
);
2449 if (!fw
) ufeFatal("zx forth word '%s' not found", wname
);
2450 UrLabelInfo
*lb
= urFindLabel("DSFORTH_START_WORD_CFA");
2451 if (!lb
) ufeFatal("label 'DSFORTH_START_WORD_CFA' not found");
2452 lb
->value
= fw
->cfa
;
2453 lb
= urFindLabel("dsforth_start_word_cfa_addr_plus_2");
2454 if (!lb
) ufeFatal("label 'dsforth_start_word_cfa_addr_plus_2' not found");
2455 if (lb
->known
) putWord(lb
->value
-2, fw
->cfa
);
2456 //fprintf(stderr, "************ #%04X\n", fw->cfa);
2461 // ////////////////////////////////////////////////////////////////////////// //
2464 const char *wname
= ufeZXWORD(' ');
2465 if (!wname
) ufeFatal("forth word name expected");
2466 /*ForthWord *nw =*/ forthWordHead(wname
, 0, FWT_VALUE
);
2468 forthEmitCallToLabel("_doconst");
2470 ufeZXEmitU16(ufePop()&0xffffU
);
2474 UFWORD(ZX_VAR_NOALLOT
) {
2475 const char *wname
= ufeZXWORD(' ');
2476 if (!wname
) ufeFatal("forth word name expected");
2477 /*ForthWord *nw =*/ forthWordHead(wname
, 0, FWT_VAR
);
2479 forthEmitCallToLabel("_dovar");
2480 // no variable value yet
2484 UFWORD(ZX_VARIABLE
) {
2485 UFCALL(ZX_VAR_NOALLOT
);
2487 ufeZXEmitU16(ufePop()&0xffffU
);
2491 UFWORD(ZX_CONSTANT
) {
2492 const char *wname
= ufeZXWORD(' ');
2493 if (!wname
) ufeFatal("forth word name expected");
2494 /*ForthWord *nw =*/ forthWordHead(wname
, 0, FWT_CONST
);
2496 forthEmitCallToLabel("_doconst");
2498 ufeZXEmitU16(ufePop()&0xffffU
);
2503 const char *wname
= ufeZXWORD(' ');
2504 if (!wname
) ufeFatal("forth word name expected");
2505 /*ForthWord *nw =*/ forthWordHead(wname
, 0, FWT_DEFER
);
2507 forthEmitCallToLabel("_dodefer");
2509 ufeZXEmitU16(ufePop()&0xffffU
);
2513 UFWORD(ZX_DP_PEEK
) {
2514 ufePush(disp
|UFE_ZX_ADDR_BIT
);
2518 UFWORD(ZX_DP_POKE
) {
2519 uint32_t ndp
= ufePop();
2520 if ((ndp
&UFE_ZX_ADDR_BIT
) == 0) ufeFatal("invalid new zx DP");
2521 disp
= ndp
&UFE_ZX_ADDR_MASK
;
2526 int32_t sz
= (int32_t)ufePop();
2527 if (sz
== 0) return;
2529 if (sz
< -65535) ufeFatal("cannot allot %d bytes", sz
);
2531 if (disp
< sz
) ufeFatal("cannot unallot %d bytes", sz
);
2535 if (sz
> 65535) ufeFatal("cannot allot %d bytes", sz
);
2536 if (disp
+sz
> 65535) ufeFatal("cannot allot %d bytes", sz
);
2537 // fill unused bytes with zeroes to avoid holes
2539 if (!memused
[disp
]) {
2546 if (zxlblLastByte
) zxlblLastByte
->value
= disp
;
2551 ufePush(disp
|UFE_ZX_ADDR_BIT
);
2555 // WARNING! keep in sync with dsForth!
2557 ufePush((disp
+68)|UFE_ZX_ADDR_BIT
);
2562 char *fnx
= ufePopStrLit();
2563 const char *wname
= ufeZXWORD(' ');
2564 if (!wname
) ufeFatal("forth word name expected");
2565 //fprintf(stderr, "<%s>\n", wname);
2566 /*ForthWord *nw =*/ forthWordHead(wname
, 0, FWT_VAR
);
2568 forthEmitCallToLabel("_dovar");
2572 int softinclude
= 0;
2573 if (fn
[0] == '?') { softinclude
= 1; ++fn
; while (isSpace(*fn
)) ++fn
; }
2574 if (!fn
[0]) ufeFatal("ZX-VARBIN: empty file name");
2576 char *fname
= createIncludeName(fn
, system
, NULL
);
2578 FILE *fl
= fopen(fname
, "rb");
2580 if (!softinclude
) ufeFatal("ZX-VARBIN: file not found: '%s'", fname
);
2584 int res
= fread(&bt
, 1, 1, fl
);
2586 if (res
!= 1) { fclose(fl
); ufeFatal("ZX-VARBIN: error reading file: '%s'", fname
); }
2596 const char *wname
= ufeZXWORD(' ');
2597 ForthWord
*fwdr
= findForthWord(wname
);
2598 if (!fwdr
) ufeFatal("forth word `%s` not found", wname
);
2599 if (fwdr
->wtype
!= FWT_DEFER
&& fwdr
->wtype
!= FWT_VALUE
) ufeFatal("forth word `%s` is not VALUE/DEFER", wname
);
2600 if (ufeGetState()) {
2603 ufeCompileZXWord("LITTO!");
2605 ufeZXEmitU16(fwdr
->cfa
+3u);
2608 putWord(fwdr
->cfa
+3u, ufePop()&0xffffU
);
2614 char *wname
= ufePopStrLit();
2615 ForthWord
*fwdr
= findForthWord(wname
);
2616 if (!fwdr
) ufeFatal("forth word `%s` not found", wname
);
2617 if (fwdr
->wtype
!= FWT_DEFER
&& fwdr
->wtype
!= FWT_VALUE
) ufeFatal("forth word `%s` is not VALUE/DEFER", wname
);
2619 if (ufeGetState()) {
2622 ufeCompileZXWord("LITTO!");
2624 ufeZXEmitU16(fwdr
->cfa
+3u);
2627 putWord(fwdr
->cfa
+3u, ufePop()&0xffffU
);
2632 UFWORD(ZX_TICKCFA_IMM
) {
2633 const char *wname
= ufeZXWORD(' ');
2634 ForthWord
*fwdr
= findForthWord(wname
);
2635 if (!fwdr
) ufeFatal("forth word `%s` not found", wname
);
2636 ufePush(fwdr
->cfa
|UFE_ZX_ADDR_BIT
);
2637 if (ufeGetState()) {
2639 ufeCompileWord(",");
2644 UFWORD(ZX_TICKPFA_IMM
) {
2645 const char *wname
= ufeZXWORD(' ');
2646 ForthWord
*fwdr
= findForthWord(wname
);
2647 if (!fwdr
) ufeFatal("forth word `%s` not found", wname
);
2648 ufePush((fwdr
->cfa
+3u)|UFE_ZX_ADDR_BIT
);
2649 if (ufeGetState()) {
2651 ufeCompileWord(",");
2656 // ////////////////////////////////////////////////////////////////////////// //
2657 static void ufeXBasedLiteral (int base
) {
2658 const char *num
= ufeZXWORD(' ');
2660 for (const char *s
= num
; *s
; ++s
) {
2661 if (*s
== '_') continue;
2662 const int dig
= digitInBase(*s
, base
);
2663 if (dig
< 0) ufeFatal("invalid hex number '%s'", num
);
2664 n
= n
*16u+(unsigned)dig
;
2671 UFWORD(ZEROX_IMM
) { ufeXBasedLiteral(16); }
2672 UFWORD(ZEROO_IMM
) { ufeXBasedLiteral(8); }
2673 UFWORD(ZEROB_IMM
) { ufeXBasedLiteral(2); }
2674 UFWORD(ZEROD_IMM
) { ufeXBasedLiteral(10); }
2677 // ////////////////////////////////////////////////////////////////////////// //
2678 static void ufeDoVariable (UForthWord
*self
) { ufePush(self
->pfa
); }
2679 static void ufeDoValue (UForthWord
*self
) { ufePush(ufeImgGetU32(self
->pfa
)); }
2680 static void ufeDoConst (UForthWord
*self
) { ufePush(ufeImgGetU32(self
->pfa
)); }
2681 static void ufeDoDefer (UForthWord
*self
) {
2682 const uint32_t cfaidx
= ufeImgGetU32(self
->pfa
);
2683 if (cfaidx
>= ufeCFAsUsed
) ufeFatal("defered word '%s' contains invalid address", self
->name
);
2689 UFWORD(NATIVE_VALUE
) {
2690 UForthWord
*fvar
= doNativeCreate();
2691 fvar
->cfa
= &ufeDoValue
;
2693 ufeImgEmitU32(ufePop());
2696 // NATIVE-VAR-NOALLOT
2697 UFWORD(NATIVE_VAR_NOALLOT
) {
2698 UForthWord
*fvar
= doNativeCreate();
2699 fvar
->cfa
= &ufeDoVariable
;
2700 // no variable value yet
2704 UFWORD(NATIVE_VARIABLE
) {
2705 UFCALL(NATIVE_VAR_NOALLOT
);
2707 ufeImgEmitU32(ufePop());
2711 UFWORD(NATIVE_CONSTANT
) {
2712 UForthWord
*fvar
= doNativeCreate();
2713 fvar
->cfa
= &ufeDoConst
;
2715 ufeImgEmitU32(ufePop());
2719 UFWORD(NATIVE_DEFER
) {
2720 UForthWord
*fvar
= doNativeCreate();
2721 fvar
->cfa
= &ufeDoDefer
;
2723 ufeImgEmitU32(ufePop());
2727 UFWORD(NATIVE_ALLOT
) {
2728 int32_t sz
= (int32_t)ufePop();
2729 if (sz
== 0) return;
2731 if (sz
< -1024*1024*64) ufeFatal("cannot allot %d bytes", sz
);
2733 // arbitrary safeguard
2734 if (ufeImageUsed
< sz
|| ufeImageUsed
-sz
< 1024) ufeFatal("cannot unallot %d bytes", sz
);
2737 if (sz
> 1024*1024*64) ufeFatal("cannot allot %d bytes", sz
);
2738 ufeImgEnsure(ufeImageUsed
+sz
);
2743 UFWORD(NATIVE_DP_PEEK
) {
2744 ufePush(ufeImageUsed
);
2748 UFWORD(NATIVE_DP_POKE
) {
2749 uint32_t ndp
= ufePop();
2750 if (ndp
>= ufeImageSize
) ufeFatal("invalid new native DP");
2755 UFWORD(NATIVE_VARBIN
) {
2756 char *fnx
= ufePopStrLit();
2757 UForthWord
*fvar
= doNativeCreate();
2758 fvar
->cfa
= &ufeDoVariable
;
2762 int softinclude
= 0;
2763 if (fn
[0] == '?') { softinclude
= 1; ++fn
; while (isSpace(*fn
)) ++fn
; }
2764 if (!fn
[0]) ufeFatal("VARBIN: empty file name");
2766 char *fname
= createIncludeName(fn
, system
, NULL
);
2768 FILE *fl
= fopen(fname
, "rb");
2770 if (!softinclude
) ufeFatal("VARBIN: file not found: '%s'", fname
);
2774 int res
= fread(&bt
, 1, 1, fl
);
2776 if (res
!= 1) { fclose(fl
); ufeFatal("VARBIN: error reading file: '%s'", fname
); }
2784 static UForthWord
*ufeNTWordAddrCount (void) {
2785 uint32_t count
= ufePop();
2786 uint32_t addr
= ufePop();
2787 UForthWord
*fw
= ufeNFind(addr
, count
);
2789 UFCALL(SPACE
); ufePush(addr
); ufePush(count
); UFCALL(XTYPE
);
2791 ufeFatal("unknown UFE word");
2796 static UForthWord
*ufeNTWord (void) {
2797 ufePush(32); UFCALL(WORD
);
2799 return ufeNTWordAddrCount();
2803 UFWORD(NATIVE_TO_IMM
) {
2804 UForthWord
*fw
= ufeNTWord();
2805 if (fw
->cfa
!= &ufeDoValue
&& fw
->cfa
!= &ufeDoDefer
) ufeFatal("UFE word `%s` is not VALUE/DEFER", fw
->name
);
2806 if (ufeGetState()) {
2809 ufeCompileNativeLiteral(fw
->pfa
);
2810 ufeCompileNativeWord("!");
2813 ufeImgPutU32(fw
->pfa
, ufePop());
2818 // ( value addr count -- )
2819 UFWORD(NATIVE_STRTO
) {
2820 UForthWord
*fw
= ufeNTWordAddrCount();
2821 if (fw
->cfa
!= &ufeDoValue
&& fw
->cfa
!= &ufeDoDefer
) ufeFatal("UFE word `%s` is not VALUE/DEFER", fw
->name
);
2822 if (ufeGetState()) {
2825 ufeCompileNativeLiteral(fw
->pfa
);
2826 ufeCompileNativeWord("!");
2829 ufeImgPutU32(fw
->pfa
, ufePop());
2834 UFWORD(NATIVE_TICKCFA_IMM
) {
2835 ufePush(32); UFCALL(WORD
);
2838 UFCALL(NFIND
); // ( cfa 1 ) | ( 0 )
2840 uint32_t cfa
= ufePop();
2842 if ((cfa
&UFE_ZX_ADDR_BIT
) != 0) ufeFatal("cannot ' ZX word");
2843 if (ufeGetState()) {
2844 ufeCompileNativeLiteral(cfa
);
2845 ufeCompileNativeWord(",");
2850 UFCALL(NATIVE_HERE
); UFCALL(COUNT
); UFCALL(SPACE
); UFCALL(XTYPE
);
2851 printf("?"); UFCALL(CR
);
2852 ufeFatal("UFE: unknown word");
2857 UFWORD(NATIVE_TICKPFA_IMM
) {
2858 ufePush(32); UFCALL(WORD
);
2861 UFCALL(NFIND
); // ( cfa 1 ) | ( 0 )
2863 uint32_t cfa
= ufePop();
2865 if ((cfa
&UFE_ZX_ADDR_BIT
) != 0) ufeFatal("cannot ' ZX word");
2866 ufePush(ufeNFindNativeWordResult
->pfa
);
2867 if (ufeGetState()) {
2868 ufeCompileNativeLiteral(ufeNFindNativeWordResult
->pfa
);
2869 ufeCompileNativeWord(",");
2871 ufePush(ufeNFindNativeWordResult
->pfa
);
2874 UFCALL(NATIVE_HERE
); UFCALL(COUNT
); UFCALL(SPACE
); UFCALL(XTYPE
);
2875 printf("?"); UFCALL(CR
);
2876 ufeFatal("UFE: unknown word");
2881 // ////////////////////////////////////////////////////////////////////////// //
2882 #define UFWORD_2MODES(wname_) \
2884 if (ufeGetState()) { \
2886 /*FIXME: check for ZX turnkey! */ \
2887 if (ufeMode == UFE_MODE_ZX) ufeCompileZXWord(""#wname_); else ufeCompileNativeWord("NATIVE-"#wname_); \
2889 if (ufeMode == UFE_MODE_ZX) UFCALL(ZX_##wname_); else UFCALL(NATIVE_##wname_); \
2893 #define UFWORD_2MODES_X(wname_,fwname_) \
2895 if (ufeGetState()) { \
2897 /*FIXME: check for ZX turnkey! */ \
2898 if (ufeMode == UFE_MODE_ZX) ufeCompileZXWord(""#fwname_); else ufeCompileNativeWord("NATIVE-"#fwname_); \
2900 if (ufeMode == UFE_MODE_ZX) UFCALL(ZX_##wname_); else UFCALL(NATIVE_##wname_); \
2904 #define UFWORD_2MODES_IMM(wname_) \
2906 if (ufeMode == UFE_MODE_ZX) UFCALL(ZX_##wname_); else UFCALL(NATIVE_##wname_); \
2910 UFWORD_2MODES(VALUE
)
2912 UFWORD_2MODES(VARIABLE
)
2914 UFWORD_2MODES(VAR_NOALLOT
)
2916 UFWORD_2MODES(CONSTANT
)
2918 UFWORD_2MODES(DEFER
)
2920 UFWORD_2MODES(ALLOT
)
2926 UFWORD_2MODES_X(DP_PEEK
, DP@
)
2928 UFWORD_2MODES_X(DP_POKE
, DP
!)
2930 UFWORD_2MODES_IMM(TO_IMM
)
2932 UFWORD_2MODES(STRTO
)
2934 UFWORD_2MODES_IMM(TICKCFA_IMM
)
2936 UFWORD_2MODES_IMM(TICKPFA_IMM
)
2940 if (ufeGetState()) {
2942 //FIXME: check for ZX turnkey!
2943 if (ufeMode
== UFE_MODE_ZX
) ufeFatal("dsForth has no `VARBIN`");
2944 ufeCompileNativeWord("NATIVE-VARBIN");
2946 if (ufeMode
== UFE_MODE_ZX
) UFCALL(ZX_VARBIN
); else UFCALL(NATIVE_VARBIN
);
2952 UFWORD(LSQBRACKET_IMM
) {
2957 UFWORD(RSQBRACKET
) {
2962 // ////////////////////////////////////////////////////////////////////////// //
2966 // ( addr count -- flag )
2967 UFWORD(UR_HAS_LABELQ
) {
2968 char *name
= ufePopStrLit();
2969 ufePush(urFindLabel(name
) ? 1u : 0u);
2974 // ( addr count -- value )
2975 // fatals when the label is not found
2976 UFWORD(UR_GET_LABELQ
) {
2977 char *name
= ufePopStrLit();
2978 UrLabelInfo
*lbl
= urFindLabel(name
);
2979 if (!lbl
) ufeFatal("label '%s' not found", name
);
2981 int32_t v
= lbl
->value
;
2982 ufePush((uint32_t)v
);
2987 // EXECUTEs cfa, returns final res
2988 // cfa: ( addr count -- stopflag )
2989 // i.e. return non-zero from cfa to stop
2990 // res is the result of the last called cfa
2991 UFWORD(UR_FOREACH_LABEL
) {
2992 uint32_t cfaidx
= ufePop();
2994 for (UrLabelInfo
*c
= labels
; c
; c
= c
->next
) {
2995 uint32_t addr
= ufePutTempStrLiteral(c
->name
, UFE_PAD1_OFFSET
);
2996 uint32_t count
= ufeImgGetU32(addr
++);
3015 UFWORD(UR_AFTER_TRACEQ
) {
3016 ufePush(ufeAfterTrace
);
3020 // ( addr count -- cfa 1 // 0 )
3021 UFWORD(UR_ZX_FIND_WORD
) {
3022 char *name
= ufePopStrLit();
3023 for (char *s
= name
; *s
; ++s
) *s
= toUpper(*s
);
3024 ForthWord
*fw
= findForthWord(name
);
3027 ufePush(fw
->cfa
|UFE_ZX_ADDR_BIT
);
3034 // UR-ZX-WORD-NAME-BY-CFA
3035 // ( cfa -- addr count 1 // 0 )
3036 UFWORD(UR_ZX_WORD_NAME_BY_CFA
) {
3037 uint32_t cfa
= ufePop();
3038 // accept non-zx address too
3039 //if ((cfa&UFE_ZX_ADDR_BIT) == 0) { ufePush(0); return; }
3040 cfa
&= UFE_ZX_ADDR_MASK
;
3041 for (ForthWord
*w
= forthWordList
; w
; w
= w
->next
) {
3042 if (w
->cfa
== cfa
) {
3043 uint32_t addr
= ufePutTempStrLiteral((w
->name
[0] ? w
->name
: "~"), UFE_PAD1_OFFSET
);
3045 ufePush(ufeImgGetU32(addr
));
3053 // UR-ZX-WORD-USED-BY-CFA?
3055 UFWORD(UR_ZX_WORD_USED_BY_CFAQ
) {
3056 uint32_t cfa
= ufePop();
3057 // accept non-zx address too
3058 //if ((cfa&UFE_ZX_ADDR_BIT) == 0) { ufePush(0); return; }
3059 cfa
&= UFE_ZX_ADDR_MASK
;
3060 for (ForthWord
*w
= forthWordList
; w
; w
= w
->next
) {
3061 if (w
->cfa
== cfa
) {
3062 ufePush(w
->usedmark
? 1u : 0u);
3069 // UR-ZX-WORD-USED-BY-CFA-1!
3071 UFWORD(UR_ZX_WORD_USED_BY_CFA_1POKE
) {
3072 uint32_t cfa
= ufePop();
3073 // accept non-zx address too
3074 //if ((cfa&UFE_ZX_ADDR_BIT) == 0) { ufePush(0); return; }
3075 cfa
&= UFE_ZX_ADDR_MASK
;
3076 for (ForthWord
*w
= forthWordList
; w
; w
= w
->next
) {
3077 if (w
->cfa
== cfa
) {
3084 // UR-ZX-WORD-FLAGS-BY-CFA
3092 // bit 6: unconditional branch
3094 // bit 8: (codeblock)
3095 UFWORD(UR_ZX_WORD_FLAGS_BY_CFA
) {
3096 uint32_t cfa
= ufePop();
3097 // accept non-zx address too
3098 //if ((cfa&UFE_ZX_ADDR_BIT) == 0) { ufePush(0); return; }
3099 cfa
&= UFE_ZX_ADDR_MASK
;
3100 for (ForthWord
*w
= forthWordList
; w
; w
= w
->next
) {
3101 if (w
->cfa
== cfa
) {
3102 uint32_t flags
= 0u;
3103 if (w
->isbranch
) flags
|= (1u<<0);
3104 if (w
->isnumlit
) flags
|= (1u<<1);
3105 if (w
->isstrlit
) flags
|= (1u<<2);
3106 if (w
->isnoreturn
) flags
|= (1u<<3);
3107 if (w
->isnoturnkey
) flags
|= (1u<<4);
3108 if (w
->immediate
) flags
|= (1u<<5);
3109 if (w
->isuncondbranch
) flags
|= (1u<<6);
3110 if (w
->usedmark
) flags
|= (1u<<7);
3111 if (w
->codeblock
) flags
|= (1u<<8);
3112 //if (flags) fprintf(stderr, " <%s>: #%02X; %d;%d;%d;%d;%d;%d;%d\n", w->name, flags, w->isbranch, w->isnumlit, w->isstrlit, w->isnoreturn, w->isnoturnkey, w->immediate, w->isuncondbranch);
3120 // UR-ZX-LAST-FORTH-WORD-NAME
3121 // ( -- addr count )
3122 UFWORD(UR_ZX_LAST_FORTH_WORD_NAME
) {
3123 ForthWord
*w
= forthWordListTail
;
3124 uint32_t addr
= ufePutTempStrLiteral((w
? (w
->name
[0] ? w
->name
: "~") : ""), UFE_PAD1_OFFSET
);
3126 ufePush(ufeImgGetU32(addr
));
3129 // UR-ZX-LAST-FORTH-WORD-CFA
3130 UFWORD(UR_ZX_LAST_FORTH_WORD_CFA
) {
3131 ForthWord
*w
= forthWordListTail
;
3132 uint32_t addr
= (w
? w
->cfa
|UFE_ZX_ADDR_BIT
: 0);
3136 // UR-ZX-WORD-TYPE-BY-CFA
3138 UFWORD(UR_ZX_WORD_TYPE_BY_CFA
) {
3139 uint32_t cfa
= ufePop();
3140 // accept non-zx address too
3141 //if ((cfa&UFE_ZX_ADDR_BIT) == 0) { ufePush(0); return; }
3142 cfa
&= UFE_ZX_ADDR_MASK
;
3143 for (ForthWord
*w
= forthWordList
; w
; w
= w
->next
) {
3144 if (w
->cfa
== cfa
) {
3149 ufePush(FWT_OTHER
); //TODO: return -1?
3153 // ////////////////////////////////////////////////////////////////////////// //
3154 // conditional compilation
3155 typedef struct UForthCondDefine_t UForthCondDefine
;
3156 struct UForthCondDefine_t
{
3159 UForthCondDefine
*prev
;
3162 static UForthCondDefine
*ufeCondDefines
= NULL
;
3165 static UForthCondDefine
*ufeFindCondDefine (const char *name
) {
3166 if (!name
|| !name
[0]) return NULL
;
3167 for (UForthCondDefine
*dd
= ufeCondDefines
; dd
; dd
= dd
->prev
) {
3168 if (strcmp(dd
->name
, name
) == 0) return dd
;
3174 static void ufeAddCondDefine (const char *name
, uint32_t value
) {
3175 if (!name
|| !name
[0]) return;
3176 for (UForthCondDefine
*dd
= ufeCondDefines
; dd
; dd
= dd
->prev
) {
3177 if (strcmp(dd
->name
, name
) == 0) {
3182 UForthCondDefine
*dd
= malloc(sizeof(UForthCondDefine
));
3183 dd
->name
= strdup(name
);
3185 dd
->prev
= ufeCondDefines
;
3186 ufeCondDefines
= dd
;
3190 static void ufeRemoveCondDefine (const char *name
) {
3191 if (!name
|| !name
[0]) return;
3192 UForthCondDefine
*pp
= NULL
;
3193 for (UForthCondDefine
*dd
= ufeCondDefines
; dd
; dd
= dd
->prev
) {
3194 if (strcmp(dd
->name
, name
) == 0) {
3195 if (pp
) pp
->prev
= dd
->prev
; else ufeCondDefines
= dd
->prev
;
3206 UFE_COND_IFDEF
= 0u,
3207 UFE_COND_IFNDEF
= 1u,
3209 UFE_COND_IFNOT
= 3u,
3211 UFE_COND_IFNATIVE
= 5u,
3212 UFE_COND_NONE
= 666u,
3216 static int strStartsWithCI (const char *s
, const char *pat
) {
3217 if (!pat
[0]) return 0;
3218 while (*s
&& *pat
) {
3219 if (toUpper(*s
) != toUpper(*pat
)) return 0;
3223 return (pat
[0] == 0);
3226 static int strIsEmpty (const char *s
) {
3227 while (*s
&& isSpace(*s
)) ++s
;
3228 if (!s
[0]) return 1;
3229 // check for comments
3230 if (s
[0] == '\\' && (!s
[1] || isSpace(s
[1]))) return 1;
3231 if (s
[0] == ';' && s
[1] == ';' && (!s
[2] || isSpace(s
[2]))) return 1;
3232 if (s
[0] == '(' && isSpace(s
[1])) {
3235 while (*s
&& *s
!= ')') ++s
;
3237 return strIsEmpty(s
);
3242 static int strStartsWithWordCI (const char *s
, const char *pat
) {
3243 if (!strStartsWithCI(s
, pat
)) return 0;
3245 return (!s
[0] || isSpace(s
[0]));
3248 static void ufeCondLoadNextLine (int stline
) {
3249 const int rd
= ufeLoadNextLine();
3250 if (rd
< -1) ufeFatal("error reading UFE input buffer");
3251 if (rd
== -1) ufeFatal("unfinished conditional from line %d", stline
);
3254 static void ufeSkipConditionals (int toelse
) {
3255 const int stline
= ufeInFileLine
;
3258 ufeCondLoadNextLine(stline
);
3259 char *s
= ufeCurrFileLine
;
3260 while (*s
&& isSpace(*s
)) ++s
;
3261 if (!s
[0]) continue;
3262 //fprintf(stderr, " skipcond(toelse=%d; nest=%d); line %d: %s", toelse, iflevel, ufeInFileLine, s);
3263 // nested conditionals
3264 if (strStartsWithWordCI(s
, "$IF") ||
3265 strStartsWithWordCI(s
, "$IFNOT") ||
3266 strStartsWithWordCI(s
, "$IFDEF") ||
3267 strStartsWithWordCI(s
, "$IFNDEF"))
3272 // in nested ifs, look only for $ENDIF
3274 if (!strStartsWithWordCI(s
, "$ENDIF")) continue;
3275 if (!strIsEmpty(s
+6)) ufeFatal("invalid $ENDIF");
3281 if (strStartsWithWordCI(s
, "$ELSE")) {
3282 if (!strIsEmpty(s
+5)) ufeFatal("invalid $ELSE");
3283 // if we're skipping "true" part, go on
3285 ufeCondLoadNextLine(stline
);
3289 // we're skipping "false" part, there should be no else
3290 ufeFatal("unexpected $ELSE, skipping from line %d", stline
);
3292 if (strStartsWithWordCI(s
, "$ENDIF")) {
3293 // it doesn't matter which part we're skipping, it ends here anyway
3294 if (!strIsEmpty(s
+6)) ufeFatal("invalid $ENDIF");
3295 ufeCondLoadNextLine(stline
);
3298 // $ELIF/$ELIFNOT/$ELIFDEF/$ELIFNDEF
3299 unsigned cc
= UFE_COND_NONE
;
3300 if (strStartsWithWordCI(s
, "$ELIF")) cc
= UFE_COND_IF
;
3301 else if (strStartsWithWordCI(s
, "$ELIFNOT")) cc
=UFE_COND_IFNOT
;
3302 else if (strStartsWithWordCI(s
, "$ELIFDEF")) cc
= UFE_COND_IFDEF
;
3303 else if (strStartsWithWordCI(s
, "$ELIFNDEF")) cc
= UFE_COND_IFNDEF
;
3304 else if (strStartsWithWordCI(s
, "$ELIFZX")) cc
= UFE_COND_IFZX
;
3305 else if (strStartsWithWordCI(s
, "$ELIFNATIVE")) cc
= UFE_COND_IFNATIVE
;
3306 if (cc
== UFE_COND_NONE
) continue;
3307 // if we're skipping "true" part, go on
3308 if (toelse
) return ufeDoConditional(UFE_COND_IFNOT
, 1); // skip first word
3309 // we're skipping "false" part, there should be no else
3310 ufeFatal("unexpected $ELIFxx, skipping from line %d", stline
);
3314 static void ufeDoConditional (unsigned type
, int skipword
) {
3315 //if (ufeInCondIf) ufeFatal("conditional inside another conditional -- seems unbalanced");
3317 ufePush(32); UFCALL(WORD
);
3318 if (skipword
) { ufeDrop(); ufePush(32); UFCALL(WORD
); }
3320 char *name
= ufePopStrLit();
3321 if (type
== UFE_COND_IF
&& strcmp(name
, "0") == 0) {
3323 } else if (type
== UFE_COND_IF
&& strcmp(name
, "1") == 0) {
3326 UForthCondDefine
*def
= ufeFindCondDefine(name
);
3327 //if (def) fprintf(stderr, "FOUNDDEF: <%s>=%u\n", def->name, def->value);
3328 UrLabelInfo
*lbl
= urFindLabel(name
);
3330 case UFE_COND_IFDEF
: res
= !!lbl
|| !!def
; break;
3331 case UFE_COND_IFNDEF
: res
= !lbl
&& !def
; break;
3332 case UFE_COND_IF
: res
= (def
? !!def
->value
: lbl
? !!lbl
->value
: 0); break;
3333 case UFE_COND_IFNOT
: res
= (def
? !def
->value
: lbl
? !lbl
->value
: 0); break;
3334 case UFE_COND_IFZX
: res
= (ufeMode
== UFE_MODE_ZX
); break;
3335 case UFE_COND_IFNATIVE
: res
= (ufeMode
== UFE_MODE_NATIVE
); break;
3336 default: ufeFatal("what conditional?");
3340 //fprintf(stderr, "line %d: cond=%u; res=%u; lbl=%d (%d)\n", ufeInFileLine, type, res, (lbl ? lbl->value : 0), (lbl ? 1 : 0));
3341 if (!res
) return ufeSkipConditionals(1);
3346 UFWORD(DLR_DEFINE
) {
3347 ufePush(32); UFCALL(WORD
);
3349 char *name
= ufePopStrLit();
3350 ufeAddCondDefine(name
, 1);
3356 ufePush(32); UFCALL(WORD
);
3358 char *name
= ufePopStrLit();
3359 ufeRemoveCondDefine(name
);
3363 // these words can be encoundered only when we done with some $IF, so skip to $ENDIF
3365 UFWORD(DLR_ELSE_IMM
) { if (!ufeInCondIf
) ufeFatal("$ELSE without $IF"); ufeSkipConditionals(0); }
3367 UFWORD(DLR_ELIFDEF_IMM
) { if (!ufeInCondIf
) ufeFatal("$ELIFDEF without $IF"); --ufeInCondIf
; ufeSkipConditionals(0); }
3369 UFWORD(DLR_ELIFNDEF_IMM
) { if (!ufeInCondIf
) ufeFatal("$ELIFNDEF without $IF"); --ufeInCondIf
; ufeSkipConditionals(0); }
3371 UFWORD(DLR_ELIF_IMM
) { if (!ufeInCondIf
) ufeFatal("$ELIF without $IF"); --ufeInCondIf
; ufeSkipConditionals(0); }
3373 UFWORD(DLR_ELIFNOT_IMM
) { if (!ufeInCondIf
) ufeFatal("$ELIFNOT without $IF"); --ufeInCondIf
; ufeSkipConditionals(0); }
3375 UFWORD(DLR_ELIFZX_IMM
) { if (!ufeInCondIf
) ufeFatal("$ELIFZX without $IF"); --ufeInCondIf
; ufeSkipConditionals(0); }
3377 UFWORD(DLR_ELIFNATIVE_IMM
) { if (!ufeInCondIf
) ufeFatal("$ELIFNATIVE without $IF"); --ufeInCondIf
; ufeSkipConditionals(0); }
3379 UFWORD(DLR_ENDIF_IMM
) { if (!ufeInCondIf
) ufeFatal("$ENDIF without $IF"); --ufeInCondIf
; }
3382 UFWORD(DLR_IFDEF_IMM
) { ufeDoConditional(UFE_COND_IFDEF
, 0); }
3383 // $IFNDEF labelname
3384 UFWORD(DLR_IFNDEF_IMM
) { ufeDoConditional(UFE_COND_IFNDEF
, 0); }
3386 // undefined label is false too
3387 UFWORD(DLR_IF_IMM
) { ufeDoConditional(UFE_COND_IF
, 0); }
3389 // undefined label is true too
3390 UFWORD(DLR_IFNOT_IMM
) { ufeDoConditional(UFE_COND_IFNOT
, 0); }
3392 UFWORD(DLR_IFZX_IMM
) { ufeDoConditional(UFE_COND_IFZX
, 0); }
3394 UFWORD(DLR_IFNATIVE_IMM
) { ufeDoConditional(UFE_COND_IFNATIVE
, 0); }
3397 UFWORD(DLR_INCLUDE_IMM
) {
3400 uint8_t ch
= ufeGetInChar();
3401 if (!ch
) ufeFatal("$INCLUDE wants filename");
3402 if (ch
== '"' || ch
== '<') {
3406 if (!isSpace((char)ch
)) ufeFatal("$INCLUDE filename must be quoted");
3408 int system
= (qCh
== '<');
3412 uint8_t ch
= ufeGetInChar();
3413 if (!ch
) ufeFatal("$INCLUDE wants properly quoted filename");
3414 if ((char)ch
== qCh
) break;
3415 if (fnpos
>= sizeof(fname
)-2) ufeFatal("$INCLUDE filename too long");
3416 fname
[fnpos
++] = (char)ch
;
3420 int softinclude
= 0;
3424 while (isSpace(*fn
)) ++fn
;
3425 if (!fn
[0]) ufeFatal("$INCLUDE: softinclude what?");
3427 char *ffn
= ufeCreateIncludeName(fn
, system
);
3428 FILE *fl
= fopen(ffn
, "rb");
3430 if (softinclude
) { free(ffn
); return; }
3431 ufeFatal("$INCLUDE: file '%s' not found", ffn
);
3436 ufeInFileName
= ffn
;
3437 // trigger next line loading
3447 UFWORD(DUMP_STACK
) {
3448 printf("***UFE STACK DEPTH: %u\n", ufeSP
);
3449 for (uint32_t sp
= 0; sp
< ufeSP
; ++sp
) printf(" %4u: 0x%08x %d\n", sp
, ufeDStack
[sp
], (int32_t)ufeDStack
[sp
]);
3456 //fprintf(stderr, "***UFE STACK DEPTH: %u\n", ufeSP); for (uint32_t sp = 0; sp < ufeSP; ++sp) fprintf(stderr, " %4u: 0x%08x %d\n", sp, ufeDStack[sp], (int32_t)ufeDStack[sp]);
3457 char *str
= ufePopStrLit();
3462 // ////////////////////////////////////////////////////////////////////////// //
3466 static __attribute__((unused
)) void ufeDefine (const char *wname
) {
3467 if (ufeFindWord(wname
)) {
3468 printf("'%s' redefined\n", wname
);
3469 ufeLastEmitWasCR
= 1;
3471 UForthWord
*fw
= ufeRegisterWord(wname
, &ufeDoForth
, 0);
3472 fw
->pfa
= ufeImageUsed
;
3473 //fprintf(stderr, "***DEFINING #%u: <%s> at 0x%08x\n", ufeCFAsUsed-1u, ufeForthCFAs[ufeCFAsUsed-1u]->name, fw->pfa);
3474 ufeSetState(1); // compiling
3477 static __attribute__((unused
)) void ufeDefineDone (void) {
3478 ufeLastDefinedZXWord
= NULL
;
3479 ufeLastDefinedNativeWord
= NULL
;
3481 if (ufeSP
) ufeFatal("UFE finishing word primary imbalance!");
3482 //if (!ufeForthDict || ufeForthDict->cfa) ufeFatal("UFE ';' without ':'");
3483 if (ufeForthDict
->pfa
== 0xffffffffU
) abort();
3484 ufeForthDict
->cfa
= &ufeDoForth
;
3485 ufeCompileNativeWord("EXIT");
3486 //ufeDecompileForth(ufeForthDict);
3487 ufeLastDefinedNativeWord
= ufeForthDict
;
3488 ufeSetState(0); // interpreting
3491 static __attribute__((unused
)) void ufeNumber (uint32_t v
) {
3492 UForthWord
*fw
= ufeAlwaysWord("LIT");
3493 ufeImgEmitU32(fw
->cfaidx
);
3497 static __attribute__((unused
)) void ufeCompile (const char *wname
) {
3498 UForthWord
*fw
= ufeFindWord(wname
);
3502 long v
= strtol(wname
, &end
, 0);
3503 if (end
== wname
|| *end
) ufeFatal("UFE word '%s' not found", wname
);
3504 ufeNumber((uint32_t)v
);
3506 // compile/execute a word
3507 if (fw
->immediate
) {
3510 ufeImgEmitU32(fw
->cfaidx
);
3515 static __attribute__((unused
)) void ufeString (const char *str
) {
3516 UForthWord
*fw
= ufeAlwaysWord("(\")");
3517 ufeImgEmitU32(fw
->cfaidx
);
3519 size_t slen
= strlen(str
);
3520 if (slen
> 65535) ufeFatal("UFE string too long");
3521 ufeImgEmitU32((uint32_t)slen
);
3523 ufeImgEmitU32((uint32_t)(str
[0]&0xffU
));
3528 static __attribute__((unused
)) void ufeDotString (const char *str
) {
3529 UForthWord
*fw
= ufeAlwaysWord("(.\")");
3530 ufeImgEmitU32(fw
->cfaidx
);
3532 size_t slen
= strlen(str
);
3533 if (slen
> 65535) ufeFatal("UFE string too long");
3534 ufeImgEmitU32((uint32_t)slen
);
3536 ufeImgEmitU32((uint32_t)(str
[0]&0xffU
));
3542 #define UFC(wn_) ufeCompile(""#wn_);
3543 #define UFS(wn_) ufeString(""#wn_);
3544 #define UFDS(wn_) ufeDotString(""#wn_);
3545 #define UFN(wn_) ufeNumber(wn_);
3547 #define UFBEGIN UFCALL(BEGIN);
3548 #define UFAGAIN UFCALL(AGAIN);
3551 static void ufeDefineQuit (void) {
3552 ufeDefine("UFE-RUN-LOOP");
3560 static void ufeDefineMisc (void) {
3562 ufeNumber(16); UFC(BASE
); UFC(!);
3565 ufeDefine("DECIMAL");
3566 ufeNumber(10); UFC(BASE
); UFC(!);
3570 UFC(0) UFC(SWAP
) UFC(!)
3574 UFC(1) UFC(SWAP
) UFC(!)
3578 UFC(DUP
) UFC(@
) UFC(ROT
) UFC(+) UFC(SWAP
) UFC(!)
3582 UFC(DUP
) UFC(@
) UFC(ROT
) UFC(SWAP
) UFC(-) UFC(SWAP
) UFC(!)
3586 UFC(DUP
) UFC(@
) UFC(1+) UFC(SWAP
) UFC(!)
3590 UFC(DUP
) UFC(@
) UFC(2+) UFC(SWAP
) UFC(!)
3594 UFC(DUP
) UFC(@
) UFC(3+) UFC(SWAP
) UFC(!)
3598 UFC(DUP
) UFC(@
) UFC(4+) UFC(SWAP
) UFC(!)
3602 UFC(DUP
) UFC(@
) UFC(1-) UFC(SWAP
) UFC(!)
3606 UFC(DUP
) UFC(@
) UFC(2-) UFC(SWAP
) UFC(!)
3610 UFC(DUP
) UFC(@
) UFC(3-) UFC(SWAP
) UFC(!)
3614 UFC(DUP
) UFC(@
) UFC(4-) UFC(SWAP
) UFC(!)
3618 ufeNumber(0); UFC(=);
3622 ufeNumber(0); UFC(<>);
3626 ufeNumber(0); UFC(!=);
3630 ufeNumber(0); UFC(<);
3634 ufeNumber(0); UFC(>);
3638 ufeNumber(0); UFC(U
>);
3646 // ////////////////////////////////////////////////////////////////////////// //
3648 #include "urforth_dbg.c"
3653 ufeFatal("there is no UFE debug breakpoint support in windoze");
3655 if (isatty(STDIN_FILENO
) && isatty(STDOUT_FILENO
)) {
3658 fprintf(stderr
, "WARNING: cannot start UFE debug session, because standard streams are not on TTY!\n");
3664 // ////////////////////////////////////////////////////////////////////////// //
3667 #define UFWORD(name_) ufeRegisterWord(""#name_, ufeWord_##name_, 0)
3668 #define UFWORDX(strname_,name_) ufeRegisterWord(strname_, ufeWord_##name_, 0)
3670 #define UFWORD_IMM(name_) ufeRegisterWord(""#name_, ufeWord_##name_, 1)
3671 #define UFWORDX_IMM(strname_,name_) ufeRegisterWord(strname_, ufeWord_##name_, 1)
3674 static void ufeInit (void) {
3675 ufeMode
= UFE_MODE_NATIVE
;
3678 zxlblLastByte
= urFindLabel("latest_byte");
3679 //if (!zxlblLastByte) ufeFatal("label 'latest_byte' not found");
3681 ufeDStack
= calloc(UFE_DSTACK_SIZE
, sizeof(ufeDStack
[0]));
3682 ufeRStack
= calloc(UFE_RSTACK_SIZE
, sizeof(ufeRStack
[0]));
3683 ufeForthCFAs
= calloc(UFE_MAX_WORDS
, sizeof(ufeForthCFAs
[0]));
3686 while (ufeImageUsed
<= ufeTIBAreaSize
) ufeImgEmitU32(0);
3689 ufeBASEaddr
= ufeImageUsed
;
3693 ufeSTATEaddr
= ufeImageUsed
;
3696 ufeSetState(0); // ensure interpreting
3698 // base low-level interpreter words
3699 UFWORDX("SP0!", SP0_PUT
);
3700 UFWORDX("RP0!", RP0_PUT
);
3705 UFWORDX("C@", CPEEK
);
3706 UFWORDX("C!", CPOKE
);
3707 UFWORDX("W@", WPEEK
);
3708 UFWORDX("W!", WPOKE
);
3709 UFWORDX("C,", CCOMMA
);
3710 UFWORDX(",", COMMA
);
3711 UFWORDX("ZXADDR?", ZXADDRQ
);
3712 UFWORDX("(TOZX)", TOZX
);
3713 UFWORDX_IMM("TOZX", TOZX_IMM
);
3714 UFWORDX("(FROMZX)", FROMZX
);
3715 UFWORDX_IMM("FROMZX", FROMZX_IMM
);
3720 UFWORDX("0BRANCH", FBRANCH
);
3721 UFWORDX("(DO)", DO_PAREN
);
3722 UFWORDX("(LOOP)", LOOP_PAREN
);
3723 UFWORDX("(+LOOP)", PLOOP_PAREN
);
3725 UFWORDX_IMM("RECURSE", RECURSE_IMM
);
3729 UFWORDX("?DUP", QDUP
);
3730 UFWORDX("2DUP", DDUP
);
3732 UFWORDX("2DROP", DDROP
);
3734 UFWORDX("2SWAP", DSWAP
);
3736 UFWORDX("2OVER", DOVER
);
3747 UFWORDX(">R", DTOR
);
3748 UFWORDX("R>", RTOD
);
3749 UFWORDX("R@", RPEEK
);
3751 UFWORDX("CMOVE>", CMOVE_FWD
);
3752 UFWORDX("CMOVE", CMOVE_BACK
);
3753 UFWORDX("MOVE", MOVE
);
3755 UFWORDX("STR=", STREQU
);
3756 UFWORDX("STR=CI", STREQUCI
);
3758 // some useful words
3759 UFWORDX_IMM("(", COMMENTPAREN
);
3760 UFWORDX_IMM("\\", COMMENTEOL
);
3761 UFWORDX_IMM(";;", COMMENTEOL
);
3775 UFWORDX("U.", UDOT
);
3776 UFWORDX(".R", DOTR
);
3777 UFWORDX("U.R", UDOTR
);
3782 UFWORDX("-", MINUS
);
3784 UFWORDX("U*", UMUL
);
3786 UFWORDX("U/", UDIV
);
3787 UFWORDX("MOD", MOD
);
3788 UFWORDX("UMOD", UMOD
);
3789 UFWORDX("/MOD", DIVMOD
);
3790 UFWORDX("U/MOD", UDIVMOD
);
3794 UFWORDX(">", GREAT
);
3795 UFWORDX("<=", LESSEQU
);
3796 UFWORDX(">=", GREATEQU
);
3797 UFWORDX("U<", ULESS
);
3798 UFWORDX("U>", UGREAT
);
3799 UFWORDX("U<=", ULESSEQU
);
3800 UFWORDX("U>=", UGREATEQU
);
3802 UFWORDX("<>", NOTEQU
);
3803 UFWORDX("!=", NOTEQU
);
3813 UFWORDX("1+", ONEPLUS
);
3814 UFWORDX("1-", ONEMINUS
);
3815 UFWORDX("2+", TWOPLUS
);
3816 UFWORDX("2-", TWOMINUS
);
3817 UFWORDX("3+", THREEPLUS
);
3818 UFWORDX("3-", THREEMINUS
);
3819 UFWORDX("4+", FOURPLUS
);
3820 UFWORDX("4-", FOURMINUS
);
3821 UFWORDX("2U*", ONESHL
);
3822 UFWORDX("2U/", ONESHR
);
3824 UFWORDX("SHL", SHL
);
3825 UFWORDX("SHR", SHR
);
3827 // low-level compiler words
3828 UFWORDX("LITERAL", LITERAL
);
3829 UFWORDX("STRLITERAL", STRLITERAL
);
3830 UFWORDX("(UNESCAPE)", UNESCAPE_PAREN
);
3831 UFWORDX("(\")", STRQ_PAREN
);
3832 UFWORDX("(.\")", STRDOTQ_PAREN
);
3834 UFWORDX_IMM("\"", STRQ
);
3835 UFWORDX_IMM(".\"", STRDOTQ
);
3837 UFWORDX("?EXEC", QEXEC
);
3838 UFWORDX("?COMP", QCOMP
);
3839 UFWORDX("?PAIRS", QPAIRS
);
3840 UFWORDX_IMM("COMPILE", COMPILE_IMM
);
3841 UFWORDX_IMM("[COMPILE]", XCOMPILE_IMM
);
3842 UFWORDX("COMP-BACK", COMP_BACK
);
3843 UFWORDX("COMP-FWD", COMP_FWD
);
3851 UFWORDX_IMM("THEN", ENDIF
);
3858 UFWORD_IMM(ENDCASE
);
3860 UFWORDX_IMM("&OF", AND_OF
);
3862 UFWORD_IMM(OTHERWISE
);
3865 UFWORDX_IMM("+LOOP", PLOOP
);
3868 UFWORDX("I'", ITICK
);
3869 UFWORDX("J'", JTICK
);
3871 UFWORDX(":", COLON
);
3872 UFWORDX("ZX:", ZX_COLON
);
3873 UFWORDX_IMM(";", SEMI
);
3881 UFWORDX("(NUMBER)", XNUMBER
);
3885 UFWORDX_IMM("<ZX>", ZX_MODE
);
3886 UFWORDX_IMM("<NATIVE>", NATIVE_MODE
);
3887 UFWORDX("<UFE-MODE@>", UFE_MODER
);
3888 UFWORDX("<UFE-MODE!>", UFE_MODEW
);
3890 UFWORDX("ZX-VALUE", ZX_VALUE
);
3891 UFWORDX("ZX-VAR-NOALLOT", ZX_VAR_NOALLOT
);
3892 UFWORDX("ZX-VARIABLE", ZX_VARIABLE
);
3893 UFWORDX("ZX-CONSTANT", ZX_CONSTANT
);
3894 UFWORDX("ZX-DEFER", ZX_DEFER
);
3895 UFWORDX("ZX-VARBIN", ZX_VARBIN
);
3896 UFWORDX("ZX-ALLOT", ZX_ALLOT
);
3897 UFWORDX("ZX-HERE", ZX_HERE
);
3898 UFWORDX("ZX-PAD", ZX_PAD
);
3899 UFWORDX("ZX-DP@", ZX_DP_PEEK
);
3900 UFWORDX("ZX-DP!", ZX_DP_POKE
);
3901 UFWORDX_IMM("ZX-TO", ZX_TO_IMM
);
3902 UFWORDX_IMM("ZX-STRTO", ZX_STRTO
);
3903 UFWORDX_IMM("ZX-'", ZX_TICKCFA_IMM
);
3904 UFWORDX_IMM("ZX-'PFA", ZX_TICKPFA_IMM
);
3906 UFWORDX("NATIVE-VALUE", NATIVE_VALUE
);
3907 UFWORDX("NATIVE-VAR-NOALLOT", NATIVE_VAR_NOALLOT
);
3908 UFWORDX("NATIVE-VARIABLE", NATIVE_VARIABLE
);
3909 UFWORDX("NATIVE-CONSTANT", NATIVE_CONSTANT
);
3910 UFWORDX("NATIVE-DEFER", NATIVE_DEFER
);
3911 UFWORDX("NATIVE-VARBIN", NATIVE_VARBIN
);
3912 UFWORDX("NATIVE-ALLOT", NATIVE_ALLOT
);
3913 UFWORDX("NATIVE-HERE", NATIVE_HERE
);
3914 UFWORDX("NATIVE-PAD", NATIVE_PAD
);
3915 UFWORDX("NATIVE-DP@", NATIVE_DP_PEEK
);
3916 UFWORDX("NATIVE-DP!", NATIVE_DP_POKE
);
3917 UFWORDX_IMM("NATIVE-TO", NATIVE_TO_IMM
);
3918 UFWORDX_IMM("NATIVE-STRTO", NATIVE_STRTO
);
3919 UFWORDX_IMM("NATIVE-'", NATIVE_TICKCFA_IMM
);
3920 UFWORDX_IMM("NATIVE-'PFA", NATIVE_TICKPFA_IMM
);
3922 UFWORDX_IMM("VALUE", VALUE
);
3923 UFWORDX_IMM("VAR-NOALLOT", VAR_NOALLOT
);
3924 UFWORDX_IMM("VARIABLE", VARIABLE
);
3925 UFWORDX_IMM("CONSTANT", CONSTANT
);
3926 UFWORDX_IMM("DEFER", DEFER
);
3927 UFWORDX_IMM("VARBIN", VARBIN
);
3928 UFWORDX_IMM("ALLOT", ALLOT
);
3929 UFWORDX_IMM("HERE", HERE
);
3930 UFWORDX_IMM("PAD", PAD
);
3931 UFWORDX_IMM("DP@", DP_PEEK
);
3932 UFWORDX_IMM("DP!", DP_POKE
);
3933 UFWORDX_IMM("TO", TO_IMM
);
3934 UFWORDX_IMM("STRTO", STRTO
);
3935 UFWORDX_IMM("'", TICKCFA_IMM
);
3936 UFWORDX_IMM("'PFA", TICKPFA_IMM
);
3938 UFWORDX_IMM("[0X]", ZEROX_IMM
);
3939 UFWORDX_IMM("[0O]", ZEROO_IMM
);
3940 UFWORDX_IMM("[0B]", ZEROB_IMM
);
3941 UFWORDX_IMM("[0D]", ZEROD_IMM
);
3943 UFWORDX_IMM("[", LSQBRACKET_IMM
);
3944 UFWORDX("]", RSQBRACKET
);
3946 UFWORDX("(CODEBLOCK)", CODEBLOCK
);
3947 UFWORDX_IMM("[:", CODEBLOCK_START_IMM
);
3948 UFWORDX_IMM(";]", CODEBLOCK_END_IMM
);
3949 /* code blocks are used like this:
3950 : A [[ ( addr count -- res ) TYPE 0 ]] UR-FOREACH-LABEL DROP ;
3951 i.e. it creates inlined code block, and returns its CFA.
3955 UFWORDX("UR-HAS-LABEL?", UR_HAS_LABELQ
);
3956 UFWORDX("UR-GET-LABEL", UR_GET_LABELQ
);
3957 UFWORDX("UR-FOREACH-LABEL", UR_FOREACH_LABEL
);
3958 UFWORDX("UR-PASS?", UR_PASSQ
);
3959 UFWORDX("UR-AFTER-TRACE?", UR_AFTER_TRACEQ
);
3961 UFWORDX("UR-ZX-FIND-WORD", UR_ZX_FIND_WORD
);
3962 UFWORDX("UR-ZX-WORD-NAME-BY-CFA", UR_ZX_WORD_NAME_BY_CFA
);
3963 UFWORDX("UR-ZX-WORD-FLAGS-BY-CFA", UR_ZX_WORD_FLAGS_BY_CFA
);
3964 UFWORDX("UR-ZX-WORD-USED-BY-CFA?", UR_ZX_WORD_USED_BY_CFAQ
);
3965 UFWORDX("UR-ZX-WORD-USED-BY-CFA-1!", UR_ZX_WORD_USED_BY_CFA_1POKE
);
3966 UFWORDX("UR-ZX-LAST-FORTH-WORD-NAME", UR_ZX_LAST_FORTH_WORD_NAME
);
3967 UFWORDX("UR-ZX-LAST-FORTH-WORD-CFA", UR_ZX_LAST_FORTH_WORD_CFA
);
3968 UFWORDX("UR-ZX-WORD-TYPE-BY-CFA", UR_ZX_WORD_TYPE_BY_CFA
);
3970 // conditional compilation
3971 UFWORDX_IMM("$IFDEF", DLR_IFDEF_IMM
);
3972 UFWORDX_IMM("$IFNDEF", DLR_IFNDEF_IMM
);
3973 UFWORDX_IMM("$IF", DLR_IF_IMM
);
3974 UFWORDX_IMM("$IFNOT", DLR_IFNOT_IMM
);
3975 UFWORDX_IMM("$ELSE", DLR_ELSE_IMM
);
3976 UFWORDX_IMM("$ELIFDEF", DLR_ELIFDEF_IMM
);
3977 UFWORDX_IMM("$ELIFNDEF", DLR_ELIFNDEF_IMM
);
3978 UFWORDX_IMM("$ELIF", DLR_ELIF_IMM
);
3979 UFWORDX_IMM("$ELIFNOT", DLR_ELIFNOT_IMM
);
3980 UFWORDX_IMM("$IFZX", DLR_IFZX_IMM
);
3981 UFWORDX_IMM("$IFNATIVE", DLR_IFNATIVE_IMM
);
3982 UFWORDX_IMM("$ELIFZX", DLR_ELIFZX_IMM
);
3983 UFWORDX_IMM("$ELIFNATIVE", DLR_ELIFNATIVE_IMM
);
3984 UFWORDX_IMM("$ENDIF", DLR_ENDIF_IMM
);
3986 UFWORDX_IMM("$DEFINE", DLR_DEFINE
);
3987 UFWORDX_IMM("$UNDEF", DLR_UNDEF
);
3989 UFWORDX_IMM("$INCLUDE", DLR_INCLUDE_IMM
);
3991 UFWORDX("ZX-START-WORD", ZX_START_WORD
);
3993 UFWORDX("DUMP-STACK", DUMP_STACK
);
3994 UFWORDX("UFE-FATAL", UFE_FATAL
);
3996 UFWORDX("(UFE-BP)", UFE_BP
);
4001 ufeSetState(0); // interpreting
4005 // ////////////////////////////////////////////////////////////////////////// //
4006 // address interpreter
4007 static void ufeRunVM (void) {
4009 while (!ufeStopVM
) {
4010 uint32_t cfaidx
= ufeImgGetU32(ufeIP
++);
4011 if (cfaidx
>= ufeCFAsUsed
) {
4013 ufeFatal("UFE tried to execute an unknown word: 0x%08x (max is 0x%08x); IP=0x%08x", cfaidx
, ufeCFAsUsed
, ufeIP
-1);
4015 UForthWord
*fw
= ufeForthCFAs
[cfaidx
];
4016 //fprintf(stderr, "...<%s>\n", fw->name);
4018 //fprintf(stderr, "....<%s>\n", fw->name);
4022 static void ufeRunIt (const char *wname
) {
4023 UForthWord
*fw
= ufeAlwaysWord(wname
);
4024 if (fw
->cfa
!= &ufeDoForth
) ufeFatal("UFE '%s' word is not Forth word", wname
);
4030 // ////////////////////////////////////////////////////////////////////////// //
4031 static int runForthEngine (const char *fname
) {
4033 ufeInFile
= fopen(fname
, "rb");
4034 if (!ufeInFile
) ufeFatal("cannot open UFE file '%s'", fname
);
4035 if (pc
!= disp
) ufeFatal("UFE can be used only for non-disped code");
4037 ufeInFileName
= strdup(fname
);
4041 ufeImgPutU32(0, 0); // trigger next line loading
4044 char *ufmname
= ufeCreateIncludeName("zzmain.f", 1);
4045 FILE *ufl
= fopen(ufmname
, "rb");
4048 ufeInFileName
= ufmname
;
4054 if (setjmp(ufeEOFJP
)) {
4056 printf("UFE complete\n");
4057 //UrLabelInfo *lhb = urFindLabel("VLIST_HASH_BITS");
4059 for (ForthWord
*fw
= forthWordList
; fw
; fw
= fw
->next
) {
4060 if (fw
->nfa
> lwa
) lwa
= fw
->nfa
;
4062 UrLabelInfo
*zxlblLastWordAddr
= urFindLabel("latest_word_addr");
4063 //if (!zxlblLastWordAddr) ufeFatal("label 'latest_word' not found");
4064 if (zxlblLastWordAddr
) {
4065 //lwa += (lhb && lhb->value ? 2 : 0);
4066 //fprintf(stderr, "LATEST WORD: #%04X (at #%04X); old=#%04X\n", lwa, (unsigned)zxlblLastWordAddr->value, getWord(zxlblLastWordAddr->value));
4067 putWord(zxlblLastWordAddr
->value
, lwa
);
4068 //fprintf(stderr, "LATEST BYTE: #%04X (#%04X)\n", disp, zxlblLastByte->value);
4069 //zxlblLastByte = urFindLabel("latest_byte");
4074 //UFCALL(INTERPRET);
4075 ufeRunIt("UFE-RUN-LOOP");
4076 abort(); // the thing that should not be