1 // and now for something completely different...
2 // UrAsm built-in Forth Engine!
16 #include <sys/types.h>
21 //#define UFO_DEBUG_STARTUP_TIMES
22 //#define UFO_DEBUG_FATAL_ABORT
23 //#define UFO_TRACE_VM_DOER
24 //#define UFO_TRACE_VM_RUN
25 //#define UFO_DEBUG_INCLUDE
26 //#define UFO_DEBUG_DUMP_NEW_HEADERS
27 //#define UFO_DEBUG_FIND_WORD
28 //#define UFO_DEBUG_FIND_WORD_IN_VOC
29 //#define UFO_DEBUG_FIND_WORD_COLON
31 // 2/8 msecs w/o inlining
32 // 1/5 msecs with inlining
34 # define UFO_FORCE_INLINE static inline __attribute__((always_inline))
36 # define UFO_FORCE_INLINE static __attribute__((noinline)) __attribute__((unused))
40 // should not be bigger than this!
41 #define UFO_MAX_WORD_LENGTH (250)
43 #define UFO_ALIGN4(v_) (((v_) + 3u) / 4u * 4u)
46 static const char *ufo_assert_failure (const char *cond
, const char *fname
, int fline
,
49 for (const char *t
= fname
; *t
; ++t
) {
51 if (*t
== '/' || *t
== '\\') fname
= t
+1;
53 if (*t
== '/') fname
= t
+1;
57 fprintf(stderr
, "\n%s:%d: Assertion in `%s` failed: %s\n", fname
, fline
, func
, cond
);
62 #define ufo_assert(cond_) do { if (__builtin_expect((!(cond_)), 0)) { ufo_assert_failure(#cond_, __FILE__, __LINE__, __PRETTY_FUNCTION__); } } while (0)
66 static time_t secstart
= 0;
70 //==========================================================================
74 //==========================================================================
75 static uint64_t ufo_get_msecs (void) {
77 return GetTickCount();
80 #ifdef CLOCK_MONOTONIC
81 ufo_assert(clock_gettime(CLOCK_MONOTONIC
, &ts
) == 0);
83 // this should be available everywhere
84 ufo_assert(clock_gettime(CLOCK_REALTIME
, &ts
) == 0);
88 secstart
= ts
.tv_sec
+1;
89 ufo_assert(secstart
); // it should not be zero
91 return (uint64_t)(ts
.tv_sec
-secstart
+2)*1000U+(uint32_t)ts
.tv_nsec
/1000000U;
93 //return (uint64_t)(ts.tv_sec-secstart+2)*1000000000U+(uint32_t)ts.tv_nsec;
98 //==========================================================================
102 //==========================================================================
103 UFO_FORCE_INLINE
uint32_t joaatHashBufCI (const void *buf
, size_t len
) {
104 uint32_t hash
= 0x29a;
105 const uint8_t *s
= (const uint8_t *)buf
;
107 //hash += (uint8_t)locase1251(*s++);
108 hash
+= (*s
++)|0x20; // this converts ASCII capitals to locase (and destroys other, but who cares)
120 //==========================================================================
124 //==========================================================================
125 UFO_FORCE_INLINE
char toUpper (char ch
) {
126 return (ch
>= 'a' && ch
<= 'z' ? ch
-'a'+'A' : ch
);
130 //==========================================================================
134 //==========================================================================
135 UFO_FORCE_INLINE
uint8_t toUpperU8 (uint8_t ch
) {
136 return (ch
>= 'a' && ch
<= 'z' ? ch
-'a'+'A' : ch
);
140 //==========================================================================
144 //==========================================================================
145 UFO_FORCE_INLINE
int digitInBase (char ch
, int base
) {
147 case '0' ... '9': ch
= ch
- '0'; break;
148 case 'A' ... 'Z': ch
= ch
- 'A' + 10; break;
149 case 'a' ... 'z': ch
= ch
- 'a' + 10; break;
150 default: base
= -1; break;
152 return (ch
>= 0 && ch
< base
? ch
: -1);
157 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
158 ;; word header format:
159 ;; note than name hash is ALWAYS calculated with ASCII-uppercased name
160 ;; (actually, bit 5 is always reset for all bytes, because we don't need the
161 ;; exact uppercase, only something that resembles it)
162 ;; bfa points to next bfa or to 0 (this is "hash bucket pointer")
163 ;; before nfa, we have such "hidden" fields:
164 ;; dd dfa ; pointer to the debug data; can be 0 if debug info is missing
165 ;; dd sfa ; points *after* the last word byte
166 ;; dd bfa ; next word in hashtable bucket; it is always here, even if hashtable is turned off
167 ;; ; if there is no hashtable, this field is not used
169 ;; dd lfa ; previous word LFA or 0 (lfa links points here)
170 ;; dd namehash ; it is always here, and always calculated, even if hashtable is turned off
172 ;; dd flags-and-name-len ; see below
173 ;; db name ; no terminating zero or other "termination flag" here
174 ;; here could be some 0 bytes to align everything to 4 bytes
175 ;; db namelen ; yes, name length again, so CFA->NFA can avoid guessing
176 ;; ; full length, including padding, but not including this byte
178 ;; dd cfaidx ; our internal CFA index, or image address for DOES>
182 ;; first word cell contains combined name length (low byte), argtype and flags (other bytes)
187 ;; i.e. we have 16 bits for flags, and 256 possible argument types. why not.
196 ;; bit 6: main scattered colon word (with "...")
199 ;; argtype is the type of the argument that this word reads from the threaded code.
200 ;; possible argument types:
203 ;; 2: cell-size numeric literal
204 ;; 3: cell-counted string with terminating zero (not counted)
205 ;; 4: cfa of another word
208 ;; 7: *UNUSED* byte-counted string with terminating zero (not counted)
215 ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
216 ;; wordlist structure (at PFA)
218 ;; dd voclink (voclink always points here)
219 ;; dd parent (if not zero, all parent words are visible)
220 ;; dd header-nfa (can be 0 for anonymous wordlists)
221 ;; hashtable (if enabled), or ~0U if no hash table
225 // ////////////////////////////////////////////////////////////////////////// //
226 #define UFO_BFA_TO_LFA(bfa_) ((bfa_) + 1u * 4u)
227 #define UFO_LFA_TO_DFA(lfa_) ((lfa_) - 3u * 4u)
228 #define UFO_LFA_TO_SFA(lfa_) ((lfa_) - 2u * 4u)
229 #define UFO_LFA_TO_BFA(lfa_) ((lfa_) - 1u * 4u)
230 #define UFO_LFA_TO_NFA(lfa_) ((lfa_) + 2u * 4u)
231 #define UFO_LFA_TO_CFA(lfa_) UFO_ALIGN4((lfa_) + 3u * 4u + 1u + ufoImgGetU8((lfa_) + 2u * 4u))
232 #define UFO_LFA_TO_NHASH(lfa_) ((lfa_) + 1u * 4u)
233 #define UFO_CFA_TO_NFA(cfa_) ((cfa_) - 1u - 4u - ufoImgGetU8((cfa_) - 1u))
234 #define UFO_CFA_TO_LFA(cfa_) ((cfa_) - 1u - 4u * 3u - ufoImgGetU8((cfa_) - 1u))
235 #define UFO_CFA_TO_PFA(cfa_) ((cfa_) + 1u * 4u)
236 #define UFO_PFA_TO_CFA(pfa_) ((pfa_) - 1u * 4u)
237 #define UFO_NFA_TO_CFA(nfa_) UFO_ALIGN4((nfa_) + 4u + 1u + ufoImgGetU8((nfa_)))
238 #define UFO_NFA_TO_LFA(nfa_) ((nfa_) - 2u * 4u)
241 // ////////////////////////////////////////////////////////////////////////// //
242 #define UFW_FLAG_IMMEDIATE (1u<<16)
243 #define UFW_FLAG_SMUDGE (1u<<17)
244 #define UFW_FLAG_NORETURN (1u<<18)
245 #define UFW_FLAG_HIDDEN (1u<<19)
246 #define UFW_FLAG_CBLOCK (1u<<20)
247 #define UFW_FLAG_VOCAB (1u<<21)
248 #define UFW_FLAG_SCOLON (1u<<22)
249 #define UFW_FLAG_PROTECTED (1u<<23)
250 #define UFW_FLAG_TRACE (1u<<31)
252 #define UFW_WARG_MASK ((uint32_t)0xff00U)
254 #define UFW_WARG_NONE (0u<<8)
255 #define UFW_WARG_BRANCH (1u<<8)
256 #define UFW_WARG_LIT (2u<<8)
257 #define UFW_WARG_C4STRZ (3u<<8)
258 #define UFW_WARG_CFA (4u<<8)
259 #define UFW_WARG_CBLOCK (5u<<8)
260 #define UFW_WARG_VOCID (6u<<8)
261 #define UFW_WARG_C1STRZ (7u<<8)
262 //#define UFW_WARG_U8 (8u<<8)
263 //#define UFW_WARG_S8 (9u<<8)
264 //#define UFW_WARG_U16 (10u<<8)
265 //#define UFW_WARG_S16 (11u<<8)
267 #define UFW_VOCAB_OFS_LATEST (0u * 4u)
268 #define UFW_VOCAB_OFS_VOCLINK (1u * 4u)
269 #define UFW_VOCAB_OFS_PARENT (2u * 4u)
270 #define UFW_VOCAB_OFS_HEADER (3u * 4u)
271 #define UFW_VOCAB_OFS_HTABLE (4u * 4u)
273 #define UFO_HASHTABLE_SIZE (256)
275 #define UFO_NO_HTABLE_FLAG (~(uint32_t)0)
277 static jmp_buf ufoInlineQuitJP
;
279 typedef void (*ufoNativeCFA
) (uint32_t pfa
);
280 #define UFO_MAX_NATIVE_CFAS (1024u)
281 static ufoNativeCFA
*ufoForthCFAs
= NULL
;
282 static uint32_t ufoCFAsUsed
= 0;
284 static uint32_t ufoDoForthCFA
;
285 static uint32_t ufoDoVarCFA
;
286 static uint32_t ufoDoValueCFA
;
287 static uint32_t ufoDoConstCFA
;
288 static uint32_t ufoDoDeferCFA
;
289 static uint32_t ufoDoVocCFA
;
290 static uint32_t ufoMaxDoCFA
;
292 static uint32_t ufoStrLit8CFA
;
294 // special address types:
295 #define UFO_ADDR_CFA_BIT ((uint32_t)1<<31)
296 #define UFO_ADDR_CFA_MASK (UFO_ADDR_CFA_BIT-1u)
298 #define UFO_ADDR_HANDLE_BIT ((uint32_t)1<<30)
299 #define UFO_ADDR_HANDLE_MASK (UFO_ADDR_HANDLE_BIT-1u)
301 // temporary area is 1MB buffer out of the main image
302 #define UFO_ADDR_TEMP_BIT ((uint32_t)1<<29)
303 #define UFO_ADDR_TEMP_MASK (UFO_ADDR_TEMP_BIT-1u)
305 #define UFO_ADDR_SPECIAL_BITS_MASK (UFO_ADDR_CFA_BIT|UFO_ADDR_HANDLE_BIT|UFO_ADDR_TEMP_BIT)
308 static uint32_t *ufoImage
= NULL
;
309 static uint32_t ufoImageSize
= 0;
311 static uint32_t *ufoImageTemp
= NULL
;
312 static uint32_t ufoImageTempSize
= 0;
314 static uint32_t ufoIP
= 0; // in image
315 static uint32_t ufoSP
= 0; // points AFTER the last value pushed
316 static uint32_t ufoRP
= 0; // points AFTER the last value pushed
317 static uint32_t ufoRPTop
= 0; // stop when RP is this, and we're doing EXIT
319 static uint32_t ufoTrueValue
= ~0u;
323 UFO_MODE_NATIVE
= 0, // executing forth code
324 UFO_MODE_MACRO
= 1, // executing forth asm macro
326 static uint32_t ufoMode
= UFO_MODE_NONE
;
328 #define UFO_DSTACK_SIZE (8192)
329 #define UFO_RSTACK_SIZE (8192)
330 #define UFO_LSTACK_SIZE (8192)
331 static uint32_t *ufoDStack
;
332 static uint32_t *ufoRStack
;
333 static uint32_t *ufoLStack
;
334 static uint32_t ufoLP
= 0;
335 static uint32_t ufoLBP
= 0;
337 // dynamically allocated text input buffer
338 // always ends with zero (this is word name too)
339 // first 512 bytes of image is TIB
340 #define ufoTIBAreaSize (512)
341 #define ufoNUMAreaSize (128)
342 static uint32_t ufoAddrTIB
= 0; // TIB; 0 means "in TIB area", otherwise in the dictionary
343 static uint32_t ufoAddrIN
= 0; // >IN
345 static uint32_t ufoAddrContext
; // CONTEXT
346 static uint32_t ufoAddrCurrent
; // CURRENT (definitions will go there)
347 static uint32_t ufoAddrVocLink
;
348 static uint32_t ufoAddrDP
;
349 static uint32_t ufoAddrDPTemp
;
350 static uint32_t ufoAddrSTATE
;
351 static uint32_t ufoAddrBASE
;
352 static uint32_t ufoAddrNewWordFlags
;
354 #define UFO_GET_DP() (ufoImgGetU32(ufoAddrDPTemp) ?: ufoImgGetU32(ufoAddrDP))
355 //#define UFO_SET_DP(val_) ufoImgPutU32(ufoAddrDP, (val_))
357 #define UFO_MAX_NESTED_INCLUDES (32)
364 uint32_t savedTIBSize
;
367 static UFOFileStackEntry ufoFileStack
[UFO_MAX_NESTED_INCLUDES
];
368 static uint32_t ufoFileStackPos
; // after the last used item
370 static FILE *ufoInFile
= NULL
;
371 static char *ufoInFileName
= NULL
;
372 static char *ufoLastIncPath
= NULL
;
373 static int ufoInFileLine
= 0;
374 static int ufoCondStLine
= -1;
376 static int ufoLastEmitWasCR
= 1;
377 static uint32_t ufoCSP
= 0;
378 static int ufoInCondIf
= 0;
380 #define UFO_VOCSTACK_SIZE (16u)
381 static uint32_t ufoVocStack
[UFO_VOCSTACK_SIZE
]; // cfas
382 static uint32_t ufoVSP
;
383 static uint32_t ufoForthVocId
;
384 static uint32_t ufoCompilerVocId
;
385 static uint32_t ufoMacroVocId
;
388 typedef struct UHandleInfo_t
{
392 uint32_t size
; // in `uint32_t`
393 uint32_t used
; // in `uint32_t`; for dynamic arrays
395 struct UHandleInfo_t
*next
;
398 static UHandleInfo
*ufoHandleFreeList
= NULL
;
399 static UHandleInfo
**ufoHandles
= NULL
;
400 static uint32_t ufoHandlesUsed
= 0;
401 static uint32_t ufoHandlesAlloted
= 0;
403 #define UFO_HANDLE_FREE (0)
405 #define UFO_GET_NATIVE_HANDLE(adr_) ({ \
406 uint32_t aa = (uint32_t)(adr_); \
407 if ((aa & UFO_ADDR_HANDLE_BIT) == 0) ufoFatal("expected handle"); \
408 aa &= UFO_HANDLE_MASK; \
409 if (aa >= ufoHandlesUsed || ufoHandles[aa] == NULL || ufoHandles[aa]->typecfa == UFO_HANDLE_FREE) ufoFatal("invalid handle"); \
414 static char ufoCurrFileLine
[520];
415 // used to extract strings from the image
416 static char ufoTempCharBuf
[1024];
419 static uint32_t ufoInBacktrace
= 0;
422 // ////////////////////////////////////////////////////////////////////////// //
424 static void ufoDbgDeinit (void);
426 static void ufoClearCondDefines (void);
428 static uint32_t ufoVMPopCFA
= 0;
429 static void ufoRunVMCFA (uint32_t cfa
);
431 static void ufoBacktrace (uint32_t ip
);
433 static void ufoFixLatestSFA (void);
434 static void ufoClearCondDefines (void);
436 __attribute__((unused
)) static void ufoDumpWordHeader (const uint32_t lfa
);
439 //==========================================================================
443 //==========================================================================
444 static UHandleInfo
*ufoAllocHandle (uint32_t typecfa
) {
445 ufo_assert(typecfa
!= UFO_HANDLE_FREE
);
446 UHandleInfo
*newh
= ufoHandleFreeList
;
448 if (ufoHandlesUsed
== ufoHandlesAlloted
) {
449 uint32_t newsz
= ufoHandlesAlloted
+ 16384;
450 if (newsz
> 0x1000000U
) {
451 if (ufoHandlesAlloted
>= 0x1000000U
) ufoFatal("too many dynamic handles");
453 UHandleInfo
**nh
= realloc(ufoHandles
, sizeof(ufoHandles
[0]) * newsz
);
454 if (nh
== NULL
) ufoFatal("out of memory for handle table");
456 ufoHandlesAlloted
= newsz
;
458 newh
= calloc(1, sizeof(UHandleInfo
));
459 if (newh
== NULL
) ufoFatal("out of memory for handle info");
460 ufoHandles
[ufoHandlesUsed
] = newh
;
461 // setup new handle info
462 newh
->ufoHandle
= ufoHandlesUsed
| UFO_ADDR_HANDLE_BIT
;
465 ufoHandleFreeList
= newh
->next
;
467 // setup new handle info
468 newh
->typecfa
= typecfa
;
476 //==========================================================================
480 //==========================================================================
481 static void ufoFreeHandle (UHandleInfo
*hh
) {
483 ufo_assert(hh
->typecfa
!= UFO_HANDLE_FREE
);
484 if (hh
->mem
) free(hh
->mem
);
485 hh
->typecfa
= UFO_HANDLE_FREE
;
488 hh
->next
= ufoHandleFreeList
;
489 ufoHandleFreeList
= hh
;
494 //==========================================================================
498 //==========================================================================
499 static UHandleInfo
*ufoGetHandle (uint32_t hh
) {
501 if (hh
!= 0 && (hh
& UFO_ADDR_HANDLE_BIT
) != 0) {
502 hh
&= UFO_ADDR_HANDLE_MASK
;
503 if (hh
< ufoHandlesUsed
) {
504 res
= ufoHandles
[hh
];
505 if (res
->typecfa
== UFO_HANDLE_FREE
) res
= NULL
;
516 //==========================================================================
520 //==========================================================================
521 static void setLastIncPath (const char *fname
) {
522 if (fname
== NULL
|| fname
[0] == 0) {
523 if (ufoLastIncPath
) free(ufoLastIncPath
);
524 ufoLastIncPath
= strdup(".");
526 if (ufoLastIncPath
) free(ufoLastIncPath
);
527 ufoLastIncPath
= strdup(fname
);
528 char *lslash
= ufoLastIncPath
;
529 char *cpos
= ufoLastIncPath
;
532 if (*cpos
== '/' || *cpos
== '\\') lslash
= cpos
;
534 if (*cpos
== '/') lslash
= cpos
;
543 //==========================================================================
547 //==========================================================================
548 static void ufoErrorPrintFile (FILE *fo
) {
550 fprintf(fo
, "UFO ERROR at file %s, line %d: ", ufoInFileName
, ufoInFileLine
);
552 fprintf(fo
, "UFO ERROR somewhere in time: ");
557 //==========================================================================
561 //==========================================================================
562 static void ufoErrorMsgV (const char *fmt
, va_list ap
) {
563 if (!ufoLastEmitWasCR
) { printf("\n"); ufoLastEmitWasCR
= 1; }
565 ufoErrorPrintFile(stderr
);
566 vfprintf(stderr
, fmt
, ap
);
573 //==========================================================================
577 //==========================================================================
578 __attribute__((format(printf
, 1, 2)))
579 void ufoWarning (const char *fmt
, ...) {
582 ufoErrorMsgV(fmt
, ap
);
586 //==========================================================================
590 //==========================================================================
591 __attribute__((noreturn
)) __attribute__((format(printf
, 1, 2)))
592 void ufoFatal (const char *fmt
, ...) {
595 ufoErrorMsgV(fmt
, ap
);
596 if (!ufoInBacktrace
) {
601 fprintf(stderr
, "DOUBLE FATAL: error in backtrace!\n");
603 #ifdef UFO_DEBUG_FATAL_ABORT
610 // ////////////////////////////////////////////////////////////////////////// //
611 // working with the stacks
612 UFO_FORCE_INLINE
void ufoPush (uint32_t v
) { if (ufoSP
>= UFO_DSTACK_SIZE
) ufoFatal("UFO data stack overflow"); ufoDStack
[ufoSP
++] = v
; }
613 UFO_FORCE_INLINE
void ufoDrop (void) { if (ufoSP
== 0) ufoFatal("UFO data stack underflow"); --ufoSP
; }
614 UFO_FORCE_INLINE
uint32_t ufoPop (void) { if (ufoSP
== 0) { ufoFatal("UFO data stack underflow"); } return ufoDStack
[--ufoSP
]; }
615 UFO_FORCE_INLINE
uint32_t ufoPeek (void) { if (ufoSP
== 0) ufoFatal("UFO data stack underflow"); return ufoDStack
[ufoSP
-1u]; }
616 UFO_FORCE_INLINE
void ufoDup (void) { if (ufoSP
== 0) ufoFatal("UFO data stack underflow"); ufoPush(ufoDStack
[ufoSP
-1u]); }
617 UFO_FORCE_INLINE
void ufoOver (void) { if (ufoSP
< 2u) ufoFatal("UFO data stack underflow"); ufoPush(ufoDStack
[ufoSP
-2u]); }
618 UFO_FORCE_INLINE
void ufoSwap (void) { if (ufoSP
< 2u) ufoFatal("UFO data stack underflow"); const uint32_t t
= ufoDStack
[ufoSP
-1u]; ufoDStack
[ufoSP
-1u] = ufoDStack
[ufoSP
-2u]; ufoDStack
[ufoSP
-2u] = t
; }
619 UFO_FORCE_INLINE
void ufoRot (void) { if (ufoSP
< 3u) ufoFatal("UFO data stack underflow"); const uint32_t t
= ufoDStack
[ufoSP
-3u]; ufoDStack
[ufoSP
-3u] = ufoDStack
[ufoSP
-2u]; ufoDStack
[ufoSP
-2u] = ufoDStack
[ufoSP
-1u]; ufoDStack
[ufoSP
-1u] = t
; }
620 UFO_FORCE_INLINE
void ufoNRot (void) { if (ufoSP
< 3u) ufoFatal("UFO data stack underflow"); const uint32_t t
= ufoDStack
[ufoSP
-1u]; ufoDStack
[ufoSP
-1u] = ufoDStack
[ufoSP
-2u]; ufoDStack
[ufoSP
-2u] = ufoDStack
[ufoSP
-3u]; ufoDStack
[ufoSP
-3u] = t
; }
622 UFO_FORCE_INLINE
void ufo2Dup (void) { ufoOver(); ufoOver(); }
623 UFO_FORCE_INLINE
void ufo2Drop (void) { ufoDrop(); ufoDrop(); }
624 UFO_FORCE_INLINE
void ufo2Over (void) { if (ufoSP
< 4u) ufoFatal("UFO data stack underflow"); const uint32_t n0
= ufoDStack
[ufoSP
-4u]; const uint32_t n1
= ufoDStack
[ufoSP
-3u]; ufoPush(n0
); ufoPush(n1
); }
625 UFO_FORCE_INLINE
void ufo2Swap (void) { if (ufoSP
< 4u) ufoFatal("UFO data stack underflow"); const uint32_t n0
= ufoDStack
[ufoSP
-4u]; const uint32_t n1
= ufoDStack
[ufoSP
-3u]; ufoDStack
[ufoSP
-4u] = ufoDStack
[ufoSP
-2u]; ufoDStack
[ufoSP
-3u] = ufoDStack
[ufoSP
-1u]; ufoDStack
[ufoSP
-2u] = n0
; ufoDStack
[ufoSP
-1u] = n1
; }
627 UFO_FORCE_INLINE
void ufoRPush (uint32_t v
) { if (ufoRP
>= UFO_RSTACK_SIZE
) ufoFatal("UFO return stack overflow"); ufoRStack
[ufoRP
++] = v
; }
628 UFO_FORCE_INLINE
void ufoRDrop (void) { if (ufoRP
== 0 || ufoRP
== ufoRPTop
) ufoFatal("UFO return stack underflow"); --ufoRP
; }
629 UFO_FORCE_INLINE
uint32_t ufoRPop (void) { if (ufoRP
== 0 || ufoRP
== ufoRPTop
) ufoFatal("UFO return stack underflow"); return ufoRStack
[--ufoRP
]; }
630 UFO_FORCE_INLINE
uint32_t ufoRPeek (void) { if (ufoRP
== 0 || ufoRP
== ufoRPTop
) ufoFatal("UFO return stack underflow"); return ufoRStack
[ufoRP
-1u]; }
631 UFO_FORCE_INLINE
void ufoRDup (void) { if (ufoRP
== 0 || ufoRP
== ufoRPTop
) ufoFatal("UFO return stack underflow"); ufoPush(ufoRStack
[ufoRP
-1u]); }
633 UFO_FORCE_INLINE
void ufoPushBool (int v
) { ufoPush(v
? ufoTrueValue
: 0u); }
636 //==========================================================================
640 //==========================================================================
641 static void ufoImgEnsureSize (uint32_t addr
) {
642 if ((addr
& UFO_ADDR_SPECIAL_BITS_MASK
) != 0) ufoFatal("ufoImgEnsureSize: internal error");
643 if (addr
>= ufoImageSize
) {
644 // 64MB should be enough for everyone!
645 if (addr
>= 0x04000000U
) {
646 ufoFatal("UFO image grown too big (addr=0%08XH)", addr
);
648 const uint32_t osz
= ufoImageSize
;
650 uint32_t nsz
= (addr
|0x000fffffU
) + 1U;
651 ufo_assert(nsz
> addr
);
652 uint32_t *nimg
= realloc(ufoImage
, nsz
);
654 ufoFatal("out of memory for UFO image (%u -> %u MBs)",
655 ufoImageSize
/ 1024u / 1024u,
656 nsz
/ 1024u / 1024u);
660 memset((char *)ufoImage
+ osz
, 0, (nsz
- osz
));
665 //==========================================================================
669 //==========================================================================
670 static void ufoImgEnsureTemp (uint32_t addr
) {
671 if ((addr
& UFO_ADDR_SPECIAL_BITS_MASK
) != 0) ufoFatal("ufoImgEnsureTemp: internal error");
672 if (addr
>= ufoImageTempSize
) {
673 if (addr
>= 1024u * 1024u) {
674 ufoFatal("Forth segmentation fault at address 0x%08X", addr
|UFO_ADDR_TEMP_BIT
);
676 const uint32_t osz
= ufoImageTempSize
;
677 // grow by 256KB steps
678 uint32_t nsz
= (addr
|0x0003ffffU
) + 1U;
679 uint32_t *nimg
= realloc(ufoImageTemp
, nsz
);
681 ufoFatal("out of memory for temp UFO image (%u -> %u KBs)",
682 ufoImageTempSize
/ 1024u,
686 ufoImageTempSize
= nsz
;
687 memset(ufoImageTemp
+ osz
, 0, (nsz
- osz
));
692 //==========================================================================
696 //==========================================================================
697 UFO_FORCE_INLINE
void ufoImgPutU8 (uint32_t addr
, uint32_t value
) {
699 if ((addr
& UFO_ADDR_SPECIAL_BITS_MASK
) == 0) {
700 if (addr
>= ufoImageSize
) ufoImgEnsureSize(addr
);
701 imgptr
= &ufoImage
[addr
/4u];
702 } else if (addr
& UFO_ADDR_TEMP_BIT
) {
703 addr
&= UFO_ADDR_TEMP_MASK
;
704 if (addr
>= ufoImageTempSize
) ufoImgEnsureTemp(addr
);
705 imgptr
= &ufoImageTemp
[addr
/4u];
707 ufoFatal("Forth segmentation fault at address 0x%08X", addr
);
709 const uint8_t val
= (uint8_t)value
;
710 memcpy((uint8_t *)imgptr
+ (addr
&3), &val
, 1);
714 //==========================================================================
718 //==========================================================================
719 UFO_FORCE_INLINE
void ufoImgPutU16 (uint32_t addr
, uint32_t value
) {
720 ufoImgPutU8(addr
, value
&0xffU
);
721 ufoImgPutU8(addr
+ 1u, (value
>>8)&0xffU
);
725 //==========================================================================
729 //==========================================================================
730 UFO_FORCE_INLINE
void ufoImgPutU32 (uint32_t addr
, uint32_t value
) {
731 ufoImgPutU16(addr
, value
&0xffffU
);
732 ufoImgPutU16(addr
+ 2u, (value
>>16)&0xffffU
);
736 //==========================================================================
740 //==========================================================================
741 UFO_FORCE_INLINE
uint32_t ufoImgGetU8 (uint32_t addr
) {
743 if ((addr
& UFO_ADDR_SPECIAL_BITS_MASK
) == 0) {
744 if (addr
>= ufoImageSize
) return 0;
745 imgptr
= &ufoImage
[addr
/4u];
746 } else if (addr
& UFO_ADDR_TEMP_BIT
) {
747 addr
&= UFO_ADDR_TEMP_MASK
;
748 if (addr
>= ufoImageTempSize
) return 0;
749 imgptr
= &ufoImageTemp
[addr
/4u];
751 ufoFatal("Forth segmentation fault at address 0x%08X", addr
);
754 memcpy(&val
, (uint8_t *)imgptr
+ (addr
&3), 1);
755 return (uint32_t)val
;
759 //==========================================================================
763 //==========================================================================
764 UFO_FORCE_INLINE
uint32_t ufoImgGetU16 (uint32_t addr
) {
765 return ufoImgGetU8(addr
) | (ufoImgGetU8(addr
+ 1u) << 8);
769 //==========================================================================
773 //==========================================================================
774 UFO_FORCE_INLINE
uint32_t ufoImgGetU32 (uint32_t addr
) {
775 return ufoImgGetU16(addr
) | (ufoImgGetU16(addr
+ 2u) << 16);
779 //==========================================================================
783 //==========================================================================
784 UFO_FORCE_INLINE
void ufoBumpDP (uint32_t delta
) {
785 uint32_t dp
= ufoImgGetU32(ufoAddrDPTemp
);
787 dp
= ufoImgGetU32(ufoAddrDP
);
789 ufoImgPutU32(ufoAddrDP
, dp
);
791 dp
= ufoImgGetU32(ufoAddrDPTemp
);
793 ufoImgPutU32(ufoAddrDPTemp
, dp
);
798 //==========================================================================
802 //==========================================================================
803 UFO_FORCE_INLINE
void ufoImgEmitU8 (uint32_t value
) {
804 ufoImgPutU8(UFO_GET_DP(), value
);
809 //==========================================================================
813 //==========================================================================
814 UFO_FORCE_INLINE
void ufoImgEmitU32 (uint32_t value
) {
815 ufoImgPutU32(UFO_GET_DP(), value
);
820 //==========================================================================
822 // ufoImgEmitU32_NoInline
824 //==========================================================================
825 static __attribute__((noinline
)) void ufoImgEmitU32_NoInline (uint32_t value
) {
826 ufoImgPutU32(UFO_GET_DP(), value
);
831 //==========================================================================
835 //==========================================================================
836 UFO_FORCE_INLINE
void ufoImgEmitAlign (void) {
837 while ((UFO_GET_DP() & 3) != 0) ufoImgEmitU8(0);
841 //==========================================================================
845 //==========================================================================
846 static void ufoDoForth (uint32_t pfa
) {
852 //==========================================================================
856 //==========================================================================
857 static void ufoDoVariable (uint32_t pfa
) {
862 //==========================================================================
866 //==========================================================================
867 static void ufoDoValue (uint32_t pfa
) {
868 ufoPush(ufoImgGetU32(pfa
));
872 //==========================================================================
876 //==========================================================================
877 static void ufoDoConst (uint32_t pfa
) {
878 ufoPush(ufoImgGetU32(pfa
));
882 //==========================================================================
886 //==========================================================================
887 static void ufoDoDefer (uint32_t pfa
) {
888 const uint32_t cfa
= ufoImgGetU32(pfa
);
896 //==========================================================================
900 //==========================================================================
901 static void ufoDoVoc (uint32_t pfa
) {
902 ufoImgPutU32(ufoAddrContext
, ufoImgGetU32(pfa
));
906 //==========================================================================
910 //==========================================================================
911 static FILE *ufoOpenFileOrDir (char **fnameptr
) {
916 if (fnameptr
== NULL
) return NULL
;
919 fprintf(stderr
, "***:fname=<%s>\n", fname
);
922 if (fname
== NULL
|| fname
[0] == 0 || stat(fname
, &st
) != 0) return NULL
;
924 if (S_ISDIR(st
.st_mode
)) {
925 tmp
= calloc(1, strlen(fname
) + 128);
926 ufo_assert(tmp
!= NULL
);
927 sprintf(tmp
, "%s/%s", fname
, "zzmain.f");
928 free(fname
); fname
= tmp
; *fnameptr
= tmp
;
930 fprintf(stderr
, "***: <%s>\n", fname
);
934 return fopen(fname
, "rb");
938 //==========================================================================
942 //==========================================================================
943 static void ufoPushInFile (void) {
944 if (ufoFileStackPos
>= UFO_MAX_NESTED_INCLUDES
) ufoFatal("too many includes");
945 UFOFileStackEntry
*stk
= &ufoFileStack
[ufoFileStackPos
];
947 stk
->fname
= ufoInFileName
;
948 stk
->fline
= ufoInFileLine
;
949 stk
->incpath
= ufoLastIncPath
;
950 // save TIB (if it is the default)
951 uint32_t tib
= ufoImgGetU32(ufoAddrTIB
);
952 uint32_t in
= ufoImgGetU32(ufoAddrIN
);
953 stk
->savedTIBSize
= 0;
954 stk
->savedTIB
= NULL
;
955 if (tib
== 0 && in
< ufoTIBAreaSize
) {
956 while (ufoImgGetU8(tib
+ in
+ stk
->savedTIBSize
) != 0) stk
->savedTIBSize
+= 1;
957 if (stk
->savedTIBSize
!= 0) {
958 stk
->savedTIB
= malloc(stk
->savedTIBSize
);
959 if (stk
->savedTIB
== NULL
) ufoFatal("out of memory for include stack");
960 for (uint32_t f
= 0; f
< stk
->savedTIBSize
; f
+= 1) {
961 stk
->savedTIB
[f
] = ufoImgGetU8(tib
+ in
+ f
);
965 ufoFileStackPos
+= 1;
967 ufoInFileName
= NULL
;
969 ufoLastIncPath
= NULL
;
973 //==========================================================================
977 //==========================================================================
978 static void ufoPopInFile (void) {
979 if (ufoFileStackPos
== 0) ufoFatal("trying to pop include from empty stack");
980 if (ufoInFileName
) free(ufoInFileName
);
981 if (ufoInFile
) fclose(ufoInFile
);
982 if (ufoLastIncPath
) free(ufoLastIncPath
);
983 ufoFileStackPos
-= 1;
984 UFOFileStackEntry
*stk
= &ufoFileStack
[ufoFileStackPos
];
986 ufoInFileName
= stk
->fname
;
987 ufoInFileLine
= stk
->fline
;
988 ufoLastIncPath
= stk
->incpath
;
990 // also, restore current line, because some code may need it
991 if (stk
->savedTIBSize
>= ufoTIBAreaSize
) ufoFatal("restored TIB too big");
992 ufoImgPutU32(ufoAddrTIB
, 0);
993 ufoImgPutU32(ufoAddrIN
, 0);
994 if (stk
->savedTIBSize
!= 0) {
995 for (uint32_t f
= 0; f
< stk
->savedTIBSize
; f
+= 1) {
996 ufoImgPutU8(f
, stk
->savedTIB
[f
]);
1000 ufoImgPutU8(stk
->savedTIBSize
, 0);
1001 #ifdef UFO_DEBUG_INCLUDE
1002 fprintf(stderr
, "INC-POP: <%s>\n", ufoCurrFileLine
);
1007 //==========================================================================
1011 //==========================================================================
1012 void ufoDeinit (void) {
1014 ufoClearCondDefines();
1017 for (uint32_t f
= 0; f
< ufoHandlesUsed
; f
+= 1) {
1018 UHandleInfo
*hh
= ufoHandles
[f
];
1020 if (hh
->mem
!= NULL
) free(hh
->mem
);
1024 if (ufoHandles
!= NULL
) free(ufoHandles
);
1025 ufoHandles
= NULL
; ufoHandlesUsed
= 0; ufoHandlesAlloted
= 0;
1026 ufoHandleFreeList
= NULL
;
1028 // release all includes
1030 if (ufoInFileName
) free(ufoInFileName
);
1031 if (ufoLastIncPath
) free(ufoLastIncPath
);
1032 ufoInFileName
= NULL
; ufoLastIncPath
= NULL
;
1036 ufoForthCFAs
= NULL
;
1044 ufoImageTemp
= NULL
;
1045 ufoImageTempSize
= 0;
1048 ufoSP
= 0; ufoRP
= 0; ufoRPTop
= 0;
1049 ufoLP
= 0; ufoLBP
= 0;
1050 ufoMode
= UFO_MODE_NATIVE
;
1052 ufoForthVocId
= 0; ufoCompilerVocId
= 0; ufoMacroVocId
= 0;
1061 ufoAddrTIB
= 0; ufoAddrIN
= 0;
1063 ufoLastEmitWasCR
= 1;
1067 ufoClearCondDefines();
1075 //==========================================================================
1077 // ufoDumpWordHeader
1079 //==========================================================================
1080 __attribute__((unused
)) static void ufoDumpWordHeader (const uint32_t lfa
) {
1081 fprintf(stderr
, "=== WORD: LFA: 0x%08x ===\n", lfa
);
1083 fprintf(stderr
, " (DFA): 0x%08x\n", ufoImgGetU32(UFO_LFA_TO_DFA(lfa
)));
1084 fprintf(stderr
, " (SFA): 0x%08x\n", ufoImgGetU32(UFO_LFA_TO_SFA(lfa
)));
1085 fprintf(stderr
, " (BFA): 0x%08x\n", ufoImgGetU32(UFO_LFA_TO_BFA(lfa
)));
1086 fprintf(stderr
, " (LFA): 0x%08x\n", ufoImgGetU32(lfa
));
1087 fprintf(stderr
, " (NHH): 0x%08x\n", ufoImgGetU32(UFO_LFA_TO_NHASH(lfa
)));
1088 const uint32_t cfa
= UFO_LFA_TO_CFA(lfa
);
1089 fprintf(stderr
, " CFA: 0x%08x\n", cfa
);
1090 fprintf(stderr
, " PFA: 0x%08x\n", UFO_CFA_TO_PFA(cfa
));
1091 fprintf(stderr
, " (CFA): 0x%08x\n", ufoImgGetU32(cfa
));
1092 const uint32_t nfa
= UFO_LFA_TO_NFA(lfa
);
1093 const uint32_t nlen
= ufoImgGetU8(nfa
);
1094 fprintf(stderr
, " NFA: 0x%08x (nlen: %u)\n", nfa
, nlen
);
1095 const uint32_t flags
= ufoImgGetU32(nfa
);
1096 fprintf(stderr
, " FLAGS: 0x%08x\n", flags
);
1097 if ((flags
& 0xffff0000U
) != 0) {
1098 fprintf(stderr
, " FLAGS:");
1099 if (flags
& UFW_FLAG_IMMEDIATE
) fprintf(stderr
, " IMM");
1100 if (flags
& UFW_FLAG_SMUDGE
) fprintf(stderr
, " SMUDGE");
1101 if (flags
& UFW_FLAG_NORETURN
) fprintf(stderr
, " NORET");
1102 if (flags
& UFW_FLAG_HIDDEN
) fprintf(stderr
, " HIDDEN");
1103 if (flags
& UFW_FLAG_CBLOCK
) fprintf(stderr
, " CBLOCK");
1104 if (flags
& UFW_FLAG_VOCAB
) fprintf(stderr
, " VOCAB");
1105 if (flags
& UFW_FLAG_SCOLON
) fprintf(stderr
, " SCOLON");
1106 if (flags
& UFW_FLAG_PROTECTED
) fprintf(stderr
, " PROTECTED");
1107 fputc('\n', stderr
);
1109 if ((flags
& 0xff00U
) != 0) {
1110 fprintf(stderr
, " ARGS: ");
1111 switch (flags
& UFW_WARG_MASK
) {
1112 case UFW_WARG_NONE
: fprintf(stderr
, "NONE"); break;
1113 case UFW_WARG_BRANCH
: fprintf(stderr
, "BRANCH"); break;
1114 case UFW_WARG_LIT
: fprintf(stderr
, "LIT"); break;
1115 case UFW_WARG_C4STRZ
: fprintf(stderr
, "C4STRZ"); break;
1116 case UFW_WARG_CFA
: fprintf(stderr
, "CFA"); break;
1117 case UFW_WARG_CBLOCK
: fprintf(stderr
, "CBLOCK"); break;
1118 case UFW_WARG_VOCID
: fprintf(stderr
, "VOCID"); break;
1119 case UFW_WARG_C1STRZ
: fprintf(stderr
, "C1STRZ"); break;
1120 default: fprintf(stderr
, "wtf?!"); break;
1122 fputc('\n', stderr
);
1124 fprintf(stderr
, " BACKLEN: %u (nfa at 0x%08x)\n", ufoImgGetU8(cfa
- 1u), UFO_CFA_TO_NFA(cfa
));
1125 fprintf(stderr
, " NAME(%u): ", nlen
);
1126 for (uint32_t f
= 0; f
< nlen
; f
+= 1) {
1127 const uint8_t ch
= ufoImgGetU8(nfa
+ 4u + f
);
1128 if (ch
<= 32 || ch
>= 127) {
1129 fprintf(stderr
, "\\x%02x", ch
);
1131 fprintf(stderr
, "%c", (char)ch
);
1134 fprintf(stderr
, "\n");
1135 ufo_assert(UFO_CFA_TO_LFA(cfa
) == lfa
);
1140 //==========================================================================
1146 //==========================================================================
1147 static uint32_t ufoVocCheckName (uint32_t lfa
, const void *wname
, uint32_t wnlen
, uint32_t hash
,
1151 #ifdef UFO_DEBUG_FIND_WORD
1152 fprintf(stderr
, "CHECK-NAME: %.*s; LFA: 0x%08x; hash: 0x%08x (wname: 0x%08x)\n",
1153 (unsigned) wnlen
, (const char *)wname
,
1154 lfa
, (lfa
!= 0 ? ufoImgGetU32(UFO_LFA_TO_NHASH(lfa
)) : 0), hash
);
1155 ufoDumpWordHeader(lfa
);
1157 if (lfa
!= 0 && ufoImgGetU32(UFO_LFA_TO_NHASH(lfa
)) == hash
) {
1158 const uint32_t lenflags
= ufoImgGetU32(UFO_LFA_TO_NFA(lfa
));
1159 if ((lenflags
& UFW_FLAG_SMUDGE
) == 0 &&
1160 (allowvochid
|| (lenflags
& UFW_FLAG_HIDDEN
) == 0))
1162 const uint32_t nlen
= lenflags
&0xffU
;
1163 if (nlen
== wnlen
) {
1164 uint32_t naddr
= UFO_LFA_TO_NFA(lfa
) + 4u;
1166 while (pos
< nlen
) {
1167 uint8_t c0
= ((const unsigned char *)wname
)[pos
];
1168 if (c0
>= 'a' && c0
<= 'z') c0
= c0
- 'a' + 'A';
1169 uint8_t c1
= ufoImgGetU8(naddr
+ pos
);
1170 if (c1
>= 'a' && c1
<= 'z') c1
= c1
- 'a' + 'A';
1171 if (c0
!= c1
) break;
1177 res
= UFO_ALIGN4(naddr
);
1186 //==========================================================================
1192 //==========================================================================
1193 static uint32_t ufoFindWordInVoc (const void *wname
, uint32_t wnlen
, uint32_t hash
,
1194 uint32_t vocid
, int allowvochid
)
1197 if (wname
== NULL
) ufo_assert(wnlen
== 0);
1199 if (hash
== 0) hash
= joaatHashBufCI(wname
, wnlen
);
1200 #if defined(UFO_DEBUG_FIND_WORD) || defined(UFO_DEBUG_FIND_WORD_IN_VOC)
1201 fprintf(stderr
, "IN-VOC: %.*s; VOCID: 0x%08x; whash: 0x%08x; htbl[0]: 0x%08x\n",
1202 (unsigned) wnlen
, (const char *)wname
,
1203 vocid
, hash
, ufoImgGetU32(vocid
+ UFW_VOCAB_OFS_HTABLE
));
1205 const uint32_t htbl
= vocid
+ UFW_VOCAB_OFS_HTABLE
;
1206 if (ufoImgGetU32(htbl
) != UFO_NO_HTABLE_FLAG
) {
1207 // hash table present, use it
1208 uint32_t bfa
= htbl
+ (hash
% (uint32_t)UFO_HASHTABLE_SIZE
) * 4u;
1209 bfa
= ufoImgGetU32(bfa
);
1210 while (res
== 0 && bfa
!= 0) {
1211 #if defined(UFO_DEBUG_FIND_WORD) || defined(UFO_DEBUG_FIND_WORD_IN_VOC)
1212 fprintf(stderr
, "IN-VOC: bfa: 0x%08x\n", bfa
);
1214 res
= ufoVocCheckName(UFO_BFA_TO_LFA(bfa
), wname
, wnlen
, hash
, allowvochid
);
1215 bfa
= ufoImgGetU32(bfa
);
1218 // no hash table, use linear search
1219 uint32_t lfa
= vocid
+ UFW_VOCAB_OFS_LATEST
;
1220 lfa
= ufoImgGetU32(lfa
);
1221 while (res
== 0 && lfa
!= 0) {
1222 res
= ufoVocCheckName(lfa
, wname
, wnlen
, hash
, allowvochid
);
1223 lfa
= ufoImgGetU32(lfa
);
1231 //==========================================================================
1235 // return part after the colon, or `NULL`
1237 //==========================================================================
1238 static const void *ufoFindColon (const void *wname
, uint32_t wnlen
) {
1239 const void *res
= NULL
;
1241 ufo_assert(wname
!= NULL
);
1242 const char *str
= (const char *)wname
;
1243 while (wnlen
!= 0 && str
[0] != ':') {
1244 str
+= 1; wnlen
-= 1;
1247 res
= (const void *)(str
+ 1); // skip colon
1254 //==========================================================================
1256 // ufoFindWordNameRes
1258 // find with name resolution
1262 //==========================================================================
1263 static uint32_t ufoFindWordNameRes (const void *wname
, uint32_t wnlen
) {
1265 if (wnlen
!= 0 && *(const char *)wname
!= ':') {
1266 ufo_assert(wname
!= NULL
);
1268 const void *stx
= wname
;
1269 wname
= ufoFindColon(wname
, wnlen
);
1270 if (wname
!= NULL
) {
1271 // look in all vocabs (excluding hidden ones)
1272 uint32_t xlen
= (uint32_t)(ptrdiff_t)(wname
- stx
) - 1u;
1273 ufo_assert(xlen
> 0 && xlen
< 255);
1274 uint32_t xhash
= joaatHashBufCI(stx
, xlen
);
1275 uint32_t voclink
= ufoImgGetU32(ufoAddrVocLink
);
1276 #ifdef UFO_DEBUG_FIND_WORD_COLON
1277 fprintf(stderr
, "COLON-FIND: first voc: {%.*s}; xhash=0x%08x; voc-link: 0x%08x\n",
1278 (unsigned)xlen
, (const char *)stx
, xhash
, voclink
);
1280 while (res
== 0 && voclink
!= 0) {
1281 const uint32_t vhdraddr
= voclink
- UFW_VOCAB_OFS_VOCLINK
+ UFW_VOCAB_OFS_HEADER
;
1282 const uint32_t vhdr
= ufoImgGetU32(vhdraddr
);
1284 res
= ufoVocCheckName(UFO_NFA_TO_LFA(vhdr
), stx
, xlen
, xhash
, 0);
1286 if (res
== 0) voclink
= ufoImgGetU32(voclink
);
1289 uint32_t vocid
= voclink
- UFW_VOCAB_OFS_VOCLINK
;
1290 ufo_assert(voclink
!= 0);
1292 #ifdef UFO_DEBUG_FIND_WORD_COLON
1293 fprintf(stderr
, "searching {%.*s}(%u) in {%.*s}\n",
1294 (unsigned)wnlen
, wname
, wnlen
, (unsigned)xlen
, stx
);
1296 while (res
!= 0 && wname
!= NULL
) {
1298 wname
= ufoFindColon(wname
, wnlen
);
1299 if (wname
== NULL
) xlen
= wnlen
; else xlen
= (uint32_t)(ptrdiff_t)(wname
- stx
) - 1u;
1300 ufo_assert(xlen
> 0 && xlen
< 255);
1301 res
= ufoFindWordInVoc(stx
, xlen
, 0, vocid
, 1);
1304 if (wname
!= NULL
) {
1305 // it should be a vocabulary
1306 const uint32_t nfa
= UFO_CFA_TO_NFA(res
);
1307 if ((ufoImgGetU32(nfa
) & UFW_FLAG_VOCAB
) != 0) {
1308 vocid
= ufoImgGetU32(UFO_CFA_TO_PFA(res
)); // pfa points to vocabulary
1323 //==========================================================================
1327 // doesn't look in CURRENT, does name resolution ("a:b" is word "b" in "a")
1331 //==========================================================================
1332 static uint32_t ufoFindWord (const char *wname
) {
1334 if (wname
&& wname
[0] != 0) {
1335 const size_t wnlen
= strlen(wname
);
1336 ufo_assert(wnlen
< 8192);
1337 uint32_t ctx
= ufoImgGetU32(ufoAddrContext
);
1338 const uint32_t hash
= joaatHashBufCI(wname
, (uint32_t)wnlen
);
1340 //fprintf(stderr, "FIND-WORD: whash: 0x%08x; name:{%s}\n", hash, wname);
1342 // first search in context
1343 res
= ufoFindWordInVoc(wname
, (uint32_t)wnlen
, hash
, ctx
, (ctx
== ufoImgGetU32(ufoAddrCurrent
)));
1346 if (res
== 0 && ctx
!= 0) {
1347 ctx
= ufoImgGetU32(ctx
+ UFW_VOCAB_OFS_PARENT
);
1348 while (res
!= 0 && ctx
!= 0) {
1349 res
= ufoFindWordInVoc(wname
, (uint32_t)wnlen
, hash
, ctx
, (ctx
== ufoImgGetU32(ufoAddrCurrent
)));
1350 ctx
= ufoImgGetU32(ctx
+ UFW_VOCAB_OFS_PARENT
);
1354 // now try vocabulary stack
1355 uint32_t vstp
= ufoVSP
;
1356 while (res
== 0 && vstp
!= 0) {
1358 ctx
= ufoVocStack
[vstp
];
1359 res
= ufoFindWordInVoc(wname
, (uint32_t)wnlen
, hash
, ctx
, (ctx
== ufoImgGetU32(ufoAddrCurrent
)));
1362 // if not found, try name resolution
1363 if (res
== 0) res
= ufoFindWordNameRes(wname
, (uint32_t)wnlen
);
1370 //==========================================================================
1374 //==========================================================================
1375 static uint32_t ufoFindWordMacro (const char *wname
) {
1376 if (!wname
|| wname
[0] == 0) return 0;
1377 const size_t wnlen
= strlen(wname
);
1378 ufo_assert(wnlen
< 8192);
1379 return ufoFindWordInVoc(wname
, (uint32_t)wnlen
, 0, ufoMacroVocId
, 0);
1383 //==========================================================================
1385 // ufoCreateWordHeader
1387 // create word header up to CFA, link to the current dictionary
1389 //==========================================================================
1390 static void ufoCreateWordHeader (const char *wname
, uint32_t flags
) {
1391 if (wname
== NULL
) wname
= "";
1392 const size_t wnlen
= strlen(wname
);
1393 ufo_assert(wnlen
< UFO_MAX_WORD_LENGTH
);
1394 const uint32_t hash
= joaatHashBufCI(wname
, (uint32_t)wnlen
);
1395 const uint32_t curr
= ufoImgGetU32(ufoAddrCurrent
);
1396 ufo_assert(curr
!= 0);
1398 const uint32_t cfa
= ufoFindWordInVoc(wname
, wnlen
, hash
, curr
, 1);
1400 const uint32_t nfa
= UFO_CFA_TO_NFA(cfa
);
1401 const uint32_t flags
= ufoImgGetU32(nfa
);
1402 if ((flags
& UFW_FLAG_PROTECTED
) != 0) {
1403 ufoFatal("trying to redefine protected word '%s'", wname
);
1405 ufoWarning("redefining word '%s'", wname
);
1409 //fprintf(stderr, "000: HERE: 0x%08x\n", UFO_GET_DP());
1410 const uint32_t bkt
= (hash
% (uint32_t)UFO_HASHTABLE_SIZE
) * 4u;
1411 const uint32_t htbl
= curr
+ UFW_VOCAB_OFS_HTABLE
;
1413 ufoImgEmitU32(0); // dfa
1414 ufoImgEmitU32(0); // sfa
1415 // bucket link (bfa)
1416 if (wnlen
== 0 || ufoImgGetU32(htbl
) == UFO_NO_HTABLE_FLAG
) {
1419 #ifdef UFO_DEBUG_DUMP_NEW_HEADERS
1420 fprintf(stderr
, "NEW HEADER: %s; curr: 0x%08x; htbl: 0x%08x; bkt: 0x%08x\n",
1421 wname
, curr
, htbl
, bkt
);
1422 fprintf(stderr
, " [bkt]: 0x%08x; nbk: 0x%08x\n", ufoImgGetU32(htbl
+ bkt
), UFO_GET_DP());
1424 // bfa points to bfa
1425 const uint32_t bfa
= UFO_GET_DP();
1426 ufoImgEmitU32(ufoImgGetU32(htbl
+ bkt
));
1427 ufoImgPutU32(htbl
+ bkt
, bfa
);
1430 const uint32_t lfa
= UFO_GET_DP();
1431 ufoImgEmitU32(ufoImgGetU32(curr
+ UFW_VOCAB_OFS_LATEST
));
1433 ufoImgPutU32(curr
+ UFW_VOCAB_OFS_LATEST
, lfa
);
1435 ufoImgEmitU32(hash
);
1437 const uint32_t nfa
= UFO_GET_DP();
1438 ufoImgEmitU32(((uint32_t)wnlen
&0xffU
) | (flags
& 0xffffff00U
));
1439 const uint32_t nstart
= UFO_GET_DP();
1441 for (size_t f
= 0; f
< wnlen
; f
+= 1) {
1442 ufoImgEmitU8(((const unsigned char *)wname
)[f
]);
1444 while ((UFO_GET_DP() & 3) != 3) ufoImgEmitU8(0);
1445 const uint32_t nend
= UFO_GET_DP(); // length byte itself is not included
1446 // name length, again
1447 ufo_assert(nend
- nstart
<= 255);
1448 ufoImgEmitU8((uint8_t)(nend
- nstart
));
1449 ufo_assert((UFO_GET_DP() & 3) == 0);
1450 ufo_assert(UFO_CFA_TO_NFA(UFO_GET_DP()) == nfa
);
1451 #ifdef UFO_DEBUG_DUMP_NEW_HEADERS
1452 fprintf(stderr
, "*** NEW HEADER ***\n");
1453 fprintf(stderr
, "CFA: 0x%08x\n", UFO_GET_DP());
1454 fprintf(stderr
, "NSTART: 0x%08x\n", nstart
);
1455 fprintf(stderr
, "NEND: 0x%08x\n", nend
);
1456 fprintf(stderr
, "NLEN: %u (%u)\n", nend
- nstart
, ufoImgGetU8(UFO_GET_DP() - 1u));
1457 ufoDumpWordHeader(lfa
);
1460 fprintf(stderr
, "NEW WORD CFA 0x%08x: %s\n", UFO_GET_DP(), wname
);
1465 //==========================================================================
1469 //==========================================================================
1470 static void ufoDecompilePart (uint32_t addr
, uint32_t eaddr
, int indent
) {
1473 while (addr
< eaddr
) {
1474 uint32_t cfa
= ufoImgGetU32(addr
);
1475 for (int n
= 0; n
< indent
; n
+= 1) fputc(' ', fo
);
1476 fprintf(fo
, "%6u: 0x%08x: ", addr
, cfa
);
1477 uint32_t nfa
= UFO_CFA_TO_NFA(cfa
);
1478 uint32_t flags
= ufoImgGetU32(nfa
);
1479 //fprintf(fo, "[0x%08x] ", flags & UFW_WARG_MASK);
1480 uint32_t nlen
= flags
& 0xffU
;
1481 for (uint32_t f
= 0; f
< nlen
; f
+= 1) {
1482 const uint8_t ch
= ufoImgGetU8(nfa
+ 4u + f
);
1483 if (ch
<= 32 || ch
>= 127) {
1484 fprintf(fo
, "\\x%02x", ch
);
1486 fprintf(fo
, "%c", (char)ch
);
1490 switch (flags
& UFW_WARG_MASK
) {
1493 case UFW_WARG_BRANCH
:
1494 fprintf(fo
, " @%u", ufoImgGetU32(addr
)); addr
+= 4u;
1497 fprintf(fo
, " %u : %d : 0x%08x", ufoImgGetU32(addr
),
1498 (int32_t)ufoImgGetU32(addr
), ufoImgGetU32(addr
)); addr
+= 4u;
1500 case UFW_WARG_C4STRZ
:
1501 count
= ufoImgGetU32(addr
); addr
+= 4;
1503 fprintf(fo
, " str:");
1504 for (int f
= 0; f
< count
; f
+= 1) {
1505 const uint8_t ch
= ufoImgGetU8(addr
); addr
+= 1u;
1506 if (ch
<= 32 || ch
>= 127) {
1507 fprintf(fo
, "\\x%02x", ch
);
1509 fprintf(fo
, "%c", (char)ch
);
1512 addr
+= 1u; // skip zero byte
1513 addr
= UFO_ALIGN4(addr
);
1516 cfa
= ufoImgGetU32(addr
); addr
+= 4u;
1517 fprintf(fo
, " CFA:%u: ", cfa
);
1518 nfa
= UFO_CFA_TO_NFA(cfa
);
1519 nlen
= ufoImgGetU8(nfa
);
1520 for (uint32_t f
= 0; f
< nlen
; f
+= 1) {
1521 const uint8_t ch
= ufoImgGetU8(nfa
+ 4u + f
);
1522 if (ch
<= 32 || ch
>= 127) {
1523 fprintf(fo
, "\\x%02x", ch
);
1525 fprintf(fo
, "%c", (char)ch
);
1529 case UFW_WARG_CBLOCK
:
1530 fprintf(fo
, " CBLOCK:%u", ufoImgGetU32(addr
)); addr
+= 4u;
1532 case UFW_WARG_VOCID
:
1533 fprintf(fo
, " VOCID:%u", ufoImgGetU32(addr
)); addr
+= 4u;
1535 case UFW_WARG_C1STRZ
:
1536 count
= ufoImgGetU8(addr
); addr
+= 1;
1540 fprintf(fo, " ubyte:%u", ufoImgGetU8(addr)); addr += 1u;
1543 fprintf(fo, " sbyte:%u", ufoImgGetU8(addr)); addr += 1u;
1546 fprintf(fo, " uword:%u", ufoImgGetU16(addr)); addr += 2u;
1549 fprintf(fo, " sword:%u", ufoImgGetU16(addr)); addr += 2u;
1553 fprintf(fo
, " -- WTF?!\n");
1561 //==========================================================================
1565 //==========================================================================
1566 static void ufoDecompileWord (const uint32_t cfa
) {
1568 const uint32_t lfa
= UFO_CFA_TO_LFA(cfa
);
1569 fprintf(stdout
, "#### DECOMPILING CFA %u ###\n", cfa
);
1570 ufoDumpWordHeader(lfa
);
1571 const uint32_t sfa
= ufoImgGetU32(UFO_LFA_TO_SFA(lfa
));
1572 if (ufoImgGetU32(cfa
) == ufoDoForthCFA
) {
1573 fprintf(stdout
, "--- DECOMPILED CODE ---\n");
1574 ufoDecompilePart(UFO_CFA_TO_PFA(cfa
), sfa
, 0);
1575 fprintf(stdout
, "=======================\n");
1581 //==========================================================================
1587 // WARNING: this is SLOW!
1589 //==========================================================================
1590 static uint32_t ufoFindWordForIP (const uint32_t ip
) {
1593 // iterate over all vocabs
1594 uint32_t voclink
= ufoImgGetU32(ufoAddrVocLink
);
1595 while (res
== 0 && voclink
!= 0) {
1596 // iterate over all words
1597 const uint32_t vocid
= voclink
- UFW_VOCAB_OFS_VOCLINK
;
1598 uint32_t lfa
= ufoImgGetU32(vocid
+ UFW_VOCAB_OFS_LATEST
);
1599 while (res
== 0 && lfa
!= 0) {
1600 const uint32_t cfa
= UFO_LFA_TO_CFA(lfa
);
1601 const uint32_t pfa
= UFO_CFA_TO_PFA(cfa
);
1602 const uint32_t sfa
= ufoImgGetU32(UFO_LFA_TO_SFA(lfa
));
1603 //fprintf(stderr, "IP: 0x%08x; lfa:0x%08x; cfa:0x%08x; sfa:0x%08x\n", ip, lfa, cfa, sfa);
1604 if (ip
>= pfa
&& ip
< sfa
) {
1605 res
= UFO_LFA_TO_NFA(lfa
);
1607 lfa
= ufoImgGetU32(lfa
);
1610 if (res
== 0) voclink
= ufoImgGetU32(vocid
+ UFW_VOCAB_OFS_VOCLINK
);
1617 //==========================================================================
1619 // ufoBTShowWordName
1621 //==========================================================================
1622 static void ufoBTShowWordName (uint32_t nfa
) {
1624 uint32_t len
= ufoImgGetU8(nfa
); nfa
+= 4u;
1625 //fprintf(stderr, "(0x%08x)", ufoImgGetU32(nfa - 4u));
1627 uint8_t ch
= ufoImgGetU8(nfa
); nfa
+= 1u; len
-= 1u;
1628 if (ch
<= 32 || ch
>= 127) {
1629 fprintf(stderr
, "\\x%02x", ch
);
1631 fprintf(stderr
, "%c", (char)ch
);
1638 //==========================================================================
1642 //==========================================================================
1643 static void ufoBacktrace (uint32_t ip
) {
1644 // dump data stack (top 16)
1645 if (!ufoLastEmitWasCR
) { printf("\n"); ufoLastEmitWasCR
= 1; }
1648 fprintf(stderr
, "***UFO STACK DEPTH: %u\n", ufoSP
);
1649 uint32_t xsp
= ufoSP
;
1650 if (xsp
> 16) xsp
= 16;
1651 for (uint32_t sp
= 0; sp
< xsp
; ++sp
) {
1652 fprintf(stderr
, " %2u: 0x%08x %d\n", sp
,
1653 ufoDStack
[xsp
- sp
- 1], (int32_t)ufoDStack
[xsp
- sp
- 1]);
1655 if (ufoSP
> 16) fprintf(stderr
, " ...more...\n");
1657 // dump return stack (top 32)
1659 fprintf(stderr
, "***UFO RETURN STACK DEPTH: %u\n", ufoRP
);
1661 nfa
= ufoFindWordForIP(ip
);
1663 fprintf(stderr
, " **: %8u -- ", ip
);
1664 ufoBTShowWordName(nfa
);
1665 fputc('\n', stderr
);
1668 uint32_t rp
= ufoRP
;
1669 uint32_t rscount
= 0;
1670 if (rp
> UFO_RSTACK_SIZE
) rp
= UFO_RSTACK_SIZE
;
1671 while (rscount
!= 32 && rp
!= 0) {
1673 const uint32_t val
= ufoRStack
[rp
];
1674 nfa
= ufoFindWordForIP(val
);
1676 fprintf(stderr
, " %2u: %8u -- ", ufoRP
- rp
- 1u, val
);
1677 ufoBTShowWordName(nfa
);
1678 fputc('\n', stderr
);
1680 fprintf(stderr
, " %2u: 0x%08x %d\n", ufoRP
- rp
- 1u, val
, (int32_t)val
);
1684 if (ufoRP
> 32) fprintf(stderr
, " ...more...\n");
1690 //==========================================================================
1694 //==========================================================================
1696 static void ufoDumpVocab (uint32_t vocid) {
1698 fprintf(stderr, "*** VOCID: 0x%08x ***\n", vocid);
1699 uint32_t vochdr = vocid + UFW_VOCAB_OFS_HEADER;
1700 vochdr = ufoImgGetU32(vochdr);
1702 fprintf(stderr, "--- HEADER ---\n");
1703 ufoDumpWordHeader(UFO_NFA_TO_LFA(vochdr));
1704 fprintf(stderr, "========\n");
1705 uint32_t htbl = vocid + UFW_VOCAB_OFS_HTABLE;
1706 if (ufoImgGetU32(htbl) != UFO_NO_HTABLE_FLAG) {
1707 fprintf(stderr, "--- HASH TABLE ---\n");
1708 for (int f = 0; f < UFO_HASHTABLE_SIZE; f += 1) {
1709 uint32_t bfa = ufoImgGetU32(htbl);
1711 fprintf(stderr, "**** %2d: 0x%08x\n", f, bfa);
1713 ufoDumpWordHeader(UFO_BFA_TO_LFA(bfa));
1714 bfa = ufoImgGetU32(bfa);
1726 //==========================================================================
1730 //==========================================================================
1731 static void ufoSetNextLine (const char *text
) {
1732 if (text
== NULL
) text
= "";
1734 ufoImgPutU32(ufoAddrTIB
, 0);
1735 ufoImgPutU32(ufoAddrIN
, 0);
1738 size_t sslen
= strlen(text
);
1739 while (sslen
!= 0 && (text
[sslen
- 1u] == 13 || text
[sslen
- 1u] == 10)) sslen
-= 1;
1740 if (sslen
> 510) ufoFatal("input line too long");
1741 if (sslen
>= ufoTIBAreaSize
) ufoFatal("input line too long");
1743 #ifdef UFO_DEBUG_INCLUDE
1744 fprintf(stderr
, "NEXT-LINE: <%.*s>\n", (unsigned)sslen
, (const char *)text
);
1748 while (dpos
!= (uint32_t)sslen
) {
1749 uint8_t ch
= ((const unsigned char *)text
)[dpos
];
1750 // replace bad chars, because why not
1751 if (ch
== 0 || ch
== 13 || ch
== 10) ch
= 32;
1752 ufoImgPutU8(dpos
, ch
); dpos
+= 1;
1754 ufoImgPutU8(dpos
, 0);
1758 //==========================================================================
1760 // ufoLoadNextLine_NativeMode
1762 // load next file line into TIB
1763 // always strips final '\n'
1765 //==========================================================================
1766 static void ufoLoadNextLine_NativeMode (int crossInclude
) {
1767 const char *text
= NULL
;
1771 while (ufoInFile
&& done
== 0) {
1772 if (fgets(ufoCurrFileLine
, 510, ufoInFile
) != NULL
) {
1773 // check for a newline
1774 // if there is no newline char at the end, the string was truncated
1775 ufoCurrFileLine
[510] = 0;
1776 uint32_t slen
= (uint32_t)strlen(ufoCurrFileLine
);
1777 if (slen
== 0 || (ufoCurrFileLine
[slen
- 1u] != 13 && ufoCurrFileLine
[slen
- 1u] != 10)) {
1778 ufoFatal("input line too long");
1781 text
= ufoCurrFileLine
;
1783 #if defined(UFO_DEBUG_INCLUDE) && 0
1784 fprintf(stderr
, "READ LINE: %s", text
);
1787 if (!crossInclude
) {
1788 if (ufoCondStLine
>= 0) {
1789 ufoFatal("unfinished conditional from line %d", ufoCondStLine
);
1791 ufoFatal("unexpected end of text");
1800 text
= ufoGetSrcLine(&fname
, &lnum
);
1802 if (ufoCondStLine
>= 0) {
1803 ufoFatal("unfinished conditional from line %d", ufoCondStLine
);
1805 ufoFatal("unexpected end of text");
1807 ufoInFileLine
= lnum
;
1808 if (ufoInFileName
== NULL
|| strcmp(ufoInFileName
, fname
) != 0) {
1809 if (ufoInFileName
!= NULL
) free(ufoInFileName
);
1810 ufoInFileName
= strdup(fname
);
1811 setLastIncPath(ufoInFileName
);
1815 ufoSetNextLine(text
);
1819 //==========================================================================
1823 //==========================================================================
1824 static void ufoLoadMacroLine (const char *line
, const char *fname
, int lnum
) {
1825 const char *text
= line
;
1826 if (text
== NULL
) text
= "";
1827 if (fname
== NULL
) fname
= "";
1829 ufoInFileLine
= lnum
;
1830 if (ufoInFileName
== NULL
|| strcmp(ufoInFileName
, fname
) != 0) {
1831 if (ufoInFileName
!= NULL
) free(ufoInFileName
);
1832 ufoInFileName
= strdup(fname
);
1833 setLastIncPath(ufoInFileName
);
1836 ufoSetNextLine(text
);
1840 //==========================================================================
1844 // load next file line into TIB
1845 // return zero on success, -1 on EOF, -2 on error
1847 //==========================================================================
1848 static void ufoLoadNextLine (int crossInclude
) {
1850 case UFO_MODE_NATIVE
:
1851 ufoLoadNextLine_NativeMode(crossInclude
);
1853 case UFO_MODE_MACRO
:
1854 if (ufoCondStLine
>= 0) {
1855 ufoFatal("unfinished conditional from line %d", ufoCondStLine
);
1857 ufoFatal("unexpected end of input for FORTH asm macro");
1859 default: ufoFatal("wtf?! not properly inited!");
1864 // ////////////////////////////////////////////////////////////////////////// //
1865 #define UFWORD(name_) \
1866 static void ufoWord_##name_ (uint32_t mypfa)
1868 #define UFCALL(name_) ufoWord_##name_(0)
1869 #define UFCFA(name_) (&ufoWord_##name_)
1872 // ////////////////////////////////////////////////////////////////////////// //
1877 UFWORD(DUMP_STACK
) {
1878 if (!ufoLastEmitWasCR
) { printf("\n"); ufoLastEmitWasCR
= 1; }
1879 printf("***UFO STACK DEPTH: %u\n", ufoSP
);
1881 uint32_t sp
= ufoSP
;
1882 while (sp
!= 0 && left
!= 0) {
1884 printf(" %4u: 0x%08x %d\n", sp
, ufoDStack
[sp
], (int32_t)ufoDStack
[sp
]);
1886 if (sp
!= 0) printf("...more...\n");
1887 ufoLastEmitWasCR
= 1;
1891 UFWORD(UFO_BACKTRACE
) {
1892 if (!ufoLastEmitWasCR
) { printf("\n"); ufoLastEmitWasCR
= 1; }
1894 if (ufoInFile
!= NULL
) {
1895 fprintf(stderr
, "*** at file %s, line %d ***\n", ufoInFileName
, ufoInFileLine
);
1897 fprintf(stderr
, "*** somewhere in time ***\n");
1899 ufoBacktrace(ufoIP
);
1902 #include "urforth_dbg.c"
1907 if (!ufoLastEmitWasCR
) { printf("\n"); ufoLastEmitWasCR
= 1; }
1909 ufoFatal("there is no UFO debug breakpoint support in windoze");
1911 if (isatty(STDIN_FILENO
) && isatty(STDOUT_FILENO
)) {
1914 fprintf(stderr
, "WARNING: cannot start UFO debug session, because standard streams are not on TTY!\n");
1920 // ////////////////////////////////////////////////////////////////////////// //
1923 UFWORD(SP0_STORE
) { ufoSP
= 0; }
1928 if (ufoRP
!= ufoRPTop
) {
1930 // we need to push a dummy value
1931 ufoRPush(0xdeadf00d);
1937 // PAD is at the beginning of temp area
1939 ufoPush(UFO_ADDR_TEMP_BIT
);
1943 // ( addr -- value32 )
1944 UFWORD(PEEK
) { const uint32_t addr
= ufoPop(); ufoPush(ufoImgGetU32(addr
)); }
1947 // ( addr -- value8 )
1948 UFWORD(CPEEK
) { const uint32_t addr
= ufoPop(); ufoPush(ufoImgGetU8(addr
)); }
1951 // ( addr -- value32 )
1952 UFWORD(WPEEK
) { const uint32_t addr
= ufoPop(); ufoPush(ufoImgGetU16(addr
)); }
1955 // ( val32 addr -- )
1956 UFWORD(POKE
) { const uint32_t addr
= ufoPop(); const uint32_t val
= ufoPop(); ufoImgPutU32(addr
, val
); }
1960 UFWORD(CPOKE
) { const uint32_t addr
= ufoPop(); const uint32_t val
= ufoPop(); ufoImgPutU8(addr
, val
&0xffU
); }
1963 // ( val32 addr -- )
1964 UFWORD(WPOKE
) { const uint32_t addr
= ufoPop(); const uint32_t val
= ufoPop(); ufoImgPutU16(addr
, val
&0xffffU
); }
1968 UFWORD(CCOMMA
) { const uint32_t val
= ufoPop(); ufoImgEmitU8(val
); }
1972 UFWORD(WCOMMA
) { const uint32_t val
= ufoPop(); ufoImgEmitU8(val
&0xffU
); ufoImgEmitU8((val
>> 8)&0xffU
); }
1976 UFWORD(COMMA
) { const uint32_t val
= ufoPop(); ufoImgEmitU32(val
); }
1981 // puts byte to zx dictionary
1983 const uint32_t val
= ufoPop()&0xffU
;
1989 // puts word to zx dictionary
1991 const uint32_t val
= ufoPop();
1992 ufoZXEmitU16(val
&0xffffU
);
1996 // ( addr -- value8 )
1997 UFWORD(ZX_CPEEK
) { const uint32_t addr
= ufoPop(); ufoPush(ufoZXGetU8(addr
)); }
2001 UFWORD(ZX_CPOKE
) { const uint32_t addr
= ufoPop(); const uint32_t val
= ufoPop(); ufoZXPutU8(addr
, val
); }
2004 // ( addr -- value16 )
2005 UFWORD(ZX_WPEEK
) { const uint32_t addr
= ufoPop(); ufoPush(ufoZXGetU16(addr
)); }
2008 // ( val16 addr -- )
2009 UFWORD(ZX_WPOKE
) { const uint32_t addr
= ufoPop(); const uint32_t val
= ufoPop(); ufoZXPutU16(addr
, val
); }
2013 UFWORD(ZX_RESERVEDQ
) {
2014 const uint32_t addr
= ufoPop();
2015 ufoPushBool(ufoZXGetReserved(addr
));
2020 UFWORD(ZX_RESERVEDS
) {
2021 const uint32_t addr
= ufoPop();
2022 const uint32_t flag
= ufoPop();
2023 ufoZXSetReserved(addr
, (flag
? 1 : 0));
2029 const uint32_t v
= ufoImgGetU32(ufoIP
); ufoIP
+= 4;
2033 // (LITCFA) ( -- n )
2034 UFWORD(PAR_LITCFA
) {
2035 const uint32_t v
= ufoImgGetU32(ufoIP
); ufoIP
+= 4;
2039 // (LITVOCID) ( -- n )
2040 UFWORD(PAR_LITVOCID
) {
2041 const uint32_t v
= ufoImgGetU32(ufoIP
); ufoIP
+= 4;
2046 UFWORD(PAR_STRLIT8
) {
2047 const uint32_t count
= ufoImgGetU8(ufoIP
); ufoIP
+= 1;
2050 ufoIP
+= count
+ 1; // 1 for terminating 0
2052 ufoIP
= UFO_ALIGN4(ufoIP
);
2056 UFWORD(PAR_BRANCH
) {
2057 ufoIP
= ufoImgGetU32(ufoIP
);
2060 // (TBRANCH) ( flag )
2061 UFWORD(PAR_TBRANCH
) {
2063 ufoIP
= ufoImgGetU32(ufoIP
);
2069 // (0BRANCH) ( flag )
2070 UFWORD(PAR_0BRANCH
) {
2072 ufoIP
= ufoImgGetU32(ufoIP
);
2083 // EXECUTE-TAIL ( cfa )
2084 UFWORD(EXECUTE_TAIL
) {
2096 UFWORD(PAR_LENTER
) {
2097 // low byte of loccount is total number of locals
2098 // high byte is the number of args
2099 uint32_t lcount
= ufoImgGetU32(ufoIP
); ufoIP
+= 4u;
2100 uint32_t acount
= (lcount
>> 8) & 0xff;
2102 if (lcount
== 0 || lcount
< acount
) ufoFatal("invalid call to (L-ENTER)");
2103 if ((ufoLBP
!= 0 && ufoLBP
>= ufoLP
) || UFO_LSTACK_SIZE
- ufoLP
<= lcount
+ 2) {
2104 ufoFatal("out of locals stack");
2107 if (ufoLP
== 0) { ufoLP
= 1; newbp
= 1; } else newbp
= ufoLP
;
2108 //fprintf(stderr, "LP: %u; LBP: %u; locs: %u; word: %s\n", ufoLP, ufoLBP, fw->locs, fw->name);
2109 ufoLStack
[ufoLP
] = ufoLBP
; ufoLP
+= 1;
2110 ufoLBP
= newbp
; ufoLP
+= lcount
;
2113 while (newbp
!= ufoLBP
) {
2114 ufoLStack
[newbp
] = ufoPop();
2120 UFWORD(PAR_LLEAVE
) {
2121 if (ufoLBP
== 0) ufoFatal("(L-LEAVE) with empty locals stack");
2122 if (ufoLBP
>= ufoLP
) ufoFatal("(L-LEAVE) broken locals stack");
2124 ufoLBP
= ufoLStack
[ufoLBP
];
2128 //==========================================================================
2132 //==========================================================================
2133 UFO_FORCE_INLINE
void ufoLoadLocal (const uint32_t lidx
) {
2134 if (lidx
== 0 || lidx
>= UFO_LSTACK_SIZE
) ufoFatal("invalid local index");
2135 if (ufoLBP
== 0 || ufoLBP
>= ufoLP
|| ufoLP
- ufoLBP
<= lidx
) ufoFatal("invalid local index");
2136 ufoPush(ufoLStack
[ufoLBP
+ lidx
]);
2140 //==========================================================================
2144 //==========================================================================
2145 UFO_FORCE_INLINE
void ufoStoreLocal (const uint32_t lidx
) {
2146 const uint32_t value
= ufoPop();
2147 if (lidx
== 0 || lidx
>= UFO_LSTACK_SIZE
) ufoFatal("invalid local index");
2148 if (ufoLBP
== 0 || ufoLBP
>= ufoLP
|| ufoLP
- ufoLBP
<= lidx
) ufoFatal("invalid local index");
2149 ufoLStack
[ufoLBP
+ lidx
] = value
;
2155 UFWORD(PAR_LOCAL_LOAD
) { ufoLoadLocal(ufoPop()); }
2159 UFWORD(PAR_LOCAL_STORE
) { ufoStoreLocal(ufoPop()); }
2163 UFWORD(DUP
) { ufoDup(); }
2164 // ?DUP ( n -- n n ) | ( 0 -- 0 )
2165 UFWORD(QDUP
) { if (ufoPeek()) ufoDup(); }
2166 // 2DUP ( n0 n1 -- n0 n1 n0 n1 ) | ( 0 -- 0 )
2167 UFWORD(DDUP
) { ufo2Dup(); }
2169 UFWORD(DROP
) { ufoDrop(); }
2171 UFWORD(DDROP
) { ufo2Drop(); }
2172 // SWAP ( n0 n1 -- n1 n0 )
2173 UFWORD(SWAP
) { ufoSwap(); }
2174 // 2SWAP ( n0 n1 -- n1 n0 )
2175 UFWORD(DSWAP
) { ufo2Swap(); }
2176 // OVER ( n0 n1 -- n0 n1 n0 )
2177 UFWORD(OVER
) { ufoOver(); }
2178 // 2OVER ( n0 n1 -- n0 n1 n0 )
2179 UFWORD(DOVER
) { ufo2Over(); }
2180 // ROT ( n0 n1 n2 -- n1 n2 n0 )
2181 UFWORD(ROT
) { ufoRot(); }
2182 // NROT ( n0 n1 n2 -- n2 n0 n1 )
2183 UFWORD(NROT
) { ufoNRot(); }
2185 // RDUP ( n -- n n )
2186 UFWORD(RDUP
) { ufoRDup(); }
2188 UFWORD(RDROP
) { ufoRDrop(); }
2191 UFWORD(DTOR
) { ufoRPush(ufoPop()); }
2192 // R> ( -- n | n-removed )
2193 UFWORD(RTOD
) { ufoPush(ufoRPop()); }
2194 // R@ ( -- n | n-removed )
2195 UFWORD(RPEEK
) { ufoPush(ufoRPeek()); }
2198 // PICK ( idx -- n )
2200 const uint32_t n
= ufoPop();
2201 if (n
>= ufoSP
) ufoFatal("invalid PICK index %u", n
);
2202 ufoPush(ufoDStack
[ufoSP
- n
- 1u]);
2205 // RPICK ( idx -- n )
2207 const uint32_t n
= ufoPop();
2208 if (n
>= ufoRP
) ufoFatal("invalid RPICK index %u", n
);
2209 const uint32_t rp
= ufoRP
- n
- 1u;
2210 if (rp
<= ufoRPTop
) ufoFatal("invalid RPICK index %u", n
);
2211 ufoPush(ufoRStack
[rp
]);
2214 // ROLL ( idx -- n )
2216 const uint32_t n
= ufoPop();
2217 if (n
>= ufoSP
) ufoFatal("invalid ROLL index %u", n
);
2219 case 0: break; // do nothing
2220 case 1: ufoSwap(); break;
2221 case 2: ufoRot(); break;
2224 const uint32_t val
= ufoDStack
[ufoSP
- n
- 1u];
2225 for (uint32_t f
= ufoSP
- n
; f
< ufoSP
; f
+= 1) ufoDStack
[f
- 1] = ufoDStack
[f
];
2226 ufoDStack
[ufoSP
- 1u] = val
;
2232 // RROLL ( idx -- n )
2234 const uint32_t n
= ufoPop();
2235 if (n
>= ufoRP
) ufoFatal("invalid RROLL index %u", n
);
2237 const uint32_t rp
= ufoRP
- n
- 1u;
2238 if (rp
<= ufoRPTop
) ufoFatal("invalid RROLL index %u", n
);
2239 const uint32_t val
= ufoRStack
[rp
];
2240 for (uint32_t f
= rp
+ 1u; f
< ufoRP
; f
+= 1u) ufoRStack
[f
- 1u] = ufoRStack
[f
];
2241 ufoRStack
[ufoRP
- 1u] = val
;
2255 UFWORD(REFILL_NOCROSS
) {
2261 //==========================================================================
2265 //==========================================================================
2266 UFO_FORCE_INLINE
int ufoIsDelim (uint8_t ch
, uint8_t delim
) {
2267 return (delim
== 32 ? (ch
<= 32) : (ch
== delim
));
2272 // ( delim skip-leading-delim? -- addr count TRUE / FALSE )
2273 // does base TIB parsing; never copies anything.
2274 // as our reader is line-based, returns FALSE on EOL.
2275 // EOL is detected after skipping leading delimiters.
2276 // passing -1 as delimiter skips the whole line, and always returns FALSE.
2277 // trailing delimiter is always skipped.
2279 const uint32_t skipDelim
= ufoPop();
2280 const uint32_t delim
= ufoPop();
2281 const uint32_t tib
= ufoImgGetU32(ufoAddrTIB
);
2282 uint32_t in
= ufoImgGetU32(ufoAddrIN
);
2285 fprintf(stderr
, "PARSE-IN: in=%u; delim=%u; skip=%u\n",
2286 in
, delim
, skipDelim
);
2289 if (delim
== 0 || delim
> 0xffU
) {
2291 while (ufoImgGetU8(tib
+ in
) != 0) in
+= 1;
2292 ufoImgPutU32(ufoAddrIN
, in
);
2296 ch
= ufoImgGetU8(tib
+ in
);
2297 // skip initial delimiters
2299 while (ch
!= 0 && ufoIsDelim(ch
, delim
)) {
2301 ch
= ufoImgGetU8(tib
+ in
);
2306 ufoImgPutU32(ufoAddrIN
, in
);
2309 const uint32_t stin
= in
;
2310 while (ch
!= 0 && !ufoIsDelim(ch
, delim
)) {
2312 ch
= ufoImgGetU8(tib
+ in
);
2314 ufoPush(tib
+ stin
);
2318 ufo_assert(ufoIsDelim(ch
, delim
));
2321 ufoImgPutU32(ufoAddrIN
, in
);
2324 fprintf(stderr
, "PARSE-OUT: len=%u\n", in
- stin
);
2330 // PARSE-SKIP-BLANKS
2332 UFWORD(PARSE_SKIP_BLANKS
) {
2333 const uint32_t tib
= ufoImgGetU32(ufoAddrTIB
);
2334 uint32_t in
= ufoImgGetU32(ufoAddrIN
);
2336 ch
= ufoImgGetU8(tib
+ in
);
2337 while (ch
!= 0 && ch
<= 32) {
2339 ch
= ufoImgGetU8(tib
+ in
);
2341 ufoImgPutU32(ufoAddrIN
, in
);
2345 //==========================================================================
2347 // ufoParseMLComment
2349 // initial two chars are skipped
2351 //==========================================================================
2352 static void ufoParseMLComment (int nested
) {
2353 uint32_t tib
= ufoImgGetU32(ufoAddrTIB
);
2354 uint32_t in
= ufoImgGetU32(ufoAddrIN
);
2357 while (level
!= 0) {
2358 ch
= ufoImgGetU8(tib
+ in
); in
+= 1;
2360 UFCALL(REFILL_NOCROSS
);
2361 if (ufoPop() == 0) ufoFatal("unexpected end of file in comment");
2362 tib
= ufoImgGetU32(ufoAddrTIB
);
2363 in
= ufoImgGetU32(ufoAddrIN
);
2365 ch1
= ufoImgGetU8(tib
+ in
);
2366 if (nested
&& ch
== '(' && ch1
== '(') { in
+= 1; level
+= 1; }
2367 else if (nested
&& ch
== ')' && ch1
== ')') { in
+= 1; level
-= 1; }
2368 else if (!nested
&& ch
== '*' && ch1
== ')') { ufo_assert(level
== 1); in
+= 1; level
= 0; }
2371 ufoImgPutU32(ufoAddrIN
, in
);
2375 // (PARSE-SKIP-COMMENTS)
2376 // ( allow-multiline? -- )
2377 // skip all blanks and comments
2378 UFWORD(PAR_PARSE_SKIP_COMMENTS
) {
2379 const uint32_t allowMulti
= ufoPop();
2380 uint32_t tib
= ufoImgGetU32(ufoAddrTIB
);
2381 uint32_t in
= ufoImgGetU32(ufoAddrIN
);
2382 uint8_t ch
, ch1
, ech
;
2383 ch
= ufoImgGetU8(tib
+ in
);
2387 ch
= ufoImgGetU8(tib
+ in
);
2389 ch1
= ufoImgGetU8(tib
+ in
+ 1u);
2390 if ((ch
== '(' || ch
== '\\') && ch1
<= 32) {
2391 // single-line comment
2392 ech
= (ch
== '(' ? ')' : 0);
2393 while (ch
!= 0 && ch
!= ech
) {
2395 ch
= ufoImgGetU8(tib
+ in
);
2399 ch
= ufoImgGetU8(tib
+ in
);
2401 } else if (ch
== ';' && ch1
== ';') {
2404 ch
= ufoImgGetU8(tib
+ in
);
2406 } else if (allowMulti
&& (ch
== '(' && (ch1
== '*' || ch1
== '('))) {
2408 ufoImgPutU32(ufoAddrIN
, in
+ 2);
2409 ufoParseMLComment((ch1
== '('));
2410 tib
= ufoImgGetU32(ufoAddrTIB
);
2411 in
= ufoImgGetU32(ufoAddrIN
);
2412 ch
= ufoImgGetU8(tib
+ in
);
2418 ufoImgPutU32(ufoAddrIN
, in
);
2423 UFWORD(PARSE_SKIP_LINE
) {
2424 ufoPush(0); ufoPushBool(0); UFCALL(PAR_PARSE
);
2425 if (ufoPop() != 0) {
2431 // ( -- addr count )
2432 // parse with leading blanks skipping. doesn't copy anything.
2433 // return empty string on EOL.
2434 UFWORD(PARSE_NAME
) {
2435 ufoPush(32); ufoPushBool(1); UFCALL(PAR_PARSE
);
2436 if (ufoPop() == 0) {
2437 const uint32_t tib
= ufoImgGetU32(ufoAddrTIB
);
2438 const uint32_t in
= ufoImgGetU32(ufoAddrIN
);
2445 // ( delim -- addr count TRUE / FALSE )
2446 // parse without skipping delimiters; never copies anything.
2447 // as our reader is line-based, returns FALSE on EOL.
2448 // passing 0 as delimiter skips the whole line, and always returns FALSE.
2449 // trailing delimiter is always skipped.
2451 ufoPushBool(0); UFCALL(PAR_PARSE
);
2455 // ( delim skip-leading-delim? -- here TRUE / FALSE )
2456 // parse word, copy it to HERE as counted string.
2457 // adds trailing zero after the string, but doesn't include it in count.
2458 // doesn't advance line.
2461 // ( delim -- here )
2462 // parse word, copy it to HERE as counted string.
2463 // adds trailing zero after the string, but doesn't include it in count.
2464 // doesn't advance line.
2465 // return empty string on EOL.
2468 // ( delim -- addr count TRUE / FALSE )
2469 // parse word w/o skipping delimiters, copy it to HERE as counted string.
2470 // adds trailing zero after the string, but doesn't include it in count.
2471 // doesn't advance line.
2474 // ////////////////////////////////////////////////////////////////////////// //
2480 uint32_t ch
= ufoPop()&0xffU
;
2481 if (ch
< 32 || ch
== 127) {
2482 if (ch
!= 9 && ch
!= 10 && ch
!= 13) ch
= '?';
2484 ufoLastEmitWasCR
= (ch
== 10);
2491 uint32_t ch
= ufoPop()&0xffU
;
2492 putchar(ch
< 32 || ch
== 127 ? '?' : (char)ch
);
2493 ufoLastEmitWasCR
= 0;
2499 ufoPushBool(ufoLastEmitWasCR
);
2505 ufoLastEmitWasCR
= !!ufoPop();
2512 ufoLastEmitWasCR
= 1;
2519 ufoLastEmitWasCR
= 0;
2526 int32_t n
= (int32_t)ufoPop();
2528 memset(tmpbuf
, 32, sizeof(tmpbuf
));
2531 if (xwr
> (int32_t)sizeof(tmpbuf
) - 1) xwr
= (int32_t)sizeof(tmpbuf
) - 1;
2533 printf("%s", tmpbuf
);
2536 ufoLastEmitWasCR
= 0;
2543 if (ufoLastEmitWasCR
== 0) {
2545 ufoLastEmitWasCR
= 1;
2550 // ( addr count -- )
2552 int32_t count
= (int32_t)ufoPop();
2553 uint32_t addr
= ufoPop();
2555 const uint8_t ch
= ufoImgGetU8(addr
);
2558 addr
+= 1; count
-= 1;
2563 // ( addr count -- )
2565 int32_t count
= (int32_t)ufoPop();
2566 uint32_t addr
= ufoPop();
2568 const uint8_t ch
= ufoImgGetU8(addr
);
2571 addr
+= 1; count
-= 1;
2576 // ////////////////////////////////////////////////////////////////////////// //
2579 #define UF_UMATH(name_,op_) \
2581 const uint32_t a = ufoPop(); \
2585 #define UF_BMATH(name_,op_) \
2587 const uint32_t b = ufoPop(); \
2588 const uint32_t a = ufoPop(); \
2592 #define UF_BDIV(name_,op_) \
2594 const uint32_t b = ufoPop(); \
2595 const uint32_t a = ufoPop(); \
2596 if (b == 0) ufoFatal("UFO division by zero"); \
2603 UF_BMATH(PLUS
, a
+ b
);
2607 UF_BMATH(MINUS
, a
- b
);
2611 UF_BMATH(MUL
, (uint32_t)((int32_t)a
* (int32_t)b
));
2615 UF_BMATH(UMUL
, a
* b
);
2619 UF_BDIV(DIV
, (uint32_t)((int32_t)a
/ (int32_t)b
));
2623 UF_BDIV(UDIV
, a
/ b
);
2627 UF_BDIV(MOD
, (uint32_t)((int32_t)a
% (int32_t)b
));
2631 UF_BDIV(UMOD
, a
% b
);
2634 // ( a b -- a/b, a%b )
2636 const int32_t b
= (int32_t)ufoPop();
2637 const int32_t a
= (int32_t)ufoPop();
2638 if (b
== 0) ufoFatal("UFO division by zero");
2639 ufoPush((uint32_t)(a
/b
));
2640 ufoPush((uint32_t)(a
%b
));
2644 // ( a b -- a/b, a%b )
2646 const uint32_t b
= ufoPop();
2647 const uint32_t a
= ufoPop();
2648 if (b
== 0) ufoFatal("UFO division by zero");
2649 ufoPush((uint32_t)(a
/b
));
2650 ufoPush((uint32_t)(a
%b
));
2654 // ////////////////////////////////////////////////////////////////////////// //
2657 #define UF_CMP(name_,op_) \
2659 const uint32_t b = ufoPop(); \
2660 const uint32_t a = ufoPop(); \
2666 UF_CMP(LESS
, (int32_t)a
< (int32_t)b
);
2670 UF_CMP(ULESS
, a
< b
);
2674 UF_CMP(GREAT
, (int32_t)a
> (int32_t)b
);
2678 UF_CMP(UGREAT
, a
> b
);
2682 UF_CMP(LESSEQU
, (int32_t)a
<= (int32_t)b
);
2686 UF_CMP(ULESSEQU
, a
<= b
);
2690 UF_CMP(GREATEQU
, (int32_t)a
>= (int32_t)b
);
2694 UF_CMP(UGREATEQU
, a
>= b
);
2698 UF_CMP(EQU
, a
== b
);
2702 UF_CMP(NOTEQU
, a
!= b
);
2707 const uint32_t a
= ufoPop();
2713 UF_CMP(LOGAND
, a
&& b
);
2717 UF_CMP(LOGOR
, a
|| b
);
2722 const uint32_t b
= ufoPop();
2723 const uint32_t a
= ufoPop();
2730 const uint32_t b
= ufoPop();
2731 const uint32_t a
= ufoPop();
2738 const uint32_t b
= ufoPop();
2739 const uint32_t a
= ufoPop();
2746 const uint32_t a
= ufoPop();
2750 UFWORD(ONESHL
) { uint32_t n
= ufoPop(); ufoPush(n
<< 1); }
2751 UFWORD(ONESHR
) { uint32_t n
= ufoPop(); ufoPush(n
>> 1); }
2752 UFWORD(TWOSHL
) { uint32_t n
= ufoPop(); ufoPush(n
<< 2); }
2753 UFWORD(TWOSHR
) { uint32_t n
= ufoPop(); ufoPush(n
>> 2); }
2757 // arithmetic shift; positive `n` shifts to the left
2759 int32_t c
= (int32_t)ufoPop();
2762 int32_t n
= (int32_t)ufoPop();
2764 if (n
< 0) n
= -1; else n
= 0;
2766 n
>>= (uint8_t)(-c
);
2768 ufoPush((uint32_t)n
);
2771 uint32_t u
= ufoPop();
2783 // logical shift; positive `n` shifts to the left
2785 int32_t c
= (int32_t) ufoPop();
2786 uint32_t u
= ufoPop();
2792 u
>>= (uint8_t)(-c
);
2807 // ( addr count -- addr count )
2808 UFWORD(PAR_UNESCAPE
) {
2809 const uint32_t count
= ufoPop();
2810 const uint32_t addr
= ufoPeek();
2811 if ((count
& ((uint32_t)1<<31)) == 0) {
2812 const uint32_t eaddr
= addr
+ count
;
2813 uint32_t caddr
= addr
;
2814 uint32_t daddr
= addr
;
2815 while (caddr
!= eaddr
) {
2816 uint8_t ch
= ufoImgGetU8(caddr
); caddr
+= 1u;
2817 if (ch
== '\\' && caddr
!= eaddr
) {
2818 ch
= ufoImgGetU8(caddr
); caddr
+= 1u;
2820 case 'r': ch
= '\r'; break;
2821 case 'n': ch
= '\n'; break;
2822 case 't': ch
= '\t'; break;
2823 case 'e': ch
= '\x1b'; break;
2824 case '`': ch
= '"'; break; // special escape to insert double-quote
2825 case '"': ch
= '"'; break;
2826 case '\\': ch
= '\\'; break;
2828 if (eaddr
- daddr
>= 1) {
2829 const int dg0
= digitInBase((char)(ufoImgGetU8(caddr
+ 1)), 16);
2830 if (dg0
< 0) ufoFatal("invalid hex string escape");
2831 if (eaddr
- daddr
>= 2) {
2832 const int dg1
= digitInBase((char)(ufoImgGetU8(caddr
+ 2)), 16);
2833 if (dg1
< 0) ufoFatal("invalid hex string escape");
2834 ch
= (uint8_t)(dg0
* 16 + dg1
);
2841 ufoFatal("invalid hex string escape");
2844 default: ufoFatal("invalid string escape");
2847 ufoImgPutU8(daddr
, ch
); daddr
+= 1u;
2849 ufoPush(daddr
- addr
);
2856 // convert number from addrl+1
2857 // returns address of the first inconvertible char
2858 // (XNUMBER) ( addr count allowsign? -- num TRUE / FALSE )
2859 UFWORD(PAR_XNUMBER
) {
2860 const uint32_t allowSign
= ufoPop();
2861 int32_t count
= (int32_t)ufoPop();
2862 uint32_t addr
= ufoPop();
2865 int xbase
= (int32_t)ufoImgGetU32(ufoAddrBASE
);
2869 if (allowSign
&& count
> 1) {
2870 ch
= ufoImgGetU8(addr
);
2871 if (ch
== '-') { neg
= 1; addr
+= 1u; count
-= 1; }
2872 else if (ch
== '+') { neg
= 0; addr
+= 1u; count
-= 1; }
2875 // special-based numbers
2876 if (count
>= 3 && ufoImgGetU8(addr
) == '0') {
2877 switch (ufoImgGetU8(addr
+ 1)) {
2878 case 'x': case 'X': base
= 16; break;
2879 case 'o': case 'O': base
= 8; break;
2880 case 'b': case 'B': base
= 2; break;
2881 case 'd': case 'D': base
= 10; break;
2884 if (base
) { addr
+= 2; count
-= 2; }
2885 } else if (count
>= 2 && ufoImgGetU8(addr
) == '$') {
2887 addr
+= 1; count
-= 1;
2888 } else if (count
>= 2 && ufoImgGetU8(addr
) == '#') {
2890 addr
+= 1; count
-= 1;
2891 } else if (count
>= 2 && ufoImgGetU8(addr
) == '%') {
2893 addr
+= 1; count
-= 1;
2894 } else if (count
>= 3 && ufoImgGetU8(addr
) == '&') {
2895 switch (ufoImgGetU8(addr
+ 1)) {
2896 case 'h': case 'H': base
= 16; break;
2897 case 'o': case 'O': base
= 8; break;
2898 case 'b': case 'B': base
= 2; break;
2899 case 'd': case 'D': base
= 10; break;
2902 if (base
) { addr
+= 2; count
-= 2; }
2903 } else if (xbase
< 12 && count
> 2 && toUpperU8(ufoImgGetU8(addr
+ count
- 1)) == 'B') {
2906 } else if (xbase
< 18 && count
> 2 && toUpperU8(ufoImgGetU8(addr
+ count
- 1)) == 'H') {
2909 } else if (xbase
< 25 && count
> 2 && toUpperU8(ufoImgGetU8(addr
+ count
- 1)) == 'O') {
2915 if (!base
) base
= xbase
;
2917 if (count
<= 0 || base
< 1 || base
> 36) {
2921 int wasDig
= 0, wasUnder
= 1, error
= 0, dig
;
2922 while (!error
&& count
!= 0) {
2923 ch
= ufoImgGetU8(addr
); addr
+= 1; count
-= 1;
2925 error
= 1; wasUnder
= 0; wasDig
= 1;
2926 dig
= digitInBase((char)ch
, (int)base
);
2928 nc
= n
* (uint32_t)base
;
2930 nc
+= (uint32_t)dig
;
2943 if (!error
&& wasDig
&& !wasUnder
) {
2944 if (allowSign
&& neg
) n
= ~n
+ 1u;
2954 // ////////////////////////////////////////////////////////////////////////// //
2955 // compiler-related, dictionary-related
2957 static char ufoWNameBuf
[256];
2961 UFWORD(LBRACKET_IMM
) {
2962 if (ufoImgGetU32(ufoAddrSTATE
) == 0) ufoFatal("expects compiling mode");
2963 ufoImgPutU32(ufoAddrSTATE
, 0);
2968 if (ufoImgGetU32(ufoAddrSTATE
) != 0) ufoFatal("expects interpreting mode");
2969 ufoImgPutU32(ufoAddrSTATE
, 1);
2972 // (CREATE-WORD-HEADER)
2973 // ( addr count word-flags -- )
2974 UFWORD(PAR_CREATE_WORD_HEADER
) {
2975 const uint32_t flags
= ufoPop();
2976 const uint32_t wlen
= ufoPop();
2977 const uint32_t waddr
= ufoPop();
2978 if (wlen
== 0) ufoFatal("word name expected");
2979 if (wlen
>= UFO_MAX_WORD_LENGTH
) ufoFatal("word name too long");
2980 // copy to separate buffer
2981 for (uint32_t f
= 0; f
< wlen
; f
+= 1) {
2982 ufoWNameBuf
[f
] = (char)ufoImgGetU8(waddr
+ f
);
2984 ufoWNameBuf
[wlen
] = 0;
2985 ufoCreateWordHeader(ufoWNameBuf
, flags
);
2988 // (CREATE-NAMELESS-WORD-HEADER)
2989 // ( word-flags -- )
2990 UFWORD(PAR_CREATE_NAMELESS_WORD_HEADER
) {
2991 const uint32_t flags
= ufoPop();
2992 ufoCreateWordHeader("", flags
);
2996 // ( addr count -- cfa TRUE / FALSE)
2998 const uint32_t wlen
= ufoPop();
2999 const uint32_t waddr
= ufoPop();
3000 if (wlen
> 0 && wlen
< UFO_MAX_WORD_LENGTH
) {
3001 // copy to separate buffer
3002 for (uint32_t f
= 0; f
< wlen
; f
+= 1) {
3003 ufoWNameBuf
[f
] = (char)ufoImgGetU8(waddr
+ f
);
3005 ufoWNameBuf
[wlen
] = 0;
3006 const uint32_t cfa
= ufoFindWord(ufoWNameBuf
);
3019 // ( addr count vocid allowhidden -- cfa TRUE / FALSE)
3020 // find only in the given voc; no name resolution
3021 UFWORD(FIND_WORD_IN_VOC
) {
3022 const uint32_t allowHidden
= ufoPop();
3023 const uint32_t vocid
= ufoPop();
3024 const uint32_t wlen
= ufoPop();
3025 const uint32_t waddr
= ufoPop();
3026 if (wlen
> 0 && wlen
< UFO_MAX_WORD_LENGTH
) {
3027 // copy to separate buffer
3028 for (uint32_t f
= 0; f
< wlen
; f
+= 1) {
3029 ufoWNameBuf
[f
] = (char)ufoImgGetU8(waddr
+ f
);
3031 ufoWNameBuf
[wlen
] = 0;
3032 const uint32_t cfa
= ufoFindWordInVoc(ufoWNameBuf
, wlen
, 0, vocid
, (allowHidden
? 1 : 0));
3045 // ////////////////////////////////////////////////////////////////////////// //
3046 // more compiler words
3050 if (ufoImgGetU32(ufoAddrSTATE
) != 0) ufoFatal("expecting execution mode");
3055 if (ufoImgGetU32(ufoAddrSTATE
) == 0) ufoFatal("expecting compilation mode");
3061 ufoPush(34); UFCALL(PARSE
);
3062 if (ufoPop() == 0) ufoFatal("string literal expected");
3063 UFCALL(PAR_UNESCAPE
);
3064 if (ufoImgGetU32(ufoAddrSTATE
) != 0) {
3066 const uint32_t wlen
= ufoPop();
3067 const uint32_t waddr
= ufoPop();
3068 if (wlen
> 255) ufoFatal("string literal too long");
3069 ufoImgEmitU32(ufoStrLit8CFA
);
3071 for (uint32_t f
= 0; f
< wlen
; f
+= 1) {
3072 ufoImgEmitU8(ufoImgGetU8(waddr
+ f
));
3080 // ////////////////////////////////////////////////////////////////////////// //
3081 // vocabulary utilities
3085 UFWORD(PAR_GET_VSP
) {
3091 UFWORD(PAR_SET_VSP
) {
3092 const uint32_t vsp
= ufoPop();
3093 if (vsp
>= UFO_VOCSTACK_SIZE
) ufoFatal("VSP %u out of range (%u)", vsp
, UFO_VOCSTACK_SIZE
);
3099 UFWORD(PAR_VSP_LOAD
) {
3100 const uint32_t vsp
= ufoPop();
3101 if (vsp
>= UFO_VOCSTACK_SIZE
) ufoFatal("VSP %u out of range (%u)", vsp
, UFO_VOCSTACK_SIZE
);
3102 ufoPush(ufoVocStack
[vsp
]);
3107 UFWORD(PAR_VSP_STORE
) {
3108 const uint32_t vsp
= ufoPop();
3109 const uint32_t value
= ufoPop();
3110 if (vsp
> UFO_VOCSTACK_SIZE
) ufoFatal("VSP %u out of range (%u)", vsp
, UFO_VOCSTACK_SIZE
);
3111 ufoVocStack
[vsp
] = value
;
3115 UFWORD(PAR_HIDDEN
) {
3116 uint32_t curr
= ufoImgGetU32(ufoAddrCurrent
);
3117 uint32_t latest
= ufoImgGetU32(curr
);
3118 if (latest
== 0) ufoFatal("wtf in `IMMEDIATE`");
3119 uint32_t nfa
= latest
+ 8u;
3120 uint32_t flags
= ufoImgGetU32(nfa
);
3121 flags
|= UFW_FLAG_HIDDEN
;
3122 ufoImgPutU32(nfa
, flags
);
3126 // ////////////////////////////////////////////////////////////////////////// //
3127 // word field address conversion
3132 const uint32_t cfa
= ufoPop();
3133 ufoPush(UFO_CFA_TO_PFA(cfa
));
3139 const uint32_t pfa
= ufoPop();
3140 ufoPush(UFO_PFA_TO_CFA(pfa
));
3146 const uint32_t cfa
= ufoPop();
3147 ufoPush(UFO_CFA_TO_NFA(cfa
));
3153 const uint32_t nfa
= ufoPop();
3154 ufoPush(UFO_NFA_TO_CFA(nfa
));
3160 const uint32_t cfa
= ufoPop();
3161 ufoPush(UFO_CFA_TO_LFA(cfa
));
3167 const uint32_t lfa
= ufoPop();
3168 ufoPush(UFO_LFA_TO_CFA(lfa
));
3174 uint32_t lfa
= ufoPop();
3175 lfa
= UFO_LFA_TO_CFA(lfa
);
3176 ufoPush(UFO_CFA_TO_PFA(lfa
));
3182 const uint32_t lfa
= ufoPop();
3183 ufoPush(UFO_LFA_TO_BFA(lfa
));
3189 const uint32_t lfa
= ufoPop();
3190 ufoPush(UFO_LFA_TO_SFA(lfa
));
3196 const uint32_t lfa
= ufoPop();
3197 ufoPush(UFO_LFA_TO_NFA(lfa
));
3203 const uint32_t nfa
= ufoPop();
3204 ufoPush(UFO_NFA_TO_LFA(nfa
));
3208 // ////////////////////////////////////////////////////////////////////////// //
3212 //==========================================================================
3214 // ufoPopStrLitToTempBuf
3216 //==========================================================================
3217 static void ufoPopStrLitToTempBuf (void) {
3218 uint32_t count
= ufoPop();
3219 uint32_t addr
= ufoPop();
3220 if ((count
& (1u<<31)) != 0) ufoFatal("invalid string length");
3221 if ((size_t)count
>= sizeof(ufoTempCharBuf
)) ufoFatal("string too long");
3222 for (uint32_t f
= 0; f
< count
; f
+= 1) {
3223 ufoTempCharBuf
[f
] = (char)ufoImgGetU8(addr
+ f
);
3225 ufoTempCharBuf
[count
] = 0;
3230 // ( addr count -- flag )
3231 UFWORD(UR_HAS_LABELQ
) {
3232 ufoPopStrLitToTempBuf();
3233 ufoPushBool(ufoZXGetLabelType(ufoTempCharBuf
) > UFO_ZX_LABEL_UNKNOWN
);
3237 // ( addr count -- type )
3239 UFWORD(UR_GET_LABELQ_TYPE
) {
3240 ufoPopStrLitToTempBuf();
3241 ufoPush(ufoZXGetLabelType(ufoTempCharBuf
));
3245 // ( addr count -- value )
3246 // fatals when the label is not found
3247 UFWORD(UR_GET_LABEL
) {
3248 ufoPopStrLitToTempBuf();
3249 ufoPush((uint32_t)ufoZXGetLabelValue(ufoTempCharBuf
));
3252 // UR-NEW-LABEL-ITER
3253 // ( -- iterid | 0 )
3254 UFWORD(UR_NEW_LABEL_ITER
) {
3255 ufoPush(ufoZXNewLabelIter());
3258 // UR-CLOSE-LABEL-ITER
3260 UFWORD(UR_CLOSE_LABEL_ITER
) {
3261 uint32_t id
= ufoPop();
3262 ufoZXLabelIterClose(id
);
3265 // UR-LABEL-ITER-NEXT
3266 // ( iterid -- not-done? )
3267 UFWORD(UR_LABEL_ITER_NEXT
) {
3268 uint32_t id
= ufoPop();
3269 ufoPushBool(ufoZXLabelIterNext(id
));
3272 // UR-LABEL-ITER-GET-NAME
3273 // ( iterid -- addr count )
3275 UFWORD(UR_LABEL_ITER_GET_NAME
) {
3276 uint32_t id
= ufoPop();
3277 const char *name
= ufoZXLabelIterGetName(id
);
3278 if (name
== NULL
) name
= "";
3281 uint32_t pad
= ufoPop() + 4u;
3282 while (count
!= 1024 && *name
!= 0) {
3283 ufoImgPutU8(pad
+ count
, ((const unsigned char *)name
)[count
]);
3284 count
+= 1u; name
+= 1u;
3286 if (count
== 1024) ufoFatal("label name too long");
3287 ufoImgPutU8(pad
+ count
, 0); // just in case
3288 ufoPush(pad
); ufoPush(count
);
3291 // UR-LABEL-ITER-GET-VALUE
3292 // ( iterid -- value )
3293 UFWORD(UR_LABEL_ITER_GET_VALUE
) {
3294 uint32_t id
= ufoPop();
3295 ufoPush((uint32_t)ufoZXIterGetValue(id
));
3298 // UR-LABEL-ITER-GET-TYPE
3299 // ( iterid -- type )
3300 UFWORD(UR_LABEL_ITER_GET_TYPE
) {
3301 uint32_t id
= ufoPop();
3302 ufoPush((uint32_t)ufoZXIterGetType(id
));
3306 //==========================================================================
3308 // urw_set_typed_label
3310 // ( value addr count -- )
3312 //==========================================================================
3313 static void urw_set_typed_label (int type
) {
3314 ufoPopStrLitToTempBuf();
3315 const char *name
= ufoTempCharBuf
;
3316 int32_t val
= (int32_t)ufoPop();
3317 ufoZXSetLabelValue(name
, type
, val
);
3322 // ( value addr count -- )
3323 // create/overwrite an "assign" label
3324 UFWORD(UR_SET_LABEL_VAR
) { urw_set_typed_label(UFO_ZX_LABEL_VAR
); }
3327 // ( value addr count -- )
3328 UFWORD(UR_SET_LABEL_EQU
) { urw_set_typed_label(UFO_ZX_LABEL_EQU
); }
3330 // UR-SET-LABEL-CODE
3331 // ( value addr count -- )
3332 UFWORD(UR_SET_LABEL_CODE
) { urw_set_typed_label(UFO_ZX_LABEL_CODE
); }
3334 // UR-SET-LABEL-STOFS
3335 // ( value addr count -- )
3336 UFWORD(UR_SET_LABEL_STOFS
) { urw_set_typed_label(UFO_ZX_LABEL_STOFS
); }
3338 // UR-SET-LABEL-DATA
3339 // ( value addr count -- )
3340 UFWORD(UR_SET_LABEL_DATA
) { urw_set_typed_label(UFO_ZX_LABEL_DATA
); }
3343 //==========================================================================
3345 // urw_declare_typed_label
3347 //==========================================================================
3348 static void urw_declare_typed_label (int type
) {
3351 ufoPopStrLitToTempBuf();
3352 if (ufoTempCharBuf
[0] == 0) ufoFatal("label name expected");
3353 const char *name
= ufoTempCharBuf
;
3354 ufoZXSetLabelValue(name
, type
, ufoZXGetOrg());
3357 // $LABEL-DATA: name
3358 UFWORD(DLR_LABEL_DATA_IMM
) { urw_declare_typed_label(UFO_ZX_LABEL_DATA
); }
3359 // $LABEL-CODE: name
3360 UFWORD(DLR_LABEL_CODE_IMM
) { urw_declare_typed_label(UFO_ZX_LABEL_CODE
); }
3366 ufoPush(ufoZXGetPass());
3372 ufoPush(ufoZXGetOrg());
3377 UFWORD(UR_GETDISP
) {
3378 ufoPush(ufoZXGetDisp());
3384 ufoPush(ufoZXGetEnt());
3391 const uint32_t addr
= ufoPop();
3397 // doesn't change ORG
3398 UFWORD(UR_SETDISP
) {
3399 const uint32_t addr
= ufoPop();
3406 const uint32_t addr
= ufoPop();
3411 // ////////////////////////////////////////////////////////////////////////// //
3414 UFO_FORCE_INLINE
uint32_t ufoHashBuf (uint32_t addr
, uint32_t size
, uint8_t orbyte
) {
3415 uint32_t hash
= 0x29a;
3416 if ((size
& ((uint32_t)1<<31)) == 0) {
3418 hash
+= ufoImgGetU8(addr
) | orbyte
;
3421 addr
+= 1u; size
-= 1u;
3432 // ( a0 c0 a1 c1 -- bool )
3434 int32_t c1
= (int32_t)ufoPop();
3435 uint32_t a1
= ufoPop();
3436 int32_t c0
= (int32_t)ufoPop();
3437 uint32_t a0
= ufoPop();
3442 while (res
!= 0 && c0
!= 0) {
3443 res
= (ufoImgGetU8(a0
) == ufoImgGetU8(a1
));
3444 a0
+= 1; a1
+= 1; c0
-= 1;
3453 // ( a0 c0 a1 c1 -- bool )
3455 int32_t c1
= (int32_t)ufoPop();
3456 uint32_t a1
= ufoPop();
3457 int32_t c0
= (int32_t)ufoPop();
3458 uint32_t a0
= ufoPop();
3463 while (res
!= 0 && c0
!= 0) {
3464 res
= (toUpperU8(ufoImgGetU8(a0
)) == toUpperU8(ufoImgGetU8(a1
)));
3465 a0
+= 1; a1
+= 1; c0
-= 1;
3474 // ( addr count -- hash )
3476 uint32_t count
= ufoPop();
3477 uint32_t addr
= ufoPop();
3478 ufoPush(ufoHashBuf(addr
, count
, 0));
3482 // ( addr count -- hash )
3484 uint32_t count
= ufoPop();
3485 uint32_t addr
= ufoPop();
3486 ufoPush(ufoHashBuf(addr
, count
, 0x20));
3490 // ////////////////////////////////////////////////////////////////////////// //
3491 // conditional defines
3492 typedef struct UForthCondDefine_t UForthCondDefine
;
3493 struct UForthCondDefine_t
{
3497 UForthCondDefine
*next
;
3500 static UForthCondDefine
*ufoCondDefines
= NULL
;
3501 static char ufoErrMsgBuf
[4096];
3504 //==========================================================================
3508 //==========================================================================
3509 UFO_FORCE_INLINE
int ufoBufEquCI (uint32_t addr
, uint32_t count
, const void *buf
) {
3511 if ((count
& ((uint32_t)1<<31)) == 0) {
3512 const unsigned char *src
= (const unsigned char *)buf
;
3514 while (res
!= 0 && count
!= 0) {
3515 res
= (toUpperU8(*src
) == toUpperU8(ufoImgGetU8(addr
)));
3516 src
+= 1; addr
+= 1u; count
-= 1u;
3525 //==========================================================================
3527 // ufoClearCondDefines
3529 //==========================================================================
3530 static void ufoClearCondDefines (void) {
3531 while (ufoCondDefines
) {
3532 UForthCondDefine
*df
= ufoCondDefines
;
3533 ufoCondDefines
= df
->next
;
3534 if (df
->name
) free(df
->name
);
3541 // ( addr count -- )
3542 UFWORD(PAR_DLR_DEFINE
) {
3543 uint32_t count
= ufoPop();
3544 uint32_t addr
= ufoPop();
3545 if (count
== 0) ufoFatal("empty define");
3546 if (count
>= UFO_MAX_WORD_LENGTH
) ufoFatal("define too long");
3547 const uint32_t hash
= ufoHashBuf(addr
, count
, 0x20);
3548 UForthCondDefine
*dd
;
3549 for (dd
= ufoCondDefines
; dd
!= NULL
; dd
= dd
->next
) {
3550 if (dd
->hash
== hash
&& dd
->namelen
== count
) {
3551 if (ufoBufEquCI(addr
, count
, dd
->name
)) return;
3555 dd
= calloc(1, sizeof(UForthCondDefine
));
3556 if (dd
== NULL
) ufoFatal("out of memory for defines");
3557 dd
->name
= calloc(1, count
+ 1u);
3558 if (dd
->name
== NULL
) { free(dd
); ufoFatal("out of memory for defines"); }
3559 for (uint32_t f
= 0; f
< count
; f
+= 1) {
3560 ((unsigned char *)dd
->name
)[f
] = ufoImgGetU8(addr
+ f
);
3562 dd
->namelen
= count
;
3564 dd
->next
= ufoCondDefines
;
3565 ufoCondDefines
= dd
;
3569 // ( addr count -- )
3570 UFWORD(PAR_DLR_UNDEF
) {
3571 uint32_t count
= ufoPop();
3572 uint32_t addr
= ufoPop();
3573 if (count
== 0) ufoFatal("empty define");
3574 if (count
>= UFO_MAX_WORD_LENGTH
) ufoFatal("define too long");
3575 const uint32_t hash
= ufoHashBuf(addr
, count
, 0x20);
3576 UForthCondDefine
*prev
= NULL
;
3577 UForthCondDefine
*dd
;
3578 for (dd
= ufoCondDefines
; dd
!= NULL
; prev
= dd
, dd
= dd
->next
) {
3579 if (dd
->hash
== hash
&& dd
->namelen
== count
) {
3580 if (ufoBufEquCI(addr
, count
, dd
->name
)) {
3581 if (prev
== NULL
) ufoCondDefines
= dd
->next
; else prev
->next
= dd
->next
;
3591 // ( addr count -- bool )
3592 UFWORD(PAR_DLR_DEFINEDQ
) {
3593 uint32_t count
= ufoPop();
3594 uint32_t addr
= ufoPop();
3595 if (count
== 0) ufoFatal("empty define");
3596 if (count
>= UFO_MAX_WORD_LENGTH
) ufoFatal("define too long");
3597 const uint32_t hash
= ufoHashBuf(addr
, count
, 0x20);
3599 UForthCondDefine
*dd
= ufoCondDefines
;
3600 while (!found
&& dd
!= NULL
) {
3601 if (dd
->hash
== hash
&& dd
->namelen
== count
) {
3602 found
= ufoBufEquCI(addr
, count
, dd
->name
);
3611 UFWORD(PAR_TYPE_CURR_FILE
) {
3612 if (ufoInFile
!= NULL
) {
3613 fprintf(stdout
, "at file %s, line %d: ", ufoInFileName
, ufoInFileLine
);
3615 fprintf(stdout
, "somewhere in time: ");
3620 // ( addr count -- )
3622 uint32_t count
= ufoPop();
3623 uint32_t addr
= ufoPop();
3624 if (count
& (1u<<31)) ufoFatal("invalid error message");
3625 if (count
== 0) ufoFatal("some error");
3626 if (count
> (uint32_t)sizeof(ufoErrMsgBuf
) - 1u) count
= (uint32_t)sizeof(ufoErrMsgBuf
) - 1u;
3627 for (uint32_t f
= 0; f
< count
; f
+= 1) {
3628 ufoErrMsgBuf
[f
] = (char)ufoImgGetU8(addr
+ f
);
3630 ufoErrMsgBuf
[count
] = 0;
3631 ufoFatal("%s", ufoErrMsgBuf
);
3635 // ( errflag addr count -- )
3637 const uint32_t count
= ufoPop();
3638 const uint32_t addr
= ufoPop();
3647 // ////////////////////////////////////////////////////////////////////////// //
3650 static char ufoFNameBuf
[4096];
3653 // ( addr count soft? system? -- )
3654 UFWORD(PAR_INCLUDE
) {
3655 uint32_t system
= ufoPop();
3656 uint32_t softinclude
= ufoPop();
3657 uint32_t count
= ufoPop();
3658 uint32_t addr
= ufoPop();
3660 if ((count
& ((uint32_t)1<<31)) != 0) ufoFatal("invalid include name");
3661 //if (count == 0) ufoFatal("empty define");
3662 //if (count > (uint32_t)sizeof(ufoErrMsgBuf) - 1u) ufoFatal("define too long");
3667 while (count
!= 0) {
3668 ch
= ufoImgGetU8(addr
);
3670 //if (system) ufoFatal("invalid file name (duplicate system mark)");
3672 } else if (ch
== '?') {
3673 //if (softinclude) ufoFatal("invalid file name (duplicate soft mark)");
3679 addr
+= 1; count
-= 1;
3680 ch
= ufoImgGetU8(addr
);
3681 } while (ch
<= 32 && count
!= 0);
3685 if (!softinclude
) ufoFatal("empty include file name");
3688 if (count
> (uint32_t)sizeof(ufoFNameBuf
) - 1u) ufoFatal("include file name too long");
3691 if ((size_t)count
>= sizeof(ufoFNameBuf
)) ufoFatal("include file name too long");
3693 while (count
!= 0) {
3694 ufoFNameBuf
[dpos
] = (char)ufoImgGetU8(addr
); dpos
+= 1;
3695 addr
+= 1; count
-= 1;
3697 ufoFNameBuf
[dpos
] = 0;
3699 char *ffn
= ufoCreateIncludeName(ufoFNameBuf
, system
, ufoLastIncPath
);
3700 FILE *fl
= ufoOpenFileOrDir(&ffn
);
3702 if (softinclude
) { free(ffn
); return; }
3703 ufoFatal("include file '%s' not found", ffn
);
3708 ufoInFileName
= ffn
;
3709 setLastIncPath(ufoInFileName
);
3711 // trigger next line loading
3713 if (!ufoPop()) ufoFatal("(INCLUDE) internal error");
3717 UFWORD(DLR_INCLUDE_IMM
) {
3718 int soft
= 0, system
= 0;
3719 // parse include filename
3720 UFCALL(PARSE_SKIP_BLANKS
);
3721 uint8_t ch
= ufoImgGetU8(ufoImgGetU32(ufoAddrTIB
) + ufoImgGetU32(ufoAddrIN
));
3723 ufoImgPutU32(ufoAddrIN
, ufoImgGetU32(ufoAddrIN
) + 1u); // skip quote
3724 ufoPush(34); UFCALL(PARSE
);
3725 } else if (ch
== '<') {
3726 ufoImgPutU32(ufoAddrIN
, ufoImgGetU32(ufoAddrIN
) + 1u); // skip quote
3727 ufoPush(62); UFCALL(PARSE
);
3730 ufoFatal("expected quoted string");
3732 if (!ufoPop()) ufoFatal("file name expected");
3733 ufoPushBool(0); UFCALL(PAR_PARSE_SKIP_COMMENTS
);
3734 if (ufoImgGetU8(ufoImgGetU32(ufoAddrTIB
) + ufoImgGetU32(ufoAddrIN
)) != 0) {
3735 ufoFatal("$INCLUDE doesn't accept extra args yet");
3737 // ( addr count soft? system? -- )
3738 ufoPushBool(soft
); ufoPushBool(system
); UFCALL(PAR_INCLUDE
);
3741 // $INCLUDE-ONCE defname "str"
3742 UFWORD(DLR_INCLUDE_ONCE_IMM
) {
3744 if (ufoPeek() == 0) ufoFatal("guard name expected");
3745 ufo2Dup(); UFCALL(PAR_DLR_DEFINEDQ
);
3746 if (ufoPop() == 0) {
3748 UFCALL(PAR_DLR_DEFINE
);
3749 // parse include filename
3750 UFCALL(DLR_INCLUDE_IMM
);
3754 //UFCALL(PARSE_SKIP_LINE);
3755 if (ufoImgGetU8(ufoImgGetU32(ufoAddrTIB
) + ufoImgGetU32(ufoAddrIN
)) != 34) {
3756 ufoFatal("expected quoted string");
3758 ufoImgPutU32(ufoAddrIN
, ufoImgGetU32(ufoAddrIN
) + 1u); // skip quote
3759 ufoPush(34); UFCALL(PARSE
);
3760 ufoPushBool(0); UFCALL(PAR_PARSE_SKIP_COMMENTS
);
3761 if (ufoImgGetU8(ufoImgGetU32(ufoAddrTIB
) + ufoImgGetU32(ufoAddrIN
)) != 0) {
3762 ufoFatal("$INCLUDE doesn't accept extra args yet");
3768 // ////////////////////////////////////////////////////////////////////////// //
3772 // ( typecfa -- hx )
3773 UFWORD(PAR_NEW_HANDLE
) {
3774 const uint32_t typecfa
= ufoPop();
3775 if (typecfa
== UFO_HANDLE_FREE
) ufoFatal("invalid handle typecfa");
3776 UHandleInfo
*hh
= ufoAllocHandle(typecfa
);
3777 ufoPush(hh
->ufoHandle
);
3782 UFWORD(PAR_FREE_HANDLE
) {
3783 const uint32_t hx
= ufoPop();
3785 if ((hx
& UFO_ADDR_HANDLE_BIT
) == 0) ufoFatal("trying to free something that is not a handle");
3786 UHandleInfo
*hh
= ufoGetHandle(hx
);
3787 if (hh
== NULL
) ufoFatal("trying to free invalid handle");
3794 UFWORD(PAR_HANDLE_GET_SIZE
) {
3795 const uint32_t hx
= ufoPop();
3797 if ((hx
& UFO_ADDR_HANDLE_BIT
) == 0) ufoFatal("not a handle");
3798 UHandleInfo
*hh
= ufoGetHandle(hx
);
3799 if (hh
== NULL
) ufoFatal("invalid handle");
3808 UFWORD(PAR_HANDLE_SET_SIZE
) {
3809 const uint32_t hx
= ufoPop();
3810 const uint32_t size
= ufoPop();
3811 if (size
> 0x04000000) ufoFatal("invalid handle size");
3812 if ((hx
& UFO_ADDR_HANDLE_BIT
) == 0) ufoFatal("not a handle");
3813 UHandleInfo
*hh
= ufoGetHandle(hx
);
3814 if (hh
== NULL
) ufoFatal("invalid handle");
3815 if (hh
->size
!= size
) {
3820 uint32_t *nx
= realloc(hh
->mem
, size
* sizeof(hh
->mem
[0]));
3821 if (nx
== NULL
) ufoFatal("out of memory for handle of size %u", size
);
3825 if (hh
->used
> size
) hh
->used
= size
;
3831 UFWORD(PAR_HANDLE_GET_USED
) {
3832 const uint32_t hx
= ufoPop();
3834 if ((hx
& UFO_ADDR_HANDLE_BIT
) == 0) ufoFatal("not a handle");
3835 UHandleInfo
*hh
= ufoGetHandle(hx
);
3836 if (hh
== NULL
) ufoFatal("invalid handle");
3845 UFWORD(PAR_HANDLE_SET_USED
) {
3846 const uint32_t hx
= ufoPop();
3847 const uint32_t used
= ufoPop();
3848 if (used
> 0x04000000) ufoFatal("invalid handle used");
3849 if ((hx
& UFO_ADDR_HANDLE_BIT
) == 0) ufoFatal("not a handle");
3850 UHandleInfo
*hh
= ufoGetHandle(hx
);
3851 if (hh
== NULL
) ufoFatal("invalid handle");
3852 if (used
> hh
->size
) ufoFatal("handle used %u out of range (%u)", used
, hh
->size
);
3857 // ( idx hx -- value )
3858 UFWORD(PAR_HANDLE_LOAD
) {
3859 const uint32_t hx
= ufoPop();
3860 const uint32_t idx
= ufoPop();
3861 if ((hx
& UFO_ADDR_HANDLE_BIT
) == 0) ufoFatal("not a handle");
3862 UHandleInfo
*hh
= ufoGetHandle(hx
);
3863 if (hh
== NULL
) ufoFatal("invalid handle");
3864 if (idx
>= hh
->size
) ufoFatal("handle index %u out of range (%u)", idx
, hh
->size
);
3865 ufoPush(hh
->mem
[idx
]);
3869 // ( value idx hx -- value )
3870 UFWORD(PAR_HANDLE_STORE
) {
3871 const uint32_t hx
= ufoPop();
3872 const uint32_t idx
= ufoPop();
3873 const uint32_t value
= ufoPop();
3874 if ((hx
& UFO_ADDR_HANDLE_BIT
) == 0) ufoFatal("not a handle");
3875 UHandleInfo
*hh
= ufoGetHandle(hx
);
3876 if (hh
== NULL
) ufoFatal("invalid handle");
3877 if (idx
>= hh
->size
) ufoFatal("handle index %u out of range (%u)", idx
, hh
->size
);
3878 hh
->mem
[idx
] = value
;
3881 // DEBUG:(DECOMPILE-CFA)
3883 UFWORD(DEBUG_DECOMPILE_CFA
) {
3884 const uint32_t cfa
= ufoPop();
3885 ufoDecompileWord(cfa
);
3891 ufoPush((uint32_t)ufo_get_msecs());
3895 // ////////////////////////////////////////////////////////////////////////// //
3899 UFWORD(DLR_END_FORTH_IMM
) {
3900 if (ufoMode
!= UFO_MODE_NATIVE
) ufoFatal("$END_FORTH in non-native mode");
3901 if (ufoImgGetU32(ufoAddrSTATE
) != 0) ufoFatal("$END_FORTH: still compiling something");
3902 longjmp(ufoInlineQuitJP
, 1);
3906 // ////////////////////////////////////////////////////////////////////////// //
3909 #define UFWORD(name_) do { \
3910 const uint32_t xcfa_ = ufoCFAsUsed; \
3911 ufo_assert(xcfa_ < UFO_MAX_NATIVE_CFAS); \
3912 ufoForthCFAs[xcfa_] = &ufoWord_##name_; \
3914 ufoDefineNative(""#name_, xcfa_, 0); \
3917 #define UFWORDX(strname_,name_) do { \
3918 const uint32_t xcfa_ = ufoCFAsUsed; \
3919 ufo_assert(xcfa_ < UFO_MAX_NATIVE_CFAS); \
3920 ufoForthCFAs[xcfa_] = &ufoWord_##name_; \
3922 ufoDefineNative(strname_, xcfa_, 0); \
3925 #define UFWORD_IMM(name_) do { \
3926 const uint32_t xcfa_ = ufoCFAsUsed; \
3927 ufo_assert(xcfa_ < UFO_MAX_NATIVE_CFAS); \
3928 ufoForthCFAs[xcfa_] = &ufoWord_##name_; \
3930 ufoDefineNative(""#name_, xcfa_, 1); \
3933 #define UFWORDX_IMM(strname_,name_) do { \
3934 const uint32_t xcfa_ = ufoCFAsUsed; \
3935 ufo_assert(xcfa_ < UFO_MAX_NATIVE_CFAS); \
3936 ufoForthCFAs[xcfa_] = &ufoWord_##name_; \
3938 ufoDefineNative(strname_, xcfa_, 1); \
3941 #define UFC(name_) ufoImgEmitU32_NoInline(ufoFindWordChecked(name_))
3944 //==========================================================================
3946 // ufoFindWordChecked
3948 //==========================================================================
3949 static __attribute__((noinline
)) uint32_t ufoFindWordChecked (const char *wname
) {
3950 const uint32_t cfa
= ufoFindWord(wname
);
3951 if (cfa
== 0) ufoFatal("word '%s' not found", wname
);
3956 //==========================================================================
3958 // ufoVocSetOnlyDefs
3960 //==========================================================================
3961 static void ufoVocSetOnlyDefs (uint32_t vocid
) {
3962 ufoImgPutU32(ufoAddrCurrent
, vocid
);
3963 ufoImgPutU32(ufoAddrContext
, vocid
);
3967 //==========================================================================
3971 // return voc PFA (vocid)
3973 //==========================================================================
3974 static uint32_t ufoCreateVoc (const char *wname
, uint32_t parentvocid
) {
3975 // create wordlist struct
3976 const uint32_t vocid
= UFO_GET_DP();
3977 //fprintf(stderr, "NEW VOCID (%s): 0x%08x\n", wname, vocid);
3978 ufoImgEmitU32(0); // latest
3979 const uint32_t vlink
= UFO_GET_DP();
3980 if ((vocid
& UFO_ADDR_TEMP_BIT
) == 0) {
3981 ufoImgEmitU32(ufoImgGetU32(ufoAddrVocLink
)); // voclink
3982 ufoImgPutU32(ufoAddrVocLink
, vlink
); // update voclink
3987 ufoImgEmitU32(parentvocid
); // parent
3988 const uint32_t hdraddr
= UFO_GET_DP();
3989 ufoImgEmitU32(0); // word header
3990 // create empty hash table
3991 for (int f
= 0; f
< UFO_HASHTABLE_SIZE
; f
+= 1) ufoImgEmitU32(0);
3992 // update CONTEXT and CURRENT if this is the first wordlist ever
3993 if (ufoImgGetU32(ufoAddrContext
) == 0) {
3994 ufoImgPutU32(ufoAddrContext
, vocid
);
3996 if (ufoImgGetU32(ufoAddrCurrent
) == 0) {
3997 ufoImgPutU32(ufoAddrCurrent
, vocid
);
3999 // create word header
4000 if (wname
!= NULL
&& wname
[0] != 0) {
4001 uint32_t flags
= ufoImgGetU32(ufoAddrNewWordFlags
);
4003 //UFW_FLAG_IMMEDIATE|
4005 //UFW_FLAG_NORETURN|
4011 flags
|= UFW_FLAG_VOCAB
;
4012 ufoCreateWordHeader(wname
, flags
);
4013 const uint32_t cfa
= UFO_GET_DP();
4014 ufoImgEmitU32(ufoDoVocCFA
); // cfa
4015 ufoImgEmitU32(vocid
); // pfa
4017 const uint32_t lfa
= UFO_CFA_TO_LFA(cfa
);
4018 const uint32_t sfa
= UFO_LFA_TO_SFA(lfa
);
4019 ufoImgPutU32(sfa
, UFO_GET_DP());
4020 // update vocab header pointer
4021 ufoImgPutU32(hdraddr
, UFO_LFA_TO_NFA(lfa
));
4022 #ifdef UFO_DEBUG_DUMP_NEW_HEADERS
4023 ufoDumpWordHeader(lfa
);
4030 //==========================================================================
4034 //==========================================================================
4035 static void ufoFixLatestSFA (void) {
4036 const uint32_t curr
= ufoImgGetU32(ufoAddrCurrent
);
4037 const uint32_t lfa
= ufoImgGetU32(curr
);
4038 const uint32_t sfa
= UFO_LFA_TO_SFA(lfa
);
4039 ufoImgPutU32(sfa
, UFO_GET_DP()); // update sfa
4040 #ifdef UFO_DEBUG_DUMP_NEW_HEADERS
4041 ufoDumpWordHeader(lfa
);
4046 //==========================================================================
4050 //==========================================================================
4051 static void ufoSetLatestArgs (uint32_t warg
) {
4052 const uint32_t curr
= ufoImgGetU32(ufoAddrCurrent
);
4053 const uint32_t lfa
= ufoImgGetU32(curr
);
4054 const uint32_t nfa
= UFO_LFA_TO_NFA(lfa
);
4055 uint32_t flags
= ufoImgGetU32(nfa
);
4056 //fprintf(stderr, "OLD FLAGS: 0x%08x\n", flags);
4057 flags
&= ~UFW_WARG_MASK
;
4058 flags
|= warg
& UFW_WARG_MASK
;
4059 //fprintf(stderr, "NEW FLAGS: 0x%08x\n", flags);
4060 ufoImgPutU32(nfa
, flags
);
4061 #ifdef UFO_DEBUG_DUMP_NEW_HEADERS
4062 ufoDumpWordHeader(lfa
);
4067 //==========================================================================
4071 //==========================================================================
4072 static void ufoDefineNative (const char *wname
, uint32_t cfaidx
, int immed
) {
4073 cfaidx
|= UFO_ADDR_CFA_BIT
;
4074 uint32_t flags
= ufoImgGetU32(ufoAddrNewWordFlags
);
4076 //UFW_FLAG_IMMEDIATE|
4078 //UFW_FLAG_NORETURN|
4084 if (immed
) flags
|= UFW_FLAG_IMMEDIATE
;
4085 ufoCreateWordHeader(wname
, flags
);
4086 ufoImgEmitU32(cfaidx
);
4091 //==========================================================================
4093 // ufoDefineConstant
4095 //==========================================================================
4096 static void ufoDefineConstant (const char *name
, uint32_t value
) {
4097 ufoDefineNative(name
, ufoDoConstCFA
, 0);
4098 ufoImgEmitU32(value
);
4103 //==========================================================================
4107 //==========================================================================
4109 static void ufoDefineVar (const char *name, uint32_t value) {
4110 ufoDefineNative(name, ufoDoVarCFA, 0);
4111 ufoImgEmitU32(value);
4117 //==========================================================================
4121 //==========================================================================
4123 static void ufoDefineDefer (const char *name, uint32_t value) {
4124 ufoDefineNative(name, ufoDoDeferCFA, 0);
4125 ufoImgEmitU32(value);
4131 //==========================================================================
4135 //==========================================================================
4136 static void ufoDefineForth (const char *name
) {
4137 ufoDefineNative(name
, ufoDoForthCFA
, 0);
4141 //==========================================================================
4143 // ufoDefineForthImm
4145 //==========================================================================
4146 static void ufoDefineForthImm (const char *name
) {
4147 ufoDefineNative(name
, ufoDoForthCFA
, 1);
4151 //==========================================================================
4153 // ufoDefineSColonForth
4155 // create word suitable for scattered colon extension
4157 //==========================================================================
4158 static void ufoDefineSColonForth (const char *name
) {
4159 ufoDefineNative(name
, ufoDoForthCFA
, 0);
4160 // placeholder for scattered colon
4161 // it will compile two branches:
4162 // the first branch will jump to the first "..:" word (or over the two branches)
4163 // the second branch is never taken, and works as a pointer to the latest branch addr in the list
4164 // this way, each extension word will simply fix the last branch address, and update list tail
4165 // at the creation time, second branch points to the first branch
4166 UFC("FORTH:(BRANCH)");
4167 const uint32_t xjmp
= UFO_GET_DP();
4169 UFC("FORTH:(BRANCH)"); ufoImgEmitU32(xjmp
);
4170 ufoImgPutU32(xjmp
, UFO_GET_DP());
4174 //==========================================================================
4178 //==========================================================================
4179 UFO_FORCE_INLINE
void ufoDoneForth (void) {
4184 //==========================================================================
4188 //==========================================================================
4189 static __attribute__((noinline
)) void ufoReset (void) {
4190 ufoSP
= 0; ufoRP
= 0;
4191 ufoLP
= 0; ufoLBP
= 0;
4195 ufoImgPutU32(ufoAddrSTATE
, 0);
4196 ufoImgPutU32(ufoAddrBASE
, 10);
4197 ufoImgPutU32(ufoAddrTIB
, 0);
4198 ufoImgPutU32(ufoAddrIN
, 0);
4201 ufoImgPutU32(ufoAddrDPTemp
, 0);
4203 ufoImgPutU32(ufoAddrNewWordFlags
, 0);
4204 ufoVocSetOnlyDefs(ufoForthVocId
);
4208 //==========================================================================
4212 // compile string literal, the same as QUOTE_IMM
4214 //==========================================================================
4215 static void ufoCompileStrLit (const char *str
) {
4216 if (str
== NULL
) str
= "";
4217 const size_t slen
= strlen(str
);
4218 if (slen
> 255) ufoFatal("string literal too long");
4219 UFC("FORTH:(STRLIT8)");
4220 ufoImgEmitU8((uint8_t)slen
);
4221 for (size_t f
= 0; f
< slen
; f
+= 1) {
4222 ufoImgEmitU8(((const unsigned char *)str
)[f
]);
4229 //==========================================================================
4233 //==========================================================================
4234 static __attribute__((unused
)) void ufoCompileLit (uint32_t value
) {
4236 ufoImgEmitU32(value
);
4240 //==========================================================================
4244 //==========================================================================
4245 UFO_FORCE_INLINE
uint32_t ufoMarkFwd (void) {
4246 const uint32_t res
= UFO_GET_DP();
4252 //==========================================================================
4256 //==========================================================================
4257 UFO_FORCE_INLINE
void ufoResolveFwd (uint32_t jaddr
) {
4258 ufoImgPutU32(jaddr
, UFO_GET_DP());
4262 //==========================================================================
4266 //==========================================================================
4267 UFO_FORCE_INLINE
uint32_t ufoMarkBwd (void) {
4268 return UFO_GET_DP();
4272 //==========================================================================
4276 //==========================================================================
4277 UFO_FORCE_INLINE
void ufoResolveBwd (uint32_t jaddr
) {
4278 ufoImgEmitU32(jaddr
);
4282 //==========================================================================
4284 // ufoDefineInterpret
4286 // define "INTERPRET" in Forth
4288 //==========================================================================
4289 static __attribute__((noinline
)) void ufoDefineInterpret (void) {
4290 // skip comments, parse name, refilling lines if necessary
4291 ufoDefineForth("(INTERPRET-PARSE-NAME)");
4292 const uint32_t label_ipn_again
= ufoMarkBwd();
4293 UFC("TRUE"); UFC("(PARSE-SKIP-COMMENTS)");
4296 UFC("FORTH:(TBRANCH)"); const uint32_t label_ipn_exit_fwd
= ufoMarkFwd();
4298 UFC("REFILL"); UFC("NOT");
4299 ufoCompileStrLit("unexpected end of file");
4301 UFC("FORTH:(BRANCH)"); ufoResolveBwd(label_ipn_again
);
4302 // patch the jump above
4303 ufoResolveFwd(label_ipn_exit_fwd
);
4304 UFC("FORTH:(EXIT)");
4305 ufoDoneForth(); UFCALL(PAR_HIDDEN
);
4306 //ufoDecompileWord(ufoFindWordChecked("(INTERPRET-PARSE-NAME)"));
4308 ufoDefineForth("INTERPRET");
4309 const uint32_t label_it_again
= ufoMarkBwd();
4310 UFC("FORTH:(INTERPRET-PARSE-NAME)");
4311 // try defered checker
4312 // ( addr count FALSE -- addr count FALSE / TRUE )
4313 UFC("FALSE"); UFC("(INTERPRET-CHECK-WORD)");
4314 UFC("FORTH:(TBRANCH)"); ufoResolveBwd(label_it_again
);
4315 UFC("2DUP"); UFC("FIND-WORD"); // ( addr count cfa TRUE / addr count FALSE )
4316 UFC("FORTH:(0BRANCH)"); const uint32_t label_it_try_num
= ufoMarkFwd();
4317 UFC("NROT"); UFC("2DROP"); // drop word string
4318 UFC("STATE"); UFC("@");
4319 UFC("FORTH:(0BRANCH)"); const uint32_t label_it_exec_fwd
= ufoMarkFwd();
4320 // compiling; check immediate bit
4321 UFC("DUP"); UFC("CFA->NFA"); UFC("@");
4322 UFC("COMPILER:(WFLAG-IMMEDIATE)"); UFC("AND");
4323 UFC("FORTH:(TBRANCH)"); const uint32_t label_it_exec_imm
= ufoMarkFwd();
4325 UFC("FORTH:COMPILE,");
4326 UFC("FORTH:(BRANCH)"); ufoResolveBwd(label_it_again
);
4328 ufoResolveFwd(label_it_exec_imm
);
4329 ufoResolveFwd(label_it_exec_fwd
);
4331 UFC("FORTH:(BRANCH)"); ufoResolveBwd(label_it_again
);
4332 // not a word, try a number
4333 ufoResolveFwd(label_it_try_num
);
4334 UFC("2DUP"); UFC("TRUE"); UFC("FORTH:(XNUMBER)");
4335 // (XNUMBER) ( addr count allowsign? -- num TRUE / FALSE )
4336 UFC("FORTH:(0BRANCH)"); const uint32_t label_it_num_error
= ufoMarkFwd();
4338 UFC("NROT"); UFC("2DROP"); // drop word string
4339 // do we need to compile it?
4340 UFC("STATE"); UFC("@");
4341 UFC("FORTH:(0BRANCH)"); ufoResolveBwd(label_it_again
);
4342 // compile "(LITERAL)" (do it properly, with "LITCFA")
4343 UFC("FORTH:(LITCFA)"); UFC("FORTH:(LIT)");
4344 UFC("FORTH:COMPILE,"); // compile "(LIT)" CFA
4345 UFC("FORTH:,"); // compile number
4346 UFC("FORTH:(BRANCH)"); ufoResolveBwd(label_it_again
);
4348 ufoResolveFwd(label_it_num_error
);
4349 // ( addr count FALSE -- addr count FALSE / TRUE )
4350 UFC("FALSE"); UFC("(INTERPRET-WORD-NOT-FOUND)");
4351 UFC("FORTH:(TBRANCH)"); ufoResolveBwd(label_it_again
);
4352 UFC("ENDCR"); UFC("SPACE"); UFC("XTYPE");
4353 ufoCompileStrLit(" -- wut?\n"); UFC("TYPE");
4354 ufoCompileStrLit("unknown word");
4357 //ufoDecompileWord(ufoFindWordChecked("INTERPRET"));
4361 //==========================================================================
4365 //==========================================================================
4366 static __attribute__((noinline
)) void ufoInitBaseDict (void) {
4367 uint32_t imgAddr
= 0;
4370 for (uint32_t f
= 0; f
< ufoTIBAreaSize
; f
+= 1) {
4371 ufoImgPutU8(imgAddr
, 0);
4375 while ((imgAddr
& 3) != 0) {
4376 ufoImgPutU8(imgAddr
, 0);
4380 // reserve numeric buffer
4381 for (uint32_t f
= 0; f
< ufoNUMAreaSize
; f
+= 1) {
4382 ufoImgPutU8(imgAddr
, 0);
4386 while ((imgAddr
& 3) != 0) {
4387 ufoImgPutU8(imgAddr
, 0);
4392 ufoAddrBASE
= imgAddr
;
4393 ufoImgPutU32(imgAddr
, 10); imgAddr
+= 4u;
4396 ufoAddrSTATE
= imgAddr
;
4397 ufoImgPutU32(imgAddr
, 0); imgAddr
+= 4u;
4400 ufoAddrDP
= imgAddr
;
4401 ufoImgPutU32(imgAddr
, 0); imgAddr
+= 4u;
4404 ufoAddrDPTemp
= imgAddr
;
4405 ufoImgPutU32(imgAddr
, 0); imgAddr
+= 4u;
4408 ufoAddrTIB
= imgAddr
;
4409 ufoImgPutU32(imgAddr
, 0); imgAddr
+= 4u;
4412 ufoAddrIN
= imgAddr
;
4413 ufoImgPutU32(imgAddr
, 0); imgAddr
+= 4u;
4416 ufoAddrContext
= imgAddr
;
4417 ufoImgPutU32(imgAddr
, 0); imgAddr
+= 4u;
4420 ufoAddrCurrent
= imgAddr
;
4421 ufoImgPutU32(imgAddr
, 0); imgAddr
+= 4u;
4424 ufoAddrVocLink
= imgAddr
;
4425 ufoImgPutU32(imgAddr
, 0); imgAddr
+= 4u;
4428 ufoAddrNewWordFlags
= imgAddr
;
4429 ufoImgPutU32(imgAddr
, UFW_FLAG_PROTECTED
); imgAddr
+= 4u;
4431 ufoImgPutU32(ufoAddrDP
, imgAddr
);
4432 ufoImgPutU32(ufoAddrDPTemp
, 0);
4435 fprintf(stderr
, "INITIAL HERE: 0x%08x (0x%08x)\n", imgAddr
, UFO_GET_DP());
4440 //==========================================================================
4442 // ufoInitBasicWords
4444 //==========================================================================
4445 static __attribute__((noinline
)) void ufoInitBasicWords (void) {
4446 ufoDefineConstant("FALSE", 0);
4447 ufoDefineConstant("TRUE", ufoTrueValue
);
4449 ufoDefineConstant("BL", 32);
4450 ufoDefineConstant("NL", 10);
4453 ufoDefineConstant("BASE", ufoAddrBASE
);
4454 ufoDefineConstant("STATE", ufoAddrSTATE
);
4455 ufoDefineConstant("TIB", ufoAddrTIB
);
4456 ufoDefineConstant(">IN", ufoAddrIN
);
4457 ufoDefineConstant("STD-TIB-ADDR", 0);
4458 ufoDefineConstant("STD-TIB-SIZE", ufoTIBAreaSize
);
4459 ufoDefineConstant("(#BUF-START)", ufoTIBAreaSize
+ 4u); UFCALL(PAR_HIDDEN
);
4460 ufoDefineConstant("(#BUF-END)", ufoTIBAreaSize
+ ufoNUMAreaSize
); UFCALL(PAR_HIDDEN
);
4461 ufoDefineConstant("(#BUF-SIZE)", ufoNUMAreaSize
- 4u); UFCALL(PAR_HIDDEN
);
4462 ufoDefineConstant("(#BUF-OFS)", ufoTIBAreaSize
); UFCALL(PAR_HIDDEN
);
4463 ufoDefineConstant("CONTEXT", ufoAddrContext
);
4464 ufoDefineConstant("CURRENT", ufoAddrCurrent
);
4465 ufoDefineConstant("(VOC-LINK)", ufoAddrVocLink
); UFCALL(PAR_HIDDEN
);
4466 ufoDefineConstant("(NEW-WORD-FLAGS)", ufoAddrNewWordFlags
); UFCALL(PAR_HIDDEN
);
4467 ufoDefineConstant("(ADDR-TEMP-BIT)", UFO_ADDR_TEMP_BIT
); UFCALL(PAR_HIDDEN
);
4468 ufoDefineConstant("(ADDR-CFA-BIT)", UFO_ADDR_CFA_BIT
); UFCALL(PAR_HIDDEN
);
4469 ufoDefineConstant("(ADDR-HANDLE-BIT)", UFO_ADDR_HANDLE_BIT
); UFCALL(PAR_HIDDEN
);
4471 ufoDefineConstant("(DP)", ufoAddrDP
); UFCALL(PAR_HIDDEN
);
4472 ufoDefineConstant("(DP-TEMP)", ufoAddrDPTemp
); UFCALL(PAR_HIDDEN
);
4474 //UFWORDX("(UFO-BUCKET-STATS)", PAR_UFO_BUCKET_STATS);
4475 UFWORDX("SP0!", SP0_STORE
);
4476 UFWORDX("RP0!", RP0_STORE
);
4478 UFWORDX("PAD", PAD
);
4481 UFWORDX("C@", CPEEK
);
4482 UFWORDX("W@", WPEEK
);
4485 UFWORDX("C!", CPOKE
);
4486 UFWORDX("W!", WPOKE
);
4488 UFWORDX(",", COMMA
);
4489 UFWORDX("C,", CCOMMA
);
4490 UFWORDX("W,", WCOMMA
);
4492 UFWORDX("(LIT)", PAR_LIT
); ufoSetLatestArgs(UFW_WARG_LIT
); UFCALL(PAR_HIDDEN
);
4493 UFWORDX("(LITCFA)", PAR_LITCFA
); ufoSetLatestArgs(UFW_WARG_CFA
); UFCALL(PAR_HIDDEN
);
4494 UFWORDX("(LITVOCID)", PAR_LITVOCID
); ufoSetLatestArgs(UFW_WARG_VOCID
); UFCALL(PAR_HIDDEN
);
4495 UFWORDX("(STRLIT8)", PAR_STRLIT8
); ufoSetLatestArgs(UFW_WARG_C1STRZ
); UFCALL(PAR_HIDDEN
);
4496 UFWORDX("(EXIT)", PAR_EXIT
); UFCALL(PAR_HIDDEN
);
4498 ufoStrLit8CFA
= ufoFindWordChecked("FORTH:(STRLIT8)");
4500 UFWORDX("(L-ENTER)", PAR_LENTER
); ufoSetLatestArgs(UFW_WARG_LIT
); UFCALL(PAR_HIDDEN
);
4501 UFWORDX("(L-LEAVE)", PAR_LLEAVE
); UFCALL(PAR_HIDDEN
);
4502 UFWORDX("(LOCAL@)", PAR_LOCAL_LOAD
); UFCALL(PAR_HIDDEN
);
4503 UFWORDX("(LOCAL!)", PAR_LOCAL_STORE
); UFCALL(PAR_HIDDEN
);
4505 UFWORDX("(BRANCH)", PAR_BRANCH
); ufoSetLatestArgs(UFW_WARG_BRANCH
); UFCALL(PAR_HIDDEN
);
4506 UFWORDX("(TBRANCH)", PAR_TBRANCH
); ufoSetLatestArgs(UFW_WARG_BRANCH
); UFCALL(PAR_HIDDEN
);
4507 UFWORDX("(0BRANCH)", PAR_0BRANCH
); ufoSetLatestArgs(UFW_WARG_BRANCH
); UFCALL(PAR_HIDDEN
);
4509 UFWORDX("(HIDDEN)", PAR_HIDDEN
);
4511 UFWORDX("GET-MSECS", GET_MSECS
);
4515 //==========================================================================
4517 // ufoInitBasicCompilerWords
4519 //==========================================================================
4520 static __attribute__((noinline
)) void ufoInitBasicCompilerWords (void) {
4521 ufoVocSetOnlyDefs(ufoCompilerVocId
);
4523 ufoDefineConstant("(CFAIDX-DO-FORTH)", ufoDoForthCFA
);
4524 ufoDefineConstant("(CFAIDX-DO-VAR)", ufoDoVarCFA
);
4525 ufoDefineConstant("(CFAIDX-DO-VALUE)", ufoDoValueCFA
);
4526 ufoDefineConstant("(CFAIDX-DO-CONST)", ufoDoConstCFA
);
4527 ufoDefineConstant("(CFAIDX-DO-DEFER)", ufoDoDeferCFA
);
4528 ufoDefineConstant("(CFAIDX-DO-VOC)", ufoDoVocCFA
);
4530 ufoDefineConstant("(WFLAG-IMMEDIATE)", UFW_FLAG_IMMEDIATE
);
4531 ufoDefineConstant("(WFLAG-SMUDGE)", UFW_FLAG_SMUDGE
);
4532 ufoDefineConstant("(WFLAG-NORETURN)", UFW_FLAG_NORETURN
);
4533 ufoDefineConstant("(WFLAG-HIDDEN)", UFW_FLAG_HIDDEN
);
4534 ufoDefineConstant("(WFLAG-CBLOCK)", UFW_FLAG_CBLOCK
);
4535 ufoDefineConstant("(WFLAG-VOCAB)", UFW_FLAG_VOCAB
);
4536 ufoDefineConstant("(WFLAG-SCOLON)", UFW_FLAG_SCOLON
);
4537 ufoDefineConstant("(WFLAG-PROTECTED)", UFW_FLAG_PROTECTED
);
4539 ufoDefineConstant("(WARG-MASK)", UFW_WARG_MASK
);
4540 ufoDefineConstant("(WARG-NONE)", UFW_WARG_NONE
);
4541 ufoDefineConstant("(WARG-BRANCH)", UFW_WARG_BRANCH
);
4542 ufoDefineConstant("(WARG-LIT)", UFW_WARG_LIT
);
4543 ufoDefineConstant("(WARG-C4STRZ)", UFW_WARG_C4STRZ
);
4544 ufoDefineConstant("(WARG-CFA)", UFW_WARG_CFA
);
4545 ufoDefineConstant("(WARG-CBLOCK)", UFW_WARG_CBLOCK
);
4546 ufoDefineConstant("(WARG-VOCID)", UFW_WARG_VOCID
);
4547 ufoDefineConstant("(WARG-C1STRZ)", UFW_WARG_C1STRZ
);
4549 ufoDefineConstant("(VOCOFS-LATEST)", UFW_VOCAB_OFS_LATEST
);
4550 ufoDefineConstant("(VOCOFS-VOCLINK)", UFW_VOCAB_OFS_VOCLINK
);
4551 ufoDefineConstant("(VOCOFS-PARENT)", UFW_VOCAB_OFS_PARENT
);
4552 ufoDefineConstant("(VOCOFS-HEADER)", UFW_VOCAB_OFS_HEADER
);
4553 ufoDefineConstant("(VOCOFS-HTABLE)", UFW_VOCAB_OFS_HTABLE
);
4554 ufoDefineConstant("(VOC-HTABLE-SIZE)", UFO_HASHTABLE_SIZE
);
4555 ufoDefineConstant("(VOC-HTABLE-NOFLAG)", UFO_NO_HTABLE_FLAG
);
4557 UFWORDX("(UNESCAPE)", PAR_UNESCAPE
);
4559 UFWORDX("?EXEC", QEXEC
);
4560 UFWORDX("?COMP", QCOMP
);
4564 UFWORDX("(INTERPRET-DUMB)", PAR_INTERPRET_DUMB); UFCALL(PAR_HIDDEN);
4565 const uint32_t idumbCFA = UFO_LFA_TO_CFA(ufoImgGetU32(ufoImgGetU32(ufoAddrCurrent)));
4566 ufo_assert(idumbCFA == UFO_PFA_TO_CFA(UFO_GET_DP()));
4569 UFWORDX("(CREATE-WORD-HEADER)", PAR_CREATE_WORD_HEADER
);
4570 UFWORDX("(CREATE-NAMELESS-WORD-HEADER)", PAR_CREATE_NAMELESS_WORD_HEADER
);
4574 ufoVocSetOnlyDefs(ufoForthVocId
);
4578 //==========================================================================
4582 //==========================================================================
4583 static __attribute__((noinline
)) void ufoInitMoreWords (void) {
4584 UFWORDX("COMPILE,", COMMA
); // just an alias, for clarity
4586 UFWORDX("CFA->PFA", CFA2PFA
);
4587 UFWORDX("PFA->CFA", PFA2CFA
);
4588 UFWORDX("CFA->NFA", CFA2NFA
);
4589 UFWORDX("NFA->CFA", NFA2CFA
);
4590 UFWORDX("CFA->LFA", CFA2LFA
);
4591 UFWORDX("LFA->CFA", LFA2CFA
);
4592 UFWORDX("LFA->PFA", LFA2PFA
);
4593 UFWORDX("LFA->BFA", LFA2BFA
);
4594 UFWORDX("LFA->SFA", LFA2SFA
);
4595 UFWORDX("LFA->NFA", LFA2NFA
);
4596 UFWORDX("NFA->LFA", NFA2LFA
);
4598 UFWORDX("ERROR", ERROR
);
4599 UFWORDX("?ERROR", QERROR
);
4601 UFWORDX("(XNUMBER)", PAR_XNUMBER
);
4602 UFWORDX("FIND-WORD", FIND_WORD
);
4603 UFWORDX("FIND-WORD-IN-VOC", FIND_WORD_IN_VOC
);
4605 UFWORDX_IMM("\"", QUOTE_IMM
);
4608 UFWORDX("EXECUTE-TAIL", EXECUTE_TAIL
);
4611 UFWORDX("?DUP", QDUP
);
4612 UFWORDX("2DUP", DDUP
);
4614 UFWORDX("2DROP", DDROP
);
4616 UFWORDX("2SWAP", DSWAP
);
4618 UFWORDX("2OVER", DOVER
);
4621 UFWORDX("PICK", PICK
);
4622 UFWORDX("ROLL", ROLL
);
4626 UFWORDX(">R", DTOR
);
4627 UFWORDX("R>", RTOD
);
4628 UFWORDX("R@", RPEEK
);
4629 UFWORDX("RPICK", RPICK
);
4630 UFWORDX("RROLL", RROLL
);
4640 UFWORDX("LASTCR?", LASTCRQ
);
4641 UFWORDX("LASTCR!", LASTCRSET
);
4645 UFWORDX("-", MINUS
);
4647 UFWORDX("U*", UMUL
);
4649 UFWORDX("U/", UDIV
);
4650 UFWORDX("MOD", MOD
);
4651 UFWORDX("UMOD", UMOD
);
4652 UFWORDX("/MOD", DIVMOD
);
4653 UFWORDX("U/MOD", UDIVMOD
);
4655 UFWORDX("2U*", ONESHL
);
4656 UFWORDX("2U/", ONESHR
);
4657 UFWORDX("4U*", TWOSHL
);
4658 UFWORDX("4U/", TWOSHR
);
4665 UFWORDX(">", GREAT
);
4666 UFWORDX("<=", LESSEQU
);
4667 UFWORDX(">=", GREATEQU
);
4668 UFWORDX("U<", ULESS
);
4669 UFWORDX("U>", UGREAT
);
4670 UFWORDX("U<=", ULESSEQU
);
4671 UFWORDX("U>=", UGREATEQU
);
4673 UFWORDX("<>", NOTEQU
);
4680 UFWORDX("LOGAND", LOGAND
);
4681 UFWORDX("LOGOR", LOGOR
);
4684 UFWORDX("(PARSE)", PAR_PARSE
); UFCALL(PAR_HIDDEN
);
4685 UFWORDX("(PARSE-SKIP-COMMENTS)", PAR_PARSE_SKIP_COMMENTS
);
4686 UFWORDX("PARSE-SKIP-BLANKS", PARSE_SKIP_BLANKS
);
4687 UFWORDX("PARSE-NAME", PARSE_NAME
);
4688 UFWORDX("PARSE-SKIP-LINE", PARSE_SKIP_LINE
);
4689 UFWORDX("PARSE", PARSE
);
4690 UFWORDX("REFILL", REFILL
);
4691 UFWORDX("REFILL-NOCROSS", REFILL_NOCROSS
);
4693 UFWORDX_IMM("[", LBRACKET_IMM
);
4694 UFWORDX("]", RBRACKET
);
4696 UFWORDX("(VSP@)", PAR_GET_VSP
); UFCALL(PAR_HIDDEN
);
4697 UFWORDX("(VSP!)", PAR_SET_VSP
); UFCALL(PAR_HIDDEN
);
4698 UFWORDX("(VSP-AT@)", PAR_VSP_LOAD
); UFCALL(PAR_HIDDEN
);
4699 UFWORDX("(VSP-AT!)", PAR_VSP_STORE
); UFCALL(PAR_HIDDEN
);
4700 ufoDefineConstant("(VSP-SIZE)", UFO_VOCSTACK_SIZE
); UFCALL(PAR_HIDDEN
);
4702 ufoDefineConstant("(SP-SIZE)", UFO_DSTACK_SIZE
); UFCALL(PAR_HIDDEN
);
4703 ufoDefineConstant("(RP-SIZE)", UFO_RSTACK_SIZE
); UFCALL(PAR_HIDDEN
);
4704 ufoDefineConstant("(LP-SIZE)", UFO_LSTACK_SIZE
); UFCALL(PAR_HIDDEN
);
4708 //==========================================================================
4710 // ufoInitHandleWords
4712 //==========================================================================
4713 static __attribute__((noinline
)) void ufoInitHandleWords (uint32_t handleVocId
) {
4714 ufoVocSetOnlyDefs(handleVocId
);
4715 UFWORDX("NEW", PAR_NEW_HANDLE
);
4716 UFWORDX("FREE", PAR_FREE_HANDLE
);
4717 UFWORDX("GET-SIZE", PAR_HANDLE_GET_SIZE
);
4718 UFWORDX("SET-SIZE", PAR_HANDLE_SET_SIZE
);
4719 UFWORDX("GET-USED", PAR_HANDLE_GET_USED
);
4720 UFWORDX("SET-USED", PAR_HANDLE_SET_USED
);
4721 UFWORDX("@", PAR_HANDLE_LOAD
);
4722 UFWORDX("!", PAR_HANDLE_STORE
);
4723 ufoVocSetOnlyDefs(ufoForthVocId
);
4727 //==========================================================================
4729 // ufoInitHigherWords
4731 //==========================================================================
4732 static __attribute__((noinline
)) void ufoInitHigherWords (void) {
4733 UFWORDX("(INCLUDE)", PAR_INCLUDE
); UFCALL(PAR_HIDDEN
);
4735 UFWORDX("($DEFINED?)", PAR_DLR_DEFINEDQ
); UFCALL(PAR_HIDDEN
);
4736 UFWORDX("($DEFINE)", PAR_DLR_DEFINE
); UFCALL(PAR_HIDDEN
);
4737 UFWORDX("($UNDEF)", PAR_DLR_UNDEF
); UFCALL(PAR_HIDDEN
);
4738 UFWORDX("(TYPE-CURR-FILE)", PAR_TYPE_CURR_FILE
); UFCALL(PAR_HIDDEN
);
4740 UFWORDX_IMM("$INCLUDE", DLR_INCLUDE_IMM
);
4741 UFWORDX_IMM("$INCLUDE-ONCE", DLR_INCLUDE_ONCE_IMM
);
4745 //==========================================================================
4747 // ufoInitStringWords
4749 //==========================================================================
4750 static __attribute__((noinline
)) void ufoInitStringWords (uint32_t stringVocId
) {
4751 ufoVocSetOnlyDefs(stringVocId
);
4752 UFWORDX("=", STREQU
);
4753 UFWORDX("=CI", STREQUCI
);
4754 UFWORDX("HASH", STRHASH
);
4755 UFWORDX("HASH-CI", STRHASHCI
);
4756 ufoVocSetOnlyDefs(ufoForthVocId
);
4760 //==========================================================================
4762 // ufoInitVeryHighWords
4764 //==========================================================================
4765 static __attribute__((noinline
)) void ufoInitVeryHighWords (void) {
4766 UFWORDX("$LABEL-CODE:", DLR_LABEL_CODE_IMM
);
4767 UFWORDX("$LABEL-DATA:", DLR_LABEL_DATA_IMM
);
4769 UFWORDX_IMM("$END_FORTH", DLR_END_FORTH_IMM
);
4770 UFWORDX_IMM("$END-FORTH", DLR_END_FORTH_IMM
);
4774 //==========================================================================
4776 // ufoInitDebugWords
4778 //==========================================================================
4779 static __attribute__((noinline
)) void ufoInitDebugWords (uint32_t debugVocId
) {
4780 ufoVocSetOnlyDefs(debugVocId
);
4781 UFWORDX("BP", UFO_BP
);
4782 UFWORDX("(DECOMPILE-CFA)", DEBUG_DECOMPILE_CFA
);
4783 UFWORDX("BACKTRACE", UFO_BACKTRACE
);
4784 UFWORDX("DUMP-STACK", DUMP_STACK
);
4785 ufoVocSetOnlyDefs(ufoForthVocId
);
4789 //==========================================================================
4791 // ufoInitUrAsmWords
4793 //==========================================================================
4794 static __attribute__((noinline
)) void ufoInitUrAsmWords (uint32_t urasmVocId
) {
4795 ufoVocSetOnlyDefs(urasmVocId
);
4796 // UrAsm label types
4797 // WARNING! keep in sync with C source!
4798 ufoDefineConstant("LBL-TYPE-UNKNOWN", UFO_ZX_LABEL_UNKNOWN
);
4799 ufoDefineConstant("LBL-TYPE-VAR", UFO_ZX_LABEL_VAR
);
4800 ufoDefineConstant("LBL-TYPE-EQU", UFO_ZX_LABEL_EQU
);
4801 ufoDefineConstant("LBL-TYPE-CODE", UFO_ZX_LABEL_CODE
);
4802 ufoDefineConstant("LBL-TYPE-STOFS", UFO_ZX_LABEL_STOFS
);
4803 ufoDefineConstant("LBL-TYPE-DATA", UFO_ZX_LABEL_DATA
);
4805 UFWORDX("C,", ZX_CCOMMA
);
4806 UFWORDX("W,", ZX_WCOMMA
);
4807 UFWORDX("C@", ZX_CPEEK
);
4808 UFWORDX("C!", ZX_CPOKE
);
4809 UFWORDX("W@", ZX_WPEEK
);
4810 UFWORDX("W!", ZX_WPOKE
);
4812 UFWORDX("RESERVED?", ZX_RESERVEDQ
);
4813 UFWORDX("RESERVED!", ZX_RESERVEDS
);
4815 UFWORDX("HAS-LABEL?", UR_HAS_LABELQ
);
4816 UFWORDX("LABEL-TYPE?", UR_GET_LABELQ_TYPE
);
4817 UFWORDX("GET-LABEL", UR_GET_LABEL
);
4818 UFWORDX("SET-LABEL-VAR", UR_SET_LABEL_VAR
);
4819 UFWORDX("SET-LABEL-EQU", UR_SET_LABEL_EQU
);
4820 UFWORDX("SET-LABEL-CODE", UR_SET_LABEL_CODE
);
4821 UFWORDX("SET-LABEL-STOFS", UR_SET_LABEL_STOFS
);
4822 UFWORDX("SET-LABEL-DATA", UR_SET_LABEL_DATA
);
4823 UFWORDX("NEW-LABEL-ITER", UR_NEW_LABEL_ITER
);
4824 UFWORDX("CLOSE-LABEL-ITER", UR_CLOSE_LABEL_ITER
);
4825 UFWORDX("LABEL-ITER-NEXT", UR_LABEL_ITER_NEXT
);
4826 UFWORDX("LABEL-ITER-GET-NAME", UR_LABEL_ITER_GET_NAME
);
4827 UFWORDX("LABEL-ITER-GET-VALUE", UR_LABEL_ITER_GET_VALUE
);
4828 UFWORDX("LABEL-ITER-GET-TYPE", UR_LABEL_ITER_GET_TYPE
);
4830 UFWORDX("PASS@", UR_PASSQ
);
4832 //UFWORDX("LOAD-DATA-FILE", ZX_LOAD_DATA_FILE);
4834 UFWORDX("ORG@", UR_GETORG
);
4835 UFWORDX("DISP@", UR_GETDISP
);
4836 UFWORDX("ENT@", UR_GETENT
);
4837 UFWORDX("ORG!", UR_SETORG
);
4838 UFWORDX("DISP!", UR_SETDISP
);
4839 UFWORDX("ENT!", UR_SETENT
);
4840 ufoVocSetOnlyDefs(ufoForthVocId
);
4844 //==========================================================================
4846 // ufoInitVeryVeryHighWords
4848 //==========================================================================
4849 static __attribute__((noinline
)) void ufoInitVeryVeryHighWords (void) {
4851 //ufoDefineDefer("INTERPRET", idumbCFA);
4853 // ( addr count FALSE -- addr count FALSE / TRUE )
4854 ufoDefineSColonForth("(INTERPRET-CHECK-WORD)");
4855 UFC("FORTH:(EXIT)");
4857 // ( addr count FALSE -- addr count FALSE / TRUE )
4858 ufoDefineSColonForth("(INTERPRET-WORD-NOT-FOUND)");
4859 UFC("FORTH:(EXIT)");
4861 // ( FALSE -- FALSE / TRUE ) -- called in "EXIT", before compiling "FORTH:(EXIT)"
4862 // return TRUE to stop calling other chained words, and omit default exit
4863 ufoDefineSColonForth("(EXIT-EXTENDER)");
4864 UFC("FORTH:(EXIT)");
4867 // create "FORTH:EXIT"
4868 // : EXIT ?COMP COMPILE FORTH:(EXIT) ;
4869 ufoDefineForthImm("EXIT");
4870 UFC("COMPILER:?COMP");
4871 UFC("FALSE"); UFC("(EXIT-EXTENDER)");
4872 UFC("FORTH:(TBRANCH)"); const uint32_t exit_branch_end
= ufoMarkFwd();
4873 UFC("FORTH:(LITCFA)"); UFC("FORTH:(EXIT)");
4874 UFC("FORTH:COMPILE,");
4875 ufoResolveFwd(exit_branch_end
);
4876 UFC("FORTH:(EXIT)");
4879 ufoDefineInterpret();
4881 //ufoDumpVocab(ufoCompilerVocId);
4883 ufoDefineForth("RUN-INTERPRET-LOOP");
4884 const uint32_t addrAgain
= UFO_GET_DP();
4887 UFC("FORTH:(BRANCH)");
4888 ufoImgEmitU32(addrAgain
);
4893 //==========================================================================
4897 //==========================================================================
4898 static __attribute__((noinline
)) void ufoInitCommon (void) {
4900 ufoForthVocId
= 0; ufoCompilerVocId
= 0; ufoMacroVocId
= 0;
4902 ufoDStack
= calloc(UFO_DSTACK_SIZE
, sizeof(ufoDStack
[0]));
4903 ufoRStack
= calloc(UFO_RSTACK_SIZE
, sizeof(ufoRStack
[0]));
4904 ufoLStack
= calloc(UFO_LSTACK_SIZE
, sizeof(ufoLStack
[0]));
4905 ufoForthCFAs
= calloc(UFO_MAX_NATIVE_CFAS
, sizeof(ufoForthCFAs
[0]));
4907 ufoForthCFAs
[0] = NULL
;
4908 ufoDoForthCFA
= 1u | UFO_ADDR_CFA_BIT
; ufoForthCFAs
[ufoDoForthCFA
& UFO_ADDR_CFA_MASK
] = &ufoDoForth
;
4909 ufoDoVarCFA
= 2u | UFO_ADDR_CFA_BIT
; ufoForthCFAs
[ufoDoVarCFA
& UFO_ADDR_CFA_MASK
] = &ufoDoVariable
;
4910 ufoDoValueCFA
= 3u | UFO_ADDR_CFA_BIT
; ufoForthCFAs
[ufoDoValueCFA
& UFO_ADDR_CFA_MASK
] = &ufoDoValue
;
4911 ufoDoConstCFA
= 4u | UFO_ADDR_CFA_BIT
; ufoForthCFAs
[ufoDoConstCFA
& UFO_ADDR_CFA_MASK
] = &ufoDoConst
;
4912 ufoDoDeferCFA
= 5u | UFO_ADDR_CFA_BIT
; ufoForthCFAs
[ufoDoDeferCFA
& UFO_ADDR_CFA_MASK
] = &ufoDoDefer
;
4913 ufoDoVocCFA
= 6u | UFO_ADDR_CFA_BIT
; ufoForthCFAs
[ufoDoVocCFA
& UFO_ADDR_CFA_MASK
] = &ufoDoVoc
;
4915 ufoMaxDoCFA
= ufoCFAsUsed
;
4917 //fprintf(stderr, "DO-FORTH-CFA: 0x%08x\n", ufoDoForthCFA);
4921 // create "FORTH" vocabulary
4922 ufoForthVocId
= ufoCreateVoc("FORTH", 0);
4923 ufoVocSetOnlyDefs(ufoForthVocId
);
4925 // create "COMPILER" vocabulary
4926 ufoCompilerVocId
= ufoCreateVoc("COMPILER", 0);
4928 // create "STRING" vocabulary
4929 uint32_t stringVocId
= ufoCreateVoc("STRING", 0);
4931 // create "HANDLE" vocabulary
4932 uint32_t handleVocId
= ufoCreateVoc("HANDLE", 0);
4934 // create "URASM-MACROS" vocabulary
4935 ufoMacroVocId
= ufoCreateVoc("URASM-MACROS", 0);
4937 // create "URASM" vocabulary
4938 uint32_t urasmVocId
= ufoCreateVoc("URASM", 0);
4940 // create "DEBUG" vocabulary
4941 uint32_t debugVocId
= ufoCreateVoc("DEBUG", 0);
4943 // base low-level interpreter words
4944 ufoInitBasicWords();
4946 // some COMPILER words
4947 ufoInitBasicCompilerWords();
4952 // HANDLE vocabulary
4953 ufoInitHandleWords(handleVocId
);
4955 // some higher-level FORTH words (includes, etc.)
4956 ufoInitHigherWords();
4958 // STRING vocabulary
4959 ufoInitStringWords(stringVocId
);
4961 // very high-level FORTH words
4962 ufoInitVeryHighWords();
4965 ufoInitDebugWords(debugVocId
);
4968 ufoInitUrAsmWords(urasmVocId
);
4970 // very-very high-level FORTH words
4971 ufoInitVeryVeryHighWords();
4974 ufoDecompileWord(ufoFindWordChecked("RUN-INTERPRET-LOOP"));
4983 //==========================================================================
4987 // address interpreter
4989 //==========================================================================
4990 static void ufoRunVMCFA (uint32_t cfa
) {
4991 const uint32_t oldRPTop
= ufoRPTop
;
4993 #ifdef UFO_TRACE_VM_RUN
4994 fprintf(stderr
, "**VM-INITIAL**: cfa=%u\n", cfa
);
4999 // VM execution loop
5001 if (ufoVMPopCFA
== 0) {
5003 if (ufoIP
== 0) ufoFatal("IP is NULL");
5004 if (ufoIP
& UFO_ADDR_HANDLE_BIT
) ufoFatal("IP is a handle");
5005 cfa
= ufoImgGetU32(ufoIP
); ufoIP
+= 4u;
5007 cfa
= ufoPop(); ufoVMPopCFA
= 0;
5010 if (cfa
== 0) ufoFatal("EXECUTE: NULL CFA");
5011 if (cfa
& UFO_ADDR_HANDLE_BIT
) ufoFatal("cannot execute handle");
5012 // get next word CFAIDX, and check it
5013 uint32_t cfaidx
= ufoImgGetU32(cfa
);
5014 if (cfaidx
& UFO_ADDR_HANDLE_BIT
) ufoFatal("cannot execute CFAIDX-handle");
5015 #ifdef UFO_TRACE_VM_RUN
5016 fprintf(stderr
, "**VM**: IP=%u; cfa=%u; cfaidx=0x%08x\n", ufoIP
- 4u, cfa
, cfaidx
);
5018 ufoDumpWordHeader(UFO_CFA_TO_LFA(cfa
));
5019 fprintf(stderr
, "######################################\n");
5021 if (cfaidx
& UFO_ADDR_CFA_BIT
) {
5022 cfaidx
&= UFO_ADDR_CFA_MASK
;
5023 if (cfaidx
>= ufoCFAsUsed
|| ufoForthCFAs
[cfaidx
] == NULL
) {
5024 ufoFatal("UFO tried to execute an unknown word: %u (max is %u); IP=%u",
5025 cfaidx
, ufoCFAsUsed
, ufoIP
- 4u);
5027 #ifdef UFO_TRACE_VM_RUN
5028 fprintf(stderr
, "**VM-NATIVE**: cfaidx=%u (doForth=%u)\n", cfaidx
,
5029 (ufoDoForthCFA
& UFO_ADDR_CFA_MASK
));
5031 ufoForthCFAs
[cfaidx
](UFO_CFA_TO_PFA(cfa
));
5033 // if CFA points somewhere inside a dict, this is "DOES>" word
5034 // IP points to PFA we need to push
5035 // CFA points to Forth word we need to jump to
5036 #ifdef UFO_TRACE_VM_DOER
5037 fprintf(stderr
, "*** DOER! IP=%u; cfa=%u; cfaidx=%u ***\n", ufoIP
, cfa
, cfaidx
);
5038 UFCALL(UFO_BACKTRACE
);
5040 ufoPush(UFO_CFA_TO_PFA(cfa
)); // push PFA
5041 ufoRPush(ufoIP
); // push IP
5042 ufoIP
= cfaidx
; // fix IP
5044 } while (ufoRP
!= oldRPTop
);
5048 //==========================================================================
5052 //==========================================================================
5053 static void ufoRunIt (const char *wname
) {
5054 uint32_t cfa
= ufoFindWord(wname
);
5055 if (cfa
== 0) ufoFatal("UFO '%s' word not found", wname
);
5060 //==========================================================================
5064 //==========================================================================
5065 void ufoInlineInit (void) {
5066 ufoMode
= UFO_MODE_NATIVE
;
5067 ufoTrueValue
= ~0u; // -1 is better!
5069 ufoInFileLine
= 0; ufoCondStLine
= -1;
5070 ufoInFileName
= NULL
;
5072 ufoLastIncPath
= NULL
;
5074 #ifdef UFO_DEBUG_STARTUP_TIMES
5075 uint32_t stt
= ufo_get_msecs();
5077 UForthCondDefine
*dd
= calloc(1, sizeof(UForthCondDefine
));
5078 if (dd
== NULL
) ufoFatal("out of memory for defines");
5079 dd
->name
= strdup("UFO-DEBUG-STARTUP-TIMES");
5080 if (dd
->name
== NULL
) { free(dd
); ufoFatal("out of memory for defines"); }
5081 dd
->namelen
= (uint32_t)strlen(dd
->name
);
5082 dd
->hash
= joaatHashBufCI(dd
->name
, dd
->namelen
);;
5083 dd
->next
= ufoCondDefines
;
5084 ufoCondDefines
= dd
;
5087 #ifdef UFO_DEBUG_STARTUP_TIMES
5088 uint32_t ett
= ufo_get_msecs();
5089 fprintf(stderr
, "UrForth init time: %u msecs\n", (unsigned)(ett
- stt
));
5097 char *ufmname
= ufoCreateIncludeName("init", 1, NULL
);
5098 FILE *ufl
= ufoOpenFileOrDir(&ufmname
);
5101 ufoInFileName
= ufmname
;
5103 setLastIncPath(ufoInFileName
);
5110 //==========================================================================
5114 //==========================================================================
5115 void ufoInlineRun (void) {
5116 if (ufoMode
== UFO_MODE_NONE
) {
5119 ufoMode
= UFO_MODE_NATIVE
;
5121 if (setjmp(ufoInlineQuitJP
) == 0) {
5123 ufoRunIt("RUN-INTERPRET-LOOP");
5124 ufo_assert(0); // the thing that should not be
5126 while (ufoFileStackPos
!= 0) ufoPopInFile();
5131 //==========================================================================
5135 //==========================================================================
5136 uint32_t ufoIsMacro (const char *wname
) {
5137 if (ufoMode
!= UFO_MODE_NONE
&& wname
!= NULL
&& wname
[0] != 0) {
5138 return ufoFindWordMacro(wname
);
5145 //==========================================================================
5149 //==========================================================================
5150 void ufoMacroRun (uint32_t cfa
, const char *line
, const char *fname
, int lnum
) {
5151 ufo_assert(ufoMode
!= UFO_MODE_NONE
);
5153 if (setjmp(ufoInlineQuitJP
) == 0) {
5155 ufoLoadMacroLine(line
, fname
, lnum
);
5156 const uint32_t oldIP
= ufoIP
;
5159 while (ufoFileStackPos
!= 0) ufoPopInFile();
5161 while (ufoFileStackPos
!= 0) ufoPopInFile();
5162 ufoFatal("wtf with UFO macro?!");
5165 ufoFatal("wtf with UFO macro?!");