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
;
322 static uint32_t ufoStrLit8CFA
;
324 // special address types:
325 #define UFO_ADDR_CFA_BIT ((uint32_t)1<<31)
326 #define UFO_ADDR_CFA_MASK (UFO_ADDR_CFA_BIT-1u)
328 // handles are somewhat special: first 12 bits can be used as offset for "@", and are ignored
329 #define UFO_ADDR_HANDLE_BIT ((uint32_t)1<<30)
330 #define UFO_ADDR_HANDLE_MASK ((UFO_ADDR_HANDLE_BIT-1u)&~((uint32_t)0xfff))
331 #define UFO_ADDR_HANDLE_SHIFT (12)
332 #define UFO_ADDR_HANDLE_OFS_MASK ((uint32_t)((1 << UFO_ADDR_HANDLE_SHIFT) - 1))
334 // temporary area is 1MB buffer out of the main image
335 #define UFO_ADDR_TEMP_BIT ((uint32_t)1<<29)
336 #define UFO_ADDR_TEMP_MASK (UFO_ADDR_TEMP_BIT-1u)
338 #define UFO_ADDR_SPECIAL_BITS_MASK (UFO_ADDR_CFA_BIT|UFO_ADDR_HANDLE_BIT|UFO_ADDR_TEMP_BIT)
341 debug image stores mapping from dictionary addresses to source files and lines.
342 it is used for backtraces and debuggers, so it doesn't need to be optimised for
343 speed; therefore i choose to optimise it for size.
345 debug map format is this:
348 align, so next data starts at 4-byte boundary
349 dxl line ; 0: no more lines
351 ...next filename record
353 "dv" is variable-length number. each byte uses bit 7 as "continuation" bit.
355 "dx?" is delta-coded number.
356 "dxi" is global, starts with 0, and incrementing.
357 "dxl" resets to 0 on each new file.
358 delta format is the same as "dv".
361 static uint32_t *ufoImage
= NULL
;
362 static uint32_t ufoImageSize
= 0;
364 static uint8_t *ufoDebugImage
= NULL
;
365 static uint32_t ufoDebugImageUsed
= 0;
366 static uint32_t ufoDebugImageSize
= 0;
367 static uint32_t ufoDebugFileId
= 0;
368 static uint32_t ufoDebugLastFRecAddr
= 0;
369 static uint32_t ufoDebugCurrDP
= 0;
371 static uint32_t ufoInRunWord
= 0;
373 static volatile int ufoVMAbort
= 0;
374 static volatile int ufoVMStop
= 0;
376 #define ufoTrueValue (~(uint32_t)0)
380 UFO_MODE_NATIVE
= 0, // executing forth code
381 UFO_MODE_MACRO
= 1, // executing forth asm macro
383 static uint32_t ufoMode
= UFO_MODE_NONE
;
385 #define UFO_DSTACK_SIZE (8192)
386 #define UFO_RSTACK_SIZE (4096)
387 #define UFO_LSTACK_SIZE (4096)
388 #define UFO_MAX_TASK_NAME (127)
390 // to support multitasking (required for the debugger),
391 // our virtual machine state is encapsulated in a struct.
392 typedef struct UfoState_t
{
394 uint32_t dStack
[UFO_DSTACK_SIZE
];
395 uint32_t rStack
[UFO_RSTACK_SIZE
];
396 uint32_t lStack
[UFO_LSTACK_SIZE
];
397 uint32_t IP
; // in image
398 uint32_t SP
; // points AFTER the last value pushed
399 uint32_t RP
; // points AFTER the last value pushed
400 uint32_t RPTop
; // stop when RP is this
407 // BASE is automatically saved and restored on task switch
408 // this would better be done with "user data area", but meh... maybe later
412 uint32_t imageTempSize
;
413 // linked list of all allocated states (tasks)
414 char name
[UFO_MAX_TASK_NAME
+ 1];
418 #define UFO_MAX_STATES (8192)
420 // this is indexed by id
421 static UfoState
*ufoStateMap
[UFO_MAX_STATES
] = {NULL
};
422 static uint32_t ufoStateUsedBitmap
[UFO_MAX_STATES
/32] = {0};
424 // currently active execution state
425 static UfoState
*ufoCurrState
= NULL
;
426 // state we're yielded from
427 static UfoState
*ufoYieldedState
= NULL
;
428 // if debug state is not NULL, VM will switch to it
429 // after executing one instruction from the current state.
430 // it will store current state in `ufoDebugeeState`.
431 static UfoState
*ufoDebuggerState
= NULL
;
432 static uint32_t ufoSingleStep
= 0;
434 #define ufoDStack (ufoCurrState->dStack)
435 #define ufoRStack (ufoCurrState->rStack)
436 #define ufoLStack (ufoCurrState->lStack)
437 #define ufoIP (ufoCurrState->IP)
438 #define ufoSP (ufoCurrState->SP)
439 #define ufoRP (ufoCurrState->RP)
440 #define ufoRPTop (ufoCurrState->RPTop)
441 #define ufoLP (ufoCurrState->LP)
442 #define ufoLBP (ufoCurrState->LBP)
443 #define ufoRegA (ufoCurrState->regA)
444 #define ufoImageTemp (ufoCurrState->imageTemp)
445 #define ufoImageTempSize (ufoCurrState->imageTempSize)
446 #define ufoVMRPopCFA (ufoCurrState->vmRPopCFA)
448 // dynamically allocated text input buffer
449 // always ends with zero (this is word name too)
450 static uint32_t ufoAddrTIBx
= 0; // TIB
451 static uint32_t ufoAddrINx
= 0; // >IN
452 static uint32_t ufoDefTIB
= 0; // default TIB (handle); user cannot change it
454 static uint32_t ufoAddrContext
; // CONTEXT
455 static uint32_t ufoAddrCurrent
; // CURRENT (definitions will go there)
456 static uint32_t ufoAddrVocLink
;
457 static uint32_t ufoAddrDP
;
458 static uint32_t ufoAddrDPTemp
;
459 static uint32_t ufoAddrSTATE
;
460 static uint32_t ufoAddrBASE
;
461 static uint32_t ufoAddrNewWordFlags
;
462 static uint32_t ufoAddrRedefineWarning
;
463 static uint32_t ufoAddrLastXFA
;
465 // allows to redefine even protected words
466 #define UFO_REDEF_WARN_DONT_CARE (~(uint32_t)0)
467 // do not warn about ordinary words, allow others
468 #define UFO_REDEF_WARN_NONE (0)
470 #define UFO_REDEF_WARN_NORMAL (1)
472 #define UFO_GET_DP() (ufoImgGetU32(ufoAddrDPTemp) ?: ufoImgGetU32(ufoAddrDP))
473 //#define UFO_SET_DP(val_) ufoImgPutU32(ufoAddrDP, (val_))
475 #define UFO_MAX_NESTED_INCLUDES (32)
481 uint32_t id
; // non-zero unique id
484 static UFOFileStackEntry ufoFileStack
[UFO_MAX_NESTED_INCLUDES
];
485 static uint32_t ufoFileStackPos
; // after the last used item
487 static FILE *ufoInFile
= NULL
;
488 static char *ufoInFileName
= NULL
;
489 static char *ufoLastIncPath
= NULL
;
490 static int ufoInFileLine
= 0;
491 static uint32_t ufoFileId
= 0;
492 static uint32_t ufoLastUsedFileId
= 0;
494 static int ufoLastEmitWasCR
= 1;
496 #define UFO_VOCSTACK_SIZE (16u)
497 static uint32_t ufoVocStack
[UFO_VOCSTACK_SIZE
]; // cfas
498 static uint32_t ufoVSP
;
499 static uint32_t ufoForthVocId
;
500 static uint32_t ufoCompilerVocId
;
503 typedef struct UHandleInfo_t
{
510 struct UHandleInfo_t
*next
;
513 static UHandleInfo
*ufoHandleFreeList
= NULL
;
514 static UHandleInfo
**ufoHandles
= NULL
;
515 static uint32_t ufoHandlesUsed
= 0;
516 static uint32_t ufoHandlesAlloted
= 0;
518 #define UFO_HANDLE_FREE (~(uint32_t)0)
520 static char ufoCurrFileLine
[520];
523 static uint32_t ufoInBacktrace
= 0;
526 // ////////////////////////////////////////////////////////////////////////// //
527 static void ufoClearCondDefines (void);
529 static void ufoRunVMCFA (uint32_t cfa
);
531 static void ufoBacktrace (uint32_t ip
);
533 static void ufoClearCondDefines (void);
535 static UfoState
*ufoNewState (uint32_t cfa
);
536 static void ufoFreeState (UfoState
*st
);
537 static UfoState
*ufoFindState (uint32_t stid
);
538 static void ufoSwitchToState (UfoState
*newst
);
540 __attribute__((unused
)) static void ufoDumpWordHeader (const uint32_t lfa
);
542 #ifdef UFO_DEBUG_DEBUG
543 static void ufoDumpDebugImage (void);
547 // ////////////////////////////////////////////////////////////////////////// //
548 #define UFWORD(name_) \
549 static void ufoWord_##name_ (uint32_t mypfa)
551 #define UFCALL(name_) ufoWord_##name_(0)
552 #define UFCFA(name_) (&ufoWord_##name_)
555 UFWORD(CPEEK_REGA_IDX
);
556 UFWORD(CPOKE_REGA_IDX
);
559 UFWORD(PAR_HANDLE_LOAD_BYTE
);
560 UFWORD(PAR_HANDLE_LOAD_WORD
);
561 UFWORD(PAR_HANDLE_LOAD_CELL
);
562 UFWORD(PAR_HANDLE_STORE_BYTE
);
563 UFWORD(PAR_HANDLE_STORE_WORD
);
564 UFWORD(PAR_HANDLE_STORE_CELL
);
567 //==========================================================================
571 //==========================================================================
572 void ufoSetUserAbort (void) {
577 //==========================================================================
581 //==========================================================================
582 static UHandleInfo
*ufoAllocHandle (uint32_t typeid) {
583 ufo_assert(typeid != UFO_HANDLE_FREE
);
584 UHandleInfo
*newh
= ufoHandleFreeList
;
586 if (ufoHandlesUsed
== ufoHandlesAlloted
) {
587 uint32_t newsz
= ufoHandlesAlloted
+ 16384;
588 // due to offsets, this is the maximum number of handles we can have
589 if (newsz
> 0x1ffffU
) {
590 if (ufoHandlesAlloted
> 0x1ffffU
) ufoFatal("too many dynamic handles");
591 newsz
= 0x1ffffU
+ 1U;
592 ufo_assert(newsz
> ufoHandlesAlloted
);
594 UHandleInfo
**nh
= realloc(ufoHandles
, sizeof(ufoHandles
[0]) * newsz
);
595 if (nh
== NULL
) ufoFatal("out of memory for handle table");
597 ufoHandlesAlloted
= newsz
;
599 newh
= calloc(1, sizeof(UHandleInfo
));
600 if (newh
== NULL
) ufoFatal("out of memory for handle info");
601 ufoHandles
[ufoHandlesUsed
] = newh
;
602 // setup new handle info
603 newh
->ufoHandle
= (ufoHandlesUsed
<< UFO_ADDR_HANDLE_SHIFT
) | UFO_ADDR_HANDLE_BIT
;
606 ufo_assert(newh
->typeid == UFO_HANDLE_FREE
);
607 ufoHandleFreeList
= newh
->next
;
609 // setup new handle info
610 newh
->typeid = typeid;
619 //==========================================================================
623 //==========================================================================
624 static void ufoFreeHandle (UHandleInfo
*hh
) {
626 ufo_assert(hh
->typeid != UFO_HANDLE_FREE
);
627 if (hh
->data
) free(hh
->data
);
628 hh
->typeid = UFO_HANDLE_FREE
;
632 hh
->next
= ufoHandleFreeList
;
633 ufoHandleFreeList
= hh
;
638 //==========================================================================
642 //==========================================================================
643 static UHandleInfo
*ufoGetHandle (uint32_t hh
) {
645 if (hh
!= 0 && (hh
& UFO_ADDR_HANDLE_BIT
) != 0) {
646 hh
= (hh
& UFO_ADDR_HANDLE_MASK
) >> UFO_ADDR_HANDLE_SHIFT
;
647 if (hh
< ufoHandlesUsed
) {
648 res
= ufoHandles
[hh
];
649 if (res
->typeid == UFO_HANDLE_FREE
) res
= NULL
;
660 //==========================================================================
664 //==========================================================================
665 static void setLastIncPath (const char *fname
) {
666 if (fname
== NULL
|| fname
[0] == 0) {
667 if (ufoLastIncPath
) free(ufoLastIncPath
);
668 ufoLastIncPath
= strdup(".");
672 if (ufoLastIncPath
) free(ufoLastIncPath
);
673 ufoLastIncPath
= strdup(fname
);
674 lslash
= ufoLastIncPath
;
675 cpos
= ufoLastIncPath
;
678 if (*cpos
== '/' || *cpos
== '\\') lslash
= cpos
;
680 if (*cpos
== '/') lslash
= cpos
;
689 //==========================================================================
691 // ufoClearIncludePath
693 // required for UrAsm
695 //==========================================================================
696 void ufoClearIncludePath (void) {
697 if (ufoLastIncPath
!= NULL
) {
698 free(ufoLastIncPath
);
699 ufoLastIncPath
= NULL
;
704 //==========================================================================
708 //==========================================================================
709 static void ufoErrorPrintFile (FILE *fo
) {
711 fprintf(fo
, "UFO ERROR at file %s, line %d: ", ufoInFileName
, ufoInFileLine
);
713 fprintf(fo
, "UFO ERROR somewhere in time: ");
718 //==========================================================================
722 //==========================================================================
723 static void ufoErrorMsgV (const char *fmt
, va_list ap
) {
724 if (!ufoLastEmitWasCR
) { printf("\n"); ufoLastEmitWasCR
= 1; }
726 ufoErrorPrintFile(stderr
);
727 vfprintf(stderr
, fmt
, ap
);
734 //==========================================================================
738 //==========================================================================
739 __attribute__((format(printf
, 1, 2)))
740 void ufoWarning (const char *fmt
, ...) {
743 ufoErrorMsgV(fmt
, ap
);
747 //==========================================================================
751 //==========================================================================
752 __attribute__((noreturn
)) __attribute__((format(printf
, 1, 2)))
753 void ufoFatal (const char *fmt
, ...) {
756 ufoErrorMsgV(fmt
, ap
);
757 if (!ufoInBacktrace
) {
762 fprintf(stderr
, "DOUBLE FATAL: error in backtrace!\n");
764 #ifdef UFO_DEBUG_FATAL_ABORT
771 // ////////////////////////////////////////////////////////////////////////// //
772 // working with the stacks
773 UFO_FORCE_INLINE
void ufoPush (uint32_t v
) { if (ufoSP
>= UFO_DSTACK_SIZE
) ufoFatal("data stack overflow"); ufoDStack
[ufoSP
++] = v
; }
774 UFO_FORCE_INLINE
void ufoDrop (void) { if (ufoSP
== 0) ufoFatal("data stack underflow"); --ufoSP
; }
775 UFO_FORCE_INLINE
uint32_t ufoPop (void) { if (ufoSP
== 0) { ufoFatal("data stack underflow"); } return ufoDStack
[--ufoSP
]; }
776 UFO_FORCE_INLINE
uint32_t ufoPeek (void) { if (ufoSP
== 0) ufoFatal("data stack underflow"); return ufoDStack
[ufoSP
-1u]; }
777 UFO_FORCE_INLINE
void ufoDup (void) { if (ufoSP
== 0) ufoFatal("data stack underflow"); ufoPush(ufoDStack
[ufoSP
-1u]); }
778 UFO_FORCE_INLINE
void ufoOver (void) { if (ufoSP
< 2u) ufoFatal("data stack underflow"); ufoPush(ufoDStack
[ufoSP
-2u]); }
779 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
; }
780 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
; }
781 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
; }
783 UFO_FORCE_INLINE
void ufo2Dup (void) { ufoOver(); ufoOver(); }
784 UFO_FORCE_INLINE
void ufo2Drop (void) { ufoDrop(); ufoDrop(); }
785 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
); }
786 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
; }
788 UFO_FORCE_INLINE
void ufoRPush (uint32_t v
) { if (ufoRP
>= UFO_RSTACK_SIZE
) ufoFatal("return stack overflow"); ufoRStack
[ufoRP
++] = v
; }
789 UFO_FORCE_INLINE
void ufoRDrop (void) { if (ufoRP
== 0 || ufoRP
== ufoRPTop
) ufoFatal("return stack underflow"); --ufoRP
; }
790 UFO_FORCE_INLINE
uint32_t ufoRPop (void) { if (ufoRP
== 0 || ufoRP
== ufoRPTop
) ufoFatal("return stack underflow"); return ufoRStack
[--ufoRP
]; }
791 UFO_FORCE_INLINE
uint32_t ufoRPeek (void) { if (ufoRP
== 0 || ufoRP
== ufoRPTop
) ufoFatal("return stack underflow"); return ufoRStack
[ufoRP
-1u]; }
792 UFO_FORCE_INLINE
void ufoRDup (void) { if (ufoRP
== 0 || ufoRP
== ufoRPTop
) ufoFatal("return stack underflow"); ufoPush(ufoRStack
[ufoRP
-1u]); }
794 UFO_FORCE_INLINE
void ufoPushBool (int v
) { ufoPush(v
? ufoTrueValue
: 0u); }
797 //==========================================================================
801 //==========================================================================
802 static void ufoImgEnsureSize (uint32_t addr
) {
803 if ((addr
& UFO_ADDR_SPECIAL_BITS_MASK
) != 0) ufoFatal("ufoImgEnsureSize: internal error");
804 if (addr
>= ufoImageSize
) {
805 // 64MB should be enough for everyone!
806 if (addr
>= 0x04000000U
) {
807 ufoFatal("image grown too big (addr=0%08XH)", addr
);
809 const const uint32_t osz
= ufoImageSize
;
811 const uint32_t nsz
= (addr
|0x000fffffU
) + 1U;
812 ufo_assert(nsz
> addr
);
813 uint32_t *nimg
= realloc(ufoImage
, nsz
);
815 ufoFatal("out of memory for UFO image (%u -> %u MBs)",
816 ufoImageSize
/ 1024u / 1024u,
817 nsz
/ 1024u / 1024u);
821 memset((char *)ufoImage
+ osz
, 0, (nsz
- osz
));
826 //==========================================================================
830 //==========================================================================
831 static void ufoImgEnsureTemp (uint32_t addr
) {
832 if ((addr
& UFO_ADDR_SPECIAL_BITS_MASK
) != 0) ufoFatal("ufoImgEnsureTemp: internal error");
833 if (addr
>= ufoImageTempSize
) {
834 if (addr
>= 1024u * 1024u) {
835 ufoFatal("Forth segmentation fault at address 0x%08X", addr
|UFO_ADDR_TEMP_BIT
);
837 const uint32_t osz
= ufoImageTempSize
;
839 const uint32_t nsz
= (addr
|0x00000fffU
) + 1U;
840 uint32_t *nimg
= realloc(ufoImageTemp
, nsz
);
842 ufoFatal("out of memory for temp UFO image (%u -> %u KBs)",
843 ufoImageTempSize
/ 1024u,
847 ufoImageTempSize
= nsz
;
848 memset(ufoImageTemp
+ osz
, 0, (nsz
- osz
));
853 #ifdef UFO_FAST_MEM_ACCESS
854 //==========================================================================
860 //==========================================================================
861 UFO_FORCE_INLINE
void ufoImgPutU8 (uint32_t addr
, const uint32_t value
) {
862 if ((addr
& UFO_ADDR_SPECIAL_BITS_MASK
) == 0) {
863 if (addr
>= ufoImageSize
) ufoImgEnsureSize(addr
);
864 *((uint8_t *)ufoImage
+ addr
) = (uint8_t)value
;
865 } else if (addr
& UFO_ADDR_TEMP_BIT
) {
866 addr
&= UFO_ADDR_TEMP_MASK
;
867 if (addr
>= ufoImageTempSize
) ufoImgEnsureTemp(addr
);
868 *((uint8_t *)ufoImageTemp
+ addr
) = (uint8_t)value
;
870 ufoFatal("Forth segmentation fault at address 0x%08X", addr
);
875 //==========================================================================
881 //==========================================================================
882 UFO_FORCE_INLINE
void ufoImgPutU16 (uint32_t addr
, const uint32_t value
) {
883 if ((addr
& UFO_ADDR_SPECIAL_BITS_MASK
) == 0) {
884 if (addr
+ 1u >= ufoImageSize
) ufoImgEnsureSize(addr
+ 1u);
885 *(uint16_t *)((uint8_t *)ufoImage
+ addr
) = (uint16_t)value
;
886 } else if (addr
& UFO_ADDR_TEMP_BIT
) {
887 addr
&= UFO_ADDR_TEMP_MASK
;
888 if (addr
+ 1u >= ufoImageTempSize
) ufoImgEnsureTemp(addr
+ 1u);
889 *(uint16_t *)((uint8_t *)ufoImageTemp
+ addr
) = (uint16_t)value
;
891 ufoFatal("Forth segmentation fault at address 0x%08X", addr
);
896 //==========================================================================
902 //==========================================================================
903 UFO_FORCE_INLINE
void ufoImgPutU32 (uint32_t addr
, const uint32_t value
) {
904 if ((addr
& UFO_ADDR_SPECIAL_BITS_MASK
) == 0) {
905 if (addr
+ 3u >= ufoImageSize
) ufoImgEnsureSize(addr
+ 3u);
906 *(uint32_t *)((uint8_t *)ufoImage
+ addr
) = value
;
907 } else if (addr
& UFO_ADDR_TEMP_BIT
) {
908 addr
&= UFO_ADDR_TEMP_MASK
;
909 if (addr
+ 3u >= ufoImageTempSize
) ufoImgEnsureTemp(addr
+ 3u);
910 *(uint32_t *)((uint8_t *)ufoImageTemp
+ addr
) = value
;
912 ufoFatal("Forth segmentation fault at address 0x%08X", addr
);
917 //==========================================================================
923 //==========================================================================
924 UFO_FORCE_INLINE
uint32_t ufoImgGetU8 (uint32_t addr
) {
925 if ((addr
& UFO_ADDR_SPECIAL_BITS_MASK
) == 0) {
926 if (addr
>= ufoImageSize
) {
927 // accessing unallocated image area is segmentation fault
928 ufoFatal("Forth segmentation fault (unallocated access) at address 0x%08X", addr
);
930 return *((const uint8_t *)ufoImage
+ addr
);
931 } else if (addr
& UFO_ADDR_TEMP_BIT
) {
932 addr
&= UFO_ADDR_TEMP_MASK
;
933 if (addr
>= ufoImageTempSize
) {
934 // accessing unallocated image area is segmentation fault
935 ufoFatal("Forth segmentation fault (unallocated access) at address 0x%08X", addr
| UFO_ADDR_TEMP_BIT
);
937 return *((const uint8_t *)ufoImageTemp
+ addr
);
939 ufoFatal("Forth segmentation fault at address 0x%08X", addr
);
944 //==========================================================================
950 //==========================================================================
951 UFO_FORCE_INLINE
uint32_t ufoImgGetU16 (uint32_t addr
) {
952 if ((addr
& UFO_ADDR_SPECIAL_BITS_MASK
) == 0) {
953 if (addr
+ 1u >= ufoImageSize
) {
954 // accessing unallocated image area is segmentation fault
955 ufoFatal("Forth segmentation fault (unallocated access) at address 0x%08X", addr
);
957 return *(const uint16_t *)((const uint8_t *)ufoImage
+ addr
);
958 } else if (addr
& UFO_ADDR_TEMP_BIT
) {
959 addr
&= UFO_ADDR_TEMP_MASK
;
960 if (addr
+ 1u >= ufoImageTempSize
) {
961 // accessing unallocated image area is segmentation fault
962 ufoFatal("Forth segmentation fault (unallocated access) at address 0x%08X", addr
| UFO_ADDR_TEMP_BIT
);
964 return *(const uint16_t *)((const uint8_t *)ufoImageTemp
+ addr
);
966 ufoFatal("Forth segmentation fault at address 0x%08X", addr
);
971 //==========================================================================
977 //==========================================================================
978 UFO_FORCE_INLINE
uint32_t ufoImgGetU32 (uint32_t addr
) {
979 if ((addr
& UFO_ADDR_SPECIAL_BITS_MASK
) == 0) {
980 if (addr
+ 3u >= ufoImageSize
) {
981 // accessing unallocated image area is segmentation fault
982 ufoFatal("Forth segmentation fault (unallocated access) at address 0x%08X", addr
);
984 return *(const uint32_t *)((const uint8_t *)ufoImage
+ addr
);
985 } else if (addr
& UFO_ADDR_TEMP_BIT
) {
986 addr
&= UFO_ADDR_TEMP_MASK
;
987 if (addr
+ 3u >= ufoImageTempSize
) {
988 // accessing unallocated image area is segmentation fault
989 ufoFatal("Forth segmentation fault (unallocated access) at address 0x%08X", addr
| UFO_ADDR_TEMP_BIT
);
991 return *(const uint32_t *)((const uint8_t *)ufoImageTemp
+ addr
);
993 ufoFatal("Forth segmentation fault at address 0x%08X", addr
);
999 //==========================================================================
1005 //==========================================================================
1006 UFO_FORCE_INLINE
void ufoImgPutU8 (uint32_t addr
, const uint32_t value
) {
1008 if ((addr
& UFO_ADDR_SPECIAL_BITS_MASK
) == 0) {
1009 if (addr
>= ufoImageSize
) ufoImgEnsureSize(addr
);
1010 imgptr
= &ufoImage
[addr
/4u];
1011 } else if (addr
& UFO_ADDR_TEMP_BIT
) {
1012 addr
&= UFO_ADDR_TEMP_MASK
;
1013 if (addr
>= ufoImageTempSize
) ufoImgEnsureTemp(addr
);
1014 imgptr
= &ufoImageTemp
[addr
/4u];
1016 ufoFatal("Forth segmentation fault at address 0x%08X", addr
);
1018 const uint8_t val
= (uint8_t)value
;
1019 memcpy((uint8_t *)imgptr
+ (addr
&3), &val
, 1);
1023 //==========================================================================
1029 //==========================================================================
1030 UFO_FORCE_INLINE
void ufoImgPutU16 (uint32_t addr
, const uint32_t value
) {
1031 ufoImgPutU8(addr
, value
&0xffU
);
1032 ufoImgPutU8(addr
+ 1u, (value
>>8)&0xffU
);
1036 //==========================================================================
1042 //==========================================================================
1043 UFO_FORCE_INLINE
void ufoImgPutU32 (uint32_t addr
, const uint32_t value
) {
1044 ufoImgPutU16(addr
, value
&0xffffU
);
1045 ufoImgPutU16(addr
+ 2u, (value
>>16)&0xffffU
);
1049 //==========================================================================
1055 //==========================================================================
1056 UFO_FORCE_INLINE
uint32_t ufoImgGetU8 (uint32_t addr
) {
1058 if ((addr
& UFO_ADDR_SPECIAL_BITS_MASK
) == 0) {
1059 if (addr
>= ufoImageSize
) return 0;
1060 imgptr
= &ufoImage
[addr
/4u];
1061 } else if (addr
& UFO_ADDR_TEMP_BIT
) {
1062 addr
&= UFO_ADDR_TEMP_MASK
;
1063 if (addr
>= ufoImageTempSize
) return 0;
1064 imgptr
= &ufoImageTemp
[addr
/4u];
1066 ufoFatal("Forth segmentation fault at address 0x%08X", addr
);
1069 memcpy(&val
, (uint8_t *)imgptr
+ (addr
&3), 1);
1070 return (uint32_t)val
;
1074 //==========================================================================
1080 //==========================================================================
1081 UFO_FORCE_INLINE
uint32_t ufoImgGetU16 (uint32_t addr
) {
1082 return ufoImgGetU8(addr
) | (ufoImgGetU8(addr
+ 1u) << 8);
1086 //==========================================================================
1092 //==========================================================================
1093 UFO_FORCE_INLINE
uint32_t ufoImgGetU32 (uint32_t addr
) {
1094 return ufoImgGetU16(addr
) | (ufoImgGetU16(addr
+ 2u) << 16);
1100 static uint32_t *ufoDebugImage = NULL;
1101 static uint32_t ufoDebugImageSize = 0;
1102 static uint32_t ufoDebugFileId = 0;
1103 static uint32_t ufoDebugLastFRecAddr = 0;
1104 static uint32_t ufoDebugLastFLine = 0;
1105 static uint32_t ufoDebugCurrDP = 0;
1109 //==========================================================================
1113 //==========================================================================
1114 UFO_DISABLE_INLINE
void ufoEnsureDebug (uint32_t sdelta
) {
1115 ufo_assert(sdelta
!= 0);
1116 if (ufoDebugImageUsed
!= 0) {
1117 if (ufoDebugImageUsed
+ sdelta
>= 0x40000000U
) ufoFatal("debug info too big");
1118 if (ufoDebugImageUsed
+ sdelta
> ufoDebugImageSize
) {
1119 const uint32_t newsz
= ((ufoDebugImageUsed
+ sdelta
) | 0xffffU
) + 1u;
1120 uint8_t *ndb
= realloc(ufoDebugImage
, newsz
);
1121 if (ndb
== NULL
) ufoFatal("out of memory for debug info");
1122 ufoDebugImage
= ndb
;
1123 ufoDebugImageSize
= newsz
;
1126 // initial allocation
1127 ufoDebugImageSize
= 1024 * 128;
1128 ufoDebugImage
= malloc(ufoDebugImageSize
);
1129 if (ufoDebugImage
== NULL
) ufoFatal("out of memory for debug info");
1134 #ifdef UFO_DEBUG_DEBUG
1135 //==========================================================================
1139 //==========================================================================
1140 static void ufoDumpDebugImage (void) {
1142 uint32_t dbgpos
= 0u; // first item is always "next file record"
1143 while (dbgpos
< ufoDebugImageUsed
) {
1144 const uint32_t ln
= *(const uint32_t *)(ufoDebugImage
+ dbgpos
); dbgpos
+= 4u;
1145 if (ln
== ~(uint32_t)0) {
1147 const uint32_t nlen
= *(const uint32_t *)(ufoDebugImage
+ dbgpos
); dbgpos
+= 4u;
1148 fprintf(stderr
, "*** NEW FILE: %s\n", (const char *)(ufoDebugImage
+ dbgpos
));
1149 dbgpos
+= nlen
+ 1u;
1150 if ((dbgpos
& 0x03) != 0) dbgpos
= (dbgpos
| 0x03u
) + 1u;
1152 const uint32_t edp
= *(const uint32_t *)(ufoDebugImage
+ dbgpos
); dbgpos
+= 4u;
1153 fprintf(stderr
, " line %6u: edp=%u\n", ln
, edp
);
1161 #define UFO_DBG_PUT_U4(val_) do { \
1162 const uint32_t vv_ = (val_); \
1163 *((uint32_t *)(ufoDebugImage + ufoDebugImageUsed)) = vv_; \
1164 ufoDebugImageUsed += 4u; \
1167 //==========================================================================
1171 //==========================================================================
1172 UFO_DISABLE_INLINE
void ufoRecordDebug (uint32_t newhere
) {
1173 if (newhere
> ufoDebugCurrDP
) {
1174 if (ufoInFileName
!= NULL
) {
1175 // check if we're doing the same file
1176 const uint32_t slen
= (uint32_t)strlen(ufoInFileName
);
1177 const int newfrec
= (ufoDebugLastFRecAddr
== 0) ||
1178 (*((const uint32_t *)(ufoDebugImage
+ ufoDebugLastFRecAddr
)) != slen
) ||
1179 (memcmp((const char *)ufoDebugImage
+ ufoDebugLastFRecAddr
+ 4u, ufoInFileName
, slen
) != 0);
1180 uint32_t fline
= (uint32_t)ufoInFileLine
;
1181 if (fline
== ~(uint32_t)0) fline
-= 1u;
1183 ufoEnsureDebug(slen
+ 4u + 4u + 4u + 32u); // way too much ;-)
1184 // finish previous record
1185 UFO_DBG_PUT_U4(~(uint32_t)0);
1186 // create new file record
1187 ufoDebugLastFRecAddr
= ufoDebugImageUsed
;
1188 UFO_DBG_PUT_U4(slen
);
1189 memcpy(ufoDebugImage
+ ufoDebugImageUsed
, ufoInFileName
, slen
+ 1u);
1190 ufoDebugImageUsed
+= slen
+ 1u;
1191 while ((ufoDebugImageUsed
& 0x03u
) != 0) {
1192 ufoDebugImage
[ufoDebugImageUsed
] = 0;
1193 ufoDebugImageUsed
+= 1;
1195 UFO_DBG_PUT_U4(fline
);
1196 UFO_DBG_PUT_U4(newhere
);
1198 // check if the line is the same
1199 if (*((const uint32_t *)(ufoDebugImage
+ ufoDebugImageUsed
- 8u)) == fline
) {
1200 *((uint32_t *)(ufoDebugImage
+ ufoDebugImageUsed
- 4u)) = newhere
;
1204 UFO_DBG_PUT_U4(fline
);
1205 UFO_DBG_PUT_U4(newhere
);
1209 // we don't have a file, don't record debug info
1211 ufoDebugLastFRecAddr
= 0;
1213 ufoDebugCurrDP
= newhere
;
1218 //==========================================================================
1220 // ufoGetWordEndAddrYFA
1222 //==========================================================================
1223 static uint32_t ufoGetWordEndAddrYFA (uint32_t yfa
) {
1225 const uint32_t oyfa
= yfa
;
1226 yfa
= ufoImgGetU32(yfa
);
1228 if ((oyfa
& UFO_ADDR_TEMP_BIT
) == 0) {
1230 if ((yfa
& UFO_ADDR_TEMP_BIT
) != 0) {
1231 yfa
= UFO_CFA_TO_PFA(UFO_NFA_TO_CFA(UFO_YFA_TO_NFA(oyfa
)));
1234 yfa
= UFO_CFA_TO_PFA(UFO_NFA_TO_CFA(UFO_YFA_TO_NFA(oyfa
)));
1237 yfa
= UFO_YFA_TO_WST(yfa
);
1246 //==========================================================================
1248 // ufoGetWordEndAddr
1250 //==========================================================================
1251 static uint32_t ufoGetWordEndAddr (const uint32_t cfa
) {
1253 return ufoGetWordEndAddrYFA(UFO_LFA_TO_YFA(UFO_CFA_TO_LFA(cfa
)));
1260 //==========================================================================
1266 // WARNING: this is SLOW!
1268 //==========================================================================
1269 static uint32_t ufoFindWordForIP (const uint32_t ip
) {
1272 // iterate over all words
1273 uint32_t xfa
= ufoImgGetU32(ufoAddrLastXFA
);
1275 while (res
== 0 && xfa
!= 0) {
1276 const uint32_t yfa
= UFO_XFA_TO_YFA(xfa
);
1277 const uint32_t wst
= UFO_YFA_TO_WST(yfa
);
1278 const uint32_t wend
= ufoGetWordEndAddrYFA(yfa
);
1279 if (ip
>= wst
&& ip
< wend
) {
1280 res
= UFO_YFA_TO_NFA(yfa
);
1282 xfa
= ufoImgGetU32(xfa
);
1291 //==========================================================================
1295 // return file name or `NULL`
1297 // WARNING: this is SLOW!
1299 //==========================================================================
1300 static const char *ufoFindFileForIP (uint32_t ip
, uint32_t *line
) {
1301 const char *res
= NULL
;
1302 if (ip
!= 0 && ufoDebugImageUsed
!= 0) {
1303 uint32_t lastfinfo
= 0u;
1304 uint32_t lastip
= 0u;
1305 uint32_t dbgpos
= 0u; // first item is always "next file record"
1306 while (res
== NULL
&& dbgpos
< ufoDebugImageUsed
) {
1307 const uint32_t ln
= *(const uint32_t *)(ufoDebugImage
+ dbgpos
); dbgpos
+= 4u;
1308 if (ln
== ~(uint32_t)0) {
1311 const uint32_t nlen
= *(const uint32_t *)(ufoDebugImage
+ dbgpos
); dbgpos
+= 4u;
1312 dbgpos
+= nlen
+ 1u;
1313 if ((dbgpos
& 0x03) != 0) dbgpos
= (dbgpos
| 0x03u
) + 1u;
1315 const uint32_t edp
= *(const uint32_t *)(ufoDebugImage
+ dbgpos
); dbgpos
+= 4u;
1316 if (ip
>= lastip
&& ip
< edp
) {
1317 if (line
) *line
= ln
;
1318 res
= (const char *)(ufoDebugImage
+ lastfinfo
+ 4u);
1328 //==========================================================================
1332 //==========================================================================
1333 UFO_FORCE_INLINE
void ufoBumpDP (uint32_t delta
) {
1334 uint32_t dp
= ufoImgGetU32(ufoAddrDPTemp
);
1336 dp
= ufoImgGetU32(ufoAddrDP
);
1337 if ((dp
& UFO_ADDR_SPECIAL_BITS_MASK
) == 0) ufoRecordDebug(dp
+ delta
);
1339 ufoImgPutU32(ufoAddrDP
, dp
);
1341 dp
= ufoImgGetU32(ufoAddrDPTemp
);
1342 if ((dp
& UFO_ADDR_SPECIAL_BITS_MASK
) == 0) ufoRecordDebug(dp
+ delta
);
1344 ufoImgPutU32(ufoAddrDPTemp
, dp
);
1349 //==========================================================================
1353 //==========================================================================
1354 UFO_FORCE_INLINE
void ufoImgEmitU8 (uint32_t value
) {
1355 ufoImgPutU8(UFO_GET_DP(), value
);
1360 //==========================================================================
1364 //==========================================================================
1365 UFO_FORCE_INLINE
void ufoImgEmitU32 (uint32_t value
) {
1366 ufoImgPutU32(UFO_GET_DP(), value
);
1371 #ifdef UFO_FAST_MEM_ACCESS
1373 //==========================================================================
1375 // ufoImgEmitU32_NoInline
1379 //==========================================================================
1380 UFO_FORCE_INLINE
void ufoImgEmitU32_NoInline (uint32_t value
) {
1381 ufoImgPutU32(UFO_GET_DP(), value
);
1387 //==========================================================================
1389 // ufoImgEmitU32_NoInline
1393 //==========================================================================
1394 UFO_DISABLE_INLINE
void ufoImgEmitU32_NoInline (uint32_t value
) {
1395 ufoImgPutU32(UFO_GET_DP(), value
);
1402 //==========================================================================
1406 // this understands handle addresses
1408 //==========================================================================
1409 UFO_FORCE_INLINE
uint32_t ufoImgGetU8Ext (uint32_t addr
) {
1410 if ((addr
& UFO_ADDR_HANDLE_BIT
) == 0) {
1411 return ufoImgGetU8(addr
);
1415 UFCALL(PAR_HANDLE_LOAD_BYTE
);
1421 //==========================================================================
1425 // this understands handle addresses
1427 //==========================================================================
1428 UFO_FORCE_INLINE
void ufoImgPutU8Ext (uint32_t addr
, uint32_t value
) {
1429 if ((addr
& UFO_ADDR_HANDLE_BIT
) == 0) {
1430 ufoImgPutU8(addr
, value
);
1435 UFCALL(PAR_HANDLE_STORE_BYTE
);
1440 //==========================================================================
1444 //==========================================================================
1445 UFO_FORCE_INLINE
void ufoImgEmitAlign (void) {
1446 while ((UFO_GET_DP() & 3) != 0) ufoImgEmitU8(0);
1450 //==========================================================================
1454 //==========================================================================
1455 UFO_FORCE_INLINE
void ufoResetTib (void) {
1456 if ((ufoDefTIB
& UFO_ADDR_HANDLE_BIT
) == 0) ufoFatal("default TIB is not allocated");
1457 UHandleInfo
*hh
= ufoGetHandle(ufoDefTIB
);
1458 if (hh
== NULL
) ufoFatal("default TIB is not allocated");
1459 if (hh
->size
== 0) {
1460 ufo_assert(hh
->data
== NULL
);
1461 hh
->data
= calloc(1, UFO_ADDR_HANDLE_OFS_MASK
+ 1);
1462 if (hh
->data
== NULL
) ufoFatal("out of memory for default TIB");
1463 hh
->size
= UFO_ADDR_HANDLE_OFS_MASK
+ 1;
1465 const uint32_t oldA
= ufoRegA
;
1466 ufoImgPutU32(ufoAddrTIBx
, ufoDefTIB
);
1467 ufoImgPutU32(ufoAddrINx
, 0);
1468 ufoRegA
= ufoDefTIB
;
1469 ufoPush(0); // value
1470 ufoPush(0); // offset
1471 UFCALL(CPOKE_REGA_IDX
);
1476 //==========================================================================
1480 //==========================================================================
1481 UFO_DISABLE_INLINE
void ufoTibEnsureSize (uint32_t size
) {
1482 if (size
> 1024u * 1024u * 256u) ufoFatal("TIB size too big");
1483 const uint32_t tib
= ufoImgGetU32(ufoAddrTIBx
);
1484 if ((tib
& UFO_ADDR_HANDLE_BIT
) == 0) {
1485 ufoFatal("cannot resize TIB, TIB is not a handle");
1487 UHandleInfo
*hh
= ufoGetHandle(tib
);
1489 ufoFatal("cannot resize TIB, TIB is not a handle");
1491 if (hh
->size
< size
) {
1492 const uint32_t newsz
= (size
| 0xfffU
) + 1u;
1493 uint8_t *nx
= realloc(hh
->data
, newsz
);
1494 if (nx
== NULL
) ufoFatal("out of memory for restored TIB");
1501 //==========================================================================
1505 //==========================================================================
1506 UFO_DISABLE_INLINE
uint32_t ufoTibGetSize (void) {
1507 const uint32_t tib
= ufoImgGetU32(ufoAddrTIBx
);
1508 if ((tib
& UFO_ADDR_HANDLE_BIT
) == 0) {
1509 ufoFatal("cannot query TIB, TIB is not a handle");
1511 UHandleInfo
*hh
= ufoGetHandle(tib
);
1513 ufoFatal("cannot query TIB, TIB is not a handle");
1519 //==========================================================================
1523 //==========================================================================
1524 UFO_FORCE_INLINE
uint8_t ufoTibPeekCh (void) {
1525 return (uint8_t)ufoImgGetU8Ext(ufoImgGetU32(ufoAddrTIBx
) + ufoImgGetU32(ufoAddrINx
));
1529 //==========================================================================
1533 //==========================================================================
1534 UFO_FORCE_INLINE
uint8_t ufoTibPeekChOfs (uint32_t ofs
) {
1535 const uint32_t tib
= ufoImgGetU32(ufoAddrTIBx
);
1536 if (ofs
<= UFO_ADDR_HANDLE_OFS_MASK
|| (tib
& UFO_ADDR_HANDLE_BIT
) == 0) {
1537 return (uint8_t)ufoImgGetU8Ext(tib
+ ufoImgGetU32(ufoAddrINx
) + ofs
);
1544 //==========================================================================
1548 //==========================================================================
1549 UFO_DISABLE_INLINE
void ufoTibPokeChOfs (uint8_t ch
, uint32_t ofs
) {
1550 const uint32_t oldA
= ufoRegA
;
1551 ufoRegA
= ufoImgGetU32(ufoAddrTIBx
);
1553 ufoPush(ufoImgGetU32(ufoAddrINx
) + ofs
);
1554 UFCALL(CPOKE_REGA_IDX
);
1559 //==========================================================================
1563 //==========================================================================
1564 UFO_FORCE_INLINE
uint8_t ufoTibGetCh (void) {
1565 const uint8_t ch
= ufoTibPeekCh();
1566 if (ch
) ufoImgPutU32(ufoAddrINx
, ufoImgGetU32(ufoAddrINx
) + 1u);
1571 //==========================================================================
1575 //==========================================================================
1576 UFO_FORCE_INLINE
void ufoTibSkipCh (void) {
1577 (void)ufoTibGetCh();
1581 // ////////////////////////////////////////////////////////////////////////// //
1582 // native CFA implementations
1585 //==========================================================================
1589 //==========================================================================
1590 static void ufoDoForth (uint32_t pfa
) {
1596 //==========================================================================
1600 //==========================================================================
1601 static void ufoDoVariable (uint32_t pfa
) {
1606 //==========================================================================
1610 //==========================================================================
1611 static void ufoDoValue (uint32_t pfa
) {
1612 ufoPush(ufoImgGetU32(pfa
));
1616 //==========================================================================
1620 //==========================================================================
1621 static void ufoDoConst (uint32_t pfa
) {
1622 ufoPush(ufoImgGetU32(pfa
));
1626 //==========================================================================
1630 //==========================================================================
1631 static void ufoDoDefer (uint32_t pfa
) {
1632 const uint32_t cfa
= ufoImgGetU32(pfa
);
1640 //==========================================================================
1644 //==========================================================================
1645 static void ufoDoVoc (uint32_t pfa
) {
1646 ufoImgPutU32(ufoAddrContext
, ufoImgGetU32(pfa
));
1650 //==========================================================================
1654 //==========================================================================
1655 static void ufoDoCreate (uint32_t pfa
) {
1660 //==========================================================================
1664 // this also increments last used file id
1666 //==========================================================================
1667 static void ufoPushInFile (void) {
1668 if (ufoFileStackPos
>= UFO_MAX_NESTED_INCLUDES
) ufoFatal("too many includes");
1669 UFOFileStackEntry
*stk
= &ufoFileStack
[ufoFileStackPos
];
1670 stk
->fl
= ufoInFile
;
1671 stk
->fname
= ufoInFileName
;
1672 stk
->fline
= ufoInFileLine
;
1673 stk
->id
= ufoFileId
;
1674 stk
->incpath
= (ufoLastIncPath
? strdup(ufoLastIncPath
) : NULL
);
1675 ufoFileStackPos
+= 1;
1677 ufoInFileName
= NULL
;
1679 ufoLastUsedFileId
+= 1;
1680 ufo_assert(ufoLastUsedFileId
!= 0); // just in case ;-)
1681 //ufoLastIncPath = NULL;
1685 //==========================================================================
1687 // ufoWipeIncludeStack
1689 //==========================================================================
1690 static void ufoWipeIncludeStack (void) {
1691 if (ufoInFileName
) { free(ufoInFileName
); ufoInFileName
= NULL
; }
1692 if (ufoInFile
) { fclose(ufoInFile
); ufoInFile
= NULL
; }
1693 if (ufoLastIncPath
) { free(ufoLastIncPath
); ufoLastIncPath
= NULL
; }
1694 while (ufoFileStackPos
!= 0) {
1695 ufoFileStackPos
-= 1;
1696 UFOFileStackEntry
*stk
= &ufoFileStack
[ufoFileStackPos
];
1697 if (stk
->fl
) fclose(stk
->fl
);
1698 if (stk
->fname
) free(stk
->fname
);
1699 if (stk
->incpath
) free(stk
->incpath
);
1704 //==========================================================================
1708 //==========================================================================
1709 static void ufoPopInFile (void) {
1710 if (ufoFileStackPos
== 0) ufoFatal("trying to pop include from empty stack");
1711 if (ufoInFileName
) { free(ufoInFileName
); ufoInFileName
= NULL
; }
1712 if (ufoInFile
) { fclose(ufoInFile
); ufoInFile
= NULL
; }
1713 if (ufoLastIncPath
) { free(ufoLastIncPath
); ufoLastIncPath
= NULL
; }
1714 ufoFileStackPos
-= 1;
1715 UFOFileStackEntry
*stk
= &ufoFileStack
[ufoFileStackPos
];
1716 ufoInFile
= stk
->fl
;
1717 ufoInFileName
= stk
->fname
;
1718 ufoInFileLine
= stk
->fline
;
1719 ufoLastIncPath
= stk
->incpath
;
1720 ufoFileId
= stk
->id
;
1722 #ifdef UFO_DEBUG_INCLUDE
1723 if (ufoInFileName
== NULL
) {
1724 fprintf(stderr
, "INC-POP: no more files.\n");
1726 fprintf(stderr
, "INC-POP: fname: %s\n", ufoInFileName
);
1732 //==========================================================================
1736 //==========================================================================
1737 void ufoDeinit (void) {
1738 #ifdef UFO_DEBUG_DEBUG
1739 fprintf(stderr
, "UFO: debug image used: %u; size: %u\n",
1740 ufoDebugImageUsed
, ufoDebugImageSize
);
1741 ufoDumpDebugImage();
1744 free(ufoDebugImage
);
1745 ufoDebugImage
= NULL
;
1746 ufoDebugImageUsed
= 0;
1747 ufoDebugImageSize
= 0;
1749 ufoDebugLastFRecAddr
= 0;
1753 ufoClearCondDefines();
1754 ufoWipeIncludeStack();
1757 for (uint32_t f
= 0; f
< ufoHandlesUsed
; f
+= 1) {
1758 UHandleInfo
*hh
= ufoHandles
[f
];
1760 if (hh
->data
!= NULL
) free(hh
->data
);
1764 if (ufoHandles
!= NULL
) free(ufoHandles
);
1765 ufoHandles
= NULL
; ufoHandlesUsed
= 0; ufoHandlesAlloted
= 0;
1766 ufoHandleFreeList
= NULL
;
1770 // release all includes
1772 if (ufoInFileName
) free(ufoInFileName
);
1773 if (ufoLastIncPath
) free(ufoLastIncPath
);
1774 ufoInFileName
= NULL
; ufoLastIncPath
= NULL
;
1778 ufoForthCFAs
= NULL
;
1786 ufoImageTemp
= NULL
;
1787 ufoImageTempSize
= 0;
1790 ufoSP
= 0; ufoRP
= 0; ufoRPTop
= 0;
1791 ufoLP
= 0; ufoLBP
= 0;
1792 ufoMode
= UFO_MODE_NATIVE
;
1794 ufoForthVocId
= 0; ufoCompilerVocId
= 0;
1798 ufoCurrState
= NULL
;
1799 ufoYieldedState
= NULL
;
1800 ufoDebuggerState
= NULL
;
1801 for (uint32_t fidx
= 0; fidx
< (uint32_t)(UFO_MAX_STATES
/32); fidx
+= 1u) {
1802 uint32_t bmp
= ufoStateUsedBitmap
[fidx
];
1804 uint32_t stid
= fidx
* 32u;
1806 if ((bmp
& 0x01) != 0) ufoFreeState(ufoStateMap
[stid
]);
1807 stid
+= 1u; bmp
>>= 1;
1812 ufoAddrTIBx
= 0; ufoAddrINx
= 0; ufoDefTIB
= 0;
1814 ufoLastEmitWasCR
= 1;
1816 ufoClearCondDefines();
1820 //==========================================================================
1822 // ufoDumpWordHeader
1824 //==========================================================================
1825 __attribute__((unused
)) static void ufoDumpWordHeader (const uint32_t lfa
) {
1826 fprintf(stderr
, "=== WORD: LFA: 0x%08x ===\n", lfa
);
1828 fprintf(stderr
, " (DFA): 0x%08x\n", ufoImgGetU32(UFO_LFA_TO_DFA(lfa
)));
1829 fprintf(stderr
, " (XFA): 0x%08x\n", ufoImgGetU32(UFO_LFA_TO_XFA(lfa
)));
1830 fprintf(stderr
, " (YFA): 0x%08x\n", ufoImgGetU32(UFO_LFA_TO_YFA(lfa
)));
1831 fprintf(stderr
, " (BFA): 0x%08x\n", ufoImgGetU32(UFO_LFA_TO_BFA(lfa
)));
1832 fprintf(stderr
, " (LFA): 0x%08x\n", ufoImgGetU32(lfa
));
1833 fprintf(stderr
, " (NHH): 0x%08x\n", ufoImgGetU32(UFO_LFA_TO_NHASH(lfa
)));
1834 const uint32_t cfa
= UFO_LFA_TO_CFA(lfa
);
1835 fprintf(stderr
, " CFA: 0x%08x\n", cfa
);
1836 fprintf(stderr
, " PFA: 0x%08x\n", UFO_CFA_TO_PFA(cfa
));
1837 fprintf(stderr
, " (CFA): 0x%08x\n", ufoImgGetU32(cfa
));
1838 const uint32_t nfa
= UFO_LFA_TO_NFA(lfa
);
1839 const uint32_t nlen
= ufoImgGetU8(nfa
);
1840 fprintf(stderr
, " NFA: 0x%08x (nlen: %u)\n", nfa
, nlen
);
1841 const uint32_t flags
= ufoImgGetU32(nfa
);
1842 fprintf(stderr
, " FLAGS: 0x%08x\n", flags
);
1843 if ((flags
& 0xffff0000U
) != 0) {
1844 fprintf(stderr
, " FLAGS:");
1845 if (flags
& UFW_FLAG_IMMEDIATE
) fprintf(stderr
, " IMM");
1846 if (flags
& UFW_FLAG_SMUDGE
) fprintf(stderr
, " SMUDGE");
1847 if (flags
& UFW_FLAG_NORETURN
) fprintf(stderr
, " NORET");
1848 if (flags
& UFW_FLAG_HIDDEN
) fprintf(stderr
, " HIDDEN");
1849 if (flags
& UFW_FLAG_CBLOCK
) fprintf(stderr
, " CBLOCK");
1850 if (flags
& UFW_FLAG_VOCAB
) fprintf(stderr
, " VOCAB");
1851 if (flags
& UFW_FLAG_SCOLON
) fprintf(stderr
, " SCOLON");
1852 if (flags
& UFW_FLAG_PROTECTED
) fprintf(stderr
, " PROTECTED");
1853 fputc('\n', stderr
);
1855 if ((flags
& 0xff00U
) != 0) {
1856 fprintf(stderr
, " ARGS: ");
1857 switch (flags
& UFW_WARG_MASK
) {
1858 case UFW_WARG_NONE
: fprintf(stderr
, "NONE"); break;
1859 case UFW_WARG_BRANCH
: fprintf(stderr
, "BRANCH"); break;
1860 case UFW_WARG_LIT
: fprintf(stderr
, "LIT"); break;
1861 case UFW_WARG_C4STRZ
: fprintf(stderr
, "C4STRZ"); break;
1862 case UFW_WARG_CFA
: fprintf(stderr
, "CFA"); break;
1863 case UFW_WARG_CBLOCK
: fprintf(stderr
, "CBLOCK"); break;
1864 case UFW_WARG_VOCID
: fprintf(stderr
, "VOCID"); break;
1865 case UFW_WARG_C1STRZ
: fprintf(stderr
, "C1STRZ"); break;
1866 default: fprintf(stderr
, "wtf?!"); break;
1868 fputc('\n', stderr
);
1870 fprintf(stderr
, " BACKLEN: %u (nfa at 0x%08x)\n", ufoImgGetU8(cfa
- 1u), UFO_CFA_TO_NFA(cfa
));
1871 fprintf(stderr
, " NAME(%u): ", nlen
);
1872 for (uint32_t f
= 0; f
< nlen
; f
+= 1) {
1873 const uint8_t ch
= ufoImgGetU8(nfa
+ 4u + f
);
1874 if (ch
<= 32 || ch
>= 127) {
1875 fprintf(stderr
, "\\x%02x", ch
);
1877 fprintf(stderr
, "%c", (char)ch
);
1880 fprintf(stderr
, "\n");
1881 ufo_assert(UFO_CFA_TO_LFA(cfa
) == lfa
);
1886 //==========================================================================
1892 //==========================================================================
1893 static uint32_t ufoVocCheckName (uint32_t lfa
, const void *wname
, uint32_t wnlen
, uint32_t hash
,
1897 #ifdef UFO_DEBUG_FIND_WORD
1898 fprintf(stderr
, "CHECK-NAME: %.*s; LFA: 0x%08x; hash: 0x%08x (wname: 0x%08x)\n",
1899 (unsigned) wnlen
, (const char *)wname
,
1900 lfa
, (lfa
!= 0 ? ufoImgGetU32(UFO_LFA_TO_NHASH(lfa
)) : 0), hash
);
1901 ufoDumpWordHeader(lfa
);
1903 if (lfa
!= 0 && ufoImgGetU32(UFO_LFA_TO_NHASH(lfa
)) == hash
) {
1904 const uint32_t lenflags
= ufoImgGetU32(UFO_LFA_TO_NFA(lfa
));
1905 if ((lenflags
& UFW_FLAG_SMUDGE
) == 0 &&
1906 (allowvochid
|| (lenflags
& UFW_FLAG_HIDDEN
) == 0))
1908 const uint32_t nlen
= lenflags
&0xffU
;
1909 if (nlen
== wnlen
) {
1910 uint32_t naddr
= UFO_LFA_TO_NFA(lfa
) + 4u;
1912 while (pos
< nlen
) {
1913 uint8_t c0
= ((const unsigned char *)wname
)[pos
];
1914 if (c0
>= 'a' && c0
<= 'z') c0
= c0
- 'a' + 'A';
1915 uint8_t c1
= ufoImgGetU8(naddr
+ pos
);
1916 if (c1
>= 'a' && c1
<= 'z') c1
= c1
- 'a' + 'A';
1917 if (c0
!= c1
) break;
1923 res
= UFO_ALIGN4(naddr
);
1932 //==========================================================================
1938 //==========================================================================
1939 static uint32_t ufoFindWordInVoc (const void *wname
, uint32_t wnlen
, uint32_t hash
,
1940 uint32_t vocid
, int allowvochid
)
1943 if (wname
== NULL
) ufo_assert(wnlen
== 0);
1944 if (wnlen
!= 0 && vocid
!= 0) {
1945 if (hash
== 0) hash
= joaatHashBufCI(wname
, wnlen
);
1946 #if defined(UFO_DEBUG_FIND_WORD) || defined(UFO_DEBUG_FIND_WORD_IN_VOC)
1947 fprintf(stderr
, "IN-VOC: %.*s; VOCID: 0x%08x; whash: 0x%08x; htbl[0]: 0x%08x\n",
1948 (unsigned) wnlen
, (const char *)wname
,
1949 vocid
, hash
, ufoImgGetU32(vocid
+ UFW_VOCAB_OFS_HTABLE
));
1951 const uint32_t htbl
= vocid
+ UFW_VOCAB_OFS_HTABLE
;
1952 if (ufoImgGetU32(htbl
) != UFO_NO_HTABLE_FLAG
) {
1953 // hash table present, use it
1954 uint32_t bfa
= htbl
+ (hash
% (uint32_t)UFO_HASHTABLE_SIZE
) * 4u;
1955 bfa
= ufoImgGetU32(bfa
);
1956 while (res
== 0 && bfa
!= 0) {
1957 #if defined(UFO_DEBUG_FIND_WORD) || defined(UFO_DEBUG_FIND_WORD_IN_VOC)
1958 fprintf(stderr
, "IN-VOC: bfa: 0x%08x\n", bfa
);
1960 res
= ufoVocCheckName(UFO_BFA_TO_LFA(bfa
), wname
, wnlen
, hash
, allowvochid
);
1961 bfa
= ufoImgGetU32(bfa
);
1964 // no hash table, use linear search
1965 uint32_t lfa
= vocid
+ UFW_VOCAB_OFS_LATEST
;
1966 lfa
= ufoImgGetU32(lfa
);
1967 while (res
== 0 && lfa
!= 0) {
1968 res
= ufoVocCheckName(lfa
, wname
, wnlen
, hash
, allowvochid
);
1969 lfa
= ufoImgGetU32(lfa
);
1977 //==========================================================================
1981 // return part after the colon, or `NULL`
1983 //==========================================================================
1984 static const void *ufoFindColon (const void *wname
, uint32_t wnlen
) {
1985 const void *res
= NULL
;
1987 ufo_assert(wname
!= NULL
);
1988 const char *str
= (const char *)wname
;
1989 while (wnlen
!= 0 && str
[0] != ':') {
1990 str
+= 1; wnlen
-= 1;
1993 res
= (const void *)(str
+ 1); // skip colon
2000 //==========================================================================
2002 // ufoFindWordInVocAndParents
2004 //==========================================================================
2005 static uint32_t ufoFindWordInVocAndParents (const void *wname
, uint32_t wnlen
, uint32_t hash
,
2006 uint32_t vocid
, int allowvochid
)
2009 if (hash
== 0) hash
= joaatHashBufCI(wname
, wnlen
);
2010 while (res
== 0 && vocid
!= 0) {
2011 res
= ufoFindWordInVoc(wname
, wnlen
, hash
, vocid
, allowvochid
);
2012 vocid
= ufoImgGetU32(vocid
+ UFW_VOCAB_OFS_PARENT
);
2018 //==========================================================================
2020 // ufoFindWordNameRes
2022 // find with name resolution
2026 //==========================================================================
2027 static uint32_t ufoFindWordNameRes (const void *wname
, uint32_t wnlen
) {
2029 if (wnlen
!= 0 && *(const char *)wname
!= ':') {
2030 ufo_assert(wname
!= NULL
);
2032 const void *stx
= wname
;
2033 wname
= ufoFindColon(wname
, wnlen
);
2034 if (wname
!= NULL
) {
2035 // look in all vocabs (excluding hidden ones)
2036 uint32_t xlen
= (uint32_t)(ptrdiff_t)(wname
- stx
) - 1u;
2037 ufo_assert(xlen
> 0 && xlen
< 255);
2038 uint32_t xhash
= joaatHashBufCI(stx
, xlen
);
2039 uint32_t voclink
= ufoImgGetU32(ufoAddrVocLink
);
2040 #ifdef UFO_DEBUG_FIND_WORD_COLON
2041 fprintf(stderr
, "COLON-FIND: first voc: {%.*s}; xhash=0x%08x; voc-link: 0x%08x\n",
2042 (unsigned)xlen
, (const char *)stx
, xhash
, voclink
);
2044 while (res
== 0 && voclink
!= 0) {
2045 const uint32_t vhdraddr
= voclink
- UFW_VOCAB_OFS_VOCLINK
+ UFW_VOCAB_OFS_HEADER
;
2046 const uint32_t vhdr
= ufoImgGetU32(vhdraddr
);
2048 res
= ufoVocCheckName(UFO_NFA_TO_LFA(vhdr
), stx
, xlen
, xhash
, 0);
2050 if (res
== 0) voclink
= ufoImgGetU32(voclink
);
2053 uint32_t vocid
= voclink
- UFW_VOCAB_OFS_VOCLINK
;
2054 ufo_assert(voclink
!= 0);
2056 #ifdef UFO_DEBUG_FIND_WORD_COLON
2057 fprintf(stderr
, "searching {%.*s}(%u) in {%.*s}\n",
2058 (unsigned)wnlen
, wname
, wnlen
, (unsigned)xlen
, stx
);
2060 while (res
!= 0 && wname
!= NULL
) {
2062 wname
= ufoFindColon(wname
, wnlen
);
2063 if (wname
== NULL
) xlen
= wnlen
; else xlen
= (uint32_t)(ptrdiff_t)(wname
- stx
) - 1u;
2064 ufo_assert(xlen
> 0 && xlen
< 255);
2065 res
= ufoFindWordInVocAndParents(stx
, xlen
, 0, vocid
, 1);
2068 if (wname
!= NULL
) {
2069 // it should be a vocabulary
2070 const uint32_t nfa
= UFO_CFA_TO_NFA(res
);
2071 if ((ufoImgGetU32(nfa
) & UFW_FLAG_VOCAB
) != 0) {
2072 vocid
= ufoImgGetU32(UFO_CFA_TO_PFA(res
)); // pfa points to vocabulary
2087 //==========================================================================
2091 // doesn't look in CURRENT, does name resolution ("a:b" is word "b" in "a")
2095 //==========================================================================
2096 static uint32_t ufoFindWord (const char *wname
) {
2098 if (wname
&& wname
[0] != 0) {
2099 const size_t wnlen
= strlen(wname
);
2100 ufo_assert(wnlen
< 8192);
2101 uint32_t ctx
= ufoImgGetU32(ufoAddrContext
);
2102 const uint32_t hash
= joaatHashBufCI(wname
, (uint32_t)wnlen
);
2104 //fprintf(stderr, "FIND-WORD: whash: 0x%08x; name:{%s}\n", hash, wname);
2106 // first search in context
2107 res
= ufoFindWordInVocAndParents(wname
, (uint32_t)wnlen
, hash
, ctx
, (ctx
== ufoImgGetU32(ufoAddrCurrent
)));
2109 // now try vocabulary stack
2110 uint32_t vstp
= ufoVSP
;
2111 while (res
== 0 && vstp
!= 0) {
2113 ctx
= ufoVocStack
[vstp
];
2114 res
= ufoFindWordInVocAndParents(wname
, (uint32_t)wnlen
, hash
, ctx
, (ctx
== ufoImgGetU32(ufoAddrCurrent
)));
2117 // if not found, try name resolution
2118 if (res
== 0) res
= ufoFindWordNameRes(wname
, (uint32_t)wnlen
);
2125 //==========================================================================
2127 // ufoCreateWordHeader
2129 // create word header up to CFA, link to the current dictionary
2131 //==========================================================================
2132 static void ufoCreateWordHeader (const char *wname
, uint32_t flags
) {
2133 if (wname
== NULL
) wname
= "";
2134 const size_t wnlen
= strlen(wname
);
2135 ufo_assert(wnlen
< UFO_MAX_WORD_LENGTH
);
2136 const uint32_t hash
= joaatHashBufCI(wname
, (uint32_t)wnlen
);
2137 const uint32_t curr
= ufoImgGetU32(ufoAddrCurrent
);
2138 ufo_assert(curr
!= 0);
2140 if (wnlen
!= 0 && ufoImgGetU32(ufoAddrRedefineWarning
) != UFO_REDEF_WARN_DONT_CARE
) {
2141 const uint32_t cfa
= ufoFindWordInVoc(wname
, wnlen
, hash
, curr
, 1);
2143 const uint32_t nfa
= UFO_CFA_TO_NFA(cfa
);
2144 const uint32_t flags
= ufoImgGetU32(nfa
);
2145 if ((flags
& UFW_FLAG_PROTECTED
) != 0) {
2146 ufoFatal("trying to redefine protected word '%s'", wname
);
2147 } else if (ufoImgGetU32(ufoAddrRedefineWarning
) != UFO_REDEF_WARN_NONE
) {
2148 ufoWarning("redefining word '%s'", wname
);
2152 //fprintf(stderr, "000: HERE: 0x%08x\n", UFO_GET_DP());
2153 const uint32_t bkt
= (hash
% (uint32_t)UFO_HASHTABLE_SIZE
) * 4u;
2154 const uint32_t htbl
= curr
+ UFW_VOCAB_OFS_HTABLE
;
2156 ufoImgEmitU32(0); // dfa
2157 const uint32_t xfaAddr
= UFO_GET_DP();
2158 if ((xfaAddr
& UFO_ADDR_TEMP_BIT
) == 0) {
2159 // link previous yfa here
2160 const uint32_t lastxfa
= ufoImgGetU32(ufoAddrLastXFA
);
2161 // fix YFA of the previous word
2163 ufoImgPutU32(UFO_XFA_TO_YFA(lastxfa
), UFO_XFA_TO_YFA(xfaAddr
));
2165 // our XFA points to the previous XFA
2166 ufoImgEmitU32(lastxfa
); // xfa
2168 ufoImgPutU32(ufoAddrLastXFA
, xfaAddr
);
2170 ufoImgEmitU32(0); // xfa
2172 ufoImgEmitU32(0); // yfa
2173 // bucket link (bfa)
2174 if (wnlen
== 0 || ufoImgGetU32(htbl
) == UFO_NO_HTABLE_FLAG
) {
2177 #ifdef UFO_DEBUG_DUMP_NEW_HEADERS
2178 fprintf(stderr
, "NEW HEADER: %s; curr: 0x%08x; htbl: 0x%08x; bkt: 0x%08x\n",
2179 wname
, curr
, htbl
, bkt
);
2180 fprintf(stderr
, " [bkt]: 0x%08x; nbk: 0x%08x\n", ufoImgGetU32(htbl
+ bkt
), UFO_GET_DP());
2182 // bfa points to bfa
2183 const uint32_t bfa
= UFO_GET_DP();
2184 ufoImgEmitU32(ufoImgGetU32(htbl
+ bkt
));
2185 ufoImgPutU32(htbl
+ bkt
, bfa
);
2188 const uint32_t lfa
= UFO_GET_DP();
2189 ufoImgEmitU32(ufoImgGetU32(curr
+ UFW_VOCAB_OFS_LATEST
));
2191 ufoImgPutU32(curr
+ UFW_VOCAB_OFS_LATEST
, lfa
);
2193 ufoImgEmitU32(hash
);
2195 const uint32_t nfa
= UFO_GET_DP();
2196 ufoImgEmitU32(((uint32_t)wnlen
&0xffU
) | (flags
& 0xffffff00U
));
2197 const uint32_t nstart
= UFO_GET_DP();
2199 for (size_t f
= 0; f
< wnlen
; f
+= 1) {
2200 ufoImgEmitU8(((const unsigned char *)wname
)[f
]);
2202 while ((UFO_GET_DP() & 3) != 3) ufoImgEmitU8(0);
2203 const uint32_t nend
= UFO_GET_DP(); // length byte itself is not included
2204 // name length, again
2205 ufo_assert(nend
- nstart
<= 255);
2206 ufoImgEmitU8((uint8_t)(nend
- nstart
));
2207 ufo_assert((UFO_GET_DP() & 3) == 0);
2208 ufo_assert(UFO_CFA_TO_NFA(UFO_GET_DP()) == nfa
);
2209 if ((nend
& UFO_ADDR_SPECIAL_BITS_MASK
) == 0) ufoRecordDebug(nend
);
2210 #ifdef UFO_DEBUG_DUMP_NEW_HEADERS
2211 fprintf(stderr
, "*** NEW HEADER ***\n");
2212 fprintf(stderr
, "CFA: 0x%08x\n", UFO_GET_DP());
2213 fprintf(stderr
, "NSTART: 0x%08x\n", nstart
);
2214 fprintf(stderr
, "NEND: 0x%08x\n", nend
);
2215 fprintf(stderr
, "NLEN: %u (%u)\n", nend
- nstart
, ufoImgGetU8(UFO_GET_DP() - 1u));
2216 ufoDumpWordHeader(lfa
);
2219 fprintf(stderr
, "NEW WORD CFA 0x%08x: %s\n", UFO_GET_DP(), wname
);
2224 //==========================================================================
2228 //==========================================================================
2229 static void ufoDecompilePart (uint32_t addr
, uint32_t eaddr
, int indent
) {
2232 while (addr
< eaddr
) {
2233 uint32_t cfa
= ufoImgGetU32(addr
);
2234 for (int n
= 0; n
< indent
; n
+= 1) fputc(' ', fo
);
2235 fprintf(fo
, "%6u: 0x%08x: ", addr
, cfa
);
2236 uint32_t nfa
= UFO_CFA_TO_NFA(cfa
);
2237 uint32_t flags
= ufoImgGetU32(nfa
);
2238 //fprintf(fo, "[0x%08x] ", flags & UFW_WARG_MASK);
2239 uint32_t nlen
= flags
& 0xffU
;
2240 for (uint32_t f
= 0; f
< nlen
; f
+= 1) {
2241 const uint8_t ch
= ufoImgGetU8(nfa
+ 4u + f
);
2242 if (ch
<= 32 || ch
>= 127) {
2243 fprintf(fo
, "\\x%02x", ch
);
2245 fprintf(fo
, "%c", (char)ch
);
2249 switch (flags
& UFW_WARG_MASK
) {
2252 case UFW_WARG_BRANCH
:
2253 fprintf(fo
, " @%u", ufoImgGetU32(addr
)); addr
+= 4u;
2256 fprintf(fo
, " %u : %d : 0x%08x", ufoImgGetU32(addr
),
2257 (int32_t)ufoImgGetU32(addr
), ufoImgGetU32(addr
)); addr
+= 4u;
2259 case UFW_WARG_C4STRZ
:
2260 count
= ufoImgGetU32(addr
); addr
+= 4;
2262 fprintf(fo
, " str:");
2263 for (int f
= 0; f
< count
; f
+= 1) {
2264 const uint8_t ch
= ufoImgGetU8(addr
); addr
+= 1u;
2265 if (ch
<= 32 || ch
>= 127) {
2266 fprintf(fo
, "\\x%02x", ch
);
2268 fprintf(fo
, "%c", (char)ch
);
2271 addr
+= 1u; // skip zero byte
2272 addr
= UFO_ALIGN4(addr
);
2275 cfa
= ufoImgGetU32(addr
); addr
+= 4u;
2276 fprintf(fo
, " CFA:%u: ", cfa
);
2277 nfa
= UFO_CFA_TO_NFA(cfa
);
2278 nlen
= ufoImgGetU8(nfa
);
2279 for (uint32_t f
= 0; f
< nlen
; f
+= 1) {
2280 const uint8_t ch
= ufoImgGetU8(nfa
+ 4u + f
);
2281 if (ch
<= 32 || ch
>= 127) {
2282 fprintf(fo
, "\\x%02x", ch
);
2284 fprintf(fo
, "%c", (char)ch
);
2288 case UFW_WARG_CBLOCK
:
2289 fprintf(fo
, " CBLOCK:%u", ufoImgGetU32(addr
)); addr
+= 4u;
2291 case UFW_WARG_VOCID
:
2292 fprintf(fo
, " VOCID:%u", ufoImgGetU32(addr
)); addr
+= 4u;
2294 case UFW_WARG_C1STRZ
:
2295 count
= ufoImgGetU8(addr
); addr
+= 1;
2299 fprintf(fo, " ubyte:%u", ufoImgGetU8(addr)); addr += 1u;
2302 fprintf(fo, " sbyte:%u", ufoImgGetU8(addr)); addr += 1u;
2305 fprintf(fo, " uword:%u", ufoImgGetU16(addr)); addr += 2u;
2308 fprintf(fo, " sword:%u", ufoImgGetU16(addr)); addr += 2u;
2312 fprintf(fo
, " -- WTF?!\n");
2320 //==========================================================================
2324 //==========================================================================
2325 static void ufoDecompileWord (const uint32_t cfa
) {
2327 const uint32_t lfa
= UFO_CFA_TO_LFA(cfa
);
2328 fprintf(stdout
, "#### DECOMPILING CFA %u ###\n", cfa
);
2329 ufoDumpWordHeader(lfa
);
2330 const uint32_t yfa
= ufoGetWordEndAddr(cfa
);
2331 if (ufoImgGetU32(cfa
) == ufoDoForthCFA
) {
2332 fprintf(stdout
, "--- DECOMPILED CODE ---\n");
2333 ufoDecompilePart(UFO_CFA_TO_PFA(cfa
), yfa
, 0);
2334 fprintf(stdout
, "=======================\n");
2340 //==========================================================================
2342 // ufoBTShowWordName
2344 //==========================================================================
2345 static void ufoBTShowWordName (uint32_t nfa
) {
2347 uint32_t len
= ufoImgGetU8(nfa
); nfa
+= 4u;
2348 //fprintf(stderr, "(0x%08x)", ufoImgGetU32(nfa - 4u));
2350 uint8_t ch
= ufoImgGetU8(nfa
); nfa
+= 1u; len
-= 1u;
2351 if (ch
<= 32 || ch
>= 127) {
2352 fprintf(stderr
, "\\x%02x", ch
);
2354 fprintf(stderr
, "%c", (char)ch
);
2361 //==========================================================================
2365 //==========================================================================
2366 static void ufoBacktrace (uint32_t ip
) {
2367 // dump data stack (top 16)
2368 if (!ufoLastEmitWasCR
) { printf("\n"); ufoLastEmitWasCR
= 1; }
2371 fprintf(stderr
, "***UFO STACK DEPTH: %u\n", ufoSP
);
2372 uint32_t xsp
= ufoSP
;
2373 if (xsp
> 16) xsp
= 16;
2374 for (uint32_t sp
= 0; sp
< xsp
; ++sp
) {
2375 fprintf(stderr
, " %2u: 0x%08x %d\n", sp
,
2376 ufoDStack
[xsp
- sp
- 1], (int32_t)ufoDStack
[xsp
- sp
- 1]);
2378 if (ufoSP
> 16) fprintf(stderr
, " ...more...\n");
2380 // dump return stack (top 32)
2382 fprintf(stderr
, "***UFO RETURN STACK DEPTH: %u\n", ufoRP
);
2384 nfa
= ufoFindWordForIP(ip
);
2387 fprintf(stderr
, " **: %8u -- ", ip
);
2388 ufoBTShowWordName(nfa
);
2389 const char *fname
= ufoFindFileForIP(ip
, &fline
);
2390 if (fname
!= NULL
) { fprintf(stderr
, " (at %s:%u)", fname
, fline
); }
2391 fputc('\n', stderr
);
2394 uint32_t rp
= ufoRP
;
2395 uint32_t rscount
= 0;
2396 if (rp
> UFO_RSTACK_SIZE
) rp
= UFO_RSTACK_SIZE
;
2397 while (rscount
!= 32 && rp
!= 0) {
2399 const uint32_t val
= ufoRStack
[rp
];
2400 nfa
= ufoFindWordForIP(val
);
2402 fprintf(stderr
, " %2u: %8u -- ", ufoRP
- rp
- 1u, val
);
2403 ufoBTShowWordName(nfa
);
2404 fputc('\n', stderr
);
2406 fprintf(stderr
, " %2u: 0x%08x %d\n", ufoRP
- rp
- 1u, val
, (int32_t)val
);
2410 if (ufoRP
> 32) fprintf(stderr
, " ...more...\n");
2416 //==========================================================================
2420 //==========================================================================
2422 static void ufoDumpVocab (uint32_t vocid) {
2424 fprintf(stderr, "*** VOCID: 0x%08x ***\n", vocid);
2425 uint32_t vochdr = vocid + UFW_VOCAB_OFS_HEADER;
2426 vochdr = ufoImgGetU32(vochdr);
2428 fprintf(stderr, "--- HEADER ---\n");
2429 ufoDumpWordHeader(UFO_NFA_TO_LFA(vochdr));
2430 fprintf(stderr, "========\n");
2431 uint32_t htbl = vocid + UFW_VOCAB_OFS_HTABLE;
2432 if (ufoImgGetU32(htbl) != UFO_NO_HTABLE_FLAG) {
2433 fprintf(stderr, "--- HASH TABLE ---\n");
2434 for (int f = 0; f < UFO_HASHTABLE_SIZE; f += 1) {
2435 uint32_t bfa = ufoImgGetU32(htbl);
2437 fprintf(stderr, "**** %2d: 0x%08x\n", f, bfa);
2439 ufoDumpWordHeader(UFO_BFA_TO_LFA(bfa));
2440 bfa = ufoImgGetU32(bfa);
2452 // if set, this will be used when we are out of include files. intended for UrAsm.
2453 // return 0 if there is no more lines, otherwise the string should be copied
2454 // to buffer, `*fname` and `*fline` should be properly set.
2455 int (*ufoFileReadLine
) (void *buf
, size_t bufsize
, const char **fname
, int *fline
) = NULL
;
2458 //==========================================================================
2460 // ufoLoadNextUserLine
2462 //==========================================================================
2463 static int ufoLoadNextUserLine (void) {
2464 uint32_t tibPos
= 0;
2465 const char *fname
= NULL
;
2468 if (ufoFileReadLine
!= NULL
&& ufoFileReadLine(ufoCurrFileLine
, 510, &fname
, &fline
) != 0) {
2469 ufoCurrFileLine
[510] = 0;
2470 uint32_t slen
= (uint32_t)strlen(ufoCurrFileLine
);
2471 while (slen
!= 0 && (ufoCurrFileLine
[slen
- 1u] == 10 || ufoCurrFileLine
[slen
- 1u] == 13)) {
2474 if (tibPos
+ slen
+ 1u > UFO_ADDR_HANDLE_OFS_MASK
) {
2475 ufoFatal("input text line too long (at least %u bytes)", tibPos
+ slen
);
2477 ufoTibEnsureSize(tibPos
+ slen
+ 1u);
2478 for (uint32_t f
= 0; f
< slen
; f
+= 1) {
2479 ufoTibPokeChOfs(((const unsigned char *)ufoCurrFileLine
)[f
], tibPos
+ f
);
2481 ufoTibPokeChOfs(0, tibPos
+ slen
);
2483 if (fname
== NULL
) fname
= "<user>";
2484 if (ufoInFileName
== NULL
|| strcmp(ufoInFileName
, fname
) != 0) {
2485 free(ufoInFileName
);
2486 ufoInFileName
= strdup(fname
);
2487 if (ufoInFileName
== NULL
) ufoFatal("out of memory");
2489 ufoInFileLine
= fline
;
2497 //==========================================================================
2499 // ufoLoadNextLine_NativeMode
2501 // load next file line into TIB
2502 // always strips final '\n'
2504 // return 0 on EOF, 1 on success
2506 //==========================================================================
2507 static int ufoLoadNextLine (int crossInclude
) {
2509 uint32_t tibPos
= 0;
2512 if (ufoMode
== UFO_MODE_MACRO
) {
2513 //fprintf(stderr, "***MAC!\n");
2517 while (ufoInFile
!= NULL
&& !done
) {
2518 if (fgets(ufoCurrFileLine
, 510, ufoInFile
) != NULL
) {
2519 // check for a newline
2520 // if there is no newline char at the end, the string was truncated
2521 ufoCurrFileLine
[510] = 0;
2522 const uint32_t slen
= (uint32_t)strlen(ufoCurrFileLine
);
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 (slen
!= 0 && (ufoCurrFileLine
[slen
- 1u] == 13 || ufoCurrFileLine
[slen
- 1u] == 10)) {
2536 // continuation, nothing to do
2539 // if we read nothing, this is EOF
2540 if (tibPos
== 0 && crossInclude
) {
2541 // we read nothing, and allowed to cross include boundaries
2550 // eof, try user-supplied input
2551 if (ufoFileStackPos
== 0) {
2552 return ufoLoadNextUserLine();
2557 // if we read at least something, this is not EOF
2563 // ////////////////////////////////////////////////////////////////////////// //
2568 UFWORD(DUMP_STACK
) {
2569 if (!ufoLastEmitWasCR
) { printf("\n"); ufoLastEmitWasCR
= 1; }
2570 printf("***UFO STACK DEPTH: %u\n", ufoSP
);
2572 uint32_t sp
= ufoSP
;
2573 while (sp
!= 0 && left
!= 0) {
2575 printf(" %4u: 0x%08x %d\n", sp
, ufoDStack
[sp
], (int32_t)ufoDStack
[sp
]);
2577 if (sp
!= 0) printf("...more...\n");
2578 ufoLastEmitWasCR
= 1;
2582 UFWORD(UFO_BACKTRACE
) {
2583 if (!ufoLastEmitWasCR
) { printf("\n"); ufoLastEmitWasCR
= 1; }
2585 if (ufoInFile
!= NULL
) {
2586 fprintf(stderr
, "*** at file %s, line %d ***\n", ufoInFileName
, ufoInFileLine
);
2588 fprintf(stderr
, "*** somewhere in time ***\n");
2590 ufoBacktrace(ufoIP
);
2594 // ////////////////////////////////////////////////////////////////////////// //
2597 UFWORD(SP0_STORE
) { ufoSP
= 0; }
2602 if (ufoRP
!= ufoRPTop
) {
2604 // we need to push a dummy value
2605 ufoRPush(0xdeadf00d);
2611 // PAD is at the beginning of temp area
2613 ufoPush(UFO_ADDR_TEMP_BIT
);
2617 // ////////////////////////////////////////////////////////////////////////// //
2618 // peeks and pokes with address register
2629 UFWORD(REGA_STORE
) {
2633 // ////////////////////////////////////////////////////////////////////////// //
2634 // useful to work with handles and normal addreses uniformly
2639 UFWORD(CPEEK_REGA_IDX
) {
2640 if ((ufoRegA
& UFO_ADDR_HANDLE_BIT
) == 0) {
2641 const uint32_t idx
= ufoPop();
2642 const uint32_t newaddr
= ufoRegA
+ idx
;
2643 if ((ufoRegA
& UFO_ADDR_SPECIAL_BITS_MASK
) == (newaddr
& UFO_ADDR_SPECIAL_BITS_MASK
)) {
2644 ufoPush(ufoImgGetU8Ext(newaddr
));
2646 ufoFatal("address offset out of range; addr=0x%08x; offset=%u; res=0x%08x",
2647 ufoRegA
, idx
, newaddr
);
2651 UFCALL(PAR_HANDLE_LOAD_BYTE
);
2657 UFWORD(WPEEK_REGA_IDX
) {
2658 if ((ufoRegA
& UFO_ADDR_HANDLE_BIT
) == 0) {
2659 const uint32_t idx
= ufoPop();
2660 const uint32_t newaddr
= ufoRegA
+ idx
;
2661 if ((ufoRegA
& UFO_ADDR_SPECIAL_BITS_MASK
) == (newaddr
& UFO_ADDR_SPECIAL_BITS_MASK
) &&
2662 (ufoRegA
& UFO_ADDR_SPECIAL_BITS_MASK
) == ((newaddr
+ 1u) & UFO_ADDR_SPECIAL_BITS_MASK
))
2664 ufoPush(ufoImgGetU16(newaddr
));
2666 ufoFatal("address offset out of range; addr=0x%08x; offset=%u; res=0x%08x",
2667 ufoRegA
, idx
, newaddr
);
2671 UFCALL(PAR_HANDLE_LOAD_WORD
);
2677 UFWORD(PEEK_REGA_IDX
) {
2678 if ((ufoRegA
& UFO_ADDR_HANDLE_BIT
) == 0) {
2679 const uint32_t idx
= ufoPop();
2680 const uint32_t newaddr
= ufoRegA
+ idx
;
2681 if ((ufoRegA
& UFO_ADDR_SPECIAL_BITS_MASK
) == (newaddr
& UFO_ADDR_SPECIAL_BITS_MASK
) &&
2682 (ufoRegA
& UFO_ADDR_SPECIAL_BITS_MASK
) == ((newaddr
+ 3u) & UFO_ADDR_SPECIAL_BITS_MASK
))
2684 ufoPush(ufoImgGetU32(newaddr
));
2686 ufoFatal("address offset out of range; addr=0x%08x; offset=%u; res=0x%08x",
2687 ufoRegA
, idx
, newaddr
);
2691 UFCALL(PAR_HANDLE_LOAD_CELL
);
2697 UFWORD(CPOKE_REGA_IDX
) {
2698 if ((ufoRegA
& UFO_ADDR_HANDLE_BIT
) == 0) {
2699 const uint32_t idx
= ufoPop();
2700 const uint32_t newaddr
= ufoRegA
+ idx
;
2701 if ((ufoRegA
& UFO_ADDR_SPECIAL_BITS_MASK
) == (newaddr
& UFO_ADDR_SPECIAL_BITS_MASK
)) {
2702 const uint32_t value
= ufoPop();
2703 ufoImgPutU8(newaddr
, value
);
2705 ufoFatal("address offset out of range; addr=0x%08x; offset=%u; res=0x%08x",
2706 ufoRegA
, idx
, newaddr
);
2710 UFCALL(PAR_HANDLE_STORE_BYTE
);
2716 UFWORD(WPOKE_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 (ufoRegA
& UFO_ADDR_SPECIAL_BITS_MASK
) == ((newaddr
+ 1u) & UFO_ADDR_SPECIAL_BITS_MASK
))
2723 const uint32_t value
= ufoPop();
2724 ufoImgPutU16(newaddr
, value
);
2726 ufoFatal("address offset out of range; addr=0x%08x; offset=%u; res=0x%08x",
2727 ufoRegA
, idx
, newaddr
);
2731 UFCALL(PAR_HANDLE_STORE_WORD
);
2737 UFWORD(POKE_REGA_IDX
) {
2738 if ((ufoRegA
& UFO_ADDR_HANDLE_BIT
) == 0) {
2739 const uint32_t idx
= ufoPop();
2740 const uint32_t newaddr
= ufoRegA
+ idx
;
2741 if ((ufoRegA
& UFO_ADDR_SPECIAL_BITS_MASK
) == (newaddr
& UFO_ADDR_SPECIAL_BITS_MASK
) &&
2742 (ufoRegA
& UFO_ADDR_SPECIAL_BITS_MASK
) == ((newaddr
+ 3u) & UFO_ADDR_SPECIAL_BITS_MASK
))
2744 const uint32_t value
= ufoPop();
2745 ufoImgPutU32(newaddr
, value
);
2747 ufoFatal("address offset out of range; addr=0x%08x; offset=%u; res=0x%08x",
2748 ufoRegA
, idx
, newaddr
);
2752 UFCALL(PAR_HANDLE_STORE_CELL
);
2757 // ////////////////////////////////////////////////////////////////////////// //
2762 // ( addr -- value8 )
2764 ufoPush(ufoImgGetU8Ext(ufoPop()));
2768 // ( addr -- value16 )
2770 const uint32_t addr
= ufoPop();
2771 if ((addr
& UFO_ADDR_HANDLE_BIT
) == 0) {
2772 ufoPush(ufoImgGetU16(addr
));
2776 UFCALL(PAR_HANDLE_LOAD_WORD
);
2781 // ( addr -- value32 )
2783 const uint32_t addr
= ufoPop();
2784 if ((addr
& UFO_ADDR_HANDLE_BIT
) == 0) {
2785 ufoPush(ufoImgGetU32(addr
));
2789 UFCALL(PAR_HANDLE_LOAD_CELL
);
2796 const uint32_t addr
= ufoPop();
2797 const uint32_t val
= ufoPop();
2798 ufoImgPutU8Ext(addr
, val
);
2802 // ( val16 addr -- )
2804 const uint32_t addr
= ufoPop();
2805 const uint32_t val
= ufoPop();
2806 if ((addr
& UFO_ADDR_HANDLE_BIT
) == 0) {
2807 ufoImgPutU16(addr
, val
);
2812 UFCALL(PAR_HANDLE_STORE_WORD
);
2817 // ( val32 addr -- )
2819 const uint32_t addr
= ufoPop();
2820 const uint32_t val
= ufoPop();
2821 if ((addr
& UFO_ADDR_HANDLE_BIT
) == 0) {
2822 ufoImgPutU32(addr
, val
);
2827 UFCALL(PAR_HANDLE_STORE_CELL
);
2832 // ////////////////////////////////////////////////////////////////////////// //
2833 // dictionary emitters
2838 UFWORD(CCOMMA
) { const uint32_t val
= ufoPop(); ufoImgEmitU8(val
); }
2842 UFWORD(WCOMMA
) { const uint32_t val
= ufoPop(); ufoImgEmitU8(val
&0xffU
); ufoImgEmitU8((val
>> 8)&0xffU
); }
2846 UFWORD(COMMA
) { const uint32_t val
= ufoPop(); ufoImgEmitU32(val
); }
2849 // ////////////////////////////////////////////////////////////////////////// //
2856 const uint32_t v
= ufoImgGetU32(ufoIP
); ufoIP
+= 4;
2860 // (LITCFA) ( -- n )
2861 UFWORD(PAR_LITCFA
) {
2862 const uint32_t v
= ufoImgGetU32(ufoIP
); ufoIP
+= 4;
2866 // (LITVOCID) ( -- n )
2867 UFWORD(PAR_LITVOCID
) {
2868 const uint32_t v
= ufoImgGetU32(ufoIP
); ufoIP
+= 4;
2873 UFWORD(PAR_STRLIT8
) {
2874 const uint32_t count
= ufoImgGetU8(ufoIP
); ufoIP
+= 1;
2877 ufoIP
+= count
+ 1; // 1 for terminating 0
2879 ufoIP
= UFO_ALIGN4(ufoIP
);
2883 // ////////////////////////////////////////////////////////////////////////// //
2889 UFWORD(PAR_BRANCH
) {
2890 ufoIP
= ufoImgGetU32(ufoIP
);
2893 // (TBRANCH) ( flag )
2894 UFWORD(PAR_TBRANCH
) {
2896 ufoIP
= ufoImgGetU32(ufoIP
);
2902 // (0BRANCH) ( flag )
2903 UFWORD(PAR_0BRANCH
) {
2905 ufoIP
= ufoImgGetU32(ufoIP
);
2912 // ////////////////////////////////////////////////////////////////////////// //
2913 // execute words by CFA
2923 // EXECUTE-TAIL ( cfa )
2924 UFWORD(EXECUTE_TAIL
) {
2931 // ////////////////////////////////////////////////////////////////////////// //
2932 // word termination, locals support
2943 UFWORD(PAR_LENTER
) {
2944 // low byte of loccount is total number of locals
2945 // high byte is the number of args
2946 uint32_t lcount
= ufoImgGetU32(ufoIP
); ufoIP
+= 4u;
2947 uint32_t acount
= (lcount
>> 8) & 0xff;
2949 if (lcount
== 0 || lcount
< acount
) ufoFatal("invalid call to (L-ENTER)");
2950 if ((ufoLBP
!= 0 && ufoLBP
>= ufoLP
) || UFO_LSTACK_SIZE
- ufoLP
<= lcount
+ 2) {
2951 ufoFatal("out of locals stack");
2954 if (ufoLP
== 0) { ufoLP
= 1; newbp
= 1; } else newbp
= ufoLP
;
2955 //fprintf(stderr, "LP: %u; LBP: %u; locs: %u; word: %s\n", ufoLP, ufoLBP, fw->locs, fw->name);
2956 ufoLStack
[ufoLP
] = ufoLBP
; ufoLP
+= 1;
2957 ufoLBP
= newbp
; ufoLP
+= lcount
;
2960 while (newbp
!= ufoLBP
) {
2961 ufoLStack
[newbp
] = ufoPop();
2967 UFWORD(PAR_LLEAVE
) {
2968 if (ufoLBP
== 0) ufoFatal("(L-LEAVE) with empty locals stack");
2969 if (ufoLBP
>= ufoLP
) ufoFatal("(L-LEAVE) broken locals stack");
2971 ufoLBP
= ufoLStack
[ufoLBP
];
2975 //==========================================================================
2979 //==========================================================================
2980 UFO_FORCE_INLINE
void ufoLoadLocal (const uint32_t lidx
) {
2981 if (lidx
== 0 || lidx
>= UFO_LSTACK_SIZE
) ufoFatal("invalid local index");
2982 if (ufoLBP
== 0 || ufoLBP
>= ufoLP
|| ufoLP
- ufoLBP
<= lidx
) ufoFatal("invalid local index");
2983 ufoPush(ufoLStack
[ufoLBP
+ lidx
]);
2987 //==========================================================================
2991 //==========================================================================
2992 UFO_FORCE_INLINE
void ufoStoreLocal (const uint32_t lidx
) {
2993 const uint32_t value
= ufoPop();
2994 if (lidx
== 0 || lidx
>= UFO_LSTACK_SIZE
) ufoFatal("invalid local index");
2995 if (ufoLBP
== 0 || ufoLBP
>= ufoLP
|| ufoLP
- ufoLBP
<= lidx
) ufoFatal("invalid local index");
2996 ufoLStack
[ufoLBP
+ lidx
] = value
;
3002 UFWORD(PAR_LOCAL_LOAD
) { ufoLoadLocal(ufoPop()); }
3006 UFWORD(PAR_LOCAL_STORE
) { ufoStoreLocal(ufoPop()); }
3009 // ////////////////////////////////////////////////////////////////////////// //
3010 // stack manipulation
3016 UFWORD(DUP
) { ufoDup(); }
3018 // ( n -- n n ) | ( 0 -- 0 )
3019 UFWORD(QDUP
) { if (ufoPeek()) ufoDup(); }
3021 // ( n0 n1 -- n0 n1 n0 n1 )
3022 UFWORD(DDUP
) { ufo2Dup(); }
3025 UFWORD(DROP
) { ufoDrop(); }
3028 UFWORD(DDROP
) { ufo2Drop(); }
3030 // ( n0 n1 -- n1 n0 )
3031 UFWORD(SWAP
) { ufoSwap(); }
3033 // ( n0 n1 -- n1 n0 )
3034 UFWORD(DSWAP
) { ufo2Swap(); }
3036 // ( n0 n1 -- n0 n1 n0 )
3037 UFWORD(OVER
) { ufoOver(); }
3039 // ( n0 n1 -- n0 n1 n0 )
3040 UFWORD(DOVER
) { ufo2Over(); }
3042 // ( n0 n1 n2 -- n1 n2 n0 )
3043 UFWORD(ROT
) { ufoRot(); }
3045 // ( n0 n1 n2 -- n2 n0 n1 )
3046 UFWORD(NROT
) { ufoNRot(); }
3050 UFWORD(RDUP
) { ufoRDup(); }
3053 UFWORD(RDROP
) { ufoRDrop(); }
3057 UFWORD(DTOR
) { ufoRPush(ufoPop()); }
3060 UFWORD(RTOD
) { ufoPush(ufoRPop()); }
3063 UFWORD(RPEEK
) { ufoPush(ufoRPeek()); }
3069 const uint32_t n
= ufoPop();
3070 if (n
>= ufoSP
) ufoFatal("invalid PICK index %u", n
);
3071 ufoPush(ufoDStack
[ufoSP
- n
- 1u]);
3077 const uint32_t n
= ufoPop();
3078 if (n
>= ufoRP
- ufoRPTop
) ufoFatal("invalid RPICK index %u", n
);
3079 const uint32_t rp
= ufoRP
- n
- 1u;
3080 ufoPush(ufoRStack
[rp
]);
3086 const uint32_t n
= ufoPop();
3087 if (n
>= ufoSP
) ufoFatal("invalid ROLL index %u", n
);
3089 case 0: break; // do nothing
3090 case 1: ufoSwap(); break;
3091 case 2: ufoRot(); break;
3094 const uint32_t val
= ufoDStack
[ufoSP
- n
- 1u];
3095 for (uint32_t f
= ufoSP
- n
; f
< ufoSP
; f
+= 1) ufoDStack
[f
- 1] = ufoDStack
[f
];
3096 ufoDStack
[ufoSP
- 1u] = val
;
3105 const uint32_t n
= ufoPop();
3106 if (n
>= ufoRP
- ufoRPTop
) ufoFatal("invalid RROLL index %u", n
);
3108 const uint32_t rp
= ufoRP
- n
- 1u;
3109 const uint32_t val
= ufoRStack
[rp
];
3110 for (uint32_t f
= rp
+ 1u; f
< ufoRP
; f
+= 1u) ufoRStack
[f
- 1u] = ufoRStack
[f
];
3111 ufoRStack
[ufoRP
- 1u] = val
;
3116 // ( | a b -- | b a )
3118 const uint32_t b
= ufoRPop();
3119 const uint32_t a
= ufoRPop();
3120 ufoRPush(b
); ufoRPush(a
);
3124 // ( | a b -- | a b a )
3126 const uint32_t b
= ufoRPop();
3127 const uint32_t a
= ufoRPop();
3128 ufoRPush(a
); ufoRPush(b
); ufoRPush(a
);
3132 // ( | a b c -- | b c a )
3134 const uint32_t c
= ufoRPop();
3135 const uint32_t b
= ufoRPop();
3136 const uint32_t a
= ufoRPop();
3137 ufoRPush(b
); ufoRPush(c
); ufoRPush(a
);
3141 // ( | a b c -- | c a b )
3143 const uint32_t c
= ufoRPop();
3144 const uint32_t b
= ufoRPop();
3145 const uint32_t a
= ufoRPop();
3146 ufoRPush(c
); ufoRPush(a
); ufoRPush(b
);
3150 // ////////////////////////////////////////////////////////////////////////// //
3157 ufoPushBool(ufoLoadNextLine(1));
3162 UFWORD(REFILL_NOCROSS
) {
3163 ufoPushBool(ufoLoadNextLine(0));
3169 ufoPush(ufoImgGetU32(ufoAddrTIBx
) + ufoImgGetU32(ufoAddrINx
));
3174 UFWORD(TIB_PEEKCH
) {
3175 ufoPush(ufoTibPeekCh());
3180 UFWORD(TIB_PEEKCH_OFS
) {
3181 const uint32_t ofs
= ufoPop();
3182 ufoPush(ufoTibPeekChOfs(ofs
));
3188 ufoPush(ufoTibGetCh());
3193 UFWORD(TIB_SKIPCH
) {
3198 // ////////////////////////////////////////////////////////////////////////// //
3202 //==========================================================================
3206 //==========================================================================
3207 UFO_FORCE_INLINE
int ufoIsDelim (uint8_t ch
, uint8_t delim
) {
3208 return (delim
== 32 ? (ch
<= 32) : (ch
== delim
));
3213 // ( delim skip-leading-delim? -- addr count TRUE / FALSE )
3214 // does base TIB parsing; never copies anything.
3215 // as our reader is line-based, returns FALSE on EOL.
3216 // EOL is detected after skipping leading delimiters.
3217 // passing -1 as delimiter skips the whole line, and always returns FALSE.
3218 // trailing delimiter is always skipped.
3220 const uint32_t skipDelim
= ufoPop();
3221 const uint32_t delim
= ufoPop();
3224 if (delim
== 0 || delim
> 0xffU
) {
3226 while (ufoTibGetCh() != 0) {}
3229 ch
= ufoTibPeekCh();
3230 // skip initial delimiters
3232 while (ch
!= 0 && ufoIsDelim(ch
, delim
)) {
3234 ch
= ufoTibPeekCh();
3238 const uint32_t staddr
= ufoImgGetU32(ufoAddrTIBx
) + ufoImgGetU32(ufoAddrINx
);
3240 while (ch
!= 0 && !ufoIsDelim(ch
, delim
)) {
3243 ch
= ufoTibPeekCh();
3246 if (ch
!= 0) ufoTibSkipCh();
3257 // PARSE-SKIP-BLANKS
3259 UFWORD(PARSE_SKIP_BLANKS
) {
3260 uint8_t ch
= ufoTibPeekCh();
3261 while (ch
!= 0 && ch
<= 32) {
3263 ch
= ufoTibPeekCh();
3268 //==========================================================================
3270 // ufoParseMLComment
3272 // initial two chars are skipped
3274 //==========================================================================
3275 static void ufoParseMLComment (uint32_t allowMulti
, int nested
) {
3278 while (level
!= 0) {
3282 UFCALL(REFILL_NOCROSS
);
3283 if (ufoPop() == 0) ufoFatal("unexpected end of file in comment");
3285 ufoFatal("unexpected end of line in comment");
3288 ch1
= ufoTibPeekCh();
3289 if (nested
&& ch
== '(' && ch1
== '(') { ufoTibSkipCh(); level
+= 1; }
3290 else if (nested
&& ch
== ')' && ch1
== ')') { ufoTibSkipCh(); level
-= 1; }
3291 else if (!nested
&& ch
== '*' && ch1
== ')') { ufo_assert(level
== 1); ufoTibSkipCh(); level
= 0; }
3297 // (PARSE-SKIP-COMMENTS)
3298 // ( allow-multiline? -- )
3299 // skip all blanks and comments
3300 UFWORD(PAR_PARSE_SKIP_COMMENTS
) {
3301 const uint32_t allowMulti
= ufoPop();
3303 ch
= ufoTibPeekCh();
3305 fprintf(stderr
, "(PARSE-SKIP-COMMENTS): first-ch:'%c'\n", (char)ch
);
3310 ch
= ufoTibPeekCh();
3312 fprintf(stderr
, "(PARSE-SKIP-COMMENTS): blank-ch:'%c'\n", (char)ch
);
3314 } else if (ch
== '(') {
3316 fprintf(stderr
, "(PARSE-SKIP-COMMENTS): ch:'%c'; ch1:'%c' ('%c')\n", (char)ch
, (char)ch1
,
3317 ufoTibPeekChOfs(0));
3319 ch1
= ufoTibPeekChOfs(1);
3321 // single-line comment
3322 do { ch
= ufoTibGetCh(); } while (ch
!= 0 && ch
!= ')');
3323 ch
= ufoTibPeekCh();
3324 } else if (ch1
== '*' || ch1
== '(') {
3325 // possibly multiline
3326 ufoTibSkipCh(); ufoTibSkipCh(); // skip opening
3327 ufoParseMLComment(allowMulti
, (ch1
== '('));
3328 ch
= ufoTibPeekCh();
3332 } else if (ch
== '\\' && ufoTibPeekChOfs(1) <= 32) {
3333 // single-line comment
3334 while (ch
!= 0) ch
= ufoTibGetCh();
3335 } else if ((ch
== ';' || ch
== '-' || ch
== '/') && (ufoTibPeekChOfs(1) == ch
)) {
3337 while (ch
!= 0) ch
= ufoTibGetCh();
3343 fprintf(stderr
, "(PARSE-SKIP-COMMENTS): end-ch:'%c'\n", ufoTibPeekCh());
3349 UFWORD(PARSE_SKIP_LINE
) {
3350 ufoPush(0); ufoPushBool(0); UFCALL(PAR_PARSE
);
3351 if (ufoPop() != 0) {
3357 // ( -- addr count )
3358 // parse with leading blanks skipping. doesn't copy anything.
3359 // return empty string on EOL.
3360 UFWORD(PARSE_NAME
) {
3361 ufoPush(32); ufoPushBool(1); UFCALL(PAR_PARSE
);
3362 if (ufoPop() == 0) {
3369 // ( delim -- addr count TRUE / FALSE )
3370 // parse without skipping delimiters; never copies anything.
3371 // as our reader is line-based, returns FALSE on EOL.
3372 // passing 0 as delimiter skips the whole line, and always returns FALSE.
3373 // trailing delimiter is always skipped.
3375 ufoPushBool(0); UFCALL(PAR_PARSE
);
3379 // ( delim skip-leading-delim? -- here TRUE / FALSE )
3380 // parse word, copy it to HERE as counted string.
3381 // adds trailing zero after the string, but doesn't include it in count.
3382 // doesn't advance line.
3385 // ( delim -- here )
3386 // parse word, copy it to HERE as counted string.
3387 // adds trailing zero after the string, but doesn't include it in count.
3388 // doesn't advance line.
3389 // return empty string on EOL.
3392 // ( delim -- addr count TRUE / FALSE )
3393 // parse word w/o skipping delimiters, copy it to HERE as counted string.
3394 // adds trailing zero after the string, but doesn't include it in count.
3395 // doesn't advance line.
3398 // ////////////////////////////////////////////////////////////////////////// //
3405 uint32_t ch
= ufoPop()&0xffU
;
3407 if (ch < 32 || ch == 127) {
3408 if (ch != 9 && ch != 10 && ch != 13) ch = '?';
3411 ufoLastEmitWasCR
= (ch
== 10);
3418 uint32_t ch
= ufoPop()&0xffU
;
3419 putchar(ch
< 32 || ch
== 127 ? '?' : (char)ch
);
3420 ufoLastEmitWasCR
= 0;
3426 ufoPushBool(ufoLastEmitWasCR
);
3432 ufoLastEmitWasCR
= !!ufoPop();
3439 ufoLastEmitWasCR
= 1;
3446 ufoLastEmitWasCR
= 0;
3453 int32_t n
= (int32_t)ufoPop();
3455 memset(tmpbuf
, 32, sizeof(tmpbuf
));
3458 if (xwr
> (int32_t)sizeof(tmpbuf
) - 1) xwr
= (int32_t)sizeof(tmpbuf
) - 1;
3460 printf("%s", tmpbuf
);
3463 ufoLastEmitWasCR
= 0;
3470 if (ufoLastEmitWasCR
== 0) {
3472 ufoLastEmitWasCR
= 1;
3477 // ( addr count -- )
3479 int32_t count
= (int32_t)ufoPop();
3480 uint32_t addr
= ufoPop();
3482 const uint8_t ch
= ufoImgGetU8Ext(addr
);
3485 addr
+= 1; count
-= 1;
3490 // ( addr count -- )
3492 int32_t count
= (int32_t)ufoPop();
3493 uint32_t addr
= ufoPop();
3495 const uint8_t ch
= ufoImgGetU8Ext(addr
);
3498 addr
+= 1; count
-= 1;
3504 UFWORD(FLUSH_EMIT
) {
3509 // ////////////////////////////////////////////////////////////////////////// //
3513 #define UF_UMATH(name_,op_) \
3515 const uint32_t a = ufoPop(); \
3519 #define UF_BMATH(name_,op_) \
3521 const uint32_t b = ufoPop(); \
3522 const uint32_t a = ufoPop(); \
3526 #define UF_BDIV(name_,op_) \
3528 const uint32_t b = ufoPop(); \
3529 const uint32_t a = ufoPop(); \
3530 if (b == 0) ufoFatal("division by zero"); \
3537 UF_BMATH(PLUS
, a
+ b
);
3541 UF_BMATH(MINUS
, a
- b
);
3545 UF_BMATH(MUL
, (uint32_t)((int32_t)a
* (int32_t)b
));
3549 UF_BMATH(UMUL
, a
* b
);
3553 UF_BDIV(DIV
, (uint32_t)((int32_t)a
/ (int32_t)b
));
3557 UF_BDIV(UDIV
, a
/ b
);
3561 UF_BDIV(MOD
, (uint32_t)((int32_t)a
% (int32_t)b
));
3565 UF_BDIV(UMOD
, a
% b
);
3568 // ( a b -- a/b, a%b )
3570 const int32_t b
= (int32_t)ufoPop();
3571 const int32_t a
= (int32_t)ufoPop();
3572 if (b
== 0) ufoFatal("division by zero");
3573 ufoPush((uint32_t)(a
/b
));
3574 ufoPush((uint32_t)(a
%b
));
3578 // ( a b -- a/b, a%b )
3580 const uint32_t b
= ufoPop();
3581 const uint32_t a
= ufoPop();
3582 if (b
== 0) ufoFatal("division by zero");
3583 ufoPush((uint32_t)(a
/b
));
3584 ufoPush((uint32_t)(a
%b
));
3588 // ( a b c -- a*b/c )
3589 // this uses 64-bit intermediate value
3591 const int32_t c
= (int32_t)ufoPop();
3592 const int32_t b
= (int32_t)ufoPop();
3593 const int32_t a
= (int32_t)ufoPop();
3594 if (c
== 0) ufoFatal("division by zero");
3595 int64_t xval
= a
; xval
*= b
; xval
/= c
;
3596 ufoPush((uint32_t)(int32_t)xval
);
3600 // ( a b c -- a*b/c )
3601 // this uses 64-bit intermediate value
3603 const uint32_t c
= ufoPop();
3604 const uint32_t b
= ufoPop();
3605 const uint32_t a
= ufoPop();
3606 if (c
== 0) ufoFatal("division by zero");
3607 uint64_t xval
= a
; xval
*= b
; xval
/= c
;
3608 ufoPush((uint32_t)xval
);
3612 // ( a b c -- a*b/c a*b%c )
3613 // this uses 64-bit intermediate value
3615 const int32_t c
= (int32_t)ufoPop();
3616 const int32_t b
= (int32_t)ufoPop();
3617 const int32_t a
= (int32_t)ufoPop();
3618 if (c
== 0) ufoFatal("division by zero");
3619 int64_t xval
= a
; xval
*= b
;
3620 ufoPush((uint32_t)(int32_t)(xval
/ c
));
3621 ufoPush((uint32_t)(int32_t)(xval
% c
));
3625 // ( a b c -- a*b/c )
3626 // this uses 64-bit intermediate value
3627 UFWORD(UMULDIVMOD
) {
3628 const uint32_t c
= ufoPop();
3629 const uint32_t b
= ufoPop();
3630 const uint32_t a
= ufoPop();
3631 if (c
== 0) ufoFatal("division by zero");
3632 uint64_t xval
= a
; xval
*= b
;
3633 ufoPush((uint32_t)(xval
/ c
));
3634 ufoPush((uint32_t)(xval
% c
));
3638 // ( a b -- lo(a*b) hi(a*b) )
3639 // this leaves 64-bit result
3641 const int32_t b
= (int32_t)ufoPop();
3642 const int32_t a
= (int32_t)ufoPop();
3643 int64_t xval
= a
; xval
*= b
;
3644 ufoPush((uint32_t)(int32_t)xval
);
3645 ufoPush((uint32_t)(int32_t)(xval
>> 32));
3649 // ( a b -- lo(a*b) hi(a*b) )
3650 // this leaves 64-bit result
3652 const uint32_t b
= ufoPop();
3653 const uint32_t a
= ufoPop();
3654 uint64_t xval
= a
; xval
*= b
;
3655 ufoPush((uint32_t)xval
);
3656 ufoPush((uint32_t)(xval
>> 32));
3660 // ( alo ahi b -- a/b a%b )
3662 const int32_t b
= (int32_t)ufoPop();
3663 const uint32_t alo
= ufoPop();
3664 const uint32_t ahi
= ufoPop();
3665 if (b
== 0) ufoFatal("division by zero");
3666 // this is UB by the idiotic C standard. i don't care.
3667 int64_t a
= alo
; a
|= ((int64_t)ahi
) << 32;
3668 int64_t adiv
= a
/ b
;
3669 int64_t amod
= a
% b
;
3670 ufoPush((uint32_t)(int32_t)adiv
);
3671 ufoPush((uint32_t)(int32_t)amod
);
3675 // ( alo ahi b -- a/b a%b )
3677 const uint32_t b
= ufoPop();
3678 const uint32_t alo
= ufoPop();
3679 const uint32_t ahi
= ufoPop();
3680 if (b
== 0) ufoFatal("division by zero");
3681 uint64_t a
= alo
; a
|= ((uint64_t)ahi
) << 32;
3682 uint64_t adiv
= a
/ b
;
3683 uint64_t amod
= a
% b
;
3684 ufoPush((uint32_t)adiv
);
3685 ufoPush((uint32_t)amod
);
3689 // ////////////////////////////////////////////////////////////////////////// //
3690 // simple logic and bit manipulation
3693 #define UF_CMP(name_,op_) \
3695 const uint32_t b = ufoPop(); \
3696 const uint32_t a = ufoPop(); \
3702 UF_CMP(LESS
, (int32_t)a
< (int32_t)b
);
3706 UF_CMP(ULESS
, a
< b
);
3710 UF_CMP(GREAT
, (int32_t)a
> (int32_t)b
);
3714 UF_CMP(UGREAT
, a
> b
);
3718 UF_CMP(LESSEQU
, (int32_t)a
<= (int32_t)b
);
3722 UF_CMP(ULESSEQU
, a
<= b
);
3726 UF_CMP(GREATEQU
, (int32_t)a
>= (int32_t)b
);
3730 UF_CMP(UGREATEQU
, a
>= b
);
3734 UF_CMP(EQU
, a
== b
);
3738 UF_CMP(NOTEQU
, a
!= b
);
3743 const uint32_t a
= ufoPop();
3749 UF_CMP(LOGAND
, a
&& b
);
3753 UF_CMP(LOGOR
, a
|| b
);
3758 const uint32_t b
= ufoPop();
3759 const uint32_t a
= ufoPop();
3766 const uint32_t b
= ufoPop();
3767 const uint32_t a
= ufoPop();
3774 const uint32_t b
= ufoPop();
3775 const uint32_t a
= ufoPop();
3782 const uint32_t a
= ufoPop();
3786 UFWORD(ONESHL
) { uint32_t n
= ufoPop(); ufoPush(n
<< 1); }
3787 UFWORD(ONESHR
) { uint32_t n
= ufoPop(); ufoPush(n
>> 1); }
3788 UFWORD(TWOSHL
) { uint32_t n
= ufoPop(); ufoPush(n
<< 2); }
3789 UFWORD(TWOSHR
) { uint32_t n
= ufoPop(); ufoPush(n
>> 2); }
3793 // arithmetic shift; positive `n` shifts to the left
3795 int32_t c
= (int32_t)ufoPop();
3798 int32_t n
= (int32_t)ufoPop();
3800 if (n
< 0) n
= -1; else n
= 0;
3802 n
>>= (uint8_t)(-c
);
3804 ufoPush((uint32_t)n
);
3807 uint32_t u
= ufoPop();
3819 // logical shift; positive `n` shifts to the left
3821 int32_t c
= (int32_t) ufoPop();
3822 uint32_t u
= ufoPop();
3828 u
>>= (uint8_t)(-c
);
3842 // ////////////////////////////////////////////////////////////////////////// //
3843 // string unescaping
3847 // ( addr count -- addr count )
3848 UFWORD(PAR_UNESCAPE
) {
3849 const uint32_t count
= ufoPop();
3850 const uint32_t addr
= ufoPeek();
3851 if ((count
& ((uint32_t)1<<31)) == 0) {
3852 const uint32_t eaddr
= addr
+ count
;
3853 uint32_t caddr
= addr
;
3854 uint32_t daddr
= addr
;
3855 while (caddr
!= eaddr
) {
3856 uint8_t ch
= ufoImgGetU8Ext(caddr
); caddr
+= 1u;
3857 if (ch
== '\\' && caddr
!= eaddr
) {
3858 ch
= ufoImgGetU8Ext(caddr
); caddr
+= 1u;
3860 case 'r': ch
= '\r'; break;
3861 case 'n': ch
= '\n'; break;
3862 case 't': ch
= '\t'; break;
3863 case 'e': ch
= '\x1b'; break;
3864 case '`': ch
= '"'; break; // special escape to insert double-quote
3865 case '"': ch
= '"'; break;
3866 case '\\': ch
= '\\'; break;
3868 if (eaddr
- daddr
>= 1) {
3869 const int dg0
= digitInBase((char)(ufoImgGetU8Ext(caddr
)), 16);
3870 if (dg0
< 0) ufoFatal("invalid hex string escape");
3871 if (eaddr
- daddr
>= 2) {
3872 const int dg1
= digitInBase((char)(ufoImgGetU8Ext(caddr
+ 1u)), 16);
3873 if (dg1
< 0) ufoFatal("invalid hex string escape");
3874 ch
= (uint8_t)(dg0
* 16 + dg1
);
3881 ufoFatal("invalid hex string escape");
3884 default: ufoFatal("invalid string escape");
3887 ufoImgPutU8Ext(daddr
, ch
); daddr
+= 1u;
3889 ufoPush(daddr
- addr
);
3896 // ////////////////////////////////////////////////////////////////////////// //
3897 // numeric conversions
3900 // (BASED-NUMBER) ( addr count allowsign? base -- num TRUE / FALSE )
3901 UFWORD(PAR_BASED_NUMBER
) {
3902 const uint32_t xbase
= ufoPop();
3903 const uint32_t allowSign
= ufoPop();
3904 int32_t count
= (int32_t)ufoPop();
3905 uint32_t addr
= ufoPop();
3911 if (allowSign
&& count
> 1) {
3912 ch
= ufoImgGetU8Ext(addr
);
3913 if (ch
== '-') { neg
= 1; addr
+= 1u; count
-= 1; }
3914 else if (ch
== '+') { neg
= 0; addr
+= 1u; count
-= 1; }
3917 // special-based numbers
3918 if (count
>= 3 && ufoImgGetU8Ext(addr
) == '0') {
3919 switch (ufoImgGetU8Ext(addr
+ 1u)) {
3920 case 'x': case 'X': base
= 16; break;
3921 case 'o': case 'O': base
= 8; break;
3922 case 'b': case 'B': base
= 2; break;
3923 case 'd': case 'D': base
= 10; break;
3926 if (base
) { addr
+= 2; count
-= 2; }
3927 } else if (count
>= 2 && ufoImgGetU8Ext(addr
) == '$') {
3929 addr
+= 1; count
-= 1;
3930 } else if (count
>= 2 && ufoImgGetU8Ext(addr
) == '#') {
3932 addr
+= 1; count
-= 1;
3933 } else if (count
>= 2 && ufoImgGetU8Ext(addr
) == '%') {
3935 addr
+= 1; count
-= 1;
3936 } else if (count
>= 3 && ufoImgGetU8Ext(addr
) == '&') {
3937 switch (ufoImgGetU8Ext(addr
+ 1u)) {
3938 case 'h': case 'H': base
= 16; break;
3939 case 'o': case 'O': base
= 8; break;
3940 case 'b': case 'B': base
= 2; break;
3941 case 'd': case 'D': base
= 10; break;
3944 if (base
) { addr
+= 2; count
-= 2; }
3945 } else if (xbase
< 12 && count
> 2 && toUpperU8(ufoImgGetU8Ext(addr
+ (uint32_t)count
- 1u)) == 'B') {
3948 } else if (xbase
< 18 && count
> 2 && toUpperU8(ufoImgGetU8Ext(addr
+ (uint32_t)count
- 1u)) == 'H') {
3951 } else if (xbase
< 25 && count
> 2 && toUpperU8(ufoImgGetU8Ext(addr
+ (uint32_t)count
- 1u)) == 'O') {
3957 if (!base
&& xbase
< 255) base
= xbase
;
3959 if (count
<= 0 || base
< 1 || base
> 36) {
3963 int wasDig
= 0, wasUnder
= 1, error
= 0, dig
;
3964 while (!error
&& count
!= 0) {
3965 ch
= ufoImgGetU8Ext(addr
); addr
+= 1u; count
-= 1;
3967 error
= 1; wasUnder
= 0; wasDig
= 1;
3968 dig
= digitInBase((char)ch
, (int)base
);
3970 nc
= n
* (uint32_t)base
;
3972 nc
+= (uint32_t)dig
;
3985 if (!error
&& wasDig
&& !wasUnder
) {
3986 if (allowSign
&& neg
) n
= ~n
+ 1u;
3996 // ////////////////////////////////////////////////////////////////////////// //
3997 // compiler-related, dictionary-related
4000 static char ufoWNameBuf
[256];
4004 UFWORD(LBRACKET_IMM
) {
4005 if (ufoImgGetU32(ufoAddrSTATE
) == 0) ufoFatal("expects compiling mode");
4006 ufoImgPutU32(ufoAddrSTATE
, 0);
4011 if (ufoImgGetU32(ufoAddrSTATE
) != 0) ufoFatal("expects interpreting mode");
4012 ufoImgPutU32(ufoAddrSTATE
, 1);
4015 // (CREATE-WORD-HEADER)
4016 // ( addr count word-flags -- )
4017 UFWORD(PAR_CREATE_WORD_HEADER
) {
4018 const uint32_t flags
= ufoPop();
4019 const uint32_t wlen
= ufoPop();
4020 const uint32_t waddr
= ufoPop();
4021 if (wlen
== 0) ufoFatal("word name expected");
4022 if (wlen
>= UFO_MAX_WORD_LENGTH
) ufoFatal("word name too long");
4023 // copy to separate buffer
4024 for (uint32_t f
= 0; f
< wlen
; f
+= 1) {
4025 ufoWNameBuf
[f
] = (char)ufoImgGetU8Ext(waddr
+ f
);
4027 ufoWNameBuf
[wlen
] = 0;
4028 ufoCreateWordHeader(ufoWNameBuf
, flags
);
4031 // (CREATE-NAMELESS-WORD-HEADER)
4032 // ( word-flags -- )
4033 UFWORD(PAR_CREATE_NAMELESS_WORD_HEADER
) {
4034 const uint32_t flags
= ufoPop();
4035 ufoCreateWordHeader("", flags
);
4039 // ( addr count -- cfa TRUE / FALSE)
4041 const uint32_t wlen
= ufoPop();
4042 const uint32_t waddr
= ufoPop();
4043 if (wlen
> 0 && wlen
< UFO_MAX_WORD_LENGTH
) {
4044 // copy to separate buffer
4045 for (uint32_t f
= 0; f
< wlen
; f
+= 1) {
4046 ufoWNameBuf
[f
] = (char)ufoImgGetU8Ext(waddr
+ f
);
4048 ufoWNameBuf
[wlen
] = 0;
4049 const uint32_t cfa
= ufoFindWord(ufoWNameBuf
);
4062 // ( addr count vocid allowhidden -- cfa TRUE / FALSE)
4063 // find only in the given voc; no name resolution
4064 UFWORD(FIND_WORD_IN_VOC
) {
4065 const uint32_t allowHidden
= ufoPop();
4066 const uint32_t vocid
= ufoPop();
4067 const uint32_t wlen
= ufoPop();
4068 const uint32_t waddr
= ufoPop();
4069 if (wlen
> 0 && wlen
< UFO_MAX_WORD_LENGTH
) {
4070 // copy to separate buffer
4071 for (uint32_t f
= 0; f
< wlen
; f
+= 1) {
4072 ufoWNameBuf
[f
] = (char)ufoImgGetU8Ext(waddr
+ f
);
4074 ufoWNameBuf
[wlen
] = 0;
4075 const uint32_t cfa
= ufoFindWordInVoc(ufoWNameBuf
, wlen
, 0, vocid
, (allowHidden
? 1 : 0));
4087 // FIND-WORD-IN-VOC-AND-PARENTS
4088 // ( addr count vocid allowhidden -- cfa TRUE / FALSE)
4089 // find only in the given voc; no name resolution
4090 UFWORD(FIND_WORD_IN_VOC_AND_PARENTS
) {
4091 const uint32_t allowHidden
= ufoPop();
4092 const uint32_t vocid
= ufoPop();
4093 const uint32_t wlen
= ufoPop();
4094 const uint32_t waddr
= ufoPop();
4095 if (wlen
> 0 && wlen
< UFO_MAX_WORD_LENGTH
) {
4096 // copy to separate buffer
4097 for (uint32_t f
= 0; f
< wlen
; f
+= 1) {
4098 ufoWNameBuf
[f
] = (char)ufoImgGetU8Ext(waddr
+ f
);
4100 ufoWNameBuf
[wlen
] = 0;
4101 const uint32_t cfa
= ufoFindWordInVocAndParents(ufoWNameBuf
, wlen
, 0, vocid
, (allowHidden
? 1 : 0));
4114 // ////////////////////////////////////////////////////////////////////////// //
4115 // more compiler words
4120 if (ufoImgGetU32(ufoAddrSTATE
) != 0) ufoFatal("expecting execution mode");
4125 if (ufoImgGetU32(ufoAddrSTATE
) == 0) ufoFatal("expecting compilation mode");
4131 ufoPush(34); UFCALL(PARSE
);
4132 if (ufoPop() == 0) ufoFatal("string literal expected");
4133 UFCALL(PAR_UNESCAPE
);
4134 if (ufoImgGetU32(ufoAddrSTATE
) != 0) {
4136 const uint32_t wlen
= ufoPop();
4137 const uint32_t waddr
= ufoPop();
4138 if (wlen
> 255) ufoFatal("string literal too long");
4139 ufoImgEmitU32(ufoStrLit8CFA
);
4141 for (uint32_t f
= 0; f
< wlen
; f
+= 1) {
4142 ufoImgEmitU8(ufoImgGetU8Ext(waddr
+ f
));
4150 // ////////////////////////////////////////////////////////////////////////// //
4151 // vocabulary and wordlist utilities
4156 UFWORD(PAR_GET_VSP
) {
4162 UFWORD(PAR_SET_VSP
) {
4163 const uint32_t vsp
= ufoPop();
4164 if (vsp
>= UFO_VOCSTACK_SIZE
) ufoFatal("VSP %u out of range (%u)", vsp
, UFO_VOCSTACK_SIZE
);
4170 UFWORD(PAR_VSP_LOAD
) {
4171 const uint32_t vsp
= ufoPop();
4172 if (vsp
>= UFO_VOCSTACK_SIZE
) ufoFatal("VSP %u out of range (%u)", vsp
, UFO_VOCSTACK_SIZE
);
4173 ufoPush(ufoVocStack
[vsp
]);
4178 UFWORD(PAR_VSP_STORE
) {
4179 const uint32_t vsp
= ufoPop();
4180 const uint32_t value
= ufoPop();
4181 if (vsp
> UFO_VOCSTACK_SIZE
) ufoFatal("VSP %u out of range (%u)", vsp
, UFO_VOCSTACK_SIZE
);
4182 ufoVocStack
[vsp
] = value
;
4186 // ////////////////////////////////////////////////////////////////////////// //
4187 // word field address conversion
4193 const uint32_t cfa
= ufoPop();
4194 ufoPush(UFO_CFA_TO_PFA(cfa
));
4200 const uint32_t pfa
= ufoPop();
4201 ufoPush(UFO_PFA_TO_CFA(pfa
));
4207 const uint32_t cfa
= ufoPop();
4208 ufoPush(UFO_CFA_TO_NFA(cfa
));
4214 const uint32_t nfa
= ufoPop();
4215 ufoPush(UFO_NFA_TO_CFA(nfa
));
4221 const uint32_t cfa
= ufoPop();
4222 ufoPush(UFO_CFA_TO_LFA(cfa
));
4228 const uint32_t lfa
= ufoPop();
4229 ufoPush(UFO_LFA_TO_CFA(lfa
));
4235 const uint32_t lfa
= ufoPop();
4236 const uint32_t cfa
= UFO_LFA_TO_CFA(lfa
);
4237 ufoPush(UFO_CFA_TO_PFA(cfa
));
4243 const uint32_t lfa
= ufoPop();
4244 ufoPush(UFO_LFA_TO_BFA(lfa
));
4250 const uint32_t lfa
= ufoPop();
4251 ufoPush(UFO_LFA_TO_XFA(lfa
));
4257 const uint32_t lfa
= ufoPop();
4258 ufoPush(UFO_LFA_TO_YFA(lfa
));
4264 const uint32_t lfa
= ufoPop();
4265 ufoPush(UFO_LFA_TO_NFA(lfa
));
4271 const uint32_t nfa
= ufoPop();
4272 ufoPush(UFO_NFA_TO_LFA(nfa
));
4276 // ( cfa -- wend-addr )
4278 const uint32_t cfa
= ufoPop();
4279 ufoPush(ufoGetWordEndAddr(cfa
));
4283 // ( ip -- nfa / 0 )
4285 const uint32_t ip
= ufoPop();
4286 ufoPush(ufoFindWordForIP(ip
));
4290 // ////////////////////////////////////////////////////////////////////////// //
4291 // string operations
4294 UFO_FORCE_INLINE
uint32_t ufoHashBuf (uint32_t addr
, uint32_t size
, uint8_t orbyte
) {
4295 uint32_t hash
= 0x29a;
4296 if ((size
& ((uint32_t)1<<31)) == 0) {
4298 hash
+= ufoImgGetU8Ext(addr
) | orbyte
;
4301 addr
+= 1u; size
-= 1u;
4312 // ( a0 c0 a1 c1 -- bool )
4314 int32_t c1
= (int32_t)ufoPop();
4315 uint32_t a1
= ufoPop();
4316 int32_t c0
= (int32_t)ufoPop();
4317 uint32_t a0
= ufoPop();
4322 while (res
!= 0 && c0
!= 0) {
4323 res
= (ufoImgGetU8Ext(a0
) == ufoImgGetU8Ext(a1
));
4324 a0
+= 1; a1
+= 1; c0
-= 1;
4333 // ( a0 c0 a1 c1 -- bool )
4335 int32_t c1
= (int32_t)ufoPop();
4336 uint32_t a1
= ufoPop();
4337 int32_t c0
= (int32_t)ufoPop();
4338 uint32_t a0
= ufoPop();
4343 while (res
!= 0 && c0
!= 0) {
4344 res
= (toUpperU8(ufoImgGetU8Ext(a0
)) == toUpperU8(ufoImgGetU8Ext(a1
)));
4345 a0
+= 1; a1
+= 1; c0
-= 1;
4354 // ( addr count -- hash )
4356 uint32_t count
= ufoPop();
4357 uint32_t addr
= ufoPop();
4358 ufoPush(ufoHashBuf(addr
, count
, 0));
4362 // ( addr count -- hash )
4364 uint32_t count
= ufoPop();
4365 uint32_t addr
= ufoPop();
4366 ufoPush(ufoHashBuf(addr
, count
, 0x20));
4370 // ////////////////////////////////////////////////////////////////////////// //
4371 // conditional defines
4374 typedef struct UForthCondDefine_t UForthCondDefine
;
4375 struct UForthCondDefine_t
{
4379 UForthCondDefine
*next
;
4382 static UForthCondDefine
*ufoCondDefines
= NULL
;
4383 static char ufoErrMsgBuf
[4096];
4386 //==========================================================================
4390 //==========================================================================
4391 UFO_DISABLE_INLINE
int ufoStrEquCI (const void *str0
, const void *str1
) {
4392 const unsigned char *s0
= (const unsigned char *)str0
;
4393 const unsigned char *s1
= (const unsigned char *)str1
;
4394 while (*s0
&& *s1
) {
4395 if (toUpperU8(*s0
) != toUpperU8(*s1
)) return 0;
4398 return (*s0
== 0 && *s1
== 0);
4402 //==========================================================================
4406 //==========================================================================
4407 UFO_FORCE_INLINE
int ufoBufEquCI (uint32_t addr
, uint32_t count
, const void *buf
) {
4409 if ((count
& ((uint32_t)1<<31)) == 0) {
4410 const unsigned char *src
= (const unsigned char *)buf
;
4412 while (res
!= 0 && count
!= 0) {
4413 res
= (toUpperU8(*src
) == toUpperU8(ufoImgGetU8Ext(addr
)));
4414 src
+= 1; addr
+= 1u; count
-= 1u;
4423 //==========================================================================
4425 // ufoClearCondDefines
4427 //==========================================================================
4428 static void ufoClearCondDefines (void) {
4429 while (ufoCondDefines
) {
4430 UForthCondDefine
*df
= ufoCondDefines
;
4431 ufoCondDefines
= df
->next
;
4432 if (df
->name
) free(df
->name
);
4438 //==========================================================================
4442 //==========================================================================
4443 int ufoHasCondDefine (const char *name
) {
4445 if (name
!= NULL
&& name
[0] != 0) {
4446 const size_t nlen
= strlen(name
);
4448 const uint32_t hash
= joaatHashBufCI(name
, nlen
);
4449 UForthCondDefine
*dd
= ufoCondDefines
;
4450 while (res
== 0 && dd
!= NULL
) {
4451 if (dd
->hash
== hash
&& dd
->namelen
== (uint32_t)nlen
) {
4452 res
= ufoStrEquCI(name
, dd
->name
);
4462 //==========================================================================
4466 //==========================================================================
4467 void ufoCondDefine (const char *name
) {
4468 if (name
!= NULL
&& name
[0] != 0) {
4469 const size_t nlen
= strlen(name
);
4470 if (nlen
> 255) ufoFatal("conditional define name too long");
4471 const uint32_t hash
= joaatHashBufCI(name
, nlen
);
4472 UForthCondDefine
*dd
= ufoCondDefines
;
4474 while (res
== 0 && dd
!= NULL
) {
4475 if (dd
->hash
== hash
&& dd
->namelen
== (uint32_t)nlen
) {
4476 res
= ufoStrEquCI(name
, dd
->name
);
4482 dd
= calloc(1, sizeof(UForthCondDefine
));
4483 if (dd
== NULL
) ufoFatal("out of memory for defines");
4484 dd
->name
= strdup(name
);
4485 if (dd
->name
== NULL
) { free(dd
); ufoFatal("out of memory for defines"); }
4486 dd
->namelen
= (uint32_t)nlen
;
4488 dd
->next
= ufoCondDefines
;
4489 ufoCondDefines
= dd
;
4495 //==========================================================================
4499 //==========================================================================
4500 void ufoCondUndef (const char *name
) {
4501 if (name
!= NULL
&& name
[0] != 0) {
4502 const size_t nlen
= strlen(name
);
4504 const uint32_t hash
= joaatHashBufCI(name
, nlen
);
4505 UForthCondDefine
*dd
= ufoCondDefines
;
4506 UForthCondDefine
*prev
= NULL
;
4507 while (dd
!= NULL
) {
4508 if (dd
->hash
== hash
&& dd
->namelen
== (uint32_t)nlen
) {
4509 if (ufoStrEquCI(name
, dd
->name
)) {
4510 if (prev
!= NULL
) prev
->next
= dd
->next
; else ufoCondDefines
= dd
->next
;
4516 if (dd
!= NULL
) { prev
= dd
; dd
= dd
->next
; }
4524 // ( addr count -- )
4525 UFWORD(PAR_DLR_DEFINE
) {
4526 uint32_t count
= ufoPop();
4527 uint32_t addr
= ufoPop();
4528 if (count
== 0) ufoFatal("empty define");
4529 if (count
>= UFO_MAX_WORD_LENGTH
) ufoFatal("define too long");
4530 const uint32_t hash
= ufoHashBuf(addr
, count
, 0x20);
4531 UForthCondDefine
*dd
;
4532 for (dd
= ufoCondDefines
; dd
!= NULL
; dd
= dd
->next
) {
4533 if (dd
->hash
== hash
&& dd
->namelen
== count
) {
4534 if (ufoBufEquCI(addr
, count
, dd
->name
)) return;
4538 dd
= calloc(1, sizeof(UForthCondDefine
));
4539 if (dd
== NULL
) ufoFatal("out of memory for defines");
4540 dd
->name
= calloc(1, count
+ 1u);
4541 if (dd
->name
== NULL
) { free(dd
); ufoFatal("out of memory for defines"); }
4542 for (uint32_t f
= 0; f
< count
; f
+= 1) {
4543 ((unsigned char *)dd
->name
)[f
] = ufoImgGetU8Ext(addr
+ f
);
4545 dd
->namelen
= count
;
4547 dd
->next
= ufoCondDefines
;
4548 ufoCondDefines
= dd
;
4552 // ( addr count -- )
4553 UFWORD(PAR_DLR_UNDEF
) {
4554 uint32_t count
= ufoPop();
4555 uint32_t addr
= ufoPop();
4556 if (count
== 0) ufoFatal("empty define");
4557 if (count
>= UFO_MAX_WORD_LENGTH
) ufoFatal("define too long");
4558 const uint32_t hash
= ufoHashBuf(addr
, count
, 0x20);
4559 UForthCondDefine
*prev
= NULL
;
4560 UForthCondDefine
*dd
;
4561 for (dd
= ufoCondDefines
; dd
!= NULL
; prev
= dd
, dd
= dd
->next
) {
4562 if (dd
->hash
== hash
&& dd
->namelen
== count
) {
4563 if (ufoBufEquCI(addr
, count
, dd
->name
)) {
4564 if (prev
== NULL
) ufoCondDefines
= dd
->next
; else prev
->next
= dd
->next
;
4574 // ( addr count -- bool )
4575 UFWORD(PAR_DLR_DEFINEDQ
) {
4576 uint32_t count
= ufoPop();
4577 uint32_t addr
= ufoPop();
4578 if (count
== 0) ufoFatal("empty define");
4579 if (count
>= UFO_MAX_WORD_LENGTH
) ufoFatal("define too long");
4580 const uint32_t hash
= ufoHashBuf(addr
, count
, 0x20);
4582 UForthCondDefine
*dd
= ufoCondDefines
;
4583 while (!found
&& dd
!= NULL
) {
4584 if (dd
->hash
== hash
&& dd
->namelen
== count
) {
4585 found
= ufoBufEquCI(addr
, count
, dd
->name
);
4593 // ////////////////////////////////////////////////////////////////////////// //
4598 // ( addr count -- )
4600 uint32_t count
= ufoPop();
4601 uint32_t addr
= ufoPop();
4602 if (count
& (1u<<31)) ufoFatal("invalid error message");
4603 if (count
== 0) ufoFatal("some error");
4604 if (count
> (uint32_t)sizeof(ufoErrMsgBuf
) - 1u) count
= (uint32_t)sizeof(ufoErrMsgBuf
) - 1u;
4605 for (uint32_t f
= 0; f
< count
; f
+= 1) {
4606 ufoErrMsgBuf
[f
] = (char)ufoImgGetU8Ext(addr
+ f
);
4608 ufoErrMsgBuf
[count
] = 0;
4609 ufoFatal("%s", ufoErrMsgBuf
);
4613 // ( errflag addr count -- )
4615 const uint32_t count
= ufoPop();
4616 const uint32_t addr
= ufoPop();
4625 // ////////////////////////////////////////////////////////////////////////// //
4629 static char ufoFNameBuf
[4096];
4632 //==========================================================================
4634 // ufoScanIncludeFileName
4636 // `*psys` and `*psoft` must be initialised!
4638 //==========================================================================
4639 static void ufoScanIncludeFileName (uint32_t addr
, uint32_t count
, char *dest
, size_t destsz
,
4640 uint32_t *psys
, uint32_t *psoft
)
4644 ufo_assert(dest
!= NULL
);
4645 ufo_assert(destsz
> 0);
4647 while (count
!= 0) {
4648 ch
= ufoImgGetU8Ext(addr
);
4650 //if (system) ufoFatal("invalid file name (duplicate system mark)");
4652 } else if (ch
== '?') {
4653 //if (softinclude) ufoFatal("invalid file name (duplicate soft mark)");
4659 addr
+= 1; count
-= 1;
4660 ch
= ufoImgGetU8Ext(addr
);
4661 } while (ch
<= 32 && count
!= 0);
4664 if (count
== 0) ufoFatal("empty include file name");
4665 if (count
>= destsz
) ufoFatal("include file name too long");
4668 while (count
!= 0) {
4669 dest
[dpos
] = (char)ufoImgGetU8Ext(addr
); dpos
+= 1;
4670 addr
+= 1; count
-= 1;
4678 // return number of items in include stack
4679 UFWORD(PAR_INCLUDE_DEPTH
) {
4680 ufoPush(ufoFileStackPos
);
4683 // (INCLUDE-FILE-ID)
4684 // ( isp -- id ) -- isp 0 is current, then 1, etc.
4685 // each include file has unique non-zero id.
4686 UFWORD(PAR_INCLUDE_FILE_ID
) {
4687 const uint32_t isp
= ufoPop();
4690 } else if (isp
<= ufoFileStackPos
) {
4691 UFOFileStackEntry
*stk
= &ufoFileStack
[ufoFileStackPos
- isp
];
4694 ufoFatal("invalid include stack index");
4698 // (INCLUDE-FILE-LINE)
4700 UFWORD(PAR_INCLUDE_FILE_LINE
) {
4701 const uint32_t isp
= ufoPop();
4703 ufoPush(ufoInFileLine
);
4704 } else if (isp
<= ufoFileStackPos
) {
4705 UFOFileStackEntry
*stk
= &ufoFileStack
[ufoFileStackPos
- isp
];
4706 ufoPush(stk
->fline
);
4708 ufoFatal("invalid include stack index");
4710 ufoPush(ufoInFileLine
);
4713 // (INCLUDE-FILE-NAME)
4714 // ( isp -- addr count )
4715 // current file name; at PAD
4716 UFWORD(PAR_INCLUDE_FILE_NAME
) {
4717 const uint32_t isp
= ufoPop();
4718 const char *fname
= NULL
;
4720 fname
= ufoInFileName
;
4721 } else if (isp
<= ufoFileStackPos
) {
4722 UFOFileStackEntry
*stk
= &ufoFileStack
[ufoFileStackPos
- isp
];
4725 ufoFatal("invalid include stack index");
4728 uint32_t addr
= ufoPop();
4730 while (fname
[count
] != 0) {
4731 ufoImgPutU8Ext(addr
+ count
, ((const unsigned char *)fname
)[count
]);
4734 ufoImgPutU8Ext(addr
+ count
, 0);
4740 // ( addr count soft? system? -- )
4741 UFWORD(PAR_INCLUDE
) {
4742 uint32_t system
= ufoPop();
4743 uint32_t softinclude
= ufoPop();
4744 uint32_t count
= ufoPop();
4745 uint32_t addr
= ufoPop();
4747 if (ufoMode
== UFO_MODE_MACRO
) ufoFatal("macros cannot include files");
4749 if ((count
& ((uint32_t)1<<31)) != 0) ufoFatal("invalid include name");
4751 ufoScanIncludeFileName(addr
, count
, ufoFNameBuf
, sizeof(ufoFNameBuf
),
4752 &system
, &softinclude
);
4754 char *ffn
= ufoCreateIncludeName(ufoFNameBuf
, system
, ufoLastIncPath
);
4756 FILE *fl
= fopen(ffn
, "rb");
4758 FILE *fl
= fopen(ffn
, "r");
4761 if (softinclude
) { free(ffn
); return; }
4762 ufoFatal("include file '%s' not found", ffn
);
4767 ufoInFileName
= ffn
;
4768 ufoFileId
= ufoLastUsedFileId
;
4769 setLastIncPath(ufoInFileName
);
4770 #ifdef UFO_DEBUG_INCLUDE
4771 fprintf(stderr
, "INC-PUSH: new fname: %s\n", ffn
);
4774 // trigger next line loading
4776 if (!ufoPop()) ufoFatal("(INCLUDE) internal error");
4780 UFWORD(DLR_INCLUDE_IMM
) {
4781 int soft
= 0, system
= 0;
4782 // parse include filename
4783 //UFCALL(PARSE_SKIP_BLANKS);
4784 ufoPushBool(0); UFCALL(PAR_PARSE_SKIP_COMMENTS
);
4785 uint8_t ch
= ufoTibPeekCh();
4787 ufoTibSkipCh(); // skip quote
4789 } else if (ch
== '<') {
4790 ufoTibSkipCh(); // skip quote
4794 ufoFatal("expected quoted string");
4797 if (!ufoPop()) ufoFatal("file name expected");
4798 ufoPushBool(0); UFCALL(PAR_PARSE_SKIP_COMMENTS
);
4799 if (ufoTibPeekCh() != 0) {
4800 ufoFatal("$INCLUDE doesn't accept extra args yet");
4802 // ( addr count soft? system? -- )
4803 ufoPushBool(soft
); ufoPushBool(system
); UFCALL(PAR_INCLUDE
);
4807 //==========================================================================
4809 // ufoCreateFileGuard
4811 //==========================================================================
4812 static const char *ufoCreateFileGuard (const char *fname
) {
4813 if (fname
== NULL
|| fname
[0] == 0) return NULL
;
4814 char *rp
= ufoRealPath(fname
);
4815 if (rp
== NULL
) return NULL
;
4817 for (char *s
= rp
; *s
; s
+= 1) if (*s
== '\\') *s
= '/';
4819 // hash the buffer; extract file name; create string with path len, file name, and hash
4820 const size_t orgplen
= strlen(rp
);
4821 const uint32_t phash
= joaatHashBuf(rp
, orgplen
, 0);
4822 size_t plen
= orgplen
;
4823 while (plen
!= 0 && rp
[plen
- 1u] != '/') plen
-= 1;
4824 snprintf(ufoRealPathHashBuf
, sizeof(ufoRealPathHashBuf
),
4825 "__INCLUDE_GUARD_%08X_%08X_%s__", phash
, (uint32_t)orgplen
, rp
+ plen
);
4826 return ufoRealPathHashBuf
;
4830 // $INCLUDE-ONCE "str"
4831 // includes file only once; unreliable on shitdoze, i believe
4832 UFWORD(DLR_INCLUDE_ONCE_IMM
) {
4833 uint32_t softinclude
= 0, system
= 0;
4834 // parse include filename
4835 //UFCALL(PARSE_SKIP_BLANKS);
4836 ufoPushBool(0); UFCALL(PAR_PARSE_SKIP_COMMENTS
);
4837 uint8_t ch
= ufoTibPeekCh();
4839 ufoTibSkipCh(); // skip quote
4841 } else if (ch
== '<') {
4842 ufoTibSkipCh(); // skip quote
4846 ufoFatal("expected quoted string");
4849 if (!ufoPop()) ufoFatal("file name expected");
4850 const uint32_t count
= ufoPop();
4851 const uint32_t addr
= ufoPop();
4852 ufoPushBool(0); UFCALL(PAR_PARSE_SKIP_COMMENTS
);
4853 if (ufoTibPeekCh() != 0) {
4854 ufoFatal("$REQUIRE doesn't accept extra args yet");
4856 ufoScanIncludeFileName(addr
, count
, ufoRealPathHashBuf
, sizeof(ufoRealPathHashBuf
),
4857 &system
, &softinclude
);
4858 char *incfname
= ufoCreateIncludeName(ufoRealPathHashBuf
, system
, ufoLastIncPath
);
4859 if (incfname
== NULL
) ufoFatal("cannot resolve include file '%s'", ufoRealPathHashBuf
);
4860 // this will overwrite `ufoRealPathHashBuf`
4861 const char *guard
= ufoCreateFileGuard(incfname
);
4863 if (guard
== NULL
) {
4864 if (!softinclude
) ufoFatal("cannot include file '%s'", ufoRealPathHashBuf
);
4868 fprintf(stderr
, "GUARD: <%s>\n", guard
);
4870 // now check for the guard
4871 const uint32_t glen
= (uint32_t)strlen(guard
);
4872 const uint32_t ghash
= joaatHashBuf(guard
, glen
, 0);
4873 UForthCondDefine
*dd
;
4874 for (dd
= ufoCondDefines
; dd
!= NULL
; dd
= dd
->next
) {
4875 if (dd
->hash
== ghash
&& dd
->namelen
== glen
&& strcmp(guard
, dd
->name
) == 0) {
4876 // nothing to do: already included
4881 dd
= calloc(1, sizeof(UForthCondDefine
));
4882 if (dd
== NULL
) ufoFatal("out of memory for defines");
4883 dd
->name
= calloc(1, glen
+ 1u);
4884 if (dd
->name
== NULL
) { free(dd
); ufoFatal("out of memory for defines"); }
4885 strcpy(dd
->name
, guard
);
4888 dd
->next
= ufoCondDefines
;
4889 ufoCondDefines
= dd
;
4890 // ( addr count soft? system? -- )
4891 ufoPush(addr
); ufoPush(count
); ufoPushBool(0); ufoPushBool(0);
4892 UFCALL(PAR_INCLUDE
);
4896 // ////////////////////////////////////////////////////////////////////////// //
4902 UFWORD(PAR_NEW_HANDLE
) {
4903 const uint32_t typeid = ufoPop();
4904 if (typeid == UFO_HANDLE_FREE
) ufoFatal("invalid handle typeid");
4905 UHandleInfo
*hh
= ufoAllocHandle(typeid);
4906 ufoPush(hh
->ufoHandle
);
4911 UFWORD(PAR_FREE_HANDLE
) {
4912 const uint32_t hx
= ufoPop();
4913 if ((hx
& UFO_ADDR_HANDLE_BIT
) == 0) ufoFatal("trying to free something that is not a handle");
4914 UHandleInfo
*hh
= ufoGetHandle(hx
);
4915 if (hh
== NULL
) ufoFatal("trying to free invalid handle");
4921 UFWORD(PAR_HANDLE_GET_TYPEID
) {
4922 const uint32_t hx
= ufoPop();
4923 if ((hx
& UFO_ADDR_HANDLE_BIT
) == 0) ufoFatal("not a handle");
4924 UHandleInfo
*hh
= ufoGetHandle(hx
);
4925 if (hh
== NULL
) ufoFatal("invalid handle");
4926 ufoPush(hh
->typeid);
4931 UFWORD(PAR_HANDLE_SET_TYPEID
) {
4932 const uint32_t hx
= ufoPop();
4933 const uint32_t typeid = ufoPop();
4934 if ((hx
& UFO_ADDR_HANDLE_BIT
) == 0) ufoFatal("not a handle");
4935 if (typeid == UFO_HANDLE_FREE
) ufoFatal("invalid handle typeid");
4936 UHandleInfo
*hh
= ufoGetHandle(hx
);
4937 if (hh
== NULL
) ufoFatal("invalid handle");
4938 hh
->typeid = typeid;
4943 UFWORD(PAR_HANDLE_GET_SIZE
) {
4944 const uint32_t hx
= ufoPop();
4945 if ((hx
& UFO_ADDR_HANDLE_BIT
) == 0) ufoFatal("not a handle");
4946 UHandleInfo
*hh
= ufoGetHandle(hx
);
4947 if (hh
== NULL
) ufoFatal("invalid handle");
4953 UFWORD(PAR_HANDLE_SET_SIZE
) {
4954 const uint32_t hx
= ufoPop();
4955 const uint32_t size
= ufoPop();
4956 if (size
> 0x04000000) ufoFatal("invalid handle size");
4957 if ((hx
& UFO_ADDR_HANDLE_BIT
) == 0) ufoFatal("not a handle");
4958 UHandleInfo
*hh
= ufoGetHandle(hx
);
4959 if (hh
== NULL
) ufoFatal("invalid handle");
4960 if (hh
->size
!= size
) {
4965 uint8_t *nx
= realloc(hh
->data
, size
* sizeof(hh
->data
[0]));
4966 if (nx
== NULL
) ufoFatal("out of memory for handle of size %u", size
);
4968 if (size
> hh
->size
) memset(hh
->data
, 0, size
- hh
->size
);
4971 if (hh
->used
> size
) hh
->used
= size
;
4977 UFWORD(PAR_HANDLE_GET_USED
) {
4978 const uint32_t hx
= ufoPop();
4979 if ((hx
& UFO_ADDR_HANDLE_BIT
) == 0) ufoFatal("not a handle");
4980 UHandleInfo
*hh
= ufoGetHandle(hx
);
4981 if (hh
== NULL
) ufoFatal("invalid handle");
4987 UFWORD(PAR_HANDLE_SET_USED
) {
4988 const uint32_t hx
= ufoPop();
4989 const uint32_t used
= ufoPop();
4990 if (used
> 0x04000000) ufoFatal("invalid handle used");
4991 if ((hx
& UFO_ADDR_HANDLE_BIT
) == 0) ufoFatal("not a handle");
4992 UHandleInfo
*hh
= ufoGetHandle(hx
);
4993 if (hh
== NULL
) ufoFatal("invalid handle");
4994 if (used
> hh
->size
) ufoFatal("handle used %u out of range (%u)", used
, hh
->size
);
4998 #define POP_PREPARE_HANDLE() \
4999 const uint32_t hx = ufoPop(); \
5000 uint32_t idx = ufoPop(); \
5001 if ((hx & UFO_ADDR_HANDLE_BIT) == 0) ufoFatal("not a handle"); \
5002 if (idx > 0x1fffffffU - UFO_ADDR_HANDLE_OFS_MASK) ufoFatal("handle index %u out of range", idx); \
5003 idx += (hx & UFO_ADDR_HANDLE_OFS_MASK); \
5004 UHandleInfo *hh = ufoGetHandle(hx); \
5005 if (hh == NULL) ufoFatal("invalid handle")
5008 // ( idx hx -- value )
5009 UFWORD(PAR_HANDLE_LOAD_BYTE
) {
5010 POP_PREPARE_HANDLE();
5011 if (idx
>= hh
->size
) ufoFatal("handle index %u out of range (%u)", idx
, hh
->size
);
5012 ufoPush(hh
->data
[idx
]);
5016 // ( idx hx -- value )
5017 UFWORD(PAR_HANDLE_LOAD_WORD
) {
5018 POP_PREPARE_HANDLE();
5019 if (idx
>= hh
->size
|| hh
->size
- idx
< 2u) {
5020 ufoFatal("handle index %u out of range (%u)", idx
, hh
->size
);
5022 #ifdef UFO_FAST_MEM_ACCESS
5023 ufoPush(*(const uint16_t *)(hh
->data
+ idx
));
5025 uint32_t res
= hh
->data
[idx
];
5026 res
|= hh
->data
[idx
+ 1u] << 8;
5032 // ( idx hx -- value )
5033 UFWORD(PAR_HANDLE_LOAD_CELL
) {
5034 POP_PREPARE_HANDLE();
5035 if (idx
>= hh
->size
|| hh
->size
- idx
< 4u) {
5036 ufoFatal("handle index %u out of range (%u)", idx
, hh
->size
);
5038 #ifdef UFO_FAST_MEM_ACCESS
5039 ufoPush(*(const uint32_t *)(hh
->data
+ idx
));
5041 uint32_t res
= hh
->data
[idx
];
5042 res
|= hh
->data
[idx
+ 1u] << 8;
5043 res
|= hh
->data
[idx
+ 2u] << 16;
5044 res
|= hh
->data
[idx
+ 3u] << 24;
5050 // ( value idx hx -- value )
5051 UFWORD(PAR_HANDLE_STORE_BYTE
) {
5052 POP_PREPARE_HANDLE();
5053 const uint32_t value
= ufoPop();
5054 if (idx
>= hh
->size
) ufoFatal("handle index %u out of range (%u)", idx
, hh
->size
);
5055 hh
->data
[idx
] = value
;
5059 // ( value idx hx -- )
5060 UFWORD(PAR_HANDLE_STORE_WORD
) {
5061 POP_PREPARE_HANDLE();
5062 const uint32_t value
= ufoPop();
5063 if (idx
>= hh
->size
|| hh
->size
- idx
< 2u) {
5064 ufoFatal("handle index %u out of range (%u)", idx
, hh
->size
);
5066 #ifdef UFO_FAST_MEM_ACCESS
5067 *(uint16_t *)(hh
->data
+ idx
) = (uint16_t)value
;
5069 hh
->data
[idx
] = (uint8_t)value
;
5070 hh
->data
[idx
+ 1u] = (uint8_t)(value
>> 8);
5075 // ( value idx hx -- )
5076 UFWORD(PAR_HANDLE_STORE_CELL
) {
5077 POP_PREPARE_HANDLE();
5078 const uint32_t value
= ufoPop();
5079 if (idx
>= hh
->size
|| hh
->size
- idx
< 4u) {
5080 ufoFatal("handle index %u out of range (%u)", idx
, hh
->size
);
5082 #ifdef UFO_FAST_MEM_ACCESS
5083 *(uint32_t *)(hh
->data
+ idx
) = value
;
5085 hh
->data
[idx
] = (uint8_t)value
;
5086 hh
->data
[idx
+ 1u] = (uint8_t)(value
>> 8);
5087 hh
->data
[idx
+ 2u] = (uint8_t)(value
>> 16);
5088 hh
->data
[idx
+ 3u] = (uint8_t)(value
>> 24);
5093 // ////////////////////////////////////////////////////////////////////////// //
5097 // DEBUG:(DECOMPILE-CFA)
5099 UFWORD(DEBUG_DECOMPILE_CFA
) {
5100 const uint32_t cfa
= ufoPop();
5101 ufoDecompileWord(cfa
);
5107 ufoPush((uint32_t)ufo_get_msecs());
5110 // this is called by INTERPRET when it is out of input stream
5111 UFWORD(UFO_INTERPRET_FINISHED
) {
5117 UFWORD(MT_NEW_STATE
) {
5118 UfoState
*st
= ufoNewState(ufoPop());
5124 UFWORD(MT_FREE_STATE
) {
5125 UfoState
*st
= ufoFindState(ufoPop());
5126 if (st
== NULL
) ufoFatal("cannot free unknown state");
5127 if (st
== ufoCurrState
) ufoFatal("cannot free current state");
5131 // MTASK:STATE-NAME@
5132 // ( stid -- addr count )
5134 UFWORD(MT_GET_STATE_NAME
) {
5135 UfoState
*st
= ufoFindState(ufoPop());
5136 if (st
== NULL
) ufoFatal("unknown state");
5138 uint32_t addr
= ufoPop();
5140 while (st
->name
[count
] != 0) {
5141 ufoImgPutU8Ext(addr
+ count
, ((const unsigned char *)st
->name
)[count
]);
5144 ufoImgPutU8Ext(addr
+ count
, 0);
5149 // MTASK:STATE-NAME!
5150 // ( addr count stid -- )
5151 UFWORD(MT_SET_STATE_NAME
) {
5152 UfoState
*st
= ufoFindState(ufoPop());
5153 if (st
== NULL
) ufoFatal("unknown state");
5154 uint32_t count
= ufoPop();
5155 uint32_t addr
= ufoPop();
5156 if ((count
& ((uint32_t)1 << 31)) == 0) {
5157 if (count
> UFO_MAX_TASK_NAME
) ufoFatal("task name too long");
5158 for (uint32_t f
= 0; f
< count
; f
+= 1u) {
5159 ((unsigned char *)st
->name
)[f
] = ufoImgGetU8Ext(addr
+ f
);
5161 st
->name
[count
] = 0;
5165 // MTASK:STATE-FIRST
5167 UFWORD(MT_STATE_FIRST
) {
5169 while (fidx
!= (uint32_t)(UFO_MAX_STATES
/32) && ufoStateUsedBitmap
[fidx
] == 0) fidx
+= 1u;
5170 // there should be at least one allocated state
5171 ufo_assert(fidx
!= (uint32_t)(UFO_MAX_STATES
/32));
5172 uint32_t bmp
= ufoStateUsedBitmap
[fidx
];
5174 while ((bmp
& 0x01) == 0) { fidx
+= 1u; bmp
>>= 1; }
5179 // ( stid -- stid / 0 )
5180 UFWORD(MT_STATE_NEXT
) {
5181 uint32_t stid
= ufoPop();
5182 if (stid
!= 0 && stid
< (uint32_t)(UFO_MAX_STATES
/32)) {
5183 // it is already incremented for us, yay!
5184 uint32_t fidx
= stid
/ 32u;
5185 uint8_t fofs
= stid
& 0x1f;
5186 while (fidx
< (uint32_t)(UFO_MAX_STATES
/32)) {
5187 const uint32_t bmp
= ufoStateUsedBitmap
[fidx
];
5189 while (fofs
!= 32u) {
5190 if ((bmp
& ((uint32_t)1 << (fofs
& 0x1f))) == 0) fofs
+= 1u;
5193 ufoPush(fidx
* 32u + fofs
+ 1u);
5197 fidx
+= 1u; fofs
= 0;
5205 // ( ... argc stid -- )
5206 UFWORD(MT_YIELD_TO
) {
5207 UfoState
*st
= ufoFindState(ufoPop());
5208 if (st
== NULL
) ufoFatal("cannot yield to unknown state");
5209 //if (st == ufoDebuggerState) ufoFatal("cannot yield to debugger"); // why not?
5210 const uint32_t argc
= ufoPop();
5211 if (argc
> 256) ufoFatal("too many YIELD-TO arguments");
5212 UfoState
*curst
= ufoCurrState
;
5213 if (st
!= ufoCurrState
) {
5214 for (uint32_t f
= 0; f
< argc
; f
+= 1) {
5215 ufoCurrState
= curst
;
5216 const uint32_t n
= ufoPop();
5220 ufoCurrState
= curst
; // we need to use API call to switch states
5222 ufoSwitchToState(st
); // always use API call for this!
5227 // MTASK:SET-SELF-AS-DEBUGGER
5229 UFWORD(MT_SET_SELF_AS_DEBUGGER
) {
5230 ufoDebuggerState
= ufoCurrState
;
5235 // debugger task receives debugge stid on the data stack, and -1 as argc.
5236 // i.e. debugger stask is: ( -1 old-stid )
5237 UFWORD(MT_DEBUGGER_BP
) {
5238 if (ufoDebuggerState
!= NULL
&& ufoCurrState
!= ufoDebuggerState
) {
5239 UfoState
*st
= ufoCurrState
;
5240 ufoSwitchToState(ufoDebuggerState
); // always use API call for this!
5247 // MTASK:DEBUGGER-RESUME
5249 UFWORD(MT_RESUME_DEBUGEE
) {
5250 if (ufoCurrState
!= ufoDebuggerState
) ufoFatal("cannot resume from non-debugger");
5251 UfoState
*st
= ufoFindState(ufoPop());
5252 if (st
== NULL
) ufoFatal("cannot yield to unknown state");
5253 if (st
== ufoCurrState
) ufoFatal("cannot resume into debugger itself");
5254 ufoSwitchToState(st
); // always use API call for this!
5258 // MTASK:DEBUGGER-SINGLE-STEP
5260 UFWORD(MT_SINGLE_STEP_DEBUGEE
) {
5261 if (ufoCurrState
!= ufoDebuggerState
) ufoFatal("cannot resume from non-debugger");
5262 UfoState
*st
= ufoFindState(ufoPop());
5263 if (st
== NULL
) ufoFatal("cannot yield to unknown state");
5264 if (st
== ufoCurrState
) ufoFatal("cannot resume into debugger itself");
5265 ufoSwitchToState(st
); // always use API call for this!
5266 ufoSingleStep
= 2; // it will be decremented after returning from this word
5271 UFWORD(MT_STATE_IP_GET
) {
5272 UfoState
*st
= ufoFindState(ufoPop());
5273 if (st
== NULL
) ufoFatal("unknown state");
5279 UFWORD(MT_STATE_IP_SET
) {
5280 UfoState
*st
= ufoFindState(ufoPop());
5281 if (st
== NULL
) ufoFatal("unknown state");
5287 UFWORD(MT_STATE_REGA_GET
) {
5288 UfoState
*st
= ufoFindState(ufoPop());
5289 if (st
== NULL
) ufoFatal("unknown state");
5295 UFWORD(MT_STATE_REGA_SET
) {
5296 UfoState
*st
= ufoFindState(ufoPop());
5297 if (st
== NULL
) ufoFatal("unknown state");
5298 st
->regA
= ufoPop();
5301 // MTASK:STATE-BASE@
5303 UFWORD(MT_STATE_BASE_GET
) {
5304 UfoState
*st
= ufoFindState(ufoPop());
5305 if (st
== NULL
) ufoFatal("unknown state");
5306 if (st
== ufoCurrState
) {
5307 ufoPush(ufoImgGetU32(ufoAddrBASE
));
5309 ufoPush(st
->baseValue
);
5313 // MTASK:STATE-BASE!
5315 UFWORD(MT_STATE_BASE_SET
) {
5316 UfoState
*st
= ufoFindState(ufoPop());
5317 if (st
== NULL
) ufoFatal("unknown state");
5318 uint32_t base
= ufoPop();
5319 if (st
== ufoCurrState
) {
5320 ufoImgPutU32(ufoAddrBASE
, base
);
5322 st
->baseValue
= base
;
5326 // MTASK:STATE-RPOPCFA@
5328 UFWORD(MT_STATE_RPOPCFA_GET
) {
5329 UfoState
*st
= ufoFindState(ufoPop());
5330 if (st
== NULL
) ufoFatal("unknown state");
5331 ufoPush(st
->vmRPopCFA
);
5334 // MTASK:STATE-RPOPCFA!
5336 UFWORD(MT_STATE_RPOPCFA_SET
) {
5337 UfoState
*st
= ufoFindState(ufoPop());
5338 if (st
== NULL
) ufoFatal("unknown state");
5339 st
->vmRPopCFA
= ufoPop();
5342 // MTASK:ACTIVE-STATE
5344 UFWORD(MT_ACTIVE_STATE
) {
5345 ufoPush(ufoCurrState
->id
);
5348 // MTASK:YIELDED-FROM
5350 UFWORD(MT_YIELDED_FROM
) {
5351 if (ufoYieldedState
!= NULL
) {
5352 ufoPush(ufoYieldedState
->id
);
5359 // ( stid -- depth )
5360 UFWORD(MT_DSTACK_DEPTH_GET
) {
5361 UfoState
*st
= ufoFindState(ufoPop());
5362 if (st
== NULL
) ufoFatal("unknown state");
5367 // ( stid -- depth )
5368 UFWORD(MT_RSTACK_DEPTH_GET
) {
5369 UfoState
*st
= ufoFindState(ufoPop());
5370 if (st
== NULL
) ufoFatal("unknown state");
5371 ufoPush(st
->RP
- st
->RPTop
);
5377 UfoState
*st
= ufoFindState(ufoPop());
5378 if (st
== NULL
) ufoFatal("unknown state");
5384 UFWORD(MT_LBP_GET
) {
5385 UfoState
*st
= ufoFindState(ufoPop());
5386 if (st
== NULL
) ufoFatal("unknown state");
5391 // ( depth stid -- )
5392 UFWORD(MT_DSTACK_DEPTH_SET
) {
5393 UfoState
*st
= ufoFindState(ufoPop());
5394 if (st
== NULL
) ufoFatal("unknown state");
5395 uint32_t idx
= ufoPop();
5396 if (idx
>= UFO_DSTACK_SIZE
) ufoFatal("invalid stack index %u (%u)", idx
, UFO_DSTACK_SIZE
);
5401 // ( stid -- depth )
5402 UFWORD(MT_RSTACK_DEPTH_SET
) {
5403 UfoState
*st
= ufoFindState(ufoPop());
5404 if (st
== NULL
) ufoFatal("unknown state");
5405 uint32_t idx
= ufoPop();
5406 const uint32_t left
= UFO_RSTACK_SIZE
- st
->RPTop
;
5407 if (idx
>= left
) ufoFatal("invalid stack index %u (%u)", idx
, left
);
5408 st
->RP
= st
->RPTop
+ idx
;
5414 UfoState
*st
= ufoFindState(ufoPop());
5415 if (st
== NULL
) ufoFatal("unknown state");
5421 UFWORD(MT_LBP_SET
) {
5422 UfoState
*st
= ufoFindState(ufoPop());
5423 if (st
== NULL
) ufoFatal("unknown state");
5428 // ( idx stid -- value )
5429 UFWORD(MT_DSTACK_LOAD
) {
5430 UfoState
*st
= ufoFindState(ufoPop());
5431 if (st
== NULL
) ufoFatal("unknown state");
5432 uint32_t idx
= ufoPop();
5433 if (idx
>= st
->SP
) ufoFatal("invalid stack index %u (%u)", idx
, st
->SP
);
5434 ufoPush(st
->dStack
[st
->SP
- idx
- 1u]);
5438 // ( idx stid -- value )
5439 UFWORD(MT_RSTACK_LOAD
) {
5440 UfoState
*st
= ufoFindState(ufoPop());
5441 if (st
== NULL
) ufoFatal("unknown state");
5442 uint32_t idx
= ufoPop();
5443 if (idx
>= st
->RP
- st
->RPTop
) ufoFatal("invalid stack index %u (%u)", idx
, st
->RP
- st
->RPTop
);
5444 ufoPush(st
->dStack
[st
->RP
- idx
- 1u]);
5448 // ( idx stid -- value )
5449 UFWORD(MT_LSTACK_LOAD
) {
5450 UfoState
*st
= ufoFindState(ufoPop());
5451 if (st
== NULL
) ufoFatal("unknown state");
5452 uint32_t idx
= ufoPop();
5453 if (idx
>= st
->LP
) ufoFatal("invalid lstack index %u (%u)", idx
, st
->LP
);
5454 ufoPush(st
->lStack
[st
->LP
- idx
- 1u]);
5458 // ( value idx stid -- )
5459 UFWORD(MT_DSTACK_STORE
) {
5460 UfoState
*st
= ufoFindState(ufoPop());
5461 if (st
== NULL
) ufoFatal("unknown state");
5462 uint32_t idx
= ufoPop();
5463 uint32_t value
= ufoPop();
5464 if (idx
>= st
->SP
) ufoFatal("invalid stack index %u (%u)", idx
, st
->SP
);
5465 st
->dStack
[st
->SP
- idx
- 1u] = value
;
5469 // ( value idx stid -- )
5470 UFWORD(MT_RSTACK_STORE
) {
5471 UfoState
*st
= ufoFindState(ufoPop());
5472 if (st
== NULL
) ufoFatal("unknown state");
5473 uint32_t idx
= ufoPop();
5474 uint32_t value
= ufoPop();
5475 if (idx
>= st
->RP
- st
->RPTop
) ufoFatal("invalid stack index %u (%u)", idx
, st
->RP
- st
->RPTop
);
5476 st
->dStack
[st
->RP
- idx
- 1u] = value
;
5480 // ( value idx stid -- )
5481 UFWORD(MT_LSTACK_STORE
) {
5482 UfoState
*st
= ufoFindState(ufoPop());
5483 if (st
== NULL
) ufoFatal("unknown state");
5484 uint32_t idx
= ufoPop();
5485 uint32_t value
= ufoPop();
5486 if (idx
>= st
->LP
) ufoFatal("invalid stack index %u (%u)", idx
, st
->LP
);
5487 st
->dStack
[st
->LP
- idx
- 1u] = value
;
5491 // ////////////////////////////////////////////////////////////////////////// //
5492 // initial dictionary definitions
5497 #define UFWORD(name_) do { \
5498 const uint32_t xcfa_ = ufoCFAsUsed; \
5499 ufo_assert(xcfa_ < UFO_MAX_NATIVE_CFAS); \
5500 ufoForthCFAs[xcfa_] = &ufoWord_##name_; \
5502 ufoDefineNative(""#name_, xcfa_, 0); \
5505 #define UFWORDX(strname_,name_) do { \
5506 const uint32_t xcfa_ = ufoCFAsUsed; \
5507 ufo_assert(xcfa_ < UFO_MAX_NATIVE_CFAS); \
5508 ufoForthCFAs[xcfa_] = &ufoWord_##name_; \
5510 ufoDefineNative(strname_, xcfa_, 0); \
5513 #define UFWORD_IMM(name_) do { \
5514 const uint32_t xcfa_ = ufoCFAsUsed; \
5515 ufo_assert(xcfa_ < UFO_MAX_NATIVE_CFAS); \
5516 ufoForthCFAs[xcfa_] = &ufoWord_##name_; \
5518 ufoDefineNative(""#name_, xcfa_, 1); \
5521 #define UFWORDX_IMM(strname_,name_) do { \
5522 const uint32_t xcfa_ = ufoCFAsUsed; \
5523 ufo_assert(xcfa_ < UFO_MAX_NATIVE_CFAS); \
5524 ufoForthCFAs[xcfa_] = &ufoWord_##name_; \
5526 ufoDefineNative(strname_, xcfa_, 1); \
5529 #define UFC(name_) ufoImgEmitU32_NoInline(ufoFindWordChecked(name_))
5532 //==========================================================================
5534 // ufoFindWordChecked
5536 //==========================================================================
5537 UFO_DISABLE_INLINE
uint32_t ufoFindWordChecked (const char *wname
) {
5538 const uint32_t cfa
= ufoFindWord(wname
);
5539 if (cfa
== 0) ufoFatal("word '%s' not found", wname
);
5544 //==========================================================================
5548 // get "FORTH" vocid
5550 //==========================================================================
5551 uint32_t ufoGetForthVocId (void) {
5552 return ufoForthVocId
;
5556 //==========================================================================
5558 // ufoVocSetOnlyDefs
5560 //==========================================================================
5561 void ufoVocSetOnlyDefs (uint32_t vocid
) {
5562 ufoImgPutU32(ufoAddrCurrent
, vocid
);
5563 ufoImgPutU32(ufoAddrContext
, vocid
);
5567 //==========================================================================
5571 // return voc PFA (vocid)
5573 //==========================================================================
5574 uint32_t ufoCreateVoc (const char *wname
, uint32_t parentvocid
, uint32_t flags
) {
5575 // create wordlist struct
5576 // typeid, used by Forth code (structs and such)
5577 ufoImgEmitU32(0); // typeid
5578 // vocid points here, to "LATEST-LFA"
5579 const uint32_t vocid
= UFO_GET_DP();
5580 //fprintf(stderr, "NEW VOCID (%s): 0x%08x\n", wname, vocid);
5581 ufoImgEmitU32(0); // latest
5582 const uint32_t vlink
= UFO_GET_DP();
5583 if ((vocid
& UFO_ADDR_TEMP_BIT
) == 0) {
5584 ufoImgEmitU32(ufoImgGetU32(ufoAddrVocLink
)); // voclink
5585 ufoImgPutU32(ufoAddrVocLink
, vlink
); // update voclink
5590 ufoImgEmitU32(parentvocid
); // parent
5591 const uint32_t hdraddr
= UFO_GET_DP();
5592 ufoImgEmitU32(0); // word header
5593 // create empty hash table
5594 for (int f
= 0; f
< UFO_HASHTABLE_SIZE
; f
+= 1) ufoImgEmitU32(0);
5595 // update CONTEXT and CURRENT if this is the first wordlist ever
5596 if (ufoImgGetU32(ufoAddrContext
) == 0) {
5597 ufoImgPutU32(ufoAddrContext
, vocid
);
5599 if (ufoImgGetU32(ufoAddrCurrent
) == 0) {
5600 ufoImgPutU32(ufoAddrCurrent
, vocid
);
5602 // create word header
5603 if (wname
!= NULL
&& wname
[0] != 0) {
5605 uint32_t flags = ufoImgGetU32(ufoAddrNewWordFlags);
5607 //UFW_FLAG_IMMEDIATE|
5609 //UFW_FLAG_NORETURN|
5615 flags |= UFW_FLAG_VOCAB;
5617 flags
&= 0xffffff00u
;
5618 flags
|= UFW_FLAG_VOCAB
;
5619 ufoCreateWordHeader(wname
, flags
);
5620 const uint32_t cfa
= UFO_GET_DP();
5621 ufoImgEmitU32(ufoDoVocCFA
); // cfa
5622 ufoImgEmitU32(vocid
); // pfa
5623 // update vocab header pointer
5624 const uint32_t lfa
= UFO_CFA_TO_LFA(cfa
);
5625 ufoImgPutU32(hdraddr
, UFO_LFA_TO_NFA(lfa
));
5626 #ifdef UFO_DEBUG_DUMP_NEW_HEADERS
5627 ufoDumpWordHeader(lfa
);
5634 //==========================================================================
5638 //==========================================================================
5639 static void ufoSetLatestArgs (uint32_t warg
) {
5640 const uint32_t curr
= ufoImgGetU32(ufoAddrCurrent
);
5641 const uint32_t lfa
= ufoImgGetU32(curr
);
5642 const uint32_t nfa
= UFO_LFA_TO_NFA(lfa
);
5643 uint32_t flags
= ufoImgGetU32(nfa
);
5644 //fprintf(stderr, "OLD FLAGS: 0x%08x\n", flags);
5645 flags
&= ~UFW_WARG_MASK
;
5646 flags
|= warg
& UFW_WARG_MASK
;
5647 //fprintf(stderr, "NEW FLAGS: 0x%08x\n", flags);
5648 ufoImgPutU32(nfa
, flags
);
5649 #ifdef UFO_DEBUG_DUMP_NEW_HEADERS
5650 ufoDumpWordHeader(lfa
);
5655 //==========================================================================
5659 //==========================================================================
5660 static void ufoDefineNative (const char *wname
, uint32_t cfaidx
, int immed
) {
5661 cfaidx
|= UFO_ADDR_CFA_BIT
;
5662 uint32_t flags
= ufoImgGetU32(ufoAddrNewWordFlags
);
5664 //UFW_FLAG_IMMEDIATE|
5666 //UFW_FLAG_NORETURN|
5672 if (immed
) flags
|= UFW_FLAG_IMMEDIATE
;
5673 ufoCreateWordHeader(wname
, flags
);
5674 ufoImgEmitU32(cfaidx
);
5678 //==========================================================================
5680 // ufoDefineConstant
5682 //==========================================================================
5683 static void ufoDefineConstant (const char *name
, uint32_t value
) {
5684 ufoDefineNative(name
, ufoDoConstCFA
, 0);
5685 ufoImgEmitU32(value
);
5689 //==========================================================================
5693 //==========================================================================
5695 static void ufoDefineVar (const char *name, uint32_t value) {
5696 ufoDefineNative(name, ufoDoVarCFA, 0);
5697 ufoImgEmitU32(value);
5702 //==========================================================================
5706 //==========================================================================
5708 static void ufoDefineDefer (const char *name, uint32_t value) {
5709 ufoDefineNative(name, ufoDoDeferCFA, 0);
5710 ufoImgEmitU32(value);
5715 //==========================================================================
5719 //==========================================================================
5720 static void ufoHiddenWords (void) {
5721 const uint32_t flags
= ufoImgGetU32(ufoAddrNewWordFlags
);
5722 ufoImgPutU32(ufoAddrNewWordFlags
, flags
| UFW_FLAG_HIDDEN
);
5726 //==========================================================================
5730 //==========================================================================
5731 static void ufoPublicWords (void) {
5732 const uint32_t flags
= ufoImgGetU32(ufoAddrNewWordFlags
);
5733 ufoImgPutU32(ufoAddrNewWordFlags
, flags
& ~UFW_FLAG_HIDDEN
);
5737 //==========================================================================
5741 //==========================================================================
5742 static void ufoDefineForth (const char *name
) {
5743 ufoDefineNative(name
, ufoDoForthCFA
, 0);
5747 //==========================================================================
5749 // ufoDefineForthImm
5751 //==========================================================================
5752 static void ufoDefineForthImm (const char *name
) {
5753 ufoDefineNative(name
, ufoDoForthCFA
, 1);
5757 //==========================================================================
5759 // ufoDefineForthHidden
5761 //==========================================================================
5762 static void ufoDefineForthHidden (const char *name
) {
5763 const uint32_t flags
= ufoImgGetU32(ufoAddrNewWordFlags
);
5764 ufoImgPutU32(ufoAddrNewWordFlags
, flags
| UFW_FLAG_HIDDEN
);
5765 ufoDefineNative(name
, ufoDoForthCFA
, 0);
5766 ufoImgPutU32(ufoAddrNewWordFlags
, flags
);
5770 //==========================================================================
5772 // ufoDefineSColonForth
5774 // create word suitable for scattered colon extension
5776 //==========================================================================
5777 static void ufoDefineSColonForth (const char *name
) {
5778 ufoDefineNative(name
, ufoDoForthCFA
, 0);
5779 // placeholder for scattered colon
5780 // it will compile two branches:
5781 // the first branch will jump to the first "..:" word (or over the two branches)
5782 // the second branch is never taken, and works as a pointer to the latest branch addr in the list
5783 // this way, each extension word will simply fix the last branch address, and update list tail
5784 // at the creation time, second branch points to the first branch
5785 UFC("FORTH:(BRANCH)");
5786 const uint32_t xjmp
= UFO_GET_DP();
5788 UFC("FORTH:(BRANCH)"); ufoImgEmitU32(xjmp
);
5789 ufoImgPutU32(xjmp
, UFO_GET_DP());
5793 //==========================================================================
5797 //==========================================================================
5798 UFO_FORCE_INLINE
void ufoDoneForth (void) {
5802 //==========================================================================
5806 // create a new state, its execution will start from the given CFA.
5807 // state is not automatically activated.
5809 //==========================================================================
5810 static UfoState
*ufoNewState (uint32_t cfa
) {
5811 // find free state id
5813 uint32_t bmp
= ufoStateUsedBitmap
[0];
5814 while (fidx
!= (uint32_t)(UFO_MAX_STATES
/32) && bmp
== ~(uint32_t)0) {
5816 bmp
= ufoStateUsedBitmap
[fidx
];
5818 if (fidx
== (uint32_t)(UFO_MAX_STATES
/32)) ufoFatal("too many execution states");
5819 //fprintf(stderr, "NST:000: fidx=%u; bmp=0x%08x\n", fidx, bmp);
5821 while ((bmp
& 0x01) != 0) { fidx
+= 1u; bmp
>>= 1; }
5822 ufo_assert(fidx
< UFO_MAX_STATES
);
5823 ufo_assert((ufoStateUsedBitmap
[fidx
/ 32u] & ((uint32_t)1 << (fidx
& 0x1f))) == 0);
5824 ufo_assert(ufoStateMap
[fidx
] == NULL
);
5825 UfoState
*st
= calloc(1, sizeof(UfoState
));
5826 if (st
== NULL
) ufoFatal("out of memory for states");
5829 st
->rStack
[0] = 0xdeadf00d; // dummy value
5830 st
->rStack
[1] = cfa
;
5832 st
->baseValue
= 10; // default
5833 ufoStateMap
[fidx
] = st
;
5834 ufoStateUsedBitmap
[fidx
/ 32u] |= ((uint32_t)1 << (fidx
& 0x1f));
5835 //fprintf(stderr, "NST: fidx=%u; 0x%08x\n", fidx, ufoStateUsedBitmap[fidx / 32u]);
5840 //==========================================================================
5844 // free all memory used for the state, remove it from state list.
5845 // WARNING! never free current state!
5847 //==========================================================================
5848 static void ufoFreeState (UfoState
*st
) {
5850 if (st
== ufoCurrState
) ufoFatal("cannot free active state");
5851 if (ufoYieldedState
== st
) ufoYieldedState
= NULL
;
5852 if (ufoDebuggerState
== st
) ufoDebuggerState
= NULL
;
5853 const uint32_t fidx
= st
->id
- 1u;
5854 //fprintf(stderr, "FST: fidx=%u; 0x%08x\n", fidx, ufoStateUsedBitmap[fidx / 32u]);
5855 ufo_assert(fidx
< UFO_MAX_STATES
);
5856 ufo_assert((ufoStateUsedBitmap
[fidx
/ 32u] & (1u << (fidx
& 0x1f))) != 0);
5857 ufo_assert(ufoStateMap
[fidx
] == st
);
5859 ufoStateMap
[fidx
] = NULL
;
5860 ufoStateUsedBitmap
[fidx
/ 32u] &= ~((uint32_t)1 << (fidx
& 0x1f));
5865 //==========================================================================
5869 //==========================================================================
5870 static UfoState
*ufoFindState (uint32_t stid
) {
5871 UfoState
*res
= NULL
;
5872 if (stid
!= 0 && stid
<= UFO_MAX_STATES
) {
5874 res
= ufoStateMap
[stid
];
5876 ufo_assert((ufoStateUsedBitmap
[stid
/ 32u] & (1u << (stid
& 0x1f))) != 0);
5877 ufo_assert(res
->id
== stid
+ 1u);
5879 ufo_assert((ufoStateUsedBitmap
[stid
/ 32u] & (1u << (stid
& 0x1f))) == 0);
5886 //==========================================================================
5890 //==========================================================================
5891 static void ufoSwitchToState (UfoState
*newst
) {
5892 ufo_assert(newst
!= NULL
);
5893 if (newst
!= ufoCurrState
) {
5894 ufoCurrState
->baseValue
= ufoImgGetU32(ufoAddrBASE
);
5895 ufoImgPutU32(ufoAddrBASE
, newst
->baseValue
);
5896 ufoCurrState
= newst
;
5902 //==========================================================================
5906 //==========================================================================
5907 UFO_DISABLE_INLINE
void ufoReset (void) {
5908 if (ufoCurrState
== NULL
) ufoFatal("no active execution state");
5910 ufoSP
= 0; ufoRP
= 0;
5911 ufoLP
= 0; ufoLBP
= 0;
5914 ufoVMStop
= 0; ufoVMAbort
= 0;
5918 ufoImgPutU32(ufoAddrSTATE
, 0);
5919 ufoImgPutU32(ufoAddrBASE
, 10);
5920 ufoImgPutU32(ufoAddrRedefineWarning
, UFO_REDEF_WARN_NORMAL
);
5923 ufoImgPutU32(ufoAddrDPTemp
, 0);
5925 ufoImgPutU32(ufoAddrNewWordFlags
, 0);
5926 ufoVocSetOnlyDefs(ufoForthVocId
);
5930 //==========================================================================
5934 // compile string literal, the same as QUOTE_IMM
5936 //==========================================================================
5937 static void ufoCompileStrLit (const char *str
) {
5938 if (str
== NULL
) str
= "";
5939 const size_t slen
= strlen(str
);
5940 if (slen
> 255) ufoFatal("string literal too long");
5941 UFC("FORTH:(STRLIT8)");
5942 ufoImgEmitU8((uint8_t)slen
);
5943 for (size_t f
= 0; f
< slen
; f
+= 1) {
5944 ufoImgEmitU8(((const unsigned char *)str
)[f
]);
5951 //==========================================================================
5955 //==========================================================================
5956 static __attribute__((unused
)) void ufoCompileLit (uint32_t value
) {
5958 ufoImgEmitU32(value
);
5962 //==========================================================================
5966 //==========================================================================
5967 UFO_FORCE_INLINE
uint32_t ufoMarkFwd (void) {
5968 const uint32_t res
= UFO_GET_DP();
5974 //==========================================================================
5978 //==========================================================================
5979 UFO_FORCE_INLINE
void ufoResolveFwd (uint32_t jaddr
) {
5980 ufoImgPutU32(jaddr
, UFO_GET_DP());
5984 //==========================================================================
5988 //==========================================================================
5989 UFO_FORCE_INLINE
uint32_t ufoMarkBwd (void) {
5990 return UFO_GET_DP();
5994 //==========================================================================
5998 //==========================================================================
5999 UFO_FORCE_INLINE
void ufoResolveBwd (uint32_t jaddr
) {
6000 ufoImgEmitU32(jaddr
);
6004 //==========================================================================
6006 // ufoDefineInterpret
6008 // define "INTERPRET" in Forth
6010 //==========================================================================
6011 UFO_DISABLE_INLINE
void ufoDefineInterpret (void) {
6012 // skip comments, parse name, refilling lines if necessary
6013 ufoDefineForthHidden("(INTERPRET-PARSE-NAME)");
6014 const uint32_t label_ipn_again
= ufoMarkBwd();
6015 UFC("TRUE"); UFC("(PARSE-SKIP-COMMENTS)");
6018 UFC("FORTH:(TBRANCH)"); const uint32_t label_ipn_exit_fwd
= ufoMarkFwd();
6021 UFC("FORTH:(TBRANCH)"); ufoResolveBwd(label_ipn_again
);
6023 UFC("FORTH:STATE"); UFC("@");
6024 ufoCompileStrLit("unexpected end of file"); UFC("?ERROR");
6025 UFC("FORTH:(UFO-INTERPRET-FINISHED)");
6026 // patch the jump above
6027 ufoResolveFwd(label_ipn_exit_fwd
);
6028 UFC("FORTH:(EXIT)");
6030 //ufoDecompileWord(ufoFindWordChecked("(INTERPRET-PARSE-NAME)"));
6032 ufoDefineForth("INTERPRET");
6033 const uint32_t label_it_again
= ufoMarkBwd();
6034 UFC("FORTH:(INTERPRET-PARSE-NAME)");
6035 // try defered checker
6036 // ( addr count FALSE -- addr count FALSE / TRUE )
6037 UFC("FALSE"); UFC("(INTERPRET-CHECK-WORD)");
6038 UFC("FORTH:(TBRANCH)"); ufoResolveBwd(label_it_again
);
6039 UFC("2DUP"); UFC("FIND-WORD"); // ( addr count cfa TRUE / addr count FALSE )
6040 UFC("FORTH:(0BRANCH)"); const uint32_t label_it_try_num
= ufoMarkFwd();
6041 UFC("NROT"); UFC("2DROP"); // drop word string
6042 UFC("STATE"); UFC("@");
6043 UFC("FORTH:(0BRANCH)"); const uint32_t label_it_exec_fwd
= ufoMarkFwd();
6044 // compiling; check immediate bit
6045 UFC("DUP"); UFC("CFA->NFA"); UFC("@");
6046 UFC("COMPILER:(WFLAG-IMMEDIATE)"); UFC("AND");
6047 UFC("FORTH:(TBRANCH)"); const uint32_t label_it_exec_imm
= ufoMarkFwd();
6049 UFC("FORTH:COMPILE,");
6050 UFC("FORTH:(BRANCH)"); ufoResolveBwd(label_it_again
);
6052 ufoResolveFwd(label_it_exec_imm
);
6053 ufoResolveFwd(label_it_exec_fwd
);
6055 UFC("FORTH:(BRANCH)"); ufoResolveBwd(label_it_again
);
6056 // not a word, try a number
6057 ufoResolveFwd(label_it_try_num
);
6058 UFC("2DUP"); UFC("TRUE"); UFC("BASE"); UFC("@"); UFC("(BASED-NUMBER)");
6059 // (BASED-NUMBER) ( addr count allowsign? base -- num TRUE / FALSE )
6060 UFC("FORTH:(0BRANCH)"); const uint32_t label_it_num_error
= ufoMarkFwd();
6062 UFC("NROT"); UFC("2DROP"); // drop word string
6063 // do we need to compile it?
6064 UFC("STATE"); UFC("@");
6065 UFC("FORTH:(0BRANCH)"); ufoResolveBwd(label_it_again
);
6066 // compile "(LITERAL)" (do it properly, with "LITCFA")
6067 UFC("FORTH:(LITCFA)"); UFC("FORTH:(LIT)");
6068 UFC("FORTH:COMPILE,"); // compile "(LIT)" CFA
6069 UFC("FORTH:,"); // compile number
6070 UFC("FORTH:(BRANCH)"); ufoResolveBwd(label_it_again
);
6072 ufoResolveFwd(label_it_num_error
);
6073 // ( addr count FALSE -- addr count FALSE / TRUE )
6074 UFC("FALSE"); UFC("(INTERPRET-WORD-NOT-FOUND)");
6075 UFC("FORTH:(TBRANCH)"); ufoResolveBwd(label_it_again
);
6076 UFC("ENDCR"); UFC("SPACE"); UFC("XTYPE");
6077 ufoCompileStrLit(" -- wut?\n"); UFC("TYPE");
6078 ufoCompileStrLit("unknown word");
6081 //ufoDecompileWord(ufoFindWordChecked("INTERPRET"));
6085 //==========================================================================
6089 //==========================================================================
6090 UFO_DISABLE_INLINE
void ufoInitBaseDict (void) {
6091 uint32_t imgAddr
= 0;
6093 // reserve 64 bytes for nothing
6094 for (uint32_t f
= 0; f
< 64; f
+= 1) {
6095 ufoImgPutU8(imgAddr
, 0);
6099 while ((imgAddr
& 3) != 0) {
6100 ufoImgPutU8(imgAddr
, 0);
6105 ufoAddrBASE
= imgAddr
;
6106 ufoImgPutU32(imgAddr
, 10); imgAddr
+= 4u;
6109 ufoAddrSTATE
= imgAddr
;
6110 ufoImgPutU32(imgAddr
, 0); imgAddr
+= 4u;
6113 ufoAddrDP
= imgAddr
;
6114 ufoImgPutU32(imgAddr
, 0); imgAddr
+= 4u;
6117 ufoAddrDPTemp
= imgAddr
;
6118 ufoImgPutU32(imgAddr
, 0); imgAddr
+= 4u;
6121 ufoAddrTIBx
= imgAddr
;
6122 ufoImgPutU32(imgAddr
, 0); imgAddr
+= 4u;
6125 ufoAddrINx
= imgAddr
;
6126 ufoImgPutU32(imgAddr
, 0); imgAddr
+= 4u;
6129 ufoAddrContext
= imgAddr
;
6130 ufoImgPutU32(imgAddr
, 0); imgAddr
+= 4u;
6133 ufoAddrCurrent
= imgAddr
;
6134 ufoImgPutU32(imgAddr
, 0); imgAddr
+= 4u;
6137 ufoAddrLastXFA
= imgAddr
;
6138 ufoImgPutU32(imgAddr
, 0); imgAddr
+= 4u;
6141 ufoAddrVocLink
= imgAddr
;
6142 ufoImgPutU32(imgAddr
, 0); imgAddr
+= 4u;
6145 ufoAddrNewWordFlags
= imgAddr
;
6146 ufoImgPutU32(imgAddr
, UFW_FLAG_PROTECTED
); imgAddr
+= 4u;
6148 // WORD-REDEFINE-WARN-MODE
6149 ufoAddrRedefineWarning
= imgAddr
;
6150 ufoImgPutU32(imgAddr
, UFO_REDEF_WARN_NORMAL
); imgAddr
+= 4u;
6152 ufoImgPutU32(ufoAddrDP
, imgAddr
);
6153 ufoImgPutU32(ufoAddrDPTemp
, 0);
6156 fprintf(stderr
, "INITIAL HERE: 0x%08x (0x%08x)\n", imgAddr
, UFO_GET_DP());
6161 //==========================================================================
6163 // ufoInitBasicWords
6165 //==========================================================================
6166 UFO_DISABLE_INLINE
void ufoInitBasicWords (void) {
6167 ufoDefineConstant("FALSE", 0);
6168 ufoDefineConstant("TRUE", ufoTrueValue
);
6170 ufoDefineConstant("BL", 32);
6171 ufoDefineConstant("NL", 10);
6174 ufoDefineConstant("BASE", ufoAddrBASE
);
6175 ufoDefineConstant("STATE", ufoAddrSTATE
);
6176 ufoDefineConstant("TIB", ufoAddrTIBx
);
6177 ufoDefineConstant(">IN", ufoAddrINx
);
6178 ufoDefineConstant("(STD-TIB-ADDR)", ufoDefTIB
);
6179 ufoDefineConstant("CONTEXT", ufoAddrContext
);
6180 ufoDefineConstant("CURRENT", ufoAddrCurrent
);
6183 ufoDefineConstant("(LATEST-XFA)", ufoAddrLastXFA
);
6184 ufoDefineConstant("(VOC-LINK)", ufoAddrVocLink
);
6185 ufoDefineConstant("(NEW-WORD-FLAGS)", ufoAddrNewWordFlags
);
6186 ufoDefineConstant("(ADDR-TEMP-BIT)", UFO_ADDR_TEMP_BIT
);
6187 ufoDefineConstant("(ADDR-CFA-BIT)", UFO_ADDR_CFA_BIT
);
6188 ufoDefineConstant("(ADDR-HANDLE-BIT)", UFO_ADDR_HANDLE_BIT
);
6189 ufoDefineConstant("(MAX-HANDLE-OFS)", UFO_ADDR_HANDLE_OFS_MASK
);
6191 ufoDefineConstant("(DP)", ufoAddrDP
);
6192 ufoDefineConstant("(DP-TEMP)", ufoAddrDPTemp
);
6195 //UFWORDX("(UFO-BUCKET-STATS)", PAR_UFO_BUCKET_STATS);
6196 UFWORDX("SP0!", SP0_STORE
);
6197 UFWORDX("RP0!", RP0_STORE
);
6199 UFWORDX("PAD", PAD
);
6202 UFWORDX("C@", CPEEK
);
6203 UFWORDX("W@", WPEEK
);
6206 UFWORDX("C!", CPOKE
);
6207 UFWORDX("W!", WPOKE
);
6209 UFWORDX(",", COMMA
);
6210 UFWORDX("C,", CCOMMA
);
6211 UFWORDX("W,", WCOMMA
);
6213 UFWORDX("A@", REGA_LOAD
);
6214 UFWORDX("A!", REGA_STORE
);
6216 UFWORDX("@A+", PEEK_REGA_IDX
);
6217 UFWORDX("C@A+", CPEEK_REGA_IDX
);
6218 UFWORDX("W@A+", WPEEK_REGA_IDX
);
6220 UFWORDX("!A+", POKE_REGA_IDX
);
6221 UFWORDX("C!A+", CPOKE_REGA_IDX
);
6222 UFWORDX("W!A+", WPOKE_REGA_IDX
);
6225 UFWORDX("(LIT)", PAR_LIT
); ufoSetLatestArgs(UFW_WARG_LIT
);
6226 UFWORDX("(LITCFA)", PAR_LITCFA
); ufoSetLatestArgs(UFW_WARG_CFA
);
6227 UFWORDX("(LITVOCID)", PAR_LITVOCID
); ufoSetLatestArgs(UFW_WARG_VOCID
);
6228 UFWORDX("(STRLIT8)", PAR_STRLIT8
); ufoSetLatestArgs(UFW_WARG_C1STRZ
);
6229 UFWORDX("(EXIT)", PAR_EXIT
);
6231 UFWORDX("(UFO-INTERPRET-FINISHED)", UFO_INTERPRET_FINISHED
);
6233 ufoStrLit8CFA
= ufoFindWordChecked("FORTH:(STRLIT8)");
6235 UFWORDX("(L-ENTER)", PAR_LENTER
); ufoSetLatestArgs(UFW_WARG_LIT
);
6236 UFWORDX("(L-LEAVE)", PAR_LLEAVE
);
6237 UFWORDX("(LOCAL@)", PAR_LOCAL_LOAD
);
6238 UFWORDX("(LOCAL!)", PAR_LOCAL_STORE
);
6240 UFWORDX("(BRANCH)", PAR_BRANCH
); ufoSetLatestArgs(UFW_WARG_BRANCH
);
6241 UFWORDX("(TBRANCH)", PAR_TBRANCH
); ufoSetLatestArgs(UFW_WARG_BRANCH
);
6242 UFWORDX("(0BRANCH)", PAR_0BRANCH
); ufoSetLatestArgs(UFW_WARG_BRANCH
);
6245 UFWORDX("GET-MSECS", GET_MSECS
);
6249 //==========================================================================
6251 // ufoInitBasicCompilerWords
6253 //==========================================================================
6254 UFO_DISABLE_INLINE
void ufoInitBasicCompilerWords (void) {
6255 ufoVocSetOnlyDefs(ufoCompilerVocId
);
6257 ufoDefineConstant("(CFAIDX-DO-FORTH)", ufoDoForthCFA
);
6258 ufoDefineConstant("(CFAIDX-DO-VAR)", ufoDoVariableCFA
);
6259 ufoDefineConstant("(CFAIDX-DO-VALUE)", ufoDoValueCFA
);
6260 ufoDefineConstant("(CFAIDX-DO-CONST)", ufoDoConstCFA
);
6261 ufoDefineConstant("(CFAIDX-DO-DEFER)", ufoDoDeferCFA
);
6262 ufoDefineConstant("(CFAIDX-DO-VOC)", ufoDoVocCFA
);
6263 ufoDefineConstant("(CFAIDX-DO-CREATE)", ufoDoCreateCFA
);
6265 ufoDefineConstant("(WFLAG-IMMEDIATE)", UFW_FLAG_IMMEDIATE
);
6266 ufoDefineConstant("(WFLAG-SMUDGE)", UFW_FLAG_SMUDGE
);
6267 ufoDefineConstant("(WFLAG-NORETURN)", UFW_FLAG_NORETURN
);
6268 ufoDefineConstant("(WFLAG-HIDDEN)", UFW_FLAG_HIDDEN
);
6269 ufoDefineConstant("(WFLAG-CBLOCK)", UFW_FLAG_CBLOCK
);
6270 ufoDefineConstant("(WFLAG-VOCAB)", UFW_FLAG_VOCAB
);
6271 ufoDefineConstant("(WFLAG-SCOLON)", UFW_FLAG_SCOLON
);
6272 ufoDefineConstant("(WFLAG-PROTECTED)", UFW_FLAG_PROTECTED
);
6274 ufoDefineConstant("(WARG-MASK)", UFW_WARG_MASK
);
6275 ufoDefineConstant("(WARG-NONE)", UFW_WARG_NONE
);
6276 ufoDefineConstant("(WARG-BRANCH)", UFW_WARG_BRANCH
);
6277 ufoDefineConstant("(WARG-LIT)", UFW_WARG_LIT
);
6278 ufoDefineConstant("(WARG-C4STRZ)", UFW_WARG_C4STRZ
);
6279 ufoDefineConstant("(WARG-CFA)", UFW_WARG_CFA
);
6280 ufoDefineConstant("(WARG-CBLOCK)", UFW_WARG_CBLOCK
);
6281 ufoDefineConstant("(WARG-VOCID)", UFW_WARG_VOCID
);
6282 ufoDefineConstant("(WARG-C1STRZ)", UFW_WARG_C1STRZ
);
6284 ufoDefineConstant("(VOCOFS-LATEST)", UFW_VOCAB_OFS_LATEST
);
6285 ufoDefineConstant("(VOCOFS-VOCLINK)", UFW_VOCAB_OFS_VOCLINK
);
6286 ufoDefineConstant("(VOCOFS-PARENT)", UFW_VOCAB_OFS_PARENT
);
6287 ufoDefineConstant("(VOCOFS-HEADER)", UFW_VOCAB_OFS_HEADER
);
6288 ufoDefineConstant("(VOCOFS-HTABLE)", UFW_VOCAB_OFS_HTABLE
);
6289 ufoDefineConstant("(VOC-HTABLE-SIZE)", UFO_HASHTABLE_SIZE
);
6290 ufoDefineConstant("(VOC-HTABLE-NOFLAG)", UFO_NO_HTABLE_FLAG
);
6292 ufoDefineConstant("(REDEFINE-WARN-DON'T-CARE)", UFO_REDEF_WARN_DONT_CARE
);
6293 ufoDefineConstant("(REDEFINE-WARN-NONE)", UFO_REDEF_WARN_NONE
);
6294 ufoDefineConstant("(REDEFINE-WARN-NORMAL)", UFO_REDEF_WARN_NORMAL
);
6296 ufoDefineConstant("WORD-REDEFINE-WARN-MODE", ufoAddrRedefineWarning
);
6298 UFWORDX("(UNESCAPE)", PAR_UNESCAPE
);
6300 UFWORDX("?EXEC", QEXEC
);
6301 UFWORDX("?COMP", QCOMP
);
6305 UFWORDX("(INTERPRET-DUMB)", PAR_INTERPRET_DUMB); UFCALL(PAR_HIDDEN);
6306 const uint32_t idumbCFA = UFO_LFA_TO_CFA(ufoImgGetU32(ufoImgGetU32(ufoAddrCurrent)));
6307 ufo_assert(idumbCFA == UFO_PFA_TO_CFA(UFO_GET_DP()));
6310 UFWORDX("(CREATE-WORD-HEADER)", PAR_CREATE_WORD_HEADER
);
6311 UFWORDX("(CREATE-NAMELESS-WORD-HEADER)", PAR_CREATE_NAMELESS_WORD_HEADER
);
6315 ufoVocSetOnlyDefs(ufoForthVocId
);
6319 //==========================================================================
6323 //==========================================================================
6324 UFO_DISABLE_INLINE
void ufoInitMoreWords (void) {
6325 UFWORDX("COMPILE,", COMMA
); // just an alias, for clarity
6327 UFWORDX("CFA->PFA", CFA2PFA
);
6328 UFWORDX("PFA->CFA", PFA2CFA
);
6329 UFWORDX("CFA->NFA", CFA2NFA
);
6330 UFWORDX("NFA->CFA", NFA2CFA
);
6331 UFWORDX("CFA->LFA", CFA2LFA
);
6332 UFWORDX("LFA->CFA", LFA2CFA
);
6333 UFWORDX("LFA->PFA", LFA2PFA
);
6334 UFWORDX("LFA->BFA", LFA2BFA
);
6335 UFWORDX("LFA->XFA", LFA2XFA
);
6336 UFWORDX("LFA->YFA", LFA2YFA
);
6337 UFWORDX("LFA->NFA", LFA2NFA
);
6338 UFWORDX("NFA->LFA", NFA2LFA
);
6339 UFWORDX("CFA->WEND", CFA2WEND
);
6341 UFWORDX("ERROR", ERROR
);
6342 UFWORDX("?ERROR", QERROR
);
6344 UFWORDX("(BASED-NUMBER)", PAR_BASED_NUMBER
);
6345 UFWORDX("FIND-WORD", FIND_WORD
);
6346 UFWORDX("FIND-WORD-IN-VOC", FIND_WORD_IN_VOC
);
6347 UFWORDX("FIND-WORD-IN-VOC-AND-PARENTS", FIND_WORD_IN_VOC_AND_PARENTS
);
6349 UFWORDX_IMM("\"", QUOTE_IMM
);
6352 UFWORDX("EXECUTE-TAIL", EXECUTE_TAIL
);
6355 UFWORDX("?DUP", QDUP
);
6356 UFWORDX("2DUP", DDUP
);
6358 UFWORDX("2DROP", DDROP
);
6360 UFWORDX("2SWAP", DSWAP
);
6362 UFWORDX("2OVER", DOVER
);
6365 UFWORDX("PICK", PICK
);
6366 UFWORDX("ROLL", ROLL
);
6370 UFWORDX(">R", DTOR
);
6371 UFWORDX("R>", RTOD
);
6372 UFWORDX("R@", RPEEK
);
6373 UFWORDX("RPICK", RPICK
);
6374 UFWORDX("RROLL", RROLL
);
6375 UFWORDX("RSWAP", RSWAP
);
6376 UFWORDX("ROVER", ROVER
);
6377 UFWORDX("RROT", RROT
);
6378 UFWORDX("RNROT", RNROT
);
6380 UFWORDX("FLUSH-EMIT", FLUSH_EMIT
);
6389 UFWORDX("LASTCR?", LASTCRQ
);
6390 UFWORDX("LASTCR!", LASTCRSET
);
6394 UFWORDX("-", MINUS
);
6396 UFWORDX("U*", UMUL
);
6398 UFWORDX("U/", UDIV
);
6399 UFWORDX("MOD", MOD
);
6400 UFWORDX("UMOD", UMOD
);
6401 UFWORDX("/MOD", DIVMOD
);
6402 UFWORDX("U/MOD", UDIVMOD
);
6403 UFWORDX("*/", MULDIV
);
6404 UFWORDX("U*/", UMULDIV
);
6405 UFWORDX("*/MOD", MULDIVMOD
);
6406 UFWORDX("U*/MOD", UMULDIVMOD
);
6407 UFWORDX("M*", MMUL
);
6408 UFWORDX("UM*", UMMUL
);
6409 UFWORDX("M/MOD", MDIVMOD
);
6410 UFWORDX("UM/MOD", UMDIVMOD
);
6412 UFWORDX("2U*", ONESHL
);
6413 UFWORDX("2U/", ONESHR
);
6414 UFWORDX("4U*", TWOSHL
);
6415 UFWORDX("4U/", TWOSHR
);
6422 UFWORDX(">", GREAT
);
6423 UFWORDX("<=", LESSEQU
);
6424 UFWORDX(">=", GREATEQU
);
6425 UFWORDX("U<", ULESS
);
6426 UFWORDX("U>", UGREAT
);
6427 UFWORDX("U<=", ULESSEQU
);
6428 UFWORDX("U>=", UGREATEQU
);
6430 UFWORDX("<>", NOTEQU
);
6437 UFWORDX("LOGAND", LOGAND
);
6438 UFWORDX("LOGOR", LOGOR
);
6441 UFWORDX("(TIB-IN)", TIB_IN
);
6442 UFWORDX("TIB-PEEKCH", TIB_PEEKCH
);
6443 UFWORDX("TIB-PEEKCH-OFS", TIB_PEEKCH_OFS
);
6444 UFWORDX("TIB-GETCH", TIB_GETCH
);
6445 UFWORDX("TIB-SKIPCH", TIB_SKIPCH
);
6447 UFWORDX("REFILL", REFILL
);
6448 UFWORDX("REFILL-NOCROSS", REFILL_NOCROSS
);
6451 UFWORDX("(PARSE)", PAR_PARSE
);
6452 UFWORDX("(PARSE-SKIP-COMMENTS)", PAR_PARSE_SKIP_COMMENTS
);
6454 UFWORDX("PARSE-SKIP-BLANKS", PARSE_SKIP_BLANKS
);
6455 UFWORDX("PARSE-NAME", PARSE_NAME
);
6456 UFWORDX("PARSE-SKIP-LINE", PARSE_SKIP_LINE
);
6457 UFWORDX("PARSE", PARSE
);
6459 UFWORDX_IMM("[", LBRACKET_IMM
);
6460 UFWORDX("]", RBRACKET
);
6463 UFWORDX("(VSP@)", PAR_GET_VSP
);
6464 UFWORDX("(VSP!)", PAR_SET_VSP
);
6465 UFWORDX("(VSP-AT@)", PAR_VSP_LOAD
);
6466 UFWORDX("(VSP-AT!)", PAR_VSP_STORE
);
6467 ufoDefineConstant("(VSP-SIZE)", UFO_VOCSTACK_SIZE
);
6469 ufoDefineConstant("(SP-SIZE)", UFO_DSTACK_SIZE
);
6470 ufoDefineConstant("(RP-SIZE)", UFO_RSTACK_SIZE
);
6471 ufoDefineConstant("(LP-SIZE)", UFO_LSTACK_SIZE
);
6476 //==========================================================================
6478 // ufoInitHandleWords
6480 //==========================================================================
6481 UFO_DISABLE_INLINE
void ufoInitHandleWords (uint32_t handleVocId
) {
6482 ufoVocSetOnlyDefs(handleVocId
);
6483 UFWORDX("NEW", PAR_NEW_HANDLE
);
6484 UFWORDX("FREE", PAR_FREE_HANDLE
);
6485 UFWORDX("TYPEID@", PAR_HANDLE_GET_TYPEID
);
6486 UFWORDX("TYPEID!", PAR_HANDLE_SET_TYPEID
);
6487 UFWORDX("SIZE@", PAR_HANDLE_GET_SIZE
);
6488 UFWORDX("SIZE!", PAR_HANDLE_SET_SIZE
);
6489 UFWORDX("USED@", PAR_HANDLE_GET_USED
);
6490 UFWORDX("USED!", PAR_HANDLE_SET_USED
);
6491 UFWORDX("C@", PAR_HANDLE_LOAD_BYTE
);
6492 UFWORDX("W@", PAR_HANDLE_LOAD_WORD
);
6493 UFWORDX("@", PAR_HANDLE_LOAD_CELL
);
6494 UFWORDX("C!", PAR_HANDLE_STORE_BYTE
);
6495 UFWORDX("W!", PAR_HANDLE_STORE_WORD
);
6496 UFWORDX("!", PAR_HANDLE_STORE_CELL
);
6497 ufoVocSetOnlyDefs(ufoForthVocId
);
6501 //==========================================================================
6503 // ufoInitHigherWords
6505 //==========================================================================
6506 UFO_DISABLE_INLINE
void ufoInitHigherWords (void) {
6507 UFWORDX("(INCLUDE)", PAR_INCLUDE
);
6509 UFWORDX("(INCLUDE-DEPTH)", PAR_INCLUDE_DEPTH
);
6510 UFWORDX("(INCLUDE-FILE-ID)", PAR_INCLUDE_FILE_ID
);
6511 UFWORDX("(INCLUDE-FILE-LINE)", PAR_INCLUDE_FILE_LINE
);
6512 UFWORDX("(INCLUDE-FILE-NAME)", PAR_INCLUDE_FILE_NAME
);
6514 UFWORDX("($DEFINED?)", PAR_DLR_DEFINEDQ
);
6515 UFWORDX("($DEFINE)", PAR_DLR_DEFINE
);
6516 UFWORDX("($UNDEF)", PAR_DLR_UNDEF
);
6518 UFWORDX_IMM("$INCLUDE", DLR_INCLUDE_IMM
);
6519 UFWORDX_IMM("$INCLUDE-ONCE", DLR_INCLUDE_ONCE_IMM
);
6523 //==========================================================================
6525 // ufoInitStringWords
6527 //==========================================================================
6528 UFO_DISABLE_INLINE
void ufoInitStringWords (uint32_t stringVocId
) {
6529 ufoVocSetOnlyDefs(stringVocId
);
6530 UFWORDX("=", STREQU
);
6531 UFWORDX("=CI", STREQUCI
);
6532 UFWORDX("HASH", STRHASH
);
6533 UFWORDX("HASH-CI", STRHASHCI
);
6534 ufoVocSetOnlyDefs(ufoForthVocId
);
6538 //==========================================================================
6540 // ufoInitDebugWords
6542 //==========================================================================
6543 UFO_DISABLE_INLINE
void ufoInitDebugWords (uint32_t debugVocId
) {
6544 ufoVocSetOnlyDefs(debugVocId
);
6545 UFWORDX("(DECOMPILE-CFA)", DEBUG_DECOMPILE_CFA
);
6546 UFWORDX("BACKTRACE", UFO_BACKTRACE
);
6547 UFWORDX("DUMP-STACK", DUMP_STACK
);
6548 UFWORDX("(BP)", MT_DEBUGGER_BP
);
6549 UFWORDX("IP->NFA", IP2NFA
);
6550 ufoVocSetOnlyDefs(ufoForthVocId
);
6554 //==========================================================================
6558 //==========================================================================
6559 UFO_DISABLE_INLINE
void ufoInitMTWords (uint32_t mtVocId
) {
6560 ufoVocSetOnlyDefs(mtVocId
);
6561 UFWORDX("NEW-STATE", MT_NEW_STATE
);
6562 UFWORDX("FREE-STATE", MT_FREE_STATE
);
6563 UFWORDX("STATE-NAME@", MT_GET_STATE_NAME
);
6564 UFWORDX("STATE-NAME!", MT_SET_STATE_NAME
);
6565 UFWORDX("STATE-FIRST", MT_STATE_FIRST
);
6566 UFWORDX("STATE-NEXT", MT_STATE_NEXT
);
6567 UFWORDX("YIELD-TO", MT_YIELD_TO
);
6568 UFWORDX("SET-SELF-AS-DEBUGGER", MT_SET_SELF_AS_DEBUGGER
);
6569 UFWORDX("DEBUGGER-RESUME", MT_RESUME_DEBUGEE
);
6570 UFWORDX("DEBUGGER-SINGLE-STEP", MT_SINGLE_STEP_DEBUGEE
);
6571 UFWORDX("ACTIVE-STATE", MT_ACTIVE_STATE
);
6572 UFWORDX("STATE-IP@", MT_STATE_IP_GET
);
6573 UFWORDX("STATE-IP!", MT_STATE_IP_SET
);
6574 UFWORDX("STATE-A@", MT_STATE_REGA_GET
);
6575 UFWORDX("STATE-A!", MT_STATE_REGA_SET
);
6576 UFWORDX("STATE-BASE@", MT_STATE_BASE_GET
);
6577 UFWORDX("STATE-BASE!", MT_STATE_BASE_SET
);
6578 UFWORDX("STATE-RPOPCFA@", MT_STATE_RPOPCFA_GET
);
6579 UFWORDX("STATE-RPOPCFA!", MT_STATE_RPOPCFA_SET
);
6580 UFWORDX("YIELDED-FROM", MT_YIELDED_FROM
);
6581 UFWORDX("STATE-SP@", MT_DSTACK_DEPTH_GET
);
6582 UFWORDX("STATE-RP@", MT_RSTACK_DEPTH_GET
);
6583 UFWORDX("STATE-LP@", MT_LP_GET
);
6584 UFWORDX("STATE-LBP@", MT_LBP_GET
);
6585 UFWORDX("STATE-SP!", MT_DSTACK_DEPTH_SET
);
6586 UFWORDX("STATE-RP!", MT_RSTACK_DEPTH_SET
);
6587 UFWORDX("STATE-LP!", MT_LP_SET
);
6588 UFWORDX("STATE-LBP!", MT_LBP_SET
);
6589 UFWORDX("STATE-DS@", MT_DSTACK_LOAD
);
6590 UFWORDX("STATE-RS@", MT_RSTACK_LOAD
);
6591 UFWORDX("STATE-LS@", MT_LSTACK_LOAD
);
6592 UFWORDX("STATE-DS!", MT_DSTACK_STORE
);
6593 UFWORDX("STATE-RS!", MT_RSTACK_STORE
);
6594 UFWORDX("STATE-LS!", MT_LSTACK_STORE
);
6595 ufoVocSetOnlyDefs(ufoForthVocId
);
6599 //==========================================================================
6601 // ufoInitVeryVeryHighWords
6603 //==========================================================================
6604 UFO_DISABLE_INLINE
void ufoInitVeryVeryHighWords (void) {
6606 //ufoDefineDefer("INTERPRET", idumbCFA);
6608 // ( addr count FALSE -- addr count FALSE / TRUE )
6609 ufoDefineSColonForth("(INTERPRET-CHECK-WORD)");
6610 UFC("FORTH:(EXIT)");
6612 // ( addr count FALSE -- addr count FALSE / TRUE )
6613 ufoDefineSColonForth("(INTERPRET-WORD-NOT-FOUND)");
6614 UFC("FORTH:(EXIT)");
6616 // ( FALSE -- FALSE / TRUE ) -- called in "EXIT", before compiling "FORTH:(EXIT)"
6617 // return TRUE to stop calling other chained words, and omit default exit
6618 ufoDefineSColonForth("(EXIT-EXTENDER)");
6619 UFC("FORTH:(EXIT)");
6622 // create "FORTH:EXIT"
6623 // : EXIT ?COMP COMPILE FORTH:(EXIT) ;
6624 ufoDefineForthImm("EXIT");
6625 UFC("COMPILER:?COMP");
6626 UFC("FALSE"); UFC("(EXIT-EXTENDER)");
6627 UFC("FORTH:(TBRANCH)"); const uint32_t exit_branch_end
= ufoMarkFwd();
6628 UFC("FORTH:(LITCFA)"); UFC("FORTH:(EXIT)");
6629 UFC("FORTH:COMPILE,");
6630 ufoResolveFwd(exit_branch_end
);
6631 UFC("FORTH:(EXIT)");
6634 ufoDefineInterpret();
6636 //ufoDumpVocab(ufoCompilerVocId);
6638 ufoDefineForth("RUN-INTERPRET-LOOP");
6639 const uint32_t addrAgain
= UFO_GET_DP();
6642 UFC("FORTH:(BRANCH)");
6643 ufoImgEmitU32(addrAgain
);
6647 #define UFO_ADD_DO_CFA(cfx_) do { \
6648 ufoDo##cfx_##CFA = ufoCFAsUsed | UFO_ADDR_CFA_BIT; \
6649 ufoForthCFAs[ufoCFAsUsed] = &ufoDo##cfx_; \
6654 //==========================================================================
6658 //==========================================================================
6659 UFO_DISABLE_INLINE
void ufoInitCommon (void) {
6661 ufoForthVocId
= 0; ufoCompilerVocId
= 0;
6663 ufoForthCFAs
= calloc(UFO_MAX_NATIVE_CFAS
, sizeof(ufoForthCFAs
[0]));
6665 // allocate default TIB handle
6666 UHandleInfo
*tibh
= ufoAllocHandle(0x69a029a6); // arbitrary number
6667 ufoDefTIB
= tibh
->ufoHandle
;
6669 ufoForthCFAs
[0] = NULL
; ufoCFAsUsed
= 1u;
6670 UFO_ADD_DO_CFA(Forth
);
6671 UFO_ADD_DO_CFA(Variable
);
6672 UFO_ADD_DO_CFA(Value
);
6673 UFO_ADD_DO_CFA(Const
);
6674 UFO_ADD_DO_CFA(Defer
);
6675 UFO_ADD_DO_CFA(Voc
);
6676 UFO_ADD_DO_CFA(Create
);
6678 //fprintf(stderr, "DO-FORTH-CFA: 0x%08x\n", ufoDoForthCFA);
6682 // create "FORTH" vocabulary
6683 ufoForthVocId
= ufoCreateVoc("FORTH", 0, UFW_FLAG_PROTECTED
);
6684 ufoVocSetOnlyDefs(ufoForthVocId
);
6686 // create "COMPILER" vocabulary
6687 ufoCompilerVocId
= ufoCreateVoc("COMPILER", 0, UFW_FLAG_PROTECTED
);
6689 // create "STRING" vocabulary
6690 uint32_t stringVocId
= ufoCreateVoc("STRING", 0, UFW_FLAG_PROTECTED
);
6692 // create "HANDLE" vocabulary
6693 uint32_t handleVocId
= ufoCreateVoc("HANDLE", 0, UFW_FLAG_PROTECTED
);
6695 // create "DEBUG" vocabulary
6696 uint32_t debugVocId
= ufoCreateVoc("DEBUG", 0, UFW_FLAG_PROTECTED
);
6698 // create "MTASK" vocabulary
6699 uint32_t mtVocId
= ufoCreateVoc("MTASK", 0, UFW_FLAG_PROTECTED
);
6701 // base low-level interpreter words
6702 ufoInitBasicWords();
6704 // some COMPILER words
6705 ufoInitBasicCompilerWords();
6710 // HANDLE vocabulary
6711 ufoInitHandleWords(handleVocId
);
6713 // some higher-level FORTH words (includes, etc.)
6714 ufoInitHigherWords();
6716 // STRING vocabulary
6717 ufoInitStringWords(stringVocId
);
6720 ufoInitDebugWords(debugVocId
);
6723 ufoInitMTWords(mtVocId
);
6725 // very-very high-level FORTH words
6726 ufoInitVeryVeryHighWords();
6729 ufoDecompileWord(ufoFindWordChecked("RUN-INTERPRET-LOOP"));
6738 // ////////////////////////////////////////////////////////////////////////// //
6739 // virtual machine executor
6743 //==========================================================================
6747 // address interpreter
6749 //==========================================================================
6750 static void ufoRunVMCFA (uint32_t cfa
) {
6751 const uint32_t oldRPTop
= ufoRPTop
;
6753 #ifdef UFO_TRACE_VM_RUN
6754 fprintf(stderr
, "**VM-INITIAL**: cfa=%u\n", cfa
);
6760 // VM execution loop
6762 if (ufoVMAbort
) ufoFatal("user abort");
6763 if (ufoVMStop
) { ufoRP
= oldRPTop
; break; }
6764 if (ufoCurrState
== NULL
) ufoFatal("execution state is lost");
6765 if (ufoVMRPopCFA
== 0) {
6767 if (ufoIP
== 0) ufoFatal("IP is NULL");
6768 if (ufoIP
& UFO_ADDR_HANDLE_BIT
) ufoFatal("IP is a handle");
6769 cfa
= ufoImgGetU32(ufoIP
); ufoIP
+= 4u;
6771 cfa
= ufoRPop(); ufoVMRPopCFA
= 0;
6774 if (cfa
== 0) ufoFatal("EXECUTE: NULL CFA");
6775 if (cfa
& UFO_ADDR_HANDLE_BIT
) ufoFatal("cannot execute handle");
6776 // get next word CFAIDX, and check it
6777 uint32_t cfaidx
= ufoImgGetU32(cfa
);
6778 if (cfaidx
& UFO_ADDR_HANDLE_BIT
) ufoFatal("cannot execute CFAIDX-handle");
6779 #ifdef UFO_TRACE_VM_RUN
6780 fprintf(stderr
, "**VM**: IP=%u; cfa=%u; cfaidx=0x%08x\n", ufoIP
- 4u, cfa
, cfaidx
);
6782 ufoDumpWordHeader(UFO_CFA_TO_LFA(cfa
));
6783 fprintf(stderr
, "######################################\n");
6785 if (cfaidx
& UFO_ADDR_CFA_BIT
) {
6786 cfaidx
&= UFO_ADDR_CFA_MASK
;
6787 if (cfaidx
>= ufoCFAsUsed
|| ufoForthCFAs
[cfaidx
] == NULL
) {
6788 ufoFatal("tried to execute an unknown word: %u (max is %u); IP=%u",
6789 cfaidx
, ufoCFAsUsed
, ufoIP
- 4u);
6791 #ifdef UFO_TRACE_VM_RUN
6792 fprintf(stderr
, "**VM-NATIVE**: cfaidx=%u (doForth=%u)\n", cfaidx
,
6793 (ufoDoForthCFA
& UFO_ADDR_CFA_MASK
));
6795 ufoForthCFAs
[cfaidx
](UFO_CFA_TO_PFA(cfa
));
6797 // if CFA points somewhere inside a dict, this is "DOES>" word
6798 // IP points to PFA we need to push
6799 // CFA points to Forth word we need to jump to
6800 #ifdef UFO_TRACE_VM_DOER
6801 fprintf(stderr
, "*** DOER! IP=%u; cfa=%u; cfaidx=%u ***\n", ufoIP
, cfa
, cfaidx
);
6802 UFCALL(UFO_BACKTRACE
);
6804 ufoPush(UFO_CFA_TO_PFA(cfa
)); // push PFA
6805 ufoRPush(ufoIP
); // push IP
6806 ufoIP
= cfaidx
; // fix IP
6808 // that's all we need to activate the debugger
6809 if (ufoSingleStep
) {
6811 if (ufoSingleStep
== 0 && ufoDebuggerState
!= NULL
) {
6812 if (ufoCurrState
== ufoDebuggerState
) ufoFatal("debugger cannot debug itself");
6813 UfoState
*ost
= ufoCurrState
;
6814 ufoSwitchToState(ufoDebuggerState
); // always use API call for this!
6819 } while (ufoRP
!= oldRPTop
);
6824 // ////////////////////////////////////////////////////////////////////////// //
6828 //==========================================================================
6832 // register new word
6834 //==========================================================================
6835 uint32_t ufoRegisterWord (const char *wname
, ufoNativeCFA cfa
, uint32_t flags
) {
6836 ufo_assert(cfa
!= NULL
);
6837 ufo_assert(wname
!= NULL
&& wname
[0] != 0);
6838 uint32_t cfaidx
= ufoCFAsUsed
;
6839 if (cfaidx
>= UFO_MAX_NATIVE_CFAS
) ufoFatal("too many native words");
6840 ufoForthCFAs
[cfaidx
] = cfa
;
6842 //ufoDefineNative(wname, xcfa, 0);
6843 cfaidx
|= UFO_ADDR_CFA_BIT
;
6844 flags
&= 0xffffff00u
;
6845 ufoCreateWordHeader(wname
, flags
);
6846 const uint32_t res
= UFO_GET_DP();
6847 ufoImgEmitU32(cfaidx
);
6852 //==========================================================================
6854 // ufoRegisterDataWord
6856 //==========================================================================
6857 static uint32_t ufoRegisterDataWord (const char *wname
, uint32_t cfaidx
, uint32_t value
,
6860 ufo_assert(wname
!= NULL
&& wname
[0] != 0);
6861 flags
&= 0xffffff00u
;
6862 ufoCreateWordHeader(wname
, flags
);
6863 ufoImgEmitU32(cfaidx
);
6864 const uint32_t res
= UFO_GET_DP();
6865 ufoImgEmitU32(value
);
6870 //==========================================================================
6872 // ufoRegisterConstant
6874 //==========================================================================
6875 void ufoRegisterConstant (const char *wname
, uint32_t value
, uint32_t flags
) {
6876 (void)ufoRegisterDataWord(wname
, ufoDoConstCFA
, value
, flags
);
6880 //==========================================================================
6882 // ufoRegisterVariable
6884 //==========================================================================
6885 uint32_t ufoRegisterVariable (const char *wname
, uint32_t value
, uint32_t flags
) {
6886 return ufoRegisterDataWord(wname
, ufoDoVariableCFA
, value
, flags
);
6890 //==========================================================================
6894 //==========================================================================
6895 uint32_t ufoRegisterValue (const char *wname
, uint32_t value
, uint32_t flags
) {
6896 return ufoRegisterDataWord(wname
, ufoDoValueCFA
, value
, flags
);
6900 //==========================================================================
6904 //==========================================================================
6905 uint32_t ufoRegisterDefer (const char *wname
, uint32_t value
, uint32_t flags
) {
6906 return ufoRegisterDataWord(wname
, ufoDoDeferCFA
, value
, flags
);
6910 //==========================================================================
6912 // ufoFindWordInVocabulary
6914 // check if we have the corresponding word.
6915 // return CFA suitable for executing, or 0.
6917 //==========================================================================
6918 uint32_t ufoFindWordInVocabulary (const char *wname
, uint32_t vocid
) {
6919 if (wname
== NULL
|| wname
[0] == 0) return 0;
6920 size_t wlen
= strlen(wname
);
6921 if (wlen
>= UFO_MAX_WORD_LENGTH
) return 0;
6922 return ufoFindWordInVocAndParents(wname
, (uint32_t)wlen
, 0, vocid
, 0);
6926 //==========================================================================
6930 //==========================================================================
6931 uint32_t ufoGetIP (void) {
6936 //==========================================================================
6940 //==========================================================================
6941 void ufoSetIP (uint32_t newip
) {
6946 //==========================================================================
6950 //==========================================================================
6951 int ufoIsExecuting (void) {
6952 return (ufoImgGetU32(ufoAddrSTATE
) == 0);
6956 //==========================================================================
6960 //==========================================================================
6961 int ufoIsCompiling (void) {
6962 return (ufoImgGetU32(ufoAddrSTATE
) != 0);
6966 //==========================================================================
6970 //==========================================================================
6971 void ufoSetExecuting (void) {
6972 ufoImgPutU32(ufoAddrSTATE
, 0);
6976 //==========================================================================
6980 //==========================================================================
6981 void ufoSetCompiling (void) {
6982 ufoImgPutU32(ufoAddrSTATE
, 1);
6986 //==========================================================================
6990 //==========================================================================
6991 uint32_t ufoGetHere () {
6992 return UFO_GET_DP();
6996 //==========================================================================
7000 //==========================================================================
7001 uint32_t ufoGetPad () {
7007 //==========================================================================
7011 //==========================================================================
7012 uint8_t ufoTIBPeekCh (uint32_t ofs
) {
7013 return ufoTibPeekChOfs(ofs
);
7017 //==========================================================================
7021 //==========================================================================
7022 uint8_t ufoTIBGetCh (void) {
7023 return ufoTibGetCh();
7027 //==========================================================================
7031 //==========================================================================
7032 void ufoTIBSkipCh (void) {
7037 //==========================================================================
7043 //==========================================================================
7044 int ufoTIBSRefill (int allowCrossIncludes
) {
7045 return ufoLoadNextLine(allowCrossIncludes
);
7049 //==========================================================================
7053 //==========================================================================
7054 uint32_t ufoPeekData (void) {
7059 //==========================================================================
7063 //==========================================================================
7064 uint32_t ufoPopData (void) {
7069 //==========================================================================
7073 //==========================================================================
7074 void ufoPushData (uint32_t value
) {
7075 return ufoPush(value
);
7079 //==========================================================================
7083 //==========================================================================
7084 void ufoPushBoolData (int val
) {
7089 //==========================================================================
7093 //==========================================================================
7094 uint32_t ufoPeekRet (void) {
7099 //==========================================================================
7103 //==========================================================================
7104 uint32_t ufoPopRet (void) {
7109 //==========================================================================
7113 //==========================================================================
7114 void ufoPushRet (uint32_t value
) {
7115 return ufoRPush(value
);
7119 //==========================================================================
7123 //==========================================================================
7124 void ufoPushBoolRet (int val
) {
7125 ufoRPush(val
? ufoTrueValue
: 0);
7129 //==========================================================================
7133 //==========================================================================
7134 uint8_t ufoPeekByte (uint32_t addr
) {
7135 return ufoImgGetU8Ext(addr
);
7139 //==========================================================================
7143 //==========================================================================
7144 uint16_t ufoPeekWord (uint32_t addr
) {
7151 //==========================================================================
7155 //==========================================================================
7156 uint32_t ufoPeekCell (uint32_t addr
) {
7163 //==========================================================================
7167 //==========================================================================
7168 void ufoPokeByte (uint32_t addr
, uint32_t value
) {
7169 ufoImgPutU8(addr
, value
);
7173 //==========================================================================
7177 //==========================================================================
7178 void ufoPokeWord (uint32_t addr
, uint32_t value
) {
7185 //==========================================================================
7189 //==========================================================================
7190 void ufoPokeCell (uint32_t addr
, uint32_t value
) {
7197 //==========================================================================
7201 //==========================================================================
7202 void ufoEmitByte (uint32_t value
) {
7203 ufoImgEmitU8(value
);
7207 //==========================================================================
7211 //==========================================================================
7212 void ufoEmitWord (uint32_t value
) {
7213 ufoImgEmitU8(value
& 0xff);
7214 ufoImgEmitU8((value
>> 8) & 0xff);
7218 //==========================================================================
7222 //==========================================================================
7223 void ufoEmitCell (uint32_t value
) {
7224 ufoImgEmitU32(value
);
7228 //==========================================================================
7232 //==========================================================================
7233 int ufoIsInited (void) {
7234 return (ufoMode
!= UFO_MODE_NONE
);
7238 static void (*ufoUserPostInitCB
) (void);
7241 //==========================================================================
7243 // ufoSetUserPostInit
7245 // called after main initialisation
7247 //==========================================================================
7248 void ufoSetUserPostInit (void (*cb
) (void)) {
7249 ufoUserPostInitCB
= cb
;
7253 //==========================================================================
7257 //==========================================================================
7258 void ufoInit (void) {
7259 if (ufoMode
!= UFO_MODE_NONE
) return;
7260 ufoMode
= UFO_MODE_NATIVE
;
7263 ufoInFileName
= NULL
;
7265 ufoLastIncPath
= NULL
;
7267 for (uint32_t f
= 0; f
< UFO_MAX_STATES
; f
+= 1u) ufoStateMap
[f
] = NULL
;
7268 memset(ufoStateUsedBitmap
, 0, sizeof(ufoStateUsedBitmap
));
7270 ufoCurrState
= ufoNewState(0); // CFA doesn't matter here
7271 strcpy(ufoCurrState
->name
, "MAIN");
7272 ufoYieldedState
= NULL
;
7273 ufoDebuggerState
= NULL
;
7276 #ifdef UFO_DEBUG_STARTUP_TIMES
7277 uint32_t stt
= ufo_get_msecs();
7278 ufoCondDefine("UFO-DEBUG-STARTUP-TIMES");
7281 #ifdef UFO_DEBUG_STARTUP_TIMES
7282 uint32_t ett
= ufo_get_msecs();
7283 fprintf(stderr
, "UrForth init time: %u msecs\n", (unsigned)(ett
- stt
));
7288 if (ufoUserPostInitCB
) {
7289 ufoUserPostInitCB();
7294 char *ufmname
= ufoCreateIncludeName("init", 1, NULL
);
7296 FILE *ufl
= fopen(ufmname
, "rb");
7298 FILE *ufl
= fopen(ufmname
, "r");
7302 ufoInFileName
= ufmname
;
7304 ufoFileId
= ufoLastUsedFileId
;
7305 setLastIncPath(ufoInFileName
);
7308 ufoFatal("cannot load init code");
7311 if (ufoInFile
!= NULL
) {
7312 ufoRunInterpretLoop();
7317 //==========================================================================
7321 //==========================================================================
7322 void ufoFinishVM (void) {
7327 //==========================================================================
7331 // check if VM was exited due to `ufoFinishVM()`
7333 //==========================================================================
7334 int ufoWasVMFinished (void) {
7335 return (ufoVMStop
!= 0);
7339 //==========================================================================
7343 // ( -- addr count TRUE / FALSE )
7344 // does base TIB parsing; never copies anything.
7345 // as our reader is line-based, returns FALSE on EOL.
7346 // EOL is detected after skipping leading delimiters.
7347 // passing -1 as delimiter skips the whole line, and always returns FALSE.
7348 // trailing delimiter is always skipped.
7349 // result is on the data stack.
7351 //==========================================================================
7352 void ufoCallParseIntr (uint32_t delim
, int skipLeading
) {
7353 ufoPush(delim
); ufoPushBool(skipLeading
);
7357 //==========================================================================
7361 // ( -- addr count )
7362 // parse with leading blanks skipping. doesn't copy anything.
7363 // return empty string on EOL.
7365 //==========================================================================
7366 void ufoCallParseName (void) {
7371 //==========================================================================
7375 // ( -- addr count TRUE / FALSE )
7376 // parse without skipping delimiters; never copies anything.
7377 // as our reader is line-based, returns FALSE on EOL.
7378 // passing 0 as delimiter skips the whole line, and always returns FALSE.
7379 // trailing delimiter is always skipped.
7381 //==========================================================================
7382 void ufoCallParse (uint32_t delim
) {
7388 //==========================================================================
7390 // ufoCallParseSkipBlanks
7392 //==========================================================================
7393 void ufoCallParseSkipBlanks (void) {
7394 UFCALL(PARSE_SKIP_BLANKS
);
7398 //==========================================================================
7400 // ufoCallParseSkipComments
7402 //==========================================================================
7403 void ufoCallParseSkipComments (void) {
7404 ufoPushBool(1); UFCALL(PAR_PARSE_SKIP_COMMENTS
);
7408 //==========================================================================
7410 // ufoCallParseSkipLineComments
7412 //==========================================================================
7413 void ufoCallParseSkipLineComments (void) {
7414 ufoPushBool(0); UFCALL(PAR_PARSE_SKIP_COMMENTS
);
7418 //==========================================================================
7420 // ufoCallParseSkipLine
7422 // to the end of line; doesn't refill
7424 //==========================================================================
7425 void ufoCallParseSkipLine (void) {
7426 UFCALL(PARSE_SKIP_LINE
);
7430 //==========================================================================
7432 // ufoCallBasedNumber
7434 // convert number from addrl+1
7435 // returns address of the first inconvertible char
7436 // (BASED-NUMBER) ( addr count allowsign? base -- num TRUE / FALSE )
7438 //==========================================================================
7439 void ufoCallBasedNumber (uint32_t addr
, uint32_t count
, int allowSign
, int base
) {
7440 ufoPush(addr
); ufoPush(count
); ufoPushBool(allowSign
);
7441 if (base
< 0) ufoPush(0); else ufoPush((uint32_t)base
);
7442 UFCALL(PAR_BASED_NUMBER
);
7446 //==========================================================================
7450 //==========================================================================
7451 void ufoRunWord (uint32_t cfa
) {
7453 if (ufoMode
== UFO_MODE_NONE
) ufoFatal("UrForth is not properly inited");
7454 if (ufoInRunWord
) ufoFatal("`ufoRunWord` cannot be called recursively");
7455 ufoMode
= UFO_MODE_NATIVE
;
7463 //==========================================================================
7467 //==========================================================================
7468 void ufoRunMacroWord (uint32_t cfa
) {
7470 if (ufoMode
== UFO_MODE_NONE
) ufoFatal("UrForth is not properly inited");
7471 if (ufoInRunWord
) ufoFatal("`ufoRunWord` cannot be called recursively");
7472 ufoMode
= UFO_MODE_MACRO
;
7473 const uint32_t oisp
= ufoFileStackPos
;
7476 (void)ufoLoadNextUserLine();
7481 ufo_assert(ufoFileStackPos
== oisp
); // sanity check
7486 //==========================================================================
7490 // check if we are currently in "MACRO" mode.
7491 // should be called from registered words.
7493 //==========================================================================
7494 int ufoIsInMacroMode (void) {
7495 return (ufoMode
== UFO_MODE_MACRO
);
7499 //==========================================================================
7501 // ufoRunInterpretLoop
7503 // run default interpret loop.
7505 //==========================================================================
7506 void ufoRunInterpretLoop (void) {
7507 if (ufoMode
== UFO_MODE_NONE
) {
7510 const uint32_t cfa
= ufoFindWord("RUN-INTERPRET-LOOP");
7511 if (cfa
== 0) ufoFatal("'RUN-INTERPRET-LOOP' word not found");
7513 ufoMode
= UFO_MODE_NATIVE
;
7517 while (ufoFileStackPos
!= 0) ufoPopInFile();
7521 //==========================================================================
7525 //==========================================================================
7526 void ufoRunFile (const char *fname
) {
7527 if (ufoMode
== UFO_MODE_NONE
) {
7530 if (ufoInRunWord
) ufoFatal("`ufoRunFile` cannot be called recursively");
7531 ufoMode
= UFO_MODE_NATIVE
;
7534 char *ufmname
= ufoCreateIncludeName(fname
, 0, ".");
7536 FILE *ufl
= fopen(ufmname
, "rb");
7538 FILE *ufl
= fopen(ufmname
, "r");
7542 ufoInFileName
= ufmname
;
7544 ufoFileId
= ufoLastUsedFileId
;
7545 setLastIncPath(ufoInFileName
);
7548 ufoFatal("cannot load source file '%s'", fname
);
7550 ufoRunInterpretLoop();