1 // and now for something completely different...
2 // UrAsm built-in Forth Engine!
16 #include <sys/types.h>
21 # define realpath(shit,fuck) _fullpath(fuck, shit, 32768)
25 #define UFO_DEBUG_STARTUP_TIMES
26 //#define UFO_DEBUG_FATAL_ABORT
27 #define UFO_DEBUG_DEBUG /* ;-) */
28 //#define UFO_TRACE_VM_DOER
29 //#define UFO_TRACE_VM_RUN
30 //#define UFO_DEBUG_INCLUDE
31 //#define UFO_DEBUG_DUMP_NEW_HEADERS
32 //#define UFO_DEBUG_FIND_WORD
33 //#define UFO_DEBUG_FIND_WORD_IN_VOC
34 //#define UFO_DEBUG_FIND_WORD_COLON
36 // 2/8 msecs w/o inlining
37 // 1/5 msecs with inlining
39 # define UFO_FORCE_INLINE static inline __attribute__((always_inline))
41 # define UFO_FORCE_INLINE static __attribute__((noinline)) __attribute__((unused))
43 #define UFO_DISABLE_INLINE static __attribute__((noinline)) __attribute__((unused))
45 // detect arch, and use faster memory access code on x86
46 #if defined(__x86_64__) || defined(_M_X64) || \
47 defined(i386) || defined(__i386__) || defined(__i386) || defined(_M_IX86)
48 # define UFO_FAST_MEM_ACCESS
51 // should not be bigger than this!
52 #define UFO_MAX_WORD_LENGTH (250)
54 #define UFO_ALIGN4(v_) (((v_) + 3u) / 4u * 4u)
57 // ////////////////////////////////////////////////////////////////////////// //
58 static const char *ufo_assert_failure (const char *cond
, const char *fname
, int fline
, const char *func
) {
59 for (const char *t
= fname
; *t
; ++t
) {
61 if (*t
== '/' || *t
== '\\') fname
= t
+1;
63 if (*t
== '/') fname
= t
+1;
67 fprintf(stderr
, "\n%s:%d: Assertion in `%s` failed: %s\n", fname
, fline
, func
, cond
);
72 #define ufo_assert(cond_) do { if (__builtin_expect((!(cond_)), 0)) { ufo_assert_failure(#cond_, __FILE__, __LINE__, __PRETTY_FUNCTION__); } } while (0)
75 static char ufoRealPathBuf
[32769];
76 static char ufoRealPathHashBuf
[32769];
79 //==========================================================================
83 //==========================================================================
84 static char *ufoRealPath (const char *fname
) {
86 if (fname
!= NULL
&& fname
[0] != 0) {
87 res
= realpath(fname
, NULL
);
89 const size_t slen
= strlen(res
);
91 strcpy(ufoRealPathBuf
, res
);
107 static time_t secstart
= 0;
112 //==========================================================================
116 //==========================================================================
117 static uint64_t ufo_get_msecs (void) {
119 return GetTickCount();
122 #ifdef CLOCK_MONOTONIC
123 ufo_assert(clock_gettime(CLOCK_MONOTONIC
, &ts
) == 0);
125 // this should be available everywhere
126 ufo_assert(clock_gettime(CLOCK_REALTIME
, &ts
) == 0);
130 secstart
= ts
.tv_sec
+1;
131 ufo_assert(secstart
); // it should not be zero
133 return (uint64_t)(ts
.tv_sec
-secstart
+2)*1000U+(uint32_t)ts
.tv_nsec
/1000000U;
135 //return (uint64_t)(ts.tv_sec-secstart+2)*1000000000U+(uint32_t)ts.tv_nsec;
140 //==========================================================================
144 //==========================================================================
145 UFO_FORCE_INLINE
uint32_t joaatHashBuf (const void *buf
, size_t len
, uint8_t orbyte
) {
146 uint32_t hash
= 0x29a;
147 const uint8_t *s
= (const uint8_t *)buf
;
149 hash
+= (*s
++)|orbyte
;
161 // this converts ASCII capitals to locase (and destroys other, but who cares)
162 #define joaatHashBufCI(buf_,len_) joaatHashBuf((buf_), (len_), 0x20)
165 //==========================================================================
169 //==========================================================================
170 UFO_FORCE_INLINE
char toUpper (char ch
) {
171 return (ch
>= 'a' && ch
<= 'z' ? ch
-'a'+'A' : ch
);
175 //==========================================================================
179 //==========================================================================
180 UFO_FORCE_INLINE
uint8_t toUpperU8 (uint8_t ch
) {
181 return (ch
>= 'a' && ch
<= 'z' ? ch
-'a'+'A' : ch
);
185 //==========================================================================
189 //==========================================================================
190 UFO_FORCE_INLINE
int digitInBase (char ch
, int base
) {
192 case '0' ... '9': ch
= ch
- '0'; break;
193 case 'A' ... 'Z': ch
= ch
- 'A' + 10; break;
194 case 'a' ... 'z': ch
= ch
- 'a' + 10; break;
195 default: base
= -1; break;
197 return (ch
>= 0 && ch
< base
? ch
: -1);
202 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
203 ;; word header format:
204 ;; note than name hash is ALWAYS calculated with ASCII-uppercased name
205 ;; (actually, bit 5 is always reset for all bytes, because we don't need the
206 ;; exact uppercase, only something that resembles it)
207 ;; bfa points to next bfa or to 0 (this is "hash bucket pointer")
208 ;; before nfa, we have such "hidden" fields:
209 ;; dd dfa ; pointer to the debug data; can be 0 if debug info is missing
210 ;; dd xfa ; points to the previous word header SFA, regardless of vocabularies (or 0)
211 ;; dd yfa ; points to the previous word header SFA, regardless of vocabularies (or 0)
212 ;; dd bfa ; next word in hashtable bucket; it is always here, even if hashtable is turned off
213 ;; ; if there is no hashtable, this field is not used
215 ;; dd lfa ; previous vocabulary word LFA or 0 (lfa links points here)
216 ;; dd namehash ; it is always here, and always calculated, even if hashtable is turned off
218 ;; dd flags-and-name-len ; see below
219 ;; db name ; no terminating zero or other "termination flag" here
220 ;; here could be some 0 bytes to align everything to 4 bytes
221 ;; db namelen ; yes, name length again, so CFA->NFA can avoid guessing
222 ;; ; full length, including padding, but not including this byte
224 ;; dd cfaidx ; our internal CFA index, or image address for DOES>
228 ;; first word cell contains combined name length (low byte), argtype and flags (other bytes)
233 ;; i.e. we have 16 bits for flags, and 256 possible argument types. why not.
242 ;; bit 6: *UNUSED* main scattered colon word (with "...")
245 ;; argtype is the type of the argument that this word reads from the threaded code.
246 ;; possible argument types:
249 ;; 2: cell-size numeric literal
250 ;; 3: cell-counted string with terminating zero (not counted)
251 ;; 4: cfa of another word
254 ;; 7: byte-counted string with terminating zero (not counted)
255 ;; 8: *UNUSED* unsigned byte
256 ;; 9: *UNUSED* signed byte
257 ;; 10: *UNUSED* unsigned word
258 ;; 11: *UNUSED* signed word
261 ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
262 ;; wordlist structure (at PFA)
263 ;; -4: wordlist type id (used by structs, for example)
265 ;; dd voclink (voclink always points here)
266 ;; dd parent (if not zero, all parent words are visible)
267 ;; dd header-nfa (can be 0 for anonymous wordlists)
268 ;; hashtable (if enabled), or ~0U if no hash table
272 // ////////////////////////////////////////////////////////////////////////// //
273 #define UFO_BFA_TO_LFA(bfa_) ((bfa_) + 1u * 4u)
274 #define UFO_LFA_TO_DFA(lfa_) ((lfa_) - 4u * 4u)
275 #define UFO_LFA_TO_XFA(lfa_) ((lfa_) - 3u * 4u)
276 #define UFO_LFA_TO_YFA(lfa_) ((lfa_) - 2u * 4u)
277 #define UFO_LFA_TO_BFA(lfa_) ((lfa_) - 1u * 4u)
278 #define UFO_LFA_TO_NFA(lfa_) ((lfa_) + 2u * 4u)
279 #define UFO_LFA_TO_CFA(lfa_) UFO_ALIGN4((lfa_) + 3u * 4u + 1u + ufoImgGetU8((lfa_) + 2u * 4u))
280 #define UFO_LFA_TO_NHASH(lfa_) ((lfa_) + 1u * 4u)
281 #define UFO_CFA_TO_NFA(cfa_) ((cfa_) - 1u - 4u - ufoImgGetU8((cfa_) - 1u))
282 #define UFO_CFA_TO_LFA(cfa_) ((cfa_) - 1u - 4u * 3u - ufoImgGetU8((cfa_) - 1u))
283 #define UFO_CFA_TO_PFA(cfa_) ((cfa_) + 1u * 4u)
284 #define UFO_PFA_TO_CFA(pfa_) ((pfa_) - 1u * 4u)
285 #define UFO_NFA_TO_CFA(nfa_) UFO_ALIGN4((nfa_) + 4u + 1u + ufoImgGetU8((nfa_)))
286 #define UFO_NFA_TO_LFA(nfa_) ((nfa_) - 2u * 4u)
287 #define UFO_XFA_TO_YFA(xfa_) ((xfa_) + 4u)
288 #define UFO_YFA_TO_XFA(yfa_) ((xfa_) - 4u)
289 #define UFO_XFA_TO_WST(xfa_) ((xfa_) - 4u)
290 #define UFO_YFA_TO_WST(yfa_) ((yfa_) - 2u * 4u)
291 #define UFO_YFA_TO_NFA(yfa_) ((yfa_) + 4u * 4u)
294 // ////////////////////////////////////////////////////////////////////////// //
295 //#define UFW_WARG_U8 (8u<<8)
296 //#define UFW_WARG_S8 (9u<<8)
297 //#define UFW_WARG_U16 (10u<<8)
298 //#define UFW_WARG_S16 (11u<<8)
300 #define UFW_VOCAB_OFS_LATEST (0u * 4u)
301 #define UFW_VOCAB_OFS_VOCLINK (1u * 4u)
302 #define UFW_VOCAB_OFS_PARENT (2u * 4u)
303 #define UFW_VOCAB_OFS_HEADER (3u * 4u)
304 #define UFW_VOCAB_OFS_HTABLE (4u * 4u)
306 #define UFO_HASHTABLE_SIZE (256)
308 #define UFO_NO_HTABLE_FLAG (~(uint32_t)0)
310 #define UFO_MAX_NATIVE_CFAS (1024u)
311 static ufoNativeCFA
*ufoForthCFAs
= NULL
;
312 static uint32_t ufoCFAsUsed
= 0;
314 static uint32_t ufoDoForthCFA
;
315 static uint32_t ufoDoVariableCFA
;
316 static uint32_t ufoDoValueCFA
;
317 static uint32_t ufoDoConstCFA
;
318 static uint32_t ufoDoDeferCFA
;
319 static uint32_t ufoDoVocCFA
;
320 static uint32_t ufoDoCreateCFA
;
321 static uint32_t ufoDoUserVariableCFA
;
323 static uint32_t ufoStrLit8CFA
;
325 // special address types:
326 #define UFO_ADDR_CFA_BIT ((uint32_t)1<<31)
327 #define UFO_ADDR_CFA_MASK (UFO_ADDR_CFA_BIT-1u)
329 // handles are somewhat special: first 12 bits can be used as offset for "@", and are ignored
330 #define UFO_ADDR_HANDLE_BIT ((uint32_t)1<<30)
331 #define UFO_ADDR_HANDLE_MASK ((UFO_ADDR_HANDLE_BIT-1u)&~((uint32_t)0xfff))
332 #define UFO_ADDR_HANDLE_SHIFT (12)
333 #define UFO_ADDR_HANDLE_OFS_MASK ((uint32_t)((1 << UFO_ADDR_HANDLE_SHIFT) - 1))
335 // temporary area is 1MB buffer out of the main image
336 #define UFO_ADDR_TEMP_BIT ((uint32_t)1<<29)
337 #define UFO_ADDR_TEMP_MASK (UFO_ADDR_TEMP_BIT-1u)
339 #define UFO_ADDR_SPECIAL_BITS_MASK (UFO_ADDR_CFA_BIT|UFO_ADDR_HANDLE_BIT|UFO_ADDR_TEMP_BIT)
342 debug image stores mapping from dictionary addresses to source files and lines.
343 it is used for backtraces and debuggers, so it doesn't need to be optimised for
344 speed; therefore i choose to optimise it for size.
346 debug map format is this:
349 align, so next data starts at 4-byte boundary
350 dxl line ; 0: no more lines
352 ...next filename record
354 "dv" is variable-length number. each byte uses bit 7 as "continuation" bit.
356 "dx?" is delta-coded number.
357 "dxi" is global, starts with 0, and incrementing.
358 "dxl" resets to 0 on each new file.
359 delta format is the same as "dv".
362 static uint32_t *ufoImage
= NULL
;
363 static uint32_t ufoImageSize
= 0;
365 static uint8_t *ufoDebugImage
= NULL
;
366 static uint32_t ufoDebugImageUsed
= 0;
367 static uint32_t ufoDebugImageSize
= 0;
368 static uint32_t ufoDebugFileId
= 0;
369 static uint32_t ufoDebugLastFRecAddr
= 0;
370 static uint32_t ufoDebugCurrDP
= 0;
372 static uint32_t ufoInRunWord
= 0;
374 static volatile int ufoVMAbort
= 0;
375 static volatile int ufoVMStop
= 0;
377 #define ufoTrueValue (~(uint32_t)0)
381 UFO_MODE_NATIVE
= 0, // executing forth code
382 UFO_MODE_MACRO
= 1, // executing forth asm macro
384 static uint32_t ufoMode
= UFO_MODE_NONE
;
386 #define UFO_DSTACK_SIZE (8192)
387 #define UFO_RSTACK_SIZE (4096)
388 #define UFO_LSTACK_SIZE (4096)
389 #define UFO_MAX_TASK_NAME (127)
391 // to support multitasking (required for the debugger),
392 // our virtual machine state is encapsulated in a struct.
393 typedef struct UfoState_t
{
395 uint32_t dStack
[UFO_DSTACK_SIZE
];
396 uint32_t rStack
[UFO_RSTACK_SIZE
];
397 uint32_t lStack
[UFO_LSTACK_SIZE
];
398 uint32_t IP
; // in image
399 uint32_t SP
; // points AFTER the last value pushed
400 uint32_t RP
; // points AFTER the last value pushed
401 uint32_t RPTop
; // stop when RP is this
410 uint32_t imageTempSize
;
411 // linked list of all allocated states (tasks)
412 char name
[UFO_MAX_TASK_NAME
+ 1];
416 #define UFO_MAX_STATES (8192)
418 // this is indexed by id
419 static UfoState
*ufoStateMap
[UFO_MAX_STATES
] = {NULL
};
420 static uint32_t ufoStateUsedBitmap
[UFO_MAX_STATES
/32] = {0};
422 // currently active execution state
423 static UfoState
*ufoCurrState
= NULL
;
424 // state we're yielded from
425 static UfoState
*ufoYieldedState
= NULL
;
426 // if debug state is not NULL, VM will switch to it
427 // after executing one instruction from the current state.
428 // it will store current state in `ufoDebugeeState`.
429 static UfoState
*ufoDebuggerState
= NULL
;
430 static uint32_t ufoSingleStep
= 0;
432 #define ufoDStack (ufoCurrState->dStack)
433 #define ufoRStack (ufoCurrState->rStack)
434 #define ufoLStack (ufoCurrState->lStack)
435 #define ufoIP (ufoCurrState->IP)
436 #define ufoSP (ufoCurrState->SP)
437 #define ufoRP (ufoCurrState->RP)
438 #define ufoRPTop (ufoCurrState->RPTop)
439 #define ufoLP (ufoCurrState->LP)
440 #define ufoLBP (ufoCurrState->LBP)
441 #define ufoRegA (ufoCurrState->regA)
442 #define ufoImageTemp (ufoCurrState->imageTemp)
443 #define ufoImageTempSize (ufoCurrState->imageTempSize)
444 #define ufoVMRPopCFA (ufoCurrState->vmRPopCFA)
446 // 256 bytes for user variables
447 #define UFO_USER_AREA_ADDR UFO_ADDR_TEMP_BIT
448 #define UFO_USER_AREA_SIZE (256u)
449 #define UFO_NBUF_ADDR UFO_USER_AREA_ADDR + UFO_USER_AREA_SIZE
450 #define UFO_NBUF_SIZE (256u)
451 #define UFO_PAD_ADDR (UFO_NBUF_ADDR + UFO_NBUF_SIZE)
452 #define UFO_DEF_TIB_ADDR (UFO_PAD_ADDR + 2048u)
454 // dynamically allocated text input buffer
455 // always ends with zero (this is word name too)
456 static const uint32_t ufoAddrTIBx
= UFO_ADDR_TEMP_BIT
+ 0u * 4u; // TIB
457 static const uint32_t ufoAddrINx
= UFO_ADDR_TEMP_BIT
+ 1u * 4u; // >IN
458 static const uint32_t ufoAddrDefTIB
= UFO_ADDR_TEMP_BIT
+ 2u * 4u; // default TIB (handle); user cannot change it
459 static const uint32_t ufoAddrBASE
= UFO_ADDR_TEMP_BIT
+ 3u * 4u;
460 static const uint32_t ufoAddrUserVarUsed
= UFO_ADDR_TEMP_BIT
+ 4u * 4u;
462 static uint32_t ufoAddrContext
; // CONTEXT
463 static uint32_t ufoAddrCurrent
; // CURRENT (definitions will go there)
464 static uint32_t ufoAddrSTATE
;
465 static uint32_t ufoAddrVocLink
;
466 static uint32_t ufoAddrDP
;
467 static uint32_t ufoAddrDPTemp
;
468 static uint32_t ufoAddrNewWordFlags
;
469 static uint32_t ufoAddrRedefineWarning
;
470 static uint32_t ufoAddrLastXFA
;
472 // allows to redefine even protected words
473 #define UFO_REDEF_WARN_DONT_CARE (~(uint32_t)0)
474 // do not warn about ordinary words, allow others
475 #define UFO_REDEF_WARN_NONE (0)
477 #define UFO_REDEF_WARN_NORMAL (1)
479 #define UFO_GET_DP() (ufoImgGetU32(ufoAddrDPTemp) ?: ufoImgGetU32(ufoAddrDP))
480 //#define UFO_SET_DP(val_) ufoImgPutU32(ufoAddrDP, (val_))
482 #define UFO_MAX_NESTED_INCLUDES (32)
489 uint32_t id
; // non-zero unique id
492 static UFOFileStackEntry ufoFileStack
[UFO_MAX_NESTED_INCLUDES
];
493 static uint32_t ufoFileStackPos
; // after the last used item
495 static FILE *ufoInFile
= NULL
;
496 static char *ufoInFileName
= NULL
;
497 static char *ufoLastIncPath
= NULL
;
498 static char *ufoLastSysIncPath
= NULL
;
499 static int ufoInFileLine
= 0;
500 static uint32_t ufoFileId
= 0;
501 static uint32_t ufoLastUsedFileId
= 0;
503 static int ufoLastEmitWasCR
= 1;
505 #define UFO_VOCSTACK_SIZE (16u)
506 static uint32_t ufoVocStack
[UFO_VOCSTACK_SIZE
]; // cfas
507 static uint32_t ufoVSP
;
508 static uint32_t ufoForthVocId
;
509 static uint32_t ufoCompilerVocId
;
512 typedef struct UHandleInfo_t
{
519 struct UHandleInfo_t
*next
;
522 static UfoHandle
*ufoHandleFreeList
= NULL
;
523 static UfoHandle
**ufoHandles
= NULL
;
524 static uint32_t ufoHandlesUsed
= 0;
525 static uint32_t ufoHandlesAlloted
= 0;
527 #define UFO_HANDLE_FREE (~(uint32_t)0)
529 static char ufoCurrFileLine
[520];
532 static uint32_t ufoInBacktrace
= 0;
535 // ////////////////////////////////////////////////////////////////////////// //
536 static void ufoClearCondDefines (void);
538 static void ufoRunVMCFA (uint32_t cfa
);
540 static void ufoBacktrace (uint32_t ip
);
542 static void ufoClearCondDefines (void);
544 static UfoState
*ufoNewState (uint32_t cfa
);
545 static void ufoInitStateUserVars (UfoState
*st
, int initial
);
546 static void ufoFreeState (UfoState
*st
);
547 static UfoState
*ufoFindState (uint32_t stid
);
548 static void ufoSwitchToState (UfoState
*newst
);
550 __attribute__((unused
)) static void ufoDumpWordHeader (const uint32_t lfa
);
553 static void ufoDisableRaw (void);
556 #ifdef UFO_DEBUG_DEBUG
557 static void ufoDumpDebugImage (void);
561 // ////////////////////////////////////////////////////////////////////////// //
562 #define UFWORD(name_) \
563 static void ufoWord_##name_ (uint32_t mypfa)
565 #define UFCALL(name_) ufoWord_##name_(0)
566 #define UFCFA(name_) (&ufoWord_##name_)
569 UFWORD(CPEEK_REGA_IDX
);
570 UFWORD(CPOKE_REGA_IDX
);
573 UFWORD(PAR_HANDLE_LOAD_BYTE
);
574 UFWORD(PAR_HANDLE_LOAD_WORD
);
575 UFWORD(PAR_HANDLE_LOAD_CELL
);
576 UFWORD(PAR_HANDLE_STORE_BYTE
);
577 UFWORD(PAR_HANDLE_STORE_WORD
);
578 UFWORD(PAR_HANDLE_STORE_CELL
);
581 //==========================================================================
585 //==========================================================================
586 void ufoSetUserAbort (void) {
591 //==========================================================================
595 //==========================================================================
596 static UfoHandle
*ufoAllocHandle (uint32_t typeid) {
597 ufo_assert(typeid != UFO_HANDLE_FREE
);
598 UfoHandle
*newh
= ufoHandleFreeList
;
600 if (ufoHandlesUsed
== ufoHandlesAlloted
) {
601 uint32_t newsz
= ufoHandlesAlloted
+ 16384;
602 // due to offsets, this is the maximum number of handles we can have
603 if (newsz
> 0x1ffffU
) {
604 if (ufoHandlesAlloted
> 0x1ffffU
) ufoFatal("too many dynamic handles");
605 newsz
= 0x1ffffU
+ 1U;
606 ufo_assert(newsz
> ufoHandlesAlloted
);
608 UfoHandle
**nh
= realloc(ufoHandles
, sizeof(ufoHandles
[0]) * newsz
);
609 if (nh
== NULL
) ufoFatal("out of memory for handle table");
611 ufoHandlesAlloted
= newsz
;
613 newh
= calloc(1, sizeof(UfoHandle
));
614 if (newh
== NULL
) ufoFatal("out of memory for handle info");
615 ufoHandles
[ufoHandlesUsed
] = newh
;
616 // setup new handle info
617 newh
->ufoHandle
= (ufoHandlesUsed
<< UFO_ADDR_HANDLE_SHIFT
) | UFO_ADDR_HANDLE_BIT
;
620 ufo_assert(newh
->typeid == UFO_HANDLE_FREE
);
621 ufoHandleFreeList
= newh
->next
;
623 // setup new handle info
624 newh
->typeid = typeid;
633 //==========================================================================
637 //==========================================================================
638 static void ufoFreeHandle (UfoHandle
*hh
) {
640 ufo_assert(hh
->typeid != UFO_HANDLE_FREE
);
641 if (hh
->data
) free(hh
->data
);
642 hh
->typeid = UFO_HANDLE_FREE
;
646 hh
->next
= ufoHandleFreeList
;
647 ufoHandleFreeList
= hh
;
652 //==========================================================================
656 //==========================================================================
657 static UfoHandle
*ufoGetHandle (uint32_t hh
) {
659 if (hh
!= 0 && (hh
& UFO_ADDR_HANDLE_BIT
) != 0) {
660 hh
= (hh
& UFO_ADDR_HANDLE_MASK
) >> UFO_ADDR_HANDLE_SHIFT
;
661 if (hh
< ufoHandlesUsed
) {
662 res
= ufoHandles
[hh
];
663 if (res
->typeid == UFO_HANDLE_FREE
) res
= NULL
;
674 //==========================================================================
678 //==========================================================================
679 static void setLastIncPath (const char *fname
, int system
) {
680 if (fname
== NULL
|| fname
[0] == 0) {
682 if (ufoLastSysIncPath
) free(ufoLastIncPath
);
683 ufoLastSysIncPath
= NULL
;
685 if (ufoLastIncPath
) free(ufoLastIncPath
);
686 ufoLastIncPath
= strdup(".");
692 if (ufoLastSysIncPath
) free(ufoLastSysIncPath
);
693 ufoLastSysIncPath
= strdup(fname
);
694 lslash
= ufoLastSysIncPath
;
695 cpos
= ufoLastSysIncPath
;
697 if (ufoLastIncPath
) free(ufoLastIncPath
);
698 ufoLastIncPath
= strdup(fname
);
699 lslash
= ufoLastIncPath
;
700 cpos
= ufoLastIncPath
;
704 if (*cpos
== '/' || *cpos
== '\\') lslash
= cpos
;
706 if (*cpos
== '/') lslash
= cpos
;
715 //==========================================================================
717 // ufoClearIncludePath
719 // required for UrAsm
721 //==========================================================================
722 void ufoClearIncludePath (void) {
723 if (ufoLastIncPath
!= NULL
) {
724 free(ufoLastIncPath
);
725 ufoLastIncPath
= NULL
;
727 if (ufoLastSysIncPath
!= NULL
) {
728 free(ufoLastSysIncPath
);
729 ufoLastSysIncPath
= NULL
;
734 //==========================================================================
738 //==========================================================================
739 static void ufoErrorPrintFile (FILE *fo
) {
741 fprintf(fo
, "UFO ERROR at file %s, line %d: ", ufoInFileName
, ufoInFileLine
);
743 fprintf(fo
, "UFO ERROR somewhere in time: ");
748 //==========================================================================
752 //==========================================================================
753 static void ufoErrorMsgV (const char *fmt
, va_list ap
) {
754 if (!ufoLastEmitWasCR
) { printf("\n"); ufoLastEmitWasCR
= 1; }
756 ufoErrorPrintFile(stderr
);
757 vfprintf(stderr
, fmt
, ap
);
764 //==========================================================================
768 //==========================================================================
769 __attribute__((format(printf
, 1, 2)))
770 void ufoWarning (const char *fmt
, ...) {
773 ufoErrorMsgV(fmt
, ap
);
777 //==========================================================================
781 //==========================================================================
782 __attribute__((noreturn
)) __attribute__((format(printf
, 1, 2)))
783 void ufoFatal (const char *fmt
, ...) {
789 ufoErrorMsgV(fmt
, ap
);
790 if (!ufoInBacktrace
) {
795 fprintf(stderr
, "DOUBLE FATAL: error in backtrace!\n");
798 #ifdef UFO_DEBUG_FATAL_ABORT
805 // ////////////////////////////////////////////////////////////////////////// //
806 // working with the stacks
807 UFO_FORCE_INLINE
void ufoPush (uint32_t v
) { if (ufoSP
>= UFO_DSTACK_SIZE
) ufoFatal("data stack overflow"); ufoDStack
[ufoSP
++] = v
; }
808 UFO_FORCE_INLINE
void ufoDrop (void) { if (ufoSP
== 0) ufoFatal("data stack underflow"); --ufoSP
; }
809 UFO_FORCE_INLINE
uint32_t ufoPop (void) { if (ufoSP
== 0) { ufoFatal("data stack underflow"); } return ufoDStack
[--ufoSP
]; }
810 UFO_FORCE_INLINE
uint32_t ufoPeek (void) { if (ufoSP
== 0) ufoFatal("data stack underflow"); return ufoDStack
[ufoSP
-1u]; }
811 UFO_FORCE_INLINE
void ufoDup (void) { if (ufoSP
== 0) ufoFatal("data stack underflow"); ufoPush(ufoDStack
[ufoSP
-1u]); }
812 UFO_FORCE_INLINE
void ufoOver (void) { if (ufoSP
< 2u) ufoFatal("data stack underflow"); ufoPush(ufoDStack
[ufoSP
-2u]); }
813 UFO_FORCE_INLINE
void ufoSwap (void) { if (ufoSP
< 2u) ufoFatal("data stack underflow"); const uint32_t t
= ufoDStack
[ufoSP
-1u]; ufoDStack
[ufoSP
-1u] = ufoDStack
[ufoSP
-2u]; ufoDStack
[ufoSP
-2u] = t
; }
814 UFO_FORCE_INLINE
void ufoRot (void) { if (ufoSP
< 3u) ufoFatal("data stack underflow"); const uint32_t t
= ufoDStack
[ufoSP
-3u]; ufoDStack
[ufoSP
-3u] = ufoDStack
[ufoSP
-2u]; ufoDStack
[ufoSP
-2u] = ufoDStack
[ufoSP
-1u]; ufoDStack
[ufoSP
-1u] = t
; }
815 UFO_FORCE_INLINE
void ufoNRot (void) { if (ufoSP
< 3u) ufoFatal("data stack underflow"); const uint32_t t
= ufoDStack
[ufoSP
-1u]; ufoDStack
[ufoSP
-1u] = ufoDStack
[ufoSP
-2u]; ufoDStack
[ufoSP
-2u] = ufoDStack
[ufoSP
-3u]; ufoDStack
[ufoSP
-3u] = t
; }
817 UFO_FORCE_INLINE
void ufo2Dup (void) { ufoOver(); ufoOver(); }
818 UFO_FORCE_INLINE
void ufo2Drop (void) { ufoDrop(); ufoDrop(); }
819 UFO_FORCE_INLINE
void ufo2Over (void) { if (ufoSP
< 4u) ufoFatal("data stack underflow"); const uint32_t n0
= ufoDStack
[ufoSP
-4u]; const uint32_t n1
= ufoDStack
[ufoSP
-3u]; ufoPush(n0
); ufoPush(n1
); }
820 UFO_FORCE_INLINE
void ufo2Swap (void) { if (ufoSP
< 4u) ufoFatal("data stack underflow"); const uint32_t n0
= ufoDStack
[ufoSP
-4u]; const uint32_t n1
= ufoDStack
[ufoSP
-3u]; ufoDStack
[ufoSP
-4u] = ufoDStack
[ufoSP
-2u]; ufoDStack
[ufoSP
-3u] = ufoDStack
[ufoSP
-1u]; ufoDStack
[ufoSP
-2u] = n0
; ufoDStack
[ufoSP
-1u] = n1
; }
822 UFO_FORCE_INLINE
void ufoRPush (uint32_t v
) { if (ufoRP
>= UFO_RSTACK_SIZE
) ufoFatal("return stack overflow"); ufoRStack
[ufoRP
++] = v
; }
823 UFO_FORCE_INLINE
void ufoRDrop (void) { if (ufoRP
== 0 || ufoRP
== ufoRPTop
) ufoFatal("return stack underflow"); --ufoRP
; }
824 UFO_FORCE_INLINE
uint32_t ufoRPop (void) { if (ufoRP
== 0 || ufoRP
== ufoRPTop
) ufoFatal("return stack underflow"); return ufoRStack
[--ufoRP
]; }
825 UFO_FORCE_INLINE
uint32_t ufoRPeek (void) { if (ufoRP
== 0 || ufoRP
== ufoRPTop
) ufoFatal("return stack underflow"); return ufoRStack
[ufoRP
-1u]; }
826 UFO_FORCE_INLINE
void ufoRDup (void) { if (ufoRP
== 0 || ufoRP
== ufoRPTop
) ufoFatal("return stack underflow"); ufoPush(ufoRStack
[ufoRP
-1u]); }
828 UFO_FORCE_INLINE
void ufoPushBool (int v
) { ufoPush(v
? ufoTrueValue
: 0u); }
831 //==========================================================================
835 //==========================================================================
836 static void ufoImgEnsureSize (uint32_t addr
) {
837 if ((addr
& UFO_ADDR_SPECIAL_BITS_MASK
) != 0) ufoFatal("ufoImgEnsureSize: internal error");
838 if (addr
>= ufoImageSize
) {
839 // 64MB should be enough for everyone!
840 if (addr
>= 0x04000000U
) {
841 ufoFatal("image grown too big (addr=0%08XH)", addr
);
843 const const uint32_t osz
= ufoImageSize
;
845 const uint32_t nsz
= (addr
|0x000fffffU
) + 1U;
846 ufo_assert(nsz
> addr
);
847 uint32_t *nimg
= realloc(ufoImage
, nsz
);
849 ufoFatal("out of memory for UFO image (%u -> %u MBs)",
850 ufoImageSize
/ 1024u / 1024u,
851 nsz
/ 1024u / 1024u);
855 memset((char *)ufoImage
+ osz
, 0, (nsz
- osz
));
860 //==========================================================================
864 //==========================================================================
865 static void ufoImgEnsureTemp (uint32_t addr
) {
866 if ((addr
& UFO_ADDR_SPECIAL_BITS_MASK
) != 0) ufoFatal("ufoImgEnsureTemp: internal error");
867 if (addr
>= ufoImageTempSize
) {
868 if (addr
>= 1024u * 1024u) {
869 ufoFatal("Forth segmentation fault at address 0x%08X", addr
| UFO_ADDR_TEMP_BIT
);
871 const uint32_t osz
= ufoImageTempSize
;
873 const uint32_t nsz
= (addr
|0x00001fffU
) + 1U;
874 uint32_t *nimg
= realloc(ufoImageTemp
, nsz
);
876 ufoFatal("out of memory for temp UFO image (%u -> %u KBs)",
877 ufoImageTempSize
/ 1024u,
881 ufoImageTempSize
= nsz
;
882 memset((char *)ufoImageTemp
+ osz
, 0, (nsz
- osz
));
887 #ifdef UFO_FAST_MEM_ACCESS
888 //==========================================================================
894 //==========================================================================
895 UFO_FORCE_INLINE
void ufoImgPutU8 (uint32_t addr
, const uint32_t value
) {
896 if ((addr
& UFO_ADDR_SPECIAL_BITS_MASK
) == 0) {
897 if (addr
>= ufoImageSize
) ufoImgEnsureSize(addr
);
898 *((uint8_t *)ufoImage
+ addr
) = (uint8_t)value
;
899 } else if (addr
& UFO_ADDR_TEMP_BIT
) {
900 addr
&= UFO_ADDR_TEMP_MASK
;
901 if (addr
>= ufoImageTempSize
) ufoImgEnsureTemp(addr
);
902 *((uint8_t *)ufoImageTemp
+ addr
) = (uint8_t)value
;
904 ufoFatal("Forth segmentation fault at address 0x%08X", addr
);
909 //==========================================================================
915 //==========================================================================
916 UFO_FORCE_INLINE
void ufoImgPutU16 (uint32_t addr
, const uint32_t value
) {
917 if ((addr
& UFO_ADDR_SPECIAL_BITS_MASK
) == 0) {
918 if (addr
+ 1u >= ufoImageSize
) ufoImgEnsureSize(addr
+ 1u);
919 *(uint16_t *)((uint8_t *)ufoImage
+ addr
) = (uint16_t)value
;
920 } else if (addr
& UFO_ADDR_TEMP_BIT
) {
921 addr
&= UFO_ADDR_TEMP_MASK
;
922 if (addr
+ 1u >= ufoImageTempSize
) ufoImgEnsureTemp(addr
+ 1u);
923 *(uint16_t *)((uint8_t *)ufoImageTemp
+ addr
) = (uint16_t)value
;
925 ufoFatal("Forth segmentation fault at address 0x%08X", addr
);
930 //==========================================================================
936 //==========================================================================
937 UFO_FORCE_INLINE
void ufoImgPutU32 (uint32_t addr
, const uint32_t value
) {
938 if ((addr
& UFO_ADDR_SPECIAL_BITS_MASK
) == 0) {
939 if (addr
+ 3u >= ufoImageSize
) ufoImgEnsureSize(addr
+ 3u);
940 *(uint32_t *)((uint8_t *)ufoImage
+ addr
) = value
;
941 } else if (addr
& UFO_ADDR_TEMP_BIT
) {
942 addr
&= UFO_ADDR_TEMP_MASK
;
943 if (addr
+ 3u >= ufoImageTempSize
) ufoImgEnsureTemp(addr
+ 3u);
944 *(uint32_t *)((uint8_t *)ufoImageTemp
+ addr
) = value
;
946 ufoFatal("Forth segmentation fault at address 0x%08X", addr
);
951 //==========================================================================
957 //==========================================================================
958 UFO_FORCE_INLINE
uint32_t ufoImgGetU8 (uint32_t addr
) {
959 if ((addr
& UFO_ADDR_SPECIAL_BITS_MASK
) == 0) {
960 if (addr
>= ufoImageSize
) {
961 // accessing unallocated image area is segmentation fault
962 ufoFatal("Forth segmentation fault (unallocated access) at address 0x%08X", addr
);
964 return *((const uint8_t *)ufoImage
+ addr
);
965 } else if (addr
& UFO_ADDR_TEMP_BIT
) {
966 addr
&= UFO_ADDR_TEMP_MASK
;
967 if (addr
>= ufoImageTempSize
) {
968 // accessing unallocated image area is segmentation fault
969 ufoFatal("Forth segmentation fault (unallocated access) at address 0x%08X", addr
| UFO_ADDR_TEMP_BIT
);
971 return *((const uint8_t *)ufoImageTemp
+ addr
);
973 ufoFatal("Forth segmentation fault at address 0x%08X", addr
);
978 //==========================================================================
984 //==========================================================================
985 UFO_FORCE_INLINE
uint32_t ufoImgGetU16 (uint32_t addr
) {
986 if ((addr
& UFO_ADDR_SPECIAL_BITS_MASK
) == 0) {
987 if (addr
+ 1u >= ufoImageSize
) {
988 // accessing unallocated image area is segmentation fault
989 ufoFatal("Forth segmentation fault (unallocated access) at address 0x%08X", addr
);
991 return *(const uint16_t *)((const uint8_t *)ufoImage
+ addr
);
992 } else if (addr
& UFO_ADDR_TEMP_BIT
) {
993 addr
&= UFO_ADDR_TEMP_MASK
;
994 if (addr
+ 1u >= ufoImageTempSize
) {
995 // accessing unallocated image area is segmentation fault
996 ufoFatal("Forth segmentation fault (unallocated access) at address 0x%08X", addr
| UFO_ADDR_TEMP_BIT
);
998 return *(const uint16_t *)((const uint8_t *)ufoImageTemp
+ addr
);
1000 ufoFatal("Forth segmentation fault at address 0x%08X", addr
);
1005 //==========================================================================
1011 //==========================================================================
1012 UFO_FORCE_INLINE
uint32_t ufoImgGetU32 (uint32_t addr
) {
1013 if ((addr
& UFO_ADDR_SPECIAL_BITS_MASK
) == 0) {
1014 if (addr
+ 3u >= ufoImageSize
) {
1015 // accessing unallocated image area is segmentation fault
1016 ufoFatal("Forth segmentation fault (unallocated access) at address 0x%08X", addr
);
1018 return *(const uint32_t *)((const uint8_t *)ufoImage
+ addr
);
1019 } else if (addr
& UFO_ADDR_TEMP_BIT
) {
1020 addr
&= UFO_ADDR_TEMP_MASK
;
1021 if (addr
+ 3u >= ufoImageTempSize
) {
1022 // accessing unallocated image area is segmentation fault
1023 ufoFatal("Forth segmentation fault (unallocated access) at address 0x%08X", addr
| UFO_ADDR_TEMP_BIT
);
1025 return *(const uint32_t *)((const uint8_t *)ufoImageTemp
+ addr
);
1027 ufoFatal("Forth segmentation fault at address 0x%08X", addr
);
1033 //==========================================================================
1039 //==========================================================================
1040 UFO_FORCE_INLINE
void ufoImgPutU8 (uint32_t addr
, const uint32_t value
) {
1042 if ((addr
& UFO_ADDR_SPECIAL_BITS_MASK
) == 0) {
1043 if (addr
>= ufoImageSize
) ufoImgEnsureSize(addr
);
1044 imgptr
= &ufoImage
[addr
/4u];
1045 } else if (addr
& UFO_ADDR_TEMP_BIT
) {
1046 addr
&= UFO_ADDR_TEMP_MASK
;
1047 if (addr
>= ufoImageTempSize
) ufoImgEnsureTemp(addr
);
1048 imgptr
= &ufoImageTemp
[addr
/4u];
1050 ufoFatal("Forth segmentation fault at address 0x%08X", addr
);
1052 const uint8_t val
= (uint8_t)value
;
1053 memcpy((uint8_t *)imgptr
+ (addr
&3), &val
, 1);
1057 //==========================================================================
1063 //==========================================================================
1064 UFO_FORCE_INLINE
void ufoImgPutU16 (uint32_t addr
, const uint32_t value
) {
1065 ufoImgPutU8(addr
, value
&0xffU
);
1066 ufoImgPutU8(addr
+ 1u, (value
>>8)&0xffU
);
1070 //==========================================================================
1076 //==========================================================================
1077 UFO_FORCE_INLINE
void ufoImgPutU32 (uint32_t addr
, const uint32_t value
) {
1078 ufoImgPutU16(addr
, value
&0xffffU
);
1079 ufoImgPutU16(addr
+ 2u, (value
>>16)&0xffffU
);
1083 //==========================================================================
1089 //==========================================================================
1090 UFO_FORCE_INLINE
uint32_t ufoImgGetU8 (uint32_t addr
) {
1092 if ((addr
& UFO_ADDR_SPECIAL_BITS_MASK
) == 0) {
1093 if (addr
>= ufoImageSize
) return 0;
1094 imgptr
= &ufoImage
[addr
/4u];
1095 } else if (addr
& UFO_ADDR_TEMP_BIT
) {
1096 addr
&= UFO_ADDR_TEMP_MASK
;
1097 if (addr
>= ufoImageTempSize
) return 0;
1098 imgptr
= &ufoImageTemp
[addr
/4u];
1100 ufoFatal("Forth segmentation fault at address 0x%08X", addr
);
1103 memcpy(&val
, (uint8_t *)imgptr
+ (addr
&3), 1);
1104 return (uint32_t)val
;
1108 //==========================================================================
1114 //==========================================================================
1115 UFO_FORCE_INLINE
uint32_t ufoImgGetU16 (uint32_t addr
) {
1116 return ufoImgGetU8(addr
) | (ufoImgGetU8(addr
+ 1u) << 8);
1120 //==========================================================================
1126 //==========================================================================
1127 UFO_FORCE_INLINE
uint32_t ufoImgGetU32 (uint32_t addr
) {
1128 return ufoImgGetU16(addr
) | (ufoImgGetU16(addr
+ 2u) << 16);
1133 //==========================================================================
1137 //==========================================================================
1138 UFO_DISABLE_INLINE
void ufoEnsureDebug (uint32_t sdelta
) {
1139 ufo_assert(sdelta
!= 0);
1140 if (ufoDebugImageUsed
!= 0) {
1141 if (ufoDebugImageUsed
+ sdelta
>= 0x40000000U
) ufoFatal("debug info too big");
1142 if (ufoDebugImageUsed
+ sdelta
> ufoDebugImageSize
) {
1143 // grow by 32KB, this should be more than enough
1144 const uint32_t newsz
= ((ufoDebugImageUsed
+ sdelta
) | 0x7fffU
) + 1u;
1145 uint8_t *ndb
= realloc(ufoDebugImage
, newsz
);
1146 if (ndb
== NULL
) ufoFatal("out of memory for debug info");
1147 ufoDebugImage
= ndb
;
1148 ufoDebugImageSize
= newsz
;
1151 // initial allocation: 32KB, quite a lot
1152 ufoDebugImageSize
= 1024 * 32;
1153 ufoDebugImage
= malloc(ufoDebugImageSize
);
1154 if (ufoDebugImage
== NULL
) ufoFatal("out of memory for debug info");
1159 #ifdef UFO_DEBUG_DEBUG
1160 //==========================================================================
1164 //==========================================================================
1165 static void ufoDumpDebugImage (void) {
1167 uint32_t dbgpos
= 0u; // first item is always "next file record"
1168 while (dbgpos
< ufoDebugImageUsed
) {
1169 const uint32_t ln
= *(const uint32_t *)(ufoDebugImage
+ dbgpos
); dbgpos
+= 4u;
1170 if (ln
== ~(uint32_t)0) {
1172 const uint32_t nlen
= *(const uint32_t *)(ufoDebugImage
+ dbgpos
); dbgpos
+= 4u;
1173 fprintf(stderr
, "*** NEW FILE: %s\n", (const char *)(ufoDebugImage
+ dbgpos
));
1174 dbgpos
+= nlen
+ 1u;
1175 if ((dbgpos
& 0x03) != 0) dbgpos
= (dbgpos
| 0x03u
) + 1u;
1177 const uint32_t edp
= *(const uint32_t *)(ufoDebugImage
+ dbgpos
); dbgpos
+= 4u;
1178 fprintf(stderr
, " line %6u: edp=%u\n", ln
, edp
);
1186 #define UFO_DBG_PUT_U4(val_) do { \
1187 const uint32_t vv_ = (val_); \
1188 *((uint32_t *)(ufoDebugImage + ufoDebugImageUsed)) = vv_; \
1189 ufoDebugImageUsed += 4u; \
1192 //==========================================================================
1196 //==========================================================================
1197 UFO_DISABLE_INLINE
void ufoRecordDebug (uint32_t newhere
) {
1198 if (newhere
> ufoDebugCurrDP
) {
1199 if (ufoInFileName
!= NULL
) {
1200 // check if we're doing the same file
1201 const uint32_t slen
= (uint32_t)strlen(ufoInFileName
);
1202 const int newfrec
= (ufoDebugLastFRecAddr
== 0) ||
1203 (*((const uint32_t *)(ufoDebugImage
+ ufoDebugLastFRecAddr
)) != slen
) ||
1204 (memcmp((const char *)ufoDebugImage
+ ufoDebugLastFRecAddr
+ 4u, ufoInFileName
, slen
) != 0);
1205 uint32_t fline
= (uint32_t)ufoInFileLine
;
1206 if (fline
== ~(uint32_t)0) fline
-= 1u;
1208 ufoEnsureDebug(slen
+ 4u + 4u + 4u + 32u); // way too much ;-)
1209 // finish previous record
1210 UFO_DBG_PUT_U4(~(uint32_t)0);
1211 // create new file record
1212 ufoDebugLastFRecAddr
= ufoDebugImageUsed
;
1213 UFO_DBG_PUT_U4(slen
);
1214 memcpy(ufoDebugImage
+ ufoDebugImageUsed
, ufoInFileName
, slen
+ 1u);
1215 ufoDebugImageUsed
+= slen
+ 1u;
1216 while ((ufoDebugImageUsed
& 0x03u
) != 0) {
1217 ufoDebugImage
[ufoDebugImageUsed
] = 0;
1218 ufoDebugImageUsed
+= 1;
1220 UFO_DBG_PUT_U4(fline
);
1221 UFO_DBG_PUT_U4(newhere
);
1223 // check if the line is the same
1224 if (*((const uint32_t *)(ufoDebugImage
+ ufoDebugImageUsed
- 8u)) == fline
) {
1225 *((uint32_t *)(ufoDebugImage
+ ufoDebugImageUsed
- 4u)) = newhere
;
1229 UFO_DBG_PUT_U4(fline
);
1230 UFO_DBG_PUT_U4(newhere
);
1234 // we don't have a file, don't record debug info
1236 ufoDebugLastFRecAddr
= 0;
1238 ufoDebugCurrDP
= newhere
;
1243 //==========================================================================
1245 // ufoGetWordEndAddrYFA
1247 //==========================================================================
1248 static uint32_t ufoGetWordEndAddrYFA (uint32_t yfa
) {
1250 const uint32_t oyfa
= yfa
;
1251 yfa
= ufoImgGetU32(yfa
);
1253 if ((oyfa
& UFO_ADDR_TEMP_BIT
) == 0) {
1255 if ((yfa
& UFO_ADDR_TEMP_BIT
) != 0) {
1256 yfa
= UFO_CFA_TO_PFA(UFO_NFA_TO_CFA(UFO_YFA_TO_NFA(oyfa
)));
1259 yfa
= UFO_CFA_TO_PFA(UFO_NFA_TO_CFA(UFO_YFA_TO_NFA(oyfa
)));
1262 yfa
= UFO_YFA_TO_WST(yfa
);
1271 //==========================================================================
1273 // ufoGetWordEndAddr
1275 //==========================================================================
1276 static uint32_t ufoGetWordEndAddr (const uint32_t cfa
) {
1278 return ufoGetWordEndAddrYFA(UFO_LFA_TO_YFA(UFO_CFA_TO_LFA(cfa
)));
1285 //==========================================================================
1291 // WARNING: this is SLOW!
1293 //==========================================================================
1294 static uint32_t ufoFindWordForIP (const uint32_t ip
) {
1297 // iterate over all words
1298 uint32_t xfa
= ufoImgGetU32(ufoAddrLastXFA
);
1300 while (res
== 0 && xfa
!= 0) {
1301 const uint32_t yfa
= UFO_XFA_TO_YFA(xfa
);
1302 const uint32_t wst
= UFO_YFA_TO_WST(yfa
);
1303 const uint32_t wend
= ufoGetWordEndAddrYFA(yfa
);
1304 if (ip
>= wst
&& ip
< wend
) {
1305 res
= UFO_YFA_TO_NFA(yfa
);
1307 xfa
= ufoImgGetU32(xfa
);
1316 //==========================================================================
1320 // return file name or `NULL`
1322 // WARNING: this is SLOW!
1324 //==========================================================================
1325 static const char *ufoFindFileForIP (uint32_t ip
, uint32_t *line
) {
1326 const char *res
= NULL
;
1327 if (ip
!= 0 && ufoDebugImageUsed
!= 0) {
1328 uint32_t lastfinfo
= 0u;
1329 uint32_t lastip
= 0u;
1330 uint32_t dbgpos
= 0u; // first item is always "next file record"
1331 while (res
== NULL
&& dbgpos
< ufoDebugImageUsed
) {
1332 const uint32_t ln
= *(const uint32_t *)(ufoDebugImage
+ dbgpos
); dbgpos
+= 4u;
1333 if (ln
== ~(uint32_t)0) {
1336 const uint32_t nlen
= *(const uint32_t *)(ufoDebugImage
+ dbgpos
); dbgpos
+= 4u;
1337 dbgpos
+= nlen
+ 1u;
1338 if ((dbgpos
& 0x03) != 0) dbgpos
= (dbgpos
| 0x03u
) + 1u;
1340 const uint32_t edp
= *(const uint32_t *)(ufoDebugImage
+ dbgpos
); dbgpos
+= 4u;
1341 if (ip
>= lastip
&& ip
< edp
) {
1342 if (line
) *line
= ln
;
1343 res
= (const char *)(ufoDebugImage
+ lastfinfo
+ 4u);
1353 //==========================================================================
1357 //==========================================================================
1358 UFO_FORCE_INLINE
void ufoBumpDP (uint32_t delta
) {
1359 uint32_t dp
= ufoImgGetU32(ufoAddrDPTemp
);
1361 dp
= ufoImgGetU32(ufoAddrDP
);
1362 if ((dp
& UFO_ADDR_SPECIAL_BITS_MASK
) == 0) ufoRecordDebug(dp
+ delta
);
1364 ufoImgPutU32(ufoAddrDP
, dp
);
1366 dp
= ufoImgGetU32(ufoAddrDPTemp
);
1367 if ((dp
& UFO_ADDR_SPECIAL_BITS_MASK
) == 0) ufoRecordDebug(dp
+ delta
);
1369 ufoImgPutU32(ufoAddrDPTemp
, dp
);
1374 //==========================================================================
1378 //==========================================================================
1379 UFO_FORCE_INLINE
void ufoImgEmitU8 (uint32_t value
) {
1380 ufoImgPutU8(UFO_GET_DP(), value
);
1385 //==========================================================================
1389 //==========================================================================
1390 UFO_FORCE_INLINE
void ufoImgEmitU32 (uint32_t value
) {
1391 ufoImgPutU32(UFO_GET_DP(), value
);
1396 #ifdef UFO_FAST_MEM_ACCESS
1398 //==========================================================================
1400 // ufoImgEmitU32_NoInline
1404 //==========================================================================
1405 UFO_FORCE_INLINE
void ufoImgEmitU32_NoInline (uint32_t value
) {
1406 ufoImgPutU32(UFO_GET_DP(), value
);
1412 //==========================================================================
1414 // ufoImgEmitU32_NoInline
1418 //==========================================================================
1419 UFO_DISABLE_INLINE
void ufoImgEmitU32_NoInline (uint32_t value
) {
1420 ufoImgPutU32(UFO_GET_DP(), value
);
1427 //==========================================================================
1431 // this understands handle addresses
1433 //==========================================================================
1434 UFO_FORCE_INLINE
uint32_t ufoImgGetU8Ext (uint32_t addr
) {
1435 if ((addr
& UFO_ADDR_HANDLE_BIT
) == 0) {
1436 return ufoImgGetU8(addr
);
1440 UFCALL(PAR_HANDLE_LOAD_BYTE
);
1446 //==========================================================================
1450 // this understands handle addresses
1452 //==========================================================================
1453 UFO_FORCE_INLINE
void ufoImgPutU8Ext (uint32_t addr
, uint32_t value
) {
1454 if ((addr
& UFO_ADDR_HANDLE_BIT
) == 0) {
1455 ufoImgPutU8(addr
, value
);
1460 UFCALL(PAR_HANDLE_STORE_BYTE
);
1465 //==========================================================================
1469 //==========================================================================
1470 UFO_FORCE_INLINE
void ufoImgEmitAlign (void) {
1471 while ((UFO_GET_DP() & 3) != 0) ufoImgEmitU8(0);
1475 //==========================================================================
1479 //==========================================================================
1480 UFO_FORCE_INLINE
void ufoResetTib (void) {
1481 uint32_t defTIB
= ufoImgGetU32(ufoAddrDefTIB
);
1482 //fprintf(stderr, "ufoResetTib(%p): defTIB=0x%08x\n", ufoCurrState, defTIB);
1484 // create new TIB handle
1485 UfoHandle
*tibh
= ufoAllocHandle(0x69a029a6); // arbitrary number
1486 defTIB
= tibh
->ufoHandle
;
1487 ufoImgPutU32(ufoAddrDefTIB
, defTIB
);
1489 if ((defTIB
& UFO_ADDR_HANDLE_BIT
) != 0) {
1490 UfoHandle
*hh
= ufoGetHandle(defTIB
);
1491 if (hh
== NULL
) ufoFatal("default TIB is not allocated");
1492 if (hh
->size
== 0) {
1493 ufo_assert(hh
->data
== NULL
);
1494 hh
->data
= calloc(1, UFO_ADDR_HANDLE_OFS_MASK
+ 1);
1495 if (hh
->data
== NULL
) ufoFatal("out of memory for default TIB");
1496 hh
->size
= UFO_ADDR_HANDLE_OFS_MASK
+ 1;
1499 const uint32_t oldA
= ufoRegA
;
1500 ufoImgPutU32(ufoAddrTIBx
, defTIB
);
1501 ufoImgPutU32(ufoAddrINx
, 0);
1503 ufoPush(0); // value
1504 ufoPush(0); // offset
1505 UFCALL(CPOKE_REGA_IDX
);
1510 //==========================================================================
1514 //==========================================================================
1515 UFO_DISABLE_INLINE
void ufoTibEnsureSize (uint32_t size
) {
1516 if (size
> 1024u * 1024u * 256u) ufoFatal("TIB size too big");
1517 const uint32_t tib
= ufoImgGetU32(ufoAddrTIBx
);
1518 //fprintf(stderr, "ufoTibEnsureSize: TIB=0x%08x; size=%u\n", tib, size);
1519 if ((tib
& UFO_ADDR_HANDLE_BIT
) != 0) {
1520 UfoHandle
*hh
= ufoGetHandle(tib
);
1522 ufoFatal("cannot resize TIB, TIB is not a handle");
1524 if (hh
->size
< size
) {
1525 const uint32_t newsz
= (size
| 0xfffU
) + 1u;
1526 uint8_t *nx
= realloc(hh
->data
, newsz
);
1527 if (nx
== NULL
) ufoFatal("out of memory for restored TIB");
1534 ufoFatal("cannot resize TIB, TIB is not a handle (0x%08x)", tib
);
1540 //==========================================================================
1544 //==========================================================================
1546 UFO_DISABLE_INLINE uint32_t ufoTibGetSize (void) {
1547 const uint32_t tib = ufoImgGetU32(ufoAddrTIBx);
1548 if ((tib & UFO_ADDR_HANDLE_BIT) == 0) {
1549 ufoFatal("cannot query TIB, TIB is not a handle");
1551 UfoHandle *hh = ufoGetHandle(tib);
1553 ufoFatal("cannot query TIB, TIB is not a handle");
1560 //==========================================================================
1564 //==========================================================================
1565 UFO_FORCE_INLINE
uint8_t ufoTibPeekCh (void) {
1566 return (uint8_t)ufoImgGetU8Ext(ufoImgGetU32(ufoAddrTIBx
) + ufoImgGetU32(ufoAddrINx
));
1570 //==========================================================================
1574 //==========================================================================
1575 UFO_FORCE_INLINE
uint8_t ufoTibPeekChOfs (uint32_t ofs
) {
1576 const uint32_t tib
= ufoImgGetU32(ufoAddrTIBx
);
1577 if (ofs
<= UFO_ADDR_HANDLE_OFS_MASK
|| (tib
& UFO_ADDR_HANDLE_BIT
) == 0) {
1578 return (uint8_t)ufoImgGetU8Ext(tib
+ ufoImgGetU32(ufoAddrINx
) + ofs
);
1585 //==========================================================================
1589 //==========================================================================
1590 UFO_DISABLE_INLINE
void ufoTibPokeChOfs (uint8_t ch
, uint32_t ofs
) {
1591 const uint32_t oldA
= ufoRegA
;
1592 ufoRegA
= ufoImgGetU32(ufoAddrTIBx
);
1594 ufoPush(ufoImgGetU32(ufoAddrINx
) + ofs
);
1595 UFCALL(CPOKE_REGA_IDX
);
1600 //==========================================================================
1604 //==========================================================================
1605 UFO_FORCE_INLINE
uint8_t ufoTibGetCh (void) {
1606 const uint8_t ch
= ufoTibPeekCh();
1607 if (ch
) ufoImgPutU32(ufoAddrINx
, ufoImgGetU32(ufoAddrINx
) + 1u);
1612 //==========================================================================
1616 //==========================================================================
1617 UFO_FORCE_INLINE
void ufoTibSkipCh (void) {
1618 (void)ufoTibGetCh();
1622 // ////////////////////////////////////////////////////////////////////////// //
1623 // native CFA implementations
1626 //==========================================================================
1630 //==========================================================================
1631 static void ufoDoForth (uint32_t pfa
) {
1637 //==========================================================================
1641 //==========================================================================
1642 static void ufoDoVariable (uint32_t pfa
) {
1647 //==========================================================================
1649 // ufoDoUserVariable
1651 //==========================================================================
1652 static void ufoDoUserVariable (uint32_t pfa
) {
1653 ufoPush(ufoImgGetU32(pfa
));
1657 //==========================================================================
1661 //==========================================================================
1662 static void ufoDoValue (uint32_t pfa
) {
1663 ufoPush(ufoImgGetU32(pfa
));
1667 //==========================================================================
1671 //==========================================================================
1672 static void ufoDoConst (uint32_t pfa
) {
1673 ufoPush(ufoImgGetU32(pfa
));
1677 //==========================================================================
1681 //==========================================================================
1682 static void ufoDoDefer (uint32_t pfa
) {
1683 const uint32_t cfa
= ufoImgGetU32(pfa
);
1691 //==========================================================================
1695 //==========================================================================
1696 static void ufoDoVoc (uint32_t pfa
) {
1697 ufoImgPutU32(ufoAddrContext
, ufoImgGetU32(pfa
));
1701 //==========================================================================
1705 //==========================================================================
1706 static void ufoDoCreate (uint32_t pfa
) {
1711 //==========================================================================
1715 // this also increments last used file id
1717 //==========================================================================
1718 static void ufoPushInFile (void) {
1719 if (ufoFileStackPos
>= UFO_MAX_NESTED_INCLUDES
) ufoFatal("too many includes");
1720 UFOFileStackEntry
*stk
= &ufoFileStack
[ufoFileStackPos
];
1721 stk
->fl
= ufoInFile
;
1722 stk
->fname
= ufoInFileName
;
1723 stk
->fline
= ufoInFileLine
;
1724 stk
->id
= ufoFileId
;
1725 stk
->incpath
= (ufoLastIncPath
? strdup(ufoLastIncPath
) : NULL
);
1726 stk
->sysincpath
= (ufoLastSysIncPath
? strdup(ufoLastSysIncPath
) : NULL
);
1727 ufoFileStackPos
+= 1;
1729 ufoInFileName
= NULL
;
1731 ufoLastUsedFileId
+= 1;
1732 ufo_assert(ufoLastUsedFileId
!= 0); // just in case ;-)
1733 //ufoLastIncPath = NULL;
1737 //==========================================================================
1739 // ufoWipeIncludeStack
1741 //==========================================================================
1742 static void ufoWipeIncludeStack (void) {
1743 if (ufoInFileName
) { free(ufoInFileName
); ufoInFileName
= NULL
; }
1744 if (ufoInFile
) { fclose(ufoInFile
); ufoInFile
= NULL
; }
1745 if (ufoLastIncPath
) { free(ufoLastIncPath
); ufoLastIncPath
= NULL
; }
1746 if (ufoLastSysIncPath
) { free(ufoLastSysIncPath
); ufoLastSysIncPath
= NULL
; }
1747 while (ufoFileStackPos
!= 0) {
1748 ufoFileStackPos
-= 1;
1749 UFOFileStackEntry
*stk
= &ufoFileStack
[ufoFileStackPos
];
1750 if (stk
->fl
) fclose(stk
->fl
);
1751 if (stk
->fname
) free(stk
->fname
);
1752 if (stk
->incpath
) free(stk
->incpath
);
1757 //==========================================================================
1761 //==========================================================================
1762 static void ufoPopInFile (void) {
1763 if (ufoFileStackPos
== 0) ufoFatal("trying to pop include from empty stack");
1764 if (ufoInFileName
) { free(ufoInFileName
); ufoInFileName
= NULL
; }
1765 if (ufoInFile
) { fclose(ufoInFile
); ufoInFile
= NULL
; }
1766 if (ufoLastIncPath
) { free(ufoLastIncPath
); ufoLastIncPath
= NULL
; }
1767 if (ufoLastSysIncPath
) { free(ufoLastSysIncPath
); ufoLastSysIncPath
= NULL
; }
1768 ufoFileStackPos
-= 1;
1769 UFOFileStackEntry
*stk
= &ufoFileStack
[ufoFileStackPos
];
1770 ufoInFile
= stk
->fl
;
1771 ufoInFileName
= stk
->fname
;
1772 ufoInFileLine
= stk
->fline
;
1773 ufoLastIncPath
= stk
->incpath
;
1774 ufoLastSysIncPath
= stk
->sysincpath
;
1775 ufoFileId
= stk
->id
;
1777 #ifdef UFO_DEBUG_INCLUDE
1778 if (ufoInFileName
== NULL
) {
1779 fprintf(stderr
, "INC-POP: no more files.\n");
1781 fprintf(stderr
, "INC-POP: fname: %s\n", ufoInFileName
);
1787 //==========================================================================
1791 //==========================================================================
1792 void ufoDeinit (void) {
1793 #ifdef UFO_DEBUG_DEBUG
1794 fprintf(stderr
, "UFO: debug image used: %u; size: %u\n",
1795 ufoDebugImageUsed
, ufoDebugImageSize
);
1796 ufoDumpDebugImage();
1800 ufoCurrState
= NULL
;
1801 ufoYieldedState
= NULL
;
1802 ufoDebuggerState
= NULL
;
1803 for (uint32_t fidx
= 0; fidx
< (uint32_t)(UFO_MAX_STATES
/32); fidx
+= 1u) {
1804 uint32_t bmp
= ufoStateUsedBitmap
[fidx
];
1806 uint32_t stid
= fidx
* 32u;
1808 if ((bmp
& 0x01) != 0) ufoFreeState(ufoStateMap
[stid
]);
1809 stid
+= 1u; bmp
>>= 1;
1814 free(ufoDebugImage
);
1815 ufoDebugImage
= NULL
;
1816 ufoDebugImageUsed
= 0;
1817 ufoDebugImageSize
= 0;
1819 ufoDebugLastFRecAddr
= 0;
1823 ufoClearCondDefines();
1824 ufoWipeIncludeStack();
1826 // release all includes
1828 if (ufoInFileName
) free(ufoInFileName
);
1829 if (ufoLastIncPath
) free(ufoLastIncPath
);
1830 if (ufoLastSysIncPath
) free(ufoLastSysIncPath
);
1831 ufoInFileName
= NULL
; ufoLastIncPath
= NULL
; ufoLastSysIncPath
= NULL
;
1835 ufoForthCFAs
= NULL
;
1842 ufoMode
= UFO_MODE_NATIVE
;
1844 ufoForthVocId
= 0; ufoCompilerVocId
= 0;
1848 for (uint32_t f
= 0; f
< ufoHandlesUsed
; f
+= 1) {
1849 UfoHandle
*hh
= ufoHandles
[f
];
1851 if (hh
->data
!= NULL
) free(hh
->data
);
1855 if (ufoHandles
!= NULL
) free(ufoHandles
);
1856 ufoHandles
= NULL
; ufoHandlesUsed
= 0; ufoHandlesAlloted
= 0;
1857 ufoHandleFreeList
= NULL
;
1859 ufoLastEmitWasCR
= 1;
1861 ufoClearCondDefines();
1865 //==========================================================================
1867 // ufoDumpWordHeader
1869 //==========================================================================
1870 __attribute__((unused
)) static void ufoDumpWordHeader (const uint32_t lfa
) {
1871 fprintf(stderr
, "=== WORD: LFA: 0x%08x ===\n", lfa
);
1873 fprintf(stderr
, " (DFA): 0x%08x\n", ufoImgGetU32(UFO_LFA_TO_DFA(lfa
)));
1874 fprintf(stderr
, " (XFA): 0x%08x\n", ufoImgGetU32(UFO_LFA_TO_XFA(lfa
)));
1875 fprintf(stderr
, " (YFA): 0x%08x\n", ufoImgGetU32(UFO_LFA_TO_YFA(lfa
)));
1876 fprintf(stderr
, " (BFA): 0x%08x\n", ufoImgGetU32(UFO_LFA_TO_BFA(lfa
)));
1877 fprintf(stderr
, " (LFA): 0x%08x\n", ufoImgGetU32(lfa
));
1878 fprintf(stderr
, " (NHH): 0x%08x\n", ufoImgGetU32(UFO_LFA_TO_NHASH(lfa
)));
1879 const uint32_t cfa
= UFO_LFA_TO_CFA(lfa
);
1880 fprintf(stderr
, " CFA: 0x%08x\n", cfa
);
1881 fprintf(stderr
, " PFA: 0x%08x\n", UFO_CFA_TO_PFA(cfa
));
1882 fprintf(stderr
, " (CFA): 0x%08x\n", ufoImgGetU32(cfa
));
1883 const uint32_t nfa
= UFO_LFA_TO_NFA(lfa
);
1884 const uint32_t nlen
= ufoImgGetU8(nfa
);
1885 fprintf(stderr
, " NFA: 0x%08x (nlen: %u)\n", nfa
, nlen
);
1886 const uint32_t flags
= ufoImgGetU32(nfa
);
1887 fprintf(stderr
, " FLAGS: 0x%08x\n", flags
);
1888 if ((flags
& 0xffff0000U
) != 0) {
1889 fprintf(stderr
, " FLAGS:");
1890 if (flags
& UFW_FLAG_IMMEDIATE
) fprintf(stderr
, " IMM");
1891 if (flags
& UFW_FLAG_SMUDGE
) fprintf(stderr
, " SMUDGE");
1892 if (flags
& UFW_FLAG_NORETURN
) fprintf(stderr
, " NORET");
1893 if (flags
& UFW_FLAG_HIDDEN
) fprintf(stderr
, " HIDDEN");
1894 if (flags
& UFW_FLAG_CBLOCK
) fprintf(stderr
, " CBLOCK");
1895 if (flags
& UFW_FLAG_VOCAB
) fprintf(stderr
, " VOCAB");
1896 if (flags
& UFW_FLAG_SCOLON
) fprintf(stderr
, " SCOLON");
1897 if (flags
& UFW_FLAG_PROTECTED
) fprintf(stderr
, " PROTECTED");
1898 fputc('\n', stderr
);
1900 if ((flags
& 0xff00U
) != 0) {
1901 fprintf(stderr
, " ARGS: ");
1902 switch (flags
& UFW_WARG_MASK
) {
1903 case UFW_WARG_NONE
: fprintf(stderr
, "NONE"); break;
1904 case UFW_WARG_BRANCH
: fprintf(stderr
, "BRANCH"); break;
1905 case UFW_WARG_LIT
: fprintf(stderr
, "LIT"); break;
1906 case UFW_WARG_C4STRZ
: fprintf(stderr
, "C4STRZ"); break;
1907 case UFW_WARG_CFA
: fprintf(stderr
, "CFA"); break;
1908 case UFW_WARG_CBLOCK
: fprintf(stderr
, "CBLOCK"); break;
1909 case UFW_WARG_VOCID
: fprintf(stderr
, "VOCID"); break;
1910 case UFW_WARG_C1STRZ
: fprintf(stderr
, "C1STRZ"); break;
1911 default: fprintf(stderr
, "wtf?!"); break;
1913 fputc('\n', stderr
);
1915 fprintf(stderr
, " BACKLEN: %u (nfa at 0x%08x)\n", ufoImgGetU8(cfa
- 1u), UFO_CFA_TO_NFA(cfa
));
1916 fprintf(stderr
, " NAME(%u): ", nlen
);
1917 for (uint32_t f
= 0; f
< nlen
; f
+= 1) {
1918 const uint8_t ch
= ufoImgGetU8(nfa
+ 4u + f
);
1919 if (ch
<= 32 || ch
>= 127) {
1920 fprintf(stderr
, "\\x%02x", ch
);
1922 fprintf(stderr
, "%c", (char)ch
);
1925 fprintf(stderr
, "\n");
1926 ufo_assert(UFO_CFA_TO_LFA(cfa
) == lfa
);
1931 //==========================================================================
1937 //==========================================================================
1938 static uint32_t ufoVocCheckName (uint32_t lfa
, const void *wname
, uint32_t wnlen
, uint32_t hash
,
1942 #ifdef UFO_DEBUG_FIND_WORD
1943 fprintf(stderr
, "CHECK-NAME: %.*s; LFA: 0x%08x; hash: 0x%08x (wname: 0x%08x)\n",
1944 (unsigned) wnlen
, (const char *)wname
,
1945 lfa
, (lfa
!= 0 ? ufoImgGetU32(UFO_LFA_TO_NHASH(lfa
)) : 0), hash
);
1946 ufoDumpWordHeader(lfa
);
1948 if (lfa
!= 0 && ufoImgGetU32(UFO_LFA_TO_NHASH(lfa
)) == hash
) {
1949 const uint32_t lenflags
= ufoImgGetU32(UFO_LFA_TO_NFA(lfa
));
1950 if ((lenflags
& UFW_FLAG_SMUDGE
) == 0 &&
1951 (allowvochid
|| (lenflags
& UFW_FLAG_HIDDEN
) == 0))
1953 const uint32_t nlen
= lenflags
&0xffU
;
1954 if (nlen
== wnlen
) {
1955 uint32_t naddr
= UFO_LFA_TO_NFA(lfa
) + 4u;
1957 while (pos
< nlen
) {
1958 uint8_t c0
= ((const unsigned char *)wname
)[pos
];
1959 if (c0
>= 'a' && c0
<= 'z') c0
= c0
- 'a' + 'A';
1960 uint8_t c1
= ufoImgGetU8(naddr
+ pos
);
1961 if (c1
>= 'a' && c1
<= 'z') c1
= c1
- 'a' + 'A';
1962 if (c0
!= c1
) break;
1968 res
= UFO_ALIGN4(naddr
);
1977 //==========================================================================
1983 //==========================================================================
1984 static uint32_t ufoFindWordInVoc (const void *wname
, uint32_t wnlen
, uint32_t hash
,
1985 uint32_t vocid
, int allowvochid
)
1988 if (wname
== NULL
) ufo_assert(wnlen
== 0);
1989 if (wnlen
!= 0 && vocid
!= 0) {
1990 if (hash
== 0) hash
= joaatHashBufCI(wname
, wnlen
);
1991 #if defined(UFO_DEBUG_FIND_WORD) || defined(UFO_DEBUG_FIND_WORD_IN_VOC)
1992 fprintf(stderr
, "IN-VOC: %.*s; VOCID: 0x%08x; whash: 0x%08x; htbl[0]: 0x%08x\n",
1993 (unsigned) wnlen
, (const char *)wname
,
1994 vocid
, hash
, ufoImgGetU32(vocid
+ UFW_VOCAB_OFS_HTABLE
));
1996 const uint32_t htbl
= vocid
+ UFW_VOCAB_OFS_HTABLE
;
1997 if (ufoImgGetU32(htbl
) != UFO_NO_HTABLE_FLAG
) {
1998 // hash table present, use it
1999 uint32_t bfa
= htbl
+ (hash
% (uint32_t)UFO_HASHTABLE_SIZE
) * 4u;
2000 bfa
= ufoImgGetU32(bfa
);
2001 while (res
== 0 && bfa
!= 0) {
2002 #if defined(UFO_DEBUG_FIND_WORD) || defined(UFO_DEBUG_FIND_WORD_IN_VOC)
2003 fprintf(stderr
, "IN-VOC: bfa: 0x%08x\n", bfa
);
2005 res
= ufoVocCheckName(UFO_BFA_TO_LFA(bfa
), wname
, wnlen
, hash
, allowvochid
);
2006 bfa
= ufoImgGetU32(bfa
);
2009 // no hash table, use linear search
2010 uint32_t lfa
= vocid
+ UFW_VOCAB_OFS_LATEST
;
2011 lfa
= ufoImgGetU32(lfa
);
2012 while (res
== 0 && lfa
!= 0) {
2013 res
= ufoVocCheckName(lfa
, wname
, wnlen
, hash
, allowvochid
);
2014 lfa
= ufoImgGetU32(lfa
);
2022 //==========================================================================
2026 // return part after the colon, or `NULL`
2028 //==========================================================================
2029 static const void *ufoFindColon (const void *wname
, uint32_t wnlen
) {
2030 const void *res
= NULL
;
2032 ufo_assert(wname
!= NULL
);
2033 const char *str
= (const char *)wname
;
2034 while (wnlen
!= 0 && str
[0] != ':') {
2035 str
+= 1; wnlen
-= 1;
2038 res
= (const void *)(str
+ 1); // skip colon
2045 //==========================================================================
2047 // ufoFindWordInVocAndParents
2049 //==========================================================================
2050 static uint32_t ufoFindWordInVocAndParents (const void *wname
, uint32_t wnlen
, uint32_t hash
,
2051 uint32_t vocid
, int allowvochid
)
2054 if (hash
== 0) hash
= joaatHashBufCI(wname
, wnlen
);
2055 while (res
== 0 && vocid
!= 0) {
2056 res
= ufoFindWordInVoc(wname
, wnlen
, hash
, vocid
, allowvochid
);
2057 vocid
= ufoImgGetU32(vocid
+ UFW_VOCAB_OFS_PARENT
);
2063 //==========================================================================
2065 // ufoFindWordNameRes
2067 // find with name resolution
2071 //==========================================================================
2072 static uint32_t ufoFindWordNameRes (const void *wname
, uint32_t wnlen
) {
2074 if (wnlen
!= 0 && *(const char *)wname
!= ':') {
2075 ufo_assert(wname
!= NULL
);
2077 const void *stx
= wname
;
2078 wname
= ufoFindColon(wname
, wnlen
);
2079 if (wname
!= NULL
) {
2080 // look in all vocabs (excluding hidden ones)
2081 uint32_t xlen
= (uint32_t)(ptrdiff_t)(wname
- stx
) - 1u;
2082 ufo_assert(xlen
> 0 && xlen
< 255);
2083 uint32_t xhash
= joaatHashBufCI(stx
, xlen
);
2084 uint32_t voclink
= ufoImgGetU32(ufoAddrVocLink
);
2085 #ifdef UFO_DEBUG_FIND_WORD_COLON
2086 fprintf(stderr
, "COLON-FIND: first voc: {%.*s}; xhash=0x%08x; voc-link: 0x%08x\n",
2087 (unsigned)xlen
, (const char *)stx
, xhash
, voclink
);
2089 while (res
== 0 && voclink
!= 0) {
2090 const uint32_t vhdraddr
= voclink
- UFW_VOCAB_OFS_VOCLINK
+ UFW_VOCAB_OFS_HEADER
;
2091 const uint32_t vhdr
= ufoImgGetU32(vhdraddr
);
2093 res
= ufoVocCheckName(UFO_NFA_TO_LFA(vhdr
), stx
, xlen
, xhash
, 0);
2095 if (res
== 0) voclink
= ufoImgGetU32(voclink
);
2098 uint32_t vocid
= voclink
- UFW_VOCAB_OFS_VOCLINK
;
2099 ufo_assert(voclink
!= 0);
2101 #ifdef UFO_DEBUG_FIND_WORD_COLON
2102 fprintf(stderr
, "searching {%.*s}(%u) in {%.*s}\n",
2103 (unsigned)wnlen
, wname
, wnlen
, (unsigned)xlen
, stx
);
2105 while (res
!= 0 && wname
!= NULL
) {
2107 wname
= ufoFindColon(wname
, wnlen
);
2108 if (wname
== NULL
) xlen
= wnlen
; else xlen
= (uint32_t)(ptrdiff_t)(wname
- stx
) - 1u;
2109 ufo_assert(xlen
> 0 && xlen
< 255);
2110 res
= ufoFindWordInVocAndParents(stx
, xlen
, 0, vocid
, 1);
2113 if (wname
!= NULL
) {
2114 // it should be a vocabulary
2115 const uint32_t nfa
= UFO_CFA_TO_NFA(res
);
2116 if ((ufoImgGetU32(nfa
) & UFW_FLAG_VOCAB
) != 0) {
2117 vocid
= ufoImgGetU32(UFO_CFA_TO_PFA(res
)); // pfa points to vocabulary
2132 //==========================================================================
2136 // doesn't look in CURRENT, does name resolution ("a:b" is word "b" in "a")
2140 //==========================================================================
2141 static uint32_t ufoFindWord (const char *wname
) {
2143 if (wname
&& wname
[0] != 0) {
2144 const size_t wnlen
= strlen(wname
);
2145 ufo_assert(wnlen
< 8192);
2146 uint32_t ctx
= ufoImgGetU32(ufoAddrContext
);
2147 const uint32_t hash
= joaatHashBufCI(wname
, (uint32_t)wnlen
);
2149 //fprintf(stderr, "FIND-WORD: whash: 0x%08x; name:{%s}\n", hash, wname);
2151 // first search in context
2152 res
= ufoFindWordInVocAndParents(wname
, (uint32_t)wnlen
, hash
, ctx
, (ctx
== ufoImgGetU32(ufoAddrCurrent
)));
2154 // now try vocabulary stack
2155 uint32_t vstp
= ufoVSP
;
2156 while (res
== 0 && vstp
!= 0) {
2158 ctx
= ufoVocStack
[vstp
];
2159 res
= ufoFindWordInVocAndParents(wname
, (uint32_t)wnlen
, hash
, ctx
, (ctx
== ufoImgGetU32(ufoAddrCurrent
)));
2162 // if not found, try name resolution
2163 if (res
== 0) res
= ufoFindWordNameRes(wname
, (uint32_t)wnlen
);
2170 //==========================================================================
2172 // ufoCreateWordHeader
2174 // create word header up to CFA, link to the current dictionary
2176 //==========================================================================
2177 static void ufoCreateWordHeader (const char *wname
, uint32_t flags
) {
2178 if (wname
== NULL
) wname
= "";
2179 const size_t wnlen
= strlen(wname
);
2180 ufo_assert(wnlen
< UFO_MAX_WORD_LENGTH
);
2181 const uint32_t hash
= joaatHashBufCI(wname
, (uint32_t)wnlen
);
2182 const uint32_t curr
= ufoImgGetU32(ufoAddrCurrent
);
2183 ufo_assert(curr
!= 0);
2185 if (wnlen
!= 0 && ufoImgGetU32(ufoAddrRedefineWarning
) != UFO_REDEF_WARN_DONT_CARE
) {
2186 const uint32_t cfa
= ufoFindWordInVoc(wname
, wnlen
, hash
, curr
, 1);
2188 const uint32_t nfa
= UFO_CFA_TO_NFA(cfa
);
2189 const uint32_t flags
= ufoImgGetU32(nfa
);
2190 if ((flags
& UFW_FLAG_PROTECTED
) != 0) {
2191 ufoFatal("trying to redefine protected word '%s'", wname
);
2192 } else if (ufoImgGetU32(ufoAddrRedefineWarning
) != UFO_REDEF_WARN_NONE
) {
2193 ufoWarning("redefining word '%s'", wname
);
2197 //fprintf(stderr, "000: HERE: 0x%08x\n", UFO_GET_DP());
2198 const uint32_t bkt
= (hash
% (uint32_t)UFO_HASHTABLE_SIZE
) * 4u;
2199 const uint32_t htbl
= curr
+ UFW_VOCAB_OFS_HTABLE
;
2201 ufoImgEmitU32(0); // dfa
2202 const uint32_t xfaAddr
= UFO_GET_DP();
2203 if ((xfaAddr
& UFO_ADDR_TEMP_BIT
) == 0) {
2204 // link previous yfa here
2205 const uint32_t lastxfa
= ufoImgGetU32(ufoAddrLastXFA
);
2206 // fix YFA of the previous word
2208 ufoImgPutU32(UFO_XFA_TO_YFA(lastxfa
), UFO_XFA_TO_YFA(xfaAddr
));
2210 // our XFA points to the previous XFA
2211 ufoImgEmitU32(lastxfa
); // xfa
2213 ufoImgPutU32(ufoAddrLastXFA
, xfaAddr
);
2215 ufoImgEmitU32(0); // xfa
2217 ufoImgEmitU32(0); // yfa
2218 // bucket link (bfa)
2219 if (wnlen
== 0 || ufoImgGetU32(htbl
) == UFO_NO_HTABLE_FLAG
) {
2222 #ifdef UFO_DEBUG_DUMP_NEW_HEADERS
2223 fprintf(stderr
, "NEW HEADER: %s; curr: 0x%08x; htbl: 0x%08x; bkt: 0x%08x\n",
2224 wname
, curr
, htbl
, bkt
);
2225 fprintf(stderr
, " [bkt]: 0x%08x; nbk: 0x%08x\n", ufoImgGetU32(htbl
+ bkt
), UFO_GET_DP());
2227 // bfa points to bfa
2228 const uint32_t bfa
= UFO_GET_DP();
2229 ufoImgEmitU32(ufoImgGetU32(htbl
+ bkt
));
2230 ufoImgPutU32(htbl
+ bkt
, bfa
);
2233 const uint32_t lfa
= UFO_GET_DP();
2234 ufoImgEmitU32(ufoImgGetU32(curr
+ UFW_VOCAB_OFS_LATEST
));
2236 ufoImgPutU32(curr
+ UFW_VOCAB_OFS_LATEST
, lfa
);
2238 ufoImgEmitU32(hash
);
2240 const uint32_t nfa
= UFO_GET_DP();
2241 ufoImgEmitU32(((uint32_t)wnlen
&0xffU
) | (flags
& 0xffffff00U
));
2242 const uint32_t nstart
= UFO_GET_DP();
2244 for (size_t f
= 0; f
< wnlen
; f
+= 1) {
2245 ufoImgEmitU8(((const unsigned char *)wname
)[f
]);
2247 while ((UFO_GET_DP() & 3) != 3) ufoImgEmitU8(0);
2248 const uint32_t nend
= UFO_GET_DP(); // length byte itself is not included
2249 // name length, again
2250 ufo_assert(nend
- nstart
<= 255);
2251 ufoImgEmitU8((uint8_t)(nend
- nstart
));
2252 ufo_assert((UFO_GET_DP() & 3) == 0);
2253 ufo_assert(UFO_CFA_TO_NFA(UFO_GET_DP()) == nfa
);
2254 if ((nend
& UFO_ADDR_SPECIAL_BITS_MASK
) == 0) ufoRecordDebug(nend
);
2255 #ifdef UFO_DEBUG_DUMP_NEW_HEADERS
2256 fprintf(stderr
, "*** NEW HEADER ***\n");
2257 fprintf(stderr
, "CFA: 0x%08x\n", UFO_GET_DP());
2258 fprintf(stderr
, "NSTART: 0x%08x\n", nstart
);
2259 fprintf(stderr
, "NEND: 0x%08x\n", nend
);
2260 fprintf(stderr
, "NLEN: %u (%u)\n", nend
- nstart
, ufoImgGetU8(UFO_GET_DP() - 1u));
2261 ufoDumpWordHeader(lfa
);
2264 fprintf(stderr
, "NEW WORD CFA 0x%08x: %s\n", UFO_GET_DP(), wname
);
2269 //==========================================================================
2273 //==========================================================================
2274 static void ufoDecompilePart (uint32_t addr
, uint32_t eaddr
, int indent
) {
2277 while (addr
< eaddr
) {
2278 uint32_t cfa
= ufoImgGetU32(addr
);
2279 for (int n
= 0; n
< indent
; n
+= 1) fputc(' ', fo
);
2280 fprintf(fo
, "%6u: 0x%08x: ", addr
, cfa
);
2281 uint32_t nfa
= UFO_CFA_TO_NFA(cfa
);
2282 uint32_t flags
= ufoImgGetU32(nfa
);
2283 //fprintf(fo, "[0x%08x] ", flags & UFW_WARG_MASK);
2284 uint32_t nlen
= flags
& 0xffU
;
2285 for (uint32_t f
= 0; f
< nlen
; f
+= 1) {
2286 const uint8_t ch
= ufoImgGetU8(nfa
+ 4u + f
);
2287 if (ch
<= 32 || ch
>= 127) {
2288 fprintf(fo
, "\\x%02x", ch
);
2290 fprintf(fo
, "%c", (char)ch
);
2294 switch (flags
& UFW_WARG_MASK
) {
2297 case UFW_WARG_BRANCH
:
2298 fprintf(fo
, " @%u", ufoImgGetU32(addr
)); addr
+= 4u;
2301 fprintf(fo
, " %u : %d : 0x%08x", ufoImgGetU32(addr
),
2302 (int32_t)ufoImgGetU32(addr
), ufoImgGetU32(addr
)); addr
+= 4u;
2304 case UFW_WARG_C4STRZ
:
2305 count
= ufoImgGetU32(addr
); addr
+= 4;
2307 fprintf(fo
, " str:");
2308 for (int f
= 0; f
< count
; f
+= 1) {
2309 const uint8_t ch
= ufoImgGetU8(addr
); addr
+= 1u;
2310 if (ch
<= 32 || ch
>= 127) {
2311 fprintf(fo
, "\\x%02x", ch
);
2313 fprintf(fo
, "%c", (char)ch
);
2316 addr
+= 1u; // skip zero byte
2317 addr
= UFO_ALIGN4(addr
);
2320 cfa
= ufoImgGetU32(addr
); addr
+= 4u;
2321 fprintf(fo
, " CFA:%u: ", cfa
);
2322 nfa
= UFO_CFA_TO_NFA(cfa
);
2323 nlen
= ufoImgGetU8(nfa
);
2324 for (uint32_t f
= 0; f
< nlen
; f
+= 1) {
2325 const uint8_t ch
= ufoImgGetU8(nfa
+ 4u + f
);
2326 if (ch
<= 32 || ch
>= 127) {
2327 fprintf(fo
, "\\x%02x", ch
);
2329 fprintf(fo
, "%c", (char)ch
);
2333 case UFW_WARG_CBLOCK
:
2334 fprintf(fo
, " CBLOCK:%u", ufoImgGetU32(addr
)); addr
+= 4u;
2336 case UFW_WARG_VOCID
:
2337 fprintf(fo
, " VOCID:%u", ufoImgGetU32(addr
)); addr
+= 4u;
2339 case UFW_WARG_C1STRZ
:
2340 count
= ufoImgGetU8(addr
); addr
+= 1;
2344 fprintf(fo, " ubyte:%u", ufoImgGetU8(addr)); addr += 1u;
2347 fprintf(fo, " sbyte:%u", ufoImgGetU8(addr)); addr += 1u;
2350 fprintf(fo, " uword:%u", ufoImgGetU16(addr)); addr += 2u;
2353 fprintf(fo, " sword:%u", ufoImgGetU16(addr)); addr += 2u;
2357 fprintf(fo
, " -- WTF?!\n");
2365 //==========================================================================
2369 //==========================================================================
2370 static void ufoDecompileWord (const uint32_t cfa
) {
2372 const uint32_t lfa
= UFO_CFA_TO_LFA(cfa
);
2373 fprintf(stdout
, "#### DECOMPILING CFA %u ###\n", cfa
);
2374 ufoDumpWordHeader(lfa
);
2375 const uint32_t yfa
= ufoGetWordEndAddr(cfa
);
2376 if (ufoImgGetU32(cfa
) == ufoDoForthCFA
) {
2377 fprintf(stdout
, "--- DECOMPILED CODE ---\n");
2378 ufoDecompilePart(UFO_CFA_TO_PFA(cfa
), yfa
, 0);
2379 fprintf(stdout
, "=======================\n");
2385 //==========================================================================
2387 // ufoBTShowWordName
2389 //==========================================================================
2390 static void ufoBTShowWordName (uint32_t nfa
) {
2392 uint32_t len
= ufoImgGetU8(nfa
); nfa
+= 4u;
2393 //fprintf(stderr, "(0x%08x)", ufoImgGetU32(nfa - 4u));
2395 uint8_t ch
= ufoImgGetU8(nfa
); nfa
+= 1u; len
-= 1u;
2396 if (ch
<= 32 || ch
>= 127) {
2397 fprintf(stderr
, "\\x%02x", ch
);
2399 fprintf(stderr
, "%c", (char)ch
);
2406 //==========================================================================
2410 //==========================================================================
2411 static void ufoBacktrace (uint32_t ip
) {
2412 // dump data stack (top 16)
2413 if (!ufoLastEmitWasCR
) { printf("\n"); ufoLastEmitWasCR
= 1; }
2416 fprintf(stderr
, "***UFO STACK DEPTH: %u\n", ufoSP
);
2417 uint32_t xsp
= ufoSP
;
2418 if (xsp
> 16) xsp
= 16;
2419 for (uint32_t sp
= 0; sp
< xsp
; ++sp
) {
2420 fprintf(stderr
, " %2u: 0x%08x %d\n", sp
,
2421 ufoDStack
[xsp
- sp
- 1], (int32_t)ufoDStack
[xsp
- sp
- 1]);
2423 if (ufoSP
> 16) fprintf(stderr
, " ...more...\n");
2425 // dump return stack (top 32)
2430 fprintf(stderr
, "***UFO RETURN STACK DEPTH: %u\n", ufoRP
);
2432 nfa
= ufoFindWordForIP(ip
);
2434 fprintf(stderr
, " **: %8u -- ", ip
);
2435 ufoBTShowWordName(nfa
);
2436 fname
= ufoFindFileForIP(ip
, &fline
);
2437 if (fname
!= NULL
) { fprintf(stderr
, " (at %s:%u)", fname
, fline
); }
2438 fputc('\n', stderr
);
2441 uint32_t rp
= ufoRP
;
2442 uint32_t rscount
= 0;
2443 if (rp
> UFO_RSTACK_SIZE
) rp
= UFO_RSTACK_SIZE
;
2444 while (rscount
!= 32 && rp
!= 0) {
2446 const uint32_t val
= ufoRStack
[rp
];
2447 nfa
= ufoFindWordForIP(val
);
2449 fprintf(stderr
, " %2u: %8u -- ", ufoRP
- rp
- 1u, val
);
2450 ufoBTShowWordName(nfa
);
2451 fname
= ufoFindFileForIP(val
- 4u, &fline
);
2452 if (fname
!= NULL
) { fprintf(stderr
, " (at %s:%u)", fname
, fline
); }
2453 fputc('\n', stderr
);
2455 fprintf(stderr
, " %2u: 0x%08x %d\n", ufoRP
- rp
- 1u, val
, (int32_t)val
);
2459 if (ufoRP
> 32) fprintf(stderr
, " ...more...\n");
2465 //==========================================================================
2469 //==========================================================================
2471 static void ufoDumpVocab (uint32_t vocid) {
2473 fprintf(stderr, "*** VOCID: 0x%08x ***\n", vocid);
2474 uint32_t vochdr = vocid + UFW_VOCAB_OFS_HEADER;
2475 vochdr = ufoImgGetU32(vochdr);
2477 fprintf(stderr, "--- HEADER ---\n");
2478 ufoDumpWordHeader(UFO_NFA_TO_LFA(vochdr));
2479 fprintf(stderr, "========\n");
2480 uint32_t htbl = vocid + UFW_VOCAB_OFS_HTABLE;
2481 if (ufoImgGetU32(htbl) != UFO_NO_HTABLE_FLAG) {
2482 fprintf(stderr, "--- HASH TABLE ---\n");
2483 for (int f = 0; f < UFO_HASHTABLE_SIZE; f += 1) {
2484 uint32_t bfa = ufoImgGetU32(htbl);
2486 fprintf(stderr, "**** %2d: 0x%08x\n", f, bfa);
2488 ufoDumpWordHeader(UFO_BFA_TO_LFA(bfa));
2489 bfa = ufoImgGetU32(bfa);
2501 // if set, this will be used when we are out of include files. intended for UrAsm.
2502 // return 0 if there is no more lines, otherwise the string should be copied
2503 // to buffer, `*fname` and `*fline` should be properly set.
2504 int (*ufoFileReadLine
) (void *buf
, size_t bufsize
, const char **fname
, int *fline
) = NULL
;
2507 //==========================================================================
2509 // ufoLoadNextUserLine
2511 //==========================================================================
2512 static int ufoLoadNextUserLine (void) {
2513 uint32_t tibPos
= 0;
2514 const char *fname
= NULL
;
2517 if (ufoFileReadLine
!= NULL
&& ufoFileReadLine(ufoCurrFileLine
, 510, &fname
, &fline
) != 0) {
2518 ufoCurrFileLine
[510] = 0;
2519 uint32_t slen
= (uint32_t)strlen(ufoCurrFileLine
);
2520 while (slen
!= 0 && (ufoCurrFileLine
[slen
- 1u] == 10 || ufoCurrFileLine
[slen
- 1u] == 13)) {
2523 if (tibPos
+ slen
+ 1u > UFO_ADDR_HANDLE_OFS_MASK
) {
2524 ufoFatal("input text line too long (at least %u bytes)", tibPos
+ slen
);
2526 ufoTibEnsureSize(tibPos
+ slen
+ 1u);
2527 for (uint32_t f
= 0; f
< slen
; f
+= 1) {
2528 ufoTibPokeChOfs(((const unsigned char *)ufoCurrFileLine
)[f
], tibPos
+ f
);
2530 ufoTibPokeChOfs(0, tibPos
+ slen
);
2532 if (fname
== NULL
) fname
= "<user>";
2533 if (ufoInFileName
== NULL
|| strcmp(ufoInFileName
, fname
) != 0) {
2534 free(ufoInFileName
);
2535 ufoInFileName
= strdup(fname
);
2536 if (ufoInFileName
== NULL
) ufoFatal("out of memory");
2538 ufoInFileLine
= fline
;
2546 //==========================================================================
2548 // ufoLoadNextLine_NativeMode
2550 // load next file line into TIB
2551 // always strips final '\n'
2553 // return 0 on EOF, 1 on success
2555 //==========================================================================
2556 static int ufoLoadNextLine (int crossInclude
) {
2558 uint32_t tibPos
= 0;
2561 if (ufoMode
== UFO_MODE_MACRO
) {
2562 //fprintf(stderr, "***MAC!\n");
2566 while (ufoInFile
!= NULL
&& !done
) {
2567 if (fgets(ufoCurrFileLine
, 510, ufoInFile
) != NULL
) {
2568 // check for a newline
2569 // if there is no newline char at the end, the string was truncated
2570 ufoCurrFileLine
[510] = 0;
2571 const uint32_t slen
= (uint32_t)strlen(ufoCurrFileLine
);
2572 if (tibPos
+ slen
+ 1u > UFO_ADDR_HANDLE_OFS_MASK
) {
2573 ufoFatal("input text line too long (at least %u bytes)", tibPos
+ slen
);
2575 ufoTibEnsureSize(tibPos
+ slen
+ 1u);
2576 for (uint32_t f
= 0; f
< slen
; f
+= 1) {
2577 ufoTibPokeChOfs(((const unsigned char *)ufoCurrFileLine
)[f
], tibPos
+ f
);
2579 ufoTibPokeChOfs(0, tibPos
+ slen
);
2581 if (slen
!= 0 && (ufoCurrFileLine
[slen
- 1u] == 13 || ufoCurrFileLine
[slen
- 1u] == 10)) {
2585 // continuation, nothing to do
2588 // if we read nothing, this is EOF
2589 if (tibPos
== 0 && crossInclude
) {
2590 // we read nothing, and allowed to cross include boundaries
2599 // eof, try user-supplied input
2600 if (ufoFileStackPos
== 0) {
2601 return ufoLoadNextUserLine();
2606 // if we read at least something, this is not EOF
2612 // ////////////////////////////////////////////////////////////////////////// //
2617 UFWORD(DUMP_STACK
) {
2618 if (!ufoLastEmitWasCR
) { printf("\n"); ufoLastEmitWasCR
= 1; }
2619 printf("***UFO STACK DEPTH: %u\n", ufoSP
);
2621 uint32_t sp
= ufoSP
;
2622 while (sp
!= 0 && left
!= 0) {
2624 printf(" %4u: 0x%08x %d\n", sp
, ufoDStack
[sp
], (int32_t)ufoDStack
[sp
]);
2626 if (sp
!= 0) printf("...more...\n");
2627 ufoLastEmitWasCR
= 1;
2631 UFWORD(UFO_BACKTRACE
) {
2632 if (!ufoLastEmitWasCR
) { printf("\n"); ufoLastEmitWasCR
= 1; }
2634 if (ufoInFile
!= NULL
) {
2635 fprintf(stderr
, "*** at file %s, line %d ***\n", ufoInFileName
, ufoInFileLine
);
2637 fprintf(stderr
, "*** somewhere in time ***\n");
2639 ufoBacktrace(ufoIP
);
2643 // ////////////////////////////////////////////////////////////////////////// //
2646 UFWORD(SP0_STORE
) { ufoSP
= 0; }
2651 if (ufoRP
!= ufoRPTop
) {
2653 // we need to push a dummy value
2654 ufoRPush(0xdeadf00d);
2660 // PAD is at the beginning of temp area
2662 ufoPush(UFO_PAD_ADDR
);
2666 // ////////////////////////////////////////////////////////////////////////// //
2667 // peeks and pokes with address register
2678 UFWORD(REGA_STORE
) {
2686 const uint32_t newa
= ufoPop();
2692 // ////////////////////////////////////////////////////////////////////////// //
2693 // useful to work with handles and normal addreses uniformly
2698 UFWORD(CPEEK_REGA_IDX
) {
2699 if ((ufoRegA
& UFO_ADDR_HANDLE_BIT
) == 0) {
2700 const uint32_t idx
= ufoPop();
2701 const uint32_t newaddr
= ufoRegA
+ idx
;
2702 if ((ufoRegA
& UFO_ADDR_SPECIAL_BITS_MASK
) == (newaddr
& UFO_ADDR_SPECIAL_BITS_MASK
)) {
2703 ufoPush(ufoImgGetU8Ext(newaddr
));
2705 ufoFatal("address offset out of range; addr=0x%08x; offset=%u; res=0x%08x",
2706 ufoRegA
, idx
, newaddr
);
2710 UFCALL(PAR_HANDLE_LOAD_BYTE
);
2716 UFWORD(WPEEK_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 ufoPush(ufoImgGetU16(newaddr
));
2725 ufoFatal("address offset out of range; addr=0x%08x; offset=%u; res=0x%08x",
2726 ufoRegA
, idx
, newaddr
);
2730 UFCALL(PAR_HANDLE_LOAD_WORD
);
2736 UFWORD(PEEK_REGA_IDX
) {
2737 if ((ufoRegA
& UFO_ADDR_HANDLE_BIT
) == 0) {
2738 const uint32_t idx
= ufoPop();
2739 const uint32_t newaddr
= ufoRegA
+ idx
;
2740 if ((ufoRegA
& UFO_ADDR_SPECIAL_BITS_MASK
) == (newaddr
& UFO_ADDR_SPECIAL_BITS_MASK
) &&
2741 (ufoRegA
& UFO_ADDR_SPECIAL_BITS_MASK
) == ((newaddr
+ 3u) & UFO_ADDR_SPECIAL_BITS_MASK
))
2743 ufoPush(ufoImgGetU32(newaddr
));
2745 ufoFatal("address offset out of range; addr=0x%08x; offset=%u; res=0x%08x",
2746 ufoRegA
, idx
, newaddr
);
2750 UFCALL(PAR_HANDLE_LOAD_CELL
);
2756 UFWORD(CPOKE_REGA_IDX
) {
2757 if ((ufoRegA
& UFO_ADDR_HANDLE_BIT
) == 0) {
2758 const uint32_t idx
= ufoPop();
2759 const uint32_t newaddr
= ufoRegA
+ idx
;
2760 if ((ufoRegA
& UFO_ADDR_SPECIAL_BITS_MASK
) == (newaddr
& UFO_ADDR_SPECIAL_BITS_MASK
)) {
2761 const uint32_t value
= ufoPop();
2762 ufoImgPutU8(newaddr
, value
);
2764 ufoFatal("address offset out of range; addr=0x%08x; offset=%u; res=0x%08x",
2765 ufoRegA
, idx
, newaddr
);
2769 UFCALL(PAR_HANDLE_STORE_BYTE
);
2775 UFWORD(WPOKE_REGA_IDX
) {
2776 if ((ufoRegA
& UFO_ADDR_HANDLE_BIT
) == 0) {
2777 const uint32_t idx
= ufoPop();
2778 const uint32_t newaddr
= ufoRegA
+ idx
;
2779 if ((ufoRegA
& UFO_ADDR_SPECIAL_BITS_MASK
) == (newaddr
& UFO_ADDR_SPECIAL_BITS_MASK
) &&
2780 (ufoRegA
& UFO_ADDR_SPECIAL_BITS_MASK
) == ((newaddr
+ 1u) & UFO_ADDR_SPECIAL_BITS_MASK
))
2782 const uint32_t value
= ufoPop();
2783 ufoImgPutU16(newaddr
, value
);
2785 ufoFatal("address offset out of range; addr=0x%08x; offset=%u; res=0x%08x",
2786 ufoRegA
, idx
, newaddr
);
2790 UFCALL(PAR_HANDLE_STORE_WORD
);
2796 UFWORD(POKE_REGA_IDX
) {
2797 if ((ufoRegA
& UFO_ADDR_HANDLE_BIT
) == 0) {
2798 const uint32_t idx
= ufoPop();
2799 const uint32_t newaddr
= ufoRegA
+ idx
;
2800 if ((ufoRegA
& UFO_ADDR_SPECIAL_BITS_MASK
) == (newaddr
& UFO_ADDR_SPECIAL_BITS_MASK
) &&
2801 (ufoRegA
& UFO_ADDR_SPECIAL_BITS_MASK
) == ((newaddr
+ 3u) & UFO_ADDR_SPECIAL_BITS_MASK
))
2803 const uint32_t value
= ufoPop();
2804 ufoImgPutU32(newaddr
, value
);
2806 ufoFatal("address offset out of range; addr=0x%08x; offset=%u; res=0x%08x",
2807 ufoRegA
, idx
, newaddr
);
2811 UFCALL(PAR_HANDLE_STORE_CELL
);
2816 // ////////////////////////////////////////////////////////////////////////// //
2821 // ( addr -- value8 )
2823 ufoPush(ufoImgGetU8Ext(ufoPop()));
2827 // ( addr -- value16 )
2829 const uint32_t addr
= ufoPop();
2830 if ((addr
& UFO_ADDR_HANDLE_BIT
) == 0) {
2831 ufoPush(ufoImgGetU16(addr
));
2835 UFCALL(PAR_HANDLE_LOAD_WORD
);
2840 // ( addr -- value32 )
2842 const uint32_t addr
= ufoPop();
2843 if ((addr
& UFO_ADDR_HANDLE_BIT
) == 0) {
2844 ufoPush(ufoImgGetU32(addr
));
2848 UFCALL(PAR_HANDLE_LOAD_CELL
);
2855 const uint32_t addr
= ufoPop();
2856 const uint32_t val
= ufoPop();
2857 ufoImgPutU8Ext(addr
, val
);
2861 // ( val16 addr -- )
2863 const uint32_t addr
= ufoPop();
2864 const uint32_t val
= ufoPop();
2865 if ((addr
& UFO_ADDR_HANDLE_BIT
) == 0) {
2866 ufoImgPutU16(addr
, val
);
2871 UFCALL(PAR_HANDLE_STORE_WORD
);
2876 // ( val32 addr -- )
2878 const uint32_t addr
= ufoPop();
2879 const uint32_t val
= ufoPop();
2880 if ((addr
& UFO_ADDR_HANDLE_BIT
) == 0) {
2881 ufoImgPutU32(addr
, val
);
2886 UFCALL(PAR_HANDLE_STORE_CELL
);
2891 // ////////////////////////////////////////////////////////////////////////// //
2892 // dictionary emitters
2897 UFWORD(CCOMMA
) { const uint32_t val
= ufoPop(); ufoImgEmitU8(val
); }
2901 UFWORD(WCOMMA
) { const uint32_t val
= ufoPop(); ufoImgEmitU8(val
&0xffU
); ufoImgEmitU8((val
>> 8)&0xffU
); }
2905 UFWORD(COMMA
) { const uint32_t val
= ufoPop(); ufoImgEmitU32(val
); }
2908 // ////////////////////////////////////////////////////////////////////////// //
2915 const uint32_t v
= ufoImgGetU32(ufoIP
); ufoIP
+= 4;
2919 // (LITCFA) ( -- n )
2920 UFWORD(PAR_LITCFA
) {
2921 const uint32_t v
= ufoImgGetU32(ufoIP
); ufoIP
+= 4;
2925 // (LITVOCID) ( -- n )
2926 UFWORD(PAR_LITVOCID
) {
2927 const uint32_t v
= ufoImgGetU32(ufoIP
); ufoIP
+= 4;
2932 UFWORD(PAR_STRLIT8
) {
2933 const uint32_t count
= ufoImgGetU8(ufoIP
); ufoIP
+= 1;
2936 ufoIP
+= count
+ 1; // 1 for terminating 0
2938 ufoIP
= UFO_ALIGN4(ufoIP
);
2942 // ////////////////////////////////////////////////////////////////////////// //
2948 UFWORD(PAR_BRANCH
) {
2949 ufoIP
= ufoImgGetU32(ufoIP
);
2952 // (TBRANCH) ( flag )
2953 UFWORD(PAR_TBRANCH
) {
2955 ufoIP
= ufoImgGetU32(ufoIP
);
2961 // (0BRANCH) ( flag )
2962 UFWORD(PAR_0BRANCH
) {
2964 ufoIP
= ufoImgGetU32(ufoIP
);
2971 // ////////////////////////////////////////////////////////////////////////// //
2972 // execute words by CFA
2982 // EXECUTE-TAIL ( cfa )
2983 UFWORD(EXECUTE_TAIL
) {
2990 // ////////////////////////////////////////////////////////////////////////// //
2991 // word termination, locals support
3002 UFWORD(PAR_LENTER
) {
3003 // low byte of loccount is total number of locals
3004 // high byte is the number of args
3005 uint32_t lcount
= ufoImgGetU32(ufoIP
); ufoIP
+= 4u;
3006 uint32_t acount
= (lcount
>> 8) & 0xff;
3008 if (lcount
== 0 || lcount
< acount
) ufoFatal("invalid call to (L-ENTER)");
3009 if ((ufoLBP
!= 0 && ufoLBP
>= ufoLP
) || UFO_LSTACK_SIZE
- ufoLP
<= lcount
+ 2) {
3010 ufoFatal("out of locals stack");
3013 if (ufoLP
== 0) { ufoLP
= 1; newbp
= 1; } else newbp
= ufoLP
;
3014 //fprintf(stderr, "LP: %u; LBP: %u; locs: %u; word: %s\n", ufoLP, ufoLBP, fw->locs, fw->name);
3015 ufoLStack
[ufoLP
] = ufoLBP
; ufoLP
+= 1;
3016 ufoLBP
= newbp
; ufoLP
+= lcount
;
3019 while (newbp
!= ufoLBP
) {
3020 ufoLStack
[newbp
] = ufoPop();
3026 UFWORD(PAR_LLEAVE
) {
3027 if (ufoLBP
== 0) ufoFatal("(L-LEAVE) with empty locals stack");
3028 if (ufoLBP
>= ufoLP
) ufoFatal("(L-LEAVE) broken locals stack");
3030 ufoLBP
= ufoLStack
[ufoLBP
];
3034 //==========================================================================
3038 //==========================================================================
3039 UFO_FORCE_INLINE
void ufoLoadLocal (const uint32_t lidx
) {
3040 if (lidx
== 0 || lidx
>= UFO_LSTACK_SIZE
) ufoFatal("invalid local index");
3041 if (ufoLBP
== 0 || ufoLBP
>= ufoLP
|| ufoLP
- ufoLBP
<= lidx
) ufoFatal("invalid local index");
3042 ufoPush(ufoLStack
[ufoLBP
+ lidx
]);
3046 //==========================================================================
3050 //==========================================================================
3051 UFO_FORCE_INLINE
void ufoStoreLocal (const uint32_t lidx
) {
3052 const uint32_t value
= ufoPop();
3053 if (lidx
== 0 || lidx
>= UFO_LSTACK_SIZE
) ufoFatal("invalid local index");
3054 if (ufoLBP
== 0 || ufoLBP
>= ufoLP
|| ufoLP
- ufoLBP
<= lidx
) ufoFatal("invalid local index");
3055 ufoLStack
[ufoLBP
+ lidx
] = value
;
3061 UFWORD(PAR_LOCAL_LOAD
) { ufoLoadLocal(ufoPop()); }
3065 UFWORD(PAR_LOCAL_STORE
) { ufoStoreLocal(ufoPop()); }
3068 // ////////////////////////////////////////////////////////////////////////// //
3069 // stack manipulation
3075 UFWORD(DUP
) { ufoDup(); }
3077 // ( n -- n n ) | ( 0 -- 0 )
3078 UFWORD(QDUP
) { if (ufoPeek()) ufoDup(); }
3080 // ( n0 n1 -- n0 n1 n0 n1 )
3081 UFWORD(DDUP
) { ufo2Dup(); }
3084 UFWORD(DROP
) { ufoDrop(); }
3087 UFWORD(DDROP
) { ufo2Drop(); }
3089 // ( n0 n1 -- n1 n0 )
3090 UFWORD(SWAP
) { ufoSwap(); }
3092 // ( n0 n1 -- n1 n0 )
3093 UFWORD(DSWAP
) { ufo2Swap(); }
3095 // ( n0 n1 -- n0 n1 n0 )
3096 UFWORD(OVER
) { ufoOver(); }
3098 // ( n0 n1 -- n0 n1 n0 )
3099 UFWORD(DOVER
) { ufo2Over(); }
3101 // ( n0 n1 n2 -- n1 n2 n0 )
3102 UFWORD(ROT
) { ufoRot(); }
3104 // ( n0 n1 n2 -- n2 n0 n1 )
3105 UFWORD(NROT
) { ufoNRot(); }
3109 UFWORD(RDUP
) { ufoRDup(); }
3112 UFWORD(RDROP
) { ufoRDrop(); }
3116 UFWORD(DTOR
) { ufoRPush(ufoPop()); }
3119 UFWORD(RTOD
) { ufoPush(ufoRPop()); }
3122 UFWORD(RPEEK
) { ufoPush(ufoRPeek()); }
3128 const uint32_t n
= ufoPop();
3129 if (n
>= ufoSP
) ufoFatal("invalid PICK index %u", n
);
3130 ufoPush(ufoDStack
[ufoSP
- n
- 1u]);
3136 const uint32_t n
= ufoPop();
3137 if (n
>= ufoRP
- ufoRPTop
) ufoFatal("invalid RPICK index %u", n
);
3138 const uint32_t rp
= ufoRP
- n
- 1u;
3139 ufoPush(ufoRStack
[rp
]);
3145 const uint32_t n
= ufoPop();
3146 if (n
>= ufoSP
) ufoFatal("invalid ROLL index %u", n
);
3148 case 0: break; // do nothing
3149 case 1: ufoSwap(); break;
3150 case 2: ufoRot(); break;
3153 const uint32_t val
= ufoDStack
[ufoSP
- n
- 1u];
3154 for (uint32_t f
= ufoSP
- n
; f
< ufoSP
; f
+= 1) ufoDStack
[f
- 1] = ufoDStack
[f
];
3155 ufoDStack
[ufoSP
- 1u] = val
;
3164 const uint32_t n
= ufoPop();
3165 if (n
>= ufoRP
- ufoRPTop
) ufoFatal("invalid RROLL index %u", n
);
3167 const uint32_t rp
= ufoRP
- n
- 1u;
3168 const uint32_t val
= ufoRStack
[rp
];
3169 for (uint32_t f
= rp
+ 1u; f
< ufoRP
; f
+= 1u) ufoRStack
[f
- 1u] = ufoRStack
[f
];
3170 ufoRStack
[ufoRP
- 1u] = val
;
3175 // ( | a b -- | b a )
3177 const uint32_t b
= ufoRPop();
3178 const uint32_t a
= ufoRPop();
3179 ufoRPush(b
); ufoRPush(a
);
3183 // ( | a b -- | a b a )
3185 const uint32_t b
= ufoRPop();
3186 const uint32_t a
= ufoRPop();
3187 ufoRPush(a
); ufoRPush(b
); ufoRPush(a
);
3191 // ( | a b c -- | b c a )
3193 const uint32_t c
= ufoRPop();
3194 const uint32_t b
= ufoRPop();
3195 const uint32_t a
= ufoRPop();
3196 ufoRPush(b
); ufoRPush(c
); ufoRPush(a
);
3200 // ( | a b c -- | c a b )
3202 const uint32_t c
= ufoRPop();
3203 const uint32_t b
= ufoRPop();
3204 const uint32_t a
= ufoRPop();
3205 ufoRPush(c
); ufoRPush(a
); ufoRPush(b
);
3209 // ////////////////////////////////////////////////////////////////////////// //
3216 ufoPushBool(ufoLoadNextLine(1));
3221 UFWORD(REFILL_NOCROSS
) {
3222 ufoPushBool(ufoLoadNextLine(0));
3228 ufoPush(ufoImgGetU32(ufoAddrTIBx
) + ufoImgGetU32(ufoAddrINx
));
3233 UFWORD(TIB_PEEKCH
) {
3234 ufoPush(ufoTibPeekCh());
3239 UFWORD(TIB_PEEKCH_OFS
) {
3240 const uint32_t ofs
= ufoPop();
3241 ufoPush(ufoTibPeekChOfs(ofs
));
3247 ufoPush(ufoTibGetCh());
3252 UFWORD(TIB_SKIPCH
) {
3257 // ////////////////////////////////////////////////////////////////////////// //
3261 //==========================================================================
3265 //==========================================================================
3266 UFO_FORCE_INLINE
int ufoIsDelim (uint8_t ch
, uint8_t delim
) {
3267 return (delim
== 32 ? (ch
<= 32) : (ch
== delim
));
3272 // ( delim skip-leading-delim? -- addr count TRUE / FALSE )
3273 // does base TIB parsing; never copies anything.
3274 // as our reader is line-based, returns FALSE on EOL.
3275 // EOL is detected after skipping leading delimiters.
3276 // passing -1 as delimiter skips the whole line, and always returns FALSE.
3277 // trailing delimiter is always skipped.
3279 const uint32_t skipDelim
= ufoPop();
3280 const uint32_t delim
= ufoPop();
3283 if (delim
== 0 || delim
> 0xffU
) {
3285 while (ufoTibGetCh() != 0) {}
3288 ch
= ufoTibPeekCh();
3289 // skip initial delimiters
3291 while (ch
!= 0 && ufoIsDelim(ch
, delim
)) {
3293 ch
= ufoTibPeekCh();
3300 const uint32_t staddr
= ufoImgGetU32(ufoAddrTIBx
) + ufoImgGetU32(ufoAddrINx
);
3302 while (ch
!= 0 && !ufoIsDelim(ch
, delim
)) {
3305 ch
= ufoTibPeekCh();
3308 if (ch
!= 0) ufoTibSkipCh();
3316 // PARSE-SKIP-BLANKS
3318 UFWORD(PARSE_SKIP_BLANKS
) {
3319 uint8_t ch
= ufoTibPeekCh();
3320 while (ch
!= 0 && ch
<= 32) {
3322 ch
= ufoTibPeekCh();
3327 //==========================================================================
3329 // ufoParseMLComment
3331 // initial two chars are skipped
3333 //==========================================================================
3334 static void ufoParseMLComment (uint32_t allowMulti
, int nested
) {
3337 while (level
!= 0) {
3341 UFCALL(REFILL_NOCROSS
);
3342 if (ufoPop() == 0) ufoFatal("unexpected end of file in comment");
3344 ufoFatal("unexpected end of line in comment");
3347 ch1
= ufoTibPeekCh();
3348 if (nested
&& ch
== '(' && ch1
== '(') { ufoTibSkipCh(); level
+= 1; }
3349 else if (nested
&& ch
== ')' && ch1
== ')') { ufoTibSkipCh(); level
-= 1; }
3350 else if (!nested
&& ch
== '*' && ch1
== ')') { ufo_assert(level
== 1); ufoTibSkipCh(); level
= 0; }
3356 // (PARSE-SKIP-COMMENTS)
3357 // ( allow-multiline? -- )
3358 // skip all blanks and comments
3359 UFWORD(PAR_PARSE_SKIP_COMMENTS
) {
3360 const uint32_t allowMulti
= ufoPop();
3362 ch
= ufoTibPeekCh();
3364 fprintf(stderr
, "(PARSE-SKIP-COMMENTS): first-ch:'%c'\n", (char)ch
);
3369 ch
= ufoTibPeekCh();
3371 fprintf(stderr
, "(PARSE-SKIP-COMMENTS): blank-ch:'%c'\n", (char)ch
);
3373 } else if (ch
== '(') {
3375 fprintf(stderr
, "(PARSE-SKIP-COMMENTS): ch:'%c'; ch1:'%c' ('%c')\n", (char)ch
, (char)ch1
,
3376 ufoTibPeekChOfs(0));
3378 ch1
= ufoTibPeekChOfs(1);
3380 // single-line comment
3381 do { ch
= ufoTibGetCh(); } while (ch
!= 0 && ch
!= ')');
3382 ch
= ufoTibPeekCh();
3383 } else if (ch1
== '*' || ch1
== '(') {
3384 // possibly multiline
3385 ufoTibSkipCh(); ufoTibSkipCh(); // skip opening
3386 ufoParseMLComment(allowMulti
, (ch1
== '('));
3387 ch
= ufoTibPeekCh();
3391 } else if (ch
== '\\' && ufoTibPeekChOfs(1) <= 32) {
3392 // single-line comment
3393 while (ch
!= 0) ch
= ufoTibGetCh();
3394 } else if ((ch
== ';' || ch
== '-' || ch
== '/') && (ufoTibPeekChOfs(1) == ch
)) {
3396 while (ch
!= 0) ch
= ufoTibGetCh();
3402 fprintf(stderr
, "(PARSE-SKIP-COMMENTS): end-ch:'%c'\n", ufoTibPeekCh());
3408 UFWORD(PARSE_SKIP_LINE
) {
3409 ufoPush(0); ufoPushBool(0); UFCALL(PAR_PARSE
);
3410 if (ufoPop() != 0) {
3416 // ( -- addr count )
3417 // parse with leading blanks skipping. doesn't copy anything.
3418 // return empty string on EOL.
3419 UFWORD(PARSE_NAME
) {
3420 ufoPush(32); ufoPushBool(1); UFCALL(PAR_PARSE
);
3421 if (ufoPop() == 0) {
3428 // ( delim -- addr count TRUE / FALSE )
3429 // parse without skipping delimiters; never copies anything.
3430 // as our reader is line-based, returns FALSE on EOL.
3431 // passing 0 as delimiter skips the whole line, and always returns FALSE.
3432 // trailing delimiter is always skipped.
3434 ufoPushBool(0); UFCALL(PAR_PARSE
);
3438 // ( delim skip-leading-delim? -- here TRUE / FALSE )
3439 // parse word, copy it to HERE as counted string.
3440 // adds trailing zero after the string, but doesn't include it in count.
3441 // doesn't advance line.
3444 // ( delim -- here )
3445 // parse word, copy it to HERE as counted string.
3446 // adds trailing zero after the string, but doesn't include it in count.
3447 // doesn't advance line.
3448 // return empty string on EOL.
3451 // ( delim -- addr count TRUE / FALSE )
3452 // parse word w/o skipping delimiters, copy it to HERE as counted string.
3453 // adds trailing zero after the string, but doesn't include it in count.
3454 // doesn't advance line.
3457 // ////////////////////////////////////////////////////////////////////////// //
3464 uint32_t ch
= ufoPop()&0xffU
;
3465 ufoLastEmitWasCR
= (ch
== 10);
3472 uint32_t ch
= ufoPop()&0xffU
;
3473 if (ch
< 32 || ch
== 127) {
3474 if (ch
!= 9 && ch
!= 10 && ch
!= 13) ch
= '?';
3476 ufoLastEmitWasCR
= (ch
== 10);
3483 uint32_t ch
= ufoPop()&0xffU
;
3484 putchar(ch
< 32 || ch
== 127 ? '?' : (char)ch
);
3485 ufoLastEmitWasCR
= 0;
3491 ufoPushBool(ufoLastEmitWasCR
);
3497 ufoLastEmitWasCR
= !!ufoPop();
3504 ufoLastEmitWasCR
= 1;
3511 ufoLastEmitWasCR
= 0;
3518 int32_t n
= (int32_t)ufoPop();
3520 memset(tmpbuf
, 32, sizeof(tmpbuf
));
3523 if (xwr
> (int32_t)sizeof(tmpbuf
) - 1) xwr
= (int32_t)sizeof(tmpbuf
) - 1;
3525 printf("%s", tmpbuf
);
3528 ufoLastEmitWasCR
= 0;
3535 if (ufoLastEmitWasCR
== 0) {
3537 ufoLastEmitWasCR
= 1;
3542 // ( addr count -- )
3544 int32_t count
= (int32_t)ufoPop();
3545 uint32_t addr
= ufoPop();
3547 const uint8_t ch
= ufoImgGetU8Ext(addr
);
3550 addr
+= 1; count
-= 1;
3555 // ( addr count -- )
3557 int32_t count
= (int32_t)ufoPop();
3558 uint32_t addr
= ufoPop();
3560 const uint8_t ch
= ufoImgGetU8Ext(addr
);
3563 addr
+= 1; count
-= 1;
3569 UFWORD(FLUSH_EMIT
) {
3574 // ////////////////////////////////////////////////////////////////////////// //
3578 #define UF_UMATH(name_,op_) \
3580 const uint32_t a = ufoPop(); \
3584 #define UF_BMATH(name_,op_) \
3586 const uint32_t b = ufoPop(); \
3587 const uint32_t a = ufoPop(); \
3591 #define UF_BDIV(name_,op_) \
3593 const uint32_t b = ufoPop(); \
3594 const uint32_t a = ufoPop(); \
3595 if (b == 0) ufoFatal("division by zero"); \
3599 #define UFO_POP_U64() ({ \
3600 const uint32_t hi_ = ufoPop(); \
3601 const uint32_t lo_ = ufoPop(); \
3602 (((uint64_t)hi_ << 32) | lo_); \
3605 // this is UB by the idiotic C standard. i don't care.
3606 #define UFO_POP_I64() ((int64_t)UFO_POP_U64())
3608 #define UFO_PUSH_U64(vn_) do { \
3609 ufoPush((uint32_t)(vn_)); \
3610 ufoPush((uint32_t)((vn_) >> 32)); \
3613 // this is UB by the idiotic C standard. i don't care.
3614 #define UFO_PUSH_I64(vn_) UFO_PUSH_U64((uint64_t)(vn_))
3619 UF_BMATH(PLUS
, a
+ b
);
3623 UF_BMATH(MINUS
, a
- b
);
3627 UF_BMATH(MUL
, (uint32_t)((int32_t)a
* (int32_t)b
));
3631 UF_BMATH(UMUL
, a
* b
);
3635 UF_BDIV(DIV
, (uint32_t)((int32_t)a
/ (int32_t)b
));
3639 UF_BDIV(UDIV
, a
/ b
);
3643 UF_BDIV(MOD
, (uint32_t)((int32_t)a
% (int32_t)b
));
3647 UF_BDIV(UMOD
, a
% b
);
3650 // ( a b -- a/b, a%b )
3652 const int32_t b
= (int32_t)ufoPop();
3653 const int32_t a
= (int32_t)ufoPop();
3654 if (b
== 0) ufoFatal("division by zero");
3655 ufoPush((uint32_t)(a
/b
));
3656 ufoPush((uint32_t)(a
%b
));
3660 // ( a b -- a/b, a%b )
3662 const uint32_t b
= ufoPop();
3663 const uint32_t a
= ufoPop();
3664 if (b
== 0) ufoFatal("division by zero");
3665 ufoPush((uint32_t)(a
/b
));
3666 ufoPush((uint32_t)(a
%b
));
3670 // ( a b c -- a*b/c )
3671 // this uses 64-bit intermediate value
3673 const int32_t c
= (int32_t)ufoPop();
3674 const int32_t b
= (int32_t)ufoPop();
3675 const int32_t a
= (int32_t)ufoPop();
3676 if (c
== 0) ufoFatal("division by zero");
3677 int64_t xval
= a
; xval
*= b
; xval
/= c
;
3678 ufoPush((uint32_t)(int32_t)xval
);
3682 // ( a b c -- a*b/c )
3683 // this uses 64-bit intermediate value
3685 const uint32_t c
= ufoPop();
3686 const uint32_t b
= ufoPop();
3687 const uint32_t a
= ufoPop();
3688 if (c
== 0) ufoFatal("division by zero");
3689 uint64_t xval
= a
; xval
*= b
; xval
/= c
;
3690 ufoPush((uint32_t)xval
);
3694 // ( a b c -- a*b/c a*b%c )
3695 // this uses 64-bit intermediate value
3697 const int32_t c
= (int32_t)ufoPop();
3698 const int32_t b
= (int32_t)ufoPop();
3699 const int32_t a
= (int32_t)ufoPop();
3700 if (c
== 0) ufoFatal("division by zero");
3701 int64_t xval
= a
; xval
*= b
;
3702 ufoPush((uint32_t)(int32_t)(xval
/ c
));
3703 ufoPush((uint32_t)(int32_t)(xval
% c
));
3707 // ( a b c -- a*b/c )
3708 // this uses 64-bit intermediate value
3709 UFWORD(UMULDIVMOD
) {
3710 const uint32_t c
= ufoPop();
3711 const uint32_t b
= ufoPop();
3712 const uint32_t a
= ufoPop();
3713 if (c
== 0) ufoFatal("division by zero");
3714 uint64_t xval
= a
; xval
*= b
;
3715 ufoPush((uint32_t)(xval
/ c
));
3716 ufoPush((uint32_t)(xval
% c
));
3720 // ( a b -- lo(a*b) hi(a*b) )
3721 // this leaves 64-bit result
3723 const int32_t b
= (int32_t)ufoPop();
3724 const int32_t a
= (int32_t)ufoPop();
3725 int64_t xval
= a
; xval
*= b
;
3730 // ( a b -- lo(a*b) hi(a*b) )
3731 // this leaves 64-bit result
3733 const uint32_t b
= ufoPop();
3734 const uint32_t a
= ufoPop();
3735 uint64_t xval
= a
; xval
*= b
;
3740 // ( alo ahi b -- a/b a%b )
3742 const int32_t b
= (int32_t)ufoPop();
3743 if (b
== 0) ufoFatal("division by zero");
3744 int64_t a
= UFO_POP_I64();
3745 int32_t adiv
= (int32_t)(a
/ b
);
3746 int32_t amod
= (int32_t)(a
% b
);
3747 ufoPush((uint32_t)adiv
);
3748 ufoPush((uint32_t)amod
);
3752 // ( alo ahi b -- a/b a%b )
3754 const uint32_t b
= ufoPop();
3755 if (b
== 0) ufoFatal("division by zero");
3756 uint64_t a
= UFO_POP_U64();
3757 uint32_t adiv
= (uint32_t)(a
/ b
);
3758 uint32_t amod
= (uint32_t)(a
% b
);
3764 // ( alo ahi u -- lo hi )
3766 const uint32_t b
= ufoPop();
3767 uint64_t a
= UFO_POP_U64();
3773 // ( lo0 hi0 lo1 hi1 -- lo hi )
3775 uint64_t n1
= UFO_POP_U64();
3776 uint64_t n0
= UFO_POP_U64();
3782 // ( lo0 hi0 lo1 hi1 -- lo hi )
3784 uint64_t n1
= UFO_POP_U64();
3785 uint64_t n0
= UFO_POP_U64();
3791 // ( lo0 hi0 lo1 hi1 -- bool )
3793 uint64_t n1
= UFO_POP_U64();
3794 uint64_t n0
= UFO_POP_U64();
3795 ufoPushBool(n0
== n1
);
3799 // ( lo0 hi0 lo1 hi1 -- bool )
3801 int64_t n1
= UFO_POP_I64();
3802 int64_t n0
= UFO_POP_I64();
3803 ufoPushBool(n0
< n1
);
3807 // ( lo0 hi0 lo1 hi1 -- bool )
3809 int64_t n1
= UFO_POP_I64();
3810 int64_t n0
= UFO_POP_I64();
3811 ufoPushBool(n0
<= n1
);
3815 // ( lo0 hi0 lo1 hi1 -- bool )
3817 uint64_t n1
= UFO_POP_U64();
3818 uint64_t n0
= UFO_POP_U64();
3819 ufoPushBool(n0
< n1
);
3823 // ( lo0 hi0 lo1 hi1 -- bool )
3825 uint64_t n1
= UFO_POP_U64();
3826 uint64_t n0
= UFO_POP_U64();
3827 ufoPushBool(n0
<= n1
);
3831 // ( dlo dhi n -- nmod ndiv )
3832 // rounds toward zero
3834 const int32_t n
= (int32_t)ufoPop();
3835 if (n
== 0) ufoFatal("division by zero");
3836 int64_t d
= UFO_POP_I64();
3837 int32_t ndiv
= (int32_t)(d
/ n
);
3838 int32_t nmod
= (int32_t)(d
% n
);
3844 // ( dlo dhi n -- nmod ndiv )
3845 // rounds toward negative infinity
3847 const int32_t n
= (int32_t)ufoPop();
3848 if (n
== 0) ufoFatal("division by zero");
3849 int64_t d
= UFO_POP_I64();
3850 int32_t ndiv
= (int32_t)(d
/ n
);
3851 int32_t nmod
= (int32_t)(d
% n
);
3852 if (nmod
!= 0 && ((uint32_t)n
^ (uint32_t)(d
>> 32)) >= 0x80000000u
) {
3861 // ////////////////////////////////////////////////////////////////////////// //
3862 // simple logic and bit manipulation
3865 #define UF_CMP(name_,op_) \
3867 const uint32_t b = ufoPop(); \
3868 const uint32_t a = ufoPop(); \
3874 UF_CMP(LESS
, (int32_t)a
< (int32_t)b
);
3878 UF_CMP(ULESS
, a
< b
);
3882 UF_CMP(GREAT
, (int32_t)a
> (int32_t)b
);
3886 UF_CMP(UGREAT
, a
> b
);
3890 UF_CMP(LESSEQU
, (int32_t)a
<= (int32_t)b
);
3894 UF_CMP(ULESSEQU
, a
<= b
);
3898 UF_CMP(GREATEQU
, (int32_t)a
>= (int32_t)b
);
3902 UF_CMP(UGREATEQU
, a
>= b
);
3906 UF_CMP(EQU
, a
== b
);
3910 UF_CMP(NOTEQU
, a
!= b
);
3915 const uint32_t a
= ufoPop();
3921 UF_CMP(LOGAND
, a
&& b
);
3925 UF_CMP(LOGOR
, a
|| b
);
3930 const uint32_t b
= ufoPop();
3931 const uint32_t a
= ufoPop();
3938 const uint32_t b
= ufoPop();
3939 const uint32_t a
= ufoPop();
3946 const uint32_t b
= ufoPop();
3947 const uint32_t a
= ufoPop();
3954 const uint32_t a
= ufoPop();
3958 UFWORD(ONESHL
) { uint32_t n
= ufoPop(); ufoPush(n
<< 1); }
3959 UFWORD(ONESHR
) { uint32_t n
= ufoPop(); ufoPush(n
>> 1); }
3960 UFWORD(TWOSHL
) { uint32_t n
= ufoPop(); ufoPush(n
<< 2); }
3961 UFWORD(TWOSHR
) { uint32_t n
= ufoPop(); ufoPush(n
>> 2); }
3965 // arithmetic shift; positive `n` shifts to the left
3967 int32_t c
= (int32_t)ufoPop();
3970 int32_t n
= (int32_t)ufoPop();
3972 if (n
< 0) n
= -1; else n
= 0;
3974 n
>>= (uint8_t)(-c
);
3976 ufoPush((uint32_t)n
);
3979 uint32_t u
= ufoPop();
3991 // logical shift; positive `n` shifts to the left
3993 int32_t c
= (int32_t) ufoPop();
3994 uint32_t u
= ufoPop();
4000 u
>>= (uint8_t)(-c
);
4014 // ////////////////////////////////////////////////////////////////////////// //
4015 // string unescaping
4019 // ( addr count -- addr count )
4020 UFWORD(PAR_UNESCAPE
) {
4021 const uint32_t count
= ufoPop();
4022 const uint32_t addr
= ufoPeek();
4023 if ((count
& ((uint32_t)1<<31)) == 0) {
4024 const uint32_t eaddr
= addr
+ count
;
4025 uint32_t caddr
= addr
;
4026 uint32_t daddr
= addr
;
4027 while (caddr
!= eaddr
) {
4028 uint8_t ch
= ufoImgGetU8Ext(caddr
); caddr
+= 1u;
4029 if (ch
== '\\' && caddr
!= eaddr
) {
4030 ch
= ufoImgGetU8Ext(caddr
); caddr
+= 1u;
4032 case 'r': ch
= '\r'; break;
4033 case 'n': ch
= '\n'; break;
4034 case 't': ch
= '\t'; break;
4035 case 'e': ch
= '\x1b'; break;
4036 case '`': ch
= '"'; break; // special escape to insert double-quote
4037 case '"': ch
= '"'; break;
4038 case '\\': ch
= '\\'; break;
4040 if (eaddr
- daddr
>= 1) {
4041 const int dg0
= digitInBase((char)(ufoImgGetU8Ext(caddr
)), 16);
4042 if (dg0
< 0) ufoFatal("invalid hex string escape");
4043 if (eaddr
- daddr
>= 2) {
4044 const int dg1
= digitInBase((char)(ufoImgGetU8Ext(caddr
+ 1u)), 16);
4045 if (dg1
< 0) ufoFatal("invalid hex string escape");
4046 ch
= (uint8_t)(dg0
* 16 + dg1
);
4053 ufoFatal("invalid hex string escape");
4056 default: ufoFatal("invalid string escape");
4059 ufoImgPutU8Ext(daddr
, ch
); daddr
+= 1u;
4061 ufoPush(daddr
- addr
);
4068 // ////////////////////////////////////////////////////////////////////////// //
4069 // numeric conversions
4072 // (BASED-NUMBER) ( addr count allowsign? base -- num TRUE / FALSE )
4073 UFWORD(PAR_BASED_NUMBER
) {
4074 const uint32_t xbase
= ufoPop();
4075 const uint32_t allowSign
= ufoPop();
4076 int32_t count
= (int32_t)ufoPop();
4077 uint32_t addr
= ufoPop();
4083 if (allowSign
&& count
> 1) {
4084 ch
= ufoImgGetU8Ext(addr
);
4085 if (ch
== '-') { neg
= 1; addr
+= 1u; count
-= 1; }
4086 else if (ch
== '+') { neg
= 0; addr
+= 1u; count
-= 1; }
4089 // special-based numbers
4090 if (count
>= 3 && ufoImgGetU8Ext(addr
) == '0') {
4091 switch (ufoImgGetU8Ext(addr
+ 1u)) {
4092 case 'x': case 'X': base
= 16; break;
4093 case 'o': case 'O': base
= 8; break;
4094 case 'b': case 'B': base
= 2; break;
4095 case 'd': case 'D': base
= 10; break;
4098 if (base
) { addr
+= 2; count
-= 2; }
4099 } else if (count
>= 2 && ufoImgGetU8Ext(addr
) == '$') {
4101 addr
+= 1; count
-= 1;
4102 } else if (count
>= 2 && ufoImgGetU8Ext(addr
) == '#') {
4104 addr
+= 1; count
-= 1;
4105 } else if (count
>= 2 && ufoImgGetU8Ext(addr
) == '%') {
4107 addr
+= 1; count
-= 1;
4108 } else if (count
>= 3 && ufoImgGetU8Ext(addr
) == '&') {
4109 switch (ufoImgGetU8Ext(addr
+ 1u)) {
4110 case 'h': case 'H': base
= 16; break;
4111 case 'o': case 'O': base
= 8; break;
4112 case 'b': case 'B': base
= 2; break;
4113 case 'd': case 'D': base
= 10; break;
4116 if (base
) { addr
+= 2; count
-= 2; }
4117 } else if (xbase
< 12 && count
> 2 && toUpperU8(ufoImgGetU8Ext(addr
+ (uint32_t)count
- 1u)) == 'B') {
4120 } else if (xbase
< 18 && count
> 2 && toUpperU8(ufoImgGetU8Ext(addr
+ (uint32_t)count
- 1u)) == 'H') {
4123 } else if (xbase
< 25 && count
> 2 && toUpperU8(ufoImgGetU8Ext(addr
+ (uint32_t)count
- 1u)) == 'O') {
4129 if (!base
&& xbase
< 255) base
= xbase
;
4131 if (count
<= 0 || base
< 1 || base
> 36) {
4135 int wasDig
= 0, wasUnder
= 1, error
= 0, dig
;
4136 while (!error
&& count
!= 0) {
4137 ch
= ufoImgGetU8Ext(addr
); addr
+= 1u; count
-= 1;
4139 error
= 1; wasUnder
= 0; wasDig
= 1;
4140 dig
= digitInBase((char)ch
, (int)base
);
4142 nc
= n
* (uint32_t)base
;
4144 nc
+= (uint32_t)dig
;
4157 if (!error
&& wasDig
&& !wasUnder
) {
4158 if (allowSign
&& neg
) n
= ~n
+ 1u;
4168 // ////////////////////////////////////////////////////////////////////////// //
4169 // compiler-related, dictionary-related
4172 static char ufoWNameBuf
[256];
4176 UFWORD(LBRACKET_IMM
) {
4177 if (ufoImgGetU32(ufoAddrSTATE
) == 0) ufoFatal("expects compiling mode");
4178 ufoImgPutU32(ufoAddrSTATE
, 0);
4183 if (ufoImgGetU32(ufoAddrSTATE
) != 0) ufoFatal("expects interpreting mode");
4184 ufoImgPutU32(ufoAddrSTATE
, 1);
4187 // (CREATE-WORD-HEADER)
4188 // ( addr count word-flags -- )
4189 UFWORD(PAR_CREATE_WORD_HEADER
) {
4190 const uint32_t flags
= ufoPop();
4191 const uint32_t wlen
= ufoPop();
4192 const uint32_t waddr
= ufoPop();
4193 if (wlen
== 0) ufoFatal("word name expected");
4194 if (wlen
>= UFO_MAX_WORD_LENGTH
) ufoFatal("word name too long");
4195 // copy to separate buffer
4196 for (uint32_t f
= 0; f
< wlen
; f
+= 1) {
4197 ufoWNameBuf
[f
] = (char)ufoImgGetU8Ext(waddr
+ f
);
4199 ufoWNameBuf
[wlen
] = 0;
4200 ufoCreateWordHeader(ufoWNameBuf
, flags
);
4203 // (CREATE-NAMELESS-WORD-HEADER)
4204 // ( word-flags -- )
4205 UFWORD(PAR_CREATE_NAMELESS_WORD_HEADER
) {
4206 const uint32_t flags
= ufoPop();
4207 ufoCreateWordHeader("", flags
);
4211 // ( addr count -- cfa TRUE / FALSE)
4213 const uint32_t wlen
= ufoPop();
4214 const uint32_t waddr
= ufoPop();
4215 if (wlen
> 0 && wlen
< UFO_MAX_WORD_LENGTH
) {
4216 // copy to separate buffer
4217 for (uint32_t f
= 0; f
< wlen
; f
+= 1) {
4218 ufoWNameBuf
[f
] = (char)ufoImgGetU8Ext(waddr
+ f
);
4220 ufoWNameBuf
[wlen
] = 0;
4221 const uint32_t cfa
= ufoFindWord(ufoWNameBuf
);
4234 // ( addr count vocid allowhidden -- cfa TRUE / FALSE)
4235 // find only in the given voc; no name resolution
4236 UFWORD(FIND_WORD_IN_VOC
) {
4237 const uint32_t allowHidden
= ufoPop();
4238 const uint32_t vocid
= ufoPop();
4239 const uint32_t wlen
= ufoPop();
4240 const uint32_t waddr
= ufoPop();
4241 if (wlen
> 0 && wlen
< UFO_MAX_WORD_LENGTH
) {
4242 // copy to separate buffer
4243 for (uint32_t f
= 0; f
< wlen
; f
+= 1) {
4244 ufoWNameBuf
[f
] = (char)ufoImgGetU8Ext(waddr
+ f
);
4246 ufoWNameBuf
[wlen
] = 0;
4247 const uint32_t cfa
= ufoFindWordInVoc(ufoWNameBuf
, wlen
, 0, vocid
, (allowHidden
? 1 : 0));
4259 // FIND-WORD-IN-VOC-AND-PARENTS
4260 // ( addr count vocid allowhidden -- cfa TRUE / FALSE)
4261 // find only in the given voc; no name resolution
4262 UFWORD(FIND_WORD_IN_VOC_AND_PARENTS
) {
4263 const uint32_t allowHidden
= ufoPop();
4264 const uint32_t vocid
= ufoPop();
4265 const uint32_t wlen
= ufoPop();
4266 const uint32_t waddr
= ufoPop();
4267 if (wlen
> 0 && wlen
< UFO_MAX_WORD_LENGTH
) {
4268 // copy to separate buffer
4269 for (uint32_t f
= 0; f
< wlen
; f
+= 1) {
4270 ufoWNameBuf
[f
] = (char)ufoImgGetU8Ext(waddr
+ f
);
4272 ufoWNameBuf
[wlen
] = 0;
4273 const uint32_t cfa
= ufoFindWordInVocAndParents(ufoWNameBuf
, wlen
, 0, vocid
, (allowHidden
? 1 : 0));
4286 // ////////////////////////////////////////////////////////////////////////// //
4287 // more compiler words
4292 if (ufoImgGetU32(ufoAddrSTATE
) != 0) ufoFatal("expecting execution mode");
4297 if (ufoImgGetU32(ufoAddrSTATE
) == 0) ufoFatal("expecting compilation mode");
4303 ufoPush(34); UFCALL(PARSE
);
4304 if (ufoPop() == 0) ufoFatal("string literal expected");
4305 UFCALL(PAR_UNESCAPE
);
4306 if (ufoImgGetU32(ufoAddrSTATE
) != 0) {
4308 const uint32_t wlen
= ufoPop();
4309 const uint32_t waddr
= ufoPop();
4310 if (wlen
> 255) ufoFatal("string literal too long");
4311 ufoImgEmitU32(ufoStrLit8CFA
);
4313 for (uint32_t f
= 0; f
< wlen
; f
+= 1) {
4314 ufoImgEmitU8(ufoImgGetU8Ext(waddr
+ f
));
4322 // ////////////////////////////////////////////////////////////////////////// //
4323 // vocabulary and wordlist utilities
4328 UFWORD(PAR_GET_VSP
) {
4334 UFWORD(PAR_SET_VSP
) {
4335 const uint32_t vsp
= ufoPop();
4336 if (vsp
>= UFO_VOCSTACK_SIZE
) ufoFatal("VSP %u out of range (%u)", vsp
, UFO_VOCSTACK_SIZE
);
4342 UFWORD(PAR_VSP_LOAD
) {
4343 const uint32_t vsp
= ufoPop();
4344 if (vsp
>= UFO_VOCSTACK_SIZE
) ufoFatal("VSP %u out of range (%u)", vsp
, UFO_VOCSTACK_SIZE
);
4345 ufoPush(ufoVocStack
[vsp
]);
4350 UFWORD(PAR_VSP_STORE
) {
4351 const uint32_t vsp
= ufoPop();
4352 const uint32_t value
= ufoPop();
4353 if (vsp
> UFO_VOCSTACK_SIZE
) ufoFatal("VSP %u out of range (%u)", vsp
, UFO_VOCSTACK_SIZE
);
4354 ufoVocStack
[vsp
] = value
;
4358 // ////////////////////////////////////////////////////////////////////////// //
4359 // word field address conversion
4365 const uint32_t cfa
= ufoPop();
4366 ufoPush(UFO_CFA_TO_PFA(cfa
));
4372 const uint32_t pfa
= ufoPop();
4373 ufoPush(UFO_PFA_TO_CFA(pfa
));
4379 const uint32_t cfa
= ufoPop();
4380 ufoPush(UFO_CFA_TO_NFA(cfa
));
4386 const uint32_t nfa
= ufoPop();
4387 ufoPush(UFO_NFA_TO_CFA(nfa
));
4393 const uint32_t cfa
= ufoPop();
4394 ufoPush(UFO_CFA_TO_LFA(cfa
));
4400 const uint32_t lfa
= ufoPop();
4401 ufoPush(UFO_LFA_TO_CFA(lfa
));
4407 const uint32_t lfa
= ufoPop();
4408 const uint32_t cfa
= UFO_LFA_TO_CFA(lfa
);
4409 ufoPush(UFO_CFA_TO_PFA(cfa
));
4415 const uint32_t lfa
= ufoPop();
4416 ufoPush(UFO_LFA_TO_BFA(lfa
));
4422 const uint32_t lfa
= ufoPop();
4423 ufoPush(UFO_LFA_TO_XFA(lfa
));
4429 const uint32_t lfa
= ufoPop();
4430 ufoPush(UFO_LFA_TO_YFA(lfa
));
4436 const uint32_t lfa
= ufoPop();
4437 ufoPush(UFO_LFA_TO_NFA(lfa
));
4443 const uint32_t nfa
= ufoPop();
4444 ufoPush(UFO_NFA_TO_LFA(nfa
));
4448 // ( cfa -- wend-addr )
4450 const uint32_t cfa
= ufoPop();
4451 ufoPush(ufoGetWordEndAddr(cfa
));
4455 // ( ip -- nfa / 0 )
4457 const uint32_t ip
= ufoPop();
4458 ufoPush(ufoFindWordForIP(ip
));
4462 // ( ip -- addr count line TRUE / FALSE )
4463 // name is at PAD; it is safe to use PAD, because each task has its own temp image
4464 UFWORD(IP2FILELINE
) {
4465 const uint32_t ip
= ufoPop();
4467 const char *fname
= ufoFindFileForIP(ip
, &fline
);
4468 if (fname
!= NULL
) {
4470 const uint32_t addr
= ufoPeek();
4472 while (*fname
!= 0) {
4473 ufoImgPutU8(addr
+ count
, *(const unsigned char *)fname
);
4474 fname
+= 1u; count
+= 1u;
4476 ufoImgPutU8(addr
+ count
, 0); // just in case
4486 // ////////////////////////////////////////////////////////////////////////// //
4487 // string operations
4490 UFO_FORCE_INLINE
uint32_t ufoHashBuf (uint32_t addr
, uint32_t size
, uint8_t orbyte
) {
4491 uint32_t hash
= 0x29a;
4492 if ((size
& ((uint32_t)1<<31)) == 0) {
4494 hash
+= ufoImgGetU8Ext(addr
) | orbyte
;
4497 addr
+= 1u; size
-= 1u;
4507 //==========================================================================
4511 //==========================================================================
4512 UFO_FORCE_INLINE
int ufoBufEqu (uint32_t addr0
, uint32_t addr1
, uint32_t count
) {
4514 if ((count
& ((uint32_t)1<<31)) == 0) {
4516 while (res
!= 0 && count
!= 0) {
4517 res
= (toUpperU8(ufoImgGetU8Ext(addr0
)) == toUpperU8(ufoImgGetU8Ext(addr1
)));
4518 addr0
+= 1u; addr1
+= 1u; count
-= 1u;
4527 // ( a0 c0 a1 c1 -- bool )
4529 int32_t c1
= (int32_t)ufoPop();
4530 uint32_t a1
= ufoPop();
4531 int32_t c0
= (int32_t)ufoPop();
4532 uint32_t a0
= ufoPop();
4537 while (res
!= 0 && c0
!= 0) {
4538 res
= (ufoImgGetU8Ext(a0
) == ufoImgGetU8Ext(a1
));
4539 a0
+= 1; a1
+= 1; c0
-= 1;
4548 // ( a0 c0 a1 c1 -- bool )
4550 int32_t c1
= (int32_t)ufoPop();
4551 uint32_t a1
= ufoPop();
4552 int32_t c0
= (int32_t)ufoPop();
4553 uint32_t a0
= ufoPop();
4558 while (res
!= 0 && c0
!= 0) {
4559 res
= (toUpperU8(ufoImgGetU8Ext(a0
)) == toUpperU8(ufoImgGetU8Ext(a1
)));
4560 a0
+= 1; a1
+= 1; c0
-= 1;
4568 // search the string specified by c-addr1 u1 for the string specified by c-addr2 u2.
4569 // if flag is true, a match was found at c-addr3 with u3 characters remaining.
4570 // if flag is false there was no match and c-addr3 is c-addr1 and u3 is u1.
4571 // ( c-addr1 u1 c-addr2 u2 -- c-addr3 u3 flag )
4573 const uint32_t pcount
= ufoPop();
4574 const uint32_t paddr
= ufoPop();
4575 const uint32_t tcount
= ufoPop();
4576 const uint32_t taddr
= ufoPop();
4577 if ((pcount
& ((uint32_t)1 << 31)) == 0 && (tcount
& ((uint32_t)1 << 31)) == 0) {
4578 for (uint32_t f
= 0; tcount
- f
>= pcount
; f
+= 1) {
4579 if (ufoBufEqu(taddr
+ f
, paddr
, pcount
)) {
4581 ufoPush(tcount
- f
);
4593 // ( addr count -- hash )
4595 uint32_t count
= ufoPop();
4596 uint32_t addr
= ufoPop();
4597 ufoPush(ufoHashBuf(addr
, count
, 0));
4601 // ( addr count -- hash )
4603 uint32_t count
= ufoPop();
4604 uint32_t addr
= ufoPop();
4605 ufoPush(ufoHashBuf(addr
, count
, 0x20));
4609 // ////////////////////////////////////////////////////////////////////////// //
4610 // conditional defines
4613 typedef struct UForthCondDefine_t UForthCondDefine
;
4614 struct UForthCondDefine_t
{
4618 UForthCondDefine
*next
;
4621 static UForthCondDefine
*ufoCondDefines
= NULL
;
4622 static char ufoErrMsgBuf
[4096];
4625 //==========================================================================
4629 //==========================================================================
4630 UFO_DISABLE_INLINE
int ufoStrEquCI (const void *str0
, const void *str1
) {
4631 const unsigned char *s0
= (const unsigned char *)str0
;
4632 const unsigned char *s1
= (const unsigned char *)str1
;
4633 while (*s0
&& *s1
) {
4634 if (toUpperU8(*s0
) != toUpperU8(*s1
)) return 0;
4637 return (*s0
== 0 && *s1
== 0);
4641 //==========================================================================
4645 //==========================================================================
4646 UFO_FORCE_INLINE
int ufoBufEquCI (uint32_t addr
, uint32_t count
, const void *buf
) {
4648 if ((count
& ((uint32_t)1<<31)) == 0) {
4649 const unsigned char *src
= (const unsigned char *)buf
;
4651 while (res
!= 0 && count
!= 0) {
4652 res
= (toUpperU8(*src
) == toUpperU8(ufoImgGetU8Ext(addr
)));
4653 src
+= 1; addr
+= 1u; count
-= 1u;
4662 //==========================================================================
4664 // ufoClearCondDefines
4666 //==========================================================================
4667 static void ufoClearCondDefines (void) {
4668 while (ufoCondDefines
) {
4669 UForthCondDefine
*df
= ufoCondDefines
;
4670 ufoCondDefines
= df
->next
;
4671 if (df
->name
) free(df
->name
);
4677 //==========================================================================
4681 //==========================================================================
4682 int ufoHasCondDefine (const char *name
) {
4684 if (name
!= NULL
&& name
[0] != 0) {
4685 const size_t nlen
= strlen(name
);
4687 const uint32_t hash
= joaatHashBufCI(name
, nlen
);
4688 UForthCondDefine
*dd
= ufoCondDefines
;
4689 while (res
== 0 && dd
!= NULL
) {
4690 if (dd
->hash
== hash
&& dd
->namelen
== (uint32_t)nlen
) {
4691 res
= ufoStrEquCI(name
, dd
->name
);
4701 //==========================================================================
4705 //==========================================================================
4706 void ufoCondDefine (const char *name
) {
4707 if (name
!= NULL
&& name
[0] != 0) {
4708 const size_t nlen
= strlen(name
);
4709 if (nlen
> 255) ufoFatal("conditional define name too long");
4710 const uint32_t hash
= joaatHashBufCI(name
, nlen
);
4711 UForthCondDefine
*dd
= ufoCondDefines
;
4713 while (res
== 0 && dd
!= NULL
) {
4714 if (dd
->hash
== hash
&& dd
->namelen
== (uint32_t)nlen
) {
4715 res
= ufoStrEquCI(name
, dd
->name
);
4721 dd
= calloc(1, sizeof(UForthCondDefine
));
4722 if (dd
== NULL
) ufoFatal("out of memory for defines");
4723 dd
->name
= strdup(name
);
4724 if (dd
->name
== NULL
) { free(dd
); ufoFatal("out of memory for defines"); }
4725 dd
->namelen
= (uint32_t)nlen
;
4727 dd
->next
= ufoCondDefines
;
4728 ufoCondDefines
= dd
;
4734 //==========================================================================
4738 //==========================================================================
4739 void ufoCondUndef (const char *name
) {
4740 if (name
!= NULL
&& name
[0] != 0) {
4741 const size_t nlen
= strlen(name
);
4743 const uint32_t hash
= joaatHashBufCI(name
, nlen
);
4744 UForthCondDefine
*dd
= ufoCondDefines
;
4745 UForthCondDefine
*prev
= NULL
;
4746 while (dd
!= NULL
) {
4747 if (dd
->hash
== hash
&& dd
->namelen
== (uint32_t)nlen
) {
4748 if (ufoStrEquCI(name
, dd
->name
)) {
4749 if (prev
!= NULL
) prev
->next
= dd
->next
; else ufoCondDefines
= dd
->next
;
4755 if (dd
!= NULL
) { prev
= dd
; dd
= dd
->next
; }
4763 // ( addr count -- )
4764 UFWORD(PAR_DLR_DEFINE
) {
4765 uint32_t count
= ufoPop();
4766 uint32_t addr
= ufoPop();
4767 if (count
== 0) ufoFatal("empty define");
4768 if (count
>= UFO_MAX_WORD_LENGTH
) ufoFatal("define too long");
4769 const uint32_t hash
= ufoHashBuf(addr
, count
, 0x20);
4770 UForthCondDefine
*dd
;
4771 for (dd
= ufoCondDefines
; dd
!= NULL
; dd
= dd
->next
) {
4772 if (dd
->hash
== hash
&& dd
->namelen
== count
) {
4773 if (ufoBufEquCI(addr
, count
, dd
->name
)) return;
4777 dd
= calloc(1, sizeof(UForthCondDefine
));
4778 if (dd
== NULL
) ufoFatal("out of memory for defines");
4779 dd
->name
= calloc(1, count
+ 1u);
4780 if (dd
->name
== NULL
) { free(dd
); ufoFatal("out of memory for defines"); }
4781 for (uint32_t f
= 0; f
< count
; f
+= 1) {
4782 ((unsigned char *)dd
->name
)[f
] = ufoImgGetU8Ext(addr
+ f
);
4784 dd
->namelen
= count
;
4786 dd
->next
= ufoCondDefines
;
4787 ufoCondDefines
= dd
;
4791 // ( addr count -- )
4792 UFWORD(PAR_DLR_UNDEF
) {
4793 uint32_t count
= ufoPop();
4794 uint32_t addr
= ufoPop();
4795 if (count
== 0) ufoFatal("empty define");
4796 if (count
>= UFO_MAX_WORD_LENGTH
) ufoFatal("define too long");
4797 const uint32_t hash
= ufoHashBuf(addr
, count
, 0x20);
4798 UForthCondDefine
*prev
= NULL
;
4799 UForthCondDefine
*dd
;
4800 for (dd
= ufoCondDefines
; dd
!= NULL
; prev
= dd
, dd
= dd
->next
) {
4801 if (dd
->hash
== hash
&& dd
->namelen
== count
) {
4802 if (ufoBufEquCI(addr
, count
, dd
->name
)) {
4803 if (prev
== NULL
) ufoCondDefines
= dd
->next
; else prev
->next
= dd
->next
;
4813 // ( addr count -- bool )
4814 UFWORD(PAR_DLR_DEFINEDQ
) {
4815 uint32_t count
= ufoPop();
4816 uint32_t addr
= ufoPop();
4817 if (count
== 0) ufoFatal("empty define");
4818 if (count
>= UFO_MAX_WORD_LENGTH
) ufoFatal("define too long");
4819 const uint32_t hash
= ufoHashBuf(addr
, count
, 0x20);
4821 UForthCondDefine
*dd
= ufoCondDefines
;
4822 while (!found
&& dd
!= NULL
) {
4823 if (dd
->hash
== hash
&& dd
->namelen
== count
) {
4824 found
= ufoBufEquCI(addr
, count
, dd
->name
);
4832 // ////////////////////////////////////////////////////////////////////////// //
4837 // ( addr count -- )
4839 uint32_t count
= ufoPop();
4840 uint32_t addr
= ufoPop();
4841 if (count
& (1u<<31)) ufoFatal("invalid error message");
4842 if (count
== 0) ufoFatal("some error");
4843 if (count
> (uint32_t)sizeof(ufoErrMsgBuf
) - 1u) count
= (uint32_t)sizeof(ufoErrMsgBuf
) - 1u;
4844 for (uint32_t f
= 0; f
< count
; f
+= 1) {
4845 ufoErrMsgBuf
[f
] = (char)ufoImgGetU8Ext(addr
+ f
);
4847 ufoErrMsgBuf
[count
] = 0;
4848 ufoFatal("%s", ufoErrMsgBuf
);
4852 // ( errflag addr count -- )
4854 const uint32_t count
= ufoPop();
4855 const uint32_t addr
= ufoPop();
4864 // ////////////////////////////////////////////////////////////////////////// //
4868 static char ufoFNameBuf
[4096];
4871 //==========================================================================
4873 // ufoScanIncludeFileName
4875 // `*psys` and `*psoft` must be initialised!
4877 //==========================================================================
4878 static void ufoScanIncludeFileName (uint32_t addr
, uint32_t count
, char *dest
, size_t destsz
,
4879 uint32_t *psys
, uint32_t *psoft
)
4883 ufo_assert(dest
!= NULL
);
4884 ufo_assert(destsz
> 0);
4886 while (count
!= 0) {
4887 ch
= ufoImgGetU8Ext(addr
);
4889 //if (system) ufoFatal("invalid file name (duplicate system mark)");
4891 } else if (ch
== '?') {
4892 //if (softinclude) ufoFatal("invalid file name (duplicate soft mark)");
4898 addr
+= 1; count
-= 1;
4899 ch
= ufoImgGetU8Ext(addr
);
4900 } while (ch
<= 32 && count
!= 0);
4903 if (count
== 0) ufoFatal("empty include file name");
4904 if (count
>= destsz
) ufoFatal("include file name too long");
4907 while (count
!= 0) {
4908 dest
[dpos
] = (char)ufoImgGetU8Ext(addr
); dpos
+= 1;
4909 addr
+= 1; count
-= 1;
4917 // return number of items in include stack
4918 UFWORD(PAR_INCLUDE_DEPTH
) {
4919 ufoPush(ufoFileStackPos
);
4922 // (INCLUDE-FILE-ID)
4923 // ( isp -- id ) -- isp 0 is current, then 1, etc.
4924 // each include file has unique non-zero id.
4925 UFWORD(PAR_INCLUDE_FILE_ID
) {
4926 const uint32_t isp
= ufoPop();
4929 } else if (isp
<= ufoFileStackPos
) {
4930 UFOFileStackEntry
*stk
= &ufoFileStack
[ufoFileStackPos
- isp
];
4933 ufoFatal("invalid include stack index");
4937 // (INCLUDE-FILE-LINE)
4939 UFWORD(PAR_INCLUDE_FILE_LINE
) {
4940 const uint32_t isp
= ufoPop();
4942 ufoPush(ufoInFileLine
);
4943 } else if (isp
<= ufoFileStackPos
) {
4944 UFOFileStackEntry
*stk
= &ufoFileStack
[ufoFileStackPos
- isp
];
4945 ufoPush(stk
->fline
);
4947 ufoFatal("invalid include stack index");
4949 ufoPush(ufoInFileLine
);
4952 // (INCLUDE-FILE-NAME)
4953 // ( isp -- addr count )
4954 // current file name; at PAD
4955 UFWORD(PAR_INCLUDE_FILE_NAME
) {
4956 const uint32_t isp
= ufoPop();
4957 const char *fname
= NULL
;
4959 fname
= ufoInFileName
;
4960 } else if (isp
<= ufoFileStackPos
) {
4961 UFOFileStackEntry
*stk
= &ufoFileStack
[ufoFileStackPos
- isp
];
4964 ufoFatal("invalid include stack index");
4967 uint32_t addr
= ufoPop();
4969 while (fname
[count
] != 0) {
4970 ufoImgPutU8Ext(addr
+ count
, ((const unsigned char *)fname
)[count
]);
4973 ufoImgPutU8Ext(addr
+ count
, 0);
4979 // ( addr count soft? system? -- )
4980 UFWORD(PAR_INCLUDE
) {
4981 uint32_t system
= ufoPop();
4982 uint32_t softinclude
= ufoPop();
4983 uint32_t count
= ufoPop();
4984 uint32_t addr
= ufoPop();
4986 if (ufoMode
== UFO_MODE_MACRO
) ufoFatal("macros cannot include files");
4988 if ((count
& ((uint32_t)1<<31)) != 0) ufoFatal("invalid include name");
4990 ufoScanIncludeFileName(addr
, count
, ufoFNameBuf
, sizeof(ufoFNameBuf
),
4991 &system
, &softinclude
);
4993 char *ffn
= ufoCreateIncludeName(ufoFNameBuf
, system
, (system
? ufoLastSysIncPath
: ufoLastIncPath
));
4995 FILE *fl
= fopen(ffn
, "rb");
4997 FILE *fl
= fopen(ffn
, "r");
5000 if (softinclude
) { free(ffn
); return; }
5001 ufoFatal("include file '%s' not found", ffn
);
5006 ufoInFileName
= ffn
;
5007 ufoFileId
= ufoLastUsedFileId
;
5008 setLastIncPath(ufoInFileName
, system
);
5009 #ifdef UFO_DEBUG_INCLUDE
5010 fprintf(stderr
, "INC-PUSH: new fname: %s\n", ffn
);
5013 // trigger next line loading
5015 if (!ufoPop()) ufoFatal("(INCLUDE) internal error");
5019 UFWORD(DLR_INCLUDE_IMM
) {
5020 int soft
= 0, system
= 0;
5021 // parse include filename
5022 //UFCALL(PARSE_SKIP_BLANKS);
5023 ufoPushBool(0); UFCALL(PAR_PARSE_SKIP_COMMENTS
);
5024 uint8_t ch
= ufoTibPeekCh();
5026 ufoTibSkipCh(); // skip quote
5028 } else if (ch
== '<') {
5029 ufoTibSkipCh(); // skip quote
5033 ufoFatal("expected quoted string");
5036 if (!ufoPop()) ufoFatal("file name expected");
5037 ufoPushBool(0); UFCALL(PAR_PARSE_SKIP_COMMENTS
);
5038 if (ufoTibPeekCh() != 0) {
5039 ufoFatal("$INCLUDE doesn't accept extra args yet");
5041 // ( addr count soft? system? -- )
5042 ufoPushBool(soft
); ufoPushBool(system
); UFCALL(PAR_INCLUDE
);
5046 //==========================================================================
5048 // ufoCreateFileGuard
5050 //==========================================================================
5051 static const char *ufoCreateFileGuard (const char *fname
) {
5052 if (fname
== NULL
|| fname
[0] == 0) return NULL
;
5053 char *rp
= ufoRealPath(fname
);
5054 if (rp
== NULL
) return NULL
;
5056 for (char *s
= rp
; *s
; s
+= 1) if (*s
== '\\') *s
= '/';
5058 // hash the buffer; extract file name; create string with path len, file name, and hash
5059 const size_t orgplen
= strlen(rp
);
5060 const uint32_t phash
= joaatHashBuf(rp
, orgplen
, 0);
5061 size_t plen
= orgplen
;
5062 while (plen
!= 0 && rp
[plen
- 1u] != '/') plen
-= 1;
5063 snprintf(ufoRealPathHashBuf
, sizeof(ufoRealPathHashBuf
),
5064 "__INCLUDE_GUARD_%08X_%08X_%s__", phash
, (uint32_t)orgplen
, rp
+ plen
);
5065 return ufoRealPathHashBuf
;
5069 // $INCLUDE-ONCE "str"
5070 // includes file only once; unreliable on shitdoze, i believe
5071 UFWORD(DLR_INCLUDE_ONCE_IMM
) {
5072 uint32_t softinclude
= 0, system
= 0;
5073 // parse include filename
5074 //UFCALL(PARSE_SKIP_BLANKS);
5075 ufoPushBool(0); UFCALL(PAR_PARSE_SKIP_COMMENTS
);
5076 uint8_t ch
= ufoTibPeekCh();
5078 ufoTibSkipCh(); // skip quote
5080 } else if (ch
== '<') {
5081 ufoTibSkipCh(); // skip quote
5085 ufoFatal("expected quoted string");
5088 if (!ufoPop()) ufoFatal("file name expected");
5089 const uint32_t count
= ufoPop();
5090 const uint32_t addr
= ufoPop();
5091 ufoPushBool(0); UFCALL(PAR_PARSE_SKIP_COMMENTS
);
5092 if (ufoTibPeekCh() != 0) {
5093 ufoFatal("$REQUIRE doesn't accept extra args yet");
5095 ufoScanIncludeFileName(addr
, count
, ufoRealPathHashBuf
, sizeof(ufoRealPathHashBuf
),
5096 &system
, &softinclude
);
5097 char *incfname
= ufoCreateIncludeName(ufoRealPathHashBuf
, system
, (system
? ufoLastSysIncPath
: ufoLastIncPath
));
5098 if (incfname
== NULL
) ufoFatal("cannot resolve include file '%s'", ufoRealPathHashBuf
);
5099 //fprintf(stderr, "?:%d;!:%d;%s|%s\n", softinclude, system, ufoRealPathHashBuf, incfname);
5100 // this will overwrite `ufoRealPathHashBuf`
5101 const char *guard
= ufoCreateFileGuard(incfname
);
5103 if (guard
== NULL
) {
5104 if (!softinclude
) ufoFatal("cannot include file '%s'", ufoRealPathHashBuf
);
5108 fprintf(stderr
, "GUARD: <%s>\n", guard
);
5110 // now check for the guard
5111 const uint32_t glen
= (uint32_t)strlen(guard
);
5112 const uint32_t ghash
= joaatHashBuf(guard
, glen
, 0);
5113 UForthCondDefine
*dd
;
5114 for (dd
= ufoCondDefines
; dd
!= NULL
; dd
= dd
->next
) {
5115 if (dd
->hash
== ghash
&& dd
->namelen
== glen
&& strcmp(guard
, dd
->name
) == 0) {
5116 // nothing to do: already included
5121 dd
= calloc(1, sizeof(UForthCondDefine
));
5122 if (dd
== NULL
) ufoFatal("out of memory for defines");
5123 dd
->name
= calloc(1, glen
+ 1u);
5124 if (dd
->name
== NULL
) { free(dd
); ufoFatal("out of memory for defines"); }
5125 strcpy(dd
->name
, guard
);
5128 dd
->next
= ufoCondDefines
;
5129 ufoCondDefines
= dd
;
5130 // ( addr count soft? system? -- )
5131 ufoPush(addr
); ufoPush(count
); ufoPushBool(softinclude
); ufoPushBool(system
);
5132 UFCALL(PAR_INCLUDE
);
5136 // ////////////////////////////////////////////////////////////////////////// //
5142 UFWORD(PAR_NEW_HANDLE
) {
5143 const uint32_t typeid = ufoPop();
5144 if (typeid == UFO_HANDLE_FREE
) ufoFatal("invalid handle typeid");
5145 UfoHandle
*hh
= ufoAllocHandle(typeid);
5146 ufoPush(hh
->ufoHandle
);
5151 UFWORD(PAR_FREE_HANDLE
) {
5152 const uint32_t hx
= ufoPop();
5153 if ((hx
& UFO_ADDR_HANDLE_BIT
) == 0) ufoFatal("trying to free something that is not a handle");
5154 UfoHandle
*hh
= ufoGetHandle(hx
);
5155 if (hh
== NULL
) ufoFatal("trying to free invalid handle");
5161 UFWORD(PAR_HANDLE_GET_TYPEID
) {
5162 const uint32_t hx
= ufoPop();
5163 if ((hx
& UFO_ADDR_HANDLE_BIT
) == 0) ufoFatal("not a handle");
5164 UfoHandle
*hh
= ufoGetHandle(hx
);
5165 if (hh
== NULL
) ufoFatal("invalid handle");
5166 ufoPush(hh
->typeid);
5171 UFWORD(PAR_HANDLE_SET_TYPEID
) {
5172 const uint32_t hx
= ufoPop();
5173 const uint32_t typeid = ufoPop();
5174 if ((hx
& UFO_ADDR_HANDLE_BIT
) == 0) ufoFatal("not a handle");
5175 if (typeid == UFO_HANDLE_FREE
) ufoFatal("invalid handle typeid");
5176 UfoHandle
*hh
= ufoGetHandle(hx
);
5177 if (hh
== NULL
) ufoFatal("invalid handle");
5178 hh
->typeid = typeid;
5183 UFWORD(PAR_HANDLE_GET_SIZE
) {
5184 const uint32_t hx
= ufoPop();
5185 if ((hx
& UFO_ADDR_HANDLE_BIT
) == 0) ufoFatal("not a handle");
5186 UfoHandle
*hh
= ufoGetHandle(hx
);
5187 if (hh
== NULL
) ufoFatal("invalid handle");
5193 UFWORD(PAR_HANDLE_SET_SIZE
) {
5194 const uint32_t hx
= ufoPop();
5195 const uint32_t size
= ufoPop();
5196 if (size
> 0x04000000) ufoFatal("invalid handle size");
5197 if ((hx
& UFO_ADDR_HANDLE_BIT
) == 0) ufoFatal("not a handle");
5198 UfoHandle
*hh
= ufoGetHandle(hx
);
5199 if (hh
== NULL
) ufoFatal("invalid handle");
5200 if (hh
->size
!= size
) {
5205 uint8_t *nx
= realloc(hh
->data
, size
* sizeof(hh
->data
[0]));
5206 if (nx
== NULL
) ufoFatal("out of memory for handle of size %u", size
);
5208 if (size
> hh
->size
) memset(hh
->data
, 0, size
- hh
->size
);
5211 if (hh
->used
> size
) hh
->used
= size
;
5217 UFWORD(PAR_HANDLE_GET_USED
) {
5218 const uint32_t hx
= ufoPop();
5219 if ((hx
& UFO_ADDR_HANDLE_BIT
) == 0) ufoFatal("not a handle");
5220 UfoHandle
*hh
= ufoGetHandle(hx
);
5221 if (hh
== NULL
) ufoFatal("invalid handle");
5227 UFWORD(PAR_HANDLE_SET_USED
) {
5228 const uint32_t hx
= ufoPop();
5229 const uint32_t used
= ufoPop();
5230 if (used
> 0x04000000) ufoFatal("invalid handle used");
5231 if ((hx
& UFO_ADDR_HANDLE_BIT
) == 0) ufoFatal("not a handle");
5232 UfoHandle
*hh
= ufoGetHandle(hx
);
5233 if (hh
== NULL
) ufoFatal("invalid handle");
5234 if (used
> hh
->size
) ufoFatal("handle used %u out of range (%u)", used
, hh
->size
);
5238 #define POP_PREPARE_HANDLE() \
5239 const uint32_t hx = ufoPop(); \
5240 uint32_t idx = ufoPop(); \
5241 if ((hx & UFO_ADDR_HANDLE_BIT) == 0) ufoFatal("not a handle"); \
5242 if (idx > 0x1fffffffU - UFO_ADDR_HANDLE_OFS_MASK) ufoFatal("handle index %u out of range", idx); \
5243 idx += (hx & UFO_ADDR_HANDLE_OFS_MASK); \
5244 UfoHandle *hh = ufoGetHandle(hx); \
5245 if (hh == NULL) ufoFatal("invalid handle")
5248 // ( idx hx -- value )
5249 UFWORD(PAR_HANDLE_LOAD_BYTE
) {
5250 POP_PREPARE_HANDLE();
5251 if (idx
>= hh
->size
) ufoFatal("handle index %u out of range (%u)", idx
, hh
->size
);
5252 ufoPush(hh
->data
[idx
]);
5256 // ( idx hx -- value )
5257 UFWORD(PAR_HANDLE_LOAD_WORD
) {
5258 POP_PREPARE_HANDLE();
5259 if (idx
>= hh
->size
|| hh
->size
- idx
< 2u) {
5260 ufoFatal("handle index %u out of range (%u)", idx
, hh
->size
);
5262 #ifdef UFO_FAST_MEM_ACCESS
5263 ufoPush(*(const uint16_t *)(hh
->data
+ idx
));
5265 uint32_t res
= hh
->data
[idx
];
5266 res
|= hh
->data
[idx
+ 1u] << 8;
5272 // ( idx hx -- value )
5273 UFWORD(PAR_HANDLE_LOAD_CELL
) {
5274 POP_PREPARE_HANDLE();
5275 if (idx
>= hh
->size
|| hh
->size
- idx
< 4u) {
5276 ufoFatal("handle index %u out of range (%u)", idx
, hh
->size
);
5278 #ifdef UFO_FAST_MEM_ACCESS
5279 ufoPush(*(const uint32_t *)(hh
->data
+ idx
));
5281 uint32_t res
= hh
->data
[idx
];
5282 res
|= hh
->data
[idx
+ 1u] << 8;
5283 res
|= hh
->data
[idx
+ 2u] << 16;
5284 res
|= hh
->data
[idx
+ 3u] << 24;
5290 // ( value idx hx -- value )
5291 UFWORD(PAR_HANDLE_STORE_BYTE
) {
5292 POP_PREPARE_HANDLE();
5293 const uint32_t value
= ufoPop();
5294 if (idx
>= hh
->size
) ufoFatal("handle index %u out of range (%u)", idx
, hh
->size
);
5295 hh
->data
[idx
] = value
;
5299 // ( value idx hx -- )
5300 UFWORD(PAR_HANDLE_STORE_WORD
) {
5301 POP_PREPARE_HANDLE();
5302 const uint32_t value
= ufoPop();
5303 if (idx
>= hh
->size
|| hh
->size
- idx
< 2u) {
5304 ufoFatal("handle index %u out of range (%u)", idx
, hh
->size
);
5306 #ifdef UFO_FAST_MEM_ACCESS
5307 *(uint16_t *)(hh
->data
+ idx
) = (uint16_t)value
;
5309 hh
->data
[idx
] = (uint8_t)value
;
5310 hh
->data
[idx
+ 1u] = (uint8_t)(value
>> 8);
5315 // ( value idx hx -- )
5316 UFWORD(PAR_HANDLE_STORE_CELL
) {
5317 POP_PREPARE_HANDLE();
5318 const uint32_t value
= ufoPop();
5319 if (idx
>= hh
->size
|| hh
->size
- idx
< 4u) {
5320 ufoFatal("handle index %u out of range (%u)", idx
, hh
->size
);
5322 #ifdef UFO_FAST_MEM_ACCESS
5323 *(uint32_t *)(hh
->data
+ idx
) = value
;
5325 hh
->data
[idx
] = (uint8_t)value
;
5326 hh
->data
[idx
+ 1u] = (uint8_t)(value
>> 8);
5327 hh
->data
[idx
+ 2u] = (uint8_t)(value
>> 16);
5328 hh
->data
[idx
+ 3u] = (uint8_t)(value
>> 24);
5334 // ( addr count -- stx )
5335 UFWORD(PAR_HANDLE_LOAD_FILE
) {
5336 uint32_t count
= ufoPop();
5337 uint32_t addr
= ufoPop();
5339 if ((count
& ((uint32_t)1<<31)) != 0) ufoFatal("invalid file name");
5341 uint8_t *dest
= (uint8_t *)ufoFNameBuf
;
5342 while (count
!= 0 && dest
< (uint8_t *)ufoFNameBuf
+ sizeof(ufoFNameBuf
)) {
5343 uint8_t ch
= ufoImgGetU8Ext(addr
);
5345 dest
+= 1u; addr
+= 1u; count
-= 1u;
5347 if (dest
== (uint8_t *)ufoFNameBuf
+ sizeof(ufoFNameBuf
)) ufoFatal("file name too long");
5350 if (*ufoFNameBuf
== 0) ufoFatal("empty file name");
5352 char *ffn
= ufoCreateIncludeName(ufoFNameBuf
, 0/*system*/, ufoLastIncPath
);
5354 FILE *fl
= fopen(ffn
, "rb");
5356 FILE *fl
= fopen(ffn
, "r");
5359 ufoFatal("file '%s' not found", ffn
);
5362 if (fseek(fl
, 0, SEEK_END
) != 0) {
5364 ufoFatal("seek error in file '%s'", ffn
);
5367 long sz
= ftell(fl
);
5368 if (sz
< 0 || sz
>= 1024 * 1024 * 64) {
5370 ufoFatal("tell error in file '%s' (or too big)", ffn
);
5373 if (fseek(fl
, 0, SEEK_SET
) != 0) {
5375 ufoFatal("seek error in file '%s'", ffn
);
5378 UfoHandle
*hh
= ufoAllocHandle(0);
5380 hh
->data
= malloc((uint32_t)sz
);
5381 if (hh
->data
== NULL
) {
5383 ufoFatal("out of memory for file '%s'", ffn
);
5385 hh
->size
= (uint32_t)sz
;
5386 if (fread(hh
->data
, (uint32_t)sz
, 1, fl
) != 1) {
5388 ufoFatal("error reading file '%s'", ffn
);
5394 ufoPush(hh
->ufoHandle
);
5398 // ////////////////////////////////////////////////////////////////////////// //
5402 // DEBUG:(DECOMPILE-CFA)
5404 UFWORD(DEBUG_DECOMPILE_CFA
) {
5405 const uint32_t cfa
= ufoPop();
5406 ufoDecompileWord(cfa
);
5412 ufoPush((uint32_t)ufo_get_msecs());
5415 // this is called by INTERPRET when it is out of input stream
5416 UFWORD(UFO_INTERPRET_FINISHED_ACTION
) {
5422 UFWORD(MT_NEW_STATE
) {
5423 UfoState
*st
= ufoNewState(ufoPop());
5424 ufoInitStateUserVars(st
, 1);
5430 UFWORD(MT_FREE_STATE
) {
5431 UfoState
*st
= ufoFindState(ufoPop());
5432 if (st
== NULL
) ufoFatal("cannot free unknown state");
5433 if (st
== ufoCurrState
) ufoFatal("cannot free current state");
5437 // MTASK:STATE-NAME@
5438 // ( stid -- addr count )
5440 UFWORD(MT_GET_STATE_NAME
) {
5441 UfoState
*st
= ufoFindState(ufoPop());
5442 if (st
== NULL
) ufoFatal("unknown state");
5444 uint32_t addr
= ufoPop();
5446 while (st
->name
[count
] != 0) {
5447 ufoImgPutU8Ext(addr
+ count
, ((const unsigned char *)st
->name
)[count
]);
5450 ufoImgPutU8Ext(addr
+ count
, 0);
5455 // MTASK:STATE-NAME!
5456 // ( addr count stid -- )
5457 UFWORD(MT_SET_STATE_NAME
) {
5458 UfoState
*st
= ufoFindState(ufoPop());
5459 if (st
== NULL
) ufoFatal("unknown state");
5460 uint32_t count
= ufoPop();
5461 uint32_t addr
= ufoPop();
5462 if ((count
& ((uint32_t)1 << 31)) == 0) {
5463 if (count
> UFO_MAX_TASK_NAME
) ufoFatal("task name too long");
5464 for (uint32_t f
= 0; f
< count
; f
+= 1u) {
5465 ((unsigned char *)st
->name
)[f
] = ufoImgGetU8Ext(addr
+ f
);
5467 st
->name
[count
] = 0;
5471 // MTASK:STATE-FIRST
5473 UFWORD(MT_STATE_FIRST
) {
5475 while (fidx
!= (uint32_t)(UFO_MAX_STATES
/32) && ufoStateUsedBitmap
[fidx
] == 0) fidx
+= 1u;
5476 // there should be at least one allocated state
5477 ufo_assert(fidx
!= (uint32_t)(UFO_MAX_STATES
/32));
5478 uint32_t bmp
= ufoStateUsedBitmap
[fidx
];
5480 while ((bmp
& 0x01) == 0) { fidx
+= 1u; bmp
>>= 1; }
5485 // ( stid -- stid / 0 )
5486 UFWORD(MT_STATE_NEXT
) {
5487 uint32_t stid
= ufoPop();
5488 if (stid
!= 0 && stid
< (uint32_t)(UFO_MAX_STATES
/32)) {
5489 // it is already incremented for us, yay!
5490 uint32_t fidx
= stid
/ 32u;
5491 uint8_t fofs
= stid
& 0x1f;
5492 while (fidx
< (uint32_t)(UFO_MAX_STATES
/32)) {
5493 const uint32_t bmp
= ufoStateUsedBitmap
[fidx
];
5495 while (fofs
!= 32u) {
5496 if ((bmp
& ((uint32_t)1 << (fofs
& 0x1f))) == 0) fofs
+= 1u;
5499 ufoPush(fidx
* 32u + fofs
+ 1u);
5503 fidx
+= 1u; fofs
= 0;
5511 // ( ... argc stid -- )
5512 UFWORD(MT_YIELD_TO
) {
5513 UfoState
*st
= ufoFindState(ufoPop());
5514 if (st
== NULL
) ufoFatal("cannot yield to unknown state");
5515 //if (st == ufoDebuggerState) ufoFatal("cannot yield to debugger"); // why not?
5516 const uint32_t argc
= ufoPop();
5517 if (argc
> 256) ufoFatal("too many YIELD-TO arguments");
5518 UfoState
*curst
= ufoCurrState
;
5519 if (st
!= ufoCurrState
) {
5520 for (uint32_t f
= 0; f
< argc
; f
+= 1) {
5521 ufoCurrState
= curst
;
5522 const uint32_t n
= ufoPop();
5526 ufoCurrState
= curst
; // we need to use API call to switch states
5528 ufoSwitchToState(st
); // always use API call for this!
5533 // MTASK:SET-SELF-AS-DEBUGGER
5535 UFWORD(MT_SET_SELF_AS_DEBUGGER
) {
5536 ufoDebuggerState
= ufoCurrState
;
5541 // debugger task receives debugge stid on the data stack, and -1 as argc.
5542 // i.e. debugger stask is: ( -1 old-stid )
5543 UFWORD(MT_DEBUGGER_BP
) {
5544 if (ufoDebuggerState
!= NULL
&& ufoCurrState
!= ufoDebuggerState
) {
5545 UfoState
*st
= ufoCurrState
;
5546 ufoSwitchToState(ufoDebuggerState
); // always use API call for this!
5553 // MTASK:DEBUGGER-RESUME
5555 UFWORD(MT_RESUME_DEBUGEE
) {
5556 if (ufoCurrState
!= ufoDebuggerState
) ufoFatal("cannot resume from non-debugger");
5557 UfoState
*st
= ufoFindState(ufoPop());
5558 if (st
== NULL
) ufoFatal("cannot yield to unknown state");
5559 if (st
== ufoCurrState
) ufoFatal("cannot resume into debugger itself");
5560 ufoSwitchToState(st
); // always use API call for this!
5564 // MTASK:DEBUGGER-SINGLE-STEP
5566 UFWORD(MT_SINGLE_STEP_DEBUGEE
) {
5567 if (ufoCurrState
!= ufoDebuggerState
) ufoFatal("cannot resume from non-debugger");
5568 UfoState
*st
= ufoFindState(ufoPop());
5569 if (st
== NULL
) ufoFatal("cannot yield to unknown state");
5570 if (st
== ufoCurrState
) ufoFatal("cannot resume into debugger itself");
5571 ufoSwitchToState(st
); // always use API call for this!
5572 ufoSingleStep
= 2; // it will be decremented after returning from this word
5577 UFWORD(MT_STATE_IP_GET
) {
5578 UfoState
*st
= ufoFindState(ufoPop());
5579 if (st
== NULL
) ufoFatal("unknown state");
5585 UFWORD(MT_STATE_IP_SET
) {
5586 UfoState
*st
= ufoFindState(ufoPop());
5587 if (st
== NULL
) ufoFatal("unknown state");
5593 UFWORD(MT_STATE_REGA_GET
) {
5594 UfoState
*st
= ufoFindState(ufoPop());
5595 if (st
== NULL
) ufoFatal("unknown state");
5601 UFWORD(MT_STATE_REGA_SET
) {
5602 UfoState
*st
= ufoFindState(ufoPop());
5603 if (st
== NULL
) ufoFatal("unknown state");
5604 st
->regA
= ufoPop();
5607 // MTASK:STATE-USER@
5608 // ( addr stid -- value )
5609 UFWORD(MT_STATE_USER_GET
) {
5610 UfoState
*st
= ufoFindState(ufoPop());
5611 if (st
== NULL
) ufoFatal("unknown state");
5612 uint32_t addr
= ufoPop();
5613 if ((addr
& UFO_ADDR_TEMP_BIT
) != 0 && (addr
& UFO_ADDR_TEMP_MASK
) + 3u < st
->imageTempSize
) {
5614 uint32_t v
= *(const uint32_t *)((const uint8_t *)st
->imageTemp
+ (addr
& UFO_ADDR_TEMP_MASK
));
5617 ufoFatal("invalid user area address");
5621 // MTASK:STATE-USER!
5622 // ( value addr stid -- )
5623 UFWORD(MT_STATE_USER_SET
) {
5624 UfoState
*st
= ufoFindState(ufoPop());
5625 if (st
== NULL
) ufoFatal("unknown state");
5626 uint32_t addr
= ufoPop();
5627 uint32_t value
= ufoPop();
5628 if ((addr
& UFO_ADDR_TEMP_BIT
) != 0 && (addr
& UFO_ADDR_TEMP_MASK
) + 3u < st
->imageTempSize
) {
5629 *(uint32_t *)((const uint8_t *)st
->imageTemp
+ (addr
& UFO_ADDR_TEMP_MASK
)) = value
;
5631 ufoFatal("invalid user area address");
5635 // MTASK:STATE-RPOPCFA@
5637 UFWORD(MT_STATE_RPOPCFA_GET
) {
5638 UfoState
*st
= ufoFindState(ufoPop());
5639 if (st
== NULL
) ufoFatal("unknown state");
5640 ufoPush(st
->vmRPopCFA
);
5643 // MTASK:STATE-RPOPCFA!
5645 UFWORD(MT_STATE_RPOPCFA_SET
) {
5646 UfoState
*st
= ufoFindState(ufoPop());
5647 if (st
== NULL
) ufoFatal("unknown state");
5648 st
->vmRPopCFA
= ufoPop();
5651 // MTASK:ACTIVE-STATE
5653 UFWORD(MT_ACTIVE_STATE
) {
5654 ufoPush(ufoCurrState
->id
);
5657 // MTASK:YIELDED-FROM
5659 UFWORD(MT_YIELDED_FROM
) {
5660 if (ufoYieldedState
!= NULL
) {
5661 ufoPush(ufoYieldedState
->id
);
5668 // ( stid -- depth )
5669 UFWORD(MT_DSTACK_DEPTH_GET
) {
5670 UfoState
*st
= ufoFindState(ufoPop());
5671 if (st
== NULL
) ufoFatal("unknown state");
5676 // ( stid -- depth )
5677 UFWORD(MT_RSTACK_DEPTH_GET
) {
5678 UfoState
*st
= ufoFindState(ufoPop());
5679 if (st
== NULL
) ufoFatal("unknown state");
5680 ufoPush(st
->RP
- st
->RPTop
);
5686 UfoState
*st
= ufoFindState(ufoPop());
5687 if (st
== NULL
) ufoFatal("unknown state");
5693 UFWORD(MT_LBP_GET
) {
5694 UfoState
*st
= ufoFindState(ufoPop());
5695 if (st
== NULL
) ufoFatal("unknown state");
5700 // ( depth stid -- )
5701 UFWORD(MT_DSTACK_DEPTH_SET
) {
5702 UfoState
*st
= ufoFindState(ufoPop());
5703 if (st
== NULL
) ufoFatal("unknown state");
5704 uint32_t idx
= ufoPop();
5705 if (idx
>= UFO_DSTACK_SIZE
) ufoFatal("invalid stack index %u (%u)", idx
, UFO_DSTACK_SIZE
);
5710 // ( stid -- depth )
5711 UFWORD(MT_RSTACK_DEPTH_SET
) {
5712 UfoState
*st
= ufoFindState(ufoPop());
5713 if (st
== NULL
) ufoFatal("unknown state");
5714 uint32_t idx
= ufoPop();
5715 const uint32_t left
= UFO_RSTACK_SIZE
- st
->RPTop
;
5716 if (idx
>= left
) ufoFatal("invalid stack index %u (%u)", idx
, left
);
5717 st
->RP
= st
->RPTop
+ idx
;
5723 UfoState
*st
= ufoFindState(ufoPop());
5724 if (st
== NULL
) ufoFatal("unknown state");
5730 UFWORD(MT_LBP_SET
) {
5731 UfoState
*st
= ufoFindState(ufoPop());
5732 if (st
== NULL
) ufoFatal("unknown state");
5737 // ( idx stid -- value )
5738 UFWORD(MT_DSTACK_LOAD
) {
5739 UfoState
*st
= ufoFindState(ufoPop());
5740 if (st
== NULL
) ufoFatal("unknown state");
5741 uint32_t idx
= ufoPop();
5742 if (idx
>= st
->SP
) ufoFatal("invalid stack index %u (%u)", idx
, st
->SP
);
5743 ufoPush(st
->dStack
[st
->SP
- idx
- 1u]);
5747 // ( idx stid -- value )
5748 UFWORD(MT_RSTACK_LOAD
) {
5749 UfoState
*st
= ufoFindState(ufoPop());
5750 if (st
== NULL
) ufoFatal("unknown state");
5751 uint32_t idx
= ufoPop();
5752 if (idx
>= st
->RP
- st
->RPTop
) ufoFatal("invalid stack index %u (%u)", idx
, st
->RP
- st
->RPTop
);
5753 ufoPush(st
->dStack
[st
->RP
- idx
- 1u]);
5757 // ( idx stid -- value )
5758 UFWORD(MT_LSTACK_LOAD
) {
5759 UfoState
*st
= ufoFindState(ufoPop());
5760 if (st
== NULL
) ufoFatal("unknown state");
5761 uint32_t idx
= ufoPop();
5762 if (idx
>= st
->LP
) ufoFatal("invalid lstack index %u (%u)", idx
, st
->LP
);
5763 ufoPush(st
->lStack
[st
->LP
- idx
- 1u]);
5767 // ( value idx stid -- )
5768 UFWORD(MT_DSTACK_STORE
) {
5769 UfoState
*st
= ufoFindState(ufoPop());
5770 if (st
== NULL
) ufoFatal("unknown state");
5771 uint32_t idx
= ufoPop();
5772 uint32_t value
= ufoPop();
5773 if (idx
>= st
->SP
) ufoFatal("invalid stack index %u (%u)", idx
, st
->SP
);
5774 st
->dStack
[st
->SP
- idx
- 1u] = value
;
5778 // ( value idx stid -- )
5779 UFWORD(MT_RSTACK_STORE
) {
5780 UfoState
*st
= ufoFindState(ufoPop());
5781 if (st
== NULL
) ufoFatal("unknown state");
5782 uint32_t idx
= ufoPop();
5783 uint32_t value
= ufoPop();
5784 if (idx
>= st
->RP
- st
->RPTop
) ufoFatal("invalid stack index %u (%u)", idx
, st
->RP
- st
->RPTop
);
5785 st
->dStack
[st
->RP
- idx
- 1u] = value
;
5789 // ( value idx stid -- )
5790 UFWORD(MT_LSTACK_STORE
) {
5791 UfoState
*st
= ufoFindState(ufoPop());
5792 if (st
== NULL
) ufoFatal("unknown state");
5793 uint32_t idx
= ufoPop();
5794 uint32_t value
= ufoPop();
5795 if (idx
>= st
->LP
) ufoFatal("invalid stack index %u (%u)", idx
, st
->LP
);
5796 st
->dStack
[st
->LP
- idx
- 1u] = value
;
5800 #include "urforth_tty.c"
5803 // ////////////////////////////////////////////////////////////////////////// //
5804 // initial dictionary definitions
5809 #define UFWORD(name_) do { \
5810 const uint32_t xcfa_ = ufoCFAsUsed; \
5811 ufo_assert(xcfa_ < UFO_MAX_NATIVE_CFAS); \
5812 ufoForthCFAs[xcfa_] = &ufoWord_##name_; \
5814 ufoDefineNative(""#name_, xcfa_, 0); \
5817 #define UFWORDX(strname_,name_) do { \
5818 const uint32_t xcfa_ = ufoCFAsUsed; \
5819 ufo_assert(xcfa_ < UFO_MAX_NATIVE_CFAS); \
5820 ufoForthCFAs[xcfa_] = &ufoWord_##name_; \
5822 ufoDefineNative(strname_, xcfa_, 0); \
5825 #define UFWORD_IMM(name_) do { \
5826 const uint32_t xcfa_ = ufoCFAsUsed; \
5827 ufo_assert(xcfa_ < UFO_MAX_NATIVE_CFAS); \
5828 ufoForthCFAs[xcfa_] = &ufoWord_##name_; \
5830 ufoDefineNative(""#name_, xcfa_, 1); \
5833 #define UFWORDX_IMM(strname_,name_) do { \
5834 const uint32_t xcfa_ = ufoCFAsUsed; \
5835 ufo_assert(xcfa_ < UFO_MAX_NATIVE_CFAS); \
5836 ufoForthCFAs[xcfa_] = &ufoWord_##name_; \
5838 ufoDefineNative(strname_, xcfa_, 1); \
5841 #define UFC(name_) ufoImgEmitU32_NoInline(ufoFindWordChecked(name_))
5844 //==========================================================================
5846 // ufoFindWordChecked
5848 //==========================================================================
5849 UFO_DISABLE_INLINE
uint32_t ufoFindWordChecked (const char *wname
) {
5850 const uint32_t cfa
= ufoFindWord(wname
);
5851 if (cfa
== 0) ufoFatal("word '%s' not found", wname
);
5856 //==========================================================================
5860 // get "FORTH" vocid
5862 //==========================================================================
5863 uint32_t ufoGetForthVocId (void) {
5864 return ufoForthVocId
;
5868 //==========================================================================
5870 // ufoVocSetOnlyDefs
5872 //==========================================================================
5873 void ufoVocSetOnlyDefs (uint32_t vocid
) {
5874 ufoImgPutU32(ufoAddrCurrent
, vocid
);
5875 ufoImgPutU32(ufoAddrContext
, vocid
);
5879 //==========================================================================
5883 // return voc PFA (vocid)
5885 //==========================================================================
5886 uint32_t ufoCreateVoc (const char *wname
, uint32_t parentvocid
, uint32_t flags
) {
5887 // create wordlist struct
5888 // typeid, used by Forth code (structs and such)
5889 ufoImgEmitU32(0); // typeid
5890 // vocid points here, to "LATEST-LFA"
5891 const uint32_t vocid
= UFO_GET_DP();
5892 //fprintf(stderr, "NEW VOCID (%s): 0x%08x\n", wname, vocid);
5893 ufoImgEmitU32(0); // latest
5894 const uint32_t vlink
= UFO_GET_DP();
5895 if ((vocid
& UFO_ADDR_TEMP_BIT
) == 0) {
5896 ufoImgEmitU32(ufoImgGetU32(ufoAddrVocLink
)); // voclink
5897 ufoImgPutU32(ufoAddrVocLink
, vlink
); // update voclink
5902 ufoImgEmitU32(parentvocid
); // parent
5903 const uint32_t hdraddr
= UFO_GET_DP();
5904 ufoImgEmitU32(0); // word header
5905 // create empty hash table
5906 for (int f
= 0; f
< UFO_HASHTABLE_SIZE
; f
+= 1) ufoImgEmitU32(0);
5907 // update CONTEXT and CURRENT if this is the first wordlist ever
5908 if (ufoImgGetU32(ufoAddrContext
) == 0) {
5909 ufoImgPutU32(ufoAddrContext
, vocid
);
5911 if (ufoImgGetU32(ufoAddrCurrent
) == 0) {
5912 ufoImgPutU32(ufoAddrCurrent
, vocid
);
5914 // create word header
5915 if (wname
!= NULL
&& wname
[0] != 0) {
5917 uint32_t flags = ufoImgGetU32(ufoAddrNewWordFlags);
5919 //UFW_FLAG_IMMEDIATE|
5921 //UFW_FLAG_NORETURN|
5927 flags |= UFW_FLAG_VOCAB;
5929 flags
&= 0xffffff00u
;
5930 flags
|= UFW_FLAG_VOCAB
;
5931 ufoCreateWordHeader(wname
, flags
);
5932 const uint32_t cfa
= UFO_GET_DP();
5933 ufoImgEmitU32(ufoDoVocCFA
); // cfa
5934 ufoImgEmitU32(vocid
); // pfa
5935 // update vocab header pointer
5936 const uint32_t lfa
= UFO_CFA_TO_LFA(cfa
);
5937 ufoImgPutU32(hdraddr
, UFO_LFA_TO_NFA(lfa
));
5938 #ifdef UFO_DEBUG_DUMP_NEW_HEADERS
5939 ufoDumpWordHeader(lfa
);
5946 //==========================================================================
5950 //==========================================================================
5951 static void ufoSetLatestArgs (uint32_t warg
) {
5952 const uint32_t curr
= ufoImgGetU32(ufoAddrCurrent
);
5953 const uint32_t lfa
= ufoImgGetU32(curr
);
5954 const uint32_t nfa
= UFO_LFA_TO_NFA(lfa
);
5955 uint32_t flags
= ufoImgGetU32(nfa
);
5956 //fprintf(stderr, "OLD FLAGS: 0x%08x\n", flags);
5957 flags
&= ~UFW_WARG_MASK
;
5958 flags
|= warg
& UFW_WARG_MASK
;
5959 //fprintf(stderr, "NEW FLAGS: 0x%08x\n", flags);
5960 ufoImgPutU32(nfa
, flags
);
5961 #ifdef UFO_DEBUG_DUMP_NEW_HEADERS
5962 ufoDumpWordHeader(lfa
);
5967 //==========================================================================
5971 //==========================================================================
5972 static void ufoDefineNative (const char *wname
, uint32_t cfaidx
, int immed
) {
5973 cfaidx
|= UFO_ADDR_CFA_BIT
;
5974 uint32_t flags
= ufoImgGetU32(ufoAddrNewWordFlags
);
5976 //UFW_FLAG_IMMEDIATE|
5978 //UFW_FLAG_NORETURN|
5984 if (immed
) flags
|= UFW_FLAG_IMMEDIATE
;
5985 ufoCreateWordHeader(wname
, flags
);
5986 ufoImgEmitU32(cfaidx
);
5990 //==========================================================================
5992 // ufoDefineConstant
5994 //==========================================================================
5995 static void ufoDefineConstant (const char *name
, uint32_t value
) {
5996 ufoDefineNative(name
, ufoDoConstCFA
, 0);
5997 ufoImgEmitU32(value
);
6001 //==========================================================================
6005 //==========================================================================
6006 static void ufoDefineUserVar (const char *name
, uint32_t addr
) {
6007 ufoDefineNative(name
, ufoDoUserVariableCFA
, 0);
6008 ufoImgEmitU32(addr
);
6012 //==========================================================================
6016 //==========================================================================
6018 static void ufoDefineVar (const char *name, uint32_t value) {
6019 ufoDefineNative(name, ufoDoVarCFA, 0);
6020 ufoImgEmitU32(value);
6025 //==========================================================================
6029 //==========================================================================
6030 static void ufoDefineDefer (const char *name
, uint32_t value
) {
6031 ufoDefineNative(name
, ufoDoDeferCFA
, 0);
6032 ufoImgEmitU32(value
);
6036 //==========================================================================
6040 //==========================================================================
6041 static void ufoHiddenWords (void) {
6042 const uint32_t flags
= ufoImgGetU32(ufoAddrNewWordFlags
);
6043 ufoImgPutU32(ufoAddrNewWordFlags
, flags
| UFW_FLAG_HIDDEN
);
6047 //==========================================================================
6051 //==========================================================================
6052 static void ufoPublicWords (void) {
6053 const uint32_t flags
= ufoImgGetU32(ufoAddrNewWordFlags
);
6054 ufoImgPutU32(ufoAddrNewWordFlags
, flags
& ~UFW_FLAG_HIDDEN
);
6058 //==========================================================================
6062 //==========================================================================
6063 static void ufoDefineForth (const char *name
) {
6064 ufoDefineNative(name
, ufoDoForthCFA
, 0);
6068 //==========================================================================
6070 // ufoDefineForthImm
6072 //==========================================================================
6073 static void ufoDefineForthImm (const char *name
) {
6074 ufoDefineNative(name
, ufoDoForthCFA
, 1);
6078 //==========================================================================
6080 // ufoDefineForthHidden
6082 //==========================================================================
6083 static void ufoDefineForthHidden (const char *name
) {
6084 const uint32_t flags
= ufoImgGetU32(ufoAddrNewWordFlags
);
6085 ufoImgPutU32(ufoAddrNewWordFlags
, flags
| UFW_FLAG_HIDDEN
);
6086 ufoDefineNative(name
, ufoDoForthCFA
, 0);
6087 ufoImgPutU32(ufoAddrNewWordFlags
, flags
);
6091 //==========================================================================
6093 // ufoDefineSColonForth
6095 // create word suitable for scattered colon extension
6097 //==========================================================================
6098 static void ufoDefineSColonForth (const char *name
) {
6099 ufoDefineNative(name
, ufoDoForthCFA
, 0);
6100 // placeholder for scattered colon
6101 // it will compile two branches:
6102 // the first branch will jump to the first "..:" word (or over the two branches)
6103 // the second branch is never taken, and works as a pointer to the latest branch addr in the list
6104 // this way, each extension word will simply fix the last branch address, and update list tail
6105 // at the creation time, second branch points to the first branch
6106 UFC("FORTH:(BRANCH)");
6107 const uint32_t xjmp
= UFO_GET_DP();
6109 UFC("FORTH:(BRANCH)"); ufoImgEmitU32(xjmp
);
6110 ufoImgPutU32(xjmp
, UFO_GET_DP());
6114 //==========================================================================
6118 //==========================================================================
6119 UFO_FORCE_INLINE
void ufoDoneForth (void) {
6123 //==========================================================================
6127 // create a new state, its execution will start from the given CFA.
6128 // state is not automatically activated.
6130 //==========================================================================
6131 static UfoState
*ufoNewState (uint32_t cfa
) {
6132 // find free state id
6134 uint32_t bmp
= ufoStateUsedBitmap
[0];
6135 while (fidx
!= (uint32_t)(UFO_MAX_STATES
/32) && bmp
== ~(uint32_t)0) {
6137 bmp
= ufoStateUsedBitmap
[fidx
];
6139 if (fidx
== (uint32_t)(UFO_MAX_STATES
/32)) ufoFatal("too many execution states");
6140 //fprintf(stderr, "NST:000: fidx=%u; bmp=0x%08x\n", fidx, bmp);
6142 while ((bmp
& 0x01) != 0) { fidx
+= 1u; bmp
>>= 1; }
6143 ufo_assert(fidx
< UFO_MAX_STATES
);
6144 ufo_assert((ufoStateUsedBitmap
[fidx
/ 32u] & ((uint32_t)1 << (fidx
& 0x1f))) == 0);
6145 ufo_assert(ufoStateMap
[fidx
] == NULL
);
6146 UfoState
*st
= calloc(1, sizeof(UfoState
));
6147 if (st
== NULL
) ufoFatal("out of memory for states");
6150 st
->rStack
[0] = 0xdeadf00d; // dummy value
6151 st
->rStack
[1] = cfa
;
6153 ufoStateMap
[fidx
] = st
;
6154 ufoStateUsedBitmap
[fidx
/ 32u] |= ((uint32_t)1 << (fidx
& 0x1f));
6155 //fprintf(stderr, "NST: fidx=%u; 0x%08x\n", fidx, ufoStateUsedBitmap[fidx / 32u]);
6160 //==========================================================================
6164 // free all memory used for the state, remove it from state list.
6165 // WARNING! never free current state!
6167 //==========================================================================
6168 static void ufoFreeState (UfoState
*st
) {
6170 if (st
== ufoCurrState
) ufoFatal("cannot free active state");
6171 if (ufoYieldedState
== st
) ufoYieldedState
= NULL
;
6172 if (ufoDebuggerState
== st
) ufoDebuggerState
= NULL
;
6173 const uint32_t fidx
= st
->id
- 1u;
6174 //fprintf(stderr, "FST: fidx=%u; 0x%08x\n", fidx, ufoStateUsedBitmap[fidx / 32u]);
6175 ufo_assert(fidx
< UFO_MAX_STATES
);
6176 ufo_assert((ufoStateUsedBitmap
[fidx
/ 32u] & (1u << (fidx
& 0x1f))) != 0);
6177 ufo_assert(ufoStateMap
[fidx
] == st
);
6178 // free default TIB handle
6179 UfoState
*oldst
= ufoCurrState
;
6181 const uint32_t tib
= ufoImgGetU32(ufoAddrDefTIB
);
6182 if ((tib
& UFO_ADDR_TEMP_BIT
) != 0) {
6183 UfoHandle
*tibh
= ufoGetHandle(tib
);
6184 if (tibh
!= NULL
) ufoFreeHandle(tibh
);
6186 ufoCurrState
= oldst
;
6188 if (st
->imageTemp
!= NULL
) free(st
->imageTemp
);
6190 ufoStateMap
[fidx
] = NULL
;
6191 ufoStateUsedBitmap
[fidx
/ 32u] &= ~((uint32_t)1 << (fidx
& 0x1f));
6196 //==========================================================================
6200 //==========================================================================
6201 static UfoState
*ufoFindState (uint32_t stid
) {
6202 UfoState
*res
= NULL
;
6203 if (stid
!= 0 && stid
<= UFO_MAX_STATES
) {
6205 res
= ufoStateMap
[stid
];
6207 ufo_assert((ufoStateUsedBitmap
[stid
/ 32u] & (1u << (stid
& 0x1f))) != 0);
6208 ufo_assert(res
->id
== stid
+ 1u);
6210 ufo_assert((ufoStateUsedBitmap
[stid
/ 32u] & (1u << (stid
& 0x1f))) == 0);
6217 //==========================================================================
6221 //==========================================================================
6222 static void ufoSwitchToState (UfoState
*newst
) {
6223 ufo_assert(newst
!= NULL
);
6224 if (newst
!= ufoCurrState
) {
6225 ufoCurrState
= newst
;
6231 //==========================================================================
6235 //==========================================================================
6236 UFO_DISABLE_INLINE
void ufoReset (void) {
6237 if (ufoCurrState
== NULL
) ufoFatal("no active execution state");
6239 ufoSP
= 0; ufoRP
= 0;
6240 ufoLP
= 0; ufoLBP
= 0;
6243 ufoVMStop
= 0; ufoVMAbort
= 0;
6247 ufoInitStateUserVars(ufoCurrState
, 0);
6248 ufoImgPutU32(ufoAddrSTATE
, 0);
6249 ufoImgPutU32(ufoAddrRedefineWarning
, UFO_REDEF_WARN_NORMAL
);
6252 ufoImgPutU32(ufoAddrDPTemp
, 0);
6254 ufoImgPutU32(ufoAddrNewWordFlags
, 0);
6255 ufoVocSetOnlyDefs(ufoForthVocId
);
6259 //==========================================================================
6263 // compile string literal, the same as QUOTE_IMM
6265 //==========================================================================
6266 static void ufoCompileStrLit (const char *str
) {
6267 if (str
== NULL
) str
= "";
6268 const size_t slen
= strlen(str
);
6269 if (slen
> 255) ufoFatal("string literal too long");
6270 UFC("FORTH:(STRLIT8)");
6271 ufoImgEmitU8((uint8_t)slen
);
6272 for (size_t f
= 0; f
< slen
; f
+= 1) {
6273 ufoImgEmitU8(((const unsigned char *)str
)[f
]);
6280 //==========================================================================
6284 //==========================================================================
6285 static __attribute__((unused
)) void ufoCompileLit (uint32_t value
) {
6287 ufoImgEmitU32(value
);
6291 //==========================================================================
6295 //==========================================================================
6296 UFO_FORCE_INLINE
uint32_t ufoMarkFwd (void) {
6297 const uint32_t res
= UFO_GET_DP();
6303 //==========================================================================
6307 //==========================================================================
6308 UFO_FORCE_INLINE
void ufoResolveFwd (uint32_t jaddr
) {
6309 ufoImgPutU32(jaddr
, UFO_GET_DP());
6313 //==========================================================================
6317 //==========================================================================
6318 UFO_FORCE_INLINE
uint32_t ufoMarkBwd (void) {
6319 return UFO_GET_DP();
6323 //==========================================================================
6327 //==========================================================================
6328 UFO_FORCE_INLINE
void ufoResolveBwd (uint32_t jaddr
) {
6329 ufoImgEmitU32(jaddr
);
6333 //==========================================================================
6335 // ufoDefineInterpret
6337 // define "INTERPRET" in Forth
6339 //==========================================================================
6340 UFO_DISABLE_INLINE
void ufoDefineInterpret (void) {
6341 // skip comments, parse name, refilling lines if necessary
6342 ufoDefineForthHidden("(INTERPRET-PARSE-NAME)");
6343 const uint32_t label_ipn_again
= ufoMarkBwd();
6344 UFC("TRUE"); UFC("(PARSE-SKIP-COMMENTS)");
6347 UFC("FORTH:(TBRANCH)"); const uint32_t label_ipn_exit_fwd
= ufoMarkFwd();
6350 UFC("FORTH:(TBRANCH)"); ufoResolveBwd(label_ipn_again
);
6352 UFC("FORTH:STATE"); UFC("@");
6353 ufoCompileStrLit("unexpected end of file"); UFC("?ERROR");
6354 UFC("FORTH:(UFO-INTERPRET-FINISHED)");
6355 // patch the jump above
6356 ufoResolveFwd(label_ipn_exit_fwd
);
6357 UFC("FORTH:(EXIT)");
6359 //ufoDecompileWord(ufoFindWordChecked("(INTERPRET-PARSE-NAME)"));
6361 ufoDefineForth("INTERPRET");
6362 const uint32_t label_it_again
= ufoMarkBwd();
6363 UFC("FORTH:(INTERPRET-PARSE-NAME)");
6364 // try defered checker
6365 // ( addr count FALSE -- addr count FALSE / TRUE )
6366 UFC("FALSE"); UFC("(INTERPRET-CHECK-WORD)");
6367 UFC("FORTH:(TBRANCH)"); ufoResolveBwd(label_it_again
);
6368 UFC("2DUP"); UFC("FIND-WORD"); // ( addr count cfa TRUE / addr count FALSE )
6369 UFC("FORTH:(0BRANCH)"); const uint32_t label_it_try_num
= ufoMarkFwd();
6370 UFC("NROT"); UFC("2DROP"); // drop word string
6371 UFC("STATE"); UFC("@");
6372 UFC("FORTH:(0BRANCH)"); const uint32_t label_it_exec_fwd
= ufoMarkFwd();
6373 // compiling; check immediate bit
6374 UFC("DUP"); UFC("CFA->NFA"); UFC("@");
6375 UFC("COMPILER:(WFLAG-IMMEDIATE)"); UFC("AND");
6376 UFC("FORTH:(TBRANCH)"); const uint32_t label_it_exec_imm
= ufoMarkFwd();
6378 UFC("FORTH:COMPILE,");
6379 UFC("FORTH:(BRANCH)"); ufoResolveBwd(label_it_again
);
6381 ufoResolveFwd(label_it_exec_imm
);
6382 ufoResolveFwd(label_it_exec_fwd
);
6384 UFC("FORTH:(BRANCH)"); ufoResolveBwd(label_it_again
);
6385 // not a word, try a number
6386 ufoResolveFwd(label_it_try_num
);
6387 UFC("2DUP"); UFC("TRUE"); UFC("BASE"); UFC("@"); UFC("(BASED-NUMBER)");
6388 // (BASED-NUMBER) ( addr count allowsign? base -- num TRUE / FALSE )
6389 UFC("FORTH:(0BRANCH)"); const uint32_t label_it_num_error
= ufoMarkFwd();
6391 UFC("NROT"); UFC("2DROP"); // drop word string
6392 // do we need to compile it?
6393 UFC("STATE"); UFC("@");
6394 UFC("FORTH:(0BRANCH)"); ufoResolveBwd(label_it_again
);
6395 // compile "(LITERAL)" (do it properly, with "LITCFA")
6396 UFC("FORTH:(LITCFA)"); UFC("FORTH:(LIT)");
6397 UFC("FORTH:COMPILE,"); // compile "(LIT)" CFA
6398 UFC("FORTH:,"); // compile number
6399 UFC("FORTH:(BRANCH)"); ufoResolveBwd(label_it_again
);
6401 ufoResolveFwd(label_it_num_error
);
6402 // ( addr count FALSE -- addr count FALSE / TRUE )
6403 UFC("FALSE"); UFC("(INTERPRET-WORD-NOT-FOUND)");
6404 UFC("FORTH:(TBRANCH)"); ufoResolveBwd(label_it_again
);
6405 UFC("ENDCR"); UFC("SPACE"); UFC("XTYPE");
6406 ufoCompileStrLit(" -- wut?\n"); UFC("TYPE");
6407 ufoCompileStrLit("unknown word");
6410 //ufoDecompileWord(ufoFindWordChecked("INTERPRET"));
6414 //==========================================================================
6418 //==========================================================================
6419 UFO_DISABLE_INLINE
void ufoInitBaseDict (void) {
6420 uint32_t imgAddr
= 0;
6422 // reserve 64 bytes for nothing
6423 for (uint32_t f
= 0; f
< 64; f
+= 1) {
6424 ufoImgPutU8(imgAddr
, 0);
6428 while ((imgAddr
& 3) != 0) {
6429 ufoImgPutU8(imgAddr
, 0);
6434 ufoAddrSTATE
= imgAddr
;
6435 ufoImgPutU32(imgAddr
, 0); imgAddr
+= 4u;
6438 ufoAddrDP
= imgAddr
;
6439 ufoImgPutU32(imgAddr
, 0); imgAddr
+= 4u;
6442 ufoAddrDPTemp
= imgAddr
;
6443 ufoImgPutU32(imgAddr
, 0); imgAddr
+= 4u;
6446 ufoAddrContext
= imgAddr
;
6447 ufoImgPutU32(imgAddr
, 0); imgAddr
+= 4u;
6450 ufoAddrCurrent
= imgAddr
;
6451 ufoImgPutU32(imgAddr
, 0); imgAddr
+= 4u;
6454 ufoAddrLastXFA
= imgAddr
;
6455 ufoImgPutU32(imgAddr
, 0); imgAddr
+= 4u;
6458 ufoAddrVocLink
= imgAddr
;
6459 ufoImgPutU32(imgAddr
, 0); imgAddr
+= 4u;
6462 ufoAddrNewWordFlags
= imgAddr
;
6463 ufoImgPutU32(imgAddr
, UFW_FLAG_PROTECTED
); imgAddr
+= 4u;
6465 // WORD-REDEFINE-WARN-MODE
6466 ufoAddrRedefineWarning
= imgAddr
;
6467 ufoImgPutU32(imgAddr
, UFO_REDEF_WARN_NORMAL
); imgAddr
+= 4u;
6469 ufoImgPutU32(ufoAddrDP
, imgAddr
);
6470 ufoImgPutU32(ufoAddrDPTemp
, 0);
6473 fprintf(stderr
, "INITIAL HERE: 0x%08x (0x%08x)\n", imgAddr
, UFO_GET_DP());
6478 //==========================================================================
6480 // ufoInitStateUserVars
6482 //==========================================================================
6483 static void ufoInitStateUserVars (UfoState
*st
, int initial
) {
6484 ufo_assert(st
!= NULL
);
6485 if (st
->imageTempSize
< 8192u) {
6486 uint32_t *itmp
= realloc(st
->imageTemp
, 8192);
6487 if (itmp
== NULL
) ufoFatal("out of memory for state user area");
6488 st
->imageTemp
= itmp
;
6489 memset((uint8_t *)st
->imageTemp
+ st
->imageTempSize
, 0, 8192u - st
->imageTempSize
);
6490 st
->imageTempSize
= 8192;
6492 st
->imageTemp
[(ufoAddrBASE
& UFO_ADDR_TEMP_MASK
) / 4u] = 10;
6494 st
->imageTemp
[(ufoAddrUserVarUsed
& UFO_ADDR_TEMP_MASK
) / 4u] = ufoAddrUserVarUsed
;
6495 st
->imageTemp
[(ufoAddrDefTIB
& UFO_ADDR_TEMP_MASK
) / 4u] = UFO_DEF_TIB_ADDR
;
6496 st
->imageTemp
[(ufoAddrTIBx
& UFO_ADDR_TEMP_MASK
) / 4u] = UFO_DEF_TIB_ADDR
;
6498 st
->imageTemp
[(ufoAddrTIBx
& UFO_ADDR_TEMP_MASK
) / 4u] =
6499 st
->imageTemp
[(ufoAddrDefTIB
& UFO_ADDR_TEMP_MASK
) / 4u];
6501 st
->imageTemp
[(ufoAddrINx
& UFO_ADDR_TEMP_MASK
) / 4u] = 0;
6505 //==========================================================================
6507 // ufoInitBasicWords
6509 //==========================================================================
6510 UFO_DISABLE_INLINE
void ufoInitBasicWords (void) {
6511 ufoDefineConstant("FALSE", 0);
6512 ufoDefineConstant("TRUE", ufoTrueValue
);
6514 ufoDefineConstant("BL", 32);
6515 ufoDefineConstant("NL", 10);
6518 ufoDefineUserVar("BASE", ufoAddrBASE
);
6519 ufoDefineUserVar("TIB", ufoAddrTIBx
);
6520 ufoDefineUserVar(">IN", ufoAddrINx
);
6521 ufoDefineUserVar("(STD-TIB-ADDR)", ufoAddrDefTIB
);
6522 ufoDefineUserVar("(USER-VAR-USED)", ufoAddrUserVarUsed
);
6523 ufoDefineConstant("(USER-VAR-ADDR)", UFO_ADDR_TEMP_BIT
);
6524 ufoDefineConstant("(USER-VAR-SIZE)", UFO_USER_AREA_SIZE
);
6525 ufoDefineConstant("(USER-TIB)", UFO_DEF_TIB_ADDR
);
6526 ufoDefineConstant("(USER-TIB-SIZE)", UFO_ADDR_HANDLE_OFS_MASK
);
6528 ufoDefineUserVar("STATE", ufoAddrSTATE
);
6529 ufoDefineConstant("CONTEXT", ufoAddrContext
);
6530 ufoDefineConstant("CURRENT", ufoAddrCurrent
);
6533 ufoDefineConstant("(LATEST-XFA)", ufoAddrLastXFA
);
6534 ufoDefineConstant("(VOC-LINK)", ufoAddrVocLink
);
6535 ufoDefineConstant("(NEW-WORD-FLAGS)", ufoAddrNewWordFlags
);
6536 ufoDefineConstant("(ADDR-TEMP-BIT)", UFO_ADDR_TEMP_BIT
);
6537 ufoDefineConstant("(ADDR-CFA-BIT)", UFO_ADDR_CFA_BIT
);
6538 ufoDefineConstant("(ADDR-HANDLE-BIT)", UFO_ADDR_HANDLE_BIT
);
6539 ufoDefineConstant("(MAX-HANDLE-OFS)", UFO_ADDR_HANDLE_OFS_MASK
);
6541 ufoDefineConstant("(PAD-ADDR)", UFO_PAD_ADDR
);
6542 ufoDefineConstant("(#BUF)", UFO_NBUF_ADDR
+ 4u); // reserve room for counter
6543 ufoDefineConstant("(#BUF-SIZE)", UFO_NBUF_SIZE
- 8u);
6545 ufoDefineConstant("(DP)", ufoAddrDP
);
6546 ufoDefineConstant("(DP-TEMP)", ufoAddrDPTemp
);
6549 //UFWORDX("(UFO-BUCKET-STATS)", PAR_UFO_BUCKET_STATS);
6550 UFWORDX("SP0!", SP0_STORE
);
6551 UFWORDX("RP0!", RP0_STORE
);
6553 UFWORDX("PAD", PAD
);
6556 UFWORDX("C@", CPEEK
);
6557 UFWORDX("W@", WPEEK
);
6560 UFWORDX("C!", CPOKE
);
6561 UFWORDX("W!", WPOKE
);
6563 UFWORDX(",", COMMA
);
6564 UFWORDX("C,", CCOMMA
);
6565 UFWORDX("W,", WCOMMA
);
6567 UFWORDX("A>", REGA_LOAD
);
6568 UFWORDX(">A", REGA_STORE
);
6569 UFWORDX("A-SWAP", REGA_SWAP
);
6571 UFWORDX("@A+", PEEK_REGA_IDX
);
6572 UFWORDX("C@A+", CPEEK_REGA_IDX
);
6573 UFWORDX("W@A+", WPEEK_REGA_IDX
);
6575 UFWORDX("!A+", POKE_REGA_IDX
);
6576 UFWORDX("C!A+", CPOKE_REGA_IDX
);
6577 UFWORDX("W!A+", WPOKE_REGA_IDX
);
6580 UFWORDX("(LIT)", PAR_LIT
); ufoSetLatestArgs(UFW_WARG_LIT
);
6581 UFWORDX("(LITCFA)", PAR_LITCFA
); ufoSetLatestArgs(UFW_WARG_CFA
);
6582 UFWORDX("(LITVOCID)", PAR_LITVOCID
); ufoSetLatestArgs(UFW_WARG_VOCID
);
6583 UFWORDX("(STRLIT8)", PAR_STRLIT8
); ufoSetLatestArgs(UFW_WARG_C1STRZ
);
6584 UFWORDX("(EXIT)", PAR_EXIT
);
6586 UFWORDX("(UFO-INTERPRET-FINISHED-ACTION)", UFO_INTERPRET_FINISHED_ACTION
);
6587 ufoDefineDefer("(UFO-INTERPRET-FINISHED)", ufoFindWordChecked("FORTH:(UFO-INTERPRET-FINISHED-ACTION)"));
6589 ufoStrLit8CFA
= ufoFindWordChecked("FORTH:(STRLIT8)");
6591 UFWORDX("(L-ENTER)", PAR_LENTER
); ufoSetLatestArgs(UFW_WARG_LIT
);
6592 UFWORDX("(L-LEAVE)", PAR_LLEAVE
);
6593 UFWORDX("(LOCAL@)", PAR_LOCAL_LOAD
);
6594 UFWORDX("(LOCAL!)", PAR_LOCAL_STORE
);
6596 UFWORDX("(BRANCH)", PAR_BRANCH
); ufoSetLatestArgs(UFW_WARG_BRANCH
);
6597 UFWORDX("(TBRANCH)", PAR_TBRANCH
); ufoSetLatestArgs(UFW_WARG_BRANCH
);
6598 UFWORDX("(0BRANCH)", PAR_0BRANCH
); ufoSetLatestArgs(UFW_WARG_BRANCH
);
6601 UFWORDX("GET-MSECS", GET_MSECS
);
6605 //==========================================================================
6607 // ufoInitBasicCompilerWords
6609 //==========================================================================
6610 UFO_DISABLE_INLINE
void ufoInitBasicCompilerWords (void) {
6611 // create "COMPILER" vocabulary
6612 ufoCompilerVocId
= ufoCreateVoc("COMPILER", 0, UFW_FLAG_PROTECTED
);
6613 ufoVocSetOnlyDefs(ufoCompilerVocId
);
6615 ufoDefineConstant("(CFAIDX-DO-FORTH)", ufoDoForthCFA
);
6616 ufoDefineConstant("(CFAIDX-DO-VAR)", ufoDoVariableCFA
);
6617 ufoDefineConstant("(CFAIDX-DO-VALUE)", ufoDoValueCFA
);
6618 ufoDefineConstant("(CFAIDX-DO-CONST)", ufoDoConstCFA
);
6619 ufoDefineConstant("(CFAIDX-DO-DEFER)", ufoDoDeferCFA
);
6620 ufoDefineConstant("(CFAIDX-DO-VOC)", ufoDoVocCFA
);
6621 ufoDefineConstant("(CFAIDX-DO-CREATE)", ufoDoCreateCFA
);
6622 ufoDefineConstant("(CFAIDX-DO-USER-VAR)", ufoDoUserVariableCFA
);
6624 ufoDefineConstant("(WFLAG-IMMEDIATE)", UFW_FLAG_IMMEDIATE
);
6625 ufoDefineConstant("(WFLAG-SMUDGE)", UFW_FLAG_SMUDGE
);
6626 ufoDefineConstant("(WFLAG-NORETURN)", UFW_FLAG_NORETURN
);
6627 ufoDefineConstant("(WFLAG-HIDDEN)", UFW_FLAG_HIDDEN
);
6628 ufoDefineConstant("(WFLAG-CBLOCK)", UFW_FLAG_CBLOCK
);
6629 ufoDefineConstant("(WFLAG-VOCAB)", UFW_FLAG_VOCAB
);
6630 ufoDefineConstant("(WFLAG-SCOLON)", UFW_FLAG_SCOLON
);
6631 ufoDefineConstant("(WFLAG-PROTECTED)", UFW_FLAG_PROTECTED
);
6633 ufoDefineConstant("(WARG-MASK)", UFW_WARG_MASK
);
6634 ufoDefineConstant("(WARG-NONE)", UFW_WARG_NONE
);
6635 ufoDefineConstant("(WARG-BRANCH)", UFW_WARG_BRANCH
);
6636 ufoDefineConstant("(WARG-LIT)", UFW_WARG_LIT
);
6637 ufoDefineConstant("(WARG-C4STRZ)", UFW_WARG_C4STRZ
);
6638 ufoDefineConstant("(WARG-CFA)", UFW_WARG_CFA
);
6639 ufoDefineConstant("(WARG-CBLOCK)", UFW_WARG_CBLOCK
);
6640 ufoDefineConstant("(WARG-VOCID)", UFW_WARG_VOCID
);
6641 ufoDefineConstant("(WARG-C1STRZ)", UFW_WARG_C1STRZ
);
6643 ufoDefineConstant("(VOCOFS-LATEST)", UFW_VOCAB_OFS_LATEST
);
6644 ufoDefineConstant("(VOCOFS-VOCLINK)", UFW_VOCAB_OFS_VOCLINK
);
6645 ufoDefineConstant("(VOCOFS-PARENT)", UFW_VOCAB_OFS_PARENT
);
6646 ufoDefineConstant("(VOCOFS-HEADER)", UFW_VOCAB_OFS_HEADER
);
6647 ufoDefineConstant("(VOCOFS-HTABLE)", UFW_VOCAB_OFS_HTABLE
);
6648 ufoDefineConstant("(VOC-HTABLE-SIZE)", UFO_HASHTABLE_SIZE
);
6649 ufoDefineConstant("(VOC-HTABLE-NOFLAG)", UFO_NO_HTABLE_FLAG
);
6651 ufoDefineConstant("(REDEFINE-WARN-DON'T-CARE)", UFO_REDEF_WARN_DONT_CARE
);
6652 ufoDefineConstant("(REDEFINE-WARN-NONE)", UFO_REDEF_WARN_NONE
);
6653 ufoDefineConstant("(REDEFINE-WARN-NORMAL)", UFO_REDEF_WARN_NORMAL
);
6655 ufoDefineConstant("WORD-REDEFINE-WARN-MODE", ufoAddrRedefineWarning
);
6657 UFWORDX("(UNESCAPE)", PAR_UNESCAPE
);
6659 UFWORDX("?EXEC", QEXEC
);
6660 UFWORDX("?COMP", QCOMP
);
6664 UFWORDX("(INTERPRET-DUMB)", PAR_INTERPRET_DUMB); UFCALL(PAR_HIDDEN);
6665 const uint32_t idumbCFA = UFO_LFA_TO_CFA(ufoImgGetU32(ufoImgGetU32(ufoAddrCurrent)));
6666 ufo_assert(idumbCFA == UFO_PFA_TO_CFA(UFO_GET_DP()));
6669 UFWORDX("(CREATE-WORD-HEADER)", PAR_CREATE_WORD_HEADER
);
6670 UFWORDX("(CREATE-NAMELESS-WORD-HEADER)", PAR_CREATE_NAMELESS_WORD_HEADER
);
6672 ufoVocSetOnlyDefs(ufoForthVocId
);
6676 //==========================================================================
6680 //==========================================================================
6681 UFO_DISABLE_INLINE
void ufoInitMoreWords (void) {
6682 UFWORDX("COMPILE,", COMMA
); // just an alias, for clarity
6684 UFWORDX("CFA->PFA", CFA2PFA
);
6685 UFWORDX("PFA->CFA", PFA2CFA
);
6686 UFWORDX("CFA->NFA", CFA2NFA
);
6687 UFWORDX("NFA->CFA", NFA2CFA
);
6688 UFWORDX("CFA->LFA", CFA2LFA
);
6689 UFWORDX("LFA->CFA", LFA2CFA
);
6690 UFWORDX("LFA->PFA", LFA2PFA
);
6691 UFWORDX("LFA->BFA", LFA2BFA
);
6692 UFWORDX("LFA->XFA", LFA2XFA
);
6693 UFWORDX("LFA->YFA", LFA2YFA
);
6694 UFWORDX("LFA->NFA", LFA2NFA
);
6695 UFWORDX("NFA->LFA", NFA2LFA
);
6696 UFWORDX("CFA->WEND", CFA2WEND
);
6698 UFWORDX("ERROR", ERROR
);
6699 UFWORDX("?ERROR", QERROR
);
6701 UFWORDX("(BASED-NUMBER)", PAR_BASED_NUMBER
);
6702 UFWORDX("FIND-WORD", FIND_WORD
);
6703 UFWORDX("FIND-WORD-IN-VOC", FIND_WORD_IN_VOC
);
6704 UFWORDX("FIND-WORD-IN-VOC-AND-PARENTS", FIND_WORD_IN_VOC_AND_PARENTS
);
6706 UFWORDX_IMM("\"", QUOTE_IMM
);
6709 UFWORDX("EXECUTE-TAIL", EXECUTE_TAIL
);
6712 UFWORDX("?DUP", QDUP
);
6713 UFWORDX("2DUP", DDUP
);
6715 UFWORDX("2DROP", DDROP
);
6717 UFWORDX("2SWAP", DSWAP
);
6719 UFWORDX("2OVER", DOVER
);
6722 UFWORDX("PICK", PICK
);
6723 UFWORDX("ROLL", ROLL
);
6727 UFWORDX(">R", DTOR
);
6728 UFWORDX("R>", RTOD
);
6729 UFWORDX("R@", RPEEK
);
6730 UFWORDX("RPICK", RPICK
);
6731 UFWORDX("RROLL", RROLL
);
6732 UFWORDX("RSWAP", RSWAP
);
6733 UFWORDX("ROVER", ROVER
);
6734 UFWORDX("RROT", RROT
);
6735 UFWORDX("RNROT", RNROT
);
6737 UFWORDX("FLUSH-EMIT", FLUSH_EMIT
);
6738 UFWORDX("(EMIT)", PAR_EMIT
);
6747 UFWORDX("LASTCR?", LASTCRQ
);
6748 UFWORDX("LASTCR!", LASTCRSET
);
6752 UFWORDX("-", MINUS
);
6754 UFWORDX("U*", UMUL
);
6756 UFWORDX("U/", UDIV
);
6757 UFWORDX("MOD", MOD
);
6758 UFWORDX("UMOD", UMOD
);
6759 UFWORDX("/MOD", DIVMOD
);
6760 UFWORDX("U/MOD", UDIVMOD
);
6761 UFWORDX("*/", MULDIV
);
6762 UFWORDX("U*/", UMULDIV
);
6763 UFWORDX("*/MOD", MULDIVMOD
);
6764 UFWORDX("U*/MOD", UMULDIVMOD
);
6765 UFWORDX("M*", MMUL
);
6766 UFWORDX("UM*", UMMUL
);
6767 UFWORDX("M/MOD", MDIVMOD
);
6768 UFWORDX("UM/MOD", UMDIVMOD
);
6769 UFWORDX("UDS*", UDSMUL
);
6771 UFWORDX("SM/REM", SMREM
);
6772 UFWORDX("FM/MOD", FMMOD
);
6774 UFWORDX("D-", DMINUS
);
6775 UFWORDX("D+", DPLUS
);
6776 UFWORDX("D=", DEQU
);
6777 UFWORDX("D<", DLESS
);
6778 UFWORDX("D<=", DLESSEQU
);
6779 UFWORDX("DU<", DULESS
);
6780 UFWORDX("DU<=", DULESSEQU
);
6782 UFWORDX("2U*", ONESHL
);
6783 UFWORDX("2U/", ONESHR
);
6784 UFWORDX("4U*", TWOSHL
);
6785 UFWORDX("4U/", TWOSHR
);
6792 UFWORDX(">", GREAT
);
6793 UFWORDX("<=", LESSEQU
);
6794 UFWORDX(">=", GREATEQU
);
6795 UFWORDX("U<", ULESS
);
6796 UFWORDX("U>", UGREAT
);
6797 UFWORDX("U<=", ULESSEQU
);
6798 UFWORDX("U>=", UGREATEQU
);
6800 UFWORDX("<>", NOTEQU
);
6807 UFWORDX("LOGAND", LOGAND
);
6808 UFWORDX("LOGOR", LOGOR
);
6811 UFWORDX("(TIB-IN)", TIB_IN
);
6812 UFWORDX("TIB-PEEKCH", TIB_PEEKCH
);
6813 UFWORDX("TIB-PEEKCH-OFS", TIB_PEEKCH_OFS
);
6814 UFWORDX("TIB-GETCH", TIB_GETCH
);
6815 UFWORDX("TIB-SKIPCH", TIB_SKIPCH
);
6817 UFWORDX("REFILL", REFILL
);
6818 UFWORDX("REFILL-NOCROSS", REFILL_NOCROSS
);
6821 UFWORDX("(PARSE)", PAR_PARSE
);
6822 UFWORDX("(PARSE-SKIP-COMMENTS)", PAR_PARSE_SKIP_COMMENTS
);
6824 UFWORDX("PARSE-SKIP-BLANKS", PARSE_SKIP_BLANKS
);
6825 UFWORDX("PARSE-NAME", PARSE_NAME
);
6826 UFWORDX("PARSE-SKIP-LINE", PARSE_SKIP_LINE
);
6827 UFWORDX("PARSE", PARSE
);
6829 UFWORDX_IMM("[", LBRACKET_IMM
);
6830 UFWORDX("]", RBRACKET
);
6833 UFWORDX("(VSP@)", PAR_GET_VSP
);
6834 UFWORDX("(VSP!)", PAR_SET_VSP
);
6835 UFWORDX("(VSP-AT@)", PAR_VSP_LOAD
);
6836 UFWORDX("(VSP-AT!)", PAR_VSP_STORE
);
6837 ufoDefineConstant("(VSP-SIZE)", UFO_VOCSTACK_SIZE
);
6839 ufoDefineConstant("(SP-SIZE)", UFO_DSTACK_SIZE
);
6840 ufoDefineConstant("(RP-SIZE)", UFO_RSTACK_SIZE
);
6841 ufoDefineConstant("(LP-SIZE)", UFO_LSTACK_SIZE
);
6846 //==========================================================================
6848 // ufoInitHandleWords
6850 //==========================================================================
6851 UFO_DISABLE_INLINE
void ufoInitHandleWords (void) {
6852 // create "HANDLE" vocabulary
6853 const uint32_t handleVocId
= ufoCreateVoc("HANDLE", 0, UFW_FLAG_PROTECTED
);
6854 ufoVocSetOnlyDefs(handleVocId
);
6855 UFWORDX("NEW", PAR_NEW_HANDLE
);
6856 UFWORDX("FREE", PAR_FREE_HANDLE
);
6857 UFWORDX("TYPEID@", PAR_HANDLE_GET_TYPEID
);
6858 UFWORDX("TYPEID!", PAR_HANDLE_SET_TYPEID
);
6859 UFWORDX("SIZE@", PAR_HANDLE_GET_SIZE
);
6860 UFWORDX("SIZE!", PAR_HANDLE_SET_SIZE
);
6861 UFWORDX("USED@", PAR_HANDLE_GET_USED
);
6862 UFWORDX("USED!", PAR_HANDLE_SET_USED
);
6863 UFWORDX("C@", PAR_HANDLE_LOAD_BYTE
);
6864 UFWORDX("W@", PAR_HANDLE_LOAD_WORD
);
6865 UFWORDX("@", PAR_HANDLE_LOAD_CELL
);
6866 UFWORDX("C!", PAR_HANDLE_STORE_BYTE
);
6867 UFWORDX("W!", PAR_HANDLE_STORE_WORD
);
6868 UFWORDX("!", PAR_HANDLE_STORE_CELL
);
6869 UFWORDX("LOAD-FILE", PAR_HANDLE_LOAD_FILE
);
6870 ufoVocSetOnlyDefs(ufoForthVocId
);
6874 //==========================================================================
6876 // ufoInitHigherWords
6878 //==========================================================================
6879 UFO_DISABLE_INLINE
void ufoInitHigherWords (void) {
6880 UFWORDX("(INCLUDE)", PAR_INCLUDE
);
6882 UFWORDX("(INCLUDE-DEPTH)", PAR_INCLUDE_DEPTH
);
6883 UFWORDX("(INCLUDE-FILE-ID)", PAR_INCLUDE_FILE_ID
);
6884 UFWORDX("(INCLUDE-FILE-LINE)", PAR_INCLUDE_FILE_LINE
);
6885 UFWORDX("(INCLUDE-FILE-NAME)", PAR_INCLUDE_FILE_NAME
);
6887 UFWORDX("($DEFINED?)", PAR_DLR_DEFINEDQ
);
6888 UFWORDX("($DEFINE)", PAR_DLR_DEFINE
);
6889 UFWORDX("($UNDEF)", PAR_DLR_UNDEF
);
6891 UFWORDX_IMM("$INCLUDE", DLR_INCLUDE_IMM
);
6892 UFWORDX_IMM("$INCLUDE-ONCE", DLR_INCLUDE_ONCE_IMM
);
6896 //==========================================================================
6898 // ufoInitStringWords
6900 //==========================================================================
6901 UFO_DISABLE_INLINE
void ufoInitStringWords (void) {
6902 // create "STRING" vocabulary
6903 const uint32_t stringVocId
= ufoCreateVoc("STRING", 0, UFW_FLAG_PROTECTED
);
6904 ufoVocSetOnlyDefs(stringVocId
);
6905 UFWORDX("=", STREQU
);
6906 UFWORDX("=CI", STREQUCI
);
6907 UFWORDX("SEARCH", SEARCH
);
6908 UFWORDX("HASH", STRHASH
);
6909 UFWORDX("HASH-CI", STRHASHCI
);
6910 ufoVocSetOnlyDefs(ufoForthVocId
);
6914 //==========================================================================
6916 // ufoInitDebugWords
6918 //==========================================================================
6919 UFO_DISABLE_INLINE
void ufoInitDebugWords (void) {
6920 // create "DEBUG" vocabulary
6921 const uint32_t debugVocId
= ufoCreateVoc("DEBUG", 0, UFW_FLAG_PROTECTED
);
6922 ufoVocSetOnlyDefs(debugVocId
);
6923 UFWORDX("(DECOMPILE-CFA)", DEBUG_DECOMPILE_CFA
);
6924 UFWORDX("BACKTRACE", UFO_BACKTRACE
);
6925 UFWORDX("DUMP-STACK", DUMP_STACK
);
6926 UFWORDX("(BP)", MT_DEBUGGER_BP
);
6927 UFWORDX("IP->NFA", IP2NFA
);
6928 UFWORDX("IP->FILE/LINE", IP2FILELINE
);
6929 ufoVocSetOnlyDefs(ufoForthVocId
);
6933 //==========================================================================
6937 //==========================================================================
6938 UFO_DISABLE_INLINE
void ufoInitMTWords (void) {
6939 // create "MTASK" vocabulary
6940 const uint32_t mtVocId
= ufoCreateVoc("MTASK", 0, UFW_FLAG_PROTECTED
);
6941 ufoVocSetOnlyDefs(mtVocId
);
6942 UFWORDX("NEW-STATE", MT_NEW_STATE
);
6943 UFWORDX("FREE-STATE", MT_FREE_STATE
);
6944 UFWORDX("STATE-NAME@", MT_GET_STATE_NAME
);
6945 UFWORDX("STATE-NAME!", MT_SET_STATE_NAME
);
6946 UFWORDX("STATE-FIRST", MT_STATE_FIRST
);
6947 UFWORDX("STATE-NEXT", MT_STATE_NEXT
);
6948 UFWORDX("YIELD-TO", MT_YIELD_TO
);
6949 UFWORDX("SET-SELF-AS-DEBUGGER", MT_SET_SELF_AS_DEBUGGER
);
6950 UFWORDX("DEBUGGER-RESUME", MT_RESUME_DEBUGEE
);
6951 UFWORDX("DEBUGGER-SINGLE-STEP", MT_SINGLE_STEP_DEBUGEE
);
6952 UFWORDX("ACTIVE-STATE", MT_ACTIVE_STATE
);
6953 UFWORDX("STATE-IP@", MT_STATE_IP_GET
);
6954 UFWORDX("STATE-IP!", MT_STATE_IP_SET
);
6955 UFWORDX("STATE-A>", MT_STATE_REGA_GET
);
6956 UFWORDX("STATE->A", MT_STATE_REGA_SET
);
6957 UFWORDX("STATE-USER@", MT_STATE_USER_GET
);
6958 UFWORDX("STATE-USER!", MT_STATE_USER_SET
);
6959 UFWORDX("STATE-RPOPCFA@", MT_STATE_RPOPCFA_GET
);
6960 UFWORDX("STATE-RPOPCFA!", MT_STATE_RPOPCFA_SET
);
6961 UFWORDX("YIELDED-FROM", MT_YIELDED_FROM
);
6962 UFWORDX("STATE-SP@", MT_DSTACK_DEPTH_GET
);
6963 UFWORDX("STATE-RP@", MT_RSTACK_DEPTH_GET
);
6964 UFWORDX("STATE-LP@", MT_LP_GET
);
6965 UFWORDX("STATE-LBP@", MT_LBP_GET
);
6966 UFWORDX("STATE-SP!", MT_DSTACK_DEPTH_SET
);
6967 UFWORDX("STATE-RP!", MT_RSTACK_DEPTH_SET
);
6968 UFWORDX("STATE-LP!", MT_LP_SET
);
6969 UFWORDX("STATE-LBP!", MT_LBP_SET
);
6970 UFWORDX("STATE-DS@", MT_DSTACK_LOAD
);
6971 UFWORDX("STATE-RS@", MT_RSTACK_LOAD
);
6972 UFWORDX("STATE-LS@", MT_LSTACK_LOAD
);
6973 UFWORDX("STATE-DS!", MT_DSTACK_STORE
);
6974 UFWORDX("STATE-RS!", MT_RSTACK_STORE
);
6975 UFWORDX("STATE-LS!", MT_LSTACK_STORE
);
6976 ufoVocSetOnlyDefs(ufoForthVocId
);
6980 //==========================================================================
6984 //==========================================================================
6985 UFO_DISABLE_INLINE
void ufoInitTTYWords (void) {
6986 // create "TTY" vocabulary
6987 const uint32_t ttyVocId
= ufoCreateVoc("TTY", 0, UFW_FLAG_PROTECTED
);
6988 ufoVocSetOnlyDefs(ttyVocId
);
6989 UFWORDX("TTY?", TTY_TTYQ
);
6990 UFWORDX("RAW?", TTY_RAWQ
);
6991 UFWORDX("SIZE", TTY_SIZE
);
6992 UFWORDX("SET-RAW", TTY_SET_RAW
);
6993 UFWORDX("SET-COOKED", TTY_SET_COOKED
);
6994 UFWORDX("RAW-EMIT", TTY_RAW_EMIT
);
6995 UFWORDX("RAW-TYPE", TTY_RAW_TYPE
);
6996 UFWORDX("RAW-FLUSH", TTY_RAW_FLUSH
);
6997 UFWORDX("RAW-READCH", TTY_RAW_READCH
);
6998 UFWORDX("RAW-READY?", TTY_RAW_READYQ
);
6999 ufoVocSetOnlyDefs(ufoForthVocId
);
7003 //==========================================================================
7005 // ufoInitVeryVeryHighWords
7007 //==========================================================================
7008 UFO_DISABLE_INLINE
void ufoInitVeryVeryHighWords (void) {
7010 //ufoDefineDefer("INTERPRET", idumbCFA);
7012 // ( addr count FALSE -- addr count FALSE / TRUE )
7013 ufoDefineSColonForth("(INTERPRET-CHECK-WORD)");
7014 UFC("FORTH:(EXIT)");
7016 // ( addr count FALSE -- addr count FALSE / TRUE )
7017 ufoDefineSColonForth("(INTERPRET-WORD-NOT-FOUND)");
7018 UFC("FORTH:(EXIT)");
7020 // ( FALSE -- FALSE / TRUE ) -- called in "EXIT", before compiling "FORTH:(EXIT)"
7021 // return TRUE to stop calling other chained words, and omit default exit
7022 ufoDefineSColonForth("(EXIT-EXTENDER)");
7023 UFC("FORTH:(EXIT)");
7026 // create "FORTH:EXIT"
7027 // : EXIT ?COMP COMPILE FORTH:(EXIT) ;
7028 ufoDefineForthImm("EXIT");
7029 UFC("COMPILER:?COMP");
7030 UFC("FALSE"); UFC("(EXIT-EXTENDER)");
7031 UFC("FORTH:(TBRANCH)"); const uint32_t exit_branch_end
= ufoMarkFwd();
7032 UFC("FORTH:(LITCFA)"); UFC("FORTH:(EXIT)");
7033 UFC("FORTH:COMPILE,");
7034 ufoResolveFwd(exit_branch_end
);
7035 UFC("FORTH:(EXIT)");
7038 ufoDefineInterpret();
7040 //ufoDumpVocab(ufoCompilerVocId);
7042 ufoDefineForth("RUN-INTERPRET-LOOP");
7043 const uint32_t addrAgain
= UFO_GET_DP();
7046 UFC("FORTH:(BRANCH)");
7047 ufoImgEmitU32(addrAgain
);
7051 #define UFO_ADD_DO_CFA(cfx_) do { \
7052 ufoDo##cfx_##CFA = ufoCFAsUsed | UFO_ADDR_CFA_BIT; \
7053 ufoForthCFAs[ufoCFAsUsed] = &ufoDo##cfx_; \
7058 //==========================================================================
7062 //==========================================================================
7063 UFO_DISABLE_INLINE
void ufoInitCommon (void) {
7065 ufoForthVocId
= 0; ufoCompilerVocId
= 0;
7067 ufoForthCFAs
= calloc(UFO_MAX_NATIVE_CFAS
, sizeof(ufoForthCFAs
[0]));
7069 // allocate default TIB handle
7070 //UfoHandle *tibh = ufoAllocHandle(0x69a029a6); // arbitrary number
7071 //ufoDefTIB = tibh->ufoHandle;
7073 ufoForthCFAs
[0] = NULL
; ufoCFAsUsed
= 1u;
7074 UFO_ADD_DO_CFA(Forth
);
7075 UFO_ADD_DO_CFA(Variable
);
7076 UFO_ADD_DO_CFA(Value
);
7077 UFO_ADD_DO_CFA(Const
);
7078 UFO_ADD_DO_CFA(Defer
);
7079 UFO_ADD_DO_CFA(Voc
);
7080 UFO_ADD_DO_CFA(Create
);
7081 UFO_ADD_DO_CFA(UserVariable
);
7083 //fprintf(stderr, "DO-FORTH-CFA: 0x%08x\n", ufoDoForthCFA);
7087 // create "FORTH" vocabulary
7088 ufoForthVocId
= ufoCreateVoc("FORTH", 0, UFW_FLAG_PROTECTED
);
7089 ufoVocSetOnlyDefs(ufoForthVocId
);
7091 // base low-level interpreter words
7092 ufoInitBasicWords();
7094 // some COMPILER words
7095 ufoInitBasicCompilerWords();
7097 // STRING vocabulary
7098 ufoInitStringWords();
7101 ufoInitDebugWords();
7106 // HANDLE vocabulary
7107 ufoInitHandleWords();
7115 // some higher-level FORTH words (includes, etc.)
7116 ufoInitHigherWords();
7118 // very-very high-level FORTH words
7119 ufoInitVeryVeryHighWords();
7122 ufoDecompileWord(ufoFindWordChecked("RUN-INTERPRET-LOOP"));
7131 // ////////////////////////////////////////////////////////////////////////// //
7132 // virtual machine executor
7136 //==========================================================================
7140 // address interpreter
7142 //==========================================================================
7143 static void ufoRunVMCFA (uint32_t cfa
) {
7144 const uint32_t oldRPTop
= ufoRPTop
;
7146 #ifdef UFO_TRACE_VM_RUN
7147 fprintf(stderr
, "**VM-INITIAL**: cfa=%u\n", cfa
);
7153 // VM execution loop
7155 if (ufoVMAbort
) ufoFatal("user abort");
7156 if (ufoVMStop
) { ufoRP
= oldRPTop
; break; }
7157 if (ufoCurrState
== NULL
) ufoFatal("execution state is lost");
7158 if (ufoVMRPopCFA
== 0) {
7160 if (ufoIP
== 0) ufoFatal("IP is NULL");
7161 if (ufoIP
& UFO_ADDR_HANDLE_BIT
) ufoFatal("IP is a handle");
7162 cfa
= ufoImgGetU32(ufoIP
); ufoIP
+= 4u;
7164 cfa
= ufoRPop(); ufoVMRPopCFA
= 0;
7167 if (cfa
== 0) ufoFatal("EXECUTE: NULL CFA");
7168 if (cfa
& UFO_ADDR_HANDLE_BIT
) ufoFatal("cannot execute handle");
7169 // get next word CFAIDX, and check it
7170 uint32_t cfaidx
= ufoImgGetU32(cfa
);
7171 if (cfaidx
& UFO_ADDR_HANDLE_BIT
) ufoFatal("cannot execute CFAIDX-handle");
7172 #ifdef UFO_TRACE_VM_RUN
7173 fprintf(stderr
, "**VM**: IP=%u; cfa=%u; cfaidx=0x%08x\n", ufoIP
- 4u, cfa
, cfaidx
);
7175 ufoDumpWordHeader(UFO_CFA_TO_LFA(cfa
));
7176 fprintf(stderr
, "######################################\n");
7178 if (cfaidx
& UFO_ADDR_CFA_BIT
) {
7179 cfaidx
&= UFO_ADDR_CFA_MASK
;
7180 if (cfaidx
>= ufoCFAsUsed
|| ufoForthCFAs
[cfaidx
] == NULL
) {
7181 ufoFatal("tried to execute an unknown word: %u (max is %u); IP=%u",
7182 cfaidx
, ufoCFAsUsed
, ufoIP
- 4u);
7184 #ifdef UFO_TRACE_VM_RUN
7185 fprintf(stderr
, "**VM-NATIVE**: cfaidx=%u (doForth=%u)\n", cfaidx
,
7186 (ufoDoForthCFA
& UFO_ADDR_CFA_MASK
));
7188 ufoForthCFAs
[cfaidx
](UFO_CFA_TO_PFA(cfa
));
7190 // if CFA points somewhere inside a dict, this is "DOES>" word
7191 // IP points to PFA we need to push
7192 // CFA points to Forth word we need to jump to
7193 #ifdef UFO_TRACE_VM_DOER
7194 fprintf(stderr
, "*** DOER! IP=%u; cfa=%u; cfaidx=%u ***\n", ufoIP
, cfa
, cfaidx
);
7195 UFCALL(UFO_BACKTRACE
);
7197 ufoPush(UFO_CFA_TO_PFA(cfa
)); // push PFA
7198 ufoRPush(ufoIP
); // push IP
7199 ufoIP
= cfaidx
; // fix IP
7201 // that's all we need to activate the debugger
7202 if (ufoSingleStep
) {
7204 if (ufoSingleStep
== 0 && ufoDebuggerState
!= NULL
) {
7205 if (ufoCurrState
== ufoDebuggerState
) ufoFatal("debugger cannot debug itself");
7206 UfoState
*ost
= ufoCurrState
;
7207 ufoSwitchToState(ufoDebuggerState
); // always use API call for this!
7212 } while (ufoRP
!= oldRPTop
);
7217 // ////////////////////////////////////////////////////////////////////////// //
7221 //==========================================================================
7225 // register new word
7227 //==========================================================================
7228 uint32_t ufoRegisterWord (const char *wname
, ufoNativeCFA cfa
, uint32_t flags
) {
7229 ufo_assert(cfa
!= NULL
);
7230 ufo_assert(wname
!= NULL
&& wname
[0] != 0);
7231 uint32_t cfaidx
= ufoCFAsUsed
;
7232 if (cfaidx
>= UFO_MAX_NATIVE_CFAS
) ufoFatal("too many native words");
7233 ufoForthCFAs
[cfaidx
] = cfa
;
7235 //ufoDefineNative(wname, xcfa, 0);
7236 cfaidx
|= UFO_ADDR_CFA_BIT
;
7237 flags
&= 0xffffff00u
;
7238 ufoCreateWordHeader(wname
, flags
);
7239 const uint32_t res
= UFO_GET_DP();
7240 ufoImgEmitU32(cfaidx
);
7245 //==========================================================================
7247 // ufoRegisterDataWord
7249 //==========================================================================
7250 static uint32_t ufoRegisterDataWord (const char *wname
, uint32_t cfaidx
, uint32_t value
,
7253 ufo_assert(wname
!= NULL
&& wname
[0] != 0);
7254 flags
&= 0xffffff00u
;
7255 ufoCreateWordHeader(wname
, flags
);
7256 ufoImgEmitU32(cfaidx
);
7257 const uint32_t res
= UFO_GET_DP();
7258 ufoImgEmitU32(value
);
7263 //==========================================================================
7265 // ufoRegisterConstant
7267 //==========================================================================
7268 void ufoRegisterConstant (const char *wname
, uint32_t value
, uint32_t flags
) {
7269 (void)ufoRegisterDataWord(wname
, ufoDoConstCFA
, value
, flags
);
7273 //==========================================================================
7275 // ufoRegisterVariable
7277 //==========================================================================
7278 uint32_t ufoRegisterVariable (const char *wname
, uint32_t value
, uint32_t flags
) {
7279 return ufoRegisterDataWord(wname
, ufoDoVariableCFA
, value
, flags
);
7283 //==========================================================================
7287 //==========================================================================
7288 uint32_t ufoRegisterValue (const char *wname
, uint32_t value
, uint32_t flags
) {
7289 return ufoRegisterDataWord(wname
, ufoDoValueCFA
, value
, flags
);
7293 //==========================================================================
7297 //==========================================================================
7298 uint32_t ufoRegisterDefer (const char *wname
, uint32_t value
, uint32_t flags
) {
7299 return ufoRegisterDataWord(wname
, ufoDoDeferCFA
, value
, flags
);
7303 //==========================================================================
7305 // ufoFindWordInVocabulary
7307 // check if we have the corresponding word.
7308 // return CFA suitable for executing, or 0.
7310 //==========================================================================
7311 uint32_t ufoFindWordInVocabulary (const char *wname
, uint32_t vocid
) {
7312 if (wname
== NULL
|| wname
[0] == 0) return 0;
7313 size_t wlen
= strlen(wname
);
7314 if (wlen
>= UFO_MAX_WORD_LENGTH
) return 0;
7315 return ufoFindWordInVocAndParents(wname
, (uint32_t)wlen
, 0, vocid
, 0);
7319 //==========================================================================
7323 //==========================================================================
7324 uint32_t ufoGetIP (void) {
7329 //==========================================================================
7333 //==========================================================================
7334 void ufoSetIP (uint32_t newip
) {
7339 //==========================================================================
7343 //==========================================================================
7344 int ufoIsExecuting (void) {
7345 return (ufoImgGetU32(ufoAddrSTATE
) == 0);
7349 //==========================================================================
7353 //==========================================================================
7354 int ufoIsCompiling (void) {
7355 return (ufoImgGetU32(ufoAddrSTATE
) != 0);
7359 //==========================================================================
7363 //==========================================================================
7364 void ufoSetExecuting (void) {
7365 ufoImgPutU32(ufoAddrSTATE
, 0);
7369 //==========================================================================
7373 //==========================================================================
7374 void ufoSetCompiling (void) {
7375 ufoImgPutU32(ufoAddrSTATE
, 1);
7379 //==========================================================================
7383 //==========================================================================
7384 uint32_t ufoGetHere () {
7385 return UFO_GET_DP();
7389 //==========================================================================
7393 //==========================================================================
7394 uint32_t ufoGetPad () {
7400 //==========================================================================
7404 //==========================================================================
7405 uint8_t ufoTIBPeekCh (uint32_t ofs
) {
7406 return ufoTibPeekChOfs(ofs
);
7410 //==========================================================================
7414 //==========================================================================
7415 uint8_t ufoTIBGetCh (void) {
7416 return ufoTibGetCh();
7420 //==========================================================================
7424 //==========================================================================
7425 void ufoTIBSkipCh (void) {
7430 //==========================================================================
7436 //==========================================================================
7437 int ufoTIBSRefill (int allowCrossIncludes
) {
7438 return ufoLoadNextLine(allowCrossIncludes
);
7442 //==========================================================================
7446 //==========================================================================
7447 uint32_t ufoPeekData (void) {
7452 //==========================================================================
7456 //==========================================================================
7457 uint32_t ufoPopData (void) {
7462 //==========================================================================
7466 //==========================================================================
7467 void ufoPushData (uint32_t value
) {
7468 return ufoPush(value
);
7472 //==========================================================================
7476 //==========================================================================
7477 void ufoPushBoolData (int val
) {
7482 //==========================================================================
7486 //==========================================================================
7487 uint32_t ufoPeekRet (void) {
7492 //==========================================================================
7496 //==========================================================================
7497 uint32_t ufoPopRet (void) {
7502 //==========================================================================
7506 //==========================================================================
7507 void ufoPushRet (uint32_t value
) {
7508 return ufoRPush(value
);
7512 //==========================================================================
7516 //==========================================================================
7517 void ufoPushBoolRet (int val
) {
7518 ufoRPush(val
? ufoTrueValue
: 0);
7522 //==========================================================================
7526 //==========================================================================
7527 uint8_t ufoPeekByte (uint32_t addr
) {
7528 return ufoImgGetU8Ext(addr
);
7532 //==========================================================================
7536 //==========================================================================
7537 uint16_t ufoPeekWord (uint32_t addr
) {
7544 //==========================================================================
7548 //==========================================================================
7549 uint32_t ufoPeekCell (uint32_t addr
) {
7556 //==========================================================================
7560 //==========================================================================
7561 void ufoPokeByte (uint32_t addr
, uint32_t value
) {
7562 ufoImgPutU8(addr
, value
);
7566 //==========================================================================
7570 //==========================================================================
7571 void ufoPokeWord (uint32_t addr
, uint32_t value
) {
7578 //==========================================================================
7582 //==========================================================================
7583 void ufoPokeCell (uint32_t addr
, uint32_t value
) {
7590 //==========================================================================
7594 //==========================================================================
7595 void ufoEmitByte (uint32_t value
) {
7596 ufoImgEmitU8(value
);
7600 //==========================================================================
7604 //==========================================================================
7605 void ufoEmitWord (uint32_t value
) {
7606 ufoImgEmitU8(value
& 0xff);
7607 ufoImgEmitU8((value
>> 8) & 0xff);
7611 //==========================================================================
7615 //==========================================================================
7616 void ufoEmitCell (uint32_t value
) {
7617 ufoImgEmitU32(value
);
7621 //==========================================================================
7625 //==========================================================================
7626 int ufoIsInited (void) {
7627 return (ufoMode
!= UFO_MODE_NONE
);
7631 static void (*ufoUserPostInitCB
) (void);
7634 //==========================================================================
7636 // ufoSetUserPostInit
7638 // called after main initialisation
7640 //==========================================================================
7641 void ufoSetUserPostInit (void (*cb
) (void)) {
7642 ufoUserPostInitCB
= cb
;
7646 //==========================================================================
7650 //==========================================================================
7651 void ufoInit (void) {
7652 if (ufoMode
!= UFO_MODE_NONE
) return;
7653 ufoMode
= UFO_MODE_NATIVE
;
7656 ufoInFileName
= NULL
;
7658 ufoLastIncPath
= NULL
; ufoLastSysIncPath
= NULL
;
7660 for (uint32_t f
= 0; f
< UFO_MAX_STATES
; f
+= 1u) ufoStateMap
[f
] = NULL
;
7661 memset(ufoStateUsedBitmap
, 0, sizeof(ufoStateUsedBitmap
));
7663 ufoCurrState
= ufoNewState(0); // CFA doesn't matter here
7664 strcpy(ufoCurrState
->name
, "MAIN");
7665 ufoInitStateUserVars(ufoCurrState
, 1);
7666 ufoImgPutU32(ufoAddrDefTIB
, 0); // create TIB handle
7667 ufoImgPutU32(ufoAddrTIBx
, 0); // create TIB handle
7669 ufoYieldedState
= NULL
;
7670 ufoDebuggerState
= NULL
;
7673 #ifdef UFO_DEBUG_STARTUP_TIMES
7674 uint32_t stt
= ufo_get_msecs();
7675 ufoCondDefine("UFO-DEBUG-STARTUP-TIMES");
7678 #ifdef UFO_DEBUG_STARTUP_TIMES
7679 uint32_t ett
= ufo_get_msecs();
7680 fprintf(stderr
, "UrForth init time: %u msecs\n", (unsigned)(ett
- stt
));
7685 if (ufoUserPostInitCB
) {
7686 ufoUserPostInitCB();
7691 char *ufmname
= ufoCreateIncludeName("init", 1, NULL
);
7693 FILE *ufl
= fopen(ufmname
, "rb");
7695 FILE *ufl
= fopen(ufmname
, "r");
7699 ufoInFileName
= ufmname
;
7701 ufoFileId
= ufoLastUsedFileId
;
7702 setLastIncPath(ufoInFileName
, 1);
7705 ufoFatal("cannot load init code");
7708 if (ufoInFile
!= NULL
) {
7709 ufoRunInterpretLoop();
7714 //==========================================================================
7718 //==========================================================================
7719 void ufoFinishVM (void) {
7724 //==========================================================================
7728 // check if VM was exited due to `ufoFinishVM()`
7730 //==========================================================================
7731 int ufoWasVMFinished (void) {
7732 return (ufoVMStop
!= 0);
7736 //==========================================================================
7740 // ( -- addr count TRUE / FALSE )
7741 // does base TIB parsing; never copies anything.
7742 // as our reader is line-based, returns FALSE on EOL.
7743 // EOL is detected after skipping leading delimiters.
7744 // passing -1 as delimiter skips the whole line, and always returns FALSE.
7745 // trailing delimiter is always skipped.
7746 // result is on the data stack.
7748 //==========================================================================
7749 void ufoCallParseIntr (uint32_t delim
, int skipLeading
) {
7750 ufoPush(delim
); ufoPushBool(skipLeading
);
7754 //==========================================================================
7758 // ( -- addr count )
7759 // parse with leading blanks skipping. doesn't copy anything.
7760 // return empty string on EOL.
7762 //==========================================================================
7763 void ufoCallParseName (void) {
7768 //==========================================================================
7772 // ( -- addr count TRUE / FALSE )
7773 // parse without skipping delimiters; never copies anything.
7774 // as our reader is line-based, returns FALSE on EOL.
7775 // passing 0 as delimiter skips the whole line, and always returns FALSE.
7776 // trailing delimiter is always skipped.
7778 //==========================================================================
7779 void ufoCallParse (uint32_t delim
) {
7785 //==========================================================================
7787 // ufoCallParseSkipBlanks
7789 //==========================================================================
7790 void ufoCallParseSkipBlanks (void) {
7791 UFCALL(PARSE_SKIP_BLANKS
);
7795 //==========================================================================
7797 // ufoCallParseSkipComments
7799 //==========================================================================
7800 void ufoCallParseSkipComments (void) {
7801 ufoPushBool(1); UFCALL(PAR_PARSE_SKIP_COMMENTS
);
7805 //==========================================================================
7807 // ufoCallParseSkipLineComments
7809 //==========================================================================
7810 void ufoCallParseSkipLineComments (void) {
7811 ufoPushBool(0); UFCALL(PAR_PARSE_SKIP_COMMENTS
);
7815 //==========================================================================
7817 // ufoCallParseSkipLine
7819 // to the end of line; doesn't refill
7821 //==========================================================================
7822 void ufoCallParseSkipLine (void) {
7823 UFCALL(PARSE_SKIP_LINE
);
7827 //==========================================================================
7829 // ufoCallBasedNumber
7831 // convert number from addrl+1
7832 // returns address of the first inconvertible char
7833 // (BASED-NUMBER) ( addr count allowsign? base -- num TRUE / FALSE )
7835 //==========================================================================
7836 void ufoCallBasedNumber (uint32_t addr
, uint32_t count
, int allowSign
, int base
) {
7837 ufoPush(addr
); ufoPush(count
); ufoPushBool(allowSign
);
7838 if (base
< 0) ufoPush(0); else ufoPush((uint32_t)base
);
7839 UFCALL(PAR_BASED_NUMBER
);
7843 //==========================================================================
7847 //==========================================================================
7848 void ufoRunWord (uint32_t cfa
) {
7850 if (ufoMode
== UFO_MODE_NONE
) ufoFatal("UrForth is not properly inited");
7851 if (ufoInRunWord
) ufoFatal("`ufoRunWord` cannot be called recursively");
7852 ufoMode
= UFO_MODE_NATIVE
;
7860 //==========================================================================
7864 //==========================================================================
7865 void ufoRunMacroWord (uint32_t cfa
) {
7867 if (ufoMode
== UFO_MODE_NONE
) ufoFatal("UrForth is not properly inited");
7868 if (ufoInRunWord
) ufoFatal("`ufoRunWord` cannot be called recursively");
7869 ufoMode
= UFO_MODE_MACRO
;
7870 const uint32_t oisp
= ufoFileStackPos
;
7873 (void)ufoLoadNextUserLine();
7878 ufo_assert(ufoFileStackPos
== oisp
); // sanity check
7883 //==========================================================================
7887 // check if we are currently in "MACRO" mode.
7888 // should be called from registered words.
7890 //==========================================================================
7891 int ufoIsInMacroMode (void) {
7892 return (ufoMode
== UFO_MODE_MACRO
);
7896 //==========================================================================
7898 // ufoRunInterpretLoop
7900 // run default interpret loop.
7902 //==========================================================================
7903 void ufoRunInterpretLoop (void) {
7904 if (ufoMode
== UFO_MODE_NONE
) {
7907 const uint32_t cfa
= ufoFindWord("RUN-INTERPRET-LOOP");
7908 if (cfa
== 0) ufoFatal("'RUN-INTERPRET-LOOP' word not found");
7910 ufoMode
= UFO_MODE_NATIVE
;
7914 while (ufoFileStackPos
!= 0) ufoPopInFile();
7918 //==========================================================================
7922 //==========================================================================
7923 void ufoRunFile (const char *fname
) {
7924 if (ufoMode
== UFO_MODE_NONE
) {
7927 if (ufoInRunWord
) ufoFatal("`ufoRunFile` cannot be called recursively");
7928 ufoMode
= UFO_MODE_NATIVE
;
7931 char *ufmname
= ufoCreateIncludeName(fname
, 0, ".");
7933 FILE *ufl
= fopen(ufmname
, "rb");
7935 FILE *ufl
= fopen(ufmname
, "r");
7939 ufoInFileName
= ufmname
;
7941 ufoFileId
= ufoLastUsedFileId
;
7942 setLastIncPath(ufoInFileName
, 0);
7945 ufoFatal("cannot load source file '%s'", fname
);
7947 ufoRunInterpretLoop();