1 // and now for something completely different...
2 // UrAsm built-in Forth Engine!
16 #include <sys/types.h>
21 # define realpath(shit,fuck) _fullpath(fuck, shit, 32768)
25 #define UFO_DEBUG_STARTUP_TIMES
26 //#define UFO_DEBUG_FATAL_ABORT
27 #define UFO_DEBUG_DEBUG /* ;-) */
28 //#define UFO_TRACE_VM_DOER
29 //#define UFO_TRACE_VM_RUN
30 //#define UFO_DEBUG_INCLUDE
31 //#define UFO_DEBUG_DUMP_NEW_HEADERS
32 //#define UFO_DEBUG_FIND_WORD
33 //#define UFO_DEBUG_FIND_WORD_IN_VOC
34 //#define UFO_DEBUG_FIND_WORD_COLON
36 // 2/8 msecs w/o inlining
37 // 1/5 msecs with inlining
39 # define UFO_FORCE_INLINE static inline __attribute__((always_inline))
41 # define UFO_FORCE_INLINE static __attribute__((noinline)) __attribute__((unused))
43 #define UFO_DISABLE_INLINE static __attribute__((noinline)) __attribute__((unused))
45 // detect arch, and use faster memory access code on x86
46 #if defined(__x86_64__) || defined(_M_X64) || \
47 defined(i386) || defined(__i386__) || defined(__i386) || defined(_M_IX86)
48 # define UFO_FAST_MEM_ACCESS
51 // should not be bigger than this!
52 #define UFO_MAX_WORD_LENGTH (250)
54 #define UFO_ALIGN4(v_) (((v_) + 3u) / 4u * 4u)
57 // ////////////////////////////////////////////////////////////////////////// //
58 static const char *ufo_assert_failure (const char *cond
, const char *fname
, int fline
, const char *func
) {
59 for (const char *t
= fname
; *t
; ++t
) {
61 if (*t
== '/' || *t
== '\\') fname
= t
+1;
63 if (*t
== '/') fname
= t
+1;
67 fprintf(stderr
, "\n%s:%d: Assertion in `%s` failed: %s\n", fname
, fline
, func
, cond
);
72 #define ufo_assert(cond_) do { if (__builtin_expect((!(cond_)), 0)) { ufo_assert_failure(#cond_, __FILE__, __LINE__, __PRETTY_FUNCTION__); } } while (0)
75 static char ufoRealPathBuf
[32769];
76 static char ufoRealPathHashBuf
[32769];
79 //==========================================================================
83 //==========================================================================
84 static char *ufoRealPath (const char *fname
) {
86 if (fname
!= NULL
&& fname
[0] != 0) {
87 res
= realpath(fname
, NULL
);
89 const size_t slen
= strlen(res
);
91 strcpy(ufoRealPathBuf
, res
);
107 static time_t secstart
= 0;
112 //==========================================================================
116 //==========================================================================
117 static uint64_t ufo_get_msecs (void) {
119 return GetTickCount();
122 #ifdef CLOCK_MONOTONIC
123 ufo_assert(clock_gettime(CLOCK_MONOTONIC
, &ts
) == 0);
125 // this should be available everywhere
126 ufo_assert(clock_gettime(CLOCK_REALTIME
, &ts
) == 0);
130 secstart
= ts
.tv_sec
+1;
131 ufo_assert(secstart
); // it should not be zero
133 return (uint64_t)(ts
.tv_sec
-secstart
+2)*1000U+(uint32_t)ts
.tv_nsec
/1000000U;
135 //return (uint64_t)(ts.tv_sec-secstart+2)*1000000000U+(uint32_t)ts.tv_nsec;
140 //==========================================================================
144 //==========================================================================
145 UFO_FORCE_INLINE
uint32_t joaatHashBuf (const void *buf
, size_t len
, uint8_t orbyte
) {
146 uint32_t hash
= 0x29a;
147 const uint8_t *s
= (const uint8_t *)buf
;
149 hash
+= (*s
++)|orbyte
;
161 // this converts ASCII capitals to locase (and destroys other, but who cares)
162 #define joaatHashBufCI(buf_,len_) joaatHashBuf((buf_), (len_), 0x20)
165 //==========================================================================
169 //==========================================================================
170 UFO_FORCE_INLINE
char toUpper (char ch
) {
171 return (ch
>= 'a' && ch
<= 'z' ? ch
-'a'+'A' : ch
);
175 //==========================================================================
179 //==========================================================================
180 UFO_FORCE_INLINE
uint8_t toUpperU8 (uint8_t ch
) {
181 return (ch
>= 'a' && ch
<= 'z' ? ch
-'a'+'A' : ch
);
185 //==========================================================================
189 //==========================================================================
190 UFO_FORCE_INLINE
int digitInBase (char ch
, int base
) {
192 case '0' ... '9': ch
= ch
- '0'; break;
193 case 'A' ... 'Z': ch
= ch
- 'A' + 10; break;
194 case 'a' ... 'z': ch
= ch
- 'a' + 10; break;
195 default: base
= -1; break;
197 return (ch
>= 0 && ch
< base
? ch
: -1);
202 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
203 ;; word header format:
204 ;; note than name hash is ALWAYS calculated with ASCII-uppercased name
205 ;; (actually, bit 5 is always reset for all bytes, because we don't need the
206 ;; exact uppercase, only something that resembles it)
207 ;; bfa points to next bfa or to 0 (this is "hash bucket pointer")
208 ;; before nfa, we have such "hidden" fields:
209 ;; dd dfa ; pointer to the debug data; can be 0 if debug info is missing
210 ;; dd xfa ; points to the previous word header SFA, regardless of vocabularies (or 0)
211 ;; dd yfa ; points to the previous word header SFA, regardless of vocabularies (or 0)
212 ;; dd bfa ; next word in hashtable bucket; it is always here, even if hashtable is turned off
213 ;; ; if there is no hashtable, this field is not used
215 ;; dd lfa ; previous vocabulary word LFA or 0 (lfa links points here)
216 ;; dd namehash ; it is always here, and always calculated, even if hashtable is turned off
218 ;; dd flags-and-name-len ; see below
219 ;; db name ; no terminating zero or other "termination flag" here
220 ;; here could be some 0 bytes to align everything to 4 bytes
221 ;; db namelen ; yes, name length again, so CFA->NFA can avoid guessing
222 ;; ; full length, including padding, but not including this byte
224 ;; dd cfaidx ; our internal CFA index, or image address for DOES>
228 ;; first word cell contains combined name length (low byte), argtype and flags (other bytes)
233 ;; i.e. we have 16 bits for flags, and 256 possible argument types. why not.
242 ;; bit 6: *UNUSED* main scattered colon word (with "...")
245 ;; argtype is the type of the argument that this word reads from the threaded code.
246 ;; possible argument types:
249 ;; 2: cell-size numeric literal
250 ;; 3: cell-counted string with terminating zero (not counted)
251 ;; 4: cfa of another word
254 ;; 7: byte-counted string with terminating zero (not counted)
255 ;; 8: *UNUSED* unsigned byte
256 ;; 9: *UNUSED* signed byte
257 ;; 10: *UNUSED* unsigned word
258 ;; 11: *UNUSED* signed word
261 ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
262 ;; wordlist structure (at PFA)
263 ;; -4: wordlist type id (used by structs, for example)
265 ;; dd voclink (voclink always points here)
266 ;; dd parent (if not zero, all parent words are visible)
267 ;; dd header-nfa (can be 0 for anonymous wordlists)
268 ;; hashtable (if enabled), or ~0U if no hash table
272 // ////////////////////////////////////////////////////////////////////////// //
273 #define UFO_BFA_TO_LFA(bfa_) ((bfa_) + 1u * 4u)
274 #define UFO_LFA_TO_DFA(lfa_) ((lfa_) - 4u * 4u)
275 #define UFO_LFA_TO_XFA(lfa_) ((lfa_) - 3u * 4u)
276 #define UFO_LFA_TO_YFA(lfa_) ((lfa_) - 2u * 4u)
277 #define UFO_LFA_TO_BFA(lfa_) ((lfa_) - 1u * 4u)
278 #define UFO_LFA_TO_NFA(lfa_) ((lfa_) + 2u * 4u)
279 #define UFO_LFA_TO_CFA(lfa_) UFO_ALIGN4((lfa_) + 3u * 4u + 1u + ufoImgGetU8((lfa_) + 2u * 4u))
280 #define UFO_LFA_TO_NHASH(lfa_) ((lfa_) + 1u * 4u)
281 #define UFO_CFA_TO_NFA(cfa_) ((cfa_) - 1u - 4u - ufoImgGetU8((cfa_) - 1u))
282 #define UFO_CFA_TO_LFA(cfa_) ((cfa_) - 1u - 4u * 3u - ufoImgGetU8((cfa_) - 1u))
283 #define UFO_CFA_TO_PFA(cfa_) ((cfa_) + 1u * 4u)
284 #define UFO_PFA_TO_CFA(pfa_) ((pfa_) - 1u * 4u)
285 #define UFO_NFA_TO_CFA(nfa_) UFO_ALIGN4((nfa_) + 4u + 1u + ufoImgGetU8((nfa_)))
286 #define UFO_NFA_TO_LFA(nfa_) ((nfa_) - 2u * 4u)
287 #define UFO_XFA_TO_YFA(xfa_) ((xfa_) + 4u)
288 #define UFO_YFA_TO_XFA(yfa_) ((xfa_) - 4u)
289 #define UFO_XFA_TO_WST(xfa_) ((xfa_) - 4u)
290 #define UFO_YFA_TO_WST(yfa_) ((yfa_) - 2u * 4u)
291 #define UFO_YFA_TO_NFA(yfa_) ((yfa_) + 4u * 4u)
294 // ////////////////////////////////////////////////////////////////////////// //
295 //#define UFW_WARG_U8 (8u<<8)
296 //#define UFW_WARG_S8 (9u<<8)
297 //#define UFW_WARG_U16 (10u<<8)
298 //#define UFW_WARG_S16 (11u<<8)
300 #define UFW_VOCAB_OFS_LATEST (0u * 4u)
301 #define UFW_VOCAB_OFS_VOCLINK (1u * 4u)
302 #define UFW_VOCAB_OFS_PARENT (2u * 4u)
303 #define UFW_VOCAB_OFS_HEADER (3u * 4u)
304 #define UFW_VOCAB_OFS_HTABLE (4u * 4u)
306 #define UFO_HASHTABLE_SIZE (256)
308 #define UFO_NO_HTABLE_FLAG (~(uint32_t)0)
310 #define UFO_MAX_NATIVE_CFAS (1024u)
311 static ufoNativeCFA
*ufoForthCFAs
= NULL
;
312 static uint32_t ufoCFAsUsed
= 0;
314 static uint32_t ufoDoForthCFA
;
315 static uint32_t ufoDoVariableCFA
;
316 static uint32_t ufoDoValueCFA
;
317 static uint32_t ufoDoConstCFA
;
318 static uint32_t ufoDoDeferCFA
;
319 static uint32_t ufoDoVocCFA
;
320 static uint32_t ufoDoCreateCFA
;
321 static uint32_t ufoDoUserVariableCFA
;
323 static uint32_t ufoStrLit8CFA
;
325 // special address types:
326 #define UFO_ADDR_CFA_BIT ((uint32_t)1<<31)
327 #define UFO_ADDR_CFA_MASK (UFO_ADDR_CFA_BIT-1u)
329 // handles are somewhat special: first 12 bits can be used as offset for "@", and are ignored
330 #define UFO_ADDR_HANDLE_BIT ((uint32_t)1<<30)
331 #define UFO_ADDR_HANDLE_MASK ((UFO_ADDR_HANDLE_BIT-1u)&~((uint32_t)0xfff))
332 #define UFO_ADDR_HANDLE_SHIFT (12)
333 #define UFO_ADDR_HANDLE_OFS_MASK ((uint32_t)((1 << UFO_ADDR_HANDLE_SHIFT) - 1))
335 // temporary area is 1MB buffer out of the main image
336 #define UFO_ADDR_TEMP_BIT ((uint32_t)1<<29)
337 #define UFO_ADDR_TEMP_MASK (UFO_ADDR_TEMP_BIT-1u)
339 #define UFO_ADDR_SPECIAL_BITS_MASK (UFO_ADDR_CFA_BIT|UFO_ADDR_HANDLE_BIT|UFO_ADDR_TEMP_BIT)
342 debug image stores mapping from dictionary addresses to source files and lines.
343 it is used for backtraces and debuggers, so it doesn't need to be optimised for
344 speed; therefore i choose to optimise it for size.
346 debug map format is this:
349 align, so next data starts at 4-byte boundary
350 dxl line ; 0: no more lines
352 ...next filename record
354 "dv" is variable-length number. each byte uses bit 7 as "continuation" bit.
356 "dx?" is delta-coded number.
357 "dxi" is global, starts with 0, and incrementing.
358 "dxl" resets to 0 on each new file.
359 delta format is the same as "dv".
362 static uint32_t *ufoImage
= NULL
;
363 static uint32_t ufoImageSize
= 0;
365 static uint8_t *ufoDebugImage
= NULL
;
366 static uint32_t ufoDebugImageUsed
= 0;
367 static uint32_t ufoDebugImageSize
= 0;
368 static uint32_t ufoDebugFileId
= 0;
369 static uint32_t ufoDebugLastFRecAddr
= 0;
370 static uint32_t ufoDebugCurrDP
= 0;
372 static uint32_t ufoInRunWord
= 0;
374 static volatile int ufoVMAbort
= 0;
375 static volatile int ufoVMStop
= 0;
377 #define ufoTrueValue (~(uint32_t)0)
381 UFO_MODE_NATIVE
= 0, // executing forth code
382 UFO_MODE_MACRO
= 1, // executing forth asm macro
384 static uint32_t ufoMode
= UFO_MODE_NONE
;
386 #define UFO_DSTACK_SIZE (8192)
387 #define UFO_RSTACK_SIZE (4096)
388 #define UFO_LSTACK_SIZE (4096)
389 #define UFO_MAX_TASK_NAME (127)
391 // to support multitasking (required for the debugger),
392 // our virtual machine state is encapsulated in a struct.
393 typedef struct UfoState_t
{
395 uint32_t dStack
[UFO_DSTACK_SIZE
];
396 uint32_t rStack
[UFO_RSTACK_SIZE
];
397 uint32_t lStack
[UFO_LSTACK_SIZE
];
398 uint32_t IP
; // in image
399 uint32_t SP
; // points AFTER the last value pushed
400 uint32_t RP
; // points AFTER the last value pushed
401 uint32_t RPTop
; // stop when RP is this
410 uint32_t imageTempSize
;
411 // linked list of all allocated states (tasks)
412 char name
[UFO_MAX_TASK_NAME
+ 1];
416 #define UFO_MAX_STATES (8192)
418 // this is indexed by id
419 static UfoState
*ufoStateMap
[UFO_MAX_STATES
] = {NULL
};
420 static uint32_t ufoStateUsedBitmap
[UFO_MAX_STATES
/32] = {0};
422 // currently active execution state
423 static UfoState
*ufoCurrState
= NULL
;
424 // state we're yielded from
425 static UfoState
*ufoYieldedState
= NULL
;
426 // if debug state is not NULL, VM will switch to it
427 // after executing one instruction from the current state.
428 // it will store current state in `ufoDebugeeState`.
429 static UfoState
*ufoDebuggerState
= NULL
;
430 static uint32_t ufoSingleStep
= 0;
432 #define ufoDStack (ufoCurrState->dStack)
433 #define ufoRStack (ufoCurrState->rStack)
434 #define ufoLStack (ufoCurrState->lStack)
435 #define ufoIP (ufoCurrState->IP)
436 #define ufoSP (ufoCurrState->SP)
437 #define ufoRP (ufoCurrState->RP)
438 #define ufoRPTop (ufoCurrState->RPTop)
439 #define ufoLP (ufoCurrState->LP)
440 #define ufoLBP (ufoCurrState->LBP)
441 #define ufoRegA (ufoCurrState->regA)
442 #define ufoImageTemp (ufoCurrState->imageTemp)
443 #define ufoImageTempSize (ufoCurrState->imageTempSize)
444 #define ufoVMRPopCFA (ufoCurrState->vmRPopCFA)
446 // 256 bytes for user variables
447 #define UFO_USER_AREA_ADDR UFO_ADDR_TEMP_BIT
448 #define UFO_USER_AREA_SIZE (256u)
449 #define UFO_NBUF_ADDR UFO_USER_AREA_ADDR + UFO_USER_AREA_SIZE
450 #define UFO_NBUF_SIZE (256u)
451 #define UFO_PAD_ADDR (UFO_NBUF_ADDR + UFO_NBUF_SIZE)
452 #define UFO_DEF_TIB_ADDR (UFO_PAD_ADDR + 2048u)
454 // dynamically allocated text input buffer
455 // always ends with zero (this is word name too)
456 static const uint32_t ufoAddrTIBx
= UFO_ADDR_TEMP_BIT
+ 0u * 4u; // TIB
457 static const uint32_t ufoAddrINx
= UFO_ADDR_TEMP_BIT
+ 1u * 4u; // >IN
458 static const uint32_t ufoAddrDefTIB
= UFO_ADDR_TEMP_BIT
+ 2u * 4u; // default TIB (handle); user cannot change it
459 static const uint32_t ufoAddrBASE
= UFO_ADDR_TEMP_BIT
+ 3u * 4u;
460 static const uint32_t ufoAddrUserVarUsed
= UFO_ADDR_TEMP_BIT
+ 4u * 4u;
462 static uint32_t ufoAddrContext
; // CONTEXT
463 static uint32_t ufoAddrCurrent
; // CURRENT (definitions will go there)
464 static uint32_t ufoAddrSTATE
;
465 static uint32_t ufoAddrVocLink
;
466 static uint32_t ufoAddrDP
;
467 static uint32_t ufoAddrDPTemp
;
468 static uint32_t ufoAddrNewWordFlags
;
469 static uint32_t ufoAddrRedefineWarning
;
470 static uint32_t ufoAddrLastXFA
;
472 // allows to redefine even protected words
473 #define UFO_REDEF_WARN_DONT_CARE (~(uint32_t)0)
474 // do not warn about ordinary words, allow others
475 #define UFO_REDEF_WARN_NONE (0)
477 #define UFO_REDEF_WARN_NORMAL (1)
479 #define UFO_GET_DP() (ufoImgGetU32(ufoAddrDPTemp) ?: ufoImgGetU32(ufoAddrDP))
480 //#define UFO_SET_DP(val_) ufoImgPutU32(ufoAddrDP, (val_))
482 #define UFO_MAX_NESTED_INCLUDES (32)
489 uint32_t id
; // non-zero unique id
492 static UFOFileStackEntry ufoFileStack
[UFO_MAX_NESTED_INCLUDES
];
493 static uint32_t ufoFileStackPos
; // after the last used item
495 static FILE *ufoInFile
= NULL
;
496 static char *ufoInFileName
= NULL
;
497 static char *ufoLastIncPath
= NULL
;
498 static char *ufoLastSysIncPath
= NULL
;
499 static int ufoInFileLine
= 0;
500 static uint32_t ufoFileId
= 0;
501 static uint32_t ufoLastUsedFileId
= 0;
503 static int ufoLastEmitWasCR
= 1;
505 #define UFO_VOCSTACK_SIZE (16u)
506 static uint32_t ufoVocStack
[UFO_VOCSTACK_SIZE
]; // cfas
507 static uint32_t ufoVSP
;
508 static uint32_t ufoForthVocId
;
509 static uint32_t ufoCompilerVocId
;
512 typedef struct UHandleInfo_t
{
519 struct UHandleInfo_t
*next
;
522 static UfoHandle
*ufoHandleFreeList
= NULL
;
523 static UfoHandle
**ufoHandles
= NULL
;
524 static uint32_t ufoHandlesUsed
= 0;
525 static uint32_t ufoHandlesAlloted
= 0;
527 #define UFO_HANDLE_FREE (~(uint32_t)0)
529 static char ufoCurrFileLine
[520];
532 static uint32_t ufoInBacktrace
= 0;
535 // ////////////////////////////////////////////////////////////////////////// //
536 static void ufoClearCondDefines (void);
538 static void ufoRunVMCFA (uint32_t cfa
);
540 static void ufoBacktrace (uint32_t ip
);
542 static void ufoClearCondDefines (void);
544 static UfoState
*ufoNewState (uint32_t cfa
);
545 static void ufoInitStateUserVars (UfoState
*st
, int initial
);
546 static void ufoFreeState (UfoState
*st
);
547 static UfoState
*ufoFindState (uint32_t stid
);
548 static void ufoSwitchToState (UfoState
*newst
);
550 __attribute__((unused
)) static void ufoDumpWordHeader (const uint32_t lfa
);
553 static void ufoDisableRaw (void);
556 #ifdef UFO_DEBUG_DEBUG
557 static void ufoDumpDebugImage (void);
561 // ////////////////////////////////////////////////////////////////////////// //
562 #define UFWORD(name_) \
563 static void ufoWord_##name_ (uint32_t mypfa)
565 #define UFCALL(name_) ufoWord_##name_(0)
566 #define UFCFA(name_) (&ufoWord_##name_)
569 UFWORD(CPEEK_REGA_IDX
);
570 UFWORD(CPOKE_REGA_IDX
);
573 UFWORD(PAR_HANDLE_LOAD_BYTE
);
574 UFWORD(PAR_HANDLE_LOAD_WORD
);
575 UFWORD(PAR_HANDLE_LOAD_CELL
);
576 UFWORD(PAR_HANDLE_STORE_BYTE
);
577 UFWORD(PAR_HANDLE_STORE_WORD
);
578 UFWORD(PAR_HANDLE_STORE_CELL
);
581 //==========================================================================
585 //==========================================================================
586 void ufoSetUserAbort (void) {
591 //==========================================================================
595 //==========================================================================
596 static UfoHandle
*ufoAllocHandle (uint32_t typeid) {
597 ufo_assert(typeid != UFO_HANDLE_FREE
);
598 UfoHandle
*newh
= ufoHandleFreeList
;
600 if (ufoHandlesUsed
== ufoHandlesAlloted
) {
601 uint32_t newsz
= ufoHandlesAlloted
+ 16384;
602 // due to offsets, this is the maximum number of handles we can have
603 if (newsz
> 0x1ffffU
) {
604 if (ufoHandlesAlloted
> 0x1ffffU
) ufoFatal("too many dynamic handles");
605 newsz
= 0x1ffffU
+ 1U;
606 ufo_assert(newsz
> ufoHandlesAlloted
);
608 UfoHandle
**nh
= realloc(ufoHandles
, sizeof(ufoHandles
[0]) * newsz
);
609 if (nh
== NULL
) ufoFatal("out of memory for handle table");
611 ufoHandlesAlloted
= newsz
;
613 newh
= calloc(1, sizeof(UfoHandle
));
614 if (newh
== NULL
) ufoFatal("out of memory for handle info");
615 ufoHandles
[ufoHandlesUsed
] = newh
;
616 // setup new handle info
617 newh
->ufoHandle
= (ufoHandlesUsed
<< UFO_ADDR_HANDLE_SHIFT
) | UFO_ADDR_HANDLE_BIT
;
620 ufo_assert(newh
->typeid == UFO_HANDLE_FREE
);
621 ufoHandleFreeList
= newh
->next
;
623 // setup new handle info
624 newh
->typeid = typeid;
633 //==========================================================================
637 //==========================================================================
638 static void ufoFreeHandle (UfoHandle
*hh
) {
640 ufo_assert(hh
->typeid != UFO_HANDLE_FREE
);
641 if (hh
->data
) free(hh
->data
);
642 hh
->typeid = UFO_HANDLE_FREE
;
646 hh
->next
= ufoHandleFreeList
;
647 ufoHandleFreeList
= hh
;
652 //==========================================================================
656 //==========================================================================
657 static UfoHandle
*ufoGetHandle (uint32_t hh
) {
659 if (hh
!= 0 && (hh
& UFO_ADDR_HANDLE_BIT
) != 0) {
660 hh
= (hh
& UFO_ADDR_HANDLE_MASK
) >> UFO_ADDR_HANDLE_SHIFT
;
661 if (hh
< ufoHandlesUsed
) {
662 res
= ufoHandles
[hh
];
663 if (res
->typeid == UFO_HANDLE_FREE
) res
= NULL
;
674 //==========================================================================
678 //==========================================================================
679 static void setLastIncPath (const char *fname
, int system
) {
680 if (fname
== NULL
|| fname
[0] == 0) {
682 if (ufoLastSysIncPath
) free(ufoLastIncPath
);
683 ufoLastSysIncPath
= NULL
;
685 if (ufoLastIncPath
) free(ufoLastIncPath
);
686 ufoLastIncPath
= strdup(".");
692 if (ufoLastSysIncPath
) free(ufoLastSysIncPath
);
693 ufoLastSysIncPath
= strdup(fname
);
694 lslash
= ufoLastSysIncPath
;
695 cpos
= ufoLastSysIncPath
;
697 if (ufoLastIncPath
) free(ufoLastIncPath
);
698 ufoLastIncPath
= strdup(fname
);
699 lslash
= ufoLastIncPath
;
700 cpos
= ufoLastIncPath
;
704 if (*cpos
== '/' || *cpos
== '\\') lslash
= cpos
;
706 if (*cpos
== '/') lslash
= cpos
;
715 //==========================================================================
717 // ufoClearIncludePath
719 // required for UrAsm
721 //==========================================================================
722 void ufoClearIncludePath (void) {
723 if (ufoLastIncPath
!= NULL
) {
724 free(ufoLastIncPath
);
725 ufoLastIncPath
= NULL
;
727 if (ufoLastSysIncPath
!= NULL
) {
728 free(ufoLastSysIncPath
);
729 ufoLastSysIncPath
= NULL
;
734 //==========================================================================
738 //==========================================================================
739 static void ufoErrorPrintFile (FILE *fo
) {
741 fprintf(fo
, "UFO ERROR at file %s, line %d: ", ufoInFileName
, ufoInFileLine
);
743 fprintf(fo
, "UFO ERROR somewhere in time: ");
748 //==========================================================================
752 //==========================================================================
753 static void ufoErrorMsgV (const char *fmt
, va_list ap
) {
754 if (!ufoLastEmitWasCR
) { printf("\n"); ufoLastEmitWasCR
= 1; }
756 ufoErrorPrintFile(stderr
);
757 vfprintf(stderr
, fmt
, ap
);
764 //==========================================================================
768 //==========================================================================
769 __attribute__((format(printf
, 1, 2)))
770 void ufoWarning (const char *fmt
, ...) {
773 ufoErrorMsgV(fmt
, ap
);
777 //==========================================================================
781 //==========================================================================
782 __attribute__((noreturn
)) __attribute__((format(printf
, 1, 2)))
783 void ufoFatal (const char *fmt
, ...) {
789 ufoErrorMsgV(fmt
, ap
);
790 if (!ufoInBacktrace
) {
795 fprintf(stderr
, "DOUBLE FATAL: error in backtrace!\n");
798 #ifdef UFO_DEBUG_FATAL_ABORT
805 // ////////////////////////////////////////////////////////////////////////// //
806 // working with the stacks
807 UFO_FORCE_INLINE
void ufoPush (uint32_t v
) { if (ufoSP
>= UFO_DSTACK_SIZE
) ufoFatal("data stack overflow"); ufoDStack
[ufoSP
++] = v
; }
808 UFO_FORCE_INLINE
void ufoDrop (void) { if (ufoSP
== 0) ufoFatal("data stack underflow"); --ufoSP
; }
809 UFO_FORCE_INLINE
uint32_t ufoPop (void) { if (ufoSP
== 0) { ufoFatal("data stack underflow"); } return ufoDStack
[--ufoSP
]; }
810 UFO_FORCE_INLINE
uint32_t ufoPeek (void) { if (ufoSP
== 0) ufoFatal("data stack underflow"); return ufoDStack
[ufoSP
-1u]; }
811 UFO_FORCE_INLINE
void ufoDup (void) { if (ufoSP
== 0) ufoFatal("data stack underflow"); ufoPush(ufoDStack
[ufoSP
-1u]); }
812 UFO_FORCE_INLINE
void ufoOver (void) { if (ufoSP
< 2u) ufoFatal("data stack underflow"); ufoPush(ufoDStack
[ufoSP
-2u]); }
813 UFO_FORCE_INLINE
void ufoSwap (void) { if (ufoSP
< 2u) ufoFatal("data stack underflow"); const uint32_t t
= ufoDStack
[ufoSP
-1u]; ufoDStack
[ufoSP
-1u] = ufoDStack
[ufoSP
-2u]; ufoDStack
[ufoSP
-2u] = t
; }
814 UFO_FORCE_INLINE
void ufoRot (void) { if (ufoSP
< 3u) ufoFatal("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
; }
815 UFO_FORCE_INLINE
void ufoNRot (void) { if (ufoSP
< 3u) ufoFatal("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
; }
817 UFO_FORCE_INLINE
void ufo2Dup (void) { ufoOver(); ufoOver(); }
818 UFO_FORCE_INLINE
void ufo2Drop (void) { ufoDrop(); ufoDrop(); }
819 UFO_FORCE_INLINE
void ufo2Over (void) { if (ufoSP
< 4u) ufoFatal("data stack underflow"); const uint32_t n0
= ufoDStack
[ufoSP
-4u]; const uint32_t n1
= ufoDStack
[ufoSP
-3u]; ufoPush(n0
); ufoPush(n1
); }
820 UFO_FORCE_INLINE
void ufo2Swap (void) { if (ufoSP
< 4u) ufoFatal("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
; }
822 UFO_FORCE_INLINE
void ufoRPush (uint32_t v
) { if (ufoRP
>= UFO_RSTACK_SIZE
) ufoFatal("return stack overflow"); ufoRStack
[ufoRP
++] = v
; }
823 UFO_FORCE_INLINE
void ufoRDrop (void) { if (ufoRP
== 0 || ufoRP
== ufoRPTop
) ufoFatal("return stack underflow"); --ufoRP
; }
824 UFO_FORCE_INLINE
uint32_t ufoRPop (void) { if (ufoRP
== 0 || ufoRP
== ufoRPTop
) ufoFatal("return stack underflow"); return ufoRStack
[--ufoRP
]; }
825 UFO_FORCE_INLINE
uint32_t ufoRPeek (void) { if (ufoRP
== 0 || ufoRP
== ufoRPTop
) ufoFatal("return stack underflow"); return ufoRStack
[ufoRP
-1u]; }
826 UFO_FORCE_INLINE
void ufoRDup (void) { if (ufoRP
== 0 || ufoRP
== ufoRPTop
) ufoFatal("return stack underflow"); ufoPush(ufoRStack
[ufoRP
-1u]); }
828 UFO_FORCE_INLINE
void ufoPushBool (int v
) { ufoPush(v
? ufoTrueValue
: 0u); }
831 //==========================================================================
835 //==========================================================================
836 static void ufoImgEnsureSize (uint32_t addr
) {
837 if ((addr
& UFO_ADDR_SPECIAL_BITS_MASK
) != 0) ufoFatal("ufoImgEnsureSize: internal error");
838 if (addr
>= ufoImageSize
) {
839 // 64MB should be enough for everyone!
840 if (addr
>= 0x04000000U
) {
841 ufoFatal("image grown too big (addr=0%08XH)", addr
);
843 const const uint32_t osz
= ufoImageSize
;
845 const uint32_t nsz
= (addr
|0x000fffffU
) + 1U;
846 ufo_assert(nsz
> addr
);
847 uint32_t *nimg
= realloc(ufoImage
, nsz
);
849 ufoFatal("out of memory for UFO image (%u -> %u MBs)",
850 ufoImageSize
/ 1024u / 1024u,
851 nsz
/ 1024u / 1024u);
855 memset((char *)ufoImage
+ osz
, 0, (nsz
- osz
));
860 //==========================================================================
864 //==========================================================================
865 static void ufoImgEnsureTemp (uint32_t addr
) {
866 if ((addr
& UFO_ADDR_SPECIAL_BITS_MASK
) != 0) ufoFatal("ufoImgEnsureTemp: internal error");
867 if (addr
>= ufoImageTempSize
) {
868 if (addr
>= 1024u * 1024u) {
869 ufoFatal("Forth segmentation fault at address 0x%08X", addr
| UFO_ADDR_TEMP_BIT
);
871 const uint32_t osz
= ufoImageTempSize
;
873 const uint32_t nsz
= (addr
|0x00001fffU
) + 1U;
874 uint32_t *nimg
= realloc(ufoImageTemp
, nsz
);
876 ufoFatal("out of memory for temp UFO image (%u -> %u KBs)",
877 ufoImageTempSize
/ 1024u,
881 ufoImageTempSize
= nsz
;
882 memset((char *)ufoImageTemp
+ osz
, 0, (nsz
- osz
));
887 #ifdef UFO_FAST_MEM_ACCESS
888 //==========================================================================
894 //==========================================================================
895 UFO_FORCE_INLINE
void ufoImgPutU8 (uint32_t addr
, const uint32_t value
) {
896 if ((addr
& UFO_ADDR_SPECIAL_BITS_MASK
) == 0) {
897 if (addr
>= ufoImageSize
) ufoImgEnsureSize(addr
);
898 *((uint8_t *)ufoImage
+ addr
) = (uint8_t)value
;
899 } else if (addr
& UFO_ADDR_TEMP_BIT
) {
900 addr
&= UFO_ADDR_TEMP_MASK
;
901 if (addr
>= ufoImageTempSize
) ufoImgEnsureTemp(addr
);
902 *((uint8_t *)ufoImageTemp
+ addr
) = (uint8_t)value
;
904 ufoFatal("Forth segmentation fault at address 0x%08X", addr
);
909 //==========================================================================
915 //==========================================================================
916 UFO_FORCE_INLINE
void ufoImgPutU16 (uint32_t addr
, const uint32_t value
) {
917 if ((addr
& UFO_ADDR_SPECIAL_BITS_MASK
) == 0) {
918 if (addr
+ 1u >= ufoImageSize
) ufoImgEnsureSize(addr
+ 1u);
919 *(uint16_t *)((uint8_t *)ufoImage
+ addr
) = (uint16_t)value
;
920 } else if (addr
& UFO_ADDR_TEMP_BIT
) {
921 addr
&= UFO_ADDR_TEMP_MASK
;
922 if (addr
+ 1u >= ufoImageTempSize
) ufoImgEnsureTemp(addr
+ 1u);
923 *(uint16_t *)((uint8_t *)ufoImageTemp
+ addr
) = (uint16_t)value
;
925 ufoFatal("Forth segmentation fault at address 0x%08X", addr
);
930 //==========================================================================
936 //==========================================================================
937 UFO_FORCE_INLINE
void ufoImgPutU32 (uint32_t addr
, const uint32_t value
) {
938 if ((addr
& UFO_ADDR_SPECIAL_BITS_MASK
) == 0) {
939 if (addr
+ 3u >= ufoImageSize
) ufoImgEnsureSize(addr
+ 3u);
940 *(uint32_t *)((uint8_t *)ufoImage
+ addr
) = value
;
941 } else if (addr
& UFO_ADDR_TEMP_BIT
) {
942 addr
&= UFO_ADDR_TEMP_MASK
;
943 if (addr
+ 3u >= ufoImageTempSize
) ufoImgEnsureTemp(addr
+ 3u);
944 *(uint32_t *)((uint8_t *)ufoImageTemp
+ addr
) = value
;
946 ufoFatal("Forth segmentation fault at address 0x%08X", addr
);
951 //==========================================================================
957 //==========================================================================
958 UFO_FORCE_INLINE
uint32_t ufoImgGetU8 (uint32_t addr
) {
959 if ((addr
& UFO_ADDR_SPECIAL_BITS_MASK
) == 0) {
960 if (addr
>= ufoImageSize
) {
961 // accessing unallocated image area is segmentation fault
962 ufoFatal("Forth segmentation fault (unallocated access) at address 0x%08X", addr
);
964 return *((const uint8_t *)ufoImage
+ addr
);
965 } else if (addr
& UFO_ADDR_TEMP_BIT
) {
966 addr
&= UFO_ADDR_TEMP_MASK
;
967 if (addr
>= ufoImageTempSize
) {
968 // accessing unallocated image area is segmentation fault
969 ufoFatal("Forth segmentation fault (unallocated access) at address 0x%08X", addr
| UFO_ADDR_TEMP_BIT
);
971 return *((const uint8_t *)ufoImageTemp
+ addr
);
973 ufoFatal("Forth segmentation fault at address 0x%08X", addr
);
978 //==========================================================================
984 //==========================================================================
985 UFO_FORCE_INLINE
uint32_t ufoImgGetU16 (uint32_t addr
) {
986 if ((addr
& UFO_ADDR_SPECIAL_BITS_MASK
) == 0) {
987 if (addr
+ 1u >= ufoImageSize
) {
988 // accessing unallocated image area is segmentation fault
989 ufoFatal("Forth segmentation fault (unallocated access) at address 0x%08X", addr
);
991 return *(const uint16_t *)((const uint8_t *)ufoImage
+ addr
);
992 } else if (addr
& UFO_ADDR_TEMP_BIT
) {
993 addr
&= UFO_ADDR_TEMP_MASK
;
994 if (addr
+ 1u >= ufoImageTempSize
) {
995 // accessing unallocated image area is segmentation fault
996 ufoFatal("Forth segmentation fault (unallocated access) at address 0x%08X", addr
| UFO_ADDR_TEMP_BIT
);
998 return *(const uint16_t *)((const uint8_t *)ufoImageTemp
+ addr
);
1000 ufoFatal("Forth segmentation fault at address 0x%08X", addr
);
1005 //==========================================================================
1011 //==========================================================================
1012 UFO_FORCE_INLINE
uint32_t ufoImgGetU32 (uint32_t addr
) {
1013 if ((addr
& UFO_ADDR_SPECIAL_BITS_MASK
) == 0) {
1014 if (addr
+ 3u >= ufoImageSize
) {
1015 // accessing unallocated image area is segmentation fault
1016 ufoFatal("Forth segmentation fault (unallocated access) at address 0x%08X", addr
);
1018 return *(const uint32_t *)((const uint8_t *)ufoImage
+ addr
);
1019 } else if (addr
& UFO_ADDR_TEMP_BIT
) {
1020 addr
&= UFO_ADDR_TEMP_MASK
;
1021 if (addr
+ 3u >= ufoImageTempSize
) {
1022 // accessing unallocated image area is segmentation fault
1023 ufoFatal("Forth segmentation fault (unallocated access) at address 0x%08X", addr
| UFO_ADDR_TEMP_BIT
);
1025 return *(const uint32_t *)((const uint8_t *)ufoImageTemp
+ addr
);
1027 ufoFatal("Forth segmentation fault at address 0x%08X", addr
);
1033 //==========================================================================
1039 //==========================================================================
1040 UFO_FORCE_INLINE
void ufoImgPutU8 (uint32_t addr
, const uint32_t value
) {
1042 if ((addr
& UFO_ADDR_SPECIAL_BITS_MASK
) == 0) {
1043 if (addr
>= ufoImageSize
) ufoImgEnsureSize(addr
);
1044 imgptr
= &ufoImage
[addr
/4u];
1045 } else if (addr
& UFO_ADDR_TEMP_BIT
) {
1046 addr
&= UFO_ADDR_TEMP_MASK
;
1047 if (addr
>= ufoImageTempSize
) ufoImgEnsureTemp(addr
);
1048 imgptr
= &ufoImageTemp
[addr
/4u];
1050 ufoFatal("Forth segmentation fault at address 0x%08X", addr
);
1052 const uint8_t val
= (uint8_t)value
;
1053 memcpy((uint8_t *)imgptr
+ (addr
&3), &val
, 1);
1057 //==========================================================================
1063 //==========================================================================
1064 UFO_FORCE_INLINE
void ufoImgPutU16 (uint32_t addr
, const uint32_t value
) {
1065 ufoImgPutU8(addr
, value
&0xffU
);
1066 ufoImgPutU8(addr
+ 1u, (value
>>8)&0xffU
);
1070 //==========================================================================
1076 //==========================================================================
1077 UFO_FORCE_INLINE
void ufoImgPutU32 (uint32_t addr
, const uint32_t value
) {
1078 ufoImgPutU16(addr
, value
&0xffffU
);
1079 ufoImgPutU16(addr
+ 2u, (value
>>16)&0xffffU
);
1083 //==========================================================================
1089 //==========================================================================
1090 UFO_FORCE_INLINE
uint32_t ufoImgGetU8 (uint32_t addr
) {
1092 if ((addr
& UFO_ADDR_SPECIAL_BITS_MASK
) == 0) {
1093 if (addr
>= ufoImageSize
) return 0;
1094 imgptr
= &ufoImage
[addr
/4u];
1095 } else if (addr
& UFO_ADDR_TEMP_BIT
) {
1096 addr
&= UFO_ADDR_TEMP_MASK
;
1097 if (addr
>= ufoImageTempSize
) return 0;
1098 imgptr
= &ufoImageTemp
[addr
/4u];
1100 ufoFatal("Forth segmentation fault at address 0x%08X", addr
);
1103 memcpy(&val
, (uint8_t *)imgptr
+ (addr
&3), 1);
1104 return (uint32_t)val
;
1108 //==========================================================================
1114 //==========================================================================
1115 UFO_FORCE_INLINE
uint32_t ufoImgGetU16 (uint32_t addr
) {
1116 return ufoImgGetU8(addr
) | (ufoImgGetU8(addr
+ 1u) << 8);
1120 //==========================================================================
1126 //==========================================================================
1127 UFO_FORCE_INLINE
uint32_t ufoImgGetU32 (uint32_t addr
) {
1128 return ufoImgGetU16(addr
) | (ufoImgGetU16(addr
+ 2u) << 16);
1133 //==========================================================================
1137 //==========================================================================
1138 UFO_DISABLE_INLINE
void ufoEnsureDebug (uint32_t sdelta
) {
1139 ufo_assert(sdelta
!= 0);
1140 if (ufoDebugImageUsed
!= 0) {
1141 if (ufoDebugImageUsed
+ sdelta
>= 0x40000000U
) ufoFatal("debug info too big");
1142 if (ufoDebugImageUsed
+ sdelta
> ufoDebugImageSize
) {
1143 // grow by 32KB, this should be more than enough
1144 const uint32_t newsz
= ((ufoDebugImageUsed
+ sdelta
) | 0x7fffU
) + 1u;
1145 uint8_t *ndb
= realloc(ufoDebugImage
, newsz
);
1146 if (ndb
== NULL
) ufoFatal("out of memory for debug info");
1147 ufoDebugImage
= ndb
;
1148 ufoDebugImageSize
= newsz
;
1151 // initial allocation: 32KB, quite a lot
1152 ufoDebugImageSize
= 1024 * 32;
1153 ufoDebugImage
= malloc(ufoDebugImageSize
);
1154 if (ufoDebugImage
== NULL
) ufoFatal("out of memory for debug info");
1159 #ifdef UFO_DEBUG_DEBUG
1160 //==========================================================================
1164 //==========================================================================
1165 static void ufoDumpDebugImage (void) {
1167 uint32_t dbgpos
= 0u; // first item is always "next file record"
1168 while (dbgpos
< ufoDebugImageUsed
) {
1169 const uint32_t ln
= *(const uint32_t *)(ufoDebugImage
+ dbgpos
); dbgpos
+= 4u;
1170 if (ln
== ~(uint32_t)0) {
1172 const uint32_t nlen
= *(const uint32_t *)(ufoDebugImage
+ dbgpos
); dbgpos
+= 4u;
1173 fprintf(stderr
, "*** NEW FILE: %s\n", (const char *)(ufoDebugImage
+ dbgpos
));
1174 dbgpos
+= nlen
+ 1u;
1175 if ((dbgpos
& 0x03) != 0) dbgpos
= (dbgpos
| 0x03u
) + 1u;
1177 const uint32_t edp
= *(const uint32_t *)(ufoDebugImage
+ dbgpos
); dbgpos
+= 4u;
1178 fprintf(stderr
, " line %6u: edp=%u\n", ln
, edp
);
1186 #define UFO_DBG_PUT_U4(val_) do { \
1187 const uint32_t vv_ = (val_); \
1188 *((uint32_t *)(ufoDebugImage + ufoDebugImageUsed)) = vv_; \
1189 ufoDebugImageUsed += 4u; \
1192 //==========================================================================
1196 //==========================================================================
1197 UFO_DISABLE_INLINE
void ufoRecordDebug (uint32_t newhere
) {
1198 if (newhere
> ufoDebugCurrDP
) {
1199 if (ufoInFileName
!= NULL
) {
1200 // check if we're doing the same file
1201 const uint32_t slen
= (uint32_t)strlen(ufoInFileName
);
1202 const int newfrec
= (ufoDebugLastFRecAddr
== 0) ||
1203 (*((const uint32_t *)(ufoDebugImage
+ ufoDebugLastFRecAddr
)) != slen
) ||
1204 (memcmp((const char *)ufoDebugImage
+ ufoDebugLastFRecAddr
+ 4u, ufoInFileName
, slen
) != 0);
1205 uint32_t fline
= (uint32_t)ufoInFileLine
;
1206 if (fline
== ~(uint32_t)0) fline
-= 1u;
1208 ufoEnsureDebug(slen
+ 4u + 4u + 4u + 32u); // way too much ;-)
1209 // finish previous record
1210 UFO_DBG_PUT_U4(~(uint32_t)0);
1211 // create new file record
1212 ufoDebugLastFRecAddr
= ufoDebugImageUsed
;
1213 UFO_DBG_PUT_U4(slen
);
1214 memcpy(ufoDebugImage
+ ufoDebugImageUsed
, ufoInFileName
, slen
+ 1u);
1215 ufoDebugImageUsed
+= slen
+ 1u;
1216 while ((ufoDebugImageUsed
& 0x03u
) != 0) {
1217 ufoDebugImage
[ufoDebugImageUsed
] = 0;
1218 ufoDebugImageUsed
+= 1;
1220 UFO_DBG_PUT_U4(fline
);
1221 UFO_DBG_PUT_U4(newhere
);
1223 // check if the line is the same
1224 if (*((const uint32_t *)(ufoDebugImage
+ ufoDebugImageUsed
- 8u)) == fline
) {
1225 *((uint32_t *)(ufoDebugImage
+ ufoDebugImageUsed
- 4u)) = newhere
;
1229 UFO_DBG_PUT_U4(fline
);
1230 UFO_DBG_PUT_U4(newhere
);
1234 // we don't have a file, don't record debug info
1236 ufoDebugLastFRecAddr
= 0;
1238 ufoDebugCurrDP
= newhere
;
1243 //==========================================================================
1245 // ufoGetWordEndAddrYFA
1247 //==========================================================================
1248 static uint32_t ufoGetWordEndAddrYFA (uint32_t yfa
) {
1250 const uint32_t oyfa
= yfa
;
1251 yfa
= ufoImgGetU32(yfa
);
1253 if ((oyfa
& UFO_ADDR_TEMP_BIT
) == 0) {
1255 if ((yfa
& UFO_ADDR_TEMP_BIT
) != 0) {
1256 yfa
= UFO_CFA_TO_PFA(UFO_NFA_TO_CFA(UFO_YFA_TO_NFA(oyfa
)));
1259 yfa
= UFO_CFA_TO_PFA(UFO_NFA_TO_CFA(UFO_YFA_TO_NFA(oyfa
)));
1262 yfa
= UFO_YFA_TO_WST(yfa
);
1271 //==========================================================================
1273 // ufoGetWordEndAddr
1275 //==========================================================================
1276 static uint32_t ufoGetWordEndAddr (const uint32_t cfa
) {
1278 return ufoGetWordEndAddrYFA(UFO_LFA_TO_YFA(UFO_CFA_TO_LFA(cfa
)));
1285 //==========================================================================
1291 // WARNING: this is SLOW!
1293 //==========================================================================
1294 static uint32_t ufoFindWordForIP (const uint32_t ip
) {
1297 // iterate over all words
1298 uint32_t xfa
= ufoImgGetU32(ufoAddrLastXFA
);
1300 while (res
== 0 && xfa
!= 0) {
1301 const uint32_t yfa
= UFO_XFA_TO_YFA(xfa
);
1302 const uint32_t wst
= UFO_YFA_TO_WST(yfa
);
1303 const uint32_t wend
= ufoGetWordEndAddrYFA(yfa
);
1304 if (ip
>= wst
&& ip
< wend
) {
1305 res
= UFO_YFA_TO_NFA(yfa
);
1307 xfa
= ufoImgGetU32(xfa
);
1316 //==========================================================================
1320 // return file name or `NULL`
1322 // WARNING: this is SLOW!
1324 //==========================================================================
1325 static const char *ufoFindFileForIP (uint32_t ip
, uint32_t *line
) {
1326 const char *res
= NULL
;
1327 if (ip
!= 0 && ufoDebugImageUsed
!= 0) {
1328 uint32_t lastfinfo
= 0u;
1329 uint32_t lastip
= 0u;
1330 uint32_t dbgpos
= 0u; // first item is always "next file record"
1331 while (res
== NULL
&& dbgpos
< ufoDebugImageUsed
) {
1332 const uint32_t ln
= *(const uint32_t *)(ufoDebugImage
+ dbgpos
); dbgpos
+= 4u;
1333 if (ln
== ~(uint32_t)0) {
1336 const uint32_t nlen
= *(const uint32_t *)(ufoDebugImage
+ dbgpos
); dbgpos
+= 4u;
1337 dbgpos
+= nlen
+ 1u;
1338 if ((dbgpos
& 0x03) != 0) dbgpos
= (dbgpos
| 0x03u
) + 1u;
1340 const uint32_t edp
= *(const uint32_t *)(ufoDebugImage
+ dbgpos
); dbgpos
+= 4u;
1341 if (ip
>= lastip
&& ip
< edp
) {
1342 if (line
) *line
= ln
;
1343 res
= (const char *)(ufoDebugImage
+ lastfinfo
+ 4u);
1353 //==========================================================================
1357 //==========================================================================
1358 UFO_FORCE_INLINE
void ufoBumpDP (uint32_t delta
) {
1359 uint32_t dp
= ufoImgGetU32(ufoAddrDPTemp
);
1361 dp
= ufoImgGetU32(ufoAddrDP
);
1362 if ((dp
& UFO_ADDR_SPECIAL_BITS_MASK
) == 0) ufoRecordDebug(dp
+ delta
);
1364 ufoImgPutU32(ufoAddrDP
, dp
);
1366 dp
= ufoImgGetU32(ufoAddrDPTemp
);
1367 if ((dp
& UFO_ADDR_SPECIAL_BITS_MASK
) == 0) ufoRecordDebug(dp
+ delta
);
1369 ufoImgPutU32(ufoAddrDPTemp
, dp
);
1374 //==========================================================================
1378 //==========================================================================
1379 UFO_FORCE_INLINE
void ufoImgEmitU8 (uint32_t value
) {
1380 ufoImgPutU8(UFO_GET_DP(), value
);
1385 //==========================================================================
1389 //==========================================================================
1390 UFO_FORCE_INLINE
void ufoImgEmitU32 (uint32_t value
) {
1391 ufoImgPutU32(UFO_GET_DP(), value
);
1396 #ifdef UFO_FAST_MEM_ACCESS
1398 //==========================================================================
1400 // ufoImgEmitU32_NoInline
1404 //==========================================================================
1405 UFO_FORCE_INLINE
void ufoImgEmitU32_NoInline (uint32_t value
) {
1406 ufoImgPutU32(UFO_GET_DP(), value
);
1412 //==========================================================================
1414 // ufoImgEmitU32_NoInline
1418 //==========================================================================
1419 UFO_DISABLE_INLINE
void ufoImgEmitU32_NoInline (uint32_t value
) {
1420 ufoImgPutU32(UFO_GET_DP(), value
);
1427 //==========================================================================
1431 // this understands handle addresses
1433 //==========================================================================
1434 UFO_FORCE_INLINE
uint32_t ufoImgGetU8Ext (uint32_t addr
) {
1435 if ((addr
& UFO_ADDR_HANDLE_BIT
) == 0) {
1436 return ufoImgGetU8(addr
);
1440 UFCALL(PAR_HANDLE_LOAD_BYTE
);
1446 //==========================================================================
1450 // this understands handle addresses
1452 //==========================================================================
1453 UFO_FORCE_INLINE
void ufoImgPutU8Ext (uint32_t addr
, uint32_t value
) {
1454 if ((addr
& UFO_ADDR_HANDLE_BIT
) == 0) {
1455 ufoImgPutU8(addr
, value
);
1460 UFCALL(PAR_HANDLE_STORE_BYTE
);
1465 //==========================================================================
1469 //==========================================================================
1470 UFO_FORCE_INLINE
void ufoImgEmitAlign (void) {
1471 while ((UFO_GET_DP() & 3) != 0) ufoImgEmitU8(0);
1475 //==========================================================================
1479 //==========================================================================
1480 UFO_FORCE_INLINE
void ufoResetTib (void) {
1481 uint32_t defTIB
= ufoImgGetU32(ufoAddrDefTIB
);
1482 //fprintf(stderr, "ufoResetTib(%p): defTIB=0x%08x\n", ufoCurrState, defTIB);
1484 // create new TIB handle
1485 UfoHandle
*tibh
= ufoAllocHandle(0x69a029a6); // arbitrary number
1486 defTIB
= tibh
->ufoHandle
;
1487 ufoImgPutU32(ufoAddrDefTIB
, defTIB
);
1489 if ((defTIB
& UFO_ADDR_HANDLE_BIT
) != 0) {
1490 UfoHandle
*hh
= ufoGetHandle(defTIB
);
1491 if (hh
== NULL
) ufoFatal("default TIB is not allocated");
1492 if (hh
->size
== 0) {
1493 ufo_assert(hh
->data
== NULL
);
1494 hh
->data
= calloc(1, UFO_ADDR_HANDLE_OFS_MASK
+ 1);
1495 if (hh
->data
== NULL
) ufoFatal("out of memory for default TIB");
1496 hh
->size
= UFO_ADDR_HANDLE_OFS_MASK
+ 1;
1499 const uint32_t oldA
= ufoRegA
;
1500 ufoImgPutU32(ufoAddrTIBx
, defTIB
);
1501 ufoImgPutU32(ufoAddrINx
, 0);
1503 ufoPush(0); // value
1504 ufoPush(0); // offset
1505 UFCALL(CPOKE_REGA_IDX
);
1510 //==========================================================================
1514 //==========================================================================
1515 UFO_DISABLE_INLINE
void ufoTibEnsureSize (uint32_t size
) {
1516 if (size
> 1024u * 1024u * 256u) ufoFatal("TIB size too big");
1517 const uint32_t tib
= ufoImgGetU32(ufoAddrTIBx
);
1518 //fprintf(stderr, "ufoTibEnsureSize: TIB=0x%08x; size=%u\n", tib, size);
1519 if ((tib
& UFO_ADDR_HANDLE_BIT
) != 0) {
1520 UfoHandle
*hh
= ufoGetHandle(tib
);
1522 ufoFatal("cannot resize TIB, TIB is not a handle");
1524 if (hh
->size
< size
) {
1525 const uint32_t newsz
= (size
| 0xfffU
) + 1u;
1526 uint8_t *nx
= realloc(hh
->data
, newsz
);
1527 if (nx
== NULL
) ufoFatal("out of memory for restored TIB");
1534 ufoFatal("cannot resize TIB, TIB is not a handle (0x%08x)", tib
);
1540 //==========================================================================
1544 //==========================================================================
1546 UFO_DISABLE_INLINE uint32_t ufoTibGetSize (void) {
1547 const uint32_t tib = ufoImgGetU32(ufoAddrTIBx);
1548 if ((tib & UFO_ADDR_HANDLE_BIT) == 0) {
1549 ufoFatal("cannot query TIB, TIB is not a handle");
1551 UfoHandle *hh = ufoGetHandle(tib);
1553 ufoFatal("cannot query TIB, TIB is not a handle");
1560 //==========================================================================
1564 //==========================================================================
1565 UFO_FORCE_INLINE
uint8_t ufoTibPeekCh (void) {
1566 return (uint8_t)ufoImgGetU8Ext(ufoImgGetU32(ufoAddrTIBx
) + ufoImgGetU32(ufoAddrINx
));
1570 //==========================================================================
1574 //==========================================================================
1575 UFO_FORCE_INLINE
uint8_t ufoTibPeekChOfs (uint32_t ofs
) {
1576 const uint32_t tib
= ufoImgGetU32(ufoAddrTIBx
);
1577 if (ofs
<= UFO_ADDR_HANDLE_OFS_MASK
|| (tib
& UFO_ADDR_HANDLE_BIT
) == 0) {
1578 return (uint8_t)ufoImgGetU8Ext(tib
+ ufoImgGetU32(ufoAddrINx
) + ofs
);
1585 //==========================================================================
1589 //==========================================================================
1590 UFO_DISABLE_INLINE
void ufoTibPokeChOfs (uint8_t ch
, uint32_t ofs
) {
1591 const uint32_t oldA
= ufoRegA
;
1592 ufoRegA
= ufoImgGetU32(ufoAddrTIBx
);
1594 ufoPush(ufoImgGetU32(ufoAddrINx
) + ofs
);
1595 UFCALL(CPOKE_REGA_IDX
);
1600 //==========================================================================
1604 //==========================================================================
1605 UFO_FORCE_INLINE
uint8_t ufoTibGetCh (void) {
1606 const uint8_t ch
= ufoTibPeekCh();
1607 if (ch
) ufoImgPutU32(ufoAddrINx
, ufoImgGetU32(ufoAddrINx
) + 1u);
1612 //==========================================================================
1616 //==========================================================================
1617 UFO_FORCE_INLINE
void ufoTibSkipCh (void) {
1618 (void)ufoTibGetCh();
1622 // ////////////////////////////////////////////////////////////////////////// //
1623 // native CFA implementations
1626 //==========================================================================
1630 //==========================================================================
1631 static void ufoDoForth (uint32_t pfa
) {
1637 //==========================================================================
1641 //==========================================================================
1642 static void ufoDoVariable (uint32_t pfa
) {
1647 //==========================================================================
1649 // ufoDoUserVariable
1651 //==========================================================================
1652 static void ufoDoUserVariable (uint32_t pfa
) {
1653 ufoPush(ufoImgGetU32(pfa
));
1657 //==========================================================================
1661 //==========================================================================
1662 static void ufoDoValue (uint32_t pfa
) {
1663 ufoPush(ufoImgGetU32(pfa
));
1667 //==========================================================================
1671 //==========================================================================
1672 static void ufoDoConst (uint32_t pfa
) {
1673 ufoPush(ufoImgGetU32(pfa
));
1677 //==========================================================================
1681 //==========================================================================
1682 static void ufoDoDefer (uint32_t pfa
) {
1683 const uint32_t cfa
= ufoImgGetU32(pfa
);
1691 //==========================================================================
1695 //==========================================================================
1696 static void ufoDoVoc (uint32_t pfa
) {
1697 ufoImgPutU32(ufoAddrContext
, ufoImgGetU32(pfa
));
1701 //==========================================================================
1705 //==========================================================================
1706 static void ufoDoCreate (uint32_t pfa
) {
1711 //==========================================================================
1715 // this also increments last used file id
1717 //==========================================================================
1718 static void ufoPushInFile (void) {
1719 if (ufoFileStackPos
>= UFO_MAX_NESTED_INCLUDES
) ufoFatal("too many includes");
1720 UFOFileStackEntry
*stk
= &ufoFileStack
[ufoFileStackPos
];
1721 stk
->fl
= ufoInFile
;
1722 stk
->fname
= ufoInFileName
;
1723 stk
->fline
= ufoInFileLine
;
1724 stk
->id
= ufoFileId
;
1725 stk
->incpath
= (ufoLastIncPath
? strdup(ufoLastIncPath
) : NULL
);
1726 stk
->sysincpath
= (ufoLastSysIncPath
? strdup(ufoLastSysIncPath
) : NULL
);
1727 ufoFileStackPos
+= 1;
1729 ufoInFileName
= NULL
;
1731 ufoLastUsedFileId
+= 1;
1732 ufo_assert(ufoLastUsedFileId
!= 0); // just in case ;-)
1733 //ufoLastIncPath = NULL;
1737 //==========================================================================
1739 // ufoWipeIncludeStack
1741 //==========================================================================
1742 static void ufoWipeIncludeStack (void) {
1743 if (ufoInFileName
) { free(ufoInFileName
); ufoInFileName
= NULL
; }
1744 if (ufoInFile
) { fclose(ufoInFile
); ufoInFile
= NULL
; }
1745 if (ufoLastIncPath
) { free(ufoLastIncPath
); ufoLastIncPath
= NULL
; }
1746 if (ufoLastSysIncPath
) { free(ufoLastSysIncPath
); ufoLastSysIncPath
= NULL
; }
1747 while (ufoFileStackPos
!= 0) {
1748 ufoFileStackPos
-= 1;
1749 UFOFileStackEntry
*stk
= &ufoFileStack
[ufoFileStackPos
];
1750 if (stk
->fl
) fclose(stk
->fl
);
1751 if (stk
->fname
) free(stk
->fname
);
1752 if (stk
->incpath
) free(stk
->incpath
);
1757 //==========================================================================
1761 //==========================================================================
1762 static void ufoPopInFile (void) {
1763 if (ufoFileStackPos
== 0) ufoFatal("trying to pop include from empty stack");
1764 if (ufoInFileName
) { free(ufoInFileName
); ufoInFileName
= NULL
; }
1765 if (ufoInFile
) { fclose(ufoInFile
); ufoInFile
= NULL
; }
1766 if (ufoLastIncPath
) { free(ufoLastIncPath
); ufoLastIncPath
= NULL
; }
1767 if (ufoLastSysIncPath
) { free(ufoLastSysIncPath
); ufoLastSysIncPath
= NULL
; }
1768 ufoFileStackPos
-= 1;
1769 UFOFileStackEntry
*stk
= &ufoFileStack
[ufoFileStackPos
];
1770 ufoInFile
= stk
->fl
;
1771 ufoInFileName
= stk
->fname
;
1772 ufoInFileLine
= stk
->fline
;
1773 ufoLastIncPath
= stk
->incpath
;
1774 ufoLastSysIncPath
= stk
->sysincpath
;
1775 ufoFileId
= stk
->id
;
1777 #ifdef UFO_DEBUG_INCLUDE
1778 if (ufoInFileName
== NULL
) {
1779 fprintf(stderr
, "INC-POP: no more files.\n");
1781 fprintf(stderr
, "INC-POP: fname: %s\n", ufoInFileName
);
1787 //==========================================================================
1791 //==========================================================================
1792 void ufoDeinit (void) {
1793 #ifdef UFO_DEBUG_DEBUG
1794 fprintf(stderr
, "UFO: debug image used: %u; size: %u\n",
1795 ufoDebugImageUsed
, ufoDebugImageSize
);
1796 ufoDumpDebugImage();
1800 ufoCurrState
= NULL
;
1801 ufoYieldedState
= NULL
;
1802 ufoDebuggerState
= NULL
;
1803 for (uint32_t fidx
= 0; fidx
< (uint32_t)(UFO_MAX_STATES
/32); fidx
+= 1u) {
1804 uint32_t bmp
= ufoStateUsedBitmap
[fidx
];
1806 uint32_t stid
= fidx
* 32u;
1808 if ((bmp
& 0x01) != 0) ufoFreeState(ufoStateMap
[stid
]);
1809 stid
+= 1u; bmp
>>= 1;
1814 free(ufoDebugImage
);
1815 ufoDebugImage
= NULL
;
1816 ufoDebugImageUsed
= 0;
1817 ufoDebugImageSize
= 0;
1819 ufoDebugLastFRecAddr
= 0;
1823 ufoClearCondDefines();
1824 ufoWipeIncludeStack();
1826 // release all includes
1828 if (ufoInFileName
) free(ufoInFileName
);
1829 if (ufoLastIncPath
) free(ufoLastIncPath
);
1830 if (ufoLastSysIncPath
) free(ufoLastSysIncPath
);
1831 ufoInFileName
= NULL
; ufoLastIncPath
= NULL
; ufoLastSysIncPath
= NULL
;
1835 ufoForthCFAs
= NULL
;
1842 ufoMode
= UFO_MODE_NATIVE
;
1844 ufoForthVocId
= 0; ufoCompilerVocId
= 0;
1848 for (uint32_t f
= 0; f
< ufoHandlesUsed
; f
+= 1) {
1849 UfoHandle
*hh
= ufoHandles
[f
];
1851 if (hh
->data
!= NULL
) free(hh
->data
);
1855 if (ufoHandles
!= NULL
) free(ufoHandles
);
1856 ufoHandles
= NULL
; ufoHandlesUsed
= 0; ufoHandlesAlloted
= 0;
1857 ufoHandleFreeList
= NULL
;
1859 ufoLastEmitWasCR
= 1;
1861 ufoClearCondDefines();
1865 //==========================================================================
1867 // ufoDumpWordHeader
1869 //==========================================================================
1870 __attribute__((unused
)) static void ufoDumpWordHeader (const uint32_t lfa
) {
1871 fprintf(stderr
, "=== WORD: LFA: 0x%08x ===\n", lfa
);
1873 fprintf(stderr
, " (DFA): 0x%08x\n", ufoImgGetU32(UFO_LFA_TO_DFA(lfa
)));
1874 fprintf(stderr
, " (XFA): 0x%08x\n", ufoImgGetU32(UFO_LFA_TO_XFA(lfa
)));
1875 fprintf(stderr
, " (YFA): 0x%08x\n", ufoImgGetU32(UFO_LFA_TO_YFA(lfa
)));
1876 fprintf(stderr
, " (BFA): 0x%08x\n", ufoImgGetU32(UFO_LFA_TO_BFA(lfa
)));
1877 fprintf(stderr
, " (LFA): 0x%08x\n", ufoImgGetU32(lfa
));
1878 fprintf(stderr
, " (NHH): 0x%08x\n", ufoImgGetU32(UFO_LFA_TO_NHASH(lfa
)));
1879 const uint32_t cfa
= UFO_LFA_TO_CFA(lfa
);
1880 fprintf(stderr
, " CFA: 0x%08x\n", cfa
);
1881 fprintf(stderr
, " PFA: 0x%08x\n", UFO_CFA_TO_PFA(cfa
));
1882 fprintf(stderr
, " (CFA): 0x%08x\n", ufoImgGetU32(cfa
));
1883 const uint32_t nfa
= UFO_LFA_TO_NFA(lfa
);
1884 const uint32_t nlen
= ufoImgGetU8(nfa
);
1885 fprintf(stderr
, " NFA: 0x%08x (nlen: %u)\n", nfa
, nlen
);
1886 const uint32_t flags
= ufoImgGetU32(nfa
);
1887 fprintf(stderr
, " FLAGS: 0x%08x\n", flags
);
1888 if ((flags
& 0xffff0000U
) != 0) {
1889 fprintf(stderr
, " FLAGS:");
1890 if (flags
& UFW_FLAG_IMMEDIATE
) fprintf(stderr
, " IMM");
1891 if (flags
& UFW_FLAG_SMUDGE
) fprintf(stderr
, " SMUDGE");
1892 if (flags
& UFW_FLAG_NORETURN
) fprintf(stderr
, " NORET");
1893 if (flags
& UFW_FLAG_HIDDEN
) fprintf(stderr
, " HIDDEN");
1894 if (flags
& UFW_FLAG_CBLOCK
) fprintf(stderr
, " CBLOCK");
1895 if (flags
& UFW_FLAG_VOCAB
) fprintf(stderr
, " VOCAB");
1896 if (flags
& UFW_FLAG_SCOLON
) fprintf(stderr
, " SCOLON");
1897 if (flags
& UFW_FLAG_PROTECTED
) fprintf(stderr
, " PROTECTED");
1898 fputc('\n', stderr
);
1900 if ((flags
& 0xff00U
) != 0) {
1901 fprintf(stderr
, " ARGS: ");
1902 switch (flags
& UFW_WARG_MASK
) {
1903 case UFW_WARG_NONE
: fprintf(stderr
, "NONE"); break;
1904 case UFW_WARG_BRANCH
: fprintf(stderr
, "BRANCH"); break;
1905 case UFW_WARG_LIT
: fprintf(stderr
, "LIT"); break;
1906 case UFW_WARG_C4STRZ
: fprintf(stderr
, "C4STRZ"); break;
1907 case UFW_WARG_CFA
: fprintf(stderr
, "CFA"); break;
1908 case UFW_WARG_CBLOCK
: fprintf(stderr
, "CBLOCK"); break;
1909 case UFW_WARG_VOCID
: fprintf(stderr
, "VOCID"); break;
1910 case UFW_WARG_C1STRZ
: fprintf(stderr
, "C1STRZ"); break;
1911 default: fprintf(stderr
, "wtf?!"); break;
1913 fputc('\n', stderr
);
1915 fprintf(stderr
, " BACKLEN: %u (nfa at 0x%08x)\n", ufoImgGetU8(cfa
- 1u), UFO_CFA_TO_NFA(cfa
));
1916 fprintf(stderr
, " NAME(%u): ", nlen
);
1917 for (uint32_t f
= 0; f
< nlen
; f
+= 1) {
1918 const uint8_t ch
= ufoImgGetU8(nfa
+ 4u + f
);
1919 if (ch
<= 32 || ch
>= 127) {
1920 fprintf(stderr
, "\\x%02x", ch
);
1922 fprintf(stderr
, "%c", (char)ch
);
1925 fprintf(stderr
, "\n");
1926 ufo_assert(UFO_CFA_TO_LFA(cfa
) == lfa
);
1931 //==========================================================================
1937 //==========================================================================
1938 static uint32_t ufoVocCheckName (uint32_t lfa
, const void *wname
, uint32_t wnlen
, uint32_t hash
,
1942 #ifdef UFO_DEBUG_FIND_WORD
1943 fprintf(stderr
, "CHECK-NAME: %.*s; LFA: 0x%08x; hash: 0x%08x (wname: 0x%08x)\n",
1944 (unsigned) wnlen
, (const char *)wname
,
1945 lfa
, (lfa
!= 0 ? ufoImgGetU32(UFO_LFA_TO_NHASH(lfa
)) : 0), hash
);
1946 ufoDumpWordHeader(lfa
);
1948 if (lfa
!= 0 && ufoImgGetU32(UFO_LFA_TO_NHASH(lfa
)) == hash
) {
1949 const uint32_t lenflags
= ufoImgGetU32(UFO_LFA_TO_NFA(lfa
));
1950 if ((lenflags
& UFW_FLAG_SMUDGE
) == 0 &&
1951 (allowvochid
|| (lenflags
& UFW_FLAG_HIDDEN
) == 0))
1953 const uint32_t nlen
= lenflags
&0xffU
;
1954 if (nlen
== wnlen
) {
1955 uint32_t naddr
= UFO_LFA_TO_NFA(lfa
) + 4u;
1957 while (pos
< nlen
) {
1958 uint8_t c0
= ((const unsigned char *)wname
)[pos
];
1959 if (c0
>= 'a' && c0
<= 'z') c0
= c0
- 'a' + 'A';
1960 uint8_t c1
= ufoImgGetU8(naddr
+ pos
);
1961 if (c1
>= 'a' && c1
<= 'z') c1
= c1
- 'a' + 'A';
1962 if (c0
!= c1
) break;
1968 res
= UFO_ALIGN4(naddr
);
1977 //==========================================================================
1983 //==========================================================================
1984 static uint32_t ufoFindWordInVoc (const void *wname
, uint32_t wnlen
, uint32_t hash
,
1985 uint32_t vocid
, int allowvochid
)
1988 if (wname
== NULL
) ufo_assert(wnlen
== 0);
1989 if (wnlen
!= 0 && vocid
!= 0) {
1990 if (hash
== 0) hash
= joaatHashBufCI(wname
, wnlen
);
1991 #if defined(UFO_DEBUG_FIND_WORD) || defined(UFO_DEBUG_FIND_WORD_IN_VOC)
1992 fprintf(stderr
, "IN-VOC: %.*s; VOCID: 0x%08x; whash: 0x%08x; htbl[0]: 0x%08x\n",
1993 (unsigned) wnlen
, (const char *)wname
,
1994 vocid
, hash
, ufoImgGetU32(vocid
+ UFW_VOCAB_OFS_HTABLE
));
1996 const uint32_t htbl
= vocid
+ UFW_VOCAB_OFS_HTABLE
;
1997 if (ufoImgGetU32(htbl
) != UFO_NO_HTABLE_FLAG
) {
1998 // hash table present, use it
1999 uint32_t bfa
= htbl
+ (hash
% (uint32_t)UFO_HASHTABLE_SIZE
) * 4u;
2000 bfa
= ufoImgGetU32(bfa
);
2001 while (res
== 0 && bfa
!= 0) {
2002 #if defined(UFO_DEBUG_FIND_WORD) || defined(UFO_DEBUG_FIND_WORD_IN_VOC)
2003 fprintf(stderr
, "IN-VOC: bfa: 0x%08x\n", bfa
);
2005 res
= ufoVocCheckName(UFO_BFA_TO_LFA(bfa
), wname
, wnlen
, hash
, allowvochid
);
2006 bfa
= ufoImgGetU32(bfa
);
2009 // no hash table, use linear search
2010 uint32_t lfa
= vocid
+ UFW_VOCAB_OFS_LATEST
;
2011 lfa
= ufoImgGetU32(lfa
);
2012 while (res
== 0 && lfa
!= 0) {
2013 res
= ufoVocCheckName(lfa
, wname
, wnlen
, hash
, allowvochid
);
2014 lfa
= ufoImgGetU32(lfa
);
2022 //==========================================================================
2026 // return part after the colon, or `NULL`
2028 //==========================================================================
2029 static const void *ufoFindColon (const void *wname
, uint32_t wnlen
) {
2030 const void *res
= NULL
;
2032 ufo_assert(wname
!= NULL
);
2033 const char *str
= (const char *)wname
;
2034 while (wnlen
!= 0 && str
[0] != ':') {
2035 str
+= 1; wnlen
-= 1;
2038 res
= (const void *)(str
+ 1); // skip colon
2045 //==========================================================================
2047 // ufoFindWordInVocAndParents
2049 //==========================================================================
2050 static uint32_t ufoFindWordInVocAndParents (const void *wname
, uint32_t wnlen
, uint32_t hash
,
2051 uint32_t vocid
, int allowvochid
)
2054 if (hash
== 0) hash
= joaatHashBufCI(wname
, wnlen
);
2055 while (res
== 0 && vocid
!= 0) {
2056 res
= ufoFindWordInVoc(wname
, wnlen
, hash
, vocid
, allowvochid
);
2057 vocid
= ufoImgGetU32(vocid
+ UFW_VOCAB_OFS_PARENT
);
2063 //==========================================================================
2065 // ufoFindWordNameRes
2067 // find with name resolution
2071 //==========================================================================
2072 static uint32_t ufoFindWordNameRes (const void *wname
, uint32_t wnlen
) {
2074 if (wnlen
!= 0 && *(const char *)wname
!= ':') {
2075 ufo_assert(wname
!= NULL
);
2077 const void *stx
= wname
;
2078 wname
= ufoFindColon(wname
, wnlen
);
2079 if (wname
!= NULL
) {
2080 // look in all vocabs (excluding hidden ones)
2081 uint32_t xlen
= (uint32_t)(ptrdiff_t)(wname
- stx
) - 1u;
2082 ufo_assert(xlen
> 0 && xlen
< 255);
2083 uint32_t xhash
= joaatHashBufCI(stx
, xlen
);
2084 uint32_t voclink
= ufoImgGetU32(ufoAddrVocLink
);
2085 #ifdef UFO_DEBUG_FIND_WORD_COLON
2086 fprintf(stderr
, "COLON-FIND: first voc: {%.*s}; xhash=0x%08x; voc-link: 0x%08x\n",
2087 (unsigned)xlen
, (const char *)stx
, xhash
, voclink
);
2089 while (res
== 0 && voclink
!= 0) {
2090 const uint32_t vhdraddr
= voclink
- UFW_VOCAB_OFS_VOCLINK
+ UFW_VOCAB_OFS_HEADER
;
2091 const uint32_t vhdr
= ufoImgGetU32(vhdraddr
);
2093 res
= ufoVocCheckName(UFO_NFA_TO_LFA(vhdr
), stx
, xlen
, xhash
, 0);
2095 if (res
== 0) voclink
= ufoImgGetU32(voclink
);
2098 uint32_t vocid
= voclink
- UFW_VOCAB_OFS_VOCLINK
;
2099 ufo_assert(voclink
!= 0);
2101 #ifdef UFO_DEBUG_FIND_WORD_COLON
2102 fprintf(stderr
, "searching {%.*s}(%u) in {%.*s}\n",
2103 (unsigned)wnlen
, wname
, wnlen
, (unsigned)xlen
, stx
);
2105 while (res
!= 0 && wname
!= NULL
) {
2107 wname
= ufoFindColon(wname
, wnlen
);
2108 if (wname
== NULL
) xlen
= wnlen
; else xlen
= (uint32_t)(ptrdiff_t)(wname
- stx
) - 1u;
2109 ufo_assert(xlen
> 0 && xlen
< 255);
2110 res
= ufoFindWordInVocAndParents(stx
, xlen
, 0, vocid
, 1);
2113 if (wname
!= NULL
) {
2114 // it should be a vocabulary
2115 const uint32_t nfa
= UFO_CFA_TO_NFA(res
);
2116 if ((ufoImgGetU32(nfa
) & UFW_FLAG_VOCAB
) != 0) {
2117 vocid
= ufoImgGetU32(UFO_CFA_TO_PFA(res
)); // pfa points to vocabulary
2132 //==========================================================================
2136 // doesn't look in CURRENT, does name resolution ("a:b" is word "b" in "a")
2140 //==========================================================================
2141 static uint32_t ufoFindWord (const char *wname
) {
2143 if (wname
&& wname
[0] != 0) {
2144 const size_t wnlen
= strlen(wname
);
2145 ufo_assert(wnlen
< 8192);
2146 uint32_t ctx
= ufoImgGetU32(ufoAddrContext
);
2147 const uint32_t hash
= joaatHashBufCI(wname
, (uint32_t)wnlen
);
2149 //fprintf(stderr, "FIND-WORD: whash: 0x%08x; name:{%s}\n", hash, wname);
2151 // first search in context
2152 res
= ufoFindWordInVocAndParents(wname
, (uint32_t)wnlen
, hash
, ctx
, (ctx
== ufoImgGetU32(ufoAddrCurrent
)));
2154 // now try vocabulary stack
2155 uint32_t vstp
= ufoVSP
;
2156 while (res
== 0 && vstp
!= 0) {
2158 ctx
= ufoVocStack
[vstp
];
2159 res
= ufoFindWordInVocAndParents(wname
, (uint32_t)wnlen
, hash
, ctx
, (ctx
== ufoImgGetU32(ufoAddrCurrent
)));
2162 // if not found, try name resolution
2163 if (res
== 0) res
= ufoFindWordNameRes(wname
, (uint32_t)wnlen
);
2170 //==========================================================================
2172 // ufoCreateWordHeader
2174 // create word header up to CFA, link to the current dictionary
2176 //==========================================================================
2177 static void ufoCreateWordHeader (const char *wname
, uint32_t flags
) {
2178 if (wname
== NULL
) wname
= "";
2179 const size_t wnlen
= strlen(wname
);
2180 ufo_assert(wnlen
< UFO_MAX_WORD_LENGTH
);
2181 const uint32_t hash
= joaatHashBufCI(wname
, (uint32_t)wnlen
);
2182 const uint32_t curr
= ufoImgGetU32(ufoAddrCurrent
);
2183 ufo_assert(curr
!= 0);
2185 if (wnlen
!= 0 && ufoImgGetU32(ufoAddrRedefineWarning
) != UFO_REDEF_WARN_DONT_CARE
) {
2186 const uint32_t cfa
= ufoFindWordInVoc(wname
, wnlen
, hash
, curr
, 1);
2188 const uint32_t nfa
= UFO_CFA_TO_NFA(cfa
);
2189 const uint32_t flags
= ufoImgGetU32(nfa
);
2190 if ((flags
& UFW_FLAG_PROTECTED
) != 0) {
2191 ufoFatal("trying to redefine protected word '%s'", wname
);
2192 } else if (ufoImgGetU32(ufoAddrRedefineWarning
) != UFO_REDEF_WARN_NONE
) {
2193 ufoWarning("redefining word '%s'", wname
);
2197 //fprintf(stderr, "000: HERE: 0x%08x\n", UFO_GET_DP());
2198 const uint32_t bkt
= (hash
% (uint32_t)UFO_HASHTABLE_SIZE
) * 4u;
2199 const uint32_t htbl
= curr
+ UFW_VOCAB_OFS_HTABLE
;
2201 ufoImgEmitU32(0); // dfa
2202 const uint32_t xfaAddr
= UFO_GET_DP();
2203 if ((xfaAddr
& UFO_ADDR_TEMP_BIT
) == 0) {
2204 // link previous yfa here
2205 const uint32_t lastxfa
= ufoImgGetU32(ufoAddrLastXFA
);
2206 // fix YFA of the previous word
2208 ufoImgPutU32(UFO_XFA_TO_YFA(lastxfa
), UFO_XFA_TO_YFA(xfaAddr
));
2210 // our XFA points to the previous XFA
2211 ufoImgEmitU32(lastxfa
); // xfa
2213 ufoImgPutU32(ufoAddrLastXFA
, xfaAddr
);
2215 ufoImgEmitU32(0); // xfa
2217 ufoImgEmitU32(0); // yfa
2218 // bucket link (bfa)
2219 if (wnlen
== 0 || ufoImgGetU32(htbl
) == UFO_NO_HTABLE_FLAG
) {
2222 #ifdef UFO_DEBUG_DUMP_NEW_HEADERS
2223 fprintf(stderr
, "NEW HEADER: %s; curr: 0x%08x; htbl: 0x%08x; bkt: 0x%08x\n",
2224 wname
, curr
, htbl
, bkt
);
2225 fprintf(stderr
, " [bkt]: 0x%08x; nbk: 0x%08x\n", ufoImgGetU32(htbl
+ bkt
), UFO_GET_DP());
2227 // bfa points to bfa
2228 const uint32_t bfa
= UFO_GET_DP();
2229 ufoImgEmitU32(ufoImgGetU32(htbl
+ bkt
));
2230 ufoImgPutU32(htbl
+ bkt
, bfa
);
2233 const uint32_t lfa
= UFO_GET_DP();
2234 ufoImgEmitU32(ufoImgGetU32(curr
+ UFW_VOCAB_OFS_LATEST
));
2236 ufoImgPutU32(curr
+ UFW_VOCAB_OFS_LATEST
, lfa
);
2238 ufoImgEmitU32(hash
);
2240 const uint32_t nfa
= UFO_GET_DP();
2241 ufoImgEmitU32(((uint32_t)wnlen
&0xffU
) | (flags
& 0xffffff00U
));
2242 const uint32_t nstart
= UFO_GET_DP();
2244 for (size_t f
= 0; f
< wnlen
; f
+= 1) {
2245 ufoImgEmitU8(((const unsigned char *)wname
)[f
]);
2247 while ((UFO_GET_DP() & 3) != 3) ufoImgEmitU8(0);
2248 const uint32_t nend
= UFO_GET_DP(); // length byte itself is not included
2249 // name length, again
2250 ufo_assert(nend
- nstart
<= 255);
2251 ufoImgEmitU8((uint8_t)(nend
- nstart
));
2252 ufo_assert((UFO_GET_DP() & 3) == 0);
2253 ufo_assert(UFO_CFA_TO_NFA(UFO_GET_DP()) == nfa
);
2254 if ((nend
& UFO_ADDR_SPECIAL_BITS_MASK
) == 0) ufoRecordDebug(nend
);
2255 #ifdef UFO_DEBUG_DUMP_NEW_HEADERS
2256 fprintf(stderr
, "*** NEW HEADER ***\n");
2257 fprintf(stderr
, "CFA: 0x%08x\n", UFO_GET_DP());
2258 fprintf(stderr
, "NSTART: 0x%08x\n", nstart
);
2259 fprintf(stderr
, "NEND: 0x%08x\n", nend
);
2260 fprintf(stderr
, "NLEN: %u (%u)\n", nend
- nstart
, ufoImgGetU8(UFO_GET_DP() - 1u));
2261 ufoDumpWordHeader(lfa
);
2264 fprintf(stderr
, "NEW WORD CFA 0x%08x: %s\n", UFO_GET_DP(), wname
);
2269 //==========================================================================
2273 //==========================================================================
2274 static void ufoDecompilePart (uint32_t addr
, uint32_t eaddr
, int indent
) {
2277 while (addr
< eaddr
) {
2278 uint32_t cfa
= ufoImgGetU32(addr
);
2279 for (int n
= 0; n
< indent
; n
+= 1) fputc(' ', fo
);
2280 fprintf(fo
, "%6u: 0x%08x: ", addr
, cfa
);
2281 uint32_t nfa
= UFO_CFA_TO_NFA(cfa
);
2282 uint32_t flags
= ufoImgGetU32(nfa
);
2283 //fprintf(fo, "[0x%08x] ", flags & UFW_WARG_MASK);
2284 uint32_t nlen
= flags
& 0xffU
;
2285 for (uint32_t f
= 0; f
< nlen
; f
+= 1) {
2286 const uint8_t ch
= ufoImgGetU8(nfa
+ 4u + f
);
2287 if (ch
<= 32 || ch
>= 127) {
2288 fprintf(fo
, "\\x%02x", ch
);
2290 fprintf(fo
, "%c", (char)ch
);
2294 switch (flags
& UFW_WARG_MASK
) {
2297 case UFW_WARG_BRANCH
:
2298 fprintf(fo
, " @%u", ufoImgGetU32(addr
)); addr
+= 4u;
2301 fprintf(fo
, " %u : %d : 0x%08x", ufoImgGetU32(addr
),
2302 (int32_t)ufoImgGetU32(addr
), ufoImgGetU32(addr
)); addr
+= 4u;
2304 case UFW_WARG_C4STRZ
:
2305 count
= ufoImgGetU32(addr
); addr
+= 4;
2307 fprintf(fo
, " str:");
2308 for (int f
= 0; f
< count
; f
+= 1) {
2309 const uint8_t ch
= ufoImgGetU8(addr
); addr
+= 1u;
2310 if (ch
<= 32 || ch
>= 127) {
2311 fprintf(fo
, "\\x%02x", ch
);
2313 fprintf(fo
, "%c", (char)ch
);
2316 addr
+= 1u; // skip zero byte
2317 addr
= UFO_ALIGN4(addr
);
2320 cfa
= ufoImgGetU32(addr
); addr
+= 4u;
2321 fprintf(fo
, " CFA:%u: ", cfa
);
2322 nfa
= UFO_CFA_TO_NFA(cfa
);
2323 nlen
= ufoImgGetU8(nfa
);
2324 for (uint32_t f
= 0; f
< nlen
; f
+= 1) {
2325 const uint8_t ch
= ufoImgGetU8(nfa
+ 4u + f
);
2326 if (ch
<= 32 || ch
>= 127) {
2327 fprintf(fo
, "\\x%02x", ch
);
2329 fprintf(fo
, "%c", (char)ch
);
2333 case UFW_WARG_CBLOCK
:
2334 fprintf(fo
, " CBLOCK:%u", ufoImgGetU32(addr
)); addr
+= 4u;
2336 case UFW_WARG_VOCID
:
2337 fprintf(fo
, " VOCID:%u", ufoImgGetU32(addr
)); addr
+= 4u;
2339 case UFW_WARG_C1STRZ
:
2340 count
= ufoImgGetU8(addr
); addr
+= 1;
2344 fprintf(fo, " ubyte:%u", ufoImgGetU8(addr)); addr += 1u;
2347 fprintf(fo, " sbyte:%u", ufoImgGetU8(addr)); addr += 1u;
2350 fprintf(fo, " uword:%u", ufoImgGetU16(addr)); addr += 2u;
2353 fprintf(fo, " sword:%u", ufoImgGetU16(addr)); addr += 2u;
2357 fprintf(fo
, " -- WTF?!\n");
2365 //==========================================================================
2369 //==========================================================================
2370 static void ufoDecompileWord (const uint32_t cfa
) {
2372 const uint32_t lfa
= UFO_CFA_TO_LFA(cfa
);
2373 fprintf(stdout
, "#### DECOMPILING CFA %u ###\n", cfa
);
2374 ufoDumpWordHeader(lfa
);
2375 const uint32_t yfa
= ufoGetWordEndAddr(cfa
);
2376 if (ufoImgGetU32(cfa
) == ufoDoForthCFA
) {
2377 fprintf(stdout
, "--- DECOMPILED CODE ---\n");
2378 ufoDecompilePart(UFO_CFA_TO_PFA(cfa
), yfa
, 0);
2379 fprintf(stdout
, "=======================\n");
2385 //==========================================================================
2387 // ufoBTShowWordName
2389 //==========================================================================
2390 static void ufoBTShowWordName (uint32_t nfa
) {
2392 uint32_t len
= ufoImgGetU8(nfa
); nfa
+= 4u;
2393 //fprintf(stderr, "(0x%08x)", ufoImgGetU32(nfa - 4u));
2395 uint8_t ch
= ufoImgGetU8(nfa
); nfa
+= 1u; len
-= 1u;
2396 if (ch
<= 32 || ch
>= 127) {
2397 fprintf(stderr
, "\\x%02x", ch
);
2399 fprintf(stderr
, "%c", (char)ch
);
2406 //==========================================================================
2410 //==========================================================================
2411 static void ufoBacktrace (uint32_t ip
) {
2412 // dump data stack (top 16)
2413 if (!ufoLastEmitWasCR
) { printf("\n"); ufoLastEmitWasCR
= 1; }
2416 fprintf(stderr
, "***UFO STACK DEPTH: %u\n", ufoSP
);
2417 uint32_t xsp
= ufoSP
;
2418 if (xsp
> 16) xsp
= 16;
2419 for (uint32_t sp
= 0; sp
< xsp
; ++sp
) {
2420 fprintf(stderr
, " %2u: 0x%08x %d\n", sp
,
2421 ufoDStack
[xsp
- sp
- 1], (int32_t)ufoDStack
[xsp
- sp
- 1]);
2423 if (ufoSP
> 16) fprintf(stderr
, " ...more...\n");
2425 // dump return stack (top 32)
2430 fprintf(stderr
, "***UFO RETURN STACK DEPTH: %u\n", ufoRP
);
2432 nfa
= ufoFindWordForIP(ip
);
2434 fprintf(stderr
, " **: %8u -- ", ip
);
2435 ufoBTShowWordName(nfa
);
2436 fname
= ufoFindFileForIP(ip
, &fline
);
2437 if (fname
!= NULL
) { fprintf(stderr
, " (at %s:%u)", fname
, fline
); }
2438 fputc('\n', stderr
);
2441 uint32_t rp
= ufoRP
;
2442 uint32_t rscount
= 0;
2443 if (rp
> UFO_RSTACK_SIZE
) rp
= UFO_RSTACK_SIZE
;
2444 while (rscount
!= 32 && rp
!= 0) {
2446 const uint32_t val
= ufoRStack
[rp
];
2447 nfa
= ufoFindWordForIP(val
);
2449 fprintf(stderr
, " %2u: %8u -- ", ufoRP
- rp
- 1u, val
);
2450 ufoBTShowWordName(nfa
);
2451 fname
= ufoFindFileForIP(val
- 4u, &fline
);
2452 if (fname
!= NULL
) { fprintf(stderr
, " (at %s:%u)", fname
, fline
); }
2453 fputc('\n', stderr
);
2455 fprintf(stderr
, " %2u: 0x%08x %d\n", ufoRP
- rp
- 1u, val
, (int32_t)val
);
2459 if (ufoRP
> 32) fprintf(stderr
, " ...more...\n");
2465 //==========================================================================
2469 //==========================================================================
2471 static void ufoDumpVocab (uint32_t vocid) {
2473 fprintf(stderr, "*** VOCID: 0x%08x ***\n", vocid);
2474 uint32_t vochdr = vocid + UFW_VOCAB_OFS_HEADER;
2475 vochdr = ufoImgGetU32(vochdr);
2477 fprintf(stderr, "--- HEADER ---\n");
2478 ufoDumpWordHeader(UFO_NFA_TO_LFA(vochdr));
2479 fprintf(stderr, "========\n");
2480 uint32_t htbl = vocid + UFW_VOCAB_OFS_HTABLE;
2481 if (ufoImgGetU32(htbl) != UFO_NO_HTABLE_FLAG) {
2482 fprintf(stderr, "--- HASH TABLE ---\n");
2483 for (int f = 0; f < UFO_HASHTABLE_SIZE; f += 1) {
2484 uint32_t bfa = ufoImgGetU32(htbl);
2486 fprintf(stderr, "**** %2d: 0x%08x\n", f, bfa);
2488 ufoDumpWordHeader(UFO_BFA_TO_LFA(bfa));
2489 bfa = ufoImgGetU32(bfa);
2501 // if set, this will be used when we are out of include files. intended for UrAsm.
2502 // return 0 if there is no more lines, otherwise the string should be copied
2503 // to buffer, `*fname` and `*fline` should be properly set.
2504 int (*ufoFileReadLine
) (void *buf
, size_t bufsize
, const char **fname
, int *fline
) = NULL
;
2507 //==========================================================================
2509 // ufoLoadNextUserLine
2511 //==========================================================================
2512 static int ufoLoadNextUserLine (void) {
2513 uint32_t tibPos
= 0;
2514 const char *fname
= NULL
;
2517 if (ufoFileReadLine
!= NULL
&& ufoFileReadLine(ufoCurrFileLine
, 510, &fname
, &fline
) != 0) {
2518 ufoCurrFileLine
[510] = 0;
2519 uint32_t slen
= (uint32_t)strlen(ufoCurrFileLine
);
2520 while (slen
!= 0 && (ufoCurrFileLine
[slen
- 1u] == 10 || ufoCurrFileLine
[slen
- 1u] == 13)) {
2523 if (tibPos
+ slen
+ 1u > UFO_ADDR_HANDLE_OFS_MASK
) {
2524 ufoFatal("input text line too long (at least %u bytes)", tibPos
+ slen
);
2526 ufoTibEnsureSize(tibPos
+ slen
+ 1u);
2527 for (uint32_t f
= 0; f
< slen
; f
+= 1) {
2528 ufoTibPokeChOfs(((const unsigned char *)ufoCurrFileLine
)[f
], tibPos
+ f
);
2530 ufoTibPokeChOfs(0, tibPos
+ slen
);
2532 if (fname
== NULL
) fname
= "<user>";
2533 if (ufoInFileName
== NULL
|| strcmp(ufoInFileName
, fname
) != 0) {
2534 free(ufoInFileName
);
2535 ufoInFileName
= strdup(fname
);
2536 if (ufoInFileName
== NULL
) ufoFatal("out of memory");
2538 ufoInFileLine
= fline
;
2546 //==========================================================================
2548 // ufoLoadNextLine_NativeMode
2550 // load next file line into TIB
2551 // always strips final '\n'
2553 // return 0 on EOF, 1 on success
2555 //==========================================================================
2556 static int ufoLoadNextLine (int crossInclude
) {
2558 uint32_t tibPos
= 0;
2561 if (ufoMode
== UFO_MODE_MACRO
) {
2562 //fprintf(stderr, "***MAC!\n");
2566 while (ufoInFile
!= NULL
&& !done
) {
2567 if (fgets(ufoCurrFileLine
, 510, ufoInFile
) != NULL
) {
2568 // check for a newline
2569 // if there is no newline char at the end, the string was truncated
2570 ufoCurrFileLine
[510] = 0;
2571 const uint32_t slen
= (uint32_t)strlen(ufoCurrFileLine
);
2572 if (tibPos
+ slen
+ 1u > UFO_ADDR_HANDLE_OFS_MASK
) {
2573 ufoFatal("input text line too long (at least %u bytes)", tibPos
+ slen
);
2575 ufoTibEnsureSize(tibPos
+ slen
+ 1u);
2576 for (uint32_t f
= 0; f
< slen
; f
+= 1) {
2577 ufoTibPokeChOfs(((const unsigned char *)ufoCurrFileLine
)[f
], tibPos
+ f
);
2579 ufoTibPokeChOfs(0, tibPos
+ slen
);
2581 if (slen
!= 0 && (ufoCurrFileLine
[slen
- 1u] == 13 || ufoCurrFileLine
[slen
- 1u] == 10)) {
2585 // continuation, nothing to do
2588 // if we read nothing, this is EOF
2589 if (tibPos
== 0 && crossInclude
) {
2590 // we read nothing, and allowed to cross include boundaries
2599 // eof, try user-supplied input
2600 if (ufoFileStackPos
== 0) {
2601 return ufoLoadNextUserLine();
2606 // if we read at least something, this is not EOF
2612 // ////////////////////////////////////////////////////////////////////////// //
2617 UFWORD(DUMP_STACK
) {
2618 if (!ufoLastEmitWasCR
) { printf("\n"); ufoLastEmitWasCR
= 1; }
2619 printf("***UFO STACK DEPTH: %u\n", ufoSP
);
2621 uint32_t sp
= ufoSP
;
2622 while (sp
!= 0 && left
!= 0) {
2624 printf(" %4u: 0x%08x %d\n", sp
, ufoDStack
[sp
], (int32_t)ufoDStack
[sp
]);
2626 if (sp
!= 0) printf("...more...\n");
2627 ufoLastEmitWasCR
= 1;
2631 UFWORD(UFO_BACKTRACE
) {
2632 if (!ufoLastEmitWasCR
) { printf("\n"); ufoLastEmitWasCR
= 1; }
2634 if (ufoInFile
!= NULL
) {
2635 fprintf(stderr
, "*** at file %s, line %d ***\n", ufoInFileName
, ufoInFileLine
);
2637 fprintf(stderr
, "*** somewhere in time ***\n");
2639 ufoBacktrace(ufoIP
);
2643 // ////////////////////////////////////////////////////////////////////////// //
2646 UFWORD(SP0_STORE
) { ufoSP
= 0; }
2651 if (ufoRP
!= ufoRPTop
) {
2653 // we need to push a dummy value
2654 ufoRPush(0xdeadf00d);
2660 // PAD is at the beginning of temp area
2662 ufoPush(UFO_PAD_ADDR
);
2666 // ////////////////////////////////////////////////////////////////////////// //
2667 // peeks and pokes with address register
2678 UFWORD(REGA_STORE
) {
2686 const uint32_t newa
= ufoPop();
2706 ufoRegA
= ufoRPop();
2710 // ////////////////////////////////////////////////////////////////////////// //
2711 // useful to work with handles and normal addreses uniformly
2716 UFWORD(CPEEK_REGA_IDX
) {
2717 if ((ufoRegA
& UFO_ADDR_HANDLE_BIT
) == 0) {
2718 const uint32_t idx
= ufoPop();
2719 const uint32_t newaddr
= ufoRegA
+ idx
;
2720 if ((ufoRegA
& UFO_ADDR_SPECIAL_BITS_MASK
) == (newaddr
& UFO_ADDR_SPECIAL_BITS_MASK
)) {
2721 ufoPush(ufoImgGetU8Ext(newaddr
));
2723 ufoFatal("address offset out of range; addr=0x%08x; offset=%u; res=0x%08x",
2724 ufoRegA
, idx
, newaddr
);
2728 UFCALL(PAR_HANDLE_LOAD_BYTE
);
2734 UFWORD(WPEEK_REGA_IDX
) {
2735 if ((ufoRegA
& UFO_ADDR_HANDLE_BIT
) == 0) {
2736 const uint32_t idx
= ufoPop();
2737 const uint32_t newaddr
= ufoRegA
+ idx
;
2738 if ((ufoRegA
& UFO_ADDR_SPECIAL_BITS_MASK
) == (newaddr
& UFO_ADDR_SPECIAL_BITS_MASK
) &&
2739 (ufoRegA
& UFO_ADDR_SPECIAL_BITS_MASK
) == ((newaddr
+ 1u) & UFO_ADDR_SPECIAL_BITS_MASK
))
2741 ufoPush(ufoImgGetU16(newaddr
));
2743 ufoFatal("address offset out of range; addr=0x%08x; offset=%u; res=0x%08x",
2744 ufoRegA
, idx
, newaddr
);
2748 UFCALL(PAR_HANDLE_LOAD_WORD
);
2754 UFWORD(PEEK_REGA_IDX
) {
2755 if ((ufoRegA
& UFO_ADDR_HANDLE_BIT
) == 0) {
2756 const uint32_t idx
= ufoPop();
2757 const uint32_t newaddr
= ufoRegA
+ idx
;
2758 if ((ufoRegA
& UFO_ADDR_SPECIAL_BITS_MASK
) == (newaddr
& UFO_ADDR_SPECIAL_BITS_MASK
) &&
2759 (ufoRegA
& UFO_ADDR_SPECIAL_BITS_MASK
) == ((newaddr
+ 3u) & UFO_ADDR_SPECIAL_BITS_MASK
))
2761 ufoPush(ufoImgGetU32(newaddr
));
2763 ufoFatal("address offset out of range; addr=0x%08x; offset=%u; res=0x%08x",
2764 ufoRegA
, idx
, newaddr
);
2768 UFCALL(PAR_HANDLE_LOAD_CELL
);
2774 UFWORD(CPOKE_REGA_IDX
) {
2775 if ((ufoRegA
& UFO_ADDR_HANDLE_BIT
) == 0) {
2776 const uint32_t idx
= ufoPop();
2777 const uint32_t newaddr
= ufoRegA
+ idx
;
2778 if ((ufoRegA
& UFO_ADDR_SPECIAL_BITS_MASK
) == (newaddr
& UFO_ADDR_SPECIAL_BITS_MASK
)) {
2779 const uint32_t value
= ufoPop();
2780 ufoImgPutU8(newaddr
, value
);
2782 ufoFatal("address offset out of range; addr=0x%08x; offset=%u; res=0x%08x",
2783 ufoRegA
, idx
, newaddr
);
2787 UFCALL(PAR_HANDLE_STORE_BYTE
);
2793 UFWORD(WPOKE_REGA_IDX
) {
2794 if ((ufoRegA
& UFO_ADDR_HANDLE_BIT
) == 0) {
2795 const uint32_t idx
= ufoPop();
2796 const uint32_t newaddr
= ufoRegA
+ idx
;
2797 if ((ufoRegA
& UFO_ADDR_SPECIAL_BITS_MASK
) == (newaddr
& UFO_ADDR_SPECIAL_BITS_MASK
) &&
2798 (ufoRegA
& UFO_ADDR_SPECIAL_BITS_MASK
) == ((newaddr
+ 1u) & UFO_ADDR_SPECIAL_BITS_MASK
))
2800 const uint32_t value
= ufoPop();
2801 ufoImgPutU16(newaddr
, value
);
2803 ufoFatal("address offset out of range; addr=0x%08x; offset=%u; res=0x%08x",
2804 ufoRegA
, idx
, newaddr
);
2808 UFCALL(PAR_HANDLE_STORE_WORD
);
2814 UFWORD(POKE_REGA_IDX
) {
2815 if ((ufoRegA
& UFO_ADDR_HANDLE_BIT
) == 0) {
2816 const uint32_t idx
= ufoPop();
2817 const uint32_t newaddr
= ufoRegA
+ idx
;
2818 if ((ufoRegA
& UFO_ADDR_SPECIAL_BITS_MASK
) == (newaddr
& UFO_ADDR_SPECIAL_BITS_MASK
) &&
2819 (ufoRegA
& UFO_ADDR_SPECIAL_BITS_MASK
) == ((newaddr
+ 3u) & UFO_ADDR_SPECIAL_BITS_MASK
))
2821 const uint32_t value
= ufoPop();
2822 ufoImgPutU32(newaddr
, value
);
2824 ufoFatal("address offset out of range; addr=0x%08x; offset=%u; res=0x%08x",
2825 ufoRegA
, idx
, newaddr
);
2829 UFCALL(PAR_HANDLE_STORE_CELL
);
2834 // ////////////////////////////////////////////////////////////////////////// //
2839 // ( addr -- value8 )
2841 ufoPush(ufoImgGetU8Ext(ufoPop()));
2845 // ( addr -- value16 )
2847 const uint32_t addr
= ufoPop();
2848 if ((addr
& UFO_ADDR_HANDLE_BIT
) == 0) {
2849 ufoPush(ufoImgGetU16(addr
));
2853 UFCALL(PAR_HANDLE_LOAD_WORD
);
2858 // ( addr -- value32 )
2860 const uint32_t addr
= ufoPop();
2861 if ((addr
& UFO_ADDR_HANDLE_BIT
) == 0) {
2862 ufoPush(ufoImgGetU32(addr
));
2866 UFCALL(PAR_HANDLE_LOAD_CELL
);
2873 const uint32_t addr
= ufoPop();
2874 const uint32_t val
= ufoPop();
2875 ufoImgPutU8Ext(addr
, val
);
2879 // ( val16 addr -- )
2881 const uint32_t addr
= ufoPop();
2882 const uint32_t val
= ufoPop();
2883 if ((addr
& UFO_ADDR_HANDLE_BIT
) == 0) {
2884 ufoImgPutU16(addr
, val
);
2889 UFCALL(PAR_HANDLE_STORE_WORD
);
2894 // ( val32 addr -- )
2896 const uint32_t addr
= ufoPop();
2897 const uint32_t val
= ufoPop();
2898 if ((addr
& UFO_ADDR_HANDLE_BIT
) == 0) {
2899 ufoImgPutU32(addr
, val
);
2904 UFCALL(PAR_HANDLE_STORE_CELL
);
2909 // ////////////////////////////////////////////////////////////////////////// //
2910 // dictionary emitters
2915 UFWORD(CCOMMA
) { const uint32_t val
= ufoPop(); ufoImgEmitU8(val
); }
2919 UFWORD(WCOMMA
) { const uint32_t val
= ufoPop(); ufoImgEmitU8(val
&0xffU
); ufoImgEmitU8((val
>> 8)&0xffU
); }
2923 UFWORD(COMMA
) { const uint32_t val
= ufoPop(); ufoImgEmitU32(val
); }
2926 // ////////////////////////////////////////////////////////////////////////// //
2933 const uint32_t v
= ufoImgGetU32(ufoIP
); ufoIP
+= 4;
2937 // (LITCFA) ( -- n )
2938 UFWORD(PAR_LITCFA
) {
2939 const uint32_t v
= ufoImgGetU32(ufoIP
); ufoIP
+= 4;
2943 // (LITVOCID) ( -- n )
2944 UFWORD(PAR_LITVOCID
) {
2945 const uint32_t v
= ufoImgGetU32(ufoIP
); ufoIP
+= 4;
2950 UFWORD(PAR_STRLIT8
) {
2951 const uint32_t count
= ufoImgGetU8(ufoIP
); ufoIP
+= 1;
2954 ufoIP
+= count
+ 1; // 1 for terminating 0
2956 ufoIP
= UFO_ALIGN4(ufoIP
);
2960 // ////////////////////////////////////////////////////////////////////////// //
2966 UFWORD(PAR_BRANCH
) {
2967 ufoIP
= ufoImgGetU32(ufoIP
);
2970 // (TBRANCH) ( flag )
2971 UFWORD(PAR_TBRANCH
) {
2973 ufoIP
= ufoImgGetU32(ufoIP
);
2979 // (0BRANCH) ( flag )
2980 UFWORD(PAR_0BRANCH
) {
2982 ufoIP
= ufoImgGetU32(ufoIP
);
2989 // ////////////////////////////////////////////////////////////////////////// //
2990 // execute words by CFA
3000 // EXECUTE-TAIL ( cfa )
3001 UFWORD(EXECUTE_TAIL
) {
3008 // ////////////////////////////////////////////////////////////////////////// //
3009 // word termination, locals support
3020 UFWORD(PAR_LENTER
) {
3021 // low byte of loccount is total number of locals
3022 // high byte is the number of args
3023 uint32_t lcount
= ufoImgGetU32(ufoIP
); ufoIP
+= 4u;
3024 uint32_t acount
= (lcount
>> 8) & 0xff;
3026 if (lcount
== 0 || lcount
< acount
) ufoFatal("invalid call to (L-ENTER)");
3027 if ((ufoLBP
!= 0 && ufoLBP
>= ufoLP
) || UFO_LSTACK_SIZE
- ufoLP
<= lcount
+ 2) {
3028 ufoFatal("out of locals stack");
3031 if (ufoLP
== 0) { ufoLP
= 1; newbp
= 1; } else newbp
= ufoLP
;
3032 //fprintf(stderr, "LP: %u; LBP: %u; locs: %u; word: %s\n", ufoLP, ufoLBP, fw->locs, fw->name);
3033 ufoLStack
[ufoLP
] = ufoLBP
; ufoLP
+= 1;
3034 ufoLBP
= newbp
; ufoLP
+= lcount
;
3037 while (newbp
!= ufoLBP
) {
3038 ufoLStack
[newbp
] = ufoPop();
3044 UFWORD(PAR_LLEAVE
) {
3045 if (ufoLBP
== 0) ufoFatal("(L-LEAVE) with empty locals stack");
3046 if (ufoLBP
>= ufoLP
) ufoFatal("(L-LEAVE) broken locals stack");
3048 ufoLBP
= ufoLStack
[ufoLBP
];
3052 //==========================================================================
3056 //==========================================================================
3057 UFO_FORCE_INLINE
void ufoLoadLocal (const uint32_t lidx
) {
3058 if (lidx
== 0 || lidx
>= UFO_LSTACK_SIZE
) ufoFatal("invalid local index");
3059 if (ufoLBP
== 0 || ufoLBP
>= ufoLP
|| ufoLP
- ufoLBP
<= lidx
) ufoFatal("invalid local index");
3060 ufoPush(ufoLStack
[ufoLBP
+ lidx
]);
3064 //==========================================================================
3068 //==========================================================================
3069 UFO_FORCE_INLINE
void ufoStoreLocal (const uint32_t lidx
) {
3070 const uint32_t value
= ufoPop();
3071 if (lidx
== 0 || lidx
>= UFO_LSTACK_SIZE
) ufoFatal("invalid local index");
3072 if (ufoLBP
== 0 || ufoLBP
>= ufoLP
|| ufoLP
- ufoLBP
<= lidx
) ufoFatal("invalid local index");
3073 ufoLStack
[ufoLBP
+ lidx
] = value
;
3079 UFWORD(PAR_LOCAL_LOAD
) { ufoLoadLocal(ufoPop()); }
3083 UFWORD(PAR_LOCAL_STORE
) { ufoStoreLocal(ufoPop()); }
3086 // ////////////////////////////////////////////////////////////////////////// //
3087 // stack manipulation
3093 UFWORD(DUP
) { ufoDup(); }
3095 // ( n -- n n ) | ( 0 -- 0 )
3096 UFWORD(QDUP
) { if (ufoPeek()) ufoDup(); }
3098 // ( n0 n1 -- n0 n1 n0 n1 )
3099 UFWORD(DDUP
) { ufo2Dup(); }
3102 UFWORD(DROP
) { ufoDrop(); }
3105 UFWORD(DDROP
) { ufo2Drop(); }
3107 // ( n0 n1 -- n1 n0 )
3108 UFWORD(SWAP
) { ufoSwap(); }
3110 // ( n0 n1 -- n1 n0 )
3111 UFWORD(DSWAP
) { ufo2Swap(); }
3113 // ( n0 n1 -- n0 n1 n0 )
3114 UFWORD(OVER
) { ufoOver(); }
3116 // ( n0 n1 -- n0 n1 n0 )
3117 UFWORD(DOVER
) { ufo2Over(); }
3119 // ( n0 n1 n2 -- n1 n2 n0 )
3120 UFWORD(ROT
) { ufoRot(); }
3122 // ( n0 n1 n2 -- n2 n0 n1 )
3123 UFWORD(NROT
) { ufoNRot(); }
3127 UFWORD(RDUP
) { ufoRDup(); }
3130 UFWORD(RDROP
) { ufoRDrop(); }
3134 UFWORD(DTOR
) { ufoRPush(ufoPop()); }
3137 UFWORD(RTOD
) { ufoPush(ufoRPop()); }
3140 UFWORD(RPEEK
) { ufoPush(ufoRPeek()); }
3146 const uint32_t n
= ufoPop();
3147 if (n
>= ufoSP
) ufoFatal("invalid PICK index %u", n
);
3148 ufoPush(ufoDStack
[ufoSP
- n
- 1u]);
3154 const uint32_t n
= ufoPop();
3155 if (n
>= ufoRP
- ufoRPTop
) ufoFatal("invalid RPICK index %u", n
);
3156 const uint32_t rp
= ufoRP
- n
- 1u;
3157 ufoPush(ufoRStack
[rp
]);
3163 const uint32_t n
= ufoPop();
3164 if (n
>= ufoSP
) ufoFatal("invalid ROLL index %u", n
);
3166 case 0: break; // do nothing
3167 case 1: ufoSwap(); break;
3168 case 2: ufoRot(); break;
3171 const uint32_t val
= ufoDStack
[ufoSP
- n
- 1u];
3172 for (uint32_t f
= ufoSP
- n
; f
< ufoSP
; f
+= 1) ufoDStack
[f
- 1] = ufoDStack
[f
];
3173 ufoDStack
[ufoSP
- 1u] = val
;
3182 const uint32_t n
= ufoPop();
3183 if (n
>= ufoRP
- ufoRPTop
) ufoFatal("invalid RROLL index %u", n
);
3185 const uint32_t rp
= ufoRP
- n
- 1u;
3186 const uint32_t val
= ufoRStack
[rp
];
3187 for (uint32_t f
= rp
+ 1u; f
< ufoRP
; f
+= 1u) ufoRStack
[f
- 1u] = ufoRStack
[f
];
3188 ufoRStack
[ufoRP
- 1u] = val
;
3193 // ( | a b -- | b a )
3195 const uint32_t b
= ufoRPop();
3196 const uint32_t a
= ufoRPop();
3197 ufoRPush(b
); ufoRPush(a
);
3201 // ( | a b -- | a b a )
3203 const uint32_t b
= ufoRPop();
3204 const uint32_t a
= ufoRPop();
3205 ufoRPush(a
); ufoRPush(b
); ufoRPush(a
);
3209 // ( | a b c -- | b c a )
3211 const uint32_t c
= ufoRPop();
3212 const uint32_t b
= ufoRPop();
3213 const uint32_t a
= ufoRPop();
3214 ufoRPush(b
); ufoRPush(c
); ufoRPush(a
);
3218 // ( | a b c -- | c a b )
3220 const uint32_t c
= ufoRPop();
3221 const uint32_t b
= ufoRPop();
3222 const uint32_t a
= ufoRPop();
3223 ufoRPush(c
); ufoRPush(a
); ufoRPush(b
);
3227 // ////////////////////////////////////////////////////////////////////////// //
3234 ufoPushBool(ufoLoadNextLine(1));
3239 UFWORD(REFILL_NOCROSS
) {
3240 ufoPushBool(ufoLoadNextLine(0));
3246 ufoPush(ufoImgGetU32(ufoAddrTIBx
) + ufoImgGetU32(ufoAddrINx
));
3251 UFWORD(TIB_PEEKCH
) {
3252 ufoPush(ufoTibPeekCh());
3257 UFWORD(TIB_PEEKCH_OFS
) {
3258 const uint32_t ofs
= ufoPop();
3259 ufoPush(ufoTibPeekChOfs(ofs
));
3265 ufoPush(ufoTibGetCh());
3270 UFWORD(TIB_SKIPCH
) {
3275 // ////////////////////////////////////////////////////////////////////////// //
3279 //==========================================================================
3283 //==========================================================================
3284 UFO_FORCE_INLINE
int ufoIsDelim (uint8_t ch
, uint8_t delim
) {
3285 return (delim
== 32 ? (ch
<= 32) : (ch
== delim
));
3290 // ( delim skip-leading-delim? -- addr count TRUE / FALSE )
3291 // does base TIB parsing; never copies anything.
3292 // as our reader is line-based, returns FALSE on EOL.
3293 // EOL is detected after skipping leading delimiters.
3294 // passing -1 as delimiter skips the whole line, and always returns FALSE.
3295 // trailing delimiter is always skipped.
3297 const uint32_t skipDelim
= ufoPop();
3298 const uint32_t delim
= ufoPop();
3301 if (delim
== 0 || delim
> 0xffU
) {
3303 while (ufoTibGetCh() != 0) {}
3306 ch
= ufoTibPeekCh();
3307 // skip initial delimiters
3309 while (ch
!= 0 && ufoIsDelim(ch
, delim
)) {
3311 ch
= ufoTibPeekCh();
3318 const uint32_t staddr
= ufoImgGetU32(ufoAddrTIBx
) + ufoImgGetU32(ufoAddrINx
);
3320 while (ch
!= 0 && !ufoIsDelim(ch
, delim
)) {
3323 ch
= ufoTibPeekCh();
3326 if (ch
!= 0) ufoTibSkipCh();
3334 // PARSE-SKIP-BLANKS
3336 UFWORD(PARSE_SKIP_BLANKS
) {
3337 uint8_t ch
= ufoTibPeekCh();
3338 while (ch
!= 0 && ch
<= 32) {
3340 ch
= ufoTibPeekCh();
3345 //==========================================================================
3347 // ufoParseMLComment
3349 // initial two chars are skipped
3351 //==========================================================================
3352 static void ufoParseMLComment (uint32_t allowMulti
, int nested
) {
3355 while (level
!= 0) {
3359 UFCALL(REFILL_NOCROSS
);
3360 if (ufoPop() == 0) ufoFatal("unexpected end of file in comment");
3362 ufoFatal("unexpected end of line in comment");
3365 ch1
= ufoTibPeekCh();
3366 if (nested
&& ch
== '(' && ch1
== '(') { ufoTibSkipCh(); level
+= 1; }
3367 else if (nested
&& ch
== ')' && ch1
== ')') { ufoTibSkipCh(); level
-= 1; }
3368 else if (!nested
&& ch
== '*' && ch1
== ')') { ufo_assert(level
== 1); ufoTibSkipCh(); level
= 0; }
3374 // (PARSE-SKIP-COMMENTS)
3375 // ( allow-multiline? -- )
3376 // skip all blanks and comments
3377 UFWORD(PAR_PARSE_SKIP_COMMENTS
) {
3378 const uint32_t allowMulti
= ufoPop();
3380 ch
= ufoTibPeekCh();
3382 fprintf(stderr
, "(PARSE-SKIP-COMMENTS): first-ch:'%c'\n", (char)ch
);
3387 ch
= ufoTibPeekCh();
3389 fprintf(stderr
, "(PARSE-SKIP-COMMENTS): blank-ch:'%c'\n", (char)ch
);
3391 } else if (ch
== '(') {
3393 fprintf(stderr
, "(PARSE-SKIP-COMMENTS): ch:'%c'; ch1:'%c' ('%c')\n", (char)ch
, (char)ch1
,
3394 ufoTibPeekChOfs(0));
3396 ch1
= ufoTibPeekChOfs(1);
3398 // single-line comment
3399 do { ch
= ufoTibGetCh(); } while (ch
!= 0 && ch
!= ')');
3400 ch
= ufoTibPeekCh();
3401 } else if (ch1
== '*' || ch1
== '(') {
3402 // possibly multiline
3403 ufoTibSkipCh(); ufoTibSkipCh(); // skip opening
3404 ufoParseMLComment(allowMulti
, (ch1
== '('));
3405 ch
= ufoTibPeekCh();
3409 } else if (ch
== '\\' && ufoTibPeekChOfs(1) <= 32) {
3410 // single-line comment
3411 while (ch
!= 0) ch
= ufoTibGetCh();
3412 } else if ((ch
== ';' || ch
== '-' || ch
== '/') && (ufoTibPeekChOfs(1) == ch
)) {
3414 while (ch
!= 0) ch
= ufoTibGetCh();
3420 fprintf(stderr
, "(PARSE-SKIP-COMMENTS): end-ch:'%c'\n", ufoTibPeekCh());
3426 UFWORD(PARSE_SKIP_LINE
) {
3427 ufoPush(0); ufoPushBool(0); UFCALL(PAR_PARSE
);
3428 if (ufoPop() != 0) {
3434 // ( -- addr count )
3435 // parse with leading blanks skipping. doesn't copy anything.
3436 // return empty string on EOL.
3437 UFWORD(PARSE_NAME
) {
3438 ufoPush(32); ufoPushBool(1); UFCALL(PAR_PARSE
);
3439 if (ufoPop() == 0) {
3446 // ( delim -- addr count TRUE / FALSE )
3447 // parse without skipping delimiters; never copies anything.
3448 // as our reader is line-based, returns FALSE on EOL.
3449 // passing 0 as delimiter skips the whole line, and always returns FALSE.
3450 // trailing delimiter is always skipped.
3452 ufoPushBool(0); UFCALL(PAR_PARSE
);
3456 // ////////////////////////////////////////////////////////////////////////// //
3462 UFWORD(PAR_NORM_EMIT_CHAR
) {
3463 uint32_t ch
= ufoPop()&0xffU
;
3464 if (ch
< 32 || ch
== 127) {
3465 if (ch
!= 9 && ch
!= 10 && ch
!= 13) ch
= '?';
3470 // (NORM-XEMIT-CHAR)
3472 UFWORD(PAR_NORM_XEMIT_CHAR
) {
3473 uint32_t ch
= ufoPop()&0xffU
;
3474 if (ch
< 32 || ch
== 127) ch
= '?';
3481 uint32_t ch
= ufoPop()&0xffU
;
3482 ufoLastEmitWasCR
= (ch
== 10);
3489 ufoPushBool(ufoLastEmitWasCR
);
3495 ufoLastEmitWasCR
= !!ufoPop();
3500 UFWORD(FLUSH_EMIT
) {
3505 // ////////////////////////////////////////////////////////////////////////// //
3509 #define UF_UMATH(name_,op_) \
3511 const uint32_t a = ufoPop(); \
3515 #define UF_BMATH(name_,op_) \
3517 const uint32_t b = ufoPop(); \
3518 const uint32_t a = ufoPop(); \
3522 #define UF_BDIV(name_,op_) \
3524 const uint32_t b = ufoPop(); \
3525 const uint32_t a = ufoPop(); \
3526 if (b == 0) ufoFatal("division by zero"); \
3530 #define UFO_POP_U64() ({ \
3531 const uint32_t hi_ = ufoPop(); \
3532 const uint32_t lo_ = ufoPop(); \
3533 (((uint64_t)hi_ << 32) | lo_); \
3536 // this is UB by the idiotic C standard. i don't care.
3537 #define UFO_POP_I64() ((int64_t)UFO_POP_U64())
3539 #define UFO_PUSH_U64(vn_) do { \
3540 ufoPush((uint32_t)(vn_)); \
3541 ufoPush((uint32_t)((vn_) >> 32)); \
3544 // this is UB by the idiotic C standard. i don't care.
3545 #define UFO_PUSH_I64(vn_) UFO_PUSH_U64((uint64_t)(vn_))
3550 UF_BMATH(PLUS
, a
+ b
);
3554 UF_BMATH(MINUS
, a
- b
);
3558 UF_BMATH(MUL
, (uint32_t)((int32_t)a
* (int32_t)b
));
3562 UF_BMATH(UMUL
, a
* b
);
3566 UF_BDIV(DIV
, (uint32_t)((int32_t)a
/ (int32_t)b
));
3570 UF_BDIV(UDIV
, a
/ b
);
3574 UF_BDIV(MOD
, (uint32_t)((int32_t)a
% (int32_t)b
));
3578 UF_BDIV(UMOD
, a
% b
);
3581 // ( a b -- a/b, a%b )
3583 const int32_t b
= (int32_t)ufoPop();
3584 const int32_t a
= (int32_t)ufoPop();
3585 if (b
== 0) ufoFatal("division by zero");
3586 ufoPush((uint32_t)(a
/b
));
3587 ufoPush((uint32_t)(a
%b
));
3591 // ( a b -- a/b, a%b )
3593 const uint32_t b
= ufoPop();
3594 const uint32_t a
= ufoPop();
3595 if (b
== 0) ufoFatal("division by zero");
3596 ufoPush((uint32_t)(a
/b
));
3597 ufoPush((uint32_t)(a
%b
));
3601 // ( a b c -- a*b/c )
3602 // this uses 64-bit intermediate value
3604 const int32_t c
= (int32_t)ufoPop();
3605 const int32_t b
= (int32_t)ufoPop();
3606 const int32_t a
= (int32_t)ufoPop();
3607 if (c
== 0) ufoFatal("division by zero");
3608 int64_t xval
= a
; xval
*= b
; xval
/= c
;
3609 ufoPush((uint32_t)(int32_t)xval
);
3613 // ( a b c -- a*b/c )
3614 // this uses 64-bit intermediate value
3616 const uint32_t c
= ufoPop();
3617 const uint32_t b
= ufoPop();
3618 const uint32_t a
= ufoPop();
3619 if (c
== 0) ufoFatal("division by zero");
3620 uint64_t xval
= a
; xval
*= b
; xval
/= c
;
3621 ufoPush((uint32_t)xval
);
3625 // ( a b c -- a*b/c a*b%c )
3626 // this uses 64-bit intermediate value
3628 const int32_t c
= (int32_t)ufoPop();
3629 const int32_t b
= (int32_t)ufoPop();
3630 const int32_t a
= (int32_t)ufoPop();
3631 if (c
== 0) ufoFatal("division by zero");
3632 int64_t xval
= a
; xval
*= b
;
3633 ufoPush((uint32_t)(int32_t)(xval
/ c
));
3634 ufoPush((uint32_t)(int32_t)(xval
% c
));
3638 // ( a b c -- a*b/c )
3639 // this uses 64-bit intermediate value
3640 UFWORD(UMULDIVMOD
) {
3641 const uint32_t c
= ufoPop();
3642 const uint32_t b
= ufoPop();
3643 const uint32_t a
= ufoPop();
3644 if (c
== 0) ufoFatal("division by zero");
3645 uint64_t xval
= a
; xval
*= b
;
3646 ufoPush((uint32_t)(xval
/ c
));
3647 ufoPush((uint32_t)(xval
% c
));
3651 // ( a b -- lo(a*b) hi(a*b) )
3652 // this leaves 64-bit result
3654 const int32_t b
= (int32_t)ufoPop();
3655 const int32_t a
= (int32_t)ufoPop();
3656 int64_t xval
= a
; xval
*= b
;
3661 // ( a b -- lo(a*b) hi(a*b) )
3662 // this leaves 64-bit result
3664 const uint32_t b
= ufoPop();
3665 const uint32_t a
= ufoPop();
3666 uint64_t xval
= a
; xval
*= b
;
3671 // ( alo ahi b -- a/b a%b )
3673 const int32_t b
= (int32_t)ufoPop();
3674 if (b
== 0) ufoFatal("division by zero");
3675 int64_t a
= UFO_POP_I64();
3676 int32_t adiv
= (int32_t)(a
/ b
);
3677 int32_t amod
= (int32_t)(a
% b
);
3678 ufoPush((uint32_t)adiv
);
3679 ufoPush((uint32_t)amod
);
3683 // ( alo ahi b -- a/b a%b )
3685 const uint32_t b
= ufoPop();
3686 if (b
== 0) ufoFatal("division by zero");
3687 uint64_t a
= UFO_POP_U64();
3688 uint32_t adiv
= (uint32_t)(a
/ b
);
3689 uint32_t amod
= (uint32_t)(a
% b
);
3695 // ( alo ahi u -- lo hi )
3697 const uint32_t b
= ufoPop();
3698 uint64_t a
= UFO_POP_U64();
3704 // ( lo0 hi0 lo1 hi1 -- lo hi )
3706 uint64_t n1
= UFO_POP_U64();
3707 uint64_t n0
= UFO_POP_U64();
3713 // ( lo0 hi0 lo1 hi1 -- lo hi )
3715 uint64_t n1
= UFO_POP_U64();
3716 uint64_t n0
= UFO_POP_U64();
3722 // ( lo0 hi0 lo1 hi1 -- bool )
3724 uint64_t n1
= UFO_POP_U64();
3725 uint64_t n0
= UFO_POP_U64();
3726 ufoPushBool(n0
== n1
);
3730 // ( lo0 hi0 lo1 hi1 -- bool )
3732 int64_t n1
= UFO_POP_I64();
3733 int64_t n0
= UFO_POP_I64();
3734 ufoPushBool(n0
< n1
);
3738 // ( lo0 hi0 lo1 hi1 -- bool )
3740 int64_t n1
= UFO_POP_I64();
3741 int64_t n0
= UFO_POP_I64();
3742 ufoPushBool(n0
<= n1
);
3746 // ( lo0 hi0 lo1 hi1 -- bool )
3748 uint64_t n1
= UFO_POP_U64();
3749 uint64_t n0
= UFO_POP_U64();
3750 ufoPushBool(n0
< n1
);
3754 // ( lo0 hi0 lo1 hi1 -- bool )
3756 uint64_t n1
= UFO_POP_U64();
3757 uint64_t n0
= UFO_POP_U64();
3758 ufoPushBool(n0
<= n1
);
3762 // ( dlo dhi n -- nmod ndiv )
3763 // rounds toward zero
3765 const int32_t n
= (int32_t)ufoPop();
3766 if (n
== 0) ufoFatal("division by zero");
3767 int64_t d
= UFO_POP_I64();
3768 int32_t ndiv
= (int32_t)(d
/ n
);
3769 int32_t nmod
= (int32_t)(d
% n
);
3775 // ( dlo dhi n -- nmod ndiv )
3776 // rounds toward negative infinity
3778 const int32_t n
= (int32_t)ufoPop();
3779 if (n
== 0) ufoFatal("division by zero");
3780 int64_t d
= UFO_POP_I64();
3781 int32_t ndiv
= (int32_t)(d
/ n
);
3782 int32_t nmod
= (int32_t)(d
% n
);
3783 if (nmod
!= 0 && ((uint32_t)n
^ (uint32_t)(d
>> 32)) >= 0x80000000u
) {
3792 // ////////////////////////////////////////////////////////////////////////// //
3793 // simple logic and bit manipulation
3796 #define UF_CMP(name_,op_) \
3798 const uint32_t b = ufoPop(); \
3799 const uint32_t a = ufoPop(); \
3805 UF_CMP(LESS
, (int32_t)a
< (int32_t)b
);
3809 UF_CMP(ULESS
, a
< b
);
3813 UF_CMP(GREAT
, (int32_t)a
> (int32_t)b
);
3817 UF_CMP(UGREAT
, a
> b
);
3821 UF_CMP(LESSEQU
, (int32_t)a
<= (int32_t)b
);
3825 UF_CMP(ULESSEQU
, a
<= b
);
3829 UF_CMP(GREATEQU
, (int32_t)a
>= (int32_t)b
);
3833 UF_CMP(UGREATEQU
, a
>= b
);
3837 UF_CMP(EQU
, a
== b
);
3841 UF_CMP(NOTEQU
, a
!= b
);
3846 const uint32_t a
= ufoPop();
3852 UF_CMP(LOGAND
, a
&& b
);
3856 UF_CMP(LOGOR
, a
|| b
);
3861 const uint32_t b
= ufoPop();
3862 const uint32_t a
= ufoPop();
3869 const uint32_t b
= ufoPop();
3870 const uint32_t a
= ufoPop();
3877 const uint32_t b
= ufoPop();
3878 const uint32_t a
= ufoPop();
3885 const uint32_t a
= ufoPop();
3889 UFWORD(ONESHL
) { uint32_t n
= ufoPop(); ufoPush(n
<< 1); }
3890 UFWORD(ONESHR
) { uint32_t n
= ufoPop(); ufoPush(n
>> 1); }
3891 UFWORD(TWOSHL
) { uint32_t n
= ufoPop(); ufoPush(n
<< 2); }
3892 UFWORD(TWOSHR
) { uint32_t n
= ufoPop(); ufoPush(n
>> 2); }
3896 // arithmetic shift; positive `n` shifts to the left
3898 int32_t c
= (int32_t)ufoPop();
3901 int32_t n
= (int32_t)ufoPop();
3903 if (n
< 0) n
= -1; else n
= 0;
3905 n
>>= (uint8_t)(-c
);
3907 ufoPush((uint32_t)n
);
3910 uint32_t u
= ufoPop();
3922 // logical shift; positive `n` shifts to the left
3924 int32_t c
= (int32_t) ufoPop();
3925 uint32_t u
= ufoPop();
3931 u
>>= (uint8_t)(-c
);
3945 // ////////////////////////////////////////////////////////////////////////// //
3946 // string unescaping
3950 // ( addr count -- addr count )
3951 UFWORD(PAR_UNESCAPE
) {
3952 const uint32_t count
= ufoPop();
3953 const uint32_t addr
= ufoPeek();
3954 if ((count
& ((uint32_t)1<<31)) == 0) {
3955 const uint32_t eaddr
= addr
+ count
;
3956 uint32_t caddr
= addr
;
3957 uint32_t daddr
= addr
;
3958 while (caddr
!= eaddr
) {
3959 uint8_t ch
= ufoImgGetU8Ext(caddr
); caddr
+= 1u;
3960 if (ch
== '\\' && caddr
!= eaddr
) {
3961 ch
= ufoImgGetU8Ext(caddr
); caddr
+= 1u;
3963 case 'r': ch
= '\r'; break;
3964 case 'n': ch
= '\n'; break;
3965 case 't': ch
= '\t'; break;
3966 case 'e': ch
= '\x1b'; break;
3967 case '`': ch
= '"'; break; // special escape to insert double-quote
3968 case '"': ch
= '"'; break;
3969 case '\\': ch
= '\\'; break;
3971 if (eaddr
- daddr
>= 1) {
3972 const int dg0
= digitInBase((char)(ufoImgGetU8Ext(caddr
)), 16);
3973 if (dg0
< 0) ufoFatal("invalid hex string escape");
3974 if (eaddr
- daddr
>= 2) {
3975 const int dg1
= digitInBase((char)(ufoImgGetU8Ext(caddr
+ 1u)), 16);
3976 if (dg1
< 0) ufoFatal("invalid hex string escape");
3977 ch
= (uint8_t)(dg0
* 16 + dg1
);
3984 ufoFatal("invalid hex string escape");
3987 default: ufoFatal("invalid string escape");
3990 ufoImgPutU8Ext(daddr
, ch
); daddr
+= 1u;
3992 ufoPush(daddr
- addr
);
3999 // ////////////////////////////////////////////////////////////////////////// //
4000 // numeric conversions
4003 // (BASED-NUMBER) ( addr count allowsign? base -- num TRUE / FALSE )
4004 UFWORD(PAR_BASED_NUMBER
) {
4005 const uint32_t xbase
= ufoPop();
4006 const uint32_t allowSign
= ufoPop();
4007 int32_t count
= (int32_t)ufoPop();
4008 uint32_t addr
= ufoPop();
4014 if (allowSign
&& count
> 1) {
4015 ch
= ufoImgGetU8Ext(addr
);
4016 if (ch
== '-') { neg
= 1; addr
+= 1u; count
-= 1; }
4017 else if (ch
== '+') { neg
= 0; addr
+= 1u; count
-= 1; }
4020 // special-based numbers
4021 if (count
>= 3 && ufoImgGetU8Ext(addr
) == '0') {
4022 switch (ufoImgGetU8Ext(addr
+ 1u)) {
4023 case 'x': case 'X': base
= 16; break;
4024 case 'o': case 'O': base
= 8; break;
4025 case 'b': case 'B': base
= 2; break;
4026 case 'd': case 'D': base
= 10; break;
4029 if (base
) { addr
+= 2; count
-= 2; }
4030 } else if (count
>= 2 && ufoImgGetU8Ext(addr
) == '$') {
4032 addr
+= 1; count
-= 1;
4033 } else if (count
>= 2 && ufoImgGetU8Ext(addr
) == '#') {
4035 addr
+= 1; count
-= 1;
4036 } else if (count
>= 2 && ufoImgGetU8Ext(addr
) == '%') {
4038 addr
+= 1; count
-= 1;
4039 } else if (count
>= 3 && ufoImgGetU8Ext(addr
) == '&') {
4040 switch (ufoImgGetU8Ext(addr
+ 1u)) {
4041 case 'h': case 'H': base
= 16; break;
4042 case 'o': case 'O': base
= 8; break;
4043 case 'b': case 'B': base
= 2; break;
4044 case 'd': case 'D': base
= 10; break;
4047 if (base
) { addr
+= 2; count
-= 2; }
4048 } else if (xbase
< 12 && count
> 2 && toUpperU8(ufoImgGetU8Ext(addr
+ (uint32_t)count
- 1u)) == 'B') {
4051 } else if (xbase
< 18 && count
> 2 && toUpperU8(ufoImgGetU8Ext(addr
+ (uint32_t)count
- 1u)) == 'H') {
4054 } else if (xbase
< 25 && count
> 2 && toUpperU8(ufoImgGetU8Ext(addr
+ (uint32_t)count
- 1u)) == 'O') {
4060 if (!base
&& xbase
< 255) base
= xbase
;
4062 if (count
<= 0 || base
< 1 || base
> 36) {
4066 int wasDig
= 0, wasUnder
= 1, error
= 0, dig
;
4067 while (!error
&& count
!= 0) {
4068 ch
= ufoImgGetU8Ext(addr
); addr
+= 1u; count
-= 1;
4070 error
= 1; wasUnder
= 0; wasDig
= 1;
4071 dig
= digitInBase((char)ch
, (int)base
);
4073 nc
= n
* (uint32_t)base
;
4075 nc
+= (uint32_t)dig
;
4088 if (!error
&& wasDig
&& !wasUnder
) {
4089 if (allowSign
&& neg
) n
= ~n
+ 1u;
4099 // ////////////////////////////////////////////////////////////////////////// //
4100 // compiler-related, dictionary-related
4103 static char ufoWNameBuf
[256];
4107 UFWORD(LBRACKET_IMM
) {
4108 if (ufoImgGetU32(ufoAddrSTATE
) == 0) ufoFatal("expects compiling mode");
4109 ufoImgPutU32(ufoAddrSTATE
, 0);
4114 if (ufoImgGetU32(ufoAddrSTATE
) != 0) ufoFatal("expects interpreting mode");
4115 ufoImgPutU32(ufoAddrSTATE
, 1);
4118 // (CREATE-WORD-HEADER)
4119 // ( addr count word-flags -- )
4120 UFWORD(PAR_CREATE_WORD_HEADER
) {
4121 const uint32_t flags
= ufoPop();
4122 const uint32_t wlen
= ufoPop();
4123 const uint32_t waddr
= ufoPop();
4124 if (wlen
== 0) ufoFatal("word name expected");
4125 if (wlen
>= UFO_MAX_WORD_LENGTH
) ufoFatal("word name too long");
4126 // copy to separate buffer
4127 for (uint32_t f
= 0; f
< wlen
; f
+= 1) {
4128 ufoWNameBuf
[f
] = (char)ufoImgGetU8Ext(waddr
+ f
);
4130 ufoWNameBuf
[wlen
] = 0;
4131 ufoCreateWordHeader(ufoWNameBuf
, flags
);
4134 // (CREATE-NAMELESS-WORD-HEADER)
4135 // ( word-flags -- )
4136 UFWORD(PAR_CREATE_NAMELESS_WORD_HEADER
) {
4137 const uint32_t flags
= ufoPop();
4138 ufoCreateWordHeader("", flags
);
4142 // ( addr count -- cfa TRUE / FALSE)
4144 const uint32_t wlen
= ufoPop();
4145 const uint32_t waddr
= ufoPop();
4146 if (wlen
> 0 && wlen
< UFO_MAX_WORD_LENGTH
) {
4147 // copy to separate buffer
4148 for (uint32_t f
= 0; f
< wlen
; f
+= 1) {
4149 ufoWNameBuf
[f
] = (char)ufoImgGetU8Ext(waddr
+ f
);
4151 ufoWNameBuf
[wlen
] = 0;
4152 const uint32_t cfa
= ufoFindWord(ufoWNameBuf
);
4164 // (FIND-WORD-IN-VOC)
4165 // ( addr count vocid allowhidden -- cfa TRUE / FALSE)
4166 // find only in the given voc; no name resolution
4167 UFWORD(FIND_WORD_IN_VOC
) {
4168 const uint32_t allowHidden
= ufoPop();
4169 const uint32_t vocid
= ufoPop();
4170 const uint32_t wlen
= ufoPop();
4171 const uint32_t waddr
= ufoPop();
4172 if (wlen
> 0 && wlen
< UFO_MAX_WORD_LENGTH
) {
4173 // copy to separate buffer
4174 for (uint32_t f
= 0; f
< wlen
; f
+= 1) {
4175 ufoWNameBuf
[f
] = (char)ufoImgGetU8Ext(waddr
+ f
);
4177 ufoWNameBuf
[wlen
] = 0;
4178 const uint32_t cfa
= ufoFindWordInVoc(ufoWNameBuf
, wlen
, 0, vocid
, (allowHidden
? 1 : 0));
4190 // (FIND-WORD-IN-VOC-AND-PARENTS)
4191 // ( addr count vocid allowhidden -- cfa TRUE / FALSE)
4192 // find only in the given voc; no name resolution
4193 UFWORD(FIND_WORD_IN_VOC_AND_PARENTS
) {
4194 const uint32_t allowHidden
= ufoPop();
4195 const uint32_t vocid
= ufoPop();
4196 const uint32_t wlen
= ufoPop();
4197 const uint32_t waddr
= ufoPop();
4198 if (wlen
> 0 && wlen
< UFO_MAX_WORD_LENGTH
) {
4199 // copy to separate buffer
4200 for (uint32_t f
= 0; f
< wlen
; f
+= 1) {
4201 ufoWNameBuf
[f
] = (char)ufoImgGetU8Ext(waddr
+ f
);
4203 ufoWNameBuf
[wlen
] = 0;
4204 const uint32_t cfa
= ufoFindWordInVocAndParents(ufoWNameBuf
, wlen
, 0, vocid
, (allowHidden
? 1 : 0));
4217 // ////////////////////////////////////////////////////////////////////////// //
4218 // more compiler words
4223 if (ufoImgGetU32(ufoAddrSTATE
) != 0) ufoFatal("expecting execution mode");
4228 if (ufoImgGetU32(ufoAddrSTATE
) == 0) ufoFatal("expecting compilation mode");
4234 ufoPush(34); UFCALL(PARSE
);
4235 if (ufoPop() == 0) ufoFatal("string literal expected");
4236 UFCALL(PAR_UNESCAPE
);
4237 if (ufoImgGetU32(ufoAddrSTATE
) != 0) {
4239 const uint32_t wlen
= ufoPop();
4240 const uint32_t waddr
= ufoPop();
4241 if (wlen
> 255) ufoFatal("string literal too long");
4242 ufoImgEmitU32(ufoStrLit8CFA
);
4244 for (uint32_t f
= 0; f
< wlen
; f
+= 1) {
4245 ufoImgEmitU8(ufoImgGetU8Ext(waddr
+ f
));
4253 // ////////////////////////////////////////////////////////////////////////// //
4254 // vocabulary and wordlist utilities
4259 UFWORD(PAR_GET_VSP
) {
4265 UFWORD(PAR_SET_VSP
) {
4266 const uint32_t vsp
= ufoPop();
4267 if (vsp
>= UFO_VOCSTACK_SIZE
) ufoFatal("VSP %u out of range (%u)", vsp
, UFO_VOCSTACK_SIZE
);
4273 UFWORD(PAR_VSP_LOAD
) {
4274 const uint32_t vsp
= ufoPop();
4275 if (vsp
>= UFO_VOCSTACK_SIZE
) ufoFatal("VSP %u out of range (%u)", vsp
, UFO_VOCSTACK_SIZE
);
4276 ufoPush(ufoVocStack
[vsp
]);
4281 UFWORD(PAR_VSP_STORE
) {
4282 const uint32_t vsp
= ufoPop();
4283 const uint32_t value
= ufoPop();
4284 if (vsp
> UFO_VOCSTACK_SIZE
) ufoFatal("VSP %u out of range (%u)", vsp
, UFO_VOCSTACK_SIZE
);
4285 ufoVocStack
[vsp
] = value
;
4289 // ////////////////////////////////////////////////////////////////////////// //
4290 // word field address conversion
4296 const uint32_t cfa
= ufoPop();
4297 ufoPush(UFO_CFA_TO_PFA(cfa
));
4303 const uint32_t pfa
= ufoPop();
4304 ufoPush(UFO_PFA_TO_CFA(pfa
));
4310 const uint32_t cfa
= ufoPop();
4311 ufoPush(UFO_CFA_TO_NFA(cfa
));
4317 const uint32_t nfa
= ufoPop();
4318 ufoPush(UFO_NFA_TO_CFA(nfa
));
4324 const uint32_t cfa
= ufoPop();
4325 ufoPush(UFO_CFA_TO_LFA(cfa
));
4331 const uint32_t lfa
= ufoPop();
4332 ufoPush(UFO_LFA_TO_CFA(lfa
));
4338 const uint32_t lfa
= ufoPop();
4339 const uint32_t cfa
= UFO_LFA_TO_CFA(lfa
);
4340 ufoPush(UFO_CFA_TO_PFA(cfa
));
4346 const uint32_t lfa
= ufoPop();
4347 ufoPush(UFO_LFA_TO_BFA(lfa
));
4353 const uint32_t lfa
= ufoPop();
4354 ufoPush(UFO_LFA_TO_XFA(lfa
));
4360 const uint32_t lfa
= ufoPop();
4361 ufoPush(UFO_LFA_TO_YFA(lfa
));
4367 const uint32_t lfa
= ufoPop();
4368 ufoPush(UFO_LFA_TO_NFA(lfa
));
4374 const uint32_t nfa
= ufoPop();
4375 ufoPush(UFO_NFA_TO_LFA(nfa
));
4379 // ( cfa -- wend-addr )
4381 const uint32_t cfa
= ufoPop();
4382 ufoPush(ufoGetWordEndAddr(cfa
));
4386 // ( ip -- nfa / 0 )
4388 const uint32_t ip
= ufoPop();
4389 ufoPush(ufoFindWordForIP(ip
));
4393 // ( ip -- addr count line TRUE / FALSE )
4394 // name is at PAD; it is safe to use PAD, because each task has its own temp image
4395 UFWORD(IP2FILELINE
) {
4396 const uint32_t ip
= ufoPop();
4398 const char *fname
= ufoFindFileForIP(ip
, &fline
);
4399 if (fname
!= NULL
) {
4401 const uint32_t addr
= ufoPeek();
4403 while (*fname
!= 0) {
4404 ufoImgPutU8(addr
+ count
, *(const unsigned char *)fname
);
4405 fname
+= 1u; count
+= 1u;
4407 ufoImgPutU8(addr
+ count
, 0); // just in case
4417 // ////////////////////////////////////////////////////////////////////////// //
4418 // string operations
4421 UFO_FORCE_INLINE
uint32_t ufoHashBuf (uint32_t addr
, uint32_t size
, uint8_t orbyte
) {
4422 uint32_t hash
= 0x29a;
4423 if ((size
& ((uint32_t)1<<31)) == 0) {
4425 hash
+= ufoImgGetU8Ext(addr
) | orbyte
;
4428 addr
+= 1u; size
-= 1u;
4438 //==========================================================================
4442 //==========================================================================
4443 UFO_FORCE_INLINE
int ufoBufEqu (uint32_t addr0
, uint32_t addr1
, uint32_t count
) {
4445 if ((count
& ((uint32_t)1<<31)) == 0) {
4447 while (res
!= 0 && count
!= 0) {
4448 res
= (toUpperU8(ufoImgGetU8Ext(addr0
)) == toUpperU8(ufoImgGetU8Ext(addr1
)));
4449 addr0
+= 1u; addr1
+= 1u; count
-= 1u;
4458 // ( a0 c0 a1 c1 -- bool )
4460 int32_t c1
= (int32_t)ufoPop();
4461 uint32_t a1
= ufoPop();
4462 int32_t c0
= (int32_t)ufoPop();
4463 uint32_t a0
= ufoPop();
4468 while (res
!= 0 && c0
!= 0) {
4469 res
= (ufoImgGetU8Ext(a0
) == ufoImgGetU8Ext(a1
));
4470 a0
+= 1; a1
+= 1; c0
-= 1;
4479 // ( a0 c0 a1 c1 -- bool )
4481 int32_t c1
= (int32_t)ufoPop();
4482 uint32_t a1
= ufoPop();
4483 int32_t c0
= (int32_t)ufoPop();
4484 uint32_t a0
= ufoPop();
4489 while (res
!= 0 && c0
!= 0) {
4490 res
= (toUpperU8(ufoImgGetU8Ext(a0
)) == toUpperU8(ufoImgGetU8Ext(a1
)));
4491 a0
+= 1; a1
+= 1; c0
-= 1;
4499 // search the string specified by c-addr1 u1 for the string specified by c-addr2 u2.
4500 // if flag is true, a match was found at c-addr3 with u3 characters remaining.
4501 // if flag is false there was no match and c-addr3 is c-addr1 and u3 is u1.
4502 // ( c-addr1 u1 c-addr2 u2 -- c-addr3 u3 flag )
4504 const uint32_t pcount
= ufoPop();
4505 const uint32_t paddr
= ufoPop();
4506 const uint32_t tcount
= ufoPop();
4507 const uint32_t taddr
= ufoPop();
4508 if ((pcount
& ((uint32_t)1 << 31)) == 0 && (tcount
& ((uint32_t)1 << 31)) == 0) {
4509 for (uint32_t f
= 0; tcount
- f
>= pcount
; f
+= 1) {
4510 if (ufoBufEqu(taddr
+ f
, paddr
, pcount
)) {
4512 ufoPush(tcount
- f
);
4524 // ( addr count -- hash )
4526 uint32_t count
= ufoPop();
4527 uint32_t addr
= ufoPop();
4528 ufoPush(ufoHashBuf(addr
, count
, 0));
4532 // ( addr count -- hash )
4534 uint32_t count
= ufoPop();
4535 uint32_t addr
= ufoPop();
4536 ufoPush(ufoHashBuf(addr
, count
, 0x20));
4540 // ////////////////////////////////////////////////////////////////////////// //
4541 // conditional defines
4544 typedef struct UForthCondDefine_t UForthCondDefine
;
4545 struct UForthCondDefine_t
{
4549 UForthCondDefine
*next
;
4552 static UForthCondDefine
*ufoCondDefines
= NULL
;
4553 static char ufoErrMsgBuf
[4096];
4556 //==========================================================================
4560 //==========================================================================
4561 UFO_DISABLE_INLINE
int ufoStrEquCI (const void *str0
, const void *str1
) {
4562 const unsigned char *s0
= (const unsigned char *)str0
;
4563 const unsigned char *s1
= (const unsigned char *)str1
;
4564 while (*s0
&& *s1
) {
4565 if (toUpperU8(*s0
) != toUpperU8(*s1
)) return 0;
4568 return (*s0
== 0 && *s1
== 0);
4572 //==========================================================================
4576 //==========================================================================
4577 UFO_FORCE_INLINE
int ufoBufEquCI (uint32_t addr
, uint32_t count
, const void *buf
) {
4579 if ((count
& ((uint32_t)1<<31)) == 0) {
4580 const unsigned char *src
= (const unsigned char *)buf
;
4582 while (res
!= 0 && count
!= 0) {
4583 res
= (toUpperU8(*src
) == toUpperU8(ufoImgGetU8Ext(addr
)));
4584 src
+= 1; addr
+= 1u; count
-= 1u;
4593 //==========================================================================
4595 // ufoClearCondDefines
4597 //==========================================================================
4598 static void ufoClearCondDefines (void) {
4599 while (ufoCondDefines
) {
4600 UForthCondDefine
*df
= ufoCondDefines
;
4601 ufoCondDefines
= df
->next
;
4602 if (df
->name
) free(df
->name
);
4608 //==========================================================================
4612 //==========================================================================
4613 int ufoHasCondDefine (const char *name
) {
4615 if (name
!= NULL
&& name
[0] != 0) {
4616 const size_t nlen
= strlen(name
);
4618 const uint32_t hash
= joaatHashBufCI(name
, nlen
);
4619 UForthCondDefine
*dd
= ufoCondDefines
;
4620 while (res
== 0 && dd
!= NULL
) {
4621 if (dd
->hash
== hash
&& dd
->namelen
== (uint32_t)nlen
) {
4622 res
= ufoStrEquCI(name
, dd
->name
);
4632 //==========================================================================
4636 //==========================================================================
4637 void ufoCondDefine (const char *name
) {
4638 if (name
!= NULL
&& name
[0] != 0) {
4639 const size_t nlen
= strlen(name
);
4640 if (nlen
> 255) ufoFatal("conditional define name too long");
4641 const uint32_t hash
= joaatHashBufCI(name
, nlen
);
4642 UForthCondDefine
*dd
= ufoCondDefines
;
4644 while (res
== 0 && dd
!= NULL
) {
4645 if (dd
->hash
== hash
&& dd
->namelen
== (uint32_t)nlen
) {
4646 res
= ufoStrEquCI(name
, dd
->name
);
4652 dd
= calloc(1, sizeof(UForthCondDefine
));
4653 if (dd
== NULL
) ufoFatal("out of memory for defines");
4654 dd
->name
= strdup(name
);
4655 if (dd
->name
== NULL
) { free(dd
); ufoFatal("out of memory for defines"); }
4656 dd
->namelen
= (uint32_t)nlen
;
4658 dd
->next
= ufoCondDefines
;
4659 ufoCondDefines
= dd
;
4665 //==========================================================================
4669 //==========================================================================
4670 void ufoCondUndef (const char *name
) {
4671 if (name
!= NULL
&& name
[0] != 0) {
4672 const size_t nlen
= strlen(name
);
4674 const uint32_t hash
= joaatHashBufCI(name
, nlen
);
4675 UForthCondDefine
*dd
= ufoCondDefines
;
4676 UForthCondDefine
*prev
= NULL
;
4677 while (dd
!= NULL
) {
4678 if (dd
->hash
== hash
&& dd
->namelen
== (uint32_t)nlen
) {
4679 if (ufoStrEquCI(name
, dd
->name
)) {
4680 if (prev
!= NULL
) prev
->next
= dd
->next
; else ufoCondDefines
= dd
->next
;
4686 if (dd
!= NULL
) { prev
= dd
; dd
= dd
->next
; }
4694 // ( addr count -- )
4695 UFWORD(PAR_DLR_DEFINE
) {
4696 uint32_t count
= ufoPop();
4697 uint32_t addr
= ufoPop();
4698 if (count
== 0) ufoFatal("empty define");
4699 if (count
>= UFO_MAX_WORD_LENGTH
) ufoFatal("define too long");
4700 const uint32_t hash
= ufoHashBuf(addr
, count
, 0x20);
4701 UForthCondDefine
*dd
;
4702 for (dd
= ufoCondDefines
; dd
!= NULL
; dd
= dd
->next
) {
4703 if (dd
->hash
== hash
&& dd
->namelen
== count
) {
4704 if (ufoBufEquCI(addr
, count
, dd
->name
)) return;
4708 dd
= calloc(1, sizeof(UForthCondDefine
));
4709 if (dd
== NULL
) ufoFatal("out of memory for defines");
4710 dd
->name
= calloc(1, count
+ 1u);
4711 if (dd
->name
== NULL
) { free(dd
); ufoFatal("out of memory for defines"); }
4712 for (uint32_t f
= 0; f
< count
; f
+= 1) {
4713 ((unsigned char *)dd
->name
)[f
] = ufoImgGetU8Ext(addr
+ f
);
4715 dd
->namelen
= count
;
4717 dd
->next
= ufoCondDefines
;
4718 ufoCondDefines
= dd
;
4722 // ( addr count -- )
4723 UFWORD(PAR_DLR_UNDEF
) {
4724 uint32_t count
= ufoPop();
4725 uint32_t addr
= ufoPop();
4726 if (count
== 0) ufoFatal("empty define");
4727 if (count
>= UFO_MAX_WORD_LENGTH
) ufoFatal("define too long");
4728 const uint32_t hash
= ufoHashBuf(addr
, count
, 0x20);
4729 UForthCondDefine
*prev
= NULL
;
4730 UForthCondDefine
*dd
;
4731 for (dd
= ufoCondDefines
; dd
!= NULL
; prev
= dd
, dd
= dd
->next
) {
4732 if (dd
->hash
== hash
&& dd
->namelen
== count
) {
4733 if (ufoBufEquCI(addr
, count
, dd
->name
)) {
4734 if (prev
== NULL
) ufoCondDefines
= dd
->next
; else prev
->next
= dd
->next
;
4744 // ( addr count -- bool )
4745 UFWORD(PAR_DLR_DEFINEDQ
) {
4746 uint32_t count
= ufoPop();
4747 uint32_t addr
= ufoPop();
4748 if (count
== 0) ufoFatal("empty define");
4749 if (count
>= UFO_MAX_WORD_LENGTH
) ufoFatal("define too long");
4750 const uint32_t hash
= ufoHashBuf(addr
, count
, 0x20);
4752 UForthCondDefine
*dd
= ufoCondDefines
;
4753 while (!found
&& dd
!= NULL
) {
4754 if (dd
->hash
== hash
&& dd
->namelen
== count
) {
4755 found
= ufoBufEquCI(addr
, count
, dd
->name
);
4763 // ////////////////////////////////////////////////////////////////////////// //
4768 // ( addr count -- )
4770 uint32_t count
= ufoPop();
4771 uint32_t addr
= ufoPop();
4772 if (count
& (1u<<31)) ufoFatal("invalid error message");
4773 if (count
== 0) ufoFatal("some error");
4774 if (count
> (uint32_t)sizeof(ufoErrMsgBuf
) - 1u) count
= (uint32_t)sizeof(ufoErrMsgBuf
) - 1u;
4775 for (uint32_t f
= 0; f
< count
; f
+= 1) {
4776 ufoErrMsgBuf
[f
] = (char)ufoImgGetU8Ext(addr
+ f
);
4778 ufoErrMsgBuf
[count
] = 0;
4779 ufoFatal("%s", ufoErrMsgBuf
);
4783 // ( errflag addr count -- )
4785 const uint32_t count
= ufoPop();
4786 const uint32_t addr
= ufoPop();
4795 // ////////////////////////////////////////////////////////////////////////// //
4799 static char ufoFNameBuf
[4096];
4802 //==========================================================================
4804 // ufoScanIncludeFileName
4806 // `*psys` and `*psoft` must be initialised!
4808 //==========================================================================
4809 static void ufoScanIncludeFileName (uint32_t addr
, uint32_t count
, char *dest
, size_t destsz
,
4810 uint32_t *psys
, uint32_t *psoft
)
4814 ufo_assert(dest
!= NULL
);
4815 ufo_assert(destsz
> 0);
4817 while (count
!= 0) {
4818 ch
= ufoImgGetU8Ext(addr
);
4820 //if (system) ufoFatal("invalid file name (duplicate system mark)");
4822 } else if (ch
== '?') {
4823 //if (softinclude) ufoFatal("invalid file name (duplicate soft mark)");
4829 addr
+= 1; count
-= 1;
4830 ch
= ufoImgGetU8Ext(addr
);
4831 } while (ch
<= 32 && count
!= 0);
4834 if (count
== 0) ufoFatal("empty include file name");
4835 if (count
>= destsz
) ufoFatal("include file name too long");
4838 while (count
!= 0) {
4839 dest
[dpos
] = (char)ufoImgGetU8Ext(addr
); dpos
+= 1;
4840 addr
+= 1; count
-= 1;
4848 // return number of items in include stack
4849 UFWORD(PAR_INCLUDE_DEPTH
) {
4850 ufoPush(ufoFileStackPos
);
4853 // (INCLUDE-FILE-ID)
4854 // ( isp -- id ) -- isp 0 is current, then 1, etc.
4855 // each include file has unique non-zero id.
4856 UFWORD(PAR_INCLUDE_FILE_ID
) {
4857 const uint32_t isp
= ufoPop();
4860 } else if (isp
<= ufoFileStackPos
) {
4861 UFOFileStackEntry
*stk
= &ufoFileStack
[ufoFileStackPos
- isp
];
4864 ufoFatal("invalid include stack index");
4868 // (INCLUDE-FILE-LINE)
4870 UFWORD(PAR_INCLUDE_FILE_LINE
) {
4871 const uint32_t isp
= ufoPop();
4873 ufoPush(ufoInFileLine
);
4874 } else if (isp
<= ufoFileStackPos
) {
4875 UFOFileStackEntry
*stk
= &ufoFileStack
[ufoFileStackPos
- isp
];
4876 ufoPush(stk
->fline
);
4878 ufoFatal("invalid include stack index");
4880 ufoPush(ufoInFileLine
);
4883 // (INCLUDE-FILE-NAME)
4884 // ( isp -- addr count )
4885 // current file name; at PAD
4886 UFWORD(PAR_INCLUDE_FILE_NAME
) {
4887 const uint32_t isp
= ufoPop();
4888 const char *fname
= NULL
;
4890 fname
= ufoInFileName
;
4891 } else if (isp
<= ufoFileStackPos
) {
4892 UFOFileStackEntry
*stk
= &ufoFileStack
[ufoFileStackPos
- isp
];
4895 ufoFatal("invalid include stack index");
4898 uint32_t addr
= ufoPop();
4900 while (fname
[count
] != 0) {
4901 ufoImgPutU8Ext(addr
+ count
, ((const unsigned char *)fname
)[count
]);
4904 ufoImgPutU8Ext(addr
+ count
, 0);
4910 // ( addr count soft? system? -- )
4911 UFWORD(PAR_INCLUDE
) {
4912 uint32_t system
= ufoPop();
4913 uint32_t softinclude
= ufoPop();
4914 uint32_t count
= ufoPop();
4915 uint32_t addr
= ufoPop();
4917 if (ufoMode
== UFO_MODE_MACRO
) ufoFatal("macros cannot include files");
4919 if ((count
& ((uint32_t)1<<31)) != 0) ufoFatal("invalid include name");
4921 ufoScanIncludeFileName(addr
, count
, ufoFNameBuf
, sizeof(ufoFNameBuf
),
4922 &system
, &softinclude
);
4924 char *ffn
= ufoCreateIncludeName(ufoFNameBuf
, system
, (system
? ufoLastSysIncPath
: ufoLastIncPath
));
4926 FILE *fl
= fopen(ffn
, "rb");
4928 FILE *fl
= fopen(ffn
, "r");
4931 if (softinclude
) { free(ffn
); return; }
4932 ufoFatal("include file '%s' not found", ffn
);
4937 ufoInFileName
= ffn
;
4938 ufoFileId
= ufoLastUsedFileId
;
4939 setLastIncPath(ufoInFileName
, system
);
4940 #ifdef UFO_DEBUG_INCLUDE
4941 fprintf(stderr
, "INC-PUSH: new fname: %s\n", ffn
);
4944 // trigger next line loading
4946 if (!ufoPop()) ufoFatal("(INCLUDE) internal error");
4950 UFWORD(DLR_INCLUDE_IMM
) {
4951 int soft
= 0, system
= 0;
4952 // parse include filename
4953 //UFCALL(PARSE_SKIP_BLANKS);
4954 ufoPushBool(0); UFCALL(PAR_PARSE_SKIP_COMMENTS
);
4955 uint8_t ch
= ufoTibPeekCh();
4957 ufoTibSkipCh(); // skip quote
4959 } else if (ch
== '<') {
4960 ufoTibSkipCh(); // skip quote
4964 ufoFatal("expected quoted string");
4967 if (!ufoPop()) ufoFatal("file name expected");
4968 ufoPushBool(0); UFCALL(PAR_PARSE_SKIP_COMMENTS
);
4969 if (ufoTibPeekCh() != 0) {
4970 ufoFatal("$INCLUDE doesn't accept extra args yet");
4972 // ( addr count soft? system? -- )
4973 ufoPushBool(soft
); ufoPushBool(system
); UFCALL(PAR_INCLUDE
);
4977 //==========================================================================
4979 // ufoCreateFileGuard
4981 //==========================================================================
4982 static const char *ufoCreateFileGuard (const char *fname
) {
4983 if (fname
== NULL
|| fname
[0] == 0) return NULL
;
4984 char *rp
= ufoRealPath(fname
);
4985 if (rp
== NULL
) return NULL
;
4987 for (char *s
= rp
; *s
; s
+= 1) if (*s
== '\\') *s
= '/';
4989 // hash the buffer; extract file name; create string with path len, file name, and hash
4990 const size_t orgplen
= strlen(rp
);
4991 const uint32_t phash
= joaatHashBuf(rp
, orgplen
, 0);
4992 size_t plen
= orgplen
;
4993 while (plen
!= 0 && rp
[plen
- 1u] != '/') plen
-= 1;
4994 snprintf(ufoRealPathHashBuf
, sizeof(ufoRealPathHashBuf
),
4995 "__INCLUDE_GUARD_%08X_%08X_%s__", phash
, (uint32_t)orgplen
, rp
+ plen
);
4996 return ufoRealPathHashBuf
;
5000 // $INCLUDE-ONCE "str"
5001 // includes file only once; unreliable on shitdoze, i believe
5002 UFWORD(DLR_INCLUDE_ONCE_IMM
) {
5003 uint32_t softinclude
= 0, system
= 0;
5004 // parse include filename
5005 //UFCALL(PARSE_SKIP_BLANKS);
5006 ufoPushBool(0); UFCALL(PAR_PARSE_SKIP_COMMENTS
);
5007 uint8_t ch
= ufoTibPeekCh();
5009 ufoTibSkipCh(); // skip quote
5011 } else if (ch
== '<') {
5012 ufoTibSkipCh(); // skip quote
5016 ufoFatal("expected quoted string");
5019 if (!ufoPop()) ufoFatal("file name expected");
5020 const uint32_t count
= ufoPop();
5021 const uint32_t addr
= ufoPop();
5022 ufoPushBool(0); UFCALL(PAR_PARSE_SKIP_COMMENTS
);
5023 if (ufoTibPeekCh() != 0) {
5024 ufoFatal("$REQUIRE doesn't accept extra args yet");
5026 ufoScanIncludeFileName(addr
, count
, ufoRealPathHashBuf
, sizeof(ufoRealPathHashBuf
),
5027 &system
, &softinclude
);
5028 char *incfname
= ufoCreateIncludeName(ufoRealPathHashBuf
, system
, (system
? ufoLastSysIncPath
: ufoLastIncPath
));
5029 if (incfname
== NULL
) ufoFatal("cannot resolve include file '%s'", ufoRealPathHashBuf
);
5030 //fprintf(stderr, "?:%d;!:%d;%s|%s\n", softinclude, system, ufoRealPathHashBuf, incfname);
5031 // this will overwrite `ufoRealPathHashBuf`
5032 const char *guard
= ufoCreateFileGuard(incfname
);
5034 if (guard
== NULL
) {
5035 if (!softinclude
) ufoFatal("cannot include file '%s'", ufoRealPathHashBuf
);
5039 fprintf(stderr
, "GUARD: <%s>\n", guard
);
5041 // now check for the guard
5042 const uint32_t glen
= (uint32_t)strlen(guard
);
5043 const uint32_t ghash
= joaatHashBuf(guard
, glen
, 0);
5044 UForthCondDefine
*dd
;
5045 for (dd
= ufoCondDefines
; dd
!= NULL
; dd
= dd
->next
) {
5046 if (dd
->hash
== ghash
&& dd
->namelen
== glen
&& strcmp(guard
, dd
->name
) == 0) {
5047 // nothing to do: already included
5052 dd
= calloc(1, sizeof(UForthCondDefine
));
5053 if (dd
== NULL
) ufoFatal("out of memory for defines");
5054 dd
->name
= calloc(1, glen
+ 1u);
5055 if (dd
->name
== NULL
) { free(dd
); ufoFatal("out of memory for defines"); }
5056 strcpy(dd
->name
, guard
);
5059 dd
->next
= ufoCondDefines
;
5060 ufoCondDefines
= dd
;
5061 // ( addr count soft? system? -- )
5062 ufoPush(addr
); ufoPush(count
); ufoPushBool(softinclude
); ufoPushBool(system
);
5063 UFCALL(PAR_INCLUDE
);
5067 // ////////////////////////////////////////////////////////////////////////// //
5073 UFWORD(PAR_NEW_HANDLE
) {
5074 const uint32_t typeid = ufoPop();
5075 if (typeid == UFO_HANDLE_FREE
) ufoFatal("invalid handle typeid");
5076 UfoHandle
*hh
= ufoAllocHandle(typeid);
5077 ufoPush(hh
->ufoHandle
);
5082 UFWORD(PAR_FREE_HANDLE
) {
5083 const uint32_t hx
= ufoPop();
5084 if ((hx
& UFO_ADDR_HANDLE_BIT
) == 0) ufoFatal("trying to free something that is not a handle");
5085 UfoHandle
*hh
= ufoGetHandle(hx
);
5086 if (hh
== NULL
) ufoFatal("trying to free invalid handle");
5092 UFWORD(PAR_HANDLE_GET_TYPEID
) {
5093 const uint32_t hx
= ufoPop();
5094 if ((hx
& UFO_ADDR_HANDLE_BIT
) == 0) ufoFatal("not a handle");
5095 UfoHandle
*hh
= ufoGetHandle(hx
);
5096 if (hh
== NULL
) ufoFatal("invalid handle");
5097 ufoPush(hh
->typeid);
5102 UFWORD(PAR_HANDLE_SET_TYPEID
) {
5103 const uint32_t hx
= ufoPop();
5104 const uint32_t typeid = ufoPop();
5105 if ((hx
& UFO_ADDR_HANDLE_BIT
) == 0) ufoFatal("not a handle");
5106 if (typeid == UFO_HANDLE_FREE
) ufoFatal("invalid handle typeid");
5107 UfoHandle
*hh
= ufoGetHandle(hx
);
5108 if (hh
== NULL
) ufoFatal("invalid handle");
5109 hh
->typeid = typeid;
5114 UFWORD(PAR_HANDLE_GET_SIZE
) {
5115 const uint32_t hx
= ufoPop();
5116 if ((hx
& UFO_ADDR_HANDLE_BIT
) == 0) ufoFatal("not a handle");
5117 UfoHandle
*hh
= ufoGetHandle(hx
);
5118 if (hh
== NULL
) ufoFatal("invalid handle");
5124 UFWORD(PAR_HANDLE_SET_SIZE
) {
5125 const uint32_t hx
= ufoPop();
5126 const uint32_t size
= ufoPop();
5127 if (size
> 0x04000000) ufoFatal("invalid handle size");
5128 if ((hx
& UFO_ADDR_HANDLE_BIT
) == 0) ufoFatal("not a handle");
5129 UfoHandle
*hh
= ufoGetHandle(hx
);
5130 if (hh
== NULL
) ufoFatal("invalid handle");
5131 if (hh
->size
!= size
) {
5136 uint8_t *nx
= realloc(hh
->data
, size
* sizeof(hh
->data
[0]));
5137 if (nx
== NULL
) ufoFatal("out of memory for handle of size %u", size
);
5139 if (size
> hh
->size
) memset(hh
->data
, 0, size
- hh
->size
);
5142 if (hh
->used
> size
) hh
->used
= size
;
5148 UFWORD(PAR_HANDLE_GET_USED
) {
5149 const uint32_t hx
= ufoPop();
5150 if ((hx
& UFO_ADDR_HANDLE_BIT
) == 0) ufoFatal("not a handle");
5151 UfoHandle
*hh
= ufoGetHandle(hx
);
5152 if (hh
== NULL
) ufoFatal("invalid handle");
5158 UFWORD(PAR_HANDLE_SET_USED
) {
5159 const uint32_t hx
= ufoPop();
5160 const uint32_t used
= ufoPop();
5161 if (used
> 0x04000000) ufoFatal("invalid handle used");
5162 if ((hx
& UFO_ADDR_HANDLE_BIT
) == 0) ufoFatal("not a handle");
5163 UfoHandle
*hh
= ufoGetHandle(hx
);
5164 if (hh
== NULL
) ufoFatal("invalid handle");
5165 if (used
> hh
->size
) ufoFatal("handle used %u out of range (%u)", used
, hh
->size
);
5169 #define POP_PREPARE_HANDLE() \
5170 const uint32_t hx = ufoPop(); \
5171 uint32_t idx = ufoPop(); \
5172 if ((hx & UFO_ADDR_HANDLE_BIT) == 0) ufoFatal("not a handle"); \
5173 if (idx > 0x1fffffffU - UFO_ADDR_HANDLE_OFS_MASK) ufoFatal("handle index %u out of range", idx); \
5174 idx += (hx & UFO_ADDR_HANDLE_OFS_MASK); \
5175 UfoHandle *hh = ufoGetHandle(hx); \
5176 if (hh == NULL) ufoFatal("invalid handle")
5179 // ( idx hx -- value )
5180 UFWORD(PAR_HANDLE_LOAD_BYTE
) {
5181 POP_PREPARE_HANDLE();
5182 if (idx
>= hh
->size
) ufoFatal("handle index %u out of range (%u)", idx
, hh
->size
);
5183 ufoPush(hh
->data
[idx
]);
5187 // ( idx hx -- value )
5188 UFWORD(PAR_HANDLE_LOAD_WORD
) {
5189 POP_PREPARE_HANDLE();
5190 if (idx
>= hh
->size
|| hh
->size
- idx
< 2u) {
5191 ufoFatal("handle index %u out of range (%u)", idx
, hh
->size
);
5193 #ifdef UFO_FAST_MEM_ACCESS
5194 ufoPush(*(const uint16_t *)(hh
->data
+ idx
));
5196 uint32_t res
= hh
->data
[idx
];
5197 res
|= hh
->data
[idx
+ 1u] << 8;
5203 // ( idx hx -- value )
5204 UFWORD(PAR_HANDLE_LOAD_CELL
) {
5205 POP_PREPARE_HANDLE();
5206 if (idx
>= hh
->size
|| hh
->size
- idx
< 4u) {
5207 ufoFatal("handle index %u out of range (%u)", idx
, hh
->size
);
5209 #ifdef UFO_FAST_MEM_ACCESS
5210 ufoPush(*(const uint32_t *)(hh
->data
+ idx
));
5212 uint32_t res
= hh
->data
[idx
];
5213 res
|= hh
->data
[idx
+ 1u] << 8;
5214 res
|= hh
->data
[idx
+ 2u] << 16;
5215 res
|= hh
->data
[idx
+ 3u] << 24;
5221 // ( value idx hx -- value )
5222 UFWORD(PAR_HANDLE_STORE_BYTE
) {
5223 POP_PREPARE_HANDLE();
5224 const uint32_t value
= ufoPop();
5225 if (idx
>= hh
->size
) ufoFatal("handle index %u out of range (%u)", idx
, hh
->size
);
5226 hh
->data
[idx
] = value
;
5230 // ( value idx hx -- )
5231 UFWORD(PAR_HANDLE_STORE_WORD
) {
5232 POP_PREPARE_HANDLE();
5233 const uint32_t value
= ufoPop();
5234 if (idx
>= hh
->size
|| hh
->size
- idx
< 2u) {
5235 ufoFatal("handle index %u out of range (%u)", idx
, hh
->size
);
5237 #ifdef UFO_FAST_MEM_ACCESS
5238 *(uint16_t *)(hh
->data
+ idx
) = (uint16_t)value
;
5240 hh
->data
[idx
] = (uint8_t)value
;
5241 hh
->data
[idx
+ 1u] = (uint8_t)(value
>> 8);
5246 // ( value idx hx -- )
5247 UFWORD(PAR_HANDLE_STORE_CELL
) {
5248 POP_PREPARE_HANDLE();
5249 const uint32_t value
= ufoPop();
5250 if (idx
>= hh
->size
|| hh
->size
- idx
< 4u) {
5251 ufoFatal("handle index %u out of range (%u)", idx
, hh
->size
);
5253 #ifdef UFO_FAST_MEM_ACCESS
5254 *(uint32_t *)(hh
->data
+ idx
) = value
;
5256 hh
->data
[idx
] = (uint8_t)value
;
5257 hh
->data
[idx
+ 1u] = (uint8_t)(value
>> 8);
5258 hh
->data
[idx
+ 2u] = (uint8_t)(value
>> 16);
5259 hh
->data
[idx
+ 3u] = (uint8_t)(value
>> 24);
5265 // ( addr count -- stx )
5266 UFWORD(PAR_HANDLE_LOAD_FILE
) {
5267 uint32_t count
= ufoPop();
5268 uint32_t addr
= ufoPop();
5270 if ((count
& ((uint32_t)1<<31)) != 0) ufoFatal("invalid file name");
5272 uint8_t *dest
= (uint8_t *)ufoFNameBuf
;
5273 while (count
!= 0 && dest
< (uint8_t *)ufoFNameBuf
+ sizeof(ufoFNameBuf
)) {
5274 uint8_t ch
= ufoImgGetU8Ext(addr
);
5276 dest
+= 1u; addr
+= 1u; count
-= 1u;
5278 if (dest
== (uint8_t *)ufoFNameBuf
+ sizeof(ufoFNameBuf
)) ufoFatal("file name too long");
5281 if (*ufoFNameBuf
== 0) ufoFatal("empty file name");
5283 char *ffn
= ufoCreateIncludeName(ufoFNameBuf
, 0/*system*/, ufoLastIncPath
);
5285 FILE *fl
= fopen(ffn
, "rb");
5287 FILE *fl
= fopen(ffn
, "r");
5290 ufoFatal("file '%s' not found", ffn
);
5293 if (fseek(fl
, 0, SEEK_END
) != 0) {
5295 ufoFatal("seek error in file '%s'", ffn
);
5298 long sz
= ftell(fl
);
5299 if (sz
< 0 || sz
>= 1024 * 1024 * 64) {
5301 ufoFatal("tell error in file '%s' (or too big)", ffn
);
5304 if (fseek(fl
, 0, SEEK_SET
) != 0) {
5306 ufoFatal("seek error in file '%s'", ffn
);
5309 UfoHandle
*hh
= ufoAllocHandle(0);
5311 hh
->data
= malloc((uint32_t)sz
);
5312 if (hh
->data
== NULL
) {
5314 ufoFatal("out of memory for file '%s'", ffn
);
5316 hh
->size
= (uint32_t)sz
;
5317 if (fread(hh
->data
, (uint32_t)sz
, 1, fl
) != 1) {
5319 ufoFatal("error reading file '%s'", ffn
);
5325 ufoPush(hh
->ufoHandle
);
5329 // ////////////////////////////////////////////////////////////////////////// //
5333 // DEBUG:(DECOMPILE-CFA)
5335 UFWORD(DEBUG_DECOMPILE_CFA
) {
5336 const uint32_t cfa
= ufoPop();
5337 ufoDecompileWord(cfa
);
5343 ufoPush((uint32_t)ufo_get_msecs());
5346 // this is called by INTERPRET when it is out of input stream
5347 UFWORD(UFO_INTERPRET_FINISHED_ACTION
) {
5353 UFWORD(MT_NEW_STATE
) {
5354 UfoState
*st
= ufoNewState(ufoPop());
5355 ufoInitStateUserVars(st
, 1);
5361 UFWORD(MT_FREE_STATE
) {
5362 UfoState
*st
= ufoFindState(ufoPop());
5363 if (st
== NULL
) ufoFatal("cannot free unknown state");
5364 if (st
== ufoCurrState
) ufoFatal("cannot free current state");
5368 // MTASK:STATE-NAME@
5369 // ( stid -- addr count )
5371 UFWORD(MT_GET_STATE_NAME
) {
5372 UfoState
*st
= ufoFindState(ufoPop());
5373 if (st
== NULL
) ufoFatal("unknown state");
5375 uint32_t addr
= ufoPop();
5377 while (st
->name
[count
] != 0) {
5378 ufoImgPutU8Ext(addr
+ count
, ((const unsigned char *)st
->name
)[count
]);
5381 ufoImgPutU8Ext(addr
+ count
, 0);
5386 // MTASK:STATE-NAME!
5387 // ( addr count stid -- )
5388 UFWORD(MT_SET_STATE_NAME
) {
5389 UfoState
*st
= ufoFindState(ufoPop());
5390 if (st
== NULL
) ufoFatal("unknown state");
5391 uint32_t count
= ufoPop();
5392 uint32_t addr
= ufoPop();
5393 if ((count
& ((uint32_t)1 << 31)) == 0) {
5394 if (count
> UFO_MAX_TASK_NAME
) ufoFatal("task name too long");
5395 for (uint32_t f
= 0; f
< count
; f
+= 1u) {
5396 ((unsigned char *)st
->name
)[f
] = ufoImgGetU8Ext(addr
+ f
);
5398 st
->name
[count
] = 0;
5402 // MTASK:STATE-FIRST
5404 UFWORD(MT_STATE_FIRST
) {
5406 while (fidx
!= (uint32_t)(UFO_MAX_STATES
/32) && ufoStateUsedBitmap
[fidx
] == 0) fidx
+= 1u;
5407 // there should be at least one allocated state
5408 ufo_assert(fidx
!= (uint32_t)(UFO_MAX_STATES
/32));
5409 uint32_t bmp
= ufoStateUsedBitmap
[fidx
];
5411 while ((bmp
& 0x01) == 0) { fidx
+= 1u; bmp
>>= 1; }
5416 // ( stid -- stid / 0 )
5417 UFWORD(MT_STATE_NEXT
) {
5418 uint32_t stid
= ufoPop();
5419 if (stid
!= 0 && stid
< (uint32_t)(UFO_MAX_STATES
/32)) {
5420 // it is already incremented for us, yay!
5421 uint32_t fidx
= stid
/ 32u;
5422 uint8_t fofs
= stid
& 0x1f;
5423 while (fidx
< (uint32_t)(UFO_MAX_STATES
/32)) {
5424 const uint32_t bmp
= ufoStateUsedBitmap
[fidx
];
5426 while (fofs
!= 32u) {
5427 if ((bmp
& ((uint32_t)1 << (fofs
& 0x1f))) == 0) fofs
+= 1u;
5430 ufoPush(fidx
* 32u + fofs
+ 1u);
5434 fidx
+= 1u; fofs
= 0;
5442 // ( ... argc stid -- )
5443 UFWORD(MT_YIELD_TO
) {
5444 UfoState
*st
= ufoFindState(ufoPop());
5445 if (st
== NULL
) ufoFatal("cannot yield to unknown state");
5446 //if (st == ufoDebuggerState) ufoFatal("cannot yield to debugger"); // why not?
5447 const uint32_t argc
= ufoPop();
5448 if (argc
> 256) ufoFatal("too many YIELD-TO arguments");
5449 UfoState
*curst
= ufoCurrState
;
5450 if (st
!= ufoCurrState
) {
5451 for (uint32_t f
= 0; f
< argc
; f
+= 1) {
5452 ufoCurrState
= curst
;
5453 const uint32_t n
= ufoPop();
5457 ufoCurrState
= curst
; // we need to use API call to switch states
5459 ufoSwitchToState(st
); // always use API call for this!
5464 // MTASK:SET-SELF-AS-DEBUGGER
5466 UFWORD(MT_SET_SELF_AS_DEBUGGER
) {
5467 ufoDebuggerState
= ufoCurrState
;
5472 // debugger task receives debugge stid on the data stack, and -1 as argc.
5473 // i.e. debugger stask is: ( -1 old-stid )
5474 UFWORD(MT_DEBUGGER_BP
) {
5475 if (ufoDebuggerState
!= NULL
&& ufoCurrState
!= ufoDebuggerState
) {
5476 UfoState
*st
= ufoCurrState
;
5477 ufoSwitchToState(ufoDebuggerState
); // always use API call for this!
5484 // MTASK:DEBUGGER-RESUME
5486 UFWORD(MT_RESUME_DEBUGEE
) {
5487 if (ufoCurrState
!= ufoDebuggerState
) ufoFatal("cannot resume from non-debugger");
5488 UfoState
*st
= ufoFindState(ufoPop());
5489 if (st
== NULL
) ufoFatal("cannot yield to unknown state");
5490 if (st
== ufoCurrState
) ufoFatal("cannot resume into debugger itself");
5491 ufoSwitchToState(st
); // always use API call for this!
5495 // MTASK:DEBUGGER-SINGLE-STEP
5497 UFWORD(MT_SINGLE_STEP_DEBUGEE
) {
5498 if (ufoCurrState
!= ufoDebuggerState
) ufoFatal("cannot resume from non-debugger");
5499 UfoState
*st
= ufoFindState(ufoPop());
5500 if (st
== NULL
) ufoFatal("cannot yield to unknown state");
5501 if (st
== ufoCurrState
) ufoFatal("cannot resume into debugger itself");
5502 ufoSwitchToState(st
); // always use API call for this!
5503 ufoSingleStep
= 2; // it will be decremented after returning from this word
5508 UFWORD(MT_STATE_IP_GET
) {
5509 UfoState
*st
= ufoFindState(ufoPop());
5510 if (st
== NULL
) ufoFatal("unknown state");
5516 UFWORD(MT_STATE_IP_SET
) {
5517 UfoState
*st
= ufoFindState(ufoPop());
5518 if (st
== NULL
) ufoFatal("unknown state");
5524 UFWORD(MT_STATE_REGA_GET
) {
5525 UfoState
*st
= ufoFindState(ufoPop());
5526 if (st
== NULL
) ufoFatal("unknown state");
5532 UFWORD(MT_STATE_REGA_SET
) {
5533 UfoState
*st
= ufoFindState(ufoPop());
5534 if (st
== NULL
) ufoFatal("unknown state");
5535 st
->regA
= ufoPop();
5538 // MTASK:STATE-USER@
5539 // ( addr stid -- value )
5540 UFWORD(MT_STATE_USER_GET
) {
5541 UfoState
*st
= ufoFindState(ufoPop());
5542 if (st
== NULL
) ufoFatal("unknown state");
5543 uint32_t addr
= ufoPop();
5544 if ((addr
& UFO_ADDR_TEMP_BIT
) != 0 && (addr
& UFO_ADDR_TEMP_MASK
) + 3u < st
->imageTempSize
) {
5545 uint32_t v
= *(const uint32_t *)((const uint8_t *)st
->imageTemp
+ (addr
& UFO_ADDR_TEMP_MASK
));
5548 ufoFatal("invalid user area address");
5552 // MTASK:STATE-USER!
5553 // ( value addr stid -- )
5554 UFWORD(MT_STATE_USER_SET
) {
5555 UfoState
*st
= ufoFindState(ufoPop());
5556 if (st
== NULL
) ufoFatal("unknown state");
5557 uint32_t addr
= ufoPop();
5558 uint32_t value
= ufoPop();
5559 if ((addr
& UFO_ADDR_TEMP_BIT
) != 0 && (addr
& UFO_ADDR_TEMP_MASK
) + 3u < st
->imageTempSize
) {
5560 *(uint32_t *)((const uint8_t *)st
->imageTemp
+ (addr
& UFO_ADDR_TEMP_MASK
)) = value
;
5562 ufoFatal("invalid user area address");
5566 // MTASK:STATE-RPOPCFA@
5568 UFWORD(MT_STATE_RPOPCFA_GET
) {
5569 UfoState
*st
= ufoFindState(ufoPop());
5570 if (st
== NULL
) ufoFatal("unknown state");
5571 ufoPush(st
->vmRPopCFA
);
5574 // MTASK:STATE-RPOPCFA!
5576 UFWORD(MT_STATE_RPOPCFA_SET
) {
5577 UfoState
*st
= ufoFindState(ufoPop());
5578 if (st
== NULL
) ufoFatal("unknown state");
5579 st
->vmRPopCFA
= ufoPop();
5582 // MTASK:ACTIVE-STATE
5584 UFWORD(MT_ACTIVE_STATE
) {
5585 ufoPush(ufoCurrState
->id
);
5588 // MTASK:YIELDED-FROM
5590 UFWORD(MT_YIELDED_FROM
) {
5591 if (ufoYieldedState
!= NULL
) {
5592 ufoPush(ufoYieldedState
->id
);
5599 // ( stid -- depth )
5600 UFWORD(MT_DSTACK_DEPTH_GET
) {
5601 UfoState
*st
= ufoFindState(ufoPop());
5602 if (st
== NULL
) ufoFatal("unknown state");
5607 // ( stid -- depth )
5608 UFWORD(MT_RSTACK_DEPTH_GET
) {
5609 UfoState
*st
= ufoFindState(ufoPop());
5610 if (st
== NULL
) ufoFatal("unknown state");
5611 ufoPush(st
->RP
- st
->RPTop
);
5617 UfoState
*st
= ufoFindState(ufoPop());
5618 if (st
== NULL
) ufoFatal("unknown state");
5624 UFWORD(MT_LBP_GET
) {
5625 UfoState
*st
= ufoFindState(ufoPop());
5626 if (st
== NULL
) ufoFatal("unknown state");
5631 // ( depth stid -- )
5632 UFWORD(MT_DSTACK_DEPTH_SET
) {
5633 UfoState
*st
= ufoFindState(ufoPop());
5634 if (st
== NULL
) ufoFatal("unknown state");
5635 uint32_t idx
= ufoPop();
5636 if (idx
>= UFO_DSTACK_SIZE
) ufoFatal("invalid stack index %u (%u)", idx
, UFO_DSTACK_SIZE
);
5641 // ( stid -- depth )
5642 UFWORD(MT_RSTACK_DEPTH_SET
) {
5643 UfoState
*st
= ufoFindState(ufoPop());
5644 if (st
== NULL
) ufoFatal("unknown state");
5645 uint32_t idx
= ufoPop();
5646 const uint32_t left
= UFO_RSTACK_SIZE
- st
->RPTop
;
5647 if (idx
>= left
) ufoFatal("invalid stack index %u (%u)", idx
, left
);
5648 st
->RP
= st
->RPTop
+ idx
;
5654 UfoState
*st
= ufoFindState(ufoPop());
5655 if (st
== NULL
) ufoFatal("unknown state");
5661 UFWORD(MT_LBP_SET
) {
5662 UfoState
*st
= ufoFindState(ufoPop());
5663 if (st
== NULL
) ufoFatal("unknown state");
5668 // ( idx stid -- value )
5669 UFWORD(MT_DSTACK_LOAD
) {
5670 UfoState
*st
= ufoFindState(ufoPop());
5671 if (st
== NULL
) ufoFatal("unknown state");
5672 uint32_t idx
= ufoPop();
5673 if (idx
>= st
->SP
) ufoFatal("invalid stack index %u (%u)", idx
, st
->SP
);
5674 ufoPush(st
->dStack
[st
->SP
- idx
- 1u]);
5678 // ( idx stid -- value )
5679 UFWORD(MT_RSTACK_LOAD
) {
5680 UfoState
*st
= ufoFindState(ufoPop());
5681 if (st
== NULL
) ufoFatal("unknown state");
5682 uint32_t idx
= ufoPop();
5683 if (idx
>= st
->RP
- st
->RPTop
) ufoFatal("invalid stack index %u (%u)", idx
, st
->RP
- st
->RPTop
);
5684 ufoPush(st
->dStack
[st
->RP
- idx
- 1u]);
5688 // ( idx stid -- value )
5689 UFWORD(MT_LSTACK_LOAD
) {
5690 UfoState
*st
= ufoFindState(ufoPop());
5691 if (st
== NULL
) ufoFatal("unknown state");
5692 uint32_t idx
= ufoPop();
5693 if (idx
>= st
->LP
) ufoFatal("invalid lstack index %u (%u)", idx
, st
->LP
);
5694 ufoPush(st
->lStack
[st
->LP
- idx
- 1u]);
5698 // ( value idx stid -- )
5699 UFWORD(MT_DSTACK_STORE
) {
5700 UfoState
*st
= ufoFindState(ufoPop());
5701 if (st
== NULL
) ufoFatal("unknown state");
5702 uint32_t idx
= ufoPop();
5703 uint32_t value
= ufoPop();
5704 if (idx
>= st
->SP
) ufoFatal("invalid stack index %u (%u)", idx
, st
->SP
);
5705 st
->dStack
[st
->SP
- idx
- 1u] = value
;
5709 // ( value idx stid -- )
5710 UFWORD(MT_RSTACK_STORE
) {
5711 UfoState
*st
= ufoFindState(ufoPop());
5712 if (st
== NULL
) ufoFatal("unknown state");
5713 uint32_t idx
= ufoPop();
5714 uint32_t value
= ufoPop();
5715 if (idx
>= st
->RP
- st
->RPTop
) ufoFatal("invalid stack index %u (%u)", idx
, st
->RP
- st
->RPTop
);
5716 st
->dStack
[st
->RP
- idx
- 1u] = value
;
5720 // ( value idx stid -- )
5721 UFWORD(MT_LSTACK_STORE
) {
5722 UfoState
*st
= ufoFindState(ufoPop());
5723 if (st
== NULL
) ufoFatal("unknown state");
5724 uint32_t idx
= ufoPop();
5725 uint32_t value
= ufoPop();
5726 if (idx
>= st
->LP
) ufoFatal("invalid stack index %u (%u)", idx
, st
->LP
);
5727 st
->dStack
[st
->LP
- idx
- 1u] = value
;
5731 #include "urforth_tty.c"
5734 // ////////////////////////////////////////////////////////////////////////// //
5735 // initial dictionary definitions
5740 #define UFWORD(name_) do { \
5741 const uint32_t xcfa_ = ufoCFAsUsed; \
5742 ufo_assert(xcfa_ < UFO_MAX_NATIVE_CFAS); \
5743 ufoForthCFAs[xcfa_] = &ufoWord_##name_; \
5745 ufoDefineNative(""#name_, xcfa_, 0); \
5748 #define UFWORDX(strname_,name_) do { \
5749 const uint32_t xcfa_ = ufoCFAsUsed; \
5750 ufo_assert(xcfa_ < UFO_MAX_NATIVE_CFAS); \
5751 ufoForthCFAs[xcfa_] = &ufoWord_##name_; \
5753 ufoDefineNative(strname_, xcfa_, 0); \
5756 #define UFWORD_IMM(name_) do { \
5757 const uint32_t xcfa_ = ufoCFAsUsed; \
5758 ufo_assert(xcfa_ < UFO_MAX_NATIVE_CFAS); \
5759 ufoForthCFAs[xcfa_] = &ufoWord_##name_; \
5761 ufoDefineNative(""#name_, xcfa_, 1); \
5764 #define UFWORDX_IMM(strname_,name_) do { \
5765 const uint32_t xcfa_ = ufoCFAsUsed; \
5766 ufo_assert(xcfa_ < UFO_MAX_NATIVE_CFAS); \
5767 ufoForthCFAs[xcfa_] = &ufoWord_##name_; \
5769 ufoDefineNative(strname_, xcfa_, 1); \
5772 #define UFC(name_) ufoImgEmitU32_NoInline(ufoFindWordChecked(name_))
5775 //==========================================================================
5777 // ufoFindWordChecked
5779 //==========================================================================
5780 UFO_DISABLE_INLINE
uint32_t ufoFindWordChecked (const char *wname
) {
5781 const uint32_t cfa
= ufoFindWord(wname
);
5782 if (cfa
== 0) ufoFatal("word '%s' not found", wname
);
5787 //==========================================================================
5791 // get "FORTH" vocid
5793 //==========================================================================
5794 uint32_t ufoGetForthVocId (void) {
5795 return ufoForthVocId
;
5799 //==========================================================================
5801 // ufoVocSetOnlyDefs
5803 //==========================================================================
5804 void ufoVocSetOnlyDefs (uint32_t vocid
) {
5805 ufoImgPutU32(ufoAddrCurrent
, vocid
);
5806 ufoImgPutU32(ufoAddrContext
, vocid
);
5810 //==========================================================================
5814 // return voc PFA (vocid)
5816 //==========================================================================
5817 uint32_t ufoCreateVoc (const char *wname
, uint32_t parentvocid
, uint32_t flags
) {
5818 // create wordlist struct
5819 // typeid, used by Forth code (structs and such)
5820 ufoImgEmitU32(0); // typeid
5821 // vocid points here, to "LATEST-LFA"
5822 const uint32_t vocid
= UFO_GET_DP();
5823 //fprintf(stderr, "NEW VOCID (%s): 0x%08x\n", wname, vocid);
5824 ufoImgEmitU32(0); // latest
5825 const uint32_t vlink
= UFO_GET_DP();
5826 if ((vocid
& UFO_ADDR_TEMP_BIT
) == 0) {
5827 ufoImgEmitU32(ufoImgGetU32(ufoAddrVocLink
)); // voclink
5828 ufoImgPutU32(ufoAddrVocLink
, vlink
); // update voclink
5833 ufoImgEmitU32(parentvocid
); // parent
5834 const uint32_t hdraddr
= UFO_GET_DP();
5835 ufoImgEmitU32(0); // word header
5836 // create empty hash table
5837 for (int f
= 0; f
< UFO_HASHTABLE_SIZE
; f
+= 1) ufoImgEmitU32(0);
5838 // update CONTEXT and CURRENT if this is the first wordlist ever
5839 if (ufoImgGetU32(ufoAddrContext
) == 0) {
5840 ufoImgPutU32(ufoAddrContext
, vocid
);
5842 if (ufoImgGetU32(ufoAddrCurrent
) == 0) {
5843 ufoImgPutU32(ufoAddrCurrent
, vocid
);
5845 // create word header
5846 if (wname
!= NULL
&& wname
[0] != 0) {
5848 uint32_t flags = ufoImgGetU32(ufoAddrNewWordFlags);
5850 //UFW_FLAG_IMMEDIATE|
5852 //UFW_FLAG_NORETURN|
5858 flags |= UFW_FLAG_VOCAB;
5860 flags
&= 0xffffff00u
;
5861 flags
|= UFW_FLAG_VOCAB
;
5862 ufoCreateWordHeader(wname
, flags
);
5863 const uint32_t cfa
= UFO_GET_DP();
5864 ufoImgEmitU32(ufoDoVocCFA
); // cfa
5865 ufoImgEmitU32(vocid
); // pfa
5866 // update vocab header pointer
5867 const uint32_t lfa
= UFO_CFA_TO_LFA(cfa
);
5868 ufoImgPutU32(hdraddr
, UFO_LFA_TO_NFA(lfa
));
5869 #ifdef UFO_DEBUG_DUMP_NEW_HEADERS
5870 ufoDumpWordHeader(lfa
);
5877 //==========================================================================
5881 //==========================================================================
5882 static void ufoSetLatestArgs (uint32_t warg
) {
5883 const uint32_t curr
= ufoImgGetU32(ufoAddrCurrent
);
5884 const uint32_t lfa
= ufoImgGetU32(curr
);
5885 const uint32_t nfa
= UFO_LFA_TO_NFA(lfa
);
5886 uint32_t flags
= ufoImgGetU32(nfa
);
5887 //fprintf(stderr, "OLD FLAGS: 0x%08x\n", flags);
5888 flags
&= ~UFW_WARG_MASK
;
5889 flags
|= warg
& UFW_WARG_MASK
;
5890 //fprintf(stderr, "NEW FLAGS: 0x%08x\n", flags);
5891 ufoImgPutU32(nfa
, flags
);
5892 #ifdef UFO_DEBUG_DUMP_NEW_HEADERS
5893 ufoDumpWordHeader(lfa
);
5898 //==========================================================================
5902 //==========================================================================
5903 static void ufoDefineNative (const char *wname
, uint32_t cfaidx
, int immed
) {
5904 cfaidx
|= UFO_ADDR_CFA_BIT
;
5905 uint32_t flags
= ufoImgGetU32(ufoAddrNewWordFlags
);
5907 //UFW_FLAG_IMMEDIATE|
5909 //UFW_FLAG_NORETURN|
5915 if (immed
) flags
|= UFW_FLAG_IMMEDIATE
;
5916 ufoCreateWordHeader(wname
, flags
);
5917 ufoImgEmitU32(cfaidx
);
5921 //==========================================================================
5923 // ufoDefineConstant
5925 //==========================================================================
5926 static void ufoDefineConstant (const char *name
, uint32_t value
) {
5927 ufoDefineNative(name
, ufoDoConstCFA
, 0);
5928 ufoImgEmitU32(value
);
5932 //==========================================================================
5936 //==========================================================================
5937 static void ufoDefineUserVar (const char *name
, uint32_t addr
) {
5938 ufoDefineNative(name
, ufoDoUserVariableCFA
, 0);
5939 ufoImgEmitU32(addr
);
5943 //==========================================================================
5947 //==========================================================================
5949 static void ufoDefineVar (const char *name, uint32_t value) {
5950 ufoDefineNative(name, ufoDoVarCFA, 0);
5951 ufoImgEmitU32(value);
5956 //==========================================================================
5960 //==========================================================================
5961 static void ufoDefineDefer (const char *name
, uint32_t value
) {
5962 ufoDefineNative(name
, ufoDoDeferCFA
, 0);
5963 ufoImgEmitU32(value
);
5967 //==========================================================================
5971 //==========================================================================
5972 static void ufoHiddenWords (void) {
5973 const uint32_t flags
= ufoImgGetU32(ufoAddrNewWordFlags
);
5974 ufoImgPutU32(ufoAddrNewWordFlags
, flags
| UFW_FLAG_HIDDEN
);
5978 //==========================================================================
5982 //==========================================================================
5983 static void ufoPublicWords (void) {
5984 const uint32_t flags
= ufoImgGetU32(ufoAddrNewWordFlags
);
5985 ufoImgPutU32(ufoAddrNewWordFlags
, flags
& ~UFW_FLAG_HIDDEN
);
5989 //==========================================================================
5993 //==========================================================================
5994 static void ufoDefineForth (const char *name
) {
5995 ufoDefineNative(name
, ufoDoForthCFA
, 0);
5999 //==========================================================================
6001 // ufoDefineForthImm
6003 //==========================================================================
6004 static void ufoDefineForthImm (const char *name
) {
6005 ufoDefineNative(name
, ufoDoForthCFA
, 1);
6009 //==========================================================================
6011 // ufoDefineForthHidden
6013 //==========================================================================
6014 static void ufoDefineForthHidden (const char *name
) {
6015 const uint32_t flags
= ufoImgGetU32(ufoAddrNewWordFlags
);
6016 ufoImgPutU32(ufoAddrNewWordFlags
, flags
| UFW_FLAG_HIDDEN
);
6017 ufoDefineNative(name
, ufoDoForthCFA
, 0);
6018 ufoImgPutU32(ufoAddrNewWordFlags
, flags
);
6022 //==========================================================================
6024 // ufoDefineSColonForth
6026 // create word suitable for scattered colon extension
6028 //==========================================================================
6029 static void ufoDefineSColonForth (const char *name
) {
6030 ufoDefineNative(name
, ufoDoForthCFA
, 0);
6031 // placeholder for scattered colon
6032 // it will compile two branches:
6033 // the first branch will jump to the first "..:" word (or over the two branches)
6034 // the second branch is never taken, and works as a pointer to the latest branch addr in the list
6035 // this way, each extension word will simply fix the last branch address, and update list tail
6036 // at the creation time, second branch points to the first branch
6037 UFC("FORTH:(BRANCH)");
6038 const uint32_t xjmp
= UFO_GET_DP();
6040 UFC("FORTH:(BRANCH)"); ufoImgEmitU32(xjmp
);
6041 ufoImgPutU32(xjmp
, UFO_GET_DP());
6045 //==========================================================================
6049 //==========================================================================
6050 UFO_FORCE_INLINE
void ufoDoneForth (void) {
6051 UFC("FORTH:(EXIT)");
6055 //==========================================================================
6059 // create a new state, its execution will start from the given CFA.
6060 // state is not automatically activated.
6062 //==========================================================================
6063 static UfoState
*ufoNewState (uint32_t cfa
) {
6064 // find free state id
6066 uint32_t bmp
= ufoStateUsedBitmap
[0];
6067 while (fidx
!= (uint32_t)(UFO_MAX_STATES
/32) && bmp
== ~(uint32_t)0) {
6069 bmp
= ufoStateUsedBitmap
[fidx
];
6071 if (fidx
== (uint32_t)(UFO_MAX_STATES
/32)) ufoFatal("too many execution states");
6072 //fprintf(stderr, "NST:000: fidx=%u; bmp=0x%08x\n", fidx, bmp);
6074 while ((bmp
& 0x01) != 0) { fidx
+= 1u; bmp
>>= 1; }
6075 ufo_assert(fidx
< UFO_MAX_STATES
);
6076 ufo_assert((ufoStateUsedBitmap
[fidx
/ 32u] & ((uint32_t)1 << (fidx
& 0x1f))) == 0);
6077 ufo_assert(ufoStateMap
[fidx
] == NULL
);
6078 UfoState
*st
= calloc(1, sizeof(UfoState
));
6079 if (st
== NULL
) ufoFatal("out of memory for states");
6082 st
->rStack
[0] = 0xdeadf00d; // dummy value
6083 st
->rStack
[1] = cfa
;
6085 ufoStateMap
[fidx
] = st
;
6086 ufoStateUsedBitmap
[fidx
/ 32u] |= ((uint32_t)1 << (fidx
& 0x1f));
6087 //fprintf(stderr, "NST: fidx=%u; 0x%08x\n", fidx, ufoStateUsedBitmap[fidx / 32u]);
6092 //==========================================================================
6096 // free all memory used for the state, remove it from state list.
6097 // WARNING! never free current state!
6099 //==========================================================================
6100 static void ufoFreeState (UfoState
*st
) {
6102 if (st
== ufoCurrState
) ufoFatal("cannot free active state");
6103 if (ufoYieldedState
== st
) ufoYieldedState
= NULL
;
6104 if (ufoDebuggerState
== st
) ufoDebuggerState
= NULL
;
6105 const uint32_t fidx
= st
->id
- 1u;
6106 //fprintf(stderr, "FST: fidx=%u; 0x%08x\n", fidx, ufoStateUsedBitmap[fidx / 32u]);
6107 ufo_assert(fidx
< UFO_MAX_STATES
);
6108 ufo_assert((ufoStateUsedBitmap
[fidx
/ 32u] & (1u << (fidx
& 0x1f))) != 0);
6109 ufo_assert(ufoStateMap
[fidx
] == st
);
6110 // free default TIB handle
6111 UfoState
*oldst
= ufoCurrState
;
6113 const uint32_t tib
= ufoImgGetU32(ufoAddrDefTIB
);
6114 if ((tib
& UFO_ADDR_TEMP_BIT
) != 0) {
6115 UfoHandle
*tibh
= ufoGetHandle(tib
);
6116 if (tibh
!= NULL
) ufoFreeHandle(tibh
);
6118 ufoCurrState
= oldst
;
6120 if (st
->imageTemp
!= NULL
) free(st
->imageTemp
);
6122 ufoStateMap
[fidx
] = NULL
;
6123 ufoStateUsedBitmap
[fidx
/ 32u] &= ~((uint32_t)1 << (fidx
& 0x1f));
6128 //==========================================================================
6132 //==========================================================================
6133 static UfoState
*ufoFindState (uint32_t stid
) {
6134 UfoState
*res
= NULL
;
6135 if (stid
!= 0 && stid
<= UFO_MAX_STATES
) {
6137 res
= ufoStateMap
[stid
];
6139 ufo_assert((ufoStateUsedBitmap
[stid
/ 32u] & (1u << (stid
& 0x1f))) != 0);
6140 ufo_assert(res
->id
== stid
+ 1u);
6142 ufo_assert((ufoStateUsedBitmap
[stid
/ 32u] & (1u << (stid
& 0x1f))) == 0);
6149 //==========================================================================
6153 //==========================================================================
6154 static void ufoSwitchToState (UfoState
*newst
) {
6155 ufo_assert(newst
!= NULL
);
6156 if (newst
!= ufoCurrState
) {
6157 ufoCurrState
= newst
;
6163 //==========================================================================
6167 //==========================================================================
6168 UFO_DISABLE_INLINE
void ufoReset (void) {
6169 if (ufoCurrState
== NULL
) ufoFatal("no active execution state");
6171 ufoSP
= 0; ufoRP
= 0;
6172 ufoLP
= 0; ufoLBP
= 0;
6175 ufoVMStop
= 0; ufoVMAbort
= 0;
6179 ufoInitStateUserVars(ufoCurrState
, 0);
6180 ufoImgPutU32(ufoAddrSTATE
, 0);
6181 ufoImgPutU32(ufoAddrRedefineWarning
, UFO_REDEF_WARN_NORMAL
);
6184 ufoImgPutU32(ufoAddrDPTemp
, 0);
6186 ufoImgPutU32(ufoAddrNewWordFlags
, 0);
6187 ufoVocSetOnlyDefs(ufoForthVocId
);
6191 //==========================================================================
6195 // compile string literal, the same as QUOTE_IMM
6197 //==========================================================================
6198 static void ufoCompileStrLit (const char *str
) {
6199 if (str
== NULL
) str
= "";
6200 const size_t slen
= strlen(str
);
6201 if (slen
> 255) ufoFatal("string literal too long");
6202 UFC("FORTH:(STRLIT8)");
6203 ufoImgEmitU8((uint8_t)slen
);
6204 for (size_t f
= 0; f
< slen
; f
+= 1) {
6205 ufoImgEmitU8(((const unsigned char *)str
)[f
]);
6212 //==========================================================================
6216 //==========================================================================
6217 static __attribute__((unused
)) void ufoCompileLit (uint32_t value
) {
6219 ufoImgEmitU32(value
);
6223 //==========================================================================
6227 //==========================================================================
6228 UFO_FORCE_INLINE
uint32_t ufoMarkFwd (void) {
6229 const uint32_t res
= UFO_GET_DP();
6235 //==========================================================================
6239 //==========================================================================
6240 UFO_FORCE_INLINE
void ufoResolveFwd (uint32_t jaddr
) {
6241 ufoImgPutU32(jaddr
, UFO_GET_DP());
6245 //==========================================================================
6249 //==========================================================================
6250 UFO_FORCE_INLINE
uint32_t ufoMarkBwd (void) {
6251 return UFO_GET_DP();
6255 //==========================================================================
6259 //==========================================================================
6260 UFO_FORCE_INLINE
void ufoResolveBwd (uint32_t jaddr
) {
6261 ufoImgEmitU32(jaddr
);
6265 //==========================================================================
6267 // ufoDefineEmitType
6269 //==========================================================================
6270 UFO_DISABLE_INLINE
void ufoDefineEmitType (void) {
6272 ufoDefineForth("EMIT");
6273 UFC("(NORM-EMIT-CHAR)");
6278 ufoDefineForth("XEMIT");
6279 UFC("(NORM-XEMIT-CHAR)");
6284 ufoDefineForth("CR");
6285 UFC("NL"); UFC("(EMIT)");
6289 ufoDefineForth("SPACE");
6290 UFC("BL"); UFC("(EMIT)");
6294 ufoDefineForth("SPACES");
6295 const uint32_t spaces_again
= ufoMarkBwd();
6296 UFC("DUP"); ufoCompileLit(0); UFC(">");
6297 UFC("FORTH:(0BRANCH)"); const uint32_t spaces_exit
= ufoMarkFwd();
6298 UFC("SPACE"); ufoCompileLit(1); UFC("-");
6299 UFC("FORTH:(BRANCH)"); ufoResolveBwd(spaces_again
);
6300 ufoResolveFwd(spaces_exit
);
6305 ufoDefineForth("ENDCR");
6307 UFC("FORTH:(TBRANCH)"); const uint32_t endcr_exit
= ufoMarkFwd();
6309 ufoResolveFwd(endcr_exit
);
6312 // ( addr count -- )
6313 ufoDefineForth("TYPE");
6314 UFC("A>R"); UFC("SWAP"); UFC(">A");
6315 const uint32_t type_again
= ufoMarkBwd();
6316 UFC("DUP"); ufoCompileLit(0); UFC(">");
6317 UFC("FORTH:(0BRANCH)"); const uint32_t type_exit
= ufoMarkFwd();
6318 ufoCompileLit(0); UFC("C@A+"); UFC("EMIT"); UFC("+1>A");
6319 ufoCompileLit(1); UFC("-");
6320 UFC("FORTH:(BRANCH)"); ufoResolveBwd(type_again
);
6321 ufoResolveFwd(type_exit
);
6322 UFC("DROP"); UFC("R>A");
6325 // ( addr count -- )
6326 ufoDefineForth("XTYPE");
6327 UFC("A>R"); UFC("SWAP"); UFC(">A");
6328 const uint32_t xtype_again
= ufoMarkBwd();
6329 UFC("DUP"); ufoCompileLit(0); UFC(">");
6330 UFC("FORTH:(0BRANCH)"); const uint32_t xtype_exit
= ufoMarkFwd();
6331 ufoCompileLit(0); UFC("C@A+"); UFC("XEMIT"); UFC("+1>A");
6332 ufoCompileLit(1); UFC("-");
6333 UFC("FORTH:(BRANCH)"); ufoResolveBwd(xtype_again
);
6334 ufoResolveFwd(xtype_exit
);
6335 UFC("DROP"); UFC("R>A");
6340 //==========================================================================
6342 // ufoDefineInterpret
6344 // define "INTERPRET" in Forth
6346 //==========================================================================
6347 UFO_DISABLE_INLINE
void ufoDefineInterpret (void) {
6348 // skip comments, parse name, refilling lines if necessary
6349 ufoDefineForthHidden("(INTERPRET-PARSE-NAME)");
6350 const uint32_t label_ipn_again
= ufoMarkBwd();
6351 UFC("TRUE"); UFC("(PARSE-SKIP-COMMENTS)");
6354 UFC("FORTH:(TBRANCH)"); const uint32_t label_ipn_exit_fwd
= ufoMarkFwd();
6357 UFC("FORTH:(TBRANCH)"); ufoResolveBwd(label_ipn_again
);
6359 UFC("FORTH:STATE"); UFC("@");
6360 ufoCompileStrLit("unexpected end of file"); UFC("?ERROR");
6361 UFC("FORTH:(UFO-INTERPRET-FINISHED)");
6362 // patch the jump above
6363 ufoResolveFwd(label_ipn_exit_fwd
);
6365 //ufoDecompileWord(ufoFindWordChecked("(INTERPRET-PARSE-NAME)"));
6367 ufoDefineForth("INTERPRET");
6368 const uint32_t label_it_again
= ufoMarkBwd();
6369 UFC("FORTH:(INTERPRET-PARSE-NAME)");
6370 // try defered checker
6371 // ( addr count FALSE -- addr count FALSE / TRUE )
6372 UFC("FALSE"); UFC("(INTERPRET-CHECK-WORD)");
6373 UFC("FORTH:(TBRANCH)"); ufoResolveBwd(label_it_again
);
6374 UFC("2DUP"); UFC("FIND-WORD"); // ( addr count cfa TRUE / addr count FALSE )
6375 UFC("FORTH:(0BRANCH)"); const uint32_t label_it_try_num
= ufoMarkFwd();
6376 UFC("NROT"); UFC("2DROP"); // drop word string
6377 UFC("STATE"); UFC("@");
6378 UFC("FORTH:(0BRANCH)"); const uint32_t label_it_exec_fwd
= ufoMarkFwd();
6379 // compiling; check immediate bit
6380 UFC("DUP"); UFC("CFA->NFA"); UFC("@");
6381 UFC("COMPILER:(WFLAG-IMMEDIATE)"); UFC("AND");
6382 UFC("FORTH:(TBRANCH)"); const uint32_t label_it_exec_imm
= ufoMarkFwd();
6384 UFC("FORTH:COMPILE,");
6385 UFC("FORTH:(BRANCH)"); ufoResolveBwd(label_it_again
);
6387 ufoResolveFwd(label_it_exec_imm
);
6388 ufoResolveFwd(label_it_exec_fwd
);
6390 UFC("FORTH:(BRANCH)"); ufoResolveBwd(label_it_again
);
6391 // not a word, try a number
6392 ufoResolveFwd(label_it_try_num
);
6393 UFC("2DUP"); UFC("TRUE"); UFC("BASE"); UFC("@"); UFC("(BASED-NUMBER)");
6394 // (BASED-NUMBER) ( addr count allowsign? base -- num TRUE / FALSE )
6395 UFC("FORTH:(0BRANCH)"); const uint32_t label_it_num_error
= ufoMarkFwd();
6397 UFC("NROT"); UFC("2DROP"); // drop word string
6398 // do we need to compile it?
6399 UFC("STATE"); UFC("@");
6400 UFC("FORTH:(0BRANCH)"); ufoResolveBwd(label_it_again
);
6401 // compile "(LITERAL)" (do it properly, with "LITCFA")
6402 UFC("FORTH:(LITCFA)"); UFC("FORTH:(LIT)");
6403 UFC("FORTH:COMPILE,"); // compile "(LIT)" CFA
6404 UFC("FORTH:,"); // compile number
6405 UFC("FORTH:(BRANCH)"); ufoResolveBwd(label_it_again
);
6407 ufoResolveFwd(label_it_num_error
);
6408 // ( addr count FALSE -- addr count FALSE / TRUE )
6409 UFC("FALSE"); UFC("(INTERPRET-WORD-NOT-FOUND)");
6410 UFC("FORTH:(TBRANCH)"); ufoResolveBwd(label_it_again
);
6411 UFC("ENDCR"); UFC("SPACE"); UFC("XTYPE");
6412 ufoCompileStrLit(" -- wut?\n"); UFC("TYPE");
6413 ufoCompileStrLit("unknown word");
6416 //ufoDecompileWord(ufoFindWordChecked("INTERPRET"));
6420 //==========================================================================
6424 //==========================================================================
6425 UFO_DISABLE_INLINE
void ufoInitBaseDict (void) {
6426 uint32_t imgAddr
= 0;
6428 // reserve 64 bytes for nothing
6429 for (uint32_t f
= 0; f
< 64; f
+= 1) {
6430 ufoImgPutU8(imgAddr
, 0);
6434 while ((imgAddr
& 3) != 0) {
6435 ufoImgPutU8(imgAddr
, 0);
6440 ufoAddrSTATE
= imgAddr
;
6441 ufoImgPutU32(imgAddr
, 0); imgAddr
+= 4u;
6444 ufoAddrDP
= imgAddr
;
6445 ufoImgPutU32(imgAddr
, 0); imgAddr
+= 4u;
6448 ufoAddrDPTemp
= imgAddr
;
6449 ufoImgPutU32(imgAddr
, 0); imgAddr
+= 4u;
6452 ufoAddrContext
= imgAddr
;
6453 ufoImgPutU32(imgAddr
, 0); imgAddr
+= 4u;
6456 ufoAddrCurrent
= imgAddr
;
6457 ufoImgPutU32(imgAddr
, 0); imgAddr
+= 4u;
6460 ufoAddrLastXFA
= imgAddr
;
6461 ufoImgPutU32(imgAddr
, 0); imgAddr
+= 4u;
6464 ufoAddrVocLink
= imgAddr
;
6465 ufoImgPutU32(imgAddr
, 0); imgAddr
+= 4u;
6468 ufoAddrNewWordFlags
= imgAddr
;
6469 ufoImgPutU32(imgAddr
, UFW_FLAG_PROTECTED
); imgAddr
+= 4u;
6471 // WORD-REDEFINE-WARN-MODE
6472 ufoAddrRedefineWarning
= imgAddr
;
6473 ufoImgPutU32(imgAddr
, UFO_REDEF_WARN_NORMAL
); imgAddr
+= 4u;
6475 ufoImgPutU32(ufoAddrDP
, imgAddr
);
6476 ufoImgPutU32(ufoAddrDPTemp
, 0);
6479 fprintf(stderr
, "INITIAL HERE: 0x%08x (0x%08x)\n", imgAddr
, UFO_GET_DP());
6484 //==========================================================================
6486 // ufoInitStateUserVars
6488 //==========================================================================
6489 static void ufoInitStateUserVars (UfoState
*st
, int initial
) {
6490 ufo_assert(st
!= NULL
);
6491 if (st
->imageTempSize
< 8192u) {
6492 uint32_t *itmp
= realloc(st
->imageTemp
, 8192);
6493 if (itmp
== NULL
) ufoFatal("out of memory for state user area");
6494 st
->imageTemp
= itmp
;
6495 memset((uint8_t *)st
->imageTemp
+ st
->imageTempSize
, 0, 8192u - st
->imageTempSize
);
6496 st
->imageTempSize
= 8192;
6498 st
->imageTemp
[(ufoAddrBASE
& UFO_ADDR_TEMP_MASK
) / 4u] = 10;
6500 st
->imageTemp
[(ufoAddrUserVarUsed
& UFO_ADDR_TEMP_MASK
) / 4u] = ufoAddrUserVarUsed
;
6501 st
->imageTemp
[(ufoAddrDefTIB
& UFO_ADDR_TEMP_MASK
) / 4u] = UFO_DEF_TIB_ADDR
;
6502 st
->imageTemp
[(ufoAddrTIBx
& UFO_ADDR_TEMP_MASK
) / 4u] = UFO_DEF_TIB_ADDR
;
6504 st
->imageTemp
[(ufoAddrTIBx
& UFO_ADDR_TEMP_MASK
) / 4u] =
6505 st
->imageTemp
[(ufoAddrDefTIB
& UFO_ADDR_TEMP_MASK
) / 4u];
6507 st
->imageTemp
[(ufoAddrINx
& UFO_ADDR_TEMP_MASK
) / 4u] = 0;
6511 //==========================================================================
6513 // ufoInitBasicWords
6515 //==========================================================================
6516 UFO_DISABLE_INLINE
void ufoInitBasicWords (void) {
6517 ufoDefineConstant("FALSE", 0);
6518 ufoDefineConstant("TRUE", ufoTrueValue
);
6520 ufoDefineConstant("BL", 32);
6521 ufoDefineConstant("NL", 10);
6524 ufoDefineUserVar("BASE", ufoAddrBASE
);
6525 ufoDefineUserVar("TIB", ufoAddrTIBx
);
6526 ufoDefineUserVar(">IN", ufoAddrINx
);
6527 ufoDefineUserVar("(STD-TIB-ADDR)", ufoAddrDefTIB
);
6528 ufoDefineUserVar("(USER-VAR-USED)", ufoAddrUserVarUsed
);
6529 ufoDefineConstant("(USER-VAR-ADDR)", UFO_ADDR_TEMP_BIT
);
6530 ufoDefineConstant("(USER-VAR-SIZE)", UFO_USER_AREA_SIZE
);
6531 ufoDefineConstant("(USER-TIB)", UFO_DEF_TIB_ADDR
);
6532 ufoDefineConstant("(USER-TIB-SIZE)", UFO_ADDR_HANDLE_OFS_MASK
);
6534 ufoDefineUserVar("STATE", ufoAddrSTATE
);
6535 ufoDefineConstant("CONTEXT", ufoAddrContext
);
6536 ufoDefineConstant("CURRENT", ufoAddrCurrent
);
6539 ufoDefineConstant("(LATEST-XFA)", ufoAddrLastXFA
);
6540 ufoDefineConstant("(VOC-LINK)", ufoAddrVocLink
);
6541 ufoDefineConstant("(NEW-WORD-FLAGS)", ufoAddrNewWordFlags
);
6542 ufoDefineConstant("(ADDR-TEMP-BIT)", UFO_ADDR_TEMP_BIT
);
6543 ufoDefineConstant("(ADDR-CFA-BIT)", UFO_ADDR_CFA_BIT
);
6544 ufoDefineConstant("(ADDR-HANDLE-BIT)", UFO_ADDR_HANDLE_BIT
);
6545 ufoDefineConstant("(MAX-HANDLE-OFS)", UFO_ADDR_HANDLE_OFS_MASK
);
6547 ufoDefineConstant("(PAD-ADDR)", UFO_PAD_ADDR
);
6548 ufoDefineConstant("(#BUF)", UFO_NBUF_ADDR
+ 4u); // reserve room for counter
6549 ufoDefineConstant("(#BUF-SIZE)", UFO_NBUF_SIZE
- 8u);
6551 ufoDefineConstant("(DP)", ufoAddrDP
);
6552 ufoDefineConstant("(DP-TEMP)", ufoAddrDPTemp
);
6555 //UFWORDX("(UFO-BUCKET-STATS)", PAR_UFO_BUCKET_STATS);
6556 UFWORDX("SP0!", SP0_STORE
);
6557 UFWORDX("RP0!", RP0_STORE
);
6559 UFWORDX("PAD", PAD
);
6562 UFWORDX("C@", CPEEK
);
6563 UFWORDX("W@", WPEEK
);
6566 UFWORDX("C!", CPOKE
);
6567 UFWORDX("W!", WPOKE
);
6569 UFWORDX(",", COMMA
);
6570 UFWORDX("C,", CCOMMA
);
6571 UFWORDX("W,", WCOMMA
);
6573 UFWORDX("A>", REGA_LOAD
);
6574 UFWORDX(">A", REGA_STORE
);
6575 UFWORDX("A-SWAP", REGA_SWAP
);
6576 UFWORDX("+1>A", REGA_INC
);
6577 UFWORDX("A>R", REGA_TO_R
);
6578 UFWORDX("R>A", R_TO_REGA
);
6580 UFWORDX("@A+", PEEK_REGA_IDX
);
6581 UFWORDX("C@A+", CPEEK_REGA_IDX
);
6582 UFWORDX("W@A+", WPEEK_REGA_IDX
);
6584 UFWORDX("!A+", POKE_REGA_IDX
);
6585 UFWORDX("C!A+", CPOKE_REGA_IDX
);
6586 UFWORDX("W!A+", WPOKE_REGA_IDX
);
6589 UFWORDX("(LIT)", PAR_LIT
); ufoSetLatestArgs(UFW_WARG_LIT
);
6590 UFWORDX("(LITCFA)", PAR_LITCFA
); ufoSetLatestArgs(UFW_WARG_CFA
);
6591 UFWORDX("(LITVOCID)", PAR_LITVOCID
); ufoSetLatestArgs(UFW_WARG_VOCID
);
6592 UFWORDX("(STRLIT8)", PAR_STRLIT8
); ufoSetLatestArgs(UFW_WARG_C1STRZ
);
6593 UFWORDX("(EXIT)", PAR_EXIT
);
6595 UFWORDX("(UFO-INTERPRET-FINISHED-ACTION)", UFO_INTERPRET_FINISHED_ACTION
);
6596 ufoDefineDefer("(UFO-INTERPRET-FINISHED)", ufoFindWordChecked("FORTH:(UFO-INTERPRET-FINISHED-ACTION)"));
6598 ufoStrLit8CFA
= ufoFindWordChecked("FORTH:(STRLIT8)");
6600 UFWORDX("(L-ENTER)", PAR_LENTER
); ufoSetLatestArgs(UFW_WARG_LIT
);
6601 UFWORDX("(L-LEAVE)", PAR_LLEAVE
);
6602 UFWORDX("(LOCAL@)", PAR_LOCAL_LOAD
);
6603 UFWORDX("(LOCAL!)", PAR_LOCAL_STORE
);
6605 UFWORDX("(BRANCH)", PAR_BRANCH
); ufoSetLatestArgs(UFW_WARG_BRANCH
);
6606 UFWORDX("(TBRANCH)", PAR_TBRANCH
); ufoSetLatestArgs(UFW_WARG_BRANCH
);
6607 UFWORDX("(0BRANCH)", PAR_0BRANCH
); ufoSetLatestArgs(UFW_WARG_BRANCH
);
6610 UFWORDX("GET-MSECS", GET_MSECS
);
6614 //==========================================================================
6616 // ufoInitBasicCompilerWords
6618 //==========================================================================
6619 UFO_DISABLE_INLINE
void ufoInitBasicCompilerWords (void) {
6620 // create "COMPILER" vocabulary
6621 ufoCompilerVocId
= ufoCreateVoc("COMPILER", 0, UFW_FLAG_PROTECTED
);
6622 ufoVocSetOnlyDefs(ufoCompilerVocId
);
6624 ufoDefineConstant("(CFAIDX-DO-FORTH)", ufoDoForthCFA
);
6625 ufoDefineConstant("(CFAIDX-DO-VAR)", ufoDoVariableCFA
);
6626 ufoDefineConstant("(CFAIDX-DO-VALUE)", ufoDoValueCFA
);
6627 ufoDefineConstant("(CFAIDX-DO-CONST)", ufoDoConstCFA
);
6628 ufoDefineConstant("(CFAIDX-DO-DEFER)", ufoDoDeferCFA
);
6629 ufoDefineConstant("(CFAIDX-DO-VOC)", ufoDoVocCFA
);
6630 ufoDefineConstant("(CFAIDX-DO-CREATE)", ufoDoCreateCFA
);
6631 ufoDefineConstant("(CFAIDX-DO-USER-VAR)", ufoDoUserVariableCFA
);
6633 ufoDefineConstant("(WFLAG-IMMEDIATE)", UFW_FLAG_IMMEDIATE
);
6634 ufoDefineConstant("(WFLAG-SMUDGE)", UFW_FLAG_SMUDGE
);
6635 ufoDefineConstant("(WFLAG-NORETURN)", UFW_FLAG_NORETURN
);
6636 ufoDefineConstant("(WFLAG-HIDDEN)", UFW_FLAG_HIDDEN
);
6637 ufoDefineConstant("(WFLAG-CBLOCK)", UFW_FLAG_CBLOCK
);
6638 ufoDefineConstant("(WFLAG-VOCAB)", UFW_FLAG_VOCAB
);
6639 ufoDefineConstant("(WFLAG-SCOLON)", UFW_FLAG_SCOLON
);
6640 ufoDefineConstant("(WFLAG-PROTECTED)", UFW_FLAG_PROTECTED
);
6642 ufoDefineConstant("(WARG-MASK)", UFW_WARG_MASK
);
6643 ufoDefineConstant("(WARG-NONE)", UFW_WARG_NONE
);
6644 ufoDefineConstant("(WARG-BRANCH)", UFW_WARG_BRANCH
);
6645 ufoDefineConstant("(WARG-LIT)", UFW_WARG_LIT
);
6646 ufoDefineConstant("(WARG-C4STRZ)", UFW_WARG_C4STRZ
);
6647 ufoDefineConstant("(WARG-CFA)", UFW_WARG_CFA
);
6648 ufoDefineConstant("(WARG-CBLOCK)", UFW_WARG_CBLOCK
);
6649 ufoDefineConstant("(WARG-VOCID)", UFW_WARG_VOCID
);
6650 ufoDefineConstant("(WARG-C1STRZ)", UFW_WARG_C1STRZ
);
6652 ufoDefineConstant("(VOCOFS-LATEST)", UFW_VOCAB_OFS_LATEST
);
6653 ufoDefineConstant("(VOCOFS-VOCLINK)", UFW_VOCAB_OFS_VOCLINK
);
6654 ufoDefineConstant("(VOCOFS-PARENT)", UFW_VOCAB_OFS_PARENT
);
6655 ufoDefineConstant("(VOCOFS-HEADER)", UFW_VOCAB_OFS_HEADER
);
6656 ufoDefineConstant("(VOCOFS-HTABLE)", UFW_VOCAB_OFS_HTABLE
);
6657 ufoDefineConstant("(VOC-HTABLE-SIZE)", UFO_HASHTABLE_SIZE
);
6658 ufoDefineConstant("(VOC-HTABLE-NOFLAG)", UFO_NO_HTABLE_FLAG
);
6660 ufoDefineConstant("(REDEFINE-WARN-DON'T-CARE)", UFO_REDEF_WARN_DONT_CARE
);
6661 ufoDefineConstant("(REDEFINE-WARN-NONE)", UFO_REDEF_WARN_NONE
);
6662 ufoDefineConstant("(REDEFINE-WARN-NORMAL)", UFO_REDEF_WARN_NORMAL
);
6664 ufoDefineConstant("WORD-REDEFINE-WARN-MODE", ufoAddrRedefineWarning
);
6666 UFWORDX("(UNESCAPE)", PAR_UNESCAPE
);
6668 UFWORDX("?EXEC", QEXEC
);
6669 UFWORDX("?COMP", QCOMP
);
6673 UFWORDX("(INTERPRET-DUMB)", PAR_INTERPRET_DUMB); UFCALL(PAR_HIDDEN);
6674 const uint32_t idumbCFA = UFO_LFA_TO_CFA(ufoImgGetU32(ufoImgGetU32(ufoAddrCurrent)));
6675 ufo_assert(idumbCFA == UFO_PFA_TO_CFA(UFO_GET_DP()));
6678 UFWORDX("(CREATE-WORD-HEADER)", PAR_CREATE_WORD_HEADER
);
6679 UFWORDX("(CREATE-NAMELESS-WORD-HEADER)", PAR_CREATE_NAMELESS_WORD_HEADER
);
6681 ufoVocSetOnlyDefs(ufoForthVocId
);
6685 //==========================================================================
6689 //==========================================================================
6690 UFO_DISABLE_INLINE
void ufoInitMoreWords (void) {
6691 UFWORDX("COMPILE,", COMMA
); // just an alias, for clarity
6693 UFWORDX("CFA->PFA", CFA2PFA
);
6694 UFWORDX("PFA->CFA", PFA2CFA
);
6695 UFWORDX("CFA->NFA", CFA2NFA
);
6696 UFWORDX("NFA->CFA", NFA2CFA
);
6697 UFWORDX("CFA->LFA", CFA2LFA
);
6698 UFWORDX("LFA->CFA", LFA2CFA
);
6699 UFWORDX("LFA->PFA", LFA2PFA
);
6700 UFWORDX("LFA->BFA", LFA2BFA
);
6701 UFWORDX("LFA->XFA", LFA2XFA
);
6702 UFWORDX("LFA->YFA", LFA2YFA
);
6703 UFWORDX("LFA->NFA", LFA2NFA
);
6704 UFWORDX("NFA->LFA", NFA2LFA
);
6705 UFWORDX("CFA->WEND", CFA2WEND
);
6707 UFWORDX("ERROR", ERROR
);
6708 UFWORDX("?ERROR", QERROR
);
6710 UFWORDX("(BASED-NUMBER)", PAR_BASED_NUMBER
);
6711 UFWORDX("FIND-WORD", FIND_WORD
);
6712 UFWORDX("(FIND-WORD-IN-VOC)", FIND_WORD_IN_VOC
);
6713 UFWORDX("(FIND-WORD-IN-VOC-AND-PARENTS)", FIND_WORD_IN_VOC_AND_PARENTS
);
6715 UFWORDX_IMM("\"", QUOTE_IMM
);
6718 UFWORDX("EXECUTE-TAIL", EXECUTE_TAIL
);
6721 UFWORDX("?DUP", QDUP
);
6722 UFWORDX("2DUP", DDUP
);
6724 UFWORDX("2DROP", DDROP
);
6726 UFWORDX("2SWAP", DSWAP
);
6728 UFWORDX("2OVER", DOVER
);
6731 UFWORDX("PICK", PICK
);
6732 UFWORDX("ROLL", ROLL
);
6736 UFWORDX(">R", DTOR
);
6737 UFWORDX("R>", RTOD
);
6738 UFWORDX("R@", RPEEK
);
6739 UFWORDX("RPICK", RPICK
);
6740 UFWORDX("RROLL", RROLL
);
6741 UFWORDX("RSWAP", RSWAP
);
6742 UFWORDX("ROVER", ROVER
);
6743 UFWORDX("RROT", RROT
);
6744 UFWORDX("RNROT", RNROT
);
6746 UFWORDX("FLUSH-EMIT", FLUSH_EMIT
);
6747 UFWORDX("(EMIT)", PAR_EMIT
);
6748 UFWORDX("(NORM-EMIT-CHAR)", PAR_NORM_EMIT_CHAR
);
6749 UFWORDX("(NORM-XEMIT-CHAR)", PAR_NORM_XEMIT_CHAR
);
6750 UFWORDX("LASTCR?", LASTCRQ
);
6751 UFWORDX("LASTCR!", LASTCRSET
);
6755 UFWORDX("-", MINUS
);
6757 UFWORDX("U*", UMUL
);
6759 UFWORDX("U/", UDIV
);
6760 UFWORDX("MOD", MOD
);
6761 UFWORDX("UMOD", UMOD
);
6762 UFWORDX("/MOD", DIVMOD
);
6763 UFWORDX("U/MOD", UDIVMOD
);
6764 UFWORDX("*/", MULDIV
);
6765 UFWORDX("U*/", UMULDIV
);
6766 UFWORDX("*/MOD", MULDIVMOD
);
6767 UFWORDX("U*/MOD", UMULDIVMOD
);
6768 UFWORDX("M*", MMUL
);
6769 UFWORDX("UM*", UMMUL
);
6770 UFWORDX("M/MOD", MDIVMOD
);
6771 UFWORDX("UM/MOD", UMDIVMOD
);
6772 UFWORDX("UDS*", UDSMUL
);
6774 UFWORDX("SM/REM", SMREM
);
6775 UFWORDX("FM/MOD", FMMOD
);
6777 UFWORDX("D-", DMINUS
);
6778 UFWORDX("D+", DPLUS
);
6779 UFWORDX("D=", DEQU
);
6780 UFWORDX("D<", DLESS
);
6781 UFWORDX("D<=", DLESSEQU
);
6782 UFWORDX("DU<", DULESS
);
6783 UFWORDX("DU<=", DULESSEQU
);
6785 UFWORDX("2U*", ONESHL
);
6786 UFWORDX("2U/", ONESHR
);
6787 UFWORDX("4U*", TWOSHL
);
6788 UFWORDX("4U/", TWOSHR
);
6795 UFWORDX(">", GREAT
);
6796 UFWORDX("<=", LESSEQU
);
6797 UFWORDX(">=", GREATEQU
);
6798 UFWORDX("U<", ULESS
);
6799 UFWORDX("U>", UGREAT
);
6800 UFWORDX("U<=", ULESSEQU
);
6801 UFWORDX("U>=", UGREATEQU
);
6803 UFWORDX("<>", NOTEQU
);
6810 UFWORDX("LOGAND", LOGAND
);
6811 UFWORDX("LOGOR", LOGOR
);
6814 UFWORDX("(TIB-IN)", TIB_IN
);
6815 UFWORDX("TIB-PEEKCH", TIB_PEEKCH
);
6816 UFWORDX("TIB-PEEKCH-OFS", TIB_PEEKCH_OFS
);
6817 UFWORDX("TIB-GETCH", TIB_GETCH
);
6818 UFWORDX("TIB-SKIPCH", TIB_SKIPCH
);
6820 UFWORDX("REFILL", REFILL
);
6821 UFWORDX("REFILL-NOCROSS", REFILL_NOCROSS
);
6824 UFWORDX("(PARSE)", PAR_PARSE
);
6825 UFWORDX("(PARSE-SKIP-COMMENTS)", PAR_PARSE_SKIP_COMMENTS
);
6827 UFWORDX("PARSE-SKIP-BLANKS", PARSE_SKIP_BLANKS
);
6828 UFWORDX("PARSE-NAME", PARSE_NAME
);
6829 UFWORDX("PARSE-SKIP-LINE", PARSE_SKIP_LINE
);
6830 UFWORDX("PARSE", PARSE
);
6832 UFWORDX_IMM("[", LBRACKET_IMM
);
6833 UFWORDX("]", RBRACKET
);
6836 UFWORDX("(VSP@)", PAR_GET_VSP
);
6837 UFWORDX("(VSP!)", PAR_SET_VSP
);
6838 UFWORDX("(VSP-AT@)", PAR_VSP_LOAD
);
6839 UFWORDX("(VSP-AT!)", PAR_VSP_STORE
);
6840 ufoDefineConstant("(VSP-SIZE)", UFO_VOCSTACK_SIZE
);
6842 ufoDefineConstant("(SP-SIZE)", UFO_DSTACK_SIZE
);
6843 ufoDefineConstant("(RP-SIZE)", UFO_RSTACK_SIZE
);
6844 ufoDefineConstant("(LP-SIZE)", UFO_LSTACK_SIZE
);
6849 //==========================================================================
6851 // ufoInitHandleWords
6853 //==========================================================================
6854 UFO_DISABLE_INLINE
void ufoInitHandleWords (void) {
6855 // create "HANDLE" vocabulary
6856 const uint32_t handleVocId
= ufoCreateVoc("HANDLE", 0, UFW_FLAG_PROTECTED
);
6857 ufoVocSetOnlyDefs(handleVocId
);
6858 UFWORDX("NEW", PAR_NEW_HANDLE
);
6859 UFWORDX("FREE", PAR_FREE_HANDLE
);
6860 UFWORDX("TYPEID@", PAR_HANDLE_GET_TYPEID
);
6861 UFWORDX("TYPEID!", PAR_HANDLE_SET_TYPEID
);
6862 UFWORDX("SIZE@", PAR_HANDLE_GET_SIZE
);
6863 UFWORDX("SIZE!", PAR_HANDLE_SET_SIZE
);
6864 UFWORDX("USED@", PAR_HANDLE_GET_USED
);
6865 UFWORDX("USED!", PAR_HANDLE_SET_USED
);
6866 UFWORDX("C@", PAR_HANDLE_LOAD_BYTE
);
6867 UFWORDX("W@", PAR_HANDLE_LOAD_WORD
);
6868 UFWORDX("@", PAR_HANDLE_LOAD_CELL
);
6869 UFWORDX("C!", PAR_HANDLE_STORE_BYTE
);
6870 UFWORDX("W!", PAR_HANDLE_STORE_WORD
);
6871 UFWORDX("!", PAR_HANDLE_STORE_CELL
);
6872 UFWORDX("LOAD-FILE", PAR_HANDLE_LOAD_FILE
);
6873 ufoVocSetOnlyDefs(ufoForthVocId
);
6877 //==========================================================================
6879 // ufoInitHigherWords
6881 //==========================================================================
6882 UFO_DISABLE_INLINE
void ufoInitHigherWords (void) {
6883 UFWORDX("(INCLUDE)", PAR_INCLUDE
);
6885 UFWORDX("(INCLUDE-DEPTH)", PAR_INCLUDE_DEPTH
);
6886 UFWORDX("(INCLUDE-FILE-ID)", PAR_INCLUDE_FILE_ID
);
6887 UFWORDX("(INCLUDE-FILE-LINE)", PAR_INCLUDE_FILE_LINE
);
6888 UFWORDX("(INCLUDE-FILE-NAME)", PAR_INCLUDE_FILE_NAME
);
6890 UFWORDX("($DEFINED?)", PAR_DLR_DEFINEDQ
);
6891 UFWORDX("($DEFINE)", PAR_DLR_DEFINE
);
6892 UFWORDX("($UNDEF)", PAR_DLR_UNDEF
);
6894 UFWORDX_IMM("$INCLUDE", DLR_INCLUDE_IMM
);
6895 UFWORDX_IMM("$INCLUDE-ONCE", DLR_INCLUDE_ONCE_IMM
);
6899 //==========================================================================
6901 // ufoInitStringWords
6903 //==========================================================================
6904 UFO_DISABLE_INLINE
void ufoInitStringWords (void) {
6905 // create "STRING" vocabulary
6906 const uint32_t stringVocId
= ufoCreateVoc("STRING", 0, UFW_FLAG_PROTECTED
);
6907 ufoVocSetOnlyDefs(stringVocId
);
6908 UFWORDX("=", STREQU
);
6909 UFWORDX("=CI", STREQUCI
);
6910 UFWORDX("SEARCH", SEARCH
);
6911 UFWORDX("HASH", STRHASH
);
6912 UFWORDX("HASH-CI", STRHASHCI
);
6913 ufoVocSetOnlyDefs(ufoForthVocId
);
6917 //==========================================================================
6919 // ufoInitDebugWords
6921 //==========================================================================
6922 UFO_DISABLE_INLINE
void ufoInitDebugWords (void) {
6923 // create "DEBUG" vocabulary
6924 const uint32_t debugVocId
= ufoCreateVoc("DEBUG", 0, UFW_FLAG_PROTECTED
);
6925 ufoVocSetOnlyDefs(debugVocId
);
6926 UFWORDX("(DECOMPILE-CFA)", DEBUG_DECOMPILE_CFA
);
6927 UFWORDX("BACKTRACE", UFO_BACKTRACE
);
6928 UFWORDX("DUMP-STACK", DUMP_STACK
);
6929 UFWORDX("(BP)", MT_DEBUGGER_BP
);
6930 UFWORDX("IP->NFA", IP2NFA
);
6931 UFWORDX("IP->FILE/LINE", IP2FILELINE
);
6932 ufoVocSetOnlyDefs(ufoForthVocId
);
6936 //==========================================================================
6940 //==========================================================================
6941 UFO_DISABLE_INLINE
void ufoInitMTWords (void) {
6942 // create "MTASK" vocabulary
6943 const uint32_t mtVocId
= ufoCreateVoc("MTASK", 0, UFW_FLAG_PROTECTED
);
6944 ufoVocSetOnlyDefs(mtVocId
);
6945 UFWORDX("NEW-STATE", MT_NEW_STATE
);
6946 UFWORDX("FREE-STATE", MT_FREE_STATE
);
6947 UFWORDX("STATE-NAME@", MT_GET_STATE_NAME
);
6948 UFWORDX("STATE-NAME!", MT_SET_STATE_NAME
);
6949 UFWORDX("STATE-FIRST", MT_STATE_FIRST
);
6950 UFWORDX("STATE-NEXT", MT_STATE_NEXT
);
6951 UFWORDX("YIELD-TO", MT_YIELD_TO
);
6952 UFWORDX("SET-SELF-AS-DEBUGGER", MT_SET_SELF_AS_DEBUGGER
);
6953 UFWORDX("DEBUGGER-RESUME", MT_RESUME_DEBUGEE
);
6954 UFWORDX("DEBUGGER-SINGLE-STEP", MT_SINGLE_STEP_DEBUGEE
);
6955 UFWORDX("ACTIVE-STATE", MT_ACTIVE_STATE
);
6956 UFWORDX("STATE-IP@", MT_STATE_IP_GET
);
6957 UFWORDX("STATE-IP!", MT_STATE_IP_SET
);
6958 UFWORDX("STATE-A>", MT_STATE_REGA_GET
);
6959 UFWORDX("STATE->A", MT_STATE_REGA_SET
);
6960 UFWORDX("STATE-USER@", MT_STATE_USER_GET
);
6961 UFWORDX("STATE-USER!", MT_STATE_USER_SET
);
6962 UFWORDX("STATE-RPOPCFA@", MT_STATE_RPOPCFA_GET
);
6963 UFWORDX("STATE-RPOPCFA!", MT_STATE_RPOPCFA_SET
);
6964 UFWORDX("YIELDED-FROM", MT_YIELDED_FROM
);
6965 UFWORDX("STATE-SP@", MT_DSTACK_DEPTH_GET
);
6966 UFWORDX("STATE-RP@", MT_RSTACK_DEPTH_GET
);
6967 UFWORDX("STATE-LP@", MT_LP_GET
);
6968 UFWORDX("STATE-LBP@", MT_LBP_GET
);
6969 UFWORDX("STATE-SP!", MT_DSTACK_DEPTH_SET
);
6970 UFWORDX("STATE-RP!", MT_RSTACK_DEPTH_SET
);
6971 UFWORDX("STATE-LP!", MT_LP_SET
);
6972 UFWORDX("STATE-LBP!", MT_LBP_SET
);
6973 UFWORDX("STATE-DS@", MT_DSTACK_LOAD
);
6974 UFWORDX("STATE-RS@", MT_RSTACK_LOAD
);
6975 UFWORDX("STATE-LS@", MT_LSTACK_LOAD
);
6976 UFWORDX("STATE-DS!", MT_DSTACK_STORE
);
6977 UFWORDX("STATE-RS!", MT_RSTACK_STORE
);
6978 UFWORDX("STATE-LS!", MT_LSTACK_STORE
);
6979 ufoVocSetOnlyDefs(ufoForthVocId
);
6983 //==========================================================================
6987 //==========================================================================
6988 UFO_DISABLE_INLINE
void ufoInitTTYWords (void) {
6989 // create "TTY" vocabulary
6990 const uint32_t ttyVocId
= ufoCreateVoc("TTY", 0, UFW_FLAG_PROTECTED
);
6991 ufoVocSetOnlyDefs(ttyVocId
);
6992 UFWORDX("TTY?", TTY_TTYQ
);
6993 UFWORDX("RAW?", TTY_RAWQ
);
6994 UFWORDX("SIZE", TTY_SIZE
);
6995 UFWORDX("SET-RAW", TTY_SET_RAW
);
6996 UFWORDX("SET-COOKED", TTY_SET_COOKED
);
6997 UFWORDX("RAW-EMIT", TTY_RAW_EMIT
);
6998 UFWORDX("RAW-TYPE", TTY_RAW_TYPE
);
6999 UFWORDX("RAW-FLUSH", TTY_RAW_FLUSH
);
7000 UFWORDX("RAW-READCH", TTY_RAW_READCH
);
7001 UFWORDX("RAW-READY?", TTY_RAW_READYQ
);
7002 ufoVocSetOnlyDefs(ufoForthVocId
);
7006 //==========================================================================
7008 // ufoInitVeryVeryHighWords
7010 //==========================================================================
7011 UFO_DISABLE_INLINE
void ufoInitVeryVeryHighWords (void) {
7013 //ufoDefineDefer("INTERPRET", idumbCFA);
7015 ufoDefineEmitType();
7017 // ( addr count FALSE -- addr count FALSE / TRUE )
7018 ufoDefineSColonForth("(INTERPRET-CHECK-WORD)");
7020 // ( addr count FALSE -- addr count FALSE / TRUE )
7021 ufoDefineSColonForth("(INTERPRET-WORD-NOT-FOUND)");
7023 // ( FALSE -- FALSE / TRUE ) -- called in "EXIT", before compiling "FORTH:(EXIT)"
7024 // return TRUE to stop calling other chained words, and omit default exit
7025 ufoDefineSColonForth("(EXIT-EXTENDER)");
7028 // create "FORTH:EXIT"
7029 // : EXIT ?COMP COMPILE FORTH:(EXIT) ;
7030 ufoDefineForthImm("EXIT");
7031 UFC("COMPILER:?COMP");
7032 UFC("FALSE"); UFC("(EXIT-EXTENDER)");
7033 UFC("FORTH:(TBRANCH)"); const uint32_t exit_branch_end
= ufoMarkFwd();
7034 UFC("FORTH:(LITCFA)"); UFC("FORTH:(EXIT)");
7035 UFC("FORTH:COMPILE,");
7036 ufoResolveFwd(exit_branch_end
);
7039 ufoDefineInterpret();
7041 //ufoDumpVocab(ufoCompilerVocId);
7043 ufoDefineForth("RUN-INTERPRET-LOOP");
7044 const uint32_t addrAgain
= UFO_GET_DP();
7047 UFC("FORTH:(BRANCH)");
7048 ufoImgEmitU32(addrAgain
);
7052 #define UFO_ADD_DO_CFA(cfx_) do { \
7053 ufoDo##cfx_##CFA = ufoCFAsUsed | UFO_ADDR_CFA_BIT; \
7054 ufoForthCFAs[ufoCFAsUsed] = &ufoDo##cfx_; \
7059 //==========================================================================
7063 //==========================================================================
7064 UFO_DISABLE_INLINE
void ufoInitCommon (void) {
7066 ufoForthVocId
= 0; ufoCompilerVocId
= 0;
7068 ufoForthCFAs
= calloc(UFO_MAX_NATIVE_CFAS
, sizeof(ufoForthCFAs
[0]));
7070 // allocate default TIB handle
7071 //UfoHandle *tibh = ufoAllocHandle(0x69a029a6); // arbitrary number
7072 //ufoDefTIB = tibh->ufoHandle;
7074 ufoForthCFAs
[0] = NULL
; ufoCFAsUsed
= 1u;
7075 UFO_ADD_DO_CFA(Forth
);
7076 UFO_ADD_DO_CFA(Variable
);
7077 UFO_ADD_DO_CFA(Value
);
7078 UFO_ADD_DO_CFA(Const
);
7079 UFO_ADD_DO_CFA(Defer
);
7080 UFO_ADD_DO_CFA(Voc
);
7081 UFO_ADD_DO_CFA(Create
);
7082 UFO_ADD_DO_CFA(UserVariable
);
7084 //fprintf(stderr, "DO-FORTH-CFA: 0x%08x\n", ufoDoForthCFA);
7088 // create "FORTH" vocabulary
7089 ufoForthVocId
= ufoCreateVoc("FORTH", 0, UFW_FLAG_PROTECTED
);
7090 ufoVocSetOnlyDefs(ufoForthVocId
);
7092 // base low-level interpreter words
7093 ufoInitBasicWords();
7095 // some COMPILER words
7096 ufoInitBasicCompilerWords();
7098 // STRING vocabulary
7099 ufoInitStringWords();
7102 ufoInitDebugWords();
7107 // HANDLE vocabulary
7108 ufoInitHandleWords();
7116 ufoDefineForth("FIND-WORD-IN-VOC");
7117 ufoCompileLit(0); UFC("(FIND-WORD-IN-VOC)");
7120 ufoDefineForth("FIND-WORD-IN-VOC-AND-PARENTS");
7121 ufoCompileLit(0); UFC("(FIND-WORD-IN-VOC-AND-PARENTS)");
7124 // some higher-level FORTH words (includes, etc.)
7125 ufoInitHigherWords();
7127 // very-very high-level FORTH words
7128 ufoInitVeryVeryHighWords();
7131 ufoDecompileWord(ufoFindWordChecked("RUN-INTERPRET-LOOP"));
7140 // ////////////////////////////////////////////////////////////////////////// //
7141 // virtual machine executor
7145 //==========================================================================
7149 // address interpreter
7151 //==========================================================================
7152 static void ufoRunVMCFA (uint32_t cfa
) {
7153 const uint32_t oldRPTop
= ufoRPTop
;
7155 #ifdef UFO_TRACE_VM_RUN
7156 fprintf(stderr
, "**VM-INITIAL**: cfa=%u\n", cfa
);
7162 // VM execution loop
7164 if (ufoVMAbort
) ufoFatal("user abort");
7165 if (ufoVMStop
) { ufoRP
= oldRPTop
; break; }
7166 if (ufoCurrState
== NULL
) ufoFatal("execution state is lost");
7167 if (ufoVMRPopCFA
== 0) {
7169 if (ufoIP
== 0) ufoFatal("IP is NULL");
7170 if (ufoIP
& UFO_ADDR_HANDLE_BIT
) ufoFatal("IP is a handle");
7171 cfa
= ufoImgGetU32(ufoIP
); ufoIP
+= 4u;
7173 cfa
= ufoRPop(); ufoVMRPopCFA
= 0;
7176 if (cfa
== 0) ufoFatal("EXECUTE: NULL CFA");
7177 if (cfa
& UFO_ADDR_HANDLE_BIT
) ufoFatal("cannot execute handle");
7178 // get next word CFAIDX, and check it
7179 uint32_t cfaidx
= ufoImgGetU32(cfa
);
7180 if (cfaidx
& UFO_ADDR_HANDLE_BIT
) ufoFatal("cannot execute CFAIDX-handle");
7181 #ifdef UFO_TRACE_VM_RUN
7182 fprintf(stderr
, "**VM**: IP=%u; cfa=%u; cfaidx=0x%08x\n", ufoIP
- 4u, cfa
, cfaidx
);
7184 ufoDumpWordHeader(UFO_CFA_TO_LFA(cfa
));
7185 fprintf(stderr
, "######################################\n");
7187 if (cfaidx
& UFO_ADDR_CFA_BIT
) {
7188 cfaidx
&= UFO_ADDR_CFA_MASK
;
7189 if (cfaidx
>= ufoCFAsUsed
|| ufoForthCFAs
[cfaidx
] == NULL
) {
7190 ufoFatal("tried to execute an unknown word: %u (max is %u); IP=%u",
7191 cfaidx
, ufoCFAsUsed
, ufoIP
- 4u);
7193 #ifdef UFO_TRACE_VM_RUN
7194 fprintf(stderr
, "**VM-NATIVE**: cfaidx=%u (doForth=%u)\n", cfaidx
,
7195 (ufoDoForthCFA
& UFO_ADDR_CFA_MASK
));
7197 ufoForthCFAs
[cfaidx
](UFO_CFA_TO_PFA(cfa
));
7199 // if CFA points somewhere inside a dict, this is "DOES>" word
7200 // IP points to PFA we need to push
7201 // CFA points to Forth word we need to jump to
7202 #ifdef UFO_TRACE_VM_DOER
7203 fprintf(stderr
, "*** DOER! IP=%u; cfa=%u; cfaidx=%u ***\n", ufoIP
, cfa
, cfaidx
);
7204 UFCALL(UFO_BACKTRACE
);
7206 ufoPush(UFO_CFA_TO_PFA(cfa
)); // push PFA
7207 ufoRPush(ufoIP
); // push IP
7208 ufoIP
= cfaidx
; // fix IP
7210 // that's all we need to activate the debugger
7211 if (ufoSingleStep
) {
7213 if (ufoSingleStep
== 0 && ufoDebuggerState
!= NULL
) {
7214 if (ufoCurrState
== ufoDebuggerState
) ufoFatal("debugger cannot debug itself");
7215 UfoState
*ost
= ufoCurrState
;
7216 ufoSwitchToState(ufoDebuggerState
); // always use API call for this!
7221 } while (ufoRP
!= oldRPTop
);
7226 // ////////////////////////////////////////////////////////////////////////// //
7230 //==========================================================================
7234 // register new word
7236 //==========================================================================
7237 uint32_t ufoRegisterWord (const char *wname
, ufoNativeCFA cfa
, uint32_t flags
) {
7238 ufo_assert(cfa
!= NULL
);
7239 ufo_assert(wname
!= NULL
&& wname
[0] != 0);
7240 uint32_t cfaidx
= ufoCFAsUsed
;
7241 if (cfaidx
>= UFO_MAX_NATIVE_CFAS
) ufoFatal("too many native words");
7242 ufoForthCFAs
[cfaidx
] = cfa
;
7244 //ufoDefineNative(wname, xcfa, 0);
7245 cfaidx
|= UFO_ADDR_CFA_BIT
;
7246 flags
&= 0xffffff00u
;
7247 ufoCreateWordHeader(wname
, flags
);
7248 const uint32_t res
= UFO_GET_DP();
7249 ufoImgEmitU32(cfaidx
);
7254 //==========================================================================
7256 // ufoRegisterDataWord
7258 //==========================================================================
7259 static uint32_t ufoRegisterDataWord (const char *wname
, uint32_t cfaidx
, uint32_t value
,
7262 ufo_assert(wname
!= NULL
&& wname
[0] != 0);
7263 flags
&= 0xffffff00u
;
7264 ufoCreateWordHeader(wname
, flags
);
7265 ufoImgEmitU32(cfaidx
);
7266 const uint32_t res
= UFO_GET_DP();
7267 ufoImgEmitU32(value
);
7272 //==========================================================================
7274 // ufoRegisterConstant
7276 //==========================================================================
7277 void ufoRegisterConstant (const char *wname
, uint32_t value
, uint32_t flags
) {
7278 (void)ufoRegisterDataWord(wname
, ufoDoConstCFA
, value
, flags
);
7282 //==========================================================================
7284 // ufoRegisterVariable
7286 //==========================================================================
7287 uint32_t ufoRegisterVariable (const char *wname
, uint32_t value
, uint32_t flags
) {
7288 return ufoRegisterDataWord(wname
, ufoDoVariableCFA
, value
, flags
);
7292 //==========================================================================
7296 //==========================================================================
7297 uint32_t ufoRegisterValue (const char *wname
, uint32_t value
, uint32_t flags
) {
7298 return ufoRegisterDataWord(wname
, ufoDoValueCFA
, value
, flags
);
7302 //==========================================================================
7306 //==========================================================================
7307 uint32_t ufoRegisterDefer (const char *wname
, uint32_t value
, uint32_t flags
) {
7308 return ufoRegisterDataWord(wname
, ufoDoDeferCFA
, value
, flags
);
7312 //==========================================================================
7314 // ufoFindWordInVocabulary
7316 // check if we have the corresponding word.
7317 // return CFA suitable for executing, or 0.
7319 //==========================================================================
7320 uint32_t ufoFindWordInVocabulary (const char *wname
, uint32_t vocid
) {
7321 if (wname
== NULL
|| wname
[0] == 0) return 0;
7322 size_t wlen
= strlen(wname
);
7323 if (wlen
>= UFO_MAX_WORD_LENGTH
) return 0;
7324 return ufoFindWordInVocAndParents(wname
, (uint32_t)wlen
, 0, vocid
, 0);
7328 //==========================================================================
7332 //==========================================================================
7333 uint32_t ufoGetIP (void) {
7338 //==========================================================================
7342 //==========================================================================
7343 void ufoSetIP (uint32_t newip
) {
7348 //==========================================================================
7352 //==========================================================================
7353 int ufoIsExecuting (void) {
7354 return (ufoImgGetU32(ufoAddrSTATE
) == 0);
7358 //==========================================================================
7362 //==========================================================================
7363 int ufoIsCompiling (void) {
7364 return (ufoImgGetU32(ufoAddrSTATE
) != 0);
7368 //==========================================================================
7372 //==========================================================================
7373 void ufoSetExecuting (void) {
7374 ufoImgPutU32(ufoAddrSTATE
, 0);
7378 //==========================================================================
7382 //==========================================================================
7383 void ufoSetCompiling (void) {
7384 ufoImgPutU32(ufoAddrSTATE
, 1);
7388 //==========================================================================
7392 //==========================================================================
7393 uint32_t ufoGetHere () {
7394 return UFO_GET_DP();
7398 //==========================================================================
7402 //==========================================================================
7403 uint32_t ufoGetPad () {
7409 //==========================================================================
7413 //==========================================================================
7414 uint8_t ufoTIBPeekCh (uint32_t ofs
) {
7415 return ufoTibPeekChOfs(ofs
);
7419 //==========================================================================
7423 //==========================================================================
7424 uint8_t ufoTIBGetCh (void) {
7425 return ufoTibGetCh();
7429 //==========================================================================
7433 //==========================================================================
7434 void ufoTIBSkipCh (void) {
7439 //==========================================================================
7445 //==========================================================================
7446 int ufoTIBSRefill (int allowCrossIncludes
) {
7447 return ufoLoadNextLine(allowCrossIncludes
);
7451 //==========================================================================
7455 //==========================================================================
7456 uint32_t ufoPeekData (void) {
7461 //==========================================================================
7465 //==========================================================================
7466 uint32_t ufoPopData (void) {
7471 //==========================================================================
7475 //==========================================================================
7476 void ufoPushData (uint32_t value
) {
7477 return ufoPush(value
);
7481 //==========================================================================
7485 //==========================================================================
7486 void ufoPushBoolData (int val
) {
7491 //==========================================================================
7495 //==========================================================================
7496 uint32_t ufoPeekRet (void) {
7501 //==========================================================================
7505 //==========================================================================
7506 uint32_t ufoPopRet (void) {
7511 //==========================================================================
7515 //==========================================================================
7516 void ufoPushRet (uint32_t value
) {
7517 return ufoRPush(value
);
7521 //==========================================================================
7525 //==========================================================================
7526 void ufoPushBoolRet (int val
) {
7527 ufoRPush(val
? ufoTrueValue
: 0);
7531 //==========================================================================
7535 //==========================================================================
7536 uint8_t ufoPeekByte (uint32_t addr
) {
7537 return ufoImgGetU8Ext(addr
);
7541 //==========================================================================
7545 //==========================================================================
7546 uint16_t ufoPeekWord (uint32_t addr
) {
7553 //==========================================================================
7557 //==========================================================================
7558 uint32_t ufoPeekCell (uint32_t addr
) {
7565 //==========================================================================
7569 //==========================================================================
7570 void ufoPokeByte (uint32_t addr
, uint32_t value
) {
7571 ufoImgPutU8(addr
, value
);
7575 //==========================================================================
7579 //==========================================================================
7580 void ufoPokeWord (uint32_t addr
, uint32_t value
) {
7587 //==========================================================================
7591 //==========================================================================
7592 void ufoPokeCell (uint32_t addr
, uint32_t value
) {
7599 //==========================================================================
7603 //==========================================================================
7604 void ufoEmitByte (uint32_t value
) {
7605 ufoImgEmitU8(value
);
7609 //==========================================================================
7613 //==========================================================================
7614 void ufoEmitWord (uint32_t value
) {
7615 ufoImgEmitU8(value
& 0xff);
7616 ufoImgEmitU8((value
>> 8) & 0xff);
7620 //==========================================================================
7624 //==========================================================================
7625 void ufoEmitCell (uint32_t value
) {
7626 ufoImgEmitU32(value
);
7630 //==========================================================================
7634 //==========================================================================
7635 int ufoIsInited (void) {
7636 return (ufoMode
!= UFO_MODE_NONE
);
7640 static void (*ufoUserPostInitCB
) (void);
7643 //==========================================================================
7645 // ufoSetUserPostInit
7647 // called after main initialisation
7649 //==========================================================================
7650 void ufoSetUserPostInit (void (*cb
) (void)) {
7651 ufoUserPostInitCB
= cb
;
7655 //==========================================================================
7659 //==========================================================================
7660 void ufoInit (void) {
7661 if (ufoMode
!= UFO_MODE_NONE
) return;
7662 ufoMode
= UFO_MODE_NATIVE
;
7665 ufoInFileName
= NULL
;
7667 ufoLastIncPath
= NULL
; ufoLastSysIncPath
= NULL
;
7669 for (uint32_t f
= 0; f
< UFO_MAX_STATES
; f
+= 1u) ufoStateMap
[f
] = NULL
;
7670 memset(ufoStateUsedBitmap
, 0, sizeof(ufoStateUsedBitmap
));
7672 ufoCurrState
= ufoNewState(0); // CFA doesn't matter here
7673 strcpy(ufoCurrState
->name
, "MAIN");
7674 ufoInitStateUserVars(ufoCurrState
, 1);
7675 ufoImgPutU32(ufoAddrDefTIB
, 0); // create TIB handle
7676 ufoImgPutU32(ufoAddrTIBx
, 0); // create TIB handle
7678 ufoYieldedState
= NULL
;
7679 ufoDebuggerState
= NULL
;
7682 #ifdef UFO_DEBUG_STARTUP_TIMES
7683 uint32_t stt
= ufo_get_msecs();
7684 ufoCondDefine("UFO-DEBUG-STARTUP-TIMES");
7687 #ifdef UFO_DEBUG_STARTUP_TIMES
7688 uint32_t ett
= ufo_get_msecs();
7689 fprintf(stderr
, "UrForth init time: %u msecs\n", (unsigned)(ett
- stt
));
7694 if (ufoUserPostInitCB
) {
7695 ufoUserPostInitCB();
7700 char *ufmname
= ufoCreateIncludeName("init", 1, NULL
);
7702 FILE *ufl
= fopen(ufmname
, "rb");
7704 FILE *ufl
= fopen(ufmname
, "r");
7708 ufoInFileName
= ufmname
;
7710 ufoFileId
= ufoLastUsedFileId
;
7711 setLastIncPath(ufoInFileName
, 1);
7714 ufoFatal("cannot load init code");
7717 if (ufoInFile
!= NULL
) {
7718 ufoRunInterpretLoop();
7723 //==========================================================================
7727 //==========================================================================
7728 void ufoFinishVM (void) {
7733 //==========================================================================
7737 // check if VM was exited due to `ufoFinishVM()`
7739 //==========================================================================
7740 int ufoWasVMFinished (void) {
7741 return (ufoVMStop
!= 0);
7745 //==========================================================================
7749 // ( -- addr count TRUE / FALSE )
7750 // does base TIB parsing; never copies anything.
7751 // as our reader is line-based, returns FALSE on EOL.
7752 // EOL is detected after skipping leading delimiters.
7753 // passing -1 as delimiter skips the whole line, and always returns FALSE.
7754 // trailing delimiter is always skipped.
7755 // result is on the data stack.
7757 //==========================================================================
7758 void ufoCallParseIntr (uint32_t delim
, int skipLeading
) {
7759 ufoPush(delim
); ufoPushBool(skipLeading
);
7763 //==========================================================================
7767 // ( -- addr count )
7768 // parse with leading blanks skipping. doesn't copy anything.
7769 // return empty string on EOL.
7771 //==========================================================================
7772 void ufoCallParseName (void) {
7777 //==========================================================================
7781 // ( -- addr count TRUE / FALSE )
7782 // parse without skipping delimiters; never copies anything.
7783 // as our reader is line-based, returns FALSE on EOL.
7784 // passing 0 as delimiter skips the whole line, and always returns FALSE.
7785 // trailing delimiter is always skipped.
7787 //==========================================================================
7788 void ufoCallParse (uint32_t delim
) {
7794 //==========================================================================
7796 // ufoCallParseSkipBlanks
7798 //==========================================================================
7799 void ufoCallParseSkipBlanks (void) {
7800 UFCALL(PARSE_SKIP_BLANKS
);
7804 //==========================================================================
7806 // ufoCallParseSkipComments
7808 //==========================================================================
7809 void ufoCallParseSkipComments (void) {
7810 ufoPushBool(1); UFCALL(PAR_PARSE_SKIP_COMMENTS
);
7814 //==========================================================================
7816 // ufoCallParseSkipLineComments
7818 //==========================================================================
7819 void ufoCallParseSkipLineComments (void) {
7820 ufoPushBool(0); UFCALL(PAR_PARSE_SKIP_COMMENTS
);
7824 //==========================================================================
7826 // ufoCallParseSkipLine
7828 // to the end of line; doesn't refill
7830 //==========================================================================
7831 void ufoCallParseSkipLine (void) {
7832 UFCALL(PARSE_SKIP_LINE
);
7836 //==========================================================================
7838 // ufoCallBasedNumber
7840 // convert number from addrl+1
7841 // returns address of the first inconvertible char
7842 // (BASED-NUMBER) ( addr count allowsign? base -- num TRUE / FALSE )
7844 //==========================================================================
7845 void ufoCallBasedNumber (uint32_t addr
, uint32_t count
, int allowSign
, int base
) {
7846 ufoPush(addr
); ufoPush(count
); ufoPushBool(allowSign
);
7847 if (base
< 0) ufoPush(0); else ufoPush((uint32_t)base
);
7848 UFCALL(PAR_BASED_NUMBER
);
7852 //==========================================================================
7856 //==========================================================================
7857 void ufoRunWord (uint32_t cfa
) {
7859 if (ufoMode
== UFO_MODE_NONE
) ufoFatal("UrForth is not properly inited");
7860 if (ufoInRunWord
) ufoFatal("`ufoRunWord` cannot be called recursively");
7861 ufoMode
= UFO_MODE_NATIVE
;
7869 //==========================================================================
7873 //==========================================================================
7874 void ufoRunMacroWord (uint32_t cfa
) {
7876 if (ufoMode
== UFO_MODE_NONE
) ufoFatal("UrForth is not properly inited");
7877 if (ufoInRunWord
) ufoFatal("`ufoRunWord` cannot be called recursively");
7878 ufoMode
= UFO_MODE_MACRO
;
7879 const uint32_t oisp
= ufoFileStackPos
;
7882 (void)ufoLoadNextUserLine();
7887 ufo_assert(ufoFileStackPos
== oisp
); // sanity check
7892 //==========================================================================
7896 // check if we are currently in "MACRO" mode.
7897 // should be called from registered words.
7899 //==========================================================================
7900 int ufoIsInMacroMode (void) {
7901 return (ufoMode
== UFO_MODE_MACRO
);
7905 //==========================================================================
7907 // ufoRunInterpretLoop
7909 // run default interpret loop.
7911 //==========================================================================
7912 void ufoRunInterpretLoop (void) {
7913 if (ufoMode
== UFO_MODE_NONE
) {
7916 const uint32_t cfa
= ufoFindWord("RUN-INTERPRET-LOOP");
7917 if (cfa
== 0) ufoFatal("'RUN-INTERPRET-LOOP' word not found");
7919 ufoMode
= UFO_MODE_NATIVE
;
7923 while (ufoFileStackPos
!= 0) ufoPopInFile();
7927 //==========================================================================
7931 //==========================================================================
7932 void ufoRunFile (const char *fname
) {
7933 if (ufoMode
== UFO_MODE_NONE
) {
7936 if (ufoInRunWord
) ufoFatal("`ufoRunFile` cannot be called recursively");
7937 ufoMode
= UFO_MODE_NATIVE
;
7940 char *ufmname
= ufoCreateIncludeName(fname
, 0, ".");
7942 FILE *ufl
= fopen(ufmname
, "rb");
7944 FILE *ufl
= fopen(ufmname
, "r");
7948 ufoInFileName
= ufmname
;
7950 ufoFileId
= ufoLastUsedFileId
;
7951 setLastIncPath(ufoInFileName
, 0);
7954 ufoFatal("cannot load source file '%s'", fname
);
7956 ufoRunInterpretLoop();