1 // and now for something completely different...
2 // UrAsm built-in Forth Engine!
15 #include <sys/fcntl.h>
17 #include <sys/types.h>
22 # define realpath(shit,fuck) _fullpath(fuck, shit, 32768)
25 // if defined, UFO will allocate 64MB main image, and 4MB temp image immediately
26 #define UFO_HUGE_IMAGES
28 // use relative branch addresses for position-independent code?
29 #define UFO_RELATIVE_BRANCH
31 // if defined, multitasking engine is allowed.
32 // multitasker is currently used only for debugger.
33 //#define UFO_MTASK_ALLOWED
36 //#define UFO_DEBUG_WRITE_MAIN_IMAGE
37 //#define UFO_DEBUG_WRITE_DEBUG_IMAGE
40 #define UFO_DEBUG_STARTUP_TIMES
41 //#define UFO_DEBUG_FATAL_ABORT
42 #define UFO_DEBUG_DEBUG /* ;-) */
43 //#define UFO_TRACE_VM_DOER
44 //#define UFO_TRACE_VM_RUN
45 //#define UFO_DEBUG_INCLUDE
46 //#define UFO_DEBUG_DUMP_NEW_HEADERS
47 //#define UFO_DEBUG_FIND_WORD
48 //#define UFO_DEBUG_FIND_WORD_IN_VOC
49 //#define UFO_DEBUG_FIND_WORD_COLON
51 // 2/8 msecs w/o inlining
52 // 1/5 msecs with inlining
54 # define UFO_FORCE_INLINE static inline __attribute__((always_inline))
56 # define UFO_FORCE_INLINE static __attribute__((noinline)) /*__attribute__((unused))*/
58 #define UFO_DISABLE_INLINE static __attribute__((noinline)) /*__attribute__((unused))*/
60 // detect arch, and use faster memory access code on x86
61 #if defined(__x86_64__) || defined(_M_X64) || \
62 defined(i386) || defined(__i386__) || defined(__i386) || defined(_M_IX86)
63 # define UFO_FAST_MEM_ACCESS
66 // should not be bigger than this!
67 #define UFO_MAX_WORD_LENGTH (250)
69 //#define UFO_ALIGN4(v_) (((v_) + 3u) / 4u * 4u)
70 #define UFO_ALIGN4(v_) (((v_) + 3u) & ~(uint32_t)3)
73 // ////////////////////////////////////////////////////////////////////////// //
74 static void ufoFlushOutput (void);
76 UFO_DISABLE_INLINE
const char *ufo_assert_failure (const char *cond
, const char *fname
,
77 int fline
, const char *func
)
79 for (const char *t
= fname
; *t
; ++t
) {
81 if (*t
== '/' || *t
== '\\') fname
= t
+1;
83 if (*t
== '/') fname
= t
+1;
87 fprintf(stderr
, "\n%s:%d: Assertion in `%s` failed: %s\n", fname
, fline
, func
, cond
);
92 #define ufo_assert(cond_) do { if (__builtin_expect((!(cond_)), 0)) { ufo_assert_failure(#cond_, __FILE__, __LINE__, __PRETTY_FUNCTION__); } } while (0)
95 static char ufoRealPathBuf
[32769];
96 static char ufoRealPathHashBuf
[32769];
99 //==========================================================================
103 //==========================================================================
104 static char *ufoRealPath (const char *fname
) {
106 if (fname
!= NULL
&& fname
[0] != 0) {
107 res
= realpath(fname
, NULL
);
109 const size_t slen
= strlen(res
);
111 strcpy(ufoRealPathBuf
, res
);
113 res
= ufoRealPathBuf
;
127 static time_t secstart
= 0;
132 //==========================================================================
136 //==========================================================================
137 static uint64_t ufo_get_msecs (void) {
139 return GetTickCount();
142 #ifdef CLOCK_MONOTONIC
143 ufo_assert(clock_gettime(CLOCK_MONOTONIC
, &ts
) == 0);
145 // this should be available everywhere
146 ufo_assert(clock_gettime(CLOCK_REALTIME
, &ts
) == 0);
150 secstart
= ts
.tv_sec
+1;
151 ufo_assert(secstart
); // it should not be zero
153 return (uint64_t)(ts
.tv_sec
-secstart
+2)*1000U+(uint32_t)ts
.tv_nsec
/1000000U;
155 //return (uint64_t)(ts.tv_sec-secstart+2)*1000000000U+(uint32_t)ts.tv_nsec;
160 //==========================================================================
164 //==========================================================================
165 UFO_FORCE_INLINE
uint32_t joaatHashBuf (const void *buf
, size_t len
, uint8_t orbyte
) {
166 uint32_t hash
= 0x29a;
167 const uint8_t *s
= (const uint8_t *)buf
;
169 hash
+= (*s
++)|orbyte
;
181 // this converts ASCII capitals to locase (and destroys other, but who cares)
182 #define joaatHashBufCI(buf_,len_) joaatHashBuf((buf_), (len_), 0x20)
185 //==========================================================================
189 //==========================================================================
190 UFO_FORCE_INLINE
char toUpper (char ch
) {
191 return (ch
>= 'a' && ch
<= 'z' ? ch
-'a'+'A' : ch
);
195 //==========================================================================
199 //==========================================================================
200 UFO_FORCE_INLINE
uint8_t toUpperU8 (uint8_t ch
) {
201 return (ch
>= 'a' && ch
<= 'z' ? ch
-'a'+'A' : ch
);
205 //==========================================================================
209 //==========================================================================
210 UFO_FORCE_INLINE
int digitInBase (char ch
, int base
) {
212 case '0' ... '9': ch
= ch
- '0'; break;
213 case 'A' ... 'Z': ch
= ch
- 'A' + 10; break;
214 case 'a' ... 'z': ch
= ch
- 'a' + 10; break;
215 default: base
= -1; break;
217 return (ch
>= 0 && ch
< base
? ch
: -1);
222 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
223 ;; word header format:
224 ;; note than name hash is ALWAYS calculated with ASCII-uppercased name
225 ;; (actually, bit 5 is always reset for all bytes, because we don't need the
226 ;; exact uppercase, only something that resembles it)
227 ;; bfa points to next bfa or to 0 (this is "hash bucket pointer")
228 ;; before nfa, we have such "hidden" fields:
229 ;; dd xfa ; points to the previous word header XFA, regardless of vocabularies (or 0)
230 ;; dd yfa ; points to the next word header YFA, regardless of vocabularies (or 0)
231 ;; dd bfa ; next word in hashtable bucket; it is always here, even if hashtable is turned off
232 ;; ; if there is no hashtable, this field is not used
234 ;; dd lfa ; previous vocabulary word LFA or 0 (lfa links points here)
235 ;; dd namehash ; it is always here, and always calculated, even if hashtable is turned off
237 ;; dd flags-and-name-len ; see below
238 ;; db name ; no terminating zero or other "termination flag" here
239 ;; here could be some 0 bytes to align everything to 4 bytes
240 ;; db namelen ; yes, name length again, so CFA->NFA can avoid guessing
241 ;; ; full length, including padding, but not including this byte
243 ;; dd cfaidx ; our internal CFA index, or image address for DOES>
244 ;; dd ? ; reserved for "does"
248 ;; first word cell contains combined name length (low byte), argtype and flags (other bytes)
253 ;; i.e. we have 16 bits for flags, and 256 possible argument types. why not.
262 ;; bit 6: *UNUSED* main scattered colon word (with "...")
265 ;; argtype is the type of the argument that this word reads from the threaded code.
266 ;; possible argument types:
269 ;; 2: cell-size numeric literal
270 ;; 3: cell-counted string with terminating zero (not counted)
271 ;; 4: cfa of another word
274 ;; 7: byte-counted string with terminating zero (not counted)
275 ;; 8: data skip: the arg is amout of bytes to skip (not including the counter itself)
278 ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
279 ;; wordlist structure (at PFA)
280 ;; -4: wordlist type id (used by structs, for example)
282 ;; dd voclink (voclink always points here)
283 ;; dd parent (if not zero, all parent words are visible)
284 ;; dd header-nfa (can be 0 for anonymous wordlists)
285 ;; hashtable (if enabled), or ~0U if no hash table
289 // ////////////////////////////////////////////////////////////////////////// //
290 #define UFO_BFA_TO_LFA(bfa_) ((bfa_) + 1u * 4u)
291 #define UFO_LFA_TO_XFA(lfa_) ((lfa_) - 3u * 4u)
292 #define UFO_LFA_TO_YFA(lfa_) ((lfa_) - 2u * 4u)
293 #define UFO_LFA_TO_BFA(lfa_) ((lfa_) - 1u * 4u)
294 #define UFO_LFA_TO_NFA(lfa_) ((lfa_) + 2u * 4u)
295 #define UFO_LFA_TO_CFA(lfa_) UFO_ALIGN4((lfa_) + 3u * 4u + 1u + ufoImgGetU8((lfa_) + 2u * 4u))
296 #define UFO_LFA_TO_NHASH(lfa_) ((lfa_) + 1u * 4u)
297 #define UFO_CFA_TO_NFA(cfa_) ((cfa_) - 1u - 4u - ufoImgGetU8((cfa_) - 1u))
298 #define UFO_CFA_TO_LFA(cfa_) ((cfa_) - 1u - 4u * 3u - ufoImgGetU8((cfa_) - 1u))
299 #define UFO_CFA_TO_PFA(cfa_) ((cfa_) + 2u * 4u)
300 #define UFO_PFA_TO_CFA(pfa_) ((pfa_) - 2u * 4u)
301 #define UFO_NFA_TO_CFA(nfa_) UFO_ALIGN4((nfa_) + 4u + 1u + ufoImgGetU8((nfa_)))
302 #define UFO_NFA_TO_LFA(nfa_) ((nfa_) - 2u * 4u)
303 #define UFO_XFA_TO_YFA(xfa_) ((xfa_) + 4u)
304 #define UFO_YFA_TO_XFA(yfa_) ((xfa_) - 4u)
305 #define UFO_YFA_TO_WST(yfa_) ((yfa_) - 4u) /* to xfa */
306 #define UFO_YFA_TO_NFA(yfa_) ((yfa_) + 4u * 4u)
308 #define UFO_CFA_TO_DOES_CFA(cfa_) ((cfa_) + 4u)
309 #define UFO_PFA_TO_DOES_CFA(pfa_) ((pfa_) - 4u)
312 // ////////////////////////////////////////////////////////////////////////// //
313 #define UFW_VOCAB_OFS_LATEST (0u * 4u)
314 #define UFW_VOCAB_OFS_VOCLINK (1u * 4u)
315 #define UFW_VOCAB_OFS_PARENT (2u * 4u)
316 #define UFW_VOCAB_OFS_HEADER (3u * 4u)
317 #define UFW_VOCAB_OFS_HTABLE (4u * 4u)
319 #define UFO_HASHTABLE_SIZE (256)
321 #define UFO_NO_HTABLE_FLAG (~(uint32_t)0)
323 #define UFO_MAX_NATIVE_CFAS (1024u)
324 static ufoNativeCFA ufoForthCFAs
[UFO_MAX_NATIVE_CFAS
];
325 static uint32_t ufoCFAsUsed
= 0;
327 static uint32_t ufoDoForthCFA
;
328 static uint32_t ufoDoVariableCFA
;
329 static uint32_t ufoDoValueCFA
;
330 static uint32_t ufoDoConstCFA
;
331 static uint32_t ufoDoDeferCFA
;
332 static uint32_t ufoDoDoesCFA
;
333 static uint32_t ufoDoRedirectCFA
;
334 static uint32_t ufoDoVocCFA
;
335 static uint32_t ufoDoCreateCFA
;
336 static uint32_t ufoDoUserVariableCFA
;
338 static uint32_t ufoLitStr8CFA
;
340 #ifdef UFO_MTASK_ALLOWED
341 static uint32_t ufoSingleStepAllowed
;
344 // special address types:
345 #define UFO_ADDR_CFA_BIT ((uint32_t)1<<31)
346 #define UFO_ADDR_CFA_MASK (UFO_ADDR_CFA_BIT-1u)
348 // handles are somewhat special: first 12 bits can be used as offset for "@", and are ignored
349 #define UFO_ADDR_HANDLE_BIT ((uint32_t)1<<30)
350 #define UFO_ADDR_HANDLE_MASK ((UFO_ADDR_HANDLE_BIT-1u)&~((uint32_t)0xfff))
351 #define UFO_ADDR_HANDLE_SHIFT (12)
352 #define UFO_ADDR_HANDLE_OFS_MASK ((uint32_t)((1 << UFO_ADDR_HANDLE_SHIFT) - 1))
354 // temporary area is 1MB buffer out of the main image
355 #define UFO_ADDR_TEMP_BIT ((uint32_t)1<<29)
356 #define UFO_ADDR_TEMP_MASK (UFO_ADDR_TEMP_BIT-1u)
358 #define UFO_ADDR_SPECIAL_BITS_MASK (UFO_ADDR_CFA_BIT|UFO_ADDR_HANDLE_BIT|UFO_ADDR_TEMP_BIT)
361 #ifdef UFO_HUGE_IMAGES
362 #define ufoImageSize (1024u * 1024u * 64u)
363 static uint32_t ufoImage
[ufoImageSize
/ 4u];
365 static uint32_t *ufoImage
= NULL
;
366 static uint32_t ufoImageSize
= 0;
369 static uint8_t *ufoDebugImage
= NULL
;
370 static uint32_t ufoDebugImageUsed
= 0; // in bytes
371 static uint32_t ufoDebugImageSize
= 0; // in bytes
372 static uint32_t ufoDebugFileNameHash
= 0; // current file name hash
373 static uint32_t ufoDebugFileNameLen
= 0; // current file name length
374 static uint32_t ufoDebugLastLine
= 0;
375 static uint32_t ufoDebugLastLinePCOfs
= 0;
376 static uint32_t ufoDebugLastLineDP
= 0;
377 static uint32_t ufoDebugCurrDP
= 0;
379 static uint32_t ufoInRunWord
= 0;
381 //static volatile int ufoVMAbort = 0;
383 #define ufoTrueValue (~(uint32_t)0)
387 UFO_MODE_NATIVE
= 0, // executing forth code
388 UFO_MODE_MACRO
= 1, // executing forth asm macro
390 static uint32_t ufoMode
= UFO_MODE_NONE
;
392 #define UFO_DSTACK_SIZE (8192)
393 #define UFO_RSTACK_SIZE (4096)
394 #define UFO_LSTACK_SIZE (4096)
395 #define UFO_MAX_TASK_NAME (127)
396 #define UFO_VOCSTACK_SIZE (16u)
398 #define UFO_MAX_TEMP_IMAGE (1024u * 1024u * 8u)
400 // to support multitasking (required for the debugger),
401 // our virtual machine state is encapsulated in a struct.
402 typedef struct UfoState_t
{
404 uint32_t dStack
[UFO_DSTACK_SIZE
];
405 uint32_t rStack
[UFO_RSTACK_SIZE
];
406 uint32_t lStack
[UFO_LSTACK_SIZE
];
407 uint32_t IP
; // in image
408 uint32_t SP
; // points AFTER the last value pushed
409 uint32_t RP
; // points AFTER the last value pushed
416 uint32_t vocStack
[UFO_VOCSTACK_SIZE
]; // cfas
419 #ifdef UFO_HUGE_IMAGES
420 uint32_t imageTemp
[UFO_MAX_TEMP_IMAGE
/ 4u];
423 uint32_t imageTempSize
;
425 // linked list of all allocated states (tasks)
426 char name
[UFO_MAX_TASK_NAME
+ 1];
430 #define UFO_MAX_STATES (8192)
432 #ifdef UFO_MTASK_ALLOWED
433 // this is indexed by id
434 static UfoState
*ufoStateMap
[UFO_MAX_STATES
] = {NULL
};
435 static uint32_t ufoStateUsedBitmap
[UFO_MAX_STATES
/32] = {0};
437 // currently active execution state
438 static UfoState
*ufoCurrState
= NULL
;
439 // state we're yielded from
440 static UfoState
*ufoYieldedState
= NULL
;
441 // if debug state is not NULL, VM will switch to it
442 // after executing one instruction from the current state.
443 // it will store current state in `ufoDebugeeState`.
444 static UfoState
*ufoDebuggerState
= NULL
;
445 static uint32_t ufoSingleStep
= 0;
447 #define ufoDStack (ufoCurrState->dStack)
448 #define ufoRStack (ufoCurrState->rStack)
449 #define ufoLStack (ufoCurrState->lStack)
450 #define ufoIP (ufoCurrState->IP)
451 #define ufoSP (ufoCurrState->SP)
452 #define ufoRP (ufoCurrState->RP)
453 #define ufoLP (ufoCurrState->LP)
454 #define ufoLBP (ufoCurrState->LBP)
455 #define ufoRegA (ufoCurrState->regA)
456 #define ufoImageTemp (ufoCurrState->imageTemp)
457 #ifdef UFO_HUGE_IMAGES
458 # define ufoImageTempSize UFO_MAX_TEMP_IMAGE
459 # define ufoSTImageTempSize(st_) UFO_MAX_TEMP_IMAGE
461 # define ufoImageTempSize (ufoCurrState->imageTempSize)
462 # define ufoSTImageTempSize(st_) ((st_)->imageTempSize)
464 #define ufoVocStack (ufoCurrState->vocStack)
465 #define ufoVSP (ufoCurrState->VSP)
467 #else /* no multitasking */
469 static UfoState ufoCurrState
;
471 #define ufoDStack (ufoCurrState.dStack)
472 #define ufoRStack (ufoCurrState.rStack)
473 #define ufoLStack (ufoCurrState.lStack)
474 #define ufoIP (ufoCurrState.IP)
475 #define ufoSP (ufoCurrState.SP)
476 #define ufoRP (ufoCurrState.RP)
477 #define ufoLP (ufoCurrState.LP)
478 #define ufoLBP (ufoCurrState.LBP)
479 #define ufoRegA (ufoCurrState.regA)
480 #define ufoImageTemp (ufoCurrState.imageTemp)
481 #ifdef UFO_HUGE_IMAGES
482 # define ufoImageTempSize UFO_MAX_TEMP_IMAGE
483 # define ufoSTImageTempSize(st_) UFO_MAX_TEMP_IMAGE
485 # define ufoImageTempSize (ufoCurrState.imageTempSize)
486 # define ufoSTImageTempSize(st_) ((st_)->imageTempSize)
488 #define ufoVocStack (ufoCurrState.vocStack)
489 #define ufoVSP (ufoCurrState.VSP)
493 static jmp_buf ufoStopVMJP
;
495 // 256 bytes for user variables
496 #define UFO_USER_AREA_ADDR UFO_ADDR_TEMP_BIT
497 #define UFO_USER_AREA_SIZE (256u)
498 #define UFO_NBUF_ADDR UFO_USER_AREA_ADDR + UFO_USER_AREA_SIZE
499 #define UFO_NBUF_SIZE (256u)
500 #define UFO_PAD_ADDR (UFO_NBUF_ADDR + UFO_NBUF_SIZE)
501 #define UFO_DEF_TIB_ADDR (UFO_PAD_ADDR + 2048u)
503 // dynamically allocated text input buffer
504 // always ends with zero (this is word name too)
505 static const uint32_t ufoAddrTIBx
= UFO_ADDR_TEMP_BIT
+ 0u * 4u; // TIB
506 static const uint32_t ufoAddrINx
= UFO_ADDR_TEMP_BIT
+ 1u * 4u; // >IN
507 static const uint32_t ufoAddrDefTIB
= UFO_ADDR_TEMP_BIT
+ 2u * 4u; // default TIB (handle); user cannot change it
508 static const uint32_t ufoAddrBASE
= UFO_ADDR_TEMP_BIT
+ 3u * 4u;
509 static const uint32_t ufoAddrSTATE
= UFO_ADDR_TEMP_BIT
+ 4u * 4u;
510 static const uint32_t ufoAddrContext
= UFO_ADDR_TEMP_BIT
+ 5u * 4u; // CONTEXT
511 static const uint32_t ufoAddrCurrent
= UFO_ADDR_TEMP_BIT
+ 6u * 4u; // CURRENT (definitions will go there)
512 static const uint32_t ufoAddrSelf
= UFO_ADDR_TEMP_BIT
+ 7u * 4u; // CURRENT (definitions will go there)
513 static const uint32_t ufoAddrInterNextLine
= UFO_ADDR_TEMP_BIT
+ 8u * 4u; // (INTERPRET-NEXT-LINE)
514 static const uint32_t ufoAddrEP
= UFO_ADDR_TEMP_BIT
+ 9u * 4u; // (EP) -- exception frame pointer
515 static const uint32_t ufoAddrDPTemp
= UFO_ADDR_TEMP_BIT
+ 10u * 4u; // pointer to currently active DP in temp dict
516 static const uint32_t ufoAddrHereDP
= UFO_ADDR_TEMP_BIT
+ 11u * 4u; // pointer to currently active DP for HERE
517 static const uint32_t ufoAddrUserVarUsed
= UFO_ADDR_TEMP_BIT
+ 12u * 4u;
519 #define UFO_DPTEMP_BASE_ADDR (UFO_ADDR_TEMP_BIT + 256u * 1024u)
521 static uint32_t ufoAddrVocLink
;
522 static uint32_t ufoAddrDP
; // DP for main dict
523 static uint32_t ufoAddrNewWordFlags
;
524 static uint32_t ufoAddrRedefineWarning
;
525 static uint32_t ufoAddrLastXFA
;
527 static uint32_t ufoForthVocId
;
528 static uint32_t ufoCompilerVocId
;
529 static uint32_t ufoInterpNextLineCFA
;
531 static uint32_t ufoUserAbortCFA
;
533 // allows to redefine even protected words
534 #define UFO_REDEF_WARN_DONT_CARE (~(uint32_t)0)
535 // do not warn about ordinary words, allow others
536 #define UFO_REDEF_WARN_NONE (0)
537 // do warn (or fail on protected)
538 #define UFO_REDEF_WARN_NORMAL (1)
539 // do warn (or fail on protected) for parent dicts too
540 #define UFO_REDEF_WARN_PARENTS (2)
542 #define UFO_GET_DP() (ufoImgGetU32(ufoImgGetU32(ufoAddrHereDP)))
544 #define UFO_MAX_NESTED_INCLUDES (32)
551 uint32_t id
; // non-zero unique id
554 static UFOFileStackEntry ufoFileStack
[UFO_MAX_NESTED_INCLUDES
];
555 static uint32_t ufoFileStackPos
; // after the last used item
557 static FILE *ufoInFile
= NULL
;
558 static uint32_t ufoInFileNameLen
= 0;
559 static uint32_t ufoInFileNameHash
= 0;
560 static char *ufoInFileName
= NULL
;
561 static char *ufoLastIncPath
= NULL
;
562 static char *ufoLastSysIncPath
= NULL
;
563 static int ufoInFileLine
= 0;
564 static uint32_t ufoFileId
= 0;
565 static uint32_t ufoLastUsedFileId
= 0;
566 static int ufoLastEmitWasCR
= 1;
567 static long ufoCurrIncludeLineFileOfs
= 0;
569 // dynamic memory handles
570 typedef struct UHandleInfo_t
{
577 struct UHandleInfo_t
*next
;
580 static UfoHandle
*ufoHandleFreeList
= NULL
;
581 static UfoHandle
**ufoHandles
= NULL
;
582 static uint32_t ufoHandlesUsed
= 0;
583 static uint32_t ufoHandlesAlloted
= 0;
585 #define UFO_HANDLE_FREE (~(uint32_t)0)
587 static char ufoCurrFileLine
[520];
590 static uint32_t ufoInBacktrace
= 0;
593 // ////////////////////////////////////////////////////////////////////////// //
594 static void ufoClearCondDefines (void);
596 static void ufoBacktrace (uint32_t ip
, int showDataStack
);
597 static void ufoBTShowWordName (uint32_t nfa
);
599 static void ufoClearCondDefines (void);
601 #ifdef UFO_MTASK_ALLOWED
602 static UfoState
*ufoNewState (void);
603 static void ufoFreeState (UfoState
*st
);
604 static UfoState
*ufoFindState (uint32_t stid
);
605 static void ufoSwitchToState (UfoState
*newst
);
607 static void ufoInitStateUserVars (UfoState
*st
);
609 __attribute__((unused
)) static void ufoDumpWordHeader (const uint32_t lfa
);
612 static void ufoDisableRaw (void);
614 static void ufoTTYRawFlush (void);
615 static int ufoIsGoodTTY (void);
617 #ifdef UFO_DEBUG_DEBUG
618 static void ufoDumpDebugImage (void);
622 // ////////////////////////////////////////////////////////////////////////// //
623 #ifdef UFO_MTASK_ALLOWED
624 #define UFO_EXEC_CFA(cfa_) do { \
625 const uint32_t cfa = (cfa_); \
626 if (ufoCurrState == NULL) ufoFatal("execution state is lost"); \
627 const uint32_t cfaidx = ufoImgGetU32(cfa); \
628 if (cfaidx >= UFO_ADDR_CFA_BIT && cfaidx < UFO_MAX_NATIVE_CFAS + UFO_ADDR_CFA_BIT) { \
629 ufoForthCFAs[cfaidx & UFO_ADDR_CFA_MASK](UFO_CFA_TO_PFA(cfa)); \
631 ufoFatal("tried to execute an unknown word: %u (max is %u); IP=%u", cfaidx, ufoCFAsUsed, ufoIP - 4u); \
633 /* that's all we need to activate the debugger */ \
634 if (ufoSingleStep) { \
635 ufoSingleStep -= 1; \
636 if (ufoSingleStep == 0 && ufoDebuggerState != NULL) { \
637 if (ufoCurrState == ufoDebuggerState) ufoFatal("debugger cannot debug itself"); \
638 UfoState *ost = ufoCurrState; \
639 ufoSwitchToState(ufoDebuggerState); /* always use API call for this! */ \
649 # define UFO_EXEC_CFA_DEBUG do { \
650 fprintf(stderr, "IP:%08X CFA:%08X (CFA):%08X\n", ufoIP, xxcfa, xxcfaidx); \
651 uint32_t nfa = ufoFindWordForIP(ufoIP - 4u); \
653 fprintf(stderr, " IP: "); ufoBTShowWordName(nfa); \
654 /*fname = ufoFindFileForIP(ip, &fline, NULL, NULL);*/ \
655 /*if (fname != NULL) { fprintf(stderr, " (at %s:%u)", fname, fline); }*/ \
656 fputc('\n', stderr); \
658 nfa = ufoFindWordForIP(xxcfa); \
660 fprintf(stderr, " CFA:"); ufoBTShowWordName(nfa); \
661 /*fname = ufoFindFileForIP(ip, &fline, NULL, NULL);*/ \
662 /*if (fname != NULL) { fprintf(stderr, " (at %s:%u)", fname, fline); }*/ \
663 fputc('\n', stderr); \
667 # define UFO_EXEC_CFA_DEBUG
670 #define UFO_EXEC_CFA(cfa__) do { \
671 const uint32_t xxcfa = (cfa__); \
672 const uint32_t xxcfaidx = ufoImgGetU32(xxcfa); \
674 if (xxcfaidx >= UFO_ADDR_CFA_BIT && xxcfaidx < UFO_MAX_NATIVE_CFAS + UFO_ADDR_CFA_BIT) { \
675 ufoForthCFAs[xxcfaidx & UFO_ADDR_CFA_MASK](UFO_CFA_TO_PFA(xxcfa)); \
677 ufoFatal("tried to execute an unknown word: %u (max is %u); IP=%u; CFA=%u", \
678 xxcfaidx, ufoCFAsUsed, ufoIP - 4u, xxcfa); \
685 // ////////////////////////////////////////////////////////////////////////// //
686 #define UFWORD(name_) \
687 static void ufoWord_##name_ (uint32_t mypfa)
689 #define UFCALL(name_) ufoWord_##name_(0)
690 #define UFCFA(name_) (&ufoWord_##name_)
693 UFWORD(CPOKE_REGA_IDX
);
696 UFWORD(PAR_HANDLE_LOAD_BYTE
);
697 UFWORD(PAR_HANDLE_LOAD_WORD
);
698 UFWORD(PAR_HANDLE_LOAD_CELL
);
699 UFWORD(PAR_HANDLE_STORE_BYTE
);
700 UFWORD(PAR_HANDLE_STORE_WORD
);
701 UFWORD(PAR_HANDLE_STORE_CELL
);
704 //==========================================================================
708 //==========================================================================
709 static void ufoFlushOutput (void) {
715 //==========================================================================
719 // if `reuse` is not 0, reuse/free `fname`
721 //==========================================================================
722 static void ufoSetInFileNameEx (const char *fname
, int reuse
) {
723 ufo_assert(fname
== NULL
|| (fname
!= ufoInFileName
));
724 if (fname
== NULL
|| fname
[0] == 0) {
725 if (ufoInFileName
) { free(ufoInFileName
); ufoInFileName
= NULL
; }
726 ufoInFileNameLen
= 0;
727 ufoInFileNameHash
= 0;
728 if (reuse
&& fname
!= NULL
) free((void *)fname
);
730 const uint32_t fnlen
= (uint32_t)strlen(fname
);
731 const uint32_t fnhash
= joaatHashBuf(fname
, fnlen
, 0);
732 if (ufoInFileNameLen
!= fnlen
|| ufoInFileNameHash
!= fnhash
) {
733 if (ufoInFileName
) { free(ufoInFileName
); ufoInFileName
= NULL
; }
735 ufoInFileName
= (char *)fname
;
737 ufoInFileName
= strdup(fname
);
738 if (ufoInFileName
== NULL
) ufoFatal("out of memory for filename info");
740 ufoInFileNameLen
= fnlen
;
741 ufoInFileNameHash
= fnhash
;
743 if (reuse
&& fname
!= NULL
) free((void *)fname
);
749 //==========================================================================
753 //==========================================================================
754 UFO_FORCE_INLINE
void ufoSetInFileName (const char *fname
) {
755 ufoSetInFileNameEx(fname
, 0);
759 //==========================================================================
761 // ufoSetInFileNameReuse
763 //==========================================================================
764 UFO_FORCE_INLINE
void ufoSetInFileNameReuse (const char *fname
) {
765 ufoSetInFileNameEx(fname
, 1);
769 //==========================================================================
773 //==========================================================================
774 static UfoHandle
*ufoAllocHandle (uint32_t typeid) {
775 ufo_assert(typeid != UFO_HANDLE_FREE
);
776 UfoHandle
*newh
= ufoHandleFreeList
;
778 if (ufoHandlesUsed
== ufoHandlesAlloted
) {
779 uint32_t newsz
= ufoHandlesAlloted
+ 16384;
780 // due to offsets, this is the maximum number of handles we can have
781 if (newsz
> 0x1ffffU
) {
782 if (ufoHandlesAlloted
> 0x1ffffU
) ufoFatal("too many dynamic handles");
783 newsz
= 0x1ffffU
+ 1U;
784 ufo_assert(newsz
> ufoHandlesAlloted
);
786 UfoHandle
**nh
= realloc(ufoHandles
, sizeof(ufoHandles
[0]) * newsz
);
787 if (nh
== NULL
) ufoFatal("out of memory for handle table");
789 ufoHandlesAlloted
= newsz
;
791 newh
= calloc(1, sizeof(UfoHandle
));
792 if (newh
== NULL
) ufoFatal("out of memory for handle info");
793 ufoHandles
[ufoHandlesUsed
] = newh
;
794 // setup new handle info
795 newh
->ufoHandle
= (ufoHandlesUsed
<< UFO_ADDR_HANDLE_SHIFT
) | UFO_ADDR_HANDLE_BIT
;
798 ufo_assert(newh
->typeid == UFO_HANDLE_FREE
);
799 ufoHandleFreeList
= newh
->next
;
801 // setup new handle info
802 newh
->typeid = typeid;
811 //==========================================================================
815 //==========================================================================
816 static void ufoFreeHandle (UfoHandle
*hh
) {
818 ufo_assert(hh
->typeid != UFO_HANDLE_FREE
);
819 if (hh
->data
) free(hh
->data
);
820 hh
->typeid = UFO_HANDLE_FREE
;
824 hh
->next
= ufoHandleFreeList
;
825 ufoHandleFreeList
= hh
;
830 //==========================================================================
834 //==========================================================================
835 static UfoHandle
*ufoGetHandle (uint32_t hh
) {
837 if (hh
!= 0 && (hh
& UFO_ADDR_HANDLE_BIT
) != 0) {
838 hh
= (hh
& UFO_ADDR_HANDLE_MASK
) >> UFO_ADDR_HANDLE_SHIFT
;
839 if (hh
< ufoHandlesUsed
) {
840 res
= ufoHandles
[hh
];
841 if (res
->typeid == UFO_HANDLE_FREE
) res
= NULL
;
852 #define POP_PREPARE_HANDLE_XX() \
853 if ((hx & UFO_ADDR_HANDLE_BIT) == 0) ufoFatal("not a handle"); \
854 if (idx > 0x1fffffffU - UFO_ADDR_HANDLE_OFS_MASK) ufoFatal("handle index %u out of range", idx); \
855 idx += (hx & UFO_ADDR_HANDLE_OFS_MASK); \
856 UfoHandle *hh = ufoGetHandle(hx); \
857 if (hh == NULL) ufoFatal("invalid handle")
859 UFO_DISABLE_INLINE
uint32_t ufoHandleLoadByte (uint32_t hx
, uint32_t idx
) {
860 POP_PREPARE_HANDLE_XX();
861 if (idx
>= hh
->size
) ufoFatal("handle index %u out of range (%u)", idx
, hh
->size
);
862 return hh
->data
[idx
];
865 UFO_DISABLE_INLINE
uint32_t ufoHandleLoadWord (uint32_t hx
, uint32_t idx
) {
866 POP_PREPARE_HANDLE_XX();
867 if (idx
>= hh
->size
|| hh
->size
- idx
< 2u) {
868 ufoFatal("handle index %u out of range (%u)", idx
, hh
->size
);
870 #ifdef UFO_FAST_MEM_ACCESS
871 return *(const uint16_t *)(hh
->data
+ idx
);
873 uint32_t res
= hh
->data
[idx
];
874 res
|= hh
->data
[idx
+ 1u] << 8;
879 UFO_DISABLE_INLINE
uint32_t ufoHandleLoadCell (uint32_t hx
, uint32_t idx
) {
880 POP_PREPARE_HANDLE_XX();
881 if (idx
>= hh
->size
|| hh
->size
- idx
< 4u) {
882 ufoFatal("handle index %u out of range (%u)", idx
, hh
->size
);
884 #ifdef UFO_FAST_MEM_ACCESS
885 return *(const uint32_t *)(hh
->data
+ idx
);
887 uint32_t res
= hh
->data
[idx
];
888 res
|= hh
->data
[idx
+ 1u] << 8;
889 res
|= hh
->data
[idx
+ 2u] << 16;
890 res
|= hh
->data
[idx
+ 3u] << 24;
895 UFO_DISABLE_INLINE
void ufoHandleStoreByte (uint32_t hx
, uint32_t idx
, uint32_t value
) {
896 POP_PREPARE_HANDLE_XX();
897 if (idx
>= hh
->size
) ufoFatal("handle index %u out of range (%u)", idx
, hh
->size
);
898 hh
->data
[idx
] = (uint8_t)value
;
901 UFO_DISABLE_INLINE
void ufoHandleStoreWord (uint32_t hx
, uint32_t idx
, uint32_t value
) {
902 POP_PREPARE_HANDLE_XX();
903 if (idx
>= hh
->size
|| hh
->size
- idx
< 2u) {
904 ufoFatal("handle index %u out of range (%u)", idx
, hh
->size
);
906 #ifdef UFO_FAST_MEM_ACCESS
907 *(uint16_t *)(hh
->data
+ idx
) = (uint16_t)value
;
909 hh
->data
[idx
] = (uint8_t)value
;
910 hh
->data
[idx
+ 1u] = (uint8_t)(value
>> 8);
914 UFO_DISABLE_INLINE
void ufoHandleStoreCell (uint32_t hx
, uint32_t idx
, uint32_t value
) {
915 POP_PREPARE_HANDLE_XX();
916 if (idx
>= hh
->size
|| hh
->size
- idx
< 4u) {
917 ufoFatal("handle index %u out of range (%u)", idx
, hh
->size
);
919 #ifdef UFO_FAST_MEM_ACCESS
920 *(uint32_t *)(hh
->data
+ idx
) = value
;
922 hh
->data
[idx
] = (uint8_t)value
;
923 hh
->data
[idx
+ 1u] = (uint8_t)(value
>> 8);
924 hh
->data
[idx
+ 2u] = (uint8_t)(value
>> 16);
925 hh
->data
[idx
+ 3u] = (uint8_t)(value
>> 24);
930 //==========================================================================
934 //==========================================================================
935 static void setLastIncPath (const char *fname
, int system
) {
936 if (fname
== NULL
|| fname
[0] == 0) {
938 if (ufoLastSysIncPath
) free(ufoLastIncPath
);
939 ufoLastSysIncPath
= NULL
;
941 if (ufoLastIncPath
) free(ufoLastIncPath
);
942 ufoLastIncPath
= strdup(".");
948 if (ufoLastSysIncPath
) free(ufoLastSysIncPath
);
949 ufoLastSysIncPath
= strdup(fname
);
950 lslash
= ufoLastSysIncPath
;
951 cpos
= ufoLastSysIncPath
;
953 if (ufoLastIncPath
) free(ufoLastIncPath
);
954 ufoLastIncPath
= strdup(fname
);
955 lslash
= ufoLastIncPath
;
956 cpos
= ufoLastIncPath
;
960 if (*cpos
== '/' || *cpos
== '\\') lslash
= cpos
;
962 if (*cpos
== '/') lslash
= cpos
;
971 //==========================================================================
973 // ufoClearIncludePath
975 // required for UrAsm
977 //==========================================================================
978 void ufoClearIncludePath (void) {
979 if (ufoLastIncPath
!= NULL
) {
980 free(ufoLastIncPath
);
981 ufoLastIncPath
= NULL
;
983 if (ufoLastSysIncPath
!= NULL
) {
984 free(ufoLastSysIncPath
);
985 ufoLastSysIncPath
= NULL
;
990 //==========================================================================
994 //==========================================================================
995 static void ufoErrorPrintFile (FILE *fo
, const char *errwarn
) {
996 if (ufoInFileName
!= NULL
) {
997 fprintf(fo
, "UFO %s at file %s, line %d: ", errwarn
, ufoInFileName
, ufoInFileLine
);
999 fprintf(fo
, "UFO %s somewhere in time: ", errwarn
);
1004 //==========================================================================
1008 //==========================================================================
1009 static void ufoErrorMsgV (const char *errwarn
, const char *fmt
, va_list ap
) {
1011 if (!ufoLastEmitWasCR
) { printf("\n"); ufoLastEmitWasCR
= 1; }
1012 ufoErrorPrintFile(stderr
, errwarn
);
1013 vfprintf(stderr
, fmt
, ap
);
1015 fputc('\n', stderr
);
1020 //==========================================================================
1024 //==========================================================================
1025 __attribute__((format(printf
, 1, 2)))
1026 void ufoWarning (const char *fmt
, ...) {
1029 ufoErrorMsgV("WARNING", fmt
, ap
);
1033 //==========================================================================
1037 //==========================================================================
1038 __attribute__((noreturn
)) __attribute__((format(printf
, 1, 2)))
1039 void ufoFatal (const char *fmt
, ...) {
1045 ufoErrorMsgV("ERROR", fmt
, ap
);
1046 if (!ufoInBacktrace
) {
1048 ufoBacktrace(ufoIP
, 1);
1051 fprintf(stderr
, "DOUBLE FATAL: error in backtrace!\n");
1054 #ifdef UFO_DEBUG_FATAL_ABORT
1063 // ////////////////////////////////////////////////////////////////////////// //
1064 // working with the stacks
1065 #define UFO_TOS (ufoDStack[ufoSP - 1u])
1066 #define UFO_RTOS (ufoRStack[ufoRP - 1u])
1068 #define UFO_S(n_) (ufoDStack[ufoSP - 1u - (n_)])
1069 #define UFO_R(n_) (ufoRStack[ufoRP - 1u - (n_)])
1071 #define UFO_STACK(n_) if (ufoSP < (uint32_t)(n_)) ufoFatal("data stack underflow")
1072 #define UFO_RSTACK(n_) if (ufoRP < (uint32_t)(n_)) ufoFatal("return stack underflow")
1074 UFO_FORCE_INLINE
void ufoPush (uint32_t v
) { if (ufoSP
>= UFO_DSTACK_SIZE
) ufoFatal("data stack overflow"); ufoDStack
[ufoSP
++] = v
; }
1075 UFO_FORCE_INLINE
void ufoDrop (void) { if (ufoSP
== 0) ufoFatal("data stack underflow"); ufoSP
-= 1u; }
1076 UFO_FORCE_INLINE
uint32_t ufoPop (void) { if (ufoSP
== 0) { ufoFatal("data stack underflow"); } return ufoDStack
[--ufoSP
]; }
1077 UFO_FORCE_INLINE
uint32_t ufoPeek (void) { if (ufoSP
== 0) ufoFatal("data stack underflow"); return ufoDStack
[ufoSP
-1u]; }
1078 UFO_FORCE_INLINE
void ufoDup (void) { if (ufoSP
== 0) ufoFatal("data stack underflow"); ufoPush(ufoDStack
[ufoSP
-1u]); }
1079 UFO_FORCE_INLINE
void ufoOver (void) { if (ufoSP
< 2u) ufoFatal("data stack underflow"); ufoPush(ufoDStack
[ufoSP
-2u]); }
1080 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
; }
1081 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
; }
1082 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
; }
1084 UFO_FORCE_INLINE
void ufo2Dup (void) { ufoOver(); ufoOver(); }
1085 UFO_FORCE_INLINE
void ufo2Drop (void) { UFO_STACK(2); ufoSP
-= 2u; }
1086 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
); }
1087 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
; }
1089 UFO_FORCE_INLINE
void ufoRPush (uint32_t v
) { if (ufoRP
>= UFO_RSTACK_SIZE
) ufoFatal("return stack overflow"); ufoRStack
[ufoRP
++] = v
; }
1090 UFO_FORCE_INLINE
void ufoRDrop (void) { if (ufoRP
== 0) ufoFatal("return stack underflow"); --ufoRP
; }
1091 UFO_FORCE_INLINE
uint32_t ufoRPop (void) { if (ufoRP
== 0) ufoFatal("return stack underflow"); return ufoRStack
[--ufoRP
]; }
1092 UFO_FORCE_INLINE
uint32_t ufoRPeek (void) { if (ufoRP
== 0) ufoFatal("return stack underflow"); return ufoRStack
[ufoRP
-1u]; }
1093 UFO_FORCE_INLINE
void ufoRDup (void) { if (ufoRP
== 0) ufoFatal("return stack underflow"); ufoPush(ufoRStack
[ufoRP
-1u]); }
1095 UFO_FORCE_INLINE
void ufoPushBool (int v
) { ufoPush(v
? ufoTrueValue
: 0u); }
1098 #ifndef UFO_HUGE_IMAGES
1099 //==========================================================================
1103 //==========================================================================
1104 static void ufoImgEnsureSize (uint32_t addr
) {
1105 if ((addr
& UFO_ADDR_SPECIAL_BITS_MASK
) != 0) ufoFatal("ufoImgEnsureSize: internal error");
1106 if (addr
>= ufoImageSize
) {
1107 // 64MB should be enough for everyone!
1108 if (addr
>= 0x04000000U
) {
1109 ufoFatal("image grown too big (addr=0%08XH)", addr
);
1111 const uint32_t osz
= ufoImageSize
;
1112 // grow by 1MB steps
1113 const uint32_t nsz
= (addr
|0x000fffffU
) + 1U;
1114 ufo_assert(nsz
> addr
);
1115 uint32_t *nimg
= realloc(ufoImage
, nsz
);
1117 ufoFatal("out of memory for UFO image (%u -> %u MBs)",
1118 ufoImageSize
/ 1024u / 1024u,
1119 nsz
/ 1024u / 1024u);
1123 memset((char *)ufoImage
+ osz
, 0, (nsz
- osz
));
1128 //==========================================================================
1132 //==========================================================================
1133 static void ufoImgEnsureTemp (uint32_t addr
) {
1134 if ((addr
& UFO_ADDR_SPECIAL_BITS_MASK
) != 0) ufoFatal("ufoImgEnsureTemp: internal error");
1135 if (addr
>= ufoImageTempSize
) {
1136 if (addr
>= 1024u * 1024u) {
1137 ufoFatal("Forth segmentation fault at address 0x%08X", addr
| UFO_ADDR_TEMP_BIT
);
1139 const uint32_t osz
= ufoImageTempSize
;
1140 // grow by 64KB steps
1141 const uint32_t nsz
= (addr
|0x0000ffffU
) + 1U;
1142 uint32_t *nimg
= realloc(ufoImageTemp
, nsz
);
1144 ufoFatal("out of memory for temp UFO image (%u -> %u KBs)",
1145 ufoImageTempSize
/ 1024u,
1148 ufoImageTemp
= nimg
;
1149 ufoImageTempSize
= nsz
;
1150 memset((char *)ufoImageTemp
+ osz
, 0, (nsz
- osz
));
1156 #ifdef UFO_FAST_MEM_ACCESS
1157 //==========================================================================
1163 //==========================================================================
1164 UFO_FORCE_INLINE
void ufoImgPutU8 (uint32_t addr
, const uint32_t value
) {
1165 if ((addr
& UFO_ADDR_SPECIAL_BITS_MASK
) == 0) {
1166 if (addr
>= ufoImageSize
) {
1167 #ifdef UFO_HUGE_IMAGES
1168 ufoFatal("Forth segmentation fault at address 0x%08X", addr
);
1170 ufoImgEnsureSize(addr
);
1173 *((uint8_t *)ufoImage
+ addr
) = (uint8_t)value
;
1174 } else if (addr
& UFO_ADDR_TEMP_BIT
) {
1175 addr
&= UFO_ADDR_TEMP_MASK
;
1176 if (addr
>= ufoImageTempSize
) {
1177 #ifdef UFO_HUGE_IMAGES
1178 ufoFatal("Forth segmentation fault at address 0x%08X", addr
);
1180 ufoImgEnsureTemp(addr
);
1183 *((uint8_t *)ufoImageTemp
+ addr
) = (uint8_t)value
;
1184 } else if ((addr
& UFO_ADDR_HANDLE_BIT
) != 0) {
1185 ufoHandleStoreByte(addr
, 0, value
);
1187 ufoFatal("Forth segmentation fault at address 0x%08X", addr
);
1192 //==========================================================================
1198 //==========================================================================
1199 UFO_FORCE_INLINE
void ufoImgPutU16 (uint32_t addr
, const uint32_t value
) {
1200 if ((addr
& UFO_ADDR_SPECIAL_BITS_MASK
) == 0) {
1201 if (addr
+ 1u >= ufoImageSize
) {
1202 #ifdef UFO_HUGE_IMAGES
1203 ufoFatal("Forth segmentation fault at address 0x%08X", addr
);
1205 ufoImgEnsureSize(addr
+ 1u);
1208 *(uint16_t *)((uint8_t *)ufoImage
+ addr
) = (uint16_t)value
;
1209 } else if (addr
& UFO_ADDR_TEMP_BIT
) {
1210 addr
&= UFO_ADDR_TEMP_MASK
;
1211 if (addr
+ 1u >= ufoImageTempSize
) {
1212 #ifdef UFO_HUGE_IMAGES
1213 ufoFatal("Forth segmentation fault at address 0x%08X", addr
);
1215 ufoImgEnsureTemp(addr
+ 1u);
1218 *(uint16_t *)((uint8_t *)ufoImageTemp
+ addr
) = (uint16_t)value
;
1219 } else if ((addr
& UFO_ADDR_HANDLE_BIT
) != 0) {
1220 ufoHandleStoreWord(addr
, 0, value
);
1222 ufoFatal("Forth segmentation fault at address 0x%08X", addr
);
1227 //==========================================================================
1233 //==========================================================================
1234 UFO_FORCE_INLINE
void ufoImgPutU32 (uint32_t addr
, const uint32_t value
) {
1235 if ((addr
& UFO_ADDR_SPECIAL_BITS_MASK
) == 0) {
1236 if (addr
+ 3u >= ufoImageSize
) {
1237 #ifdef UFO_HUGE_IMAGES
1238 ufoFatal("Forth segmentation fault at address 0x%08X", addr
);
1240 ufoImgEnsureSize(addr
+ 3u);
1243 *(uint32_t *)((uint8_t *)ufoImage
+ addr
) = value
;
1244 } else if (addr
& UFO_ADDR_TEMP_BIT
) {
1245 addr
&= UFO_ADDR_TEMP_MASK
;
1246 if (addr
+ 3u >= ufoImageTempSize
) {
1247 #ifdef UFO_HUGE_IMAGES
1248 ufoFatal("Forth segmentation fault at address 0x%08X", addr
);
1250 ufoImgEnsureTemp(addr
+ 3u);
1253 *(uint32_t *)((uint8_t *)ufoImageTemp
+ addr
) = value
;
1254 } else if ((addr
& UFO_ADDR_HANDLE_BIT
) != 0) {
1255 ufoHandleStoreCell(addr
, 0, value
);
1257 ufoFatal("Forth segmentation fault at address 0x%08X", addr
);
1262 //==========================================================================
1268 //==========================================================================
1269 UFO_FORCE_INLINE
uint32_t ufoImgGetU8 (uint32_t addr
) {
1270 if ((addr
& UFO_ADDR_SPECIAL_BITS_MASK
) == 0) {
1271 if (addr
>= ufoImageSize
) {
1272 // accessing unallocated image area is segmentation fault
1273 ufoFatal("Forth segmentation fault (unallocated access) at address 0x%08X", addr
);
1275 return *((const uint8_t *)ufoImage
+ addr
);
1276 } else if (addr
& UFO_ADDR_TEMP_BIT
) {
1277 addr
&= UFO_ADDR_TEMP_MASK
;
1278 if (addr
>= ufoImageTempSize
) {
1279 // accessing unallocated image area is segmentation fault
1280 ufoFatal("Forth segmentation fault (unallocated access) at address 0x%08X", addr
| UFO_ADDR_TEMP_BIT
);
1282 return *((const uint8_t *)ufoImageTemp
+ addr
);
1283 } else if ((addr
& UFO_ADDR_HANDLE_BIT
) != 0) {
1284 return ufoHandleLoadByte(addr
, 0);
1286 ufoFatal("Forth segmentation fault at address 0x%08X", addr
);
1291 //==========================================================================
1297 //==========================================================================
1298 UFO_FORCE_INLINE
uint32_t ufoImgGetU16 (uint32_t addr
) {
1299 if ((addr
& UFO_ADDR_SPECIAL_BITS_MASK
) == 0) {
1300 if (addr
+ 1u >= ufoImageSize
) {
1301 // accessing unallocated image area is segmentation fault
1302 ufoFatal("Forth segmentation fault (unallocated access) at address 0x%08X", addr
);
1304 return *(const uint16_t *)((const uint8_t *)ufoImage
+ addr
);
1305 } else if (addr
& UFO_ADDR_TEMP_BIT
) {
1306 addr
&= UFO_ADDR_TEMP_MASK
;
1307 if (addr
+ 1u >= ufoImageTempSize
) {
1308 // accessing unallocated image area is segmentation fault
1309 ufoFatal("Forth segmentation fault (unallocated access) at address 0x%08X", addr
| UFO_ADDR_TEMP_BIT
);
1311 return *(const uint16_t *)((const uint8_t *)ufoImageTemp
+ addr
);
1312 } else if ((addr
& UFO_ADDR_HANDLE_BIT
) != 0) {
1313 return ufoHandleLoadWord(addr
, 0);
1315 ufoFatal("Forth segmentation fault at address 0x%08X", addr
);
1320 //==========================================================================
1326 //==========================================================================
1327 UFO_FORCE_INLINE
uint32_t ufoImgGetU32 (uint32_t addr
) {
1328 if ((addr
& UFO_ADDR_SPECIAL_BITS_MASK
) == 0) {
1329 if (addr
+ 3u >= ufoImageSize
) {
1330 // accessing unallocated image area is segmentation fault
1331 ufoFatal("Forth segmentation fault (unallocated access) at address 0x%08X", addr
);
1333 return *(const uint32_t *)((const uint8_t *)ufoImage
+ addr
);
1334 } else if (addr
& UFO_ADDR_TEMP_BIT
) {
1335 addr
&= UFO_ADDR_TEMP_MASK
;
1336 if (addr
+ 3u >= ufoImageTempSize
) {
1337 // accessing unallocated image area is segmentation fault
1338 ufoFatal("Forth segmentation fault (unallocated access) at address 0x%08X", addr
| UFO_ADDR_TEMP_BIT
);
1340 return *(const uint32_t *)((const uint8_t *)ufoImageTemp
+ addr
);
1341 } else if ((addr
& UFO_ADDR_HANDLE_BIT
) != 0) {
1342 return ufoHandleLoadCell(addr
, 0);
1344 ufoFatal("Forth segmentation fault at address 0x%08X", addr
);
1350 //==========================================================================
1356 //==========================================================================
1357 UFO_FORCE_INLINE
void ufoImgPutU8 (uint32_t addr
, const uint32_t value
) {
1359 if ((addr
& UFO_ADDR_SPECIAL_BITS_MASK
) == 0) {
1360 if (addr
>= ufoImageSize
) {
1361 #ifdef UFO_HUGE_IMAGES
1362 ufoFatal("Forth segmentation fault at address 0x%08X", addr
);
1364 ufoImgEnsureSize(addr
);
1367 imgptr
= &ufoImage
[addr
/4u];
1368 } else if (addr
& UFO_ADDR_TEMP_BIT
) {
1369 addr
&= UFO_ADDR_TEMP_MASK
;
1370 if (addr
>= ufoImageTempSize
) {
1371 #ifdef UFO_HUGE_IMAGES
1372 ufoFatal("Forth segmentation fault at address 0x%08X", addr
);
1374 ufoImgEnsureTemp(addr
);
1377 imgptr
= &ufoImageTemp
[addr
/4u];
1378 } else if ((addr
& UFO_ADDR_HANDLE_BIT
) != 0) {
1379 ufoHandleStoreByte(addr
, 0, value
);
1381 ufoFatal("Forth segmentation fault at address 0x%08X", addr
);
1383 const uint8_t val
= (uint8_t)value
;
1384 memcpy((uint8_t *)imgptr
+ (addr
&3), &val
, 1);
1388 //==========================================================================
1394 //==========================================================================
1395 UFO_FORCE_INLINE
void ufoImgPutU16 (uint32_t addr
, const uint32_t value
) {
1396 ufoImgPutU8(addr
, value
&0xffU
);
1397 ufoImgPutU8(addr
+ 1u, (value
>>8)&0xffU
);
1401 //==========================================================================
1407 //==========================================================================
1408 UFO_FORCE_INLINE
void ufoImgPutU32 (uint32_t addr
, const uint32_t value
) {
1409 ufoImgPutU16(addr
, value
&0xffffU
);
1410 ufoImgPutU16(addr
+ 2u, (value
>>16)&0xffffU
);
1414 //==========================================================================
1420 //==========================================================================
1421 UFO_FORCE_INLINE
uint32_t ufoImgGetU8 (uint32_t addr
) {
1423 if ((addr
& UFO_ADDR_SPECIAL_BITS_MASK
) == 0) {
1424 if (addr
>= ufoImageSize
) {
1425 // accessing unallocated image area is segmentation fault
1426 ufoFatal("Forth segmentation fault (unallocated access) at address 0x%08X", addr
);
1428 imgptr
= &ufoImage
[addr
/4u];
1429 } else if (addr
& UFO_ADDR_TEMP_BIT
) {
1430 addr
&= UFO_ADDR_TEMP_MASK
;
1431 if (addr
>= ufoImageTempSize
) return 0;
1432 imgptr
= &ufoImageTemp
[addr
/4u];
1433 } else if ((addr
& UFO_ADDR_HANDLE_BIT
) != 0) {
1434 return ufoHandleLoadByte(addr
, 0, value
);
1436 ufoFatal("Forth segmentation fault at address 0x%08X", addr
);
1439 memcpy(&val
, (uint8_t *)imgptr
+ (addr
&3), 1);
1440 return (uint32_t)val
;
1444 //==========================================================================
1450 //==========================================================================
1451 UFO_FORCE_INLINE
uint32_t ufoImgGetU16 (uint32_t addr
) {
1452 return ufoImgGetU8(addr
) | (ufoImgGetU8(addr
+ 1u) << 8);
1456 //==========================================================================
1462 //==========================================================================
1463 UFO_FORCE_INLINE
uint32_t ufoImgGetU32 (uint32_t addr
) {
1464 return ufoImgGetU16(addr
) | (ufoImgGetU16(addr
+ 2u) << 16);
1469 //==========================================================================
1471 // ufoEnsureDebugSize
1473 //==========================================================================
1474 UFO_DISABLE_INLINE
void ufoEnsureDebugSize (uint32_t sdelta
) {
1475 ufo_assert(sdelta
!= 0);
1476 if (ufoDebugImageSize
!= 0) {
1477 if (ufoDebugImageUsed
+ sdelta
>= 0x40000000U
) ufoFatal("debug info too big");
1478 if (ufoDebugImageUsed
+ sdelta
> ufoDebugImageSize
) {
1479 // grow by 32KB, this should be more than enough
1480 const uint32_t newsz
= ((ufoDebugImageUsed
+ sdelta
) | 0x7fffU
) + 1u;
1481 uint8_t *ndb
= realloc(ufoDebugImage
, newsz
);
1482 if (ndb
== NULL
) ufoFatal("out of memory for debug info");
1483 ufoDebugImage
= ndb
;
1484 ufoDebugImageSize
= newsz
;
1487 // initial allocation: 32KB, quite a lot
1488 ufo_assert(ufoDebugImage
== NULL
);
1489 ufo_assert(ufoDebugImageUsed
== 0);
1490 ufoDebugImageSize
= 1024 * 32;
1491 ufoDebugImage
= malloc(ufoDebugImageSize
);
1492 if (ufoDebugImage
== NULL
) ufoFatal("out of memory for debug info");
1497 #define UFO_DBG_PUT_U4(val_) do { \
1498 const uint32_t vv_ = (val_); \
1499 *((uint32_t *)(ufoDebugImage + ufoDebugImageUsed)) = vv_; \
1500 ufoDebugImageUsed += 4u; \
1507 ...first line info header...
1508 line info header (or reset):
1509 db 0 ; zero line delta
1510 dw followFileInfoSize ; either it, or 0 if reused
1511 dd fileInfoOfs ; present only if reused
1519 dd nameLen ; without terminating 0
1520 ...name... (0-terminated)
1522 we will never compare file names: length and hash should provide
1523 good enough unique identifier.
1525 static uint8_t *ufoDebugImage = NULL;
1526 static uint32_t ufoDebugImageUsed = 0; // in bytes
1527 static uint32_t ufoDebugImageSize = 0; // in bytes
1528 static uint32_t ufoDebugFileNameHash = 0; // current file name hash
1529 static uint32_t ufoDebugFileNameLen = 0; // current file name length
1530 static uint32_t ufoDebugCurrDP = 0;
1534 //==========================================================================
1536 // ufoSkipDebugVarInt
1538 //==========================================================================
1539 static __attribute__((unused
)) uint32_t ufoSkipDebugVarInt (uint32_t ofs
) {
1542 if (ofs
>= ufoDebugImageUsed
) ufoFatal("invalid debug data");
1543 byte
= ufoDebugImage
[ofs
]; ofs
+= 1u;
1544 } while (byte
>= 0x80);
1549 //==========================================================================
1551 // ufoCalcDebugVarIntSize
1553 //==========================================================================
1554 UFO_FORCE_INLINE
uint8_t ufoCalcDebugVarIntSize (uint32_t v
) {
1564 //==========================================================================
1566 // ufoGetDebugVarInt
1568 //==========================================================================
1569 static __attribute__((unused
)) uint32_t ufoGetDebugVarInt (uint32_t ofs
) {
1574 if (ofs
>= ufoDebugImageUsed
) ufoFatal("invalid debug data");
1575 byte
= ufoDebugImage
[ofs
];
1576 v
|= (uint32_t)(byte
& 0x7f) << shift
;
1581 } while (byte
>= 0x80);
1586 //==========================================================================
1588 // ufoPutDebugVarInt
1590 //==========================================================================
1591 UFO_FORCE_INLINE
void ufoPutDebugVarInt (uint32_t v
) {
1592 ufoEnsureDebugSize(5u); // maximum size
1595 ufoDebugImage
[ufoDebugImageUsed
] = (uint8_t)(v
| 0x80u
);
1597 ufoDebugImage
[ufoDebugImageUsed
] = (uint8_t)v
;
1599 ufoDebugImageUsed
+= 1;
1605 #ifdef UFO_DEBUG_DEBUG
1606 //==========================================================================
1610 //==========================================================================
1611 static void ufoDumpDebugImage (void) {
1613 uint32_t dbgpos
= 4u; // first line header info
1614 uint32_t lastline
= 0;
1615 uint32_t lastdp
= 0;
1616 while (dbgpos
< ufoDebugImageUsed
) {
1617 if (ufoDebugImage
[dbgpos
] == 0) {
1619 dbgpos
+= 1u; // skip flag
1620 const uint32_t fhdrSize
= *(const uint16_t *)(ufoDebugImage
+ dbgpos
); dbgpos
+= 2u;
1621 lastdp
= ufoGetDebugVarInt(dbgpos
);
1622 dbgpos
= ufoSkipDebugVarInt(dbgpos
);
1623 if (fhdrSize
== 0) {
1625 const uint32_t infoOfs
= *(const uint32_t *)(ufoDebugImage
+ dbgpos
); dbgpos
+= 4u;
1626 fprintf(stderr
, "*** OLD FILE: %s\n", (const char *)(ufoDebugImage
+ infoOfs
+ 3u * 4u));
1627 fprintf(stderr
, "FILE NAME LEN: %u\n", ((const uint32_t *)(ufoDebugImage
+ infoOfs
))[2]);
1628 fprintf(stderr
, "FILE NAME HASH: 0x%08x\n", ((const uint32_t *)(ufoDebugImage
+ infoOfs
))[1]);
1631 fprintf(stderr
, "*** NEW FILE: %s\n", (const char *)(ufoDebugImage
+ dbgpos
+ 3u * 4u));
1632 fprintf(stderr
, "FILE NAME LEN: %u\n", ((const uint32_t *)(ufoDebugImage
+ dbgpos
))[2]);
1633 fprintf(stderr
, "FILE NAME HASH: 0x%08x\n", ((const uint32_t *)(ufoDebugImage
+ dbgpos
))[1]);
1636 fprintf(stderr
, "LINES-OFS: 0x%08x (hsz: %u -- 0x%08x)\n", dbgpos
, fhdrSize
, fhdrSize
);
1637 lastline
= ~(uint32_t)0;
1639 const uint32_t ln
= ufoGetDebugVarInt(dbgpos
);
1640 dbgpos
= ufoSkipDebugVarInt(dbgpos
);
1641 ufo_assert(ln
!= 0);
1643 const uint32_t edp
= ufoGetDebugVarInt(dbgpos
);
1644 dbgpos
= ufoSkipDebugVarInt(dbgpos
);
1646 fprintf(stderr
, " line %6u: edp=%u\n", lastline
, lastdp
);
1654 //==========================================================================
1656 // ufoRecordDebugCheckFile
1658 // if we moved to the new file:
1659 // put "line info header"
1660 // put new file info (or reuse old)
1662 //==========================================================================
1663 UFO_FORCE_INLINE
void ufoRecordDebugCheckFile (void) {
1664 if (ufoDebugImageUsed
== 0 ||
1665 ufoDebugFileNameLen
!= ufoInFileNameLen
||
1666 ufoDebugFileNameHash
!= ufoInFileNameHash
)
1668 // new file record (or reuse old one)
1669 const int initial
= (ufoDebugImageUsed
== 0);
1670 uint32_t fileRec
= 0;
1671 // try to find and old one
1673 fileRec
= *(const uint32_t *)ufoDebugImage
;
1675 fprintf(stderr
, "*** NEW-FILE(%u): 0x%08x: <%s> (frec=0x%08x)\n", ufoInFileNameLen
,
1676 ufoInFileNameHash
, ufoInFileName
, fileRec
);
1678 while (fileRec
!= 0 &&
1679 (ufoInFileNameLen
!= ((const uint32_t *)(ufoDebugImage
+ fileRec
))[1] ||
1680 ufoInFileNameHash
!= ((const uint32_t *)(ufoDebugImage
+ fileRec
))[2]))
1683 fprintf(stderr
, "*** FRCHECK: 0x%08x\n", fileRec
);
1684 fprintf(stderr
, " FILE NAME: %s\n", (const char *)(ufoDebugImage
+ fileRec
+ 3u * 4u));
1685 fprintf(stderr
, " FILE NAME LEN: %u\n", ((const uint32_t *)(ufoDebugImage
+ fileRec
))[2]);
1686 fprintf(stderr
, " FILE NAME HASH: 0x%08x\n", ((const uint32_t *)(ufoDebugImage
+ fileRec
))[1]);
1687 fprintf(stderr
, " FILE PREV: 0x%08x\n", *(const uint32_t *)(ufoDebugImage
+ fileRec
));
1689 fileRec
= *(const uint32_t *)(ufoDebugImage
+ fileRec
);
1692 fprintf(stderr
, "*** FRCHECK-DONE: 0x%08x\n", fileRec
);
1694 fprintf(stderr
, " FILE NAME: %s\n", (const char *)(ufoDebugImage
+ fileRec
+ 3u * 4u));
1695 fprintf(stderr
, " FILE NAME LEN: %u\n", ((const uint32_t *)(ufoDebugImage
+ fileRec
))[2]);
1696 fprintf(stderr
, " FILE NAME HASH: 0x%08x\n", ((const uint32_t *)(ufoDebugImage
+ fileRec
))[1]);
1697 fprintf(stderr
, " FILE PREV: 0x%08x\n", *(const uint32_t *)(ufoDebugImage
+ fileRec
));
1701 ufoEnsureDebugSize(8u);
1702 *(uint32_t *)ufoDebugImage
= 0;
1704 // write "line info header"
1706 ufoEnsureDebugSize(32u);
1707 ufoDebugImage
[ufoDebugImageUsed
] = 0; ufoDebugImageUsed
+= 1u; // header flag (0 delta)
1708 // file record size: 0 (reused)
1709 *((uint16_t *)(ufoDebugImage
+ ufoDebugImageUsed
)) = 0; ufoDebugImageUsed
+= 2u;
1711 ufoPutDebugVarInt(ufoDebugCurrDP
);
1713 UFO_DBG_PUT_U4(fileRec
);
1715 // name, trailing 0 byte, 3 dword fields
1716 const uint32_t finfoSize
= ufoInFileNameLen
+ 1u + 3u * 4u;
1717 ufo_assert(finfoSize
< 65536u);
1718 ufoEnsureDebugSize(finfoSize
+ 32u);
1720 *(uint32_t *)ufoDebugImage
= 0;
1721 ufoDebugImageUsed
= 4;
1723 ufoDebugImage
[ufoDebugImageUsed
] = 0; ufoDebugImageUsed
+= 1u; // header flag (0 delta)
1725 *((uint16_t *)(ufoDebugImage
+ ufoDebugImageUsed
)) = (uint16_t)finfoSize
; ufoDebugImageUsed
+= 2u;
1727 ufoPutDebugVarInt(ufoDebugCurrDP
);
1728 // file record follows
1729 // fix file info offsets
1730 uint32_t lastOfs
= *(const uint32_t *)ufoDebugImage
;
1731 *(uint32_t *)ufoDebugImage
= ufoDebugImageUsed
;
1732 UFO_DBG_PUT_U4(lastOfs
);
1733 // save file info hash
1734 UFO_DBG_PUT_U4(ufoInFileNameHash
);
1735 // save file info length
1736 UFO_DBG_PUT_U4(ufoInFileNameLen
);
1738 if (ufoInFileNameLen
!= 0) {
1739 memcpy(ufoDebugImage
+ ufoDebugImageUsed
, ufoInFileName
, ufoInFileNameLen
+ 1u);
1740 ufoDebugImageUsed
+= ufoInFileNameLen
+ 1u;
1742 ufoDebugImage
[ufoDebugImageUsed
] = 0; ufoDebugImageUsed
+= 1u;
1745 ufoDebugFileNameLen
= ufoInFileNameLen
;
1746 ufoDebugFileNameHash
= ufoInFileNameHash
;
1747 ufoDebugLastLine
= ~(uint32_t)0;
1748 ufoDebugLastLinePCOfs
= 0;
1749 ufoDebugLastLineDP
= ufoDebugCurrDP
;
1754 //==========================================================================
1756 // ufoRecordDebugRecordLine
1758 //==========================================================================
1759 UFO_FORCE_INLINE
void ufoRecordDebugRecordLine (uint32_t line
, uint32_t newhere
) {
1760 if (line
== ufoDebugLastLine
) {
1761 ufo_assert(ufoDebugLastLinePCOfs
!= 0);
1762 ufoDebugImageUsed
= ufoDebugLastLinePCOfs
;
1765 fprintf(stderr
, "FL-NEW-LINE(0x%08x): <%s>; new line: %u (old: %u)\n",
1767 ufoInFileName
, line
, ufoDebugLastLine
);
1769 ufoPutDebugVarInt(line
- ufoDebugLastLine
);
1770 ufoDebugLastLinePCOfs
= ufoDebugImageUsed
;
1771 ufoDebugLastLine
= line
;
1772 ufoDebugLastLineDP
= ufoDebugCurrDP
;
1774 ufoPutDebugVarInt(newhere
- ufoDebugLastLineDP
);
1775 ufoDebugCurrDP
= newhere
;
1779 //==========================================================================
1783 //==========================================================================
1784 UFO_DISABLE_INLINE
void ufoRecordDebug (uint32_t newhere
) {
1785 if (newhere
> ufoDebugCurrDP
) {
1786 uint32_t ln
= (uint32_t)ufoInFileLine
;
1787 if (ln
== ~(uint32_t)0) ln
= 0;
1789 fprintf(stderr
, "FL: <%s>; line: %d\n", ufoInFileName
, ufoInFileLine
);
1791 ufoRecordDebugCheckFile();
1792 ufoRecordDebugRecordLine(ln
, newhere
);
1797 //==========================================================================
1799 // ufoGetWordEndAddrYFA
1801 //==========================================================================
1802 static uint32_t ufoGetWordEndAddrYFA (uint32_t yfa
) {
1804 const uint32_t oyfa
= yfa
;
1805 yfa
= ufoImgGetU32(yfa
); // YFA points to next YFA
1807 // last defined word
1808 if ((oyfa
& UFO_ADDR_TEMP_BIT
) == 0) {
1809 yfa
= ufoImgGetU32(ufoAddrDP
);
1811 yfa
= ufoImgGetU32(ufoAddrDPTemp
);
1814 yfa
= UFO_YFA_TO_WST(yfa
);
1823 //==========================================================================
1825 // ufoGetWordEndAddr
1827 //==========================================================================
1828 static uint32_t ufoGetWordEndAddr (const uint32_t cfa
) {
1830 const uint32_t lfa
= UFO_CFA_TO_LFA(cfa
);
1831 const uint32_t yfa
= UFO_LFA_TO_YFA(lfa
);
1832 return ufoGetWordEndAddrYFA(yfa
);
1839 //==========================================================================
1845 // WARNING: this is SLOW!
1847 //==========================================================================
1848 static uint32_t ufoFindWordForIP (const uint32_t ip
) {
1851 //fprintf(stderr, "ufoFindWordForIP:000: ip=0x%08x\n", ip);
1852 // iterate over all words
1853 uint32_t xfa
= ufoImgGetU32(ufoAddrLastXFA
);
1854 //fprintf(stderr, "ufoFindWordForIP:001: xfa=0x%08x\n", xfa);
1856 while (res
== 0 && xfa
!= 0) {
1857 const uint32_t yfa
= UFO_XFA_TO_YFA(xfa
);
1858 const uint32_t wst
= UFO_YFA_TO_WST(yfa
);
1859 //fprintf(stderr, "ufoFindWordForIP:002: yfa=0x%08x; wst=0x%08x\n", yfa, wst);
1860 const uint32_t wend
= ufoGetWordEndAddrYFA(yfa
);
1861 if (ip
>= wst
&& ip
< wend
) {
1862 res
= UFO_YFA_TO_NFA(yfa
);
1864 xfa
= ufoImgGetU32(xfa
);
1873 //==========================================================================
1877 // return file name or `NULL`
1879 // WARNING: this is SLOW!
1881 //==========================================================================
1882 static const char *ufoFindFileForIP (uint32_t ip
, uint32_t *line
,
1883 uint32_t *nlen
, uint32_t *nhash
)
1885 if (ip
!= 0 && ufoDebugImageUsed
!= 0) {
1886 const char *filename
= NULL
;
1887 uint32_t dbgpos
= 4u; // first line header info
1888 uint32_t lastline
= 0;
1889 uint32_t lastdp
= 0;
1890 uint32_t namelen
= 0;
1891 uint32_t namehash
= 0;
1892 while (dbgpos
< ufoDebugImageUsed
) {
1893 if (ufoDebugImage
[dbgpos
] == 0) {
1895 dbgpos
+= 1u; // skip flag
1896 const uint32_t fhdrSize
= *(const uint16_t *)(ufoDebugImage
+ dbgpos
); dbgpos
+= 2u;
1897 lastdp
= ufoGetDebugVarInt(dbgpos
);
1898 dbgpos
= ufoSkipDebugVarInt(dbgpos
);
1900 if (fhdrSize
== 0) {
1902 infoOfs
= *(const uint32_t *)(ufoDebugImage
+ dbgpos
); dbgpos
+= 4u;
1907 filename
= (const char *)(ufoDebugImage
+ infoOfs
+ 3u * 4u);
1908 namelen
= ((const uint32_t *)(ufoDebugImage
+ infoOfs
))[2];
1909 namehash
= ((const uint32_t *)(ufoDebugImage
+ infoOfs
))[1];
1910 if (filename
[0] == 0) filename
= NULL
;
1912 lastline
= ~(uint32_t)0;
1914 const uint32_t ln
= ufoGetDebugVarInt(dbgpos
);
1915 dbgpos
= ufoSkipDebugVarInt(dbgpos
);
1916 ufo_assert(ln
!= 0);
1918 const uint32_t edp
= ufoGetDebugVarInt(dbgpos
);
1919 dbgpos
= ufoSkipDebugVarInt(dbgpos
);
1920 if (ip
>= lastdp
&& ip
< lastdp
+ edp
) {
1921 if (line
) *line
= lastline
;
1922 if (nlen
) *nlen
= namelen
;
1923 if (nhash
) *nhash
= namehash
;
1930 if (line
) *line
= 0;
1931 if (nlen
) *nlen
= 0;
1932 if (nhash
) *nlen
= 0;
1937 //==========================================================================
1941 //==========================================================================
1942 UFO_FORCE_INLINE
void ufoBumpDP (uint32_t delta
) {
1943 const uint32_t dpa
= ufoImgGetU32(ufoAddrHereDP
);
1944 uint32_t dp
= ufoImgGetU32(dpa
);
1945 if ((dp
& UFO_ADDR_SPECIAL_BITS_MASK
) == 0) ufoRecordDebug(dp
+ delta
);
1947 ufoImgPutU32(dpa
, dp
);
1951 //==========================================================================
1955 //==========================================================================
1956 UFO_FORCE_INLINE
void ufoImgEmitU8 (uint32_t value
) {
1957 ufoImgPutU8(UFO_GET_DP(), value
);
1962 //==========================================================================
1966 //==========================================================================
1967 UFO_FORCE_INLINE
void ufoImgEmitU16 (uint32_t value
) {
1968 ufoImgPutU16(UFO_GET_DP(), value
);
1973 //==========================================================================
1977 //==========================================================================
1978 UFO_FORCE_INLINE
void ufoImgEmitU32 (uint32_t value
) {
1979 ufoImgPutU32(UFO_GET_DP(), value
);
1984 //==========================================================================
1988 //==========================================================================
1989 UFO_FORCE_INLINE
void ufoImgEmitCFA (uint32_t cfa
) {
1990 const uint32_t addr
= UFO_GET_DP();
1991 ufoImgPutU32(addr
, cfa
);
1992 ufoImgPutU32(addr
+ 4u, 0);
1997 #ifdef UFO_FAST_MEM_ACCESS
1999 //==========================================================================
2001 // ufoImgEmitU32_NoInline
2005 //==========================================================================
2006 UFO_FORCE_INLINE
void ufoImgEmitU32_NoInline (uint32_t value
) {
2007 ufoImgPutU32(UFO_GET_DP(), value
);
2013 //==========================================================================
2015 // ufoImgEmitU32_NoInline
2019 //==========================================================================
2020 UFO_DISABLE_INLINE
void ufoImgEmitU32_NoInline (uint32_t value
) {
2021 ufoImgPutU32(UFO_GET_DP(), value
);
2028 //==========================================================================
2032 //==========================================================================
2033 UFO_FORCE_INLINE
void ufoImgEmitAlign (void) {
2034 while ((UFO_GET_DP() & 3) != 0) ufoImgEmitU8(0);
2038 //==========================================================================
2042 //==========================================================================
2043 UFO_FORCE_INLINE
void ufoResetTib (void) {
2044 uint32_t defTIB
= ufoImgGetU32(ufoAddrDefTIB
);
2045 //fprintf(stderr, "ufoResetTib(%p): defTIB=0x%08x\n", ufoCurrState, defTIB);
2047 // create new TIB handle
2048 UfoHandle
*tibh
= ufoAllocHandle(0x69a029a6); // arbitrary number
2049 defTIB
= tibh
->ufoHandle
;
2050 ufoImgPutU32(ufoAddrDefTIB
, defTIB
);
2052 if ((defTIB
& UFO_ADDR_HANDLE_BIT
) != 0) {
2053 UfoHandle
*hh
= ufoGetHandle(defTIB
);
2054 if (hh
== NULL
) ufoFatal("default TIB is not allocated");
2055 if (hh
->size
== 0) {
2056 ufo_assert(hh
->data
== NULL
);
2057 hh
->data
= calloc(1, UFO_ADDR_HANDLE_OFS_MASK
+ 1);
2058 if (hh
->data
== NULL
) ufoFatal("out of memory for default TIB");
2059 hh
->size
= UFO_ADDR_HANDLE_OFS_MASK
+ 1;
2062 const uint32_t oldA
= ufoRegA
;
2063 ufoImgPutU32(ufoAddrTIBx
, defTIB
);
2064 ufoImgPutU32(ufoAddrINx
, 0);
2066 ufoPush(0); // value
2067 ufoPush(0); // offset
2068 UFCALL(CPOKE_REGA_IDX
);
2073 //==========================================================================
2077 //==========================================================================
2078 UFO_DISABLE_INLINE
void ufoTibEnsureSize (uint32_t size
) {
2079 if (size
> 1024u * 1024u * 256u) ufoFatal("TIB size too big");
2080 const uint32_t tib
= ufoImgGetU32(ufoAddrTIBx
);
2081 //fprintf(stderr, "ufoTibEnsureSize: TIB=0x%08x; size=%u\n", tib, size);
2082 if ((tib
& UFO_ADDR_HANDLE_BIT
) != 0) {
2083 UfoHandle
*hh
= ufoGetHandle(tib
);
2085 ufoFatal("cannot resize TIB, TIB is not a handle");
2087 if (hh
->size
< size
) {
2088 const uint32_t newsz
= (size
| 0xfffU
) + 1u;
2089 uint8_t *nx
= realloc(hh
->data
, newsz
);
2090 if (nx
== NULL
) ufoFatal("out of memory for restored TIB");
2097 ufoFatal("cannot resize TIB, TIB is not a handle (0x%08x)", tib
);
2103 //==========================================================================
2107 //==========================================================================
2109 UFO_DISABLE_INLINE uint32_t ufoTibGetSize (void) {
2110 const uint32_t tib = ufoImgGetU32(ufoAddrTIBx);
2111 if ((tib & UFO_ADDR_HANDLE_BIT) == 0) {
2112 ufoFatal("cannot query TIB, TIB is not a handle");
2114 UfoHandle *hh = ufoGetHandle(tib);
2116 ufoFatal("cannot query TIB, TIB is not a handle");
2123 //==========================================================================
2127 //==========================================================================
2128 UFO_FORCE_INLINE
uint8_t ufoTibPeekCh (void) {
2129 return (uint8_t)ufoImgGetU8(ufoImgGetU32(ufoAddrTIBx
) + ufoImgGetU32(ufoAddrINx
));
2133 //==========================================================================
2137 //==========================================================================
2138 UFO_FORCE_INLINE
uint8_t ufoTibPeekChOfs (uint32_t ofs
) {
2139 const uint32_t tib
= ufoImgGetU32(ufoAddrTIBx
);
2140 if (ofs
<= UFO_ADDR_HANDLE_OFS_MASK
|| (tib
& UFO_ADDR_HANDLE_BIT
) == 0) {
2141 return (uint8_t)ufoImgGetU8(tib
+ ufoImgGetU32(ufoAddrINx
) + ofs
);
2148 //==========================================================================
2152 //==========================================================================
2153 UFO_DISABLE_INLINE
void ufoTibPokeChOfs (uint8_t ch
, uint32_t ofs
) {
2154 const uint32_t oldA
= ufoRegA
;
2155 ufoRegA
= ufoImgGetU32(ufoAddrTIBx
);
2157 ufoPush(ufoImgGetU32(ufoAddrINx
) + ofs
);
2158 UFCALL(CPOKE_REGA_IDX
);
2163 //==========================================================================
2167 //==========================================================================
2168 UFO_FORCE_INLINE
uint8_t ufoTibGetCh (void) {
2169 const uint8_t ch
= ufoTibPeekCh();
2170 if (ch
) ufoImgPutU32(ufoAddrINx
, ufoImgGetU32(ufoAddrINx
) + 1u);
2175 //==========================================================================
2179 //==========================================================================
2180 UFO_FORCE_INLINE
void ufoTibSkipCh (void) {
2181 (void)ufoTibGetCh();
2185 // ////////////////////////////////////////////////////////////////////////// //
2186 // native CFA implementations
2189 //==========================================================================
2193 //==========================================================================
2194 static void ufoDoForth (uint32_t pfa
) {
2200 //==========================================================================
2204 //==========================================================================
2205 static void ufoDoVariable (uint32_t pfa
) {
2210 //==========================================================================
2212 // ufoDoUserVariable
2214 //==========================================================================
2215 static void ufoDoUserVariable (uint32_t pfa
) {
2216 ufoPush(ufoImgGetU32(pfa
));
2220 //==========================================================================
2224 //==========================================================================
2225 static void ufoDoValue (uint32_t pfa
) {
2226 ufoPush(ufoImgGetU32(pfa
));
2230 //==========================================================================
2234 //==========================================================================
2235 static void ufoDoConst (uint32_t pfa
) {
2236 ufoPush(ufoImgGetU32(pfa
));
2240 //==========================================================================
2244 //==========================================================================
2245 static void ufoDoDefer (uint32_t pfa
) {
2246 pfa
= ufoImgGetU32(pfa
);
2251 //==========================================================================
2255 //==========================================================================
2256 static void ufoDoDoes (uint32_t pfa
) {
2259 ufoIP
= ufoImgGetU32(UFO_PFA_TO_DOES_CFA(pfa
));
2263 //==========================================================================
2267 //==========================================================================
2268 static void ufoDoRedirect (uint32_t pfa
) {
2269 pfa
= ufoImgGetU32(UFO_PFA_TO_DOES_CFA(pfa
));
2274 //==========================================================================
2278 //==========================================================================
2279 static void ufoDoVoc (uint32_t pfa
) {
2280 ufoImgPutU32(ufoAddrContext
, ufoImgGetU32(pfa
));
2284 //==========================================================================
2288 //==========================================================================
2289 static void ufoDoCreate (uint32_t pfa
) {
2294 //==========================================================================
2298 // this also increments last used file id
2300 //==========================================================================
2301 static void ufoPushInFile (void) {
2302 if (ufoFileStackPos
>= UFO_MAX_NESTED_INCLUDES
) ufoFatal("too many includes");
2303 UFOFileStackEntry
*stk
= &ufoFileStack
[ufoFileStackPos
];
2304 stk
->fl
= ufoInFile
;
2305 stk
->fname
= ufoInFileName
;
2306 stk
->fline
= ufoInFileLine
;
2307 stk
->id
= ufoFileId
;
2308 stk
->incpath
= (ufoLastIncPath
? strdup(ufoLastIncPath
) : NULL
);
2309 stk
->sysincpath
= (ufoLastSysIncPath
? strdup(ufoLastSysIncPath
) : NULL
);
2310 ufoFileStackPos
+= 1;
2312 ufoInFileName
= NULL
; ufoInFileNameLen
= 0; ufoInFileNameHash
= 0;
2314 ufoLastUsedFileId
+= 1;
2315 ufo_assert(ufoLastUsedFileId
!= 0); // just in case ;-)
2316 //ufoLastIncPath = NULL;
2320 //==========================================================================
2322 // ufoWipeIncludeStack
2324 //==========================================================================
2325 static void ufoWipeIncludeStack (void) {
2326 if (ufoInFileName
) { free(ufoInFileName
); ufoInFileName
= NULL
; }
2327 if (ufoInFile
) { fclose(ufoInFile
); ufoInFile
= NULL
; }
2328 if (ufoLastIncPath
) { free(ufoLastIncPath
); ufoLastIncPath
= NULL
; }
2329 if (ufoLastSysIncPath
) { free(ufoLastSysIncPath
); ufoLastSysIncPath
= NULL
; }
2330 while (ufoFileStackPos
!= 0) {
2331 ufoFileStackPos
-= 1;
2332 UFOFileStackEntry
*stk
= &ufoFileStack
[ufoFileStackPos
];
2333 if (stk
->fl
) fclose(stk
->fl
);
2334 if (stk
->fname
) free(stk
->fname
);
2335 if (stk
->incpath
) free(stk
->incpath
);
2340 //==========================================================================
2344 //==========================================================================
2345 static void ufoPopInFile (void) {
2346 if (ufoFileStackPos
== 0) ufoFatal("trying to pop include from empty stack");
2347 if (ufoInFileName
) { free(ufoInFileName
); ufoInFileName
= NULL
; }
2348 if (ufoInFile
) { fclose(ufoInFile
); ufoInFile
= NULL
; }
2349 if (ufoLastIncPath
) { free(ufoLastIncPath
); ufoLastIncPath
= NULL
; }
2350 if (ufoLastSysIncPath
) { free(ufoLastSysIncPath
); ufoLastSysIncPath
= NULL
; }
2351 ufoFileStackPos
-= 1;
2352 UFOFileStackEntry
*stk
= &ufoFileStack
[ufoFileStackPos
];
2353 ufoInFile
= stk
->fl
;
2354 ufoSetInFileNameReuse(stk
->fname
);
2355 ufoInFileLine
= stk
->fline
;
2356 ufoLastIncPath
= stk
->incpath
;
2357 ufoLastSysIncPath
= stk
->sysincpath
;
2358 ufoFileId
= stk
->id
;
2360 #ifdef UFO_DEBUG_INCLUDE
2361 if (ufoInFileName
== NULL
) {
2362 fprintf(stderr
, "INC-POP: no more files.\n");
2364 fprintf(stderr
, "INC-POP: fname: %s\n", ufoInFileName
);
2370 //==========================================================================
2374 //==========================================================================
2375 void ufoDeinit (void) {
2376 #ifdef UFO_DEBUG_WRITE_MAIN_IMAGE
2378 FILE *fo
= fopen("zufo_main.img", "w");
2379 const uint32_t dpMain
= ufoImgGetU32(ufoAddrDP
);
2380 fwrite(ufoImage
, dpMain
, 1, fo
);
2385 #ifdef UFO_DEBUG_WRITE_DEBUG_IMAGE
2387 FILE *fo
= fopen("zufo_debug.img", "w");
2388 fwrite(ufoDebugImage
, ufoDebugImageUsed
, 1, fo
);
2393 #ifdef UFO_DEBUG_DEBUG
2395 const uint32_t dpMain
= ufoImgGetU32(ufoAddrDP
);
2396 fprintf(stderr
, "UFO: image used: %u; size: %u\n", dpMain
, ufoImageSize
);
2397 fprintf(stderr
, "UFO: debug image used: %u; size: %u\n", ufoDebugImageUsed
, ufoDebugImageSize
);
2398 ufoDumpDebugImage();
2403 #ifdef UFO_MTASK_ALLOWED
2404 ufoCurrState
= NULL
;
2405 ufoYieldedState
= NULL
;
2406 ufoDebuggerState
= NULL
;
2407 for (uint32_t fidx
= 0; fidx
< (uint32_t)(UFO_MAX_STATES
/32); fidx
+= 1u) {
2408 uint32_t bmp
= ufoStateUsedBitmap
[fidx
];
2410 uint32_t stid
= fidx
* 32u;
2412 if ((bmp
& 0x01) != 0) ufoFreeState(ufoStateMap
[stid
]);
2413 stid
+= 1u; bmp
>>= 1;
2419 free(ufoDebugImage
);
2420 ufoDebugImage
= NULL
;
2421 ufoDebugImageUsed
= 0;
2422 ufoDebugImageSize
= 0;
2423 ufoDebugFileNameHash
= 0;
2424 ufoDebugFileNameLen
= 0;
2425 ufoDebugLastLine
= 0;
2426 ufoDebugLastLinePCOfs
= 0;
2427 ufoDebugLastLineDP
= 0;
2431 ufoClearCondDefines();
2432 ufoWipeIncludeStack();
2434 // release all includes
2436 if (ufoInFileName
) free(ufoInFileName
);
2437 if (ufoLastIncPath
) free(ufoLastIncPath
);
2438 if (ufoLastSysIncPath
) free(ufoLastSysIncPath
);
2439 ufoInFileName
= NULL
; ufoLastIncPath
= NULL
; ufoLastSysIncPath
= NULL
;
2440 ufoInFileNameHash
= 0; ufoInFileNameLen
= 0;
2443 //free(ufoForthCFAs);
2444 //ufoForthCFAs = NULL;
2447 #ifndef UFO_HUGE_IMAGES
2453 ufoMode
= UFO_MODE_NATIVE
;
2454 ufoForthVocId
= 0; ufoCompilerVocId
= 0;
2455 #ifdef UFO_MTASK_ALLOWED
2460 for (uint32_t f
= 0; f
< ufoHandlesUsed
; f
+= 1) {
2461 UfoHandle
*hh
= ufoHandles
[f
];
2463 if (hh
->data
!= NULL
) free(hh
->data
);
2467 if (ufoHandles
!= NULL
) free(ufoHandles
);
2468 ufoHandles
= NULL
; ufoHandlesUsed
= 0; ufoHandlesAlloted
= 0;
2469 ufoHandleFreeList
= NULL
;
2471 ufoLastEmitWasCR
= 1;
2473 ufoClearCondDefines();
2477 //==========================================================================
2479 // ufoDumpWordHeader
2481 //==========================================================================
2482 __attribute__((unused
)) static void ufoDumpWordHeader (const uint32_t lfa
) {
2483 fprintf(stderr
, "=== WORD: LFA: 0x%08x ===\n", lfa
);
2485 fprintf(stderr
, " (XFA): 0x%08x\n", ufoImgGetU32(UFO_LFA_TO_XFA(lfa
)));
2486 fprintf(stderr
, " (YFA): 0x%08x\n", ufoImgGetU32(UFO_LFA_TO_YFA(lfa
)));
2487 fprintf(stderr
, " (BFA): 0x%08x\n", ufoImgGetU32(UFO_LFA_TO_BFA(lfa
)));
2488 fprintf(stderr
, " (LFA): 0x%08x\n", ufoImgGetU32(lfa
));
2489 fprintf(stderr
, " (NHH): 0x%08x\n", ufoImgGetU32(UFO_LFA_TO_NHASH(lfa
)));
2490 const uint32_t cfa
= UFO_LFA_TO_CFA(lfa
);
2491 fprintf(stderr
, " CFA: 0x%08x\n", cfa
);
2492 fprintf(stderr
, " PFA: 0x%08x\n", UFO_CFA_TO_PFA(cfa
));
2493 fprintf(stderr
, " (CFA): 0x%08x\n", ufoImgGetU32(cfa
));
2494 const uint32_t nfa
= UFO_LFA_TO_NFA(lfa
);
2495 const uint32_t nlen
= ufoImgGetU8(nfa
);
2496 fprintf(stderr
, " NFA: 0x%08x (nlen: %u)\n", nfa
, nlen
);
2497 const uint32_t flags
= ufoImgGetU32(nfa
);
2498 fprintf(stderr
, " FLAGS: 0x%08x\n", flags
);
2499 if ((flags
& 0xffff0000U
) != 0) {
2500 fprintf(stderr
, " FLAGS:");
2501 if (flags
& UFW_FLAG_IMMEDIATE
) fprintf(stderr
, " IMM");
2502 if (flags
& UFW_FLAG_SMUDGE
) fprintf(stderr
, " SMUDGE");
2503 if (flags
& UFW_FLAG_NORETURN
) fprintf(stderr
, " NORET");
2504 if (flags
& UFW_FLAG_HIDDEN
) fprintf(stderr
, " HIDDEN");
2505 if (flags
& UFW_FLAG_CBLOCK
) fprintf(stderr
, " CBLOCK");
2506 if (flags
& UFW_FLAG_VOCAB
) fprintf(stderr
, " VOCAB");
2507 if (flags
& UFW_FLAG_SCOLON
) fprintf(stderr
, " SCOLON");
2508 if (flags
& UFW_FLAG_PROTECTED
) fprintf(stderr
, " PROTECTED");
2509 fputc('\n', stderr
);
2511 if ((flags
& 0xff00U
) != 0) {
2512 fprintf(stderr
, " ARGS: ");
2513 switch (flags
& UFW_WARG_MASK
) {
2514 case UFW_WARG_NONE
: fprintf(stderr
, "NONE"); break;
2515 case UFW_WARG_BRANCH
: fprintf(stderr
, "BRANCH"); break;
2516 case UFW_WARG_LIT
: fprintf(stderr
, "LIT"); break;
2517 case UFW_WARG_C4STRZ
: fprintf(stderr
, "C4STRZ"); break;
2518 case UFW_WARG_CFA
: fprintf(stderr
, "CFA"); break;
2519 case UFW_WARG_CBLOCK
: fprintf(stderr
, "CBLOCK"); break;
2520 case UFW_WARG_VOCID
: fprintf(stderr
, "VOCID"); break;
2521 case UFW_WARG_C1STRZ
: fprintf(stderr
, "C1STRZ"); break;
2522 case UFW_WARG_DATASKIP
: fprintf(stderr
, "DATA"); break;
2523 case UFW_WARG_PFA
: fprintf(stderr
, "PFA"); break;
2524 default: fprintf(stderr
, "wtf?!"); break;
2526 fputc('\n', stderr
);
2528 fprintf(stderr
, " BACKLEN: %u (nfa at 0x%08x)\n", ufoImgGetU8(cfa
- 1u), UFO_CFA_TO_NFA(cfa
));
2529 fprintf(stderr
, " NAME(%u): ", nlen
);
2530 for (uint32_t f
= 0; f
< nlen
; f
+= 1) {
2531 const uint8_t ch
= ufoImgGetU8(nfa
+ 4u + f
);
2532 if (ch
<= 32 || ch
>= 127) {
2533 fprintf(stderr
, "\\x%02x", ch
);
2535 fprintf(stderr
, "%c", (char)ch
);
2538 fprintf(stderr
, "\n");
2539 ufo_assert(UFO_CFA_TO_LFA(cfa
) == lfa
);
2544 //==========================================================================
2550 //==========================================================================
2551 static uint32_t ufoVocCheckName (uint32_t lfa
, const void *wname
, uint32_t wnlen
, uint32_t hash
,
2555 #ifdef UFO_DEBUG_FIND_WORD
2556 fprintf(stderr
, "CHECK-NAME: %.*s; LFA: 0x%08x; hash: 0x%08x (wname: 0x%08x)\n",
2557 (unsigned) wnlen
, (const char *)wname
,
2558 lfa
, (lfa
!= 0 ? ufoImgGetU32(UFO_LFA_TO_NHASH(lfa
)) : 0), hash
);
2559 ufoDumpWordHeader(lfa
);
2561 if (lfa
!= 0 && ufoImgGetU32(UFO_LFA_TO_NHASH(lfa
)) == hash
) {
2562 const uint32_t lenflags
= ufoImgGetU32(UFO_LFA_TO_NFA(lfa
));
2563 if ((lenflags
& UFW_FLAG_SMUDGE
) == 0 &&
2564 (allowvochid
|| (lenflags
& UFW_FLAG_HIDDEN
) == 0))
2566 const uint32_t nlen
= lenflags
&0xffU
;
2567 if (nlen
== wnlen
) {
2568 uint32_t naddr
= UFO_LFA_TO_NFA(lfa
) + 4u;
2570 while (pos
< nlen
) {
2571 uint8_t c0
= ((const unsigned char *)wname
)[pos
];
2572 if (c0
>= 'a' && c0
<= 'z') c0
= c0
- 'a' + 'A';
2573 uint8_t c1
= ufoImgGetU8(naddr
+ pos
);
2574 if (c1
>= 'a' && c1
<= 'z') c1
= c1
- 'a' + 'A';
2575 if (c0
!= c1
) break;
2581 res
= UFO_ALIGN4(naddr
);
2590 //==========================================================================
2596 //==========================================================================
2597 static uint32_t ufoFindWordInVoc (const void *wname
, uint32_t wnlen
, uint32_t hash
,
2598 uint32_t vocid
, int allowvochid
)
2601 if (wname
== NULL
) ufo_assert(wnlen
== 0);
2602 if (wnlen
!= 0 && vocid
!= 0) {
2603 if (hash
== 0) hash
= joaatHashBufCI(wname
, wnlen
);
2604 #if defined(UFO_DEBUG_FIND_WORD) || defined(UFO_DEBUG_FIND_WORD_IN_VOC)
2605 fprintf(stderr
, "IN-VOC: %.*s; VOCID: 0x%08x; whash: 0x%08x; htbl[0]: 0x%08x\n",
2606 (unsigned) wnlen
, (const char *)wname
,
2607 vocid
, hash
, ufoImgGetU32(vocid
+ UFW_VOCAB_OFS_HTABLE
));
2609 const uint32_t htbl
= vocid
+ UFW_VOCAB_OFS_HTABLE
;
2610 if (ufoImgGetU32(htbl
) != UFO_NO_HTABLE_FLAG
) {
2611 // hash table present, use it
2612 uint32_t bfa
= htbl
+ (hash
% (uint32_t)UFO_HASHTABLE_SIZE
) * 4u;
2613 bfa
= ufoImgGetU32(bfa
);
2614 while (res
== 0 && bfa
!= 0) {
2615 #if defined(UFO_DEBUG_FIND_WORD) || defined(UFO_DEBUG_FIND_WORD_IN_VOC)
2616 fprintf(stderr
, "IN-VOC: bfa: 0x%08x\n", bfa
);
2618 res
= ufoVocCheckName(UFO_BFA_TO_LFA(bfa
), wname
, wnlen
, hash
, allowvochid
);
2619 bfa
= ufoImgGetU32(bfa
);
2622 // no hash table, use linear search
2623 uint32_t lfa
= vocid
+ UFW_VOCAB_OFS_LATEST
;
2624 lfa
= ufoImgGetU32(lfa
);
2625 while (res
== 0 && lfa
!= 0) {
2626 res
= ufoVocCheckName(lfa
, wname
, wnlen
, hash
, allowvochid
);
2627 lfa
= ufoImgGetU32(lfa
);
2635 //==========================================================================
2639 // return part after the colon, or `NULL`
2641 //==========================================================================
2642 static const void *ufoFindColon (const void *wname
, uint32_t wnlen
) {
2643 const void *res
= NULL
;
2645 ufo_assert(wname
!= NULL
);
2646 const char *str
= (const char *)wname
;
2647 while (wnlen
!= 0 && str
[0] != ':') {
2648 str
+= 1; wnlen
-= 1;
2651 res
= (const void *)(str
+ 1); // skip colon
2658 //==========================================================================
2660 // ufoFindWordInVocAndParents
2662 //==========================================================================
2663 static uint32_t ufoFindWordInVocAndParents (const void *wname
, uint32_t wnlen
, uint32_t hash
,
2664 uint32_t vocid
, int allowvochid
)
2667 if (hash
== 0) hash
= joaatHashBufCI(wname
, wnlen
);
2668 while (res
== 0 && vocid
!= 0) {
2669 res
= ufoFindWordInVoc(wname
, wnlen
, hash
, vocid
, allowvochid
);
2670 vocid
= ufoImgGetU32(vocid
+ UFW_VOCAB_OFS_PARENT
);
2676 //==========================================================================
2678 // ufoFindWordNameRes
2680 // find with name resolution
2684 //==========================================================================
2685 static uint32_t ufoFindWordNameRes (const void *wname
, uint32_t wnlen
) {
2687 if (wnlen
!= 0 && *(const char *)wname
!= ':') {
2688 ufo_assert(wname
!= NULL
);
2690 const void *stx
= wname
;
2691 wname
= ufoFindColon(wname
, wnlen
);
2692 if (wname
!= NULL
&& wname
!= stx
+ wnlen
) {
2693 // look in all vocabs (excluding hidden ones)
2694 uint32_t xlen
= (uint32_t)(ptrdiff_t)(wname
- stx
) - 1u;
2695 ufo_assert(xlen
> 0 && xlen
< 255);
2696 uint32_t xhash
= joaatHashBufCI(stx
, xlen
);
2697 uint32_t voclink
= ufoImgGetU32(ufoAddrVocLink
);
2698 #ifdef UFO_DEBUG_FIND_WORD_COLON
2699 fprintf(stderr
, "COLON-FIND: first voc: {%.*s}; xhash=0x%08x; voc-link: 0x%08x\n",
2700 (unsigned)xlen
, (const char *)stx
, xhash
, voclink
);
2702 while (res
== 0 && voclink
!= 0) {
2703 const uint32_t vhdraddr
= voclink
- UFW_VOCAB_OFS_VOCLINK
+ UFW_VOCAB_OFS_HEADER
;
2704 const uint32_t vhdr
= ufoImgGetU32(vhdraddr
);
2706 res
= ufoVocCheckName(UFO_NFA_TO_LFA(vhdr
), stx
, xlen
, xhash
, 0);
2708 if (res
== 0) voclink
= ufoImgGetU32(voclink
);
2711 uint32_t vocid
= voclink
- UFW_VOCAB_OFS_VOCLINK
;
2712 ufo_assert(voclink
!= 0);
2714 #ifdef UFO_DEBUG_FIND_WORD_COLON
2715 fprintf(stderr
, "searching {%.*s}(%u) in {%.*s}\n",
2716 (unsigned)wnlen
, wname
, wnlen
, (unsigned)xlen
, stx
);
2718 while (res
!= 0 && wname
!= NULL
) {
2719 // first, the whole rest
2720 res
= ufoFindWordInVocAndParents(wname
, wnlen
, 0, vocid
, 1);
2725 wname
= ufoFindColon(wname
, wnlen
);
2726 if (wname
== NULL
) xlen
= wnlen
; else xlen
= (uint32_t)(ptrdiff_t)(wname
- stx
) - 1u;
2727 ufo_assert(xlen
> 0 && xlen
< 255);
2728 res
= ufoFindWordInVocAndParents(stx
, xlen
, 0, vocid
, 1);
2731 if (wname
!= NULL
) {
2732 // it should be a vocabulary
2733 const uint32_t nfa
= UFO_CFA_TO_NFA(res
);
2734 if ((ufoImgGetU32(nfa
) & UFW_FLAG_VOCAB
) != 0) {
2735 vocid
= ufoImgGetU32(UFO_CFA_TO_PFA(res
)); // pfa points to vocabulary
2751 //==========================================================================
2755 // doesn't look in CURRENT, does name resolution ("a:b" is word "b" in "a")
2759 //==========================================================================
2760 static uint32_t ufoFindWord (const char *wname
) {
2762 if (wname
&& wname
[0] != 0) {
2763 const size_t wnlen
= strlen(wname
);
2764 ufo_assert(wnlen
< 8192);
2765 uint32_t ctx
= ufoImgGetU32(ufoAddrContext
);
2766 const uint32_t hash
= joaatHashBufCI(wname
, (uint32_t)wnlen
);
2768 //fprintf(stderr, "FIND-WORD: whash: 0x%08x; name:{%s}\n", hash, wname);
2770 // first search in context
2771 res
= ufoFindWordInVocAndParents(wname
, (uint32_t)wnlen
, hash
, ctx
, (ctx
== ufoImgGetU32(ufoAddrCurrent
)));
2773 // now try vocabulary stack
2774 uint32_t vstp
= ufoVSP
;
2775 while (res
== 0 && vstp
!= 0) {
2777 ctx
= ufoVocStack
[vstp
];
2778 res
= ufoFindWordInVocAndParents(wname
, (uint32_t)wnlen
, hash
, ctx
, (ctx
== ufoImgGetU32(ufoAddrCurrent
)));
2781 // if not found, try name resolution
2782 if (res
== 0) res
= ufoFindWordNameRes(wname
, (uint32_t)wnlen
);
2789 //==========================================================================
2791 // ufoCreateWordHeader
2793 // create word header up to CFA, link to the current dictionary
2795 //==========================================================================
2796 static void ufoCreateWordHeader (const char *wname
, uint32_t flags
) {
2797 if (wname
== NULL
) wname
= "";
2798 const size_t wnlen
= strlen(wname
);
2799 ufo_assert(wnlen
< UFO_MAX_WORD_LENGTH
);
2800 const uint32_t hash
= joaatHashBufCI(wname
, (uint32_t)wnlen
);
2801 const uint32_t curr
= ufoImgGetU32(ufoAddrCurrent
);
2802 ufo_assert(curr
!= 0);
2805 const uint32_t warn
= ufoImgGetU32(ufoAddrRedefineWarning
);
2806 if (wnlen
!= 0 && warn
!= UFO_REDEF_WARN_DONT_CARE
) {
2808 if (warn
!= UFO_REDEF_WARN_PARENTS
) {
2809 cfa
= ufoFindWordInVoc(wname
, wnlen
, hash
, curr
, 1);
2811 cfa
= ufoFindWordInVocAndParents(wname
, wnlen
, hash
, curr
, 1);
2814 const uint32_t nfa
= UFO_CFA_TO_NFA(cfa
);
2815 const uint32_t flags
= ufoImgGetU32(nfa
);
2816 if ((flags
& UFW_FLAG_PROTECTED
) != 0) {
2817 ufoFatal("trying to redefine protected word '%s'", wname
);
2818 } else if (warn
!= UFO_REDEF_WARN_NONE
) {
2819 ufoWarning("redefining word '%s'", wname
);
2824 const uint32_t bkt
= (hash
% (uint32_t)UFO_HASHTABLE_SIZE
) * 4u;
2825 const uint32_t htbl
= curr
+ UFW_VOCAB_OFS_HTABLE
;
2828 const uint32_t xfaAddr
= UFO_GET_DP();
2829 if ((xfaAddr
& UFO_ADDR_TEMP_BIT
) == 0) {
2830 // link previous yfa here
2831 const uint32_t lastxfa
= ufoImgGetU32(ufoAddrLastXFA
);
2832 // fix YFA of the previous word (it points to our YFA)
2834 ufoImgPutU32(UFO_XFA_TO_YFA(lastxfa
), UFO_XFA_TO_YFA(xfaAddr
));
2836 // our XFA points to the previous XFA
2837 ufoImgEmitU32(lastxfa
); // xfa
2839 ufoImgPutU32(ufoAddrLastXFA
, xfaAddr
);
2841 ufoImgEmitU32(0); // xfa
2843 ufoImgEmitU32(0); // yfa
2845 // bucket link (bfa)
2846 if (wnlen
== 0 || ufoImgGetU32(htbl
) == UFO_NO_HTABLE_FLAG
) {
2849 #ifdef UFO_DEBUG_DUMP_NEW_HEADERS
2850 fprintf(stderr
, "NEW HEADER: %s; curr: 0x%08x; htbl: 0x%08x; bkt: 0x%08x\n",
2851 wname
, curr
, htbl
, bkt
);
2852 fprintf(stderr
, " [bkt]: 0x%08x; nbk: 0x%08x\n", ufoImgGetU32(htbl
+ bkt
), UFO_GET_DP());
2854 // bfa points to bfa
2855 const uint32_t bfa
= UFO_GET_DP();
2856 ufoImgEmitU32(ufoImgGetU32(htbl
+ bkt
));
2857 ufoImgPutU32(htbl
+ bkt
, bfa
);
2861 const uint32_t lfa
= UFO_GET_DP();
2862 ufoImgEmitU32(ufoImgGetU32(curr
+ UFW_VOCAB_OFS_LATEST
));
2864 ufoImgPutU32(curr
+ UFW_VOCAB_OFS_LATEST
, lfa
);
2866 ufoImgEmitU32(hash
);
2868 const uint32_t nfa
= UFO_GET_DP();
2869 ufoImgEmitU32(((uint32_t)wnlen
&0xffU
) | (flags
& 0xffffff00U
));
2870 const uint32_t nstart
= UFO_GET_DP();
2872 for (size_t f
= 0; f
< wnlen
; f
+= 1) {
2873 ufoImgEmitU8(((const unsigned char *)wname
)[f
]);
2875 while ((UFO_GET_DP() & 3) != 3) ufoImgEmitU8(0);
2876 const uint32_t nend
= UFO_GET_DP(); // length byte itself is not included
2877 // name length, again
2878 ufo_assert(nend
- nstart
<= 255);
2879 ufoImgEmitU8((uint8_t)(nend
- nstart
));
2880 ufo_assert((UFO_GET_DP() & 3) == 0);
2881 ufo_assert(UFO_CFA_TO_NFA(UFO_GET_DP()) == nfa
);
2882 if ((nend
& UFO_ADDR_SPECIAL_BITS_MASK
) == 0) ufoRecordDebug(nend
);
2883 #ifdef UFO_DEBUG_DUMP_NEW_HEADERS
2884 fprintf(stderr
, "*** NEW HEADER ***\n");
2885 fprintf(stderr
, "CFA: 0x%08x\n", UFO_GET_DP());
2886 fprintf(stderr
, "NSTART: 0x%08x\n", nstart
);
2887 fprintf(stderr
, "NEND: 0x%08x\n", nend
);
2888 fprintf(stderr
, "NLEN: %u (%u)\n", nend
- nstart
, ufoImgGetU8(UFO_GET_DP() - 1u));
2889 ufoDumpWordHeader(lfa
);
2892 fprintf(stderr
, "NEW WORD CFA 0x%08x: %s\n", UFO_GET_DP(), wname
);
2897 //==========================================================================
2901 //==========================================================================
2902 static void ufoDecompilePart (uint32_t addr
, uint32_t eaddr
, int indent
) {
2905 while (addr
< eaddr
) {
2906 uint32_t cfa
= ufoImgGetU32(addr
);
2907 for (int n
= 0; n
< indent
; n
+= 1) fputc(' ', fo
);
2908 fprintf(fo
, "%6u: 0x%08x: ", addr
, cfa
);
2909 uint32_t nfa
= UFO_CFA_TO_NFA(cfa
);
2910 uint32_t flags
= ufoImgGetU32(nfa
);
2911 //fprintf(fo, "[0x%08x] ", flags & UFW_WARG_MASK);
2912 uint32_t nlen
= flags
& 0xffU
;
2913 for (uint32_t f
= 0; f
< nlen
; f
+= 1) {
2914 const uint8_t ch
= ufoImgGetU8(nfa
+ 4u + f
);
2915 if (ch
<= 32 || ch
>= 127) {
2916 fprintf(fo
, "\\x%02x", ch
);
2918 fprintf(fo
, "%c", (char)ch
);
2922 switch (flags
& UFW_WARG_MASK
) {
2925 case UFW_WARG_BRANCH
:
2926 #ifdef UFO_RELATIVE_BRANCH
2927 fprintf(fo
, " @%u", addr
+ ufoImgGetU32(addr
)); addr
+= 4u;
2929 fprintf(fo
, " @%u", ufoImgGetU32(addr
)); addr
+= 4u;
2933 fprintf(fo
, " %u : %d : 0x%08x", ufoImgGetU32(addr
),
2934 (int32_t)ufoImgGetU32(addr
), ufoImgGetU32(addr
)); addr
+= 4u;
2936 case UFW_WARG_C4STRZ
:
2937 count
= ufoImgGetU32(addr
); addr
+= 4;
2939 fprintf(fo
, " str:");
2940 for (int f
= 0; f
< count
; f
+= 1) {
2941 const uint8_t ch
= ufoImgGetU8(addr
); addr
+= 1u;
2942 if (ch
<= 32 || ch
>= 127) {
2943 fprintf(fo
, "\\x%02x", ch
);
2945 fprintf(fo
, "%c", (char)ch
);
2948 addr
+= 1u; // skip zero byte
2949 addr
= UFO_ALIGN4(addr
);
2952 cfa
= ufoImgGetU32(addr
); addr
+= 4u;
2953 fprintf(fo
, " CFA:%u: ", cfa
);
2954 nfa
= UFO_CFA_TO_NFA(cfa
);
2955 nlen
= ufoImgGetU8(nfa
);
2956 for (uint32_t f
= 0; f
< nlen
; f
+= 1) {
2957 const uint8_t ch
= ufoImgGetU8(nfa
+ 4u + f
);
2958 if (ch
<= 32 || ch
>= 127) {
2959 fprintf(fo
, "\\x%02x", ch
);
2961 fprintf(fo
, "%c", (char)ch
);
2966 cfa
= ufoImgGetU32(addr
); addr
+= 4u;
2967 fprintf(fo
, " PFA:%u: ", cfa
);
2968 cfa
= UFO_PFA_TO_CFA(cfa
);
2969 nfa
= UFO_CFA_TO_NFA(cfa
);
2970 nlen
= ufoImgGetU8(nfa
);
2971 for (uint32_t f
= 0; f
< nlen
; f
+= 1) {
2972 const uint8_t ch
= ufoImgGetU8(nfa
+ 4u + f
);
2973 if (ch
<= 32 || ch
>= 127) {
2974 fprintf(fo
, "\\x%02x", ch
);
2976 fprintf(fo
, "%c", (char)ch
);
2980 case UFW_WARG_CBLOCK
:
2981 fprintf(fo
, " CBLOCK:%u", ufoImgGetU32(addr
)); addr
+= 4u;
2983 case UFW_WARG_VOCID
:
2984 fprintf(fo
, " VOCID:%u", ufoImgGetU32(addr
)); addr
+= 4u;
2986 case UFW_WARG_C1STRZ
:
2987 count
= ufoImgGetU8(addr
); addr
+= 1;
2989 case UFW_WARG_DATASKIP
:
2990 fprintf(fo
, " DATA:%u", ufoImgGetU32(addr
));
2991 addr
+= UFO_ALIGN4(4u + ufoImgGetU32(addr
));
2994 fprintf(fo
, " -- WTF?!\n");
3002 //==========================================================================
3006 //==========================================================================
3007 static void ufoDecompileWord (const uint32_t cfa
) {
3009 const uint32_t lfa
= UFO_CFA_TO_LFA(cfa
);
3010 fprintf(stdout
, "#### DECOMPILING CFA %u ###\n", cfa
);
3011 ufoDumpWordHeader(lfa
);
3012 const uint32_t yfa
= ufoGetWordEndAddr(cfa
);
3013 if (ufoImgGetU32(cfa
) == ufoDoForthCFA
) {
3014 fprintf(stdout
, "--- DECOMPILED CODE ---\n");
3015 ufoDecompilePart(UFO_CFA_TO_PFA(cfa
), yfa
, 0);
3016 fprintf(stdout
, "=======================\n");
3022 //==========================================================================
3024 // ufoBTShowWordName
3026 //==========================================================================
3027 static void ufoBTShowWordName (uint32_t nfa
) {
3029 uint32_t len
= ufoImgGetU8(nfa
); nfa
+= 4u;
3030 //fprintf(stderr, "(0x%08x)", ufoImgGetU32(nfa - 4u));
3032 uint8_t ch
= ufoImgGetU8(nfa
); nfa
+= 1u; len
-= 1u;
3033 if (ch
<= 32 || ch
>= 127) {
3034 fprintf(stderr
, "\\x%02x", ch
);
3036 fprintf(stderr
, "%c", (char)ch
);
3043 //==========================================================================
3047 //==========================================================================
3048 static void ufoBacktrace (uint32_t ip
, int showDataStack
) {
3049 // dump data stack (top 16)
3051 if (!ufoLastEmitWasCR
) { printf("\n"); ufoLastEmitWasCR
= 1; }
3053 if (showDataStack
) {
3054 fprintf(stderr
, "***UFO STACK DEPTH: %u\n", ufoSP
);
3055 uint32_t xsp
= ufoSP
;
3056 if (xsp
> 16) xsp
= 16;
3057 for (uint32_t sp
= 0; sp
< xsp
; ++sp
) {
3058 fprintf(stderr
, " %2u: 0x%08x %d%s\n",
3059 sp
, ufoDStack
[xsp
- sp
- 1], (int32_t)ufoDStack
[xsp
- sp
- 1],
3060 (sp
== 0 ? " -- TOS" : ""));
3062 if (ufoSP
> 16) fprintf(stderr
, " ...more...\n");
3065 // dump return stack (top 32)
3070 fprintf(stderr
, "***UFO RETURN STACK DEPTH: %u\n", ufoRP
);
3072 nfa
= ufoFindWordForIP(ip
);
3074 fprintf(stderr
, " **: %8u -- ", ip
);
3075 ufoBTShowWordName(nfa
);
3076 fname
= ufoFindFileForIP(ip
, &fline
, NULL
, NULL
);
3077 if (fname
!= NULL
) { fprintf(stderr
, " (at %s:%u)", fname
, fline
); }
3078 fputc('\n', stderr
);
3081 uint32_t rp
= ufoRP
;
3082 uint32_t rscount
= 0;
3083 if (rp
> UFO_RSTACK_SIZE
) rp
= UFO_RSTACK_SIZE
;
3084 while (rscount
!= 32 && rp
!= 0) {
3086 const uint32_t val
= ufoRStack
[rp
];
3087 nfa
= ufoFindWordForIP(val
- 4u);
3089 fprintf(stderr
, " %2u: %8u -- ", ufoRP
- rp
- 1u, val
);
3090 ufoBTShowWordName(nfa
);
3091 fname
= ufoFindFileForIP(val
- 4u, &fline
, NULL
, NULL
);
3092 if (fname
!= NULL
) { fprintf(stderr
, " (at %s:%u)", fname
, fline
); }
3093 fputc('\n', stderr
);
3095 fprintf(stderr
, " %2u: 0x%08x %d\n", ufoRP
- rp
- 1u, val
, (int32_t)val
);
3099 if (ufoRP
> 32) fprintf(stderr
, " ...more...\n");
3105 //==========================================================================
3109 //==========================================================================
3111 static void ufoDumpVocab (uint32_t vocid) {
3113 fprintf(stderr, "*** VOCID: 0x%08x ***\n", vocid);
3114 uint32_t vochdr = vocid + UFW_VOCAB_OFS_HEADER;
3115 vochdr = ufoImgGetU32(vochdr);
3117 fprintf(stderr, "--- HEADER ---\n");
3118 ufoDumpWordHeader(UFO_NFA_TO_LFA(vochdr));
3119 fprintf(stderr, "========\n");
3120 uint32_t htbl = vocid + UFW_VOCAB_OFS_HTABLE;
3121 if (ufoImgGetU32(htbl) != UFO_NO_HTABLE_FLAG) {
3122 fprintf(stderr, "--- HASH TABLE ---\n");
3123 for (int f = 0; f < UFO_HASHTABLE_SIZE; f += 1) {
3124 uint32_t bfa = ufoImgGetU32(htbl);
3126 fprintf(stderr, "**** %2d: 0x%08x\n", f, bfa);
3128 ufoDumpWordHeader(UFO_BFA_TO_LFA(bfa));
3129 bfa = ufoImgGetU32(bfa);
3141 // if set, this will be used when we are out of include files. intended for UrAsm.
3142 // return 0 if there is no more lines, otherwise the string should be copied
3143 // to buffer, `*fname` and `*fline` should be properly set.
3144 int (*ufoFileReadLine
) (void *buf
, size_t bufsize
, const char **fname
, int *fline
) = NULL
;
3147 //==========================================================================
3149 // ufoLoadNextUserLine
3151 //==========================================================================
3152 static int ufoLoadNextUserLine (void) {
3153 uint32_t tibPos
= 0;
3154 const char *fname
= NULL
;
3157 if (ufoFileReadLine
!= NULL
&& ufoFileReadLine(ufoCurrFileLine
, 510, &fname
, &fline
) != 0) {
3158 ufoCurrFileLine
[510] = 0;
3159 uint32_t slen
= (uint32_t)strlen(ufoCurrFileLine
);
3160 while (slen
!= 0 && (ufoCurrFileLine
[slen
- 1u] == 10 || ufoCurrFileLine
[slen
- 1u] == 13)) {
3163 if (tibPos
+ slen
+ 1u > UFO_ADDR_HANDLE_OFS_MASK
) {
3164 ufoFatal("input text line too long (at least %u bytes)", tibPos
+ slen
);
3166 ufoTibEnsureSize(tibPos
+ slen
+ 1u);
3167 for (uint32_t f
= 0; f
< slen
; f
+= 1) {
3168 ufoTibPokeChOfs(((const unsigned char *)ufoCurrFileLine
)[f
], tibPos
+ f
);
3170 ufoTibPokeChOfs(0, tibPos
+ slen
);
3172 if (fname
== NULL
) fname
= "<user>";
3173 ufoSetInFileName(fname
);
3174 ufoInFileLine
= fline
;
3182 //==========================================================================
3184 // ufoLoadNextLine_NativeMode
3186 // load next file line into TIB
3187 // always strips final '\n'
3189 // return 0 on EOF, 1 on success
3191 //==========================================================================
3192 static int ufoLoadNextLine (int crossInclude
) {
3194 uint32_t tibPos
= 0;
3197 if (ufoMode
== UFO_MODE_MACRO
) {
3198 //fprintf(stderr, "***MAC!\n");
3202 while (ufoInFile
!= NULL
&& !done
) {
3203 ufoCurrIncludeLineFileOfs
= ftell(ufoInFile
);
3204 if (fgets(ufoCurrFileLine
, 510, ufoInFile
) != NULL
) {
3205 // check for a newline
3206 // if there is no newline char at the end, the string was truncated
3207 ufoCurrFileLine
[510] = 0;
3208 const uint32_t slen
= (uint32_t)strlen(ufoCurrFileLine
);
3209 if (tibPos
+ slen
+ 1u > UFO_ADDR_HANDLE_OFS_MASK
) {
3210 ufoFatal("input text line too long (at least %u bytes)", tibPos
+ slen
);
3212 ufoTibEnsureSize(tibPos
+ slen
+ 1u);
3213 for (uint32_t f
= 0; f
< slen
; f
+= 1) {
3214 ufoTibPokeChOfs(((const unsigned char *)ufoCurrFileLine
)[f
], tibPos
+ f
);
3216 ufoTibPokeChOfs(0, tibPos
+ slen
);
3218 if (slen
!= 0 && (ufoCurrFileLine
[slen
- 1u] == 13 || ufoCurrFileLine
[slen
- 1u] == 10)) {
3222 // continuation, nothing to do
3225 // if we read nothing, this is EOF
3226 if (tibPos
== 0 && crossInclude
) {
3227 // we read nothing, and allowed to cross include boundaries
3236 // eof, try user-supplied input
3237 if (ufoFileStackPos
== 0) {
3238 return ufoLoadNextUserLine();
3243 // if we read at least something, this is not EOF
3249 // ////////////////////////////////////////////////////////////////////////// //
3254 UFWORD(DUMP_STACK
) {
3255 if (!ufoLastEmitWasCR
) { printf("\n"); ufoLastEmitWasCR
= 1; }
3256 printf("***UFO STACK DEPTH: %u\n", ufoSP
);
3257 uint32_t xsp
= ufoSP
;
3258 if (xsp
> 16) xsp
= 16;
3259 for (uint32_t sp
= 0; sp
< xsp
; ++sp
) {
3260 printf(" %2u: 0x%08x %d%s\n",
3261 sp
, ufoDStack
[xsp
- sp
- 1], (int32_t)ufoDStack
[xsp
- sp
- 1],
3262 (sp
== 0 ? " -- TOS" : ""));
3264 if (ufoSP
> 16) printf(" ...more...\n");
3265 ufoLastEmitWasCR
= 1;
3270 UFWORD(UFO_BACKTRACE
) {
3272 if (!ufoLastEmitWasCR
) { printf("\n"); ufoLastEmitWasCR
= 1; }
3273 if (ufoInFile
!= NULL
) {
3274 fprintf(stderr
, "*** at file %s, line %d ***\n", ufoInFileName
, ufoInFileLine
);
3276 fprintf(stderr
, "*** somewhere in time ***\n");
3278 ufoBacktrace(ufoIP
, 1);
3281 #ifdef UFO_MTASK_ALLOWED
3284 UFWORD(DUMP_STACK_TASK
) {
3285 UfoState
*st
= ufoFindState(ufoPop());
3286 if (st
== NULL
) ufoFatal("invalid state id");
3287 // temporarily switch the task
3288 UfoState
*oldst
= ufoCurrState
; ufoCurrState
= st
;
3290 if (!ufoLastEmitWasCR
) { printf("\n"); ufoLastEmitWasCR
= 1; }
3291 printf("***UFO STACK DEPTH: %u\n", ufoSP
);
3292 uint32_t xsp
= ufoSP
;
3293 if (xsp
> 16) xsp
= 16;
3294 for (uint32_t sp
= 0; sp
< xsp
; ++sp
) {
3295 printf(" %2u: 0x%08x %d%s\n",
3296 sp
, ufoDStack
[xsp
- sp
- 1], (int32_t)ufoDStack
[xsp
- sp
- 1],
3297 (sp
== 0 ? " -- TOS" : ""));
3299 if (ufoSP
> 16) printf(" ...more...\n");
3300 ufoLastEmitWasCR
= 1;
3302 ufoCurrState
= oldst
;
3307 UFWORD(DUMP_RSTACK_TASK
) {
3308 UfoState
*st
= ufoFindState(ufoPop());
3309 if (st
== NULL
) ufoFatal("invalid state id");
3310 // temporarily switch the task
3311 UfoState
*oldst
= ufoCurrState
; ufoCurrState
= st
;
3314 if (!ufoLastEmitWasCR
) { printf("\n"); ufoLastEmitWasCR
= 1; }
3315 if (ufoInFile
!= NULL
) {
3316 fprintf(stderr
, "*** at file %s, line %d ***\n", ufoInFileName
, ufoInFileLine
);
3318 fprintf(stderr
, "*** somewhere in time ***\n");
3320 ufoBacktrace(ufoIP
, 0);
3322 ufoCurrState
= oldst
;
3327 UFWORD(UFO_BACKTRACE_TASK
) {
3328 UfoState
*st
= ufoFindState(ufoPop());
3329 if (st
== NULL
) ufoFatal("invalid state id");
3330 // temporarily switch the task
3331 UfoState
*oldst
= ufoCurrState
; ufoCurrState
= st
;
3334 if (!ufoLastEmitWasCR
) { printf("\n"); ufoLastEmitWasCR
= 1; }
3335 if (ufoInFile
!= NULL
) {
3336 fprintf(stderr
, "*** at file %s, line %d ***\n", ufoInFileName
, ufoInFileLine
);
3338 fprintf(stderr
, "*** somewhere in time ***\n");
3340 ufoBacktrace(ufoIP
, 1);
3342 ufoCurrState
= oldst
;
3347 // ////////////////////////////////////////////////////////////////////////// //
3348 // some init words, and PAD
3357 UFWORD(PAR_NOTIMPL
) {
3358 ufoFatal("not implemented");
3363 UFWORD(SP0_STORE
) { ufoSP
= 0; }
3373 // PAD is at the beginning of temp area
3375 ufoPush(UFO_PAD_ADDR
);
3381 ufoPush(UFO_GET_DP());
3386 UFWORD(ALIGN_HERE
) {
3391 // ////////////////////////////////////////////////////////////////////////// //
3392 // peeks and pokes with address register
3403 UFWORD(REGA_STORE
) {
3411 const uint32_t newa
= ufoPop();
3424 UFWORD(REGA_INC_WORD
) {
3430 UFWORD(REGA_INC_CELL
) {
3442 UFWORD(REGA_DEC_WORD
) {
3448 UFWORD(REGA_DEC_CELL
) {
3461 ufoRegA
= ufoRPop();
3465 // ////////////////////////////////////////////////////////////////////////// //
3466 // useful to work with handles and normal addreses uniformly
3471 UFWORD(CPEEK_REGA
) {
3472 ufoPush(ufoImgGetU8(ufoRegA
));
3477 UFWORD(WPEEK_REGA
) {
3478 ufoPush(ufoImgGetU16(ufoRegA
));
3484 ufoPush(ufoImgGetU32(ufoRegA
));
3489 UFWORD(CPOKE_REGA
) {
3490 ufoImgPutU8(ufoRegA
, ufoPop());
3495 UFWORD(WPOKE_REGA
) {
3496 ufoImgPutU16(ufoRegA
, ufoPop());
3502 ufoImgPutU32(ufoRegA
, ufoPop());
3507 UFWORD(CPEEK_REGA_IDX
) {
3508 if ((ufoRegA
& UFO_ADDR_HANDLE_BIT
) == 0) {
3509 const uint32_t idx
= ufoPop();
3510 const uint32_t newaddr
= ufoRegA
+ idx
;
3511 if ((ufoRegA
& UFO_ADDR_SPECIAL_BITS_MASK
) == (newaddr
& UFO_ADDR_SPECIAL_BITS_MASK
)) {
3512 ufoPush(ufoImgGetU8(newaddr
));
3514 ufoFatal("address offset out of range; addr=0x%08x; offset=%u; res=0x%08x",
3515 ufoRegA
, idx
, newaddr
);
3519 UFCALL(PAR_HANDLE_LOAD_BYTE
);
3525 UFWORD(WPEEK_REGA_IDX
) {
3526 if ((ufoRegA
& UFO_ADDR_HANDLE_BIT
) == 0) {
3527 const uint32_t idx
= ufoPop();
3528 const uint32_t newaddr
= ufoRegA
+ idx
;
3529 if ((ufoRegA
& UFO_ADDR_SPECIAL_BITS_MASK
) == (newaddr
& UFO_ADDR_SPECIAL_BITS_MASK
) &&
3530 (ufoRegA
& UFO_ADDR_SPECIAL_BITS_MASK
) == ((newaddr
+ 1u) & UFO_ADDR_SPECIAL_BITS_MASK
))
3532 ufoPush(ufoImgGetU16(newaddr
));
3534 ufoFatal("address offset out of range; addr=0x%08x; offset=%u; res=0x%08x",
3535 ufoRegA
, idx
, newaddr
);
3539 UFCALL(PAR_HANDLE_LOAD_WORD
);
3545 UFWORD(PEEK_REGA_IDX
) {
3546 if ((ufoRegA
& UFO_ADDR_HANDLE_BIT
) == 0) {
3547 const uint32_t idx
= ufoPop();
3548 const uint32_t newaddr
= ufoRegA
+ idx
;
3549 if ((ufoRegA
& UFO_ADDR_SPECIAL_BITS_MASK
) == (newaddr
& UFO_ADDR_SPECIAL_BITS_MASK
) &&
3550 (ufoRegA
& UFO_ADDR_SPECIAL_BITS_MASK
) == ((newaddr
+ 3u) & UFO_ADDR_SPECIAL_BITS_MASK
))
3552 ufoPush(ufoImgGetU32(newaddr
));
3554 ufoFatal("address offset out of range; addr=0x%08x; offset=%u; res=0x%08x",
3555 ufoRegA
, idx
, newaddr
);
3559 UFCALL(PAR_HANDLE_LOAD_CELL
);
3565 UFWORD(CPOKE_REGA_IDX
) {
3566 if ((ufoRegA
& UFO_ADDR_HANDLE_BIT
) == 0) {
3567 const uint32_t idx
= ufoPop();
3568 const uint32_t newaddr
= ufoRegA
+ idx
;
3569 if ((ufoRegA
& UFO_ADDR_SPECIAL_BITS_MASK
) == (newaddr
& UFO_ADDR_SPECIAL_BITS_MASK
)) {
3570 const uint32_t value
= ufoPop();
3571 ufoImgPutU8(newaddr
, value
);
3573 ufoFatal("address offset out of range; addr=0x%08x; offset=%u; res=0x%08x",
3574 ufoRegA
, idx
, newaddr
);
3578 UFCALL(PAR_HANDLE_STORE_BYTE
);
3584 UFWORD(WPOKE_REGA_IDX
) {
3585 if ((ufoRegA
& UFO_ADDR_HANDLE_BIT
) == 0) {
3586 const uint32_t idx
= ufoPop();
3587 const uint32_t newaddr
= ufoRegA
+ idx
;
3588 if ((ufoRegA
& UFO_ADDR_SPECIAL_BITS_MASK
) == (newaddr
& UFO_ADDR_SPECIAL_BITS_MASK
) &&
3589 (ufoRegA
& UFO_ADDR_SPECIAL_BITS_MASK
) == ((newaddr
+ 1u) & UFO_ADDR_SPECIAL_BITS_MASK
))
3591 const uint32_t value
= ufoPop();
3592 ufoImgPutU16(newaddr
, value
);
3594 ufoFatal("address offset out of range; addr=0x%08x; offset=%u; res=0x%08x",
3595 ufoRegA
, idx
, newaddr
);
3599 UFCALL(PAR_HANDLE_STORE_WORD
);
3605 UFWORD(POKE_REGA_IDX
) {
3606 if ((ufoRegA
& UFO_ADDR_HANDLE_BIT
) == 0) {
3607 const uint32_t idx
= ufoPop();
3608 const uint32_t newaddr
= ufoRegA
+ idx
;
3609 if ((ufoRegA
& UFO_ADDR_SPECIAL_BITS_MASK
) == (newaddr
& UFO_ADDR_SPECIAL_BITS_MASK
) &&
3610 (ufoRegA
& UFO_ADDR_SPECIAL_BITS_MASK
) == ((newaddr
+ 3u) & UFO_ADDR_SPECIAL_BITS_MASK
))
3612 const uint32_t value
= ufoPop();
3613 ufoImgPutU32(newaddr
, value
);
3615 ufoFatal("address offset out of range; addr=0x%08x; offset=%u; res=0x%08x",
3616 ufoRegA
, idx
, newaddr
);
3620 UFCALL(PAR_HANDLE_STORE_CELL
);
3626 UFWORD(CPOKE_REGA_INC1
) {
3627 ufoImgPutU8(ufoRegA
, ufoPop());
3633 UFWORD(WPOKE_REGA_INC2
) {
3634 ufoImgPutU16(ufoRegA
, ufoPop());
3640 UFWORD(POKE_REGA_INC4
) {
3641 ufoImgPutU32(ufoRegA
, ufoPop());
3647 UFWORD(CPEEK_REGA_INC1
) {
3648 ufoPush(ufoImgGetU8(ufoRegA
));
3654 UFWORD(WPEEK_REGA_INC2
) {
3655 ufoPush(ufoImgGetU16(ufoRegA
));
3661 UFWORD(PEEK_REGA_INC4
) {
3662 ufoPush(ufoImgGetU32(ufoRegA
));
3667 // ////////////////////////////////////////////////////////////////////////// //
3674 const uint32_t cfa
= ufoPop();
3679 // ( destaddr addr -- )
3680 // write "branch to destaddr" address to addr
3681 UFWORD(PAR_BRANCH_ADDR_POKE
) {
3682 const uint32_t addr
= ufoPop();
3683 const uint32_t dest
= ufoPop();
3684 #ifdef UFO_RELATIVE_BRANCH
3685 ufoImgPutU32(addr
, dest
- addr
);
3687 ufoImgPutU32(addr
, dest
);
3693 // read branch address
3694 UFWORD(PAR_BRANCH_ADDR_PEEK
) {
3696 #ifdef UFO_RELATIVE_BRANCH
3697 UFO_TOS
+= ufoImgGetU32(UFO_TOS
);
3699 UFO_TOS
= ufoImgGetU32(UFO_TOS
);
3704 // ( addr -- value8 )
3706 const uint32_t addr
= ufoPop();
3707 ufoPush(ufoImgGetU8(addr
));
3711 // ( addr -- value16 )
3713 const uint32_t addr
= ufoPop();
3714 ufoPush(ufoImgGetU16(addr
));
3718 // ( addr -- value32 )
3720 const uint32_t addr
= ufoPop();
3721 ufoPush(ufoImgGetU32(addr
));
3727 const uint32_t addr
= ufoPop();
3728 const uint32_t val
= ufoPop();
3729 ufoImgPutU8(addr
, val
);
3733 // ( val16 addr -- )
3735 const uint32_t addr
= ufoPop();
3736 const uint32_t val
= ufoPop();
3737 ufoImgPutU16(addr
, val
);
3741 // ( val32 addr -- )
3743 const uint32_t addr
= ufoPop();
3744 const uint32_t val
= ufoPop();
3745 ufoImgPutU32(addr
, val
);
3750 // code arg is address
3751 UFWORD(DIRECT_PEEK
) {
3752 const uint32_t addr
= ufoImgGetU32(ufoIP
); ufoIP
+= 4u;
3753 ufoPush(ufoImgGetU32(addr
));
3758 // code arg is address
3759 UFWORD(DIRECT_POKE0
) {
3760 const uint32_t addr
= ufoImgGetU32(ufoIP
); ufoIP
+= 4u;
3761 ufoImgPutU32(addr
, 0);
3766 // code arg is address
3767 UFWORD(DIRECT_POKE1
) {
3768 const uint32_t addr
= ufoImgGetU32(ufoIP
); ufoIP
+= 4u;
3769 ufoImgPutU32(addr
, 1);
3774 // code arg is address
3775 UFWORD(DIRECT_POKEM1
) {
3776 const uint32_t addr
= ufoImgGetU32(ufoIP
); ufoIP
+= 4u;
3777 ufoImgPutU32(addr
, ~(uint32_t)0);
3782 // code arg is address
3783 UFWORD(DIRECT_POKE
) {
3784 const uint32_t addr
= ufoImgGetU32(ufoIP
); ufoIP
+= 4u;
3785 const uint32_t val
= ufoPop();
3786 ufoImgPutU32(addr
, val
);
3791 // code arg is address
3792 UFWORD(DIRECT_ADD_POKE
) {
3793 const uint32_t addr
= ufoImgGetU32(ufoIP
); ufoIP
+= 4u;
3794 uint32_t val
= ufoPop();
3795 val
+= ufoImgGetU32(addr
);
3796 ufoImgPutU32(addr
, val
);
3801 // code arg is address
3802 UFWORD(DIRECT_SUB_POKE
) {
3803 const uint32_t addr
= ufoImgGetU32(ufoIP
); ufoIP
+= 4u;
3804 uint32_t val
= ufoPop();
3805 val
-= ufoImgGetU32(addr
);
3806 ufoImgPutU32(addr
, val
);
3810 // ( addr -- value32 )
3811 // code arg is offset
3812 UFWORD(DIRECT_OFS_PEEK
) {
3813 uint32_t addr
= ufoPop();
3814 addr
+= ufoImgGetU32(ufoIP
); ufoIP
+= 4u;
3815 ufoPush(ufoImgGetU32(addr
));
3819 // ( value32 addr -- )
3820 // code arg is offset
3821 UFWORD(DIRECT_OFS_POKE
) {
3822 uint32_t addr
= ufoPop();
3823 uint32_t val
= ufoPop();
3824 addr
+= ufoImgGetU32(ufoIP
); ufoIP
+= 4u;
3825 ufoImgPutU32(addr
, val
);
3830 // code arg is address
3831 UFWORD(DIRECT_POKE_INC1
) {
3832 const uint32_t addr
= ufoImgGetU32(ufoIP
); ufoIP
+= 4u;
3833 const uint32_t val
= ufoImgGetU32(addr
);
3834 ufoImgPutU32(addr
, val
+ 1u);
3839 // code arg is address
3840 UFWORD(DIRECT_POKE_INC2
) {
3841 const uint32_t addr
= ufoImgGetU32(ufoIP
); ufoIP
+= 4u;
3842 const uint32_t val
= ufoImgGetU32(addr
);
3843 ufoImgPutU32(addr
, val
+ 2u);
3848 // code arg is address
3849 UFWORD(DIRECT_POKE_INC4
) {
3850 const uint32_t addr
= ufoImgGetU32(ufoIP
); ufoIP
+= 4u;
3851 const uint32_t val
= ufoImgGetU32(addr
);
3852 ufoImgPutU32(addr
, val
+ 4u);
3857 // code arg is address
3858 UFWORD(DIRECT_POKE_INC8
) {
3859 const uint32_t addr
= ufoImgGetU32(ufoIP
); ufoIP
+= 4u;
3860 const uint32_t val
= ufoImgGetU32(addr
);
3861 ufoImgPutU32(addr
, val
+ 8u);
3866 // code arg is address
3867 UFWORD(DIRECT_POKE_DEC1
) {
3868 const uint32_t addr
= ufoImgGetU32(ufoIP
); ufoIP
+= 4u;
3869 const uint32_t val
= ufoImgGetU32(addr
);
3870 ufoImgPutU32(addr
, val
- 1u);
3875 // code arg is address
3876 UFWORD(DIRECT_POKE_DEC2
) {
3877 const uint32_t addr
= ufoImgGetU32(ufoIP
); ufoIP
+= 4u;
3878 const uint32_t val
= ufoImgGetU32(addr
);
3879 ufoImgPutU32(addr
, val
- 2u);
3884 // code arg is address
3885 UFWORD(DIRECT_POKE_DEC4
) {
3886 const uint32_t addr
= ufoImgGetU32(ufoIP
); ufoIP
+= 4u;
3887 const uint32_t val
= ufoImgGetU32(addr
);
3888 ufoImgPutU32(addr
, val
- 4u);
3893 // code arg is address
3894 UFWORD(DIRECT_POKE_DEC8
) {
3895 const uint32_t addr
= ufoImgGetU32(ufoIP
); ufoIP
+= 4u;
3896 const uint32_t val
= ufoImgGetU32(addr
);
3897 ufoImgPutU32(addr
, val
- 8u);
3901 // ( addr value -- )
3902 UFWORD(SWAP_CPOKE
) {
3903 const uint32_t val
= ufoPop();
3904 const uint32_t addr
= ufoPop();
3905 ufoImgPutU8(addr
, val
);
3909 // ( addr value -- )
3910 UFWORD(SWAP_WPOKE
) {
3911 const uint32_t val
= ufoPop();
3912 const uint32_t addr
= ufoPop();
3913 ufoImgPutU16(addr
, val
);
3917 // ( addr value -- )
3919 const uint32_t val
= ufoPop();
3920 const uint32_t addr
= ufoPop();
3921 ufoImgPutU32(addr
, val
);
3925 // ( value addr -- )
3927 const uint32_t addr
= ufoPop();
3928 uint32_t val
= ufoPop();
3929 val
|= ufoImgGetU8(addr
);
3930 ufoImgPutU8(addr
, val
);
3934 // ( value addr -- )
3936 const uint32_t addr
= ufoPop();
3937 uint32_t val
= ufoPop();
3938 val
|= ufoImgGetU16(addr
);
3939 ufoImgPutU16(addr
, val
);
3943 // ( value addr -- )
3945 const uint32_t addr
= ufoPop();
3946 uint32_t val
= ufoPop();
3947 val
|= ufoImgGetU32(addr
);
3948 ufoImgPutU32(addr
, val
);
3952 // ( value addr -- )
3954 const uint32_t addr
= ufoPop();
3955 uint32_t val
= ufoPop();
3956 val
^= ufoImgGetU8(addr
);
3957 ufoImgPutU8(addr
, val
);
3961 // ( value addr -- )
3963 const uint32_t addr
= ufoPop();
3964 uint32_t val
= ufoPop();
3965 val
^= ufoImgGetU16(addr
);
3966 ufoImgPutU16(addr
, val
);
3970 // ( value addr -- )
3972 const uint32_t addr
= ufoPop();
3973 uint32_t val
= ufoPop();
3974 val
^= ufoImgGetU32(addr
);
3975 ufoImgPutU32(addr
, val
);
3979 // ( value addr -- )
3980 UFWORD(NAND_CPOKE
) {
3981 const uint32_t addr
= ufoPop();
3982 uint32_t val
= ufoPop();
3983 val
= ufoImgGetU8(addr
)&~val
;
3984 ufoImgPutU8(addr
, val
);
3988 // ( value addr -- )
3989 UFWORD(NAND_WPOKE
) {
3990 const uint32_t addr
= ufoPop();
3991 uint32_t val
= ufoPop();
3992 val
= ufoImgGetU16(addr
)&~val
;
3993 ufoImgPutU16(addr
, val
);
3997 // ( value addr -- )
3999 const uint32_t addr
= ufoPop();
4000 uint32_t val
= ufoPop();
4001 val
= ufoImgGetU32(addr
)&~val
;
4002 ufoImgPutU32(addr
, val
);
4006 // ( addr -- addr+4 addr@ )
4008 const uint32_t addr
= ufoPop();
4009 const uint32_t count
= ufoImgGetU32(addr
);
4015 // ( addr -- addr+4 addr@&0xff )
4017 const uint32_t addr
= ufoPop();
4018 const uint32_t count
= ufoImgGetU32(addr
);
4020 ufoPush(count
& 0xffU
);
4025 // ( addr -- addr+1 addrC@ )
4027 const uint32_t addr
= ufoPop();
4028 const uint32_t count
= ufoImgGetU8(addr
);
4030 ufoPush(count
& 0xffU
);
4036 ufoImgPutU32(ufoPop(), 0);
4042 ufoImgPutU32(ufoPop(), 1);
4047 UFWORD(POKE_INC_1
) {
4048 const uint32_t addr
= ufoPop();
4049 const uint32_t val
= ufoImgGetU32(addr
);
4050 ufoImgPutU32(addr
, val
+ 1u);
4055 UFWORD(POKE_DEC_1
) {
4056 const uint32_t addr
= ufoPop();
4057 const uint32_t val
= ufoImgGetU32(addr
);
4058 ufoImgPutU32(addr
, val
- 1u);
4062 // ( delta addr -- )
4064 const uint32_t addr
= ufoPop();
4065 const uint32_t delta
= ufoPop();
4066 const uint32_t val
= ufoImgGetU32(addr
);
4067 ufoImgPutU32(addr
, val
+ delta
);
4071 // ( delta addr -- )
4073 const uint32_t addr
= ufoPop();
4074 const uint32_t delta
= ufoPop();
4075 const uint32_t val
= ufoImgGetU32(addr
);
4076 ufoImgPutU32(addr
, val
- delta
);
4080 // ////////////////////////////////////////////////////////////////////////// //
4081 // dictionary emitters
4086 UFWORD(CCOMMA
) { const uint32_t val
= ufoPop(); ufoImgEmitU8(val
); }
4090 UFWORD(WCOMMA
) { const uint32_t val
= ufoPop(); ufoImgEmitU16(val
); }
4094 UFWORD(COMMA
) { const uint32_t val
= ufoPop(); ufoImgEmitU32(val
); }
4097 // ////////////////////////////////////////////////////////////////////////// //
4103 const uint32_t v
= ufoImgGetU32(ufoIP
); ufoIP
+= 4;
4107 // (LITCFA) ( -- n )
4108 UFWORD(PAR_LITCFA
) {
4109 const uint32_t v
= ufoImgGetU32(ufoIP
); ufoIP
+= 4;
4113 // (LITPFA) ( -- n )
4114 UFWORD(PAR_LITPFA
) {
4115 const uint32_t v
= ufoImgGetU32(ufoIP
); ufoIP
+= 4;
4119 // (LITVOCID) ( -- n )
4120 UFWORD(PAR_LITVOCID
) {
4121 const uint32_t v
= ufoImgGetU32(ufoIP
); ufoIP
+= 4;
4126 UFWORD(PAR_LITSTR8
) {
4127 const uint32_t count
= ufoImgGetU8(ufoIP
); ufoIP
+= 1;
4130 ufoIP
+= count
+ 1; // 1 for terminating 0
4131 ufoIP
= UFO_ALIGN4(ufoIP
);
4135 // ////////////////////////////////////////////////////////////////////////// //
4139 #ifdef UFO_RELATIVE_BRANCH
4140 # define UFO_IP_BRANCH() (ufoIP += ufoImgGetU32(ufoIP))
4142 # define UFO_IP_BRANCH() (ufoIP = ufoImgGetU32(ufoIP))
4146 UFWORD(PAR_BRANCH
) {
4150 // (TBRANCH) ( flag )
4151 UFWORD(PAR_TBRANCH
) {
4159 // (0BRANCH) ( flag )
4160 UFWORD(PAR_0BRANCH
) {
4168 // (+0BRANCH) ( flag )
4169 UFWORD(PAR_P0BRANCH
) {
4170 if ((ufoPop() & 0x80000000u
) == 0) {
4177 // (+BRANCH) ( flag )
4178 UFWORD(PAR_PBRANCH
) {
4179 const int32_t v
= (int32_t)ufoPop();
4187 // (-0BRANCH) ( flag )
4188 UFWORD(PAR_M0BRANCH
) {
4189 const int32_t v
= (int32_t)ufoPop();
4197 // (-BRANCH) ( flag )
4198 UFWORD(PAR_MBRANCH
) {
4199 if ((ufoPop() & 0x80000000u
) != 0) {
4206 // (DATASKIP) ( -- )
4207 UFWORD(PAR_DATASKIP
) {
4208 ufoIP
+= UFO_ALIGN4(4u + ufoImgGetU32(ufoIP
));
4212 // ( !0 -- !0 ) -- jmp
4213 // ( 0 -- ) -- no jmp
4214 UFWORD(PAR_OR_BRANCH
) {
4225 // ( 0 -- 0 ) -- jmp
4226 // ( !0 -- ) -- no jmp
4227 UFWORD(PAR_AND_BRANCH
) {
4239 // ( !0 -- !0 ) -- no jmp
4240 UFWORD(PAR_QDUP_0BRANCH
) {
4252 // ( n !0 -- ) -- no jmp
4253 UFWORD(PAR_CASE_BRANCH
) {
4265 // ////////////////////////////////////////////////////////////////////////// //
4266 // execute words by CFA
4271 UFO_EXEC_CFA(ufoPop());
4274 // EXECUTE-TAIL ( cfa )
4275 UFWORD(EXECUTE_TAIL
) {
4276 if (ufoRP
!= 0) ufoIP
= ufoRPop();
4277 UFO_EXEC_CFA(ufoPop());
4280 // @EXECUTE ( addr )
4281 UFWORD(LOAD_EXECUTE
) {
4282 const uint32_t addr
= ufoPop();
4283 UFO_EXEC_CFA(ufoImgGetU32(addr
));
4286 // @EXECUTE-TAIL ( cfa )
4287 UFWORD(LOAD_EXECUTE_TAIL
) {
4288 if (ufoRP
!= 0) ufoIP
= ufoRPop();
4289 const uint32_t addr
= ufoPop();
4290 UFO_EXEC_CFA(ufoImgGetU32(addr
));
4293 // (FORTH-CALL) ( pfa )
4294 UFWORD(FORTH_CALL
) {
4299 // (FORTH-TAIL-CALL) ( pfa )
4300 UFWORD(FORTH_TAIL_CALL
) {
4305 // ////////////////////////////////////////////////////////////////////////// //
4306 // word termination, locals support
4311 if (ufoRP
== 0) longjmp(ufoStopVMJP
, 667);
4316 // ( -- self-value )
4317 UFWORD(PAR_SELF_LOAD
) {
4318 ufoPush(ufoImgGetU32(ufoAddrSelf
));
4322 // ( self-value -- )
4323 UFWORD(PAR_SELF_STORE
) {
4324 const uint32_t val
= ufoPop();
4325 ufoImgPutU32(ufoAddrSelf
, val
);
4330 UFWORD(PAR_LENTER
) {
4331 // low byte of loccount is total number of locals
4332 // high byte is the number of args
4333 uint32_t lcount
= ufoImgGetU32(ufoIP
); ufoIP
+= 4u;
4334 uint32_t acount
= (lcount
>> 8) & 0xff;
4336 if (lcount
== 0 || lcount
< acount
) ufoFatal("invalid call to (L-ENTER)");
4337 if ((ufoLBP
!= 0 && ufoLBP
>= ufoLP
) || UFO_LSTACK_SIZE
- ufoLP
<= lcount
+ 2) {
4338 ufoFatal("out of locals stack");
4341 if (ufoLP
== 0) { ufoLP
= 1; newbp
= 1; } else newbp
= ufoLP
;
4342 //fprintf(stderr, "LP: %u; LBP: %u; locs: %u; word: %s\n", ufoLP, ufoLBP, fw->locs, fw->name);
4343 ufoLStack
[ufoLP
] = ufoLBP
; ufoLP
+= 1;
4344 ufoLBP
= newbp
; ufoLP
+= lcount
;
4347 while (newbp
!= ufoLBP
) {
4348 ufoLStack
[newbp
] = ufoPop();
4354 UFWORD(PAR_LLEAVE
) {
4355 if (ufoLBP
== 0) ufoFatal("(L-LEAVE) with empty locals stack");
4356 if (ufoLBP
>= ufoLP
) ufoFatal("(L-LEAVE) broken locals stack");
4358 ufoLBP
= ufoLStack
[ufoLBP
];
4361 //==========================================================================
4365 //==========================================================================
4366 UFO_FORCE_INLINE
void ufoLoadLocal (const uint32_t lidx
) {
4367 if (lidx
== 0 || lidx
>= UFO_LSTACK_SIZE
) ufoFatal("invalid local index");
4368 if (ufoLBP
== 0 || ufoLBP
>= ufoLP
|| ufoLP
- ufoLBP
<= lidx
) ufoFatal("invalid local index");
4369 ufoPush(ufoLStack
[ufoLBP
+ lidx
]);
4372 //==========================================================================
4376 //==========================================================================
4377 UFO_FORCE_INLINE
void ufoStoreLocal (const uint32_t lidx
) {
4378 const uint32_t value
= ufoPop();
4379 if (lidx
== 0 || lidx
>= UFO_LSTACK_SIZE
) ufoFatal("invalid local index");
4380 if (ufoLBP
== 0 || ufoLBP
>= ufoLP
|| ufoLP
- ufoLBP
<= lidx
) ufoFatal("invalid local index");
4381 ufoLStack
[ufoLBP
+ lidx
] = value
;
4386 UFWORD(PAR_LOCAL_LOAD
) { ufoLoadLocal(ufoPop()); }
4390 UFWORD(PAR_LOCAL_STORE
) { ufoStoreLocal(ufoPop()); }
4393 // ////////////////////////////////////////////////////////////////////////// //
4394 // stack manipulation
4399 UFWORD(DUP
) { ufoDup(); }
4404 const uint32_t b
= UFO_TOS
;
4411 const uint32_t b
= ufoPop();
4412 const uint32_t a
= ufoPop();
4413 ufoPush(b
); ufoPush(a
); ufoPush(b
);
4416 // ( n -- n n ) | ( 0 -- 0 )
4419 const uint32_t n
= UFO_TOS
;
4423 // ( n0 n1 -- n0 n1 n0 n1 )
4424 UFWORD(DDUP
) { ufo2Dup(); }
4427 UFWORD(DROP
) { ufoDrop(); }
4430 UFWORD(DDROP
) { ufo2Drop(); }
4432 // ( n0 n1 -- n1 n0 )
4433 UFWORD(SWAP
) { ufoSwap(); }
4435 // ( n0 n1 -- n1 n0 )
4436 UFWORD(DSWAP
) { ufo2Swap(); }
4438 // ( n0 n1 -- n0 n1 n0 )
4439 UFWORD(OVER
) { ufoOver(); }
4441 // ( n0 n1 -- n0 n1 n0 )
4442 UFWORD(DOVER
) { ufo2Over(); }
4444 // ( n0 n1 n2 -- n1 n2 n0 )
4445 UFWORD(ROT
) { ufoRot(); }
4447 // ( n0 n1 n2 -- n2 n0 n1 )
4448 UFWORD(NROT
) { ufoNRot(); }
4452 UFWORD(RDUP
) { ufoRDup(); }
4455 UFWORD(RDROP
) { ufoRDrop(); }
4459 UFWORD(DTOR
) { ufoRPush(ufoPop()); }
4462 UFWORD(RTOD
) { ufoPush(ufoRPop()); }
4465 UFWORD(RPEEK
) { ufoPush(ufoRPeek()); }
4473 // ( a b | -- | a b )
4475 const uint32_t b
= ufoPop();
4476 const uint32_t a
= ufoPop();
4481 // ( | a b -- a b | )
4483 const uint32_t b
= ufoRPop();
4484 const uint32_t a
= ufoRPop();
4489 // ( | a b -- a b | a b )
4499 const uint32_t n
= ufoPop();
4500 if (n
>= ufoSP
) ufoFatal("invalid PICK index %u", n
);
4501 ufoPush(ufoDStack
[ufoSP
- n
- 1u]);
4507 const uint32_t n
= ufoPop();
4508 if (n
>= ufoRP
) ufoFatal("invalid RPICK index %u", n
);
4509 const uint32_t rp
= ufoRP
- n
- 1u;
4510 ufoPush(ufoRStack
[rp
]);
4516 const uint32_t n
= ufoPop();
4517 if (n
>= ufoSP
) ufoFatal("invalid ROLL index %u", n
);
4519 case 0: break; // do nothing
4520 case 1: ufoSwap(); break;
4521 case 2: ufoRot(); break;
4524 const uint32_t val
= ufoDStack
[ufoSP
- n
- 1u];
4525 for (uint32_t f
= ufoSP
- n
; f
< ufoSP
; f
+= 1) ufoDStack
[f
- 1] = ufoDStack
[f
];
4526 ufoDStack
[ufoSP
- 1u] = val
;
4535 const uint32_t n
= ufoPop();
4536 if (n
>= ufoRP
) ufoFatal("invalid RROLL index %u", n
);
4538 const uint32_t rp
= ufoRP
- n
- 1u;
4539 const uint32_t val
= ufoRStack
[rp
];
4540 for (uint32_t f
= rp
+ 1u; f
< ufoRP
; f
+= 1u) ufoRStack
[f
- 1u] = ufoRStack
[f
];
4541 ufoRStack
[ufoRP
- 1u] = val
;
4546 // ( | a b -- | b a )
4549 const uint32_t b
= UFO_RTOS
;
4550 const uint32_t a
= UFO_R(1);
4556 // ( | a b -- | a b a )
4559 const uint32_t a
= UFO_R(1);
4564 // ( | a b c -- | b c a )
4567 const uint32_t c
= UFO_RTOS
;
4568 const uint32_t b
= UFO_R(1);
4569 const uint32_t a
= UFO_R(2);
4576 // ( | a b c -- | c a b )
4579 const uint32_t c
= UFO_RTOS
;
4580 const uint32_t b
= UFO_R(1);
4581 const uint32_t a
= UFO_R(2);
4588 // ////////////////////////////////////////////////////////////////////////// //
4595 ufoPushBool(ufoLoadNextLine(1));
4600 UFWORD(REFILL_NOCROSS
) {
4601 ufoPushBool(ufoLoadNextLine(0));
4607 ufoPush(ufoImgGetU32(ufoAddrTIBx
) + ufoImgGetU32(ufoAddrINx
));
4612 UFWORD(TIB_PEEKCH
) {
4613 ufoPush(ufoTibPeekCh());
4618 UFWORD(TIB_PEEKCH_OFS
) {
4619 const uint32_t ofs
= ufoPop();
4620 ufoPush(ufoTibPeekChOfs(ofs
));
4626 ufoPush(ufoTibGetCh());
4631 UFWORD(TIB_SKIPCH
) {
4636 // ////////////////////////////////////////////////////////////////////////// //
4640 //==========================================================================
4644 //==========================================================================
4645 UFO_FORCE_INLINE
int ufoIsDelim (uint8_t ch
, uint8_t delim
) {
4646 return (delim
== 32 ? (ch
<= 32) : (ch
== delim
));
4650 // ( delim skip-leading-delim? -- addr count TRUE / FALSE )
4651 // does base TIB parsing; never copies anything.
4652 // as our reader is line-based, returns FALSE on EOL.
4653 // EOL is detected after skipping leading delimiters.
4654 // passing -1 as delimiter skips the whole line, and always returns FALSE.
4655 // trailing delimiter is always skipped.
4657 const uint32_t skipDelim
= ufoPop();
4658 const uint32_t delim
= ufoPop();
4661 if (delim
== 0 || delim
> 0xffU
) {
4663 while (ufoTibGetCh() != 0) {}
4666 ch
= ufoTibPeekCh();
4667 // skip initial delimiters
4669 while (ch
!= 0 && ufoIsDelim(ch
, delim
)) {
4671 ch
= ufoTibPeekCh();
4678 const uint32_t staddr
= ufoImgGetU32(ufoAddrTIBx
) + ufoImgGetU32(ufoAddrINx
);
4680 while (ch
!= 0 && !ufoIsDelim(ch
, delim
)) {
4683 ch
= ufoTibPeekCh();
4686 if (ch
!= 0) ufoTibSkipCh();
4694 // PARSE-SKIP-BLANKS
4696 UFWORD(PARSE_SKIP_BLANKS
) {
4697 uint8_t ch
= ufoTibPeekCh();
4698 while (ch
!= 0 && ch
<= 32) {
4700 ch
= ufoTibPeekCh();
4704 //==========================================================================
4706 // ufoParseMLComment
4708 // initial two chars are skipped
4710 //==========================================================================
4711 static void ufoParseMLComment (uint32_t allowMulti
, int nested
) {
4714 while (level
!= 0) {
4718 UFCALL(REFILL_NOCROSS
);
4719 if (ufoPop() == 0) ufoFatal("unexpected end of file in comment");
4721 ufoFatal("unexpected end of line in comment");
4724 ch1
= ufoTibPeekCh();
4725 if (nested
&& ch
== '(' && ch1
== '(') { ufoTibSkipCh(); level
+= 1; }
4726 else if (nested
&& ch
== ')' && ch1
== ')') { ufoTibSkipCh(); level
-= 1; }
4727 else if (!nested
&& ch
== '*' && ch1
== ')') { ufo_assert(level
== 1); ufoTibSkipCh(); level
= 0; }
4732 // (PARSE-SKIP-COMMENTS)
4733 // ( allow-multiline? -- )
4734 // skip all blanks and comments
4735 UFWORD(PAR_PARSE_SKIP_COMMENTS
) {
4736 const uint32_t allowMulti
= ufoPop();
4738 ch
= ufoTibPeekCh();
4740 fprintf(stderr
, "(PARSE-SKIP-COMMENTS): first-ch:'%c'\n", (char)ch
);
4745 ch
= ufoTibPeekCh();
4747 fprintf(stderr
, "(PARSE-SKIP-COMMENTS): blank-ch:'%c'\n", (char)ch
);
4749 } else if (ch
== '(') {
4751 fprintf(stderr
, "(PARSE-SKIP-COMMENTS): ch:'%c'; ch1:'%c' ('%c')\n", (char)ch
, (char)ch1
,
4752 ufoTibPeekChOfs(0));
4754 ch1
= ufoTibPeekChOfs(1);
4756 // single-line comment
4757 do { ch
= ufoTibGetCh(); } while (ch
!= 0 && ch
!= ')');
4758 ch
= ufoTibPeekCh();
4759 } else if ((ch1
== '*' || ch1
== '(') && ufoTibPeekChOfs(2) <= 32) {
4760 // possibly multiline
4761 ufoTibSkipCh(); ufoTibSkipCh(); // skip opening
4762 ufoParseMLComment(allowMulti
, (ch1
== '('));
4763 ch
= ufoTibPeekCh();
4767 } else if (ch
== '\\' && ufoTibPeekChOfs(1) <= 32) {
4768 // single-line comment
4769 while (ch
!= 0) ch
= ufoTibGetCh();
4770 } else if (ch
== '-' && ufoTibPeekChOfs(1) == ch
&& ufoTibPeekChOfs(2) <= 32) {
4772 while (ch
!= 0) ch
= ufoTibGetCh();
4773 } else if ((ch
== ';' || ch
== '/') && ufoTibPeekChOfs(1) == ch
) {
4775 while (ch
!= 0) ch
= ufoTibGetCh();
4781 fprintf(stderr
, "(PARSE-SKIP-COMMENTS): end-ch:'%c'\n", ufoTibPeekCh());
4787 UFWORD(PARSE_SKIP_LINE
) {
4788 ufoPush(0); ufoPushBool(0); UFCALL(PAR_PARSE
);
4789 if (ufoPop() != 0) {
4795 // ( -- addr count )
4796 // parse with leading blanks skipping. doesn't copy anything.
4797 // return empty string on EOL.
4798 UFWORD(PARSE_NAME
) {
4799 ufoPush(32); ufoPushBool(1); UFCALL(PAR_PARSE
);
4800 if (ufoPop() == 0) {
4807 // ( delim -- addr count TRUE / FALSE )
4808 // parse without skipping delimiters; never copies anything.
4809 // as our reader is line-based, returns FALSE on EOL.
4810 // passing 0 as delimiter skips the whole line, and always returns FALSE.
4811 // trailing delimiter is always skipped.
4813 ufoPushBool(0); UFCALL(PAR_PARSE
);
4817 // ////////////////////////////////////////////////////////////////////////// //
4823 UFWORD(PAR_NORM_EMIT_CHAR
) {
4824 uint32_t ch
= ufoPop()&0xffU
;
4825 if (ch
< 32 || ch
== 127) {
4826 if (ch
!= 9 && ch
!= 10 && ch
!= 13) ch
= '?';
4831 // (NORM-XEMIT-CHAR)
4833 UFWORD(PAR_NORM_XEMIT_CHAR
) {
4834 uint32_t ch
= ufoPop()&0xffU
;
4835 if (ch
< 32 || ch
== 127) ch
= '?';
4842 uint32_t ch
= ufoPop()&0xffU
;
4843 ufoLastEmitWasCR
= (ch
== 10);
4850 ufoPushBool(ufoLastEmitWasCR
);
4856 ufoLastEmitWasCR
= !!ufoPop();
4861 UFWORD(FLUSH_EMIT
) {
4866 // ////////////////////////////////////////////////////////////////////////// //
4870 #define UF_UMATH(name_,op_) \
4872 const uint32_t a = ufoPop(); \
4876 #define UF_BMATH(name_,op_) \
4878 const uint32_t b = ufoPop(); \
4879 const uint32_t a = ufoPop(); \
4883 #define UF_BDIV(name_,op_) \
4885 const uint32_t b = ufoPop(); \
4886 const uint32_t a = ufoPop(); \
4887 if (b == 0) ufoFatal("division by zero"); \
4891 #define UFO_POP_U64() ({ \
4892 const uint32_t hi_ = ufoPop(); \
4893 const uint32_t lo_ = ufoPop(); \
4894 (((uint64_t)hi_ << 32) | lo_); \
4897 // this is UB by the idiotic C standard. i don't care.
4898 #define UFO_POP_I64() ((int64_t)UFO_POP_U64())
4900 #define UFO_PUSH_U64(vn_) do { \
4901 ufoPush((uint32_t)(vn_)); \
4902 ufoPush((uint32_t)((vn_) >> 32)); \
4905 // this is UB by the idiotic C standard. i don't care.
4906 #define UFO_PUSH_I64(vn_) UFO_PUSH_U64((uint64_t)(vn_))
4910 UF_BMATH(PLUS
, a
+ b
);
4914 UF_BMATH(MINUS
, a
- b
);
4918 UF_BMATH(MUL
, (uint32_t)((int32_t)a
* (int32_t)b
));
4922 UF_BMATH(UMUL
, a
* b
);
4926 UF_BDIV(DIV
, (uint32_t)((int32_t)a
/ (int32_t)b
));
4930 UF_BDIV(UDIV
, a
/ b
);
4934 UF_BDIV(MOD
, (uint32_t)((int32_t)a
% (int32_t)b
));
4938 UF_BDIV(UMOD
, a
% b
);
4941 // ( a b -- a/b, a%b )
4943 const int32_t b
= (int32_t)ufoPop();
4944 const int32_t a
= (int32_t)ufoPop();
4945 if (b
== 0) ufoFatal("division by zero");
4946 ufoPush((uint32_t)(a
/b
));
4947 ufoPush((uint32_t)(a
%b
));
4951 // ( a b -- a/b, a%b )
4953 const uint32_t b
= ufoPop();
4954 const uint32_t a
= ufoPop();
4955 if (b
== 0) ufoFatal("division by zero");
4956 ufoPush((uint32_t)(a
/b
));
4957 ufoPush((uint32_t)(a
%b
));
4961 // ( a b c -- a*b/c )
4962 // this uses 64-bit intermediate value
4964 const int32_t c
= (int32_t)ufoPop();
4965 const int32_t b
= (int32_t)ufoPop();
4966 const int32_t a
= (int32_t)ufoPop();
4967 if (c
== 0) ufoFatal("division by zero");
4968 int64_t xval
= a
; xval
*= b
; xval
/= c
;
4969 ufoPush((uint32_t)(int32_t)xval
);
4973 // ( a b c -- a*b/c )
4974 // this uses 64-bit intermediate value
4976 const uint32_t c
= ufoPop();
4977 const uint32_t b
= ufoPop();
4978 const uint32_t a
= ufoPop();
4979 if (c
== 0) ufoFatal("division by zero");
4980 uint64_t xval
= a
; xval
*= b
; xval
/= c
;
4981 ufoPush((uint32_t)xval
);
4985 // ( a b c -- a*b/c a*b%c )
4986 // this uses 64-bit intermediate value
4988 const int32_t c
= (int32_t)ufoPop();
4989 const int32_t b
= (int32_t)ufoPop();
4990 const int32_t a
= (int32_t)ufoPop();
4991 if (c
== 0) ufoFatal("division by zero");
4992 int64_t xval
= a
; xval
*= b
;
4993 ufoPush((uint32_t)(int32_t)(xval
/ c
));
4994 ufoPush((uint32_t)(int32_t)(xval
% c
));
4998 // ( a b c -- a*b/c )
4999 // this uses 64-bit intermediate value
5000 UFWORD(UMULDIVMOD
) {
5001 const uint32_t c
= ufoPop();
5002 const uint32_t b
= ufoPop();
5003 const uint32_t a
= ufoPop();
5004 if (c
== 0) ufoFatal("division by zero");
5005 uint64_t xval
= a
; xval
*= b
;
5006 ufoPush((uint32_t)(xval
/ c
));
5007 ufoPush((uint32_t)(xval
% c
));
5011 // ( a b -- lo(a*b) hi(a*b) )
5012 // this leaves 64-bit result
5014 const int32_t b
= (int32_t)ufoPop();
5015 const int32_t a
= (int32_t)ufoPop();
5016 int64_t xval
= a
; xval
*= b
;
5021 // ( a b -- lo(a*b) hi(a*b) )
5022 // this leaves 64-bit result
5024 const uint32_t b
= ufoPop();
5025 const uint32_t a
= ufoPop();
5026 uint64_t xval
= a
; xval
*= b
;
5031 // ( alo ahi b -- a/b a%b )
5033 const int32_t b
= (int32_t)ufoPop();
5034 if (b
== 0) ufoFatal("division by zero");
5035 int64_t a
= UFO_POP_I64();
5036 int32_t adiv
= (int32_t)(a
/ b
);
5037 int32_t amod
= (int32_t)(a
% b
);
5038 ufoPush((uint32_t)adiv
);
5039 ufoPush((uint32_t)amod
);
5043 // ( alo ahi b -- a/b a%b )
5045 const uint32_t b
= ufoPop();
5046 if (b
== 0) ufoFatal("division by zero");
5047 uint64_t a
= UFO_POP_U64();
5048 uint32_t adiv
= (uint32_t)(a
/ b
);
5049 uint32_t amod
= (uint32_t)(a
% b
);
5055 // ( alo ahi u -- lo hi )
5057 const uint32_t b
= ufoPop();
5058 uint64_t a
= UFO_POP_U64();
5064 // ( lo0 hi0 lo1 hi1 -- lo hi )
5066 uint64_t n1
= UFO_POP_U64();
5067 uint64_t n0
= UFO_POP_U64();
5073 // ( lo0 hi0 lo1 hi1 -- lo hi )
5075 uint64_t n1
= UFO_POP_U64();
5076 uint64_t n0
= UFO_POP_U64();
5082 // ( lo0 hi0 lo1 hi1 -- bool )
5084 uint64_t n1
= UFO_POP_U64();
5085 uint64_t n0
= UFO_POP_U64();
5086 ufoPushBool(n0
== n1
);
5090 // ( lo0 hi0 lo1 hi1 -- bool )
5092 int64_t n1
= UFO_POP_I64();
5093 int64_t n0
= UFO_POP_I64();
5094 ufoPushBool(n0
< n1
);
5098 // ( lo0 hi0 lo1 hi1 -- bool )
5100 int64_t n1
= UFO_POP_I64();
5101 int64_t n0
= UFO_POP_I64();
5102 ufoPushBool(n0
<= n1
);
5106 // ( lo0 hi0 lo1 hi1 -- bool )
5108 uint64_t n1
= UFO_POP_U64();
5109 uint64_t n0
= UFO_POP_U64();
5110 ufoPushBool(n0
< n1
);
5114 // ( lo0 hi0 lo1 hi1 -- bool )
5116 uint64_t n1
= UFO_POP_U64();
5117 uint64_t n0
= UFO_POP_U64();
5118 ufoPushBool(n0
<= n1
);
5122 // ( dlo dhi n -- nmod ndiv )
5123 // rounds toward zero
5125 const int32_t n
= (int32_t)ufoPop();
5126 if (n
== 0) ufoFatal("division by zero");
5127 int64_t d
= UFO_POP_I64();
5128 int32_t ndiv
= (int32_t)(d
/ n
);
5129 int32_t nmod
= (int32_t)(d
% n
);
5135 // ( dlo dhi n -- nmod ndiv )
5136 // rounds toward negative infinity
5138 const int32_t n
= (int32_t)ufoPop();
5139 if (n
== 0) ufoFatal("division by zero");
5140 int64_t d
= UFO_POP_I64();
5141 int32_t ndiv
= (int32_t)(d
/ n
);
5142 int32_t nmod
= (int32_t)(d
% n
);
5143 if (nmod
!= 0 && ((uint32_t)n
^ (uint32_t)(d
>> 32)) >= 0x80000000u
) {
5152 // ////////////////////////////////////////////////////////////////////////// //
5153 // simple logic and bit manipulation
5156 #define UF_CMP(name_,op_) \
5158 const uint32_t b = ufoPop(); \
5159 const uint32_t a = ufoPop(); \
5165 UF_CMP(LESS
, (int32_t)a
< (int32_t)b
);
5169 UF_CMP(ULESS
, a
< b
);
5173 UF_CMP(GREAT
, (int32_t)a
> (int32_t)b
);
5177 UF_CMP(UGREAT
, a
> b
);
5181 UF_CMP(LESSEQU
, (int32_t)a
<= (int32_t)b
);
5185 UF_CMP(ULESSEQU
, a
<= b
);
5189 UF_CMP(GREATEQU
, (int32_t)a
>= (int32_t)b
);
5193 UF_CMP(UGREATEQU
, a
>= b
);
5197 UF_CMP(EQU
, a
== b
);
5201 UF_CMP(NOTEQU
, a
!= b
);
5206 const uint32_t a
= ufoPop();
5207 ufoPushBool(a
== 0);
5212 UFWORD(ZERO_NOTEQU
) {
5213 const uint32_t a
= ufoPop();
5214 ufoPushBool(a
!= 0);
5219 UF_CMP(LOGAND
, a
&& b
);
5223 UF_CMP(LOGOR
, a
|| b
);
5228 const uint32_t b
= ufoPop();
5229 const uint32_t a
= ufoPop();
5236 const uint32_t b
= ufoPop();
5237 const uint32_t a
= ufoPop();
5244 const uint32_t b
= ufoPop();
5245 const uint32_t a
= ufoPop();
5253 UFO_TOS
&= ufoImgGetU32(ufoIP
); ufoIP
+= 4u;
5260 UFO_TOS
&= ~ufoImgGetU32(ufoIP
); ufoIP
+= 4u;
5267 UFO_TOS
|= ufoImgGetU32(ufoIP
); ufoIP
+= 4u;
5274 UFO_TOS
^= ufoImgGetU32(ufoIP
); ufoIP
+= 4u;
5281 const uint32_t a
= ufoPop();
5287 // arithmetic shift; positive `n` shifts to the left
5289 int32_t c
= (int32_t)ufoPop();
5292 int32_t n
= (int32_t)ufoPop();
5294 n
>>= (uint8_t)(-c
);
5296 if (n
< 0) n
= -1; else n
= 0;
5298 ufoPush((uint32_t)n
);
5301 uint32_t u
= ufoPop();
5313 // logical shift; positive `n` shifts to the left
5315 int32_t c
= (int32_t) ufoPop();
5316 uint32_t u
= ufoPop();
5320 u
>>= (uint8_t)(-c
);
5337 // arithmetic shift right
5339 int32_t c
= (int32_t)ufoPop();
5341 int32_t n
= (int32_t)ufoPop();
5345 if (n
< 0) n
= -1; else n
= 0;
5347 ufoPush((uint32_t)n
);
5349 ufoFatal("negative shift");
5355 // logical shift right
5357 uint32_t c
= (int32_t)ufoPop();
5359 uint32_t n
= (int32_t)ufoPop();
5365 ufoPush((uint32_t)n
);
5367 ufoFatal("negative shift");
5373 // logical shift left
5375 int32_t c
= (int32_t) ufoPop();
5376 uint32_t u
= ufoPop();
5385 ufoFatal("negative shift");
5392 const uint32_t b
= ufoPop();
5393 const uint32_t a
= ufoPop();
5400 if ((ufoPeek() & 0x80000000) != 0) {
5401 UFO_TOS
= ~UFO_TOS
+ 1u;
5409 UFO_TOS
= ~UFO_TOS
+ 1u;
5415 const uint32_t a
= ufoPop();
5416 if ((a
& 0x80000000) != 0) ufoPush(~(uint32_t)0);
5417 else if (a
!= 0) ufoPush(1);
5422 // ( a -- a&0xffff )
5436 // ( a -- (a>>16)&0xffff )
5439 UFO_TOS
= (UFO_TOS
>>16)&0xffffU
;
5443 // ( a -- (a>>8)&0xff )
5446 UFO_TOS
= (UFO_TOS
>>8)&0xffU
;
5450 // ( a b -- min[a,b] )
5452 const int32_t b
= (int32_t)ufoPop();
5454 if ((int32_t)UFO_TOS
> b
) UFO_TOS
= (uint32_t)b
;
5458 // ( a b -- max[a,b] )
5460 const int32_t b
= (int32_t)ufoPop();
5462 if ((int32_t)UFO_TOS
< b
) UFO_TOS
= (uint32_t)b
;
5466 // ( a b -- umin[a,b] )
5468 const uint32_t b
= ufoPop();
5470 if (UFO_TOS
> b
) UFO_TOS
= b
;
5474 // ( a b -- umax[a,b] )
5476 const uint32_t b
= ufoPop();
5478 if (UFO_TOS
< b
) UFO_TOS
= b
;
5482 // ( a lo hi -- a>=lo&&a<hi )
5484 //const int32_t hi = (int32_t)ufoPop();
5485 //const int32_t lo = (int32_t)ufoPop();
5486 //const int32_t a = (int32_t)ufoPop();
5487 //ufoPushBool(a >= lo && a < hi);
5488 // sadly, idiotic ANS standard requires this:
5489 const uint32_t hi
= ufoPop();
5490 const uint32_t lo
= ufoPop();
5491 const uint32_t a
= ufoPop();
5492 ufoPushBool(a
- lo
< hi
- lo
);
5496 // ( ua ulo uhi -- ua>=ulo&&ua<uhi )
5498 const uint32_t hi
= ufoPop();
5499 const uint32_t lo
= ufoPop();
5500 const uint32_t a
= ufoPop();
5501 ufoPushBool(a
>= lo
&& a
< hi
);
5505 // ( ua ulo uhi -- ua>=ulo&&ua<=uhi )
5507 const uint32_t hi
= ufoPop();
5508 const uint32_t lo
= ufoPop();
5509 const uint32_t a
= ufoPop();
5510 ufoPushBool(a
>= lo
&& a
<= hi
);
5517 const uint32_t a
= UFO_TOS
;
5518 UFO_TOS
= (uint32_t)__builtin_bswap16((uint16_t)a
);
5525 const uint32_t a
= UFO_TOS
;
5526 UFO_TOS
= __builtin_bswap32(a
);
5531 UFWORD(PAR_SWAP_INC_SWAP
) {
5595 const uint32_t n
= ufoPop();
5603 const uint32_t n
= ufoPop();
5633 UFO_TOS
= (uint32_t)((int32_t)UFO_TOS
>> 1);
5640 UFO_TOS
= (uint32_t)((int32_t)UFO_TOS
>> 2);
5647 UFO_TOS
= (uint32_t)((int32_t)UFO_TOS
>> 3);
5675 if ((int32_t)UFO_TOS
< 0) UFO_TOS
= ufoTrueValue
; else UFO_TOS
= 0;
5682 if ((int32_t)UFO_TOS
<= 0) UFO_TOS
= ufoTrueValue
; else UFO_TOS
= 0;
5689 if ((int32_t)UFO_TOS
> 0) UFO_TOS
= ufoTrueValue
; else UFO_TOS
= 0;
5696 if ((int32_t)UFO_TOS
>= 0) UFO_TOS
= ufoTrueValue
; else UFO_TOS
= 0;
5700 // ////////////////////////////////////////////////////////////////////////// //
5701 // string unescaping
5705 // ( addr count -- addr count )
5706 UFWORD(PAR_UNESCAPE
) {
5707 const uint32_t count
= ufoPop();
5708 const uint32_t addr
= ufoPeek();
5709 if ((count
& ((uint32_t)1<<31)) == 0) {
5710 const uint32_t eaddr
= addr
+ count
;
5711 uint32_t caddr
= addr
;
5712 uint32_t daddr
= addr
;
5713 while (caddr
!= eaddr
) {
5714 uint8_t ch
= ufoImgGetU8(caddr
); caddr
+= 1u;
5715 if (ch
== '\\' && caddr
!= eaddr
) {
5716 ch
= ufoImgGetU8(caddr
); caddr
+= 1u;
5718 case 'r': ch
= '\r'; break;
5719 case 'n': ch
= '\n'; break;
5720 case 't': ch
= '\t'; break;
5721 case 'e': ch
= '\x1b'; break;
5722 case '`': ch
= '"'; break; // special escape to insert double-quote
5723 case '"': ch
= '"'; break;
5724 case '\\': ch
= '\\'; break;
5726 if (eaddr
- daddr
>= 1) {
5727 const int dg0
= digitInBase((char)(ufoImgGetU8(caddr
)), 16);
5728 if (dg0
< 0) ufoFatal("invalid hex string escape");
5729 if (eaddr
- daddr
>= 2) {
5730 const int dg1
= digitInBase((char)(ufoImgGetU8(caddr
+ 1u)), 16);
5731 if (dg1
< 0) ufoFatal("invalid hex string escape");
5732 ch
= (uint8_t)(dg0
* 16 + dg1
);
5739 ufoFatal("invalid hex string escape");
5742 default: ufoFatal("invalid string escape");
5745 ufoImgPutU8(daddr
, ch
); daddr
+= 1u;
5747 ufoPush(daddr
- addr
);
5754 // ////////////////////////////////////////////////////////////////////////// //
5755 // numeric conversions
5758 // (BASED-NUMBER) ( addr count allowsign? base -- num TRUE / FALSE )
5759 UFWORD(PAR_BASED_NUMBER
) {
5760 const uint32_t xbase
= ufoPop();
5761 const uint32_t allowSign
= ufoPop();
5762 int32_t count
= (int32_t)ufoPop();
5763 uint32_t addr
= ufoPop();
5769 if (allowSign
&& count
> 1) {
5770 ch
= ufoImgGetU8(addr
);
5771 if (ch
== '-') { neg
= 1; addr
+= 1u; count
-= 1; }
5772 else if (ch
== '+') { neg
= 0; addr
+= 1u; count
-= 1; }
5775 // special-based numbers
5776 ch
= ufoImgGetU8(addr
);
5777 if (count
>= 3 && ch
== '0') {
5778 switch (ufoImgGetU8(addr
+ 1u)) {
5779 case 'x': case 'X': base
= 16; break;
5780 case 'o': case 'O': base
= 8; break;
5781 case 'b': case 'B': base
= 2; break;
5782 case 'd': case 'D': base
= 10; break;
5785 if (base
&& digitInBase((char)ufoImgGetU8(addr
+ (uint32_t)count
- 1u), base
) >= 0) {
5786 addr
+= 2; count
-= 2;
5790 } else if (count
>= 2 && ch
== '$') {
5792 addr
+= 1u; count
-= 1;
5793 } else if (count
>= 2 && ch
== '#') {
5795 addr
+= 1u; count
-= 1;
5796 } else if (count
>= 2 && ch
== '%') {
5798 addr
+= 1u; count
-= 1;
5799 } else if (count
>= 3 && ch
== '&') {
5800 switch (ufoImgGetU8(addr
+ 1u)) {
5801 case 'h': case 'H': base
= 16; break;
5802 case 'o': case 'O': base
= 8; break;
5803 case 'b': case 'B': base
= 2; break;
5804 case 'd': case 'D': base
= 10; break;
5807 if (base
) { addr
+= 2u; count
-= 2; }
5809 if (!base
&& count
> 2 && ch
>= '0' && ch
<= '9') {
5810 ch
= ufoImgGetU8(addr
+ (uint32_t)count
- 1u);
5812 case 'b': case 'B': if (xbase
< 12) base
= 2; break;
5813 case 'o': case 'O': if (xbase
< 25) base
= 8; break;
5814 case 'h': case 'H': if (xbase
< 18) base
= 16; break;
5816 if (base
) count
-= 1;
5820 if (!base
&& xbase
< 255) base
= xbase
;
5822 if (count
<= 0 || base
< 1 || base
> 36) {
5826 int wasDig
= 0, wasUnder
= 1, error
= 0, dig
;
5827 while (!error
&& count
!= 0) {
5828 ch
= ufoImgGetU8(addr
); addr
+= 1u; count
-= 1;
5830 error
= 1; wasUnder
= 0; wasDig
= 1;
5831 dig
= digitInBase((char)ch
, (int)base
);
5833 nc
= n
* (uint32_t)base
;
5835 nc
+= (uint32_t)dig
;
5848 if (!error
&& wasDig
&& !wasUnder
) {
5849 if (allowSign
&& neg
) n
= ~n
+ 1u;
5859 // ////////////////////////////////////////////////////////////////////////// //
5860 // compiler-related, dictionary-related
5863 static char ufoWNameBuf
[256];
5865 // (CREATE-WORD-HEADER)
5866 // ( addr count word-flags -- )
5867 UFWORD(PAR_CREATE_WORD_HEADER
) {
5868 const uint32_t flags
= ufoPop();
5869 const uint32_t wlen
= ufoPop();
5870 const uint32_t waddr
= ufoPop();
5871 if (wlen
== 0) ufoFatal("word name expected");
5872 if (wlen
>= UFO_MAX_WORD_LENGTH
) ufoFatal("word name too long");
5873 // copy to separate buffer
5874 for (uint32_t f
= 0; f
< wlen
; f
+= 1) {
5875 ufoWNameBuf
[f
] = (char)ufoImgGetU8(waddr
+ f
);
5877 ufoWNameBuf
[wlen
] = 0;
5878 ufoCreateWordHeader(ufoWNameBuf
, flags
);
5881 // (CREATE-NAMELESS-WORD-HEADER)
5882 // ( word-flags -- )
5883 UFWORD(PAR_CREATE_NAMELESS_WORD_HEADER
) {
5884 const uint32_t flags
= ufoPop();
5885 ufoCreateWordHeader("", flags
);
5889 // ( addr count -- cfa TRUE / FALSE )
5891 const uint32_t wlen
= ufoPop();
5892 const uint32_t waddr
= ufoPop();
5893 if (wlen
> 0 && wlen
< UFO_MAX_WORD_LENGTH
) {
5894 // copy to separate buffer
5895 for (uint32_t f
= 0; f
< wlen
; f
+= 1) {
5896 ufoWNameBuf
[f
] = (char)ufoImgGetU8(waddr
+ f
);
5898 ufoWNameBuf
[wlen
] = 0;
5899 const uint32_t cfa
= ufoFindWord(ufoWNameBuf
);
5911 // (FIND-WORD-IN-VOC)
5912 // ( addr count vocid allowhidden -- cfa TRUE / FALSE)
5913 // find only in the given voc; no name resolution
5914 UFWORD(PAR_FIND_WORD_IN_VOC
) {
5915 const uint32_t allowHidden
= ufoPop();
5916 const uint32_t vocid
= ufoPop();
5917 const uint32_t wlen
= ufoPop();
5918 const uint32_t waddr
= ufoPop();
5919 if (wlen
> 0 && wlen
< UFO_MAX_WORD_LENGTH
) {
5920 // copy to separate buffer
5921 for (uint32_t f
= 0; f
< wlen
; f
+= 1) {
5922 ufoWNameBuf
[f
] = (char)ufoImgGetU8(waddr
+ f
);
5924 ufoWNameBuf
[wlen
] = 0;
5925 const uint32_t cfa
= ufoFindWordInVoc(ufoWNameBuf
, wlen
, 0, vocid
, (allowHidden
? 1 : 0));
5937 // (FIND-WORD-IN-VOC-AND-PARENTS)
5938 // ( addr count vocid allowhidden -- cfa TRUE / FALSE)
5939 // find only in the given voc; no name resolution
5940 UFWORD(PAR_FIND_WORD_IN_VOC_AND_PARENTS
) {
5941 const uint32_t allowHidden
= ufoPop();
5942 const uint32_t vocid
= ufoPop();
5943 const uint32_t wlen
= ufoPop();
5944 const uint32_t waddr
= ufoPop();
5945 if (wlen
> 0 && wlen
< UFO_MAX_WORD_LENGTH
) {
5946 // copy to separate buffer
5947 for (uint32_t f
= 0; f
< wlen
; f
+= 1) {
5948 ufoWNameBuf
[f
] = (char)ufoImgGetU8(waddr
+ f
);
5950 ufoWNameBuf
[wlen
] = 0;
5951 const uint32_t cfa
= ufoFindWordInVocAndParents(ufoWNameBuf
, wlen
, 0, vocid
, (allowHidden
? 1 : 0));
5964 // ( addr count vocid -- cfa TRUE / FALSE)
5965 // find only in the given voc; no name resolution, no hidden words
5966 UFWORD(FIND_WORD_IN_VOC
) { ufoPush(0); UFCALL(PAR_FIND_WORD_IN_VOC
); }
5968 // FIND-WORD-IN-VOC-AND-PARENTS
5969 // ( addr count vocid -- cfa TRUE / FALSE)
5970 // find only in the given voc; no name resolution, no hidden words
5971 UFWORD(FIND_WORD_IN_VOC_AND_PARENTS
) { ufoPush(0); UFCALL(PAR_FIND_WORD_IN_VOC_AND_PARENTS
); }
5974 // ////////////////////////////////////////////////////////////////////////// //
5975 // more compiler words
5978 // ////////////////////////////////////////////////////////////////////////// //
5979 // vocabulary and wordlist utilities
5984 UFWORD(PAR_GET_VSP
) {
5990 UFWORD(PAR_SET_VSP
) {
5991 const uint32_t vsp
= ufoPop();
5992 if (vsp
> UFO_VOCSTACK_SIZE
) ufoFatal("VSP %u out of range (%u)", vsp
, UFO_VOCSTACK_SIZE
);
5998 UFWORD(PAR_VSP_LOAD
) {
5999 const uint32_t vsp
= ufoPop();
6000 if (vsp
>= UFO_VOCSTACK_SIZE
) ufoFatal("VSP %u out of range (%u)", vsp
, UFO_VOCSTACK_SIZE
);
6001 ufoPush(ufoVocStack
[vsp
]);
6006 UFWORD(PAR_VSP_STORE
) {
6007 const uint32_t vsp
= ufoPop();
6008 const uint32_t value
= ufoPop();
6009 if (vsp
>= UFO_VOCSTACK_SIZE
) ufoFatal("VSP %u out of range (%u)", vsp
, UFO_VOCSTACK_SIZE
);
6010 ufoVocStack
[vsp
] = value
;
6014 // ////////////////////////////////////////////////////////////////////////// //
6015 // word field address conversion
6019 // ( cfa -- does-cfa )
6020 UFWORD(CFA2DOESCFA
) {
6022 UFO_TOS
= UFO_CFA_TO_DOES_CFA(UFO_TOS
);
6029 UFO_TOS
= UFO_CFA_TO_PFA(UFO_TOS
);
6036 UFO_TOS
= UFO_CFA_TO_NFA(UFO_TOS
);
6043 UFO_TOS
= UFO_CFA_TO_LFA(UFO_TOS
);
6047 // ( cfa -- wend-addr )
6050 UFO_TOS
= ufoGetWordEndAddr(UFO_TOS
);
6057 UFO_TOS
= UFO_PFA_TO_CFA(UFO_TOS
);
6064 UFO_TOS
= UFO_PFA_TO_CFA(UFO_TOS
);
6065 UFO_TOS
= UFO_CFA_TO_NFA(UFO_TOS
);
6072 UFO_TOS
= UFO_NFA_TO_CFA(UFO_TOS
);
6079 UFO_TOS
= UFO_NFA_TO_CFA(UFO_TOS
);
6080 UFO_TOS
= UFO_CFA_TO_PFA(UFO_TOS
);
6087 UFO_TOS
= UFO_NFA_TO_LFA(UFO_TOS
);
6094 UFO_TOS
= UFO_LFA_TO_CFA(UFO_TOS
);
6101 UFO_TOS
= UFO_LFA_TO_CFA(UFO_TOS
);
6102 UFO_TOS
= UFO_CFA_TO_PFA(UFO_TOS
);
6109 UFO_TOS
= UFO_LFA_TO_BFA(UFO_TOS
);
6116 UFO_TOS
= UFO_LFA_TO_XFA(UFO_TOS
);
6123 UFO_TOS
= UFO_LFA_TO_YFA(UFO_TOS
);
6130 UFO_TOS
= UFO_LFA_TO_NFA(UFO_TOS
);
6134 // ( ip -- nfa / 0 )
6137 UFO_TOS
= ufoFindWordForIP(UFO_TOS
);
6141 // ( ip -- addr count line TRUE / FALSE )
6142 // name is at PAD; it is safe to use PAD, because each task has its own temp image
6143 UFWORD(IP2FILELINE
) {
6144 const uint32_t ip
= ufoPop();
6146 const char *fname
= ufoFindFileForIP(ip
, &fline
, NULL
, NULL
);
6147 if (fname
!= NULL
) {
6148 uint32_t addr
= UFO_PAD_ADDR
;
6150 while (*fname
!= 0) {
6151 ufoImgPutU8(addr
, *(const unsigned char *)fname
);
6152 fname
+= 1u; addr
+= 1u; count
+= 1u;
6154 ufoImgPutU8(addr
, 0); // just in case
6164 // IP->FILE-HASH/LINE
6165 // ( ip -- len hash line TRUE / FALSE )
6166 UFWORD(IP2FILEHASHLINE
) {
6167 const uint32_t ip
= ufoPop();
6168 uint32_t fline
, fhash
, flen
;
6169 const char *fname
= ufoFindFileForIP(ip
, &fline
, &flen
, &fhash
);
6170 if (fname
!= NULL
) {
6181 // ////////////////////////////////////////////////////////////////////////// //
6182 // string operations
6185 UFO_FORCE_INLINE
uint32_t ufoHashBuf (uint32_t addr
, uint32_t size
, uint8_t orbyte
) {
6186 uint32_t hash
= 0x29a;
6187 if ((size
& ((uint32_t)1<<31)) == 0) {
6189 hash
+= ufoImgGetU8(addr
) | orbyte
;
6192 addr
+= 1u; size
-= 1u;
6202 //==========================================================================
6206 //==========================================================================
6207 UFO_FORCE_INLINE
int ufoBufEqu (uint32_t addr0
, uint32_t addr1
, uint32_t count
) {
6209 if ((count
& ((uint32_t)1<<31)) == 0) {
6211 while (res
!= 0 && count
!= 0) {
6212 res
= (toUpperU8(ufoImgGetU8(addr0
)) == toUpperU8(ufoImgGetU8(addr1
)));
6213 addr0
+= 1u; addr1
+= 1u; count
-= 1u;
6222 // ( a0 c0 a1 c1 -- bool )
6224 int32_t c1
= (int32_t)ufoPop();
6225 uint32_t a1
= ufoPop();
6226 int32_t c0
= (int32_t)ufoPop();
6227 uint32_t a0
= ufoPop();
6232 while (res
!= 0 && c0
!= 0) {
6233 res
= (ufoImgGetU8(a0
) == ufoImgGetU8(a1
));
6234 a0
+= 1; a1
+= 1; c0
-= 1;
6243 // ( a0 c0 a1 c1 -- bool )
6245 int32_t c1
= (int32_t)ufoPop();
6246 uint32_t a1
= ufoPop();
6247 int32_t c0
= (int32_t)ufoPop();
6248 uint32_t a0
= ufoPop();
6253 while (res
!= 0 && c0
!= 0) {
6254 res
= (toUpperU8(ufoImgGetU8(a0
)) == toUpperU8(ufoImgGetU8(a1
)));
6255 a0
+= 1; a1
+= 1; c0
-= 1;
6263 // search the string specified by c-addr1 u1 for the string specified by c-addr2 u2.
6264 // if flag is true, a match was found at c-addr3 with u3 characters remaining.
6265 // if flag is false there was no match and c-addr3 is c-addr1 and u3 is u1.
6266 // ( c-addr1 u1 c-addr2 u2 -- c-addr3 u3 flag )
6268 const uint32_t pcount
= ufoPop();
6269 const uint32_t paddr
= ufoPop();
6270 const uint32_t tcount
= ufoPop();
6271 const uint32_t taddr
= ufoPop();
6272 if ((pcount
& ((uint32_t)1 << 31)) == 0 && (tcount
& ((uint32_t)1 << 31)) == 0) {
6273 for (uint32_t f
= 0; tcount
- f
>= pcount
; f
+= 1) {
6274 if (ufoBufEqu(taddr
+ f
, paddr
, pcount
)) {
6276 ufoPush(tcount
- f
);
6288 // ( addr count -- hash )
6290 uint32_t count
= ufoPop();
6291 uint32_t addr
= ufoPop();
6292 ufoPush(ufoHashBuf(addr
, count
, 0));
6296 // ( addr count -- hash )
6298 uint32_t count
= ufoPop();
6299 uint32_t addr
= ufoPop();
6300 ufoPush(ufoHashBuf(addr
, count
, 0x20));
6303 // STRING:CHAR-UPPER
6305 UFWORD(CHAR_UPPER
) {
6307 uint32_t c
= UFO_TOS
& 0xffU
;
6308 if (c
>= 'a' && c
<= 'z') c
= c
- 'a' + 'A';
6312 // STRING:CHAR-LOWER
6314 UFWORD(CHAR_LOWER
) {
6316 uint32_t c
= UFO_TOS
& 0xffU
;
6317 if (c
>= 'A' && c
<= 'Z') c
= c
- 'A' + 'a';
6322 // ( addr count -- )
6324 int32_t count
= (int32_t)ufoPop();
6325 uint32_t addr
= ufoPop();
6327 uint32_t c
= ufoImgGetU8(addr
);
6328 if (c
>= 'a' && c
<= 'z') {
6330 ufoImgPutU8(addr
, c
);
6332 addr
+= 1u; count
-= 1;
6337 // ( addr count -- )
6339 int32_t count
= (int32_t)ufoPop();
6340 uint32_t addr
= ufoPop();
6342 uint32_t c
= ufoImgGetU8(addr
);
6343 if (c
>= 'A' && c
<= 'Z') {
6345 ufoImgPutU8(addr
, c
);
6347 addr
+= 1u; count
-= 1;
6351 // STRING:(CHAR-DIGIT)
6352 // ( ch -- digit true // false )
6353 UFWORD(CHAR_DIGIT
) {
6355 const uint32_t c
= UFO_TOS
;
6356 if (c
>= '0' && c
<= '9') { UFO_TOS
= c
- '0'; ufoPushBool(1); }
6357 else if (c
>= 'A' && c
<= 'Z') { UFO_TOS
= c
- 'A' + 10; ufoPushBool(1); }
6358 else if (c
>= 'a' && c
<= 'z') { UFO_TOS
= c
- 'a' + 10; ufoPushBool(1); }
6363 // ( char base -- digit TRUE / FALSE )
6365 const uint32_t base
= ufoPop();
6367 if (base
> 0 && base
< 0x80000000u
) {
6368 uint32_t c
= UFO_TOS
;
6369 if (c
>= '0' && c
<= '9') c
= c
- '0';
6370 else if (c
>= 'A' && c
<= 'Z') c
= c
- 'A' + 10;
6371 else if (c
>= 'a' && c
<= 'z') c
= c
- 'a' + 10;
6372 else { UFO_TOS
= 0; return; }
6373 if (c
< base
) { UFO_TOS
= c
; ufoPushBool(1); } else UFO_TOS
= 0;
6380 // ( char base -- TRUE / FALSE )
6382 const uint32_t base
= ufoPop();
6384 if (base
> 0 && base
< 0x80000000u
) {
6385 uint32_t c
= UFO_TOS
;
6386 if (c
>= '0' && c
<= '9') c
= c
- '0';
6387 else if (c
>= 'A' && c
<= 'Z') c
= c
- 'A' + 10;
6388 else if (c
>= 'a' && c
<= 'z') c
= c
- 'a' + 10;
6389 else { UFO_TOS
= 0; return; }
6390 if (c
< base
) UFO_TOS
= ufoTrueValue
; else UFO_TOS
= 0;
6398 // ( addr1 addr2 size -- -1|0|1 )
6400 uint32_t count
= ufoPop();
6401 uint32_t addr1
= ufoPop();
6402 uint32_t addr0
= ufoPop();
6403 if ((count
& 0x80000000u
) == 0) {
6404 while (count
!= 0) {
6405 const int n
= (int)ufoImgGetU8(addr0
) - (int)ufoImgGetU8(addr1
);
6407 if (n
< 0) ufoPush(~(uint32_t)0); else ufoPush(1);
6410 addr0
+= 1u; addr1
+= 1u; count
-= 1u;
6414 ufoFatal("invalid MEMCMP counter");
6419 // ( addr1 addr2 size -- -1|0|1 )
6421 uint32_t count
= ufoPop();
6422 uint32_t addr1
= ufoPop();
6423 uint32_t addr0
= ufoPop();
6424 if ((count
& 0x80000000u
) == 0) {
6425 while (count
!= 0) {
6426 const int c0
= (int)toUpperU8(ufoImgGetU8(addr0
));
6427 const int c1
= (int)toUpperU8(ufoImgGetU8(addr1
));
6428 const int n
= c0
- c1
;
6430 if (n
< 0) ufoPush(~(uint32_t)0); else ufoPush(1);
6433 addr0
+= 1u; addr1
+= 1u; count
-= 1u;
6437 ufoFatal("invalid MEMCMP counter");
6442 // ( addr count u32 -- )
6443 UFWORD(FILL_CELLS
) {
6444 const uint32_t v
= ufoPop();
6445 uint32_t count
= ufoPop();
6446 uint32_t dest
= ufoPop();
6447 if ((count
& 0x80000000u
) == 0) {
6448 while (count
!= 0) {
6449 ufoImgPutU32(dest
, v
);
6450 dest
+= 4u; count
-= 1u;
6456 // ( addr count byte -- )
6458 const uint32_t v
= ufoPop() & 0xffU
;
6459 uint32_t count
= ufoPop();
6460 uint32_t dest
= ufoPop();
6461 if (count
!= 0 && (count
& 0x80000000u
) == 0) {
6462 while (count
!= 0 && (dest
& 3) != 0) {
6463 ufoImgPutU8(dest
, v
);
6464 dest
+= 1u; count
-= 1u;
6467 const uint32_t vv
= (v
<< 24) | (v
<< 16) | (v
<< 8) | v
;
6468 while (count
>= 4u) {
6469 ufoImgPutU32(dest
, vv
);
6470 dest
+= 4u; count
-= 4u;
6473 while (count
!= 0) {
6474 ufoImgPutU8(dest
, v
);
6475 dest
+= 1u; count
-= 1u;
6480 //==========================================================================
6484 //==========================================================================
6485 static void doCMoveFwd (uint32_t src
, uint32_t dest
, uint32_t count
) {
6487 if (count
!= 0 && (count
& 0x80000000u
) == 0 && src
!= dest
) {
6488 if ((src
& 3) == (dest
& 3)) {
6489 // we can align addresses
6490 while (count
!= 0 && (src
& 3) != 0) {
6491 v
= ufoImgGetU8(src
); ufoImgPutU8(dest
, v
);
6492 src
+= 1u; dest
+= 1u; count
-= 1u;
6494 // ...and move by whole cells
6495 while (count
>= 4u) {
6496 v
= ufoImgGetU32(src
); ufoImgPutU32(dest
, v
);
6497 src
+= 4u; dest
+= 4u; count
-= 4u;
6501 while (count
!= 0) {
6502 v
= ufoImgGetU8(src
); ufoImgPutU8(dest
, v
);
6503 src
+= 1u; dest
+= 1u; count
-= 1u;
6508 //==========================================================================
6512 //==========================================================================
6513 static void doCMoveBwd (uint32_t src
, uint32_t dest
, uint32_t count
) {
6514 if (count
!= 0 && (count
& 0x80000000u
) == 0 && src
!= dest
) {
6515 src
+= count
; dest
+= count
;
6516 while (count
!= 0) {
6517 src
-= 1u; dest
-= 1u; count
-= 1u;
6518 const uint8_t v
= ufoImgGetU8(src
); ufoImgPutU8(dest
, v
);
6524 // ( source dest count -- )
6525 UFWORD(CMOVE_CELLS_FWD
) {
6526 uint32_t count
= ufoPop();
6527 uint32_t dest
= ufoPop();
6528 uint32_t src
= ufoPop();
6529 if (count
!= 0 && (count
& 0x80000000u
) == 0 && src
!= dest
) {
6530 if (count
* 4u >= 0x80000000u
) ufoFatal("invalid CMOVE-CELLS counter");
6531 doCMoveFwd(src
, dest
, count
* 4u);
6536 // ( source dest count -- )
6537 UFWORD(CMOVE_CELLS_BWD
) {
6538 uint32_t count
= ufoPop();
6539 uint32_t dest
= ufoPop();
6540 uint32_t src
= ufoPop();
6541 if ((count
& 0x80000000u
) == 0) {
6542 src
+= count
* 4u; dest
+= count
* 4u;
6543 while (count
!= 0) {
6544 src
-= 4u; dest
-= 4u; count
-= 1u;
6545 const uint32_t v
= ufoImgGetU32(src
); ufoImgPutU32(dest
, v
);
6551 // ( source dest count -- )
6553 uint32_t count
= ufoPop();
6554 uint32_t dest
= ufoPop();
6555 uint32_t src
= ufoPop();
6556 doCMoveFwd(src
, dest
, count
);
6560 // ( source dest count -- )
6562 uint32_t count
= ufoPop();
6563 uint32_t dest
= ufoPop();
6564 uint32_t src
= ufoPop();
6565 doCMoveBwd(src
, dest
, count
);
6569 // ( source dest count -- )
6571 uint32_t count
= ufoPop();
6572 uint32_t dest
= ufoPop();
6573 uint32_t src
= ufoPop();
6574 if (count
!= 0 && (count
& 0x80000000u
) == 0 && src
!= dest
) {
6575 if (src
+ count
<= src
|| dest
+ count
<= dest
) ufoFatal("invalid MOVE");
6576 if (src
<= dest
&& src
+ count
> dest
) doCMoveBwd(src
, dest
, count
);
6577 else doCMoveFwd(src
, dest
, count
);
6582 // ////////////////////////////////////////////////////////////////////////// //
6583 // heavily used in UrAsm
6590 const uint32_t c
= UFO_TOS
& 0xffU
;
6591 if (c
>= '0' && c
<= '9') UFO_TOS
= ufoTrueValue
; else UFO_TOS
= 0;
6596 UFWORD(IS_BIN_DIGIT
) {
6598 const uint32_t c
= UFO_TOS
& 0xffU
;
6599 if (c
>= '0' && c
<= '1') UFO_TOS
= ufoTrueValue
; else UFO_TOS
= 0;
6604 UFWORD(IS_OCT_DIGIT
) {
6606 const uint32_t c
= UFO_TOS
& 0xffU
;
6607 if (c
>= '0' && c
<= '7') UFO_TOS
= ufoTrueValue
; else UFO_TOS
= 0;
6612 UFWORD(IS_HEX_DIGIT
) {
6614 const uint32_t c
= UFO_TOS
& 0xffU
;
6615 if ((c
>= '0' && c
<= '9') ||
6616 (c
>= 'A' && c
<= 'F') ||
6617 (c
>= 'a' && c
<= 'f')) UFO_TOS
= ufoTrueValue
; else UFO_TOS
= 0;
6624 const uint32_t c
= UFO_TOS
& 0xffU
;
6625 if ((c
>= 'A' && c
<= 'Z') ||
6626 (c
>= 'a' && c
<= 'z')) UFO_TOS
= ufoTrueValue
; else UFO_TOS
= 0;
6631 UFWORD(IS_UNDER_DOT
) {
6633 const uint32_t c
= UFO_TOS
& 0xffU
;
6634 if (c
== '_' || c
== '.') UFO_TOS
= ufoTrueValue
; else UFO_TOS
= 0;
6641 const uint32_t c
= UFO_TOS
& 0xffU
;
6642 if ((c
>= 'A' && c
<= 'Z') ||
6643 (c
>= 'a' && c
<= 'z') ||
6644 (c
>= '0' && c
<= '9')) UFO_TOS
= ufoTrueValue
; else UFO_TOS
= 0;
6649 UFWORD(IS_ID_START
) {
6651 const uint32_t c
= UFO_TOS
& 0xffU
;
6652 if ((c
>= 'A' && c
<= 'Z') ||
6653 (c
>= 'a' && c
<= 'z') ||
6654 c
== '_' || c
== '.') UFO_TOS
= ufoTrueValue
; else UFO_TOS
= 0;
6659 UFWORD(IS_ID_CHAR
) {
6661 const uint32_t c
= UFO_TOS
& 0xffU
;
6662 if ((c
>= 'A' && c
<= 'Z') ||
6663 (c
>= 'a' && c
<= 'z') ||
6664 (c
>= '0' && c
<= '9') ||
6665 c
== '_' || c
== '.') UFO_TOS
= ufoTrueValue
; else UFO_TOS
= 0;
6669 // ////////////////////////////////////////////////////////////////////////// //
6670 // conditional defines
6673 typedef struct UForthCondDefine_t UForthCondDefine
;
6674 struct UForthCondDefine_t
{
6678 UForthCondDefine
*next
;
6681 static UForthCondDefine
*ufoCondDefines
= NULL
;
6682 static char ufoErrMsgBuf
[4096];
6685 //==========================================================================
6689 //==========================================================================
6690 UFO_DISABLE_INLINE
int ufoStrEquCI (const void *str0
, const void *str1
) {
6691 const unsigned char *s0
= (const unsigned char *)str0
;
6692 const unsigned char *s1
= (const unsigned char *)str1
;
6693 while (*s0
&& *s1
) {
6694 if (toUpperU8(*s0
) != toUpperU8(*s1
)) return 0;
6697 return (*s0
== 0 && *s1
== 0);
6701 //==========================================================================
6705 //==========================================================================
6706 UFO_FORCE_INLINE
int ufoBufEquCI (uint32_t addr
, uint32_t count
, const void *buf
) {
6708 if ((count
& ((uint32_t)1<<31)) == 0) {
6709 const unsigned char *src
= (const unsigned char *)buf
;
6711 while (res
!= 0 && count
!= 0) {
6712 res
= (toUpperU8(*src
) == toUpperU8(ufoImgGetU8(addr
)));
6713 src
+= 1; addr
+= 1u; count
-= 1u;
6722 //==========================================================================
6724 // ufoClearCondDefines
6726 //==========================================================================
6727 static void ufoClearCondDefines (void) {
6728 while (ufoCondDefines
) {
6729 UForthCondDefine
*df
= ufoCondDefines
;
6730 ufoCondDefines
= df
->next
;
6731 if (df
->name
) free(df
->name
);
6737 //==========================================================================
6741 //==========================================================================
6742 int ufoHasCondDefine (const char *name
) {
6744 if (name
!= NULL
&& name
[0] != 0) {
6745 const size_t nlen
= strlen(name
);
6747 const uint32_t hash
= joaatHashBufCI(name
, nlen
);
6748 UForthCondDefine
*dd
= ufoCondDefines
;
6749 while (res
== 0 && dd
!= NULL
) {
6750 if (dd
->hash
== hash
&& dd
->namelen
== (uint32_t)nlen
) {
6751 res
= ufoStrEquCI(name
, dd
->name
);
6761 //==========================================================================
6765 //==========================================================================
6766 void ufoCondDefine (const char *name
) {
6767 if (name
!= NULL
&& name
[0] != 0) {
6768 const size_t nlen
= strlen(name
);
6769 if (nlen
> 255) ufoFatal("conditional define name too long");
6770 const uint32_t hash
= joaatHashBufCI(name
, nlen
);
6771 UForthCondDefine
*dd
= ufoCondDefines
;
6773 while (res
== 0 && dd
!= NULL
) {
6774 if (dd
->hash
== hash
&& dd
->namelen
== (uint32_t)nlen
) {
6775 res
= ufoStrEquCI(name
, dd
->name
);
6781 dd
= calloc(1, sizeof(UForthCondDefine
));
6782 if (dd
== NULL
) ufoFatal("out of memory for defines");
6783 dd
->name
= strdup(name
);
6784 if (dd
->name
== NULL
) { free(dd
); ufoFatal("out of memory for defines"); }
6785 dd
->namelen
= (uint32_t)nlen
;
6787 dd
->next
= ufoCondDefines
;
6788 ufoCondDefines
= dd
;
6794 //==========================================================================
6798 //==========================================================================
6799 void ufoCondUndef (const char *name
) {
6800 if (name
!= NULL
&& name
[0] != 0) {
6801 const size_t nlen
= strlen(name
);
6803 const uint32_t hash
= joaatHashBufCI(name
, nlen
);
6804 UForthCondDefine
*dd
= ufoCondDefines
;
6805 UForthCondDefine
*prev
= NULL
;
6806 while (dd
!= NULL
) {
6807 if (dd
->hash
== hash
&& dd
->namelen
== (uint32_t)nlen
) {
6808 if (ufoStrEquCI(name
, dd
->name
)) {
6809 if (prev
!= NULL
) prev
->next
= dd
->next
; else ufoCondDefines
= dd
->next
;
6815 if (dd
!= NULL
) { prev
= dd
; dd
= dd
->next
; }
6823 // ( addr count -- )
6824 UFWORD(PAR_DLR_DEFINE
) {
6825 uint32_t count
= ufoPop();
6826 uint32_t addr
= ufoPop();
6827 if (count
== 0) ufoFatal("empty define");
6828 if (count
>= UFO_MAX_WORD_LENGTH
) ufoFatal("define too long");
6829 const uint32_t hash
= ufoHashBuf(addr
, count
, 0x20);
6830 UForthCondDefine
*dd
;
6831 for (dd
= ufoCondDefines
; dd
!= NULL
; dd
= dd
->next
) {
6832 if (dd
->hash
== hash
&& dd
->namelen
== count
) {
6833 if (ufoBufEquCI(addr
, count
, dd
->name
)) return;
6837 dd
= calloc(1, sizeof(UForthCondDefine
));
6838 if (dd
== NULL
) ufoFatal("out of memory for defines");
6839 dd
->name
= calloc(1, count
+ 1u);
6840 if (dd
->name
== NULL
) { free(dd
); ufoFatal("out of memory for defines"); }
6841 for (uint32_t f
= 0; f
< count
; f
+= 1) {
6842 ((unsigned char *)dd
->name
)[f
] = ufoImgGetU8(addr
+ f
);
6844 dd
->namelen
= count
;
6846 dd
->next
= ufoCondDefines
;
6847 ufoCondDefines
= dd
;
6851 // ( addr count -- )
6852 UFWORD(PAR_DLR_UNDEF
) {
6853 uint32_t count
= ufoPop();
6854 uint32_t addr
= ufoPop();
6855 if (count
== 0) ufoFatal("empty define");
6856 if (count
>= UFO_MAX_WORD_LENGTH
) ufoFatal("define too long");
6857 const uint32_t hash
= ufoHashBuf(addr
, count
, 0x20);
6858 UForthCondDefine
*prev
= NULL
;
6859 UForthCondDefine
*dd
;
6860 for (dd
= ufoCondDefines
; dd
!= NULL
; prev
= dd
, dd
= dd
->next
) {
6861 if (dd
->hash
== hash
&& dd
->namelen
== count
) {
6862 if (ufoBufEquCI(addr
, count
, dd
->name
)) {
6863 if (prev
== NULL
) ufoCondDefines
= dd
->next
; else prev
->next
= dd
->next
;
6873 // ( addr count -- bool )
6874 UFWORD(PAR_DLR_DEFINEDQ
) {
6875 uint32_t count
= ufoPop();
6876 uint32_t addr
= ufoPop();
6877 if (count
== 0) ufoFatal("empty define");
6878 if (count
>= UFO_MAX_WORD_LENGTH
) ufoFatal("define too long");
6879 const uint32_t hash
= ufoHashBuf(addr
, count
, 0x20);
6881 UForthCondDefine
*dd
= ufoCondDefines
;
6882 while (!found
&& dd
!= NULL
) {
6883 if (dd
->hash
== hash
&& dd
->namelen
== count
) {
6884 found
= ufoBufEquCI(addr
, count
, dd
->name
);
6892 // ////////////////////////////////////////////////////////////////////////// //
6897 // ( addr count -- )
6899 uint32_t count
= ufoPop();
6900 uint32_t addr
= ufoPop();
6901 if (count
& (1u<<31)) ufoFatal("invalid error message");
6902 if (count
== 0) ufoFatal("some error");
6903 if (count
> (uint32_t)sizeof(ufoErrMsgBuf
) - 1u) count
= (uint32_t)sizeof(ufoErrMsgBuf
) - 1u;
6904 for (uint32_t f
= 0; f
< count
; f
+= 1) {
6905 ufoErrMsgBuf
[f
] = (char)ufoImgGetU8(addr
+ f
);
6907 ufoErrMsgBuf
[count
] = 0;
6908 ufoFatal("%s", ufoErrMsgBuf
);
6912 UFWORD(PAR_USER_ABORT
) {
6913 ufoFatal("user abort");
6917 // ( errflag addr count -- )
6928 // ( errflag addr count -- )
6931 if (UFO_S(2) == 0) {
6939 // ////////////////////////////////////////////////////////////////////////// //
6943 static char ufoFNameBuf
[4096];
6946 //==========================================================================
6948 // ufoScanIncludeFileName
6950 // `*psys` and `*psoft` must be initialised!
6952 //==========================================================================
6953 static void ufoScanIncludeFileName (uint32_t addr
, uint32_t count
, char *dest
, size_t destsz
,
6954 uint32_t *psys
, uint32_t *psoft
)
6958 ufo_assert(dest
!= NULL
);
6959 ufo_assert(destsz
> 0);
6961 while (count
!= 0) {
6962 ch
= ufoImgGetU8(addr
);
6964 //if (system) ufoFatal("invalid file name (duplicate system mark)");
6966 } else if (ch
== '?') {
6967 //if (softinclude) ufoFatal("invalid file name (duplicate soft mark)");
6973 addr
+= 1; count
-= 1;
6974 ch
= ufoImgGetU8(addr
);
6975 } while (ch
<= 32 && count
!= 0);
6978 if (count
== 0) ufoFatal("empty include file name");
6979 if (count
>= destsz
) ufoFatal("include file name too long");
6982 while (count
!= 0) {
6983 dest
[dpos
] = (char)ufoImgGetU8(addr
); dpos
+= 1;
6984 addr
+= 1; count
-= 1;
6990 // (INCLUDE-LINE-FOFS)
6992 UFWORD(PAR_INCLUDE_LINE_FOFS
) {
6993 ufoPush((uint32_t)(int32_t)ufoCurrIncludeLineFileOfs
);
6996 // (INCLUDE-LINE-SEEK)
6998 UFWORD(PAR_INCLUDE_LINE_SEEK
) {
6999 uint32_t fofs
= ufoPop();
7000 uint32_t lidx
= ufoPop();
7001 if (lidx
>= 0x0fffffffU
) lidx
= 0;
7002 if (ufoInFile
== NULL
) ufoFatal("cannot seek without opened include file");
7003 if (fseek(ufoInFile
, (long)fofs
, SEEK_SET
) != 0) {
7004 ufoFatal("error seeking in include file");
7006 ufoInFileLine
= lidx
;
7011 // return number of items in include stack
7012 UFWORD(PAR_INCLUDE_DEPTH
) {
7013 ufoPush(ufoFileStackPos
);
7016 // (INCLUDE-FILE-ID)
7017 // ( isp -- id ) -- isp 0 is current, then 1, etc.
7018 // each include file has unique non-zero id.
7019 UFWORD(PAR_INCLUDE_FILE_ID
) {
7020 const uint32_t isp
= ufoPop();
7023 } else if (isp
<= ufoFileStackPos
) {
7024 UFOFileStackEntry
*stk
= &ufoFileStack
[ufoFileStackPos
- isp
];
7027 ufoFatal("invalid include stack index");
7031 // (INCLUDE-FILE-LINE)
7033 UFWORD(PAR_INCLUDE_FILE_LINE
) {
7034 const uint32_t isp
= ufoPop();
7036 ufoPush(ufoInFileLine
);
7037 } else if (isp
<= ufoFileStackPos
) {
7038 UFOFileStackEntry
*stk
= &ufoFileStack
[ufoFileStackPos
- isp
];
7039 ufoPush(stk
->fline
);
7041 ufoFatal("invalid include stack index");
7045 // (INCLUDE-FILE-NAME)
7046 // ( isp -- addr count )
7047 // current file name; at PAD
7048 UFWORD(PAR_INCLUDE_FILE_NAME
) {
7049 const uint32_t isp
= ufoPop();
7050 const char *fname
= NULL
;
7052 fname
= ufoInFileName
;
7053 } else if (isp
<= ufoFileStackPos
) {
7054 UFOFileStackEntry
*stk
= &ufoFileStack
[ufoFileStackPos
- isp
];
7057 ufoFatal("invalid include stack index");
7059 uint32_t addr
= UFO_PAD_ADDR
+ 4u;
7061 if (fname
!= NULL
) {
7062 while (fname
[count
] != 0) {
7063 ufoImgPutU8(addr
+ count
, ((const unsigned char *)fname
)[count
]);
7067 ufoImgPutU32(addr
- 4u, count
);
7068 ufoImgPutU8(addr
+ count
, 0);
7074 // (INCLUDE-BUILD-NAME)
7075 // ( addr count soft? system? -- addr count )
7077 UFWORD(PAR_INCLUDE_BUILD_NAME
) {
7078 uint32_t system
= ufoPop();
7079 uint32_t softinclude
= ufoPop();
7080 uint32_t count
= ufoPop();
7081 uint32_t addr
= ufoPop();
7083 if ((count
& ((uint32_t)1<<31)) != 0) ufoFatal("invalid include name");
7085 ufoScanIncludeFileName(addr
, count
, ufoFNameBuf
, sizeof(ufoFNameBuf
),
7086 &system
, &softinclude
);
7088 char *ffn
= ufoCreateIncludeName(ufoFNameBuf
, system
, (system
? ufoLastSysIncPath
: ufoLastIncPath
));
7089 addr
= UFO_PAD_ADDR
+ 4u;
7091 while (ffn
[count
] != 0) {
7092 ufoImgPutU8(addr
+ count
, ((const unsigned char *)ffn
)[count
]);
7096 ufoImgPutU8(addr
+ count
, 0);
7097 ufoImgPutU32(addr
- 4u, count
);
7102 // (INCLUDE-NO-REFILL)
7103 // ( addr count soft? system? -- )
7104 UFWORD(PAR_INCLUDE_NO_REFILL
) {
7105 uint32_t system
= ufoPop();
7106 uint32_t softinclude
= ufoPop();
7107 uint32_t count
= ufoPop();
7108 uint32_t addr
= ufoPop();
7110 if (ufoMode
== UFO_MODE_MACRO
) ufoFatal("macros cannot include files");
7112 if ((count
& ((uint32_t)1<<31)) != 0) ufoFatal("invalid include name");
7114 ufoScanIncludeFileName(addr
, count
, ufoFNameBuf
, sizeof(ufoFNameBuf
),
7115 &system
, &softinclude
);
7117 char *ffn
= ufoCreateIncludeName(ufoFNameBuf
, system
, (system
? ufoLastSysIncPath
: ufoLastIncPath
));
7119 FILE *fl
= fopen(ffn
, "rb");
7121 FILE *fl
= fopen(ffn
, "r");
7124 if (softinclude
) { free(ffn
); return; }
7125 ufoFatal("include file '%s' not found", ffn
);
7127 #ifdef UFO_DEBUG_INCLUDE
7128 fprintf(stderr
, "INC-PUSH: new fname: %s\n", ffn
);
7133 ufoSetInFileNameReuse(ffn
);
7134 ufoFileId
= ufoLastUsedFileId
;
7135 setLastIncPath(ufoInFileName
, system
);
7140 UFWORD(PAR_INCLUDE_DROP
) {
7145 // ( addr count soft? system? -- )
7146 UFWORD(PAR_INCLUDE
) {
7147 UFCALL(PAR_INCLUDE_NO_REFILL
);
7148 // trigger next line loading
7150 if (!ufoPop()) ufoFatal("(INCLUDE) internal error");
7154 UFWORD(DLR_INCLUDE_IMM
) {
7155 int soft
= 0, system
= 0;
7156 // parse include filename
7157 ufoPushBool(0); UFCALL(PAR_PARSE_SKIP_COMMENTS
);
7158 uint8_t ch
= ufoTibPeekCh();
7160 ufoTibSkipCh(); // skip quote
7162 } else if (ch
== '<') {
7163 ufoTibSkipCh(); // skip quote
7167 ufoFatal("expected quoted string");
7170 if (!ufoPop()) ufoFatal("file name expected");
7171 ufoPushBool(0); UFCALL(PAR_PARSE_SKIP_COMMENTS
);
7172 if (ufoTibPeekCh() != 0) {
7173 ufoFatal("$INCLUDE doesn't accept extra args yet");
7175 // ( addr count soft? system? -- )
7176 ufoPushBool(soft
); ufoPushBool(system
); UFCALL(PAR_INCLUDE
);
7180 //==========================================================================
7182 // ufoCreateFileGuard
7184 //==========================================================================
7185 static const char *ufoCreateFileGuard (const char *fname
) {
7186 if (fname
== NULL
|| fname
[0] == 0) return NULL
;
7187 char *rp
= ufoRealPath(fname
);
7188 if (rp
== NULL
) return NULL
;
7190 for (char *s
= rp
; *s
; s
+= 1) if (*s
== '\\') *s
= '/';
7192 // hash the buffer; extract file name; create string with path len, file name, and hash
7193 const size_t orgplen
= strlen(rp
);
7194 const uint32_t phash
= joaatHashBuf(rp
, orgplen
, 0);
7195 size_t plen
= orgplen
;
7196 while (plen
!= 0 && rp
[plen
- 1u] != '/') plen
-= 1;
7197 snprintf(ufoRealPathHashBuf
, sizeof(ufoRealPathHashBuf
),
7198 "__INCLUDE_GUARD_%08X_%08X_%s__", phash
, (uint32_t)orgplen
, rp
+ plen
);
7199 return ufoRealPathHashBuf
;
7203 // $INCLUDE-ONCE "str"
7204 // includes file only once; unreliable on shitdoze, i believe
7205 UFWORD(DLR_INCLUDE_ONCE_IMM
) {
7206 uint32_t softinclude
= 0, system
= 0;
7207 // parse include filename
7208 ufoPushBool(0); UFCALL(PAR_PARSE_SKIP_COMMENTS
);
7209 uint8_t ch
= ufoTibPeekCh();
7211 ufoTibSkipCh(); // skip quote
7213 } else if (ch
== '<') {
7214 ufoTibSkipCh(); // skip quote
7218 ufoFatal("expected quoted string");
7221 if (!ufoPop()) ufoFatal("file name expected");
7222 const uint32_t count
= ufoPop();
7223 const uint32_t addr
= ufoPop();
7224 ufoPushBool(0); UFCALL(PAR_PARSE_SKIP_COMMENTS
);
7225 if (ufoTibPeekCh() != 0) {
7226 ufoFatal("$REQUIRE doesn't accept extra args yet");
7228 ufoScanIncludeFileName(addr
, count
, ufoRealPathHashBuf
, sizeof(ufoRealPathHashBuf
),
7229 &system
, &softinclude
);
7230 char *incfname
= ufoCreateIncludeName(ufoRealPathHashBuf
, system
, (system
? ufoLastSysIncPath
: ufoLastIncPath
));
7231 if (incfname
== NULL
) ufoFatal("cannot resolve include file '%s'", ufoRealPathHashBuf
);
7232 //fprintf(stderr, "?:%d;!:%d;%s|%s\n", softinclude, system, ufoRealPathHashBuf, incfname);
7233 // this will overwrite `ufoRealPathHashBuf`
7234 const char *guard
= ufoCreateFileGuard(incfname
);
7236 if (guard
== NULL
) {
7237 if (!softinclude
) ufoFatal("cannot include file '%s'", ufoRealPathHashBuf
);
7241 fprintf(stderr
, "GUARD: <%s>\n", guard
);
7243 // now check for the guard
7244 const uint32_t glen
= (uint32_t)strlen(guard
);
7245 const uint32_t ghash
= joaatHashBuf(guard
, glen
, 0);
7246 UForthCondDefine
*dd
;
7247 for (dd
= ufoCondDefines
; dd
!= NULL
; dd
= dd
->next
) {
7248 if (dd
->hash
== ghash
&& dd
->namelen
== glen
&& strcmp(guard
, dd
->name
) == 0) {
7249 // nothing to do: already included
7254 dd
= calloc(1, sizeof(UForthCondDefine
));
7255 if (dd
== NULL
) ufoFatal("out of memory for defines");
7256 dd
->name
= calloc(1, glen
+ 1u);
7257 if (dd
->name
== NULL
) { free(dd
); ufoFatal("out of memory for defines"); }
7258 strcpy(dd
->name
, guard
);
7261 dd
->next
= ufoCondDefines
;
7262 ufoCondDefines
= dd
;
7263 // ( addr count soft? system? -- )
7264 ufoPush(addr
); ufoPush(count
); ufoPushBool(softinclude
); ufoPushBool(system
);
7265 UFCALL(PAR_INCLUDE
);
7269 // ////////////////////////////////////////////////////////////////////////// //
7275 UFWORD(PAR_NEW_HANDLE
) {
7276 const uint32_t typeid = ufoPop();
7277 if (typeid == UFO_HANDLE_FREE
) ufoFatal("invalid handle typeid");
7278 UfoHandle
*hh
= ufoAllocHandle(typeid);
7279 ufoPush(hh
->ufoHandle
);
7284 UFWORD(PAR_FREE_HANDLE
) {
7285 const uint32_t hx
= ufoPop();
7287 if ((hx
& UFO_ADDR_HANDLE_BIT
) == 0) ufoFatal("trying to free something that is not a handle");
7288 UfoHandle
*hh
= ufoGetHandle(hx
);
7289 if (hh
== NULL
) ufoFatal("trying to free invalid handle");
7296 UFWORD(PAR_HANDLE_GET_TYPEID
) {
7297 const uint32_t hx
= ufoPop();
7298 if ((hx
& UFO_ADDR_HANDLE_BIT
) == 0) ufoFatal("not a handle");
7299 UfoHandle
*hh
= ufoGetHandle(hx
);
7300 if (hh
== NULL
) ufoFatal("invalid handle");
7301 ufoPush(hh
->typeid);
7306 UFWORD(PAR_HANDLE_SET_TYPEID
) {
7307 const uint32_t hx
= ufoPop();
7308 const uint32_t typeid = ufoPop();
7309 if ((hx
& UFO_ADDR_HANDLE_BIT
) == 0) ufoFatal("not a handle");
7310 if (typeid == UFO_HANDLE_FREE
) ufoFatal("invalid handle typeid");
7311 UfoHandle
*hh
= ufoGetHandle(hx
);
7312 if (hh
== NULL
) ufoFatal("invalid handle");
7313 hh
->typeid = typeid;
7318 UFWORD(PAR_HANDLE_GET_SIZE
) {
7319 const uint32_t hx
= ufoPop();
7321 if ((hx
& UFO_ADDR_HANDLE_BIT
) == 0) ufoFatal("not a handle");
7322 UfoHandle
*hh
= ufoGetHandle(hx
);
7323 if (hh
== NULL
) ufoFatal("invalid handle");
7332 UFWORD(PAR_HANDLE_SET_SIZE
) {
7333 const uint32_t hx
= ufoPop();
7334 const uint32_t size
= ufoPop();
7335 if (size
> 0x04000000) ufoFatal("invalid handle size");
7336 if ((hx
& UFO_ADDR_HANDLE_BIT
) == 0) ufoFatal("not a handle");
7337 UfoHandle
*hh
= ufoGetHandle(hx
);
7338 if (hh
== NULL
) ufoFatal("invalid handle");
7339 if (hh
->size
!= size
) {
7344 uint8_t *nx
= realloc(hh
->data
, size
* sizeof(hh
->data
[0]));
7345 if (nx
== NULL
) ufoFatal("out of memory for handle of size %u", size
);
7347 if (size
> hh
->size
) memset(hh
->data
, 0, size
- hh
->size
);
7350 if (hh
->used
> size
) hh
->used
= size
;
7356 UFWORD(PAR_HANDLE_GET_USED
) {
7357 const uint32_t hx
= ufoPop();
7359 if ((hx
& UFO_ADDR_HANDLE_BIT
) == 0) ufoFatal("not a handle");
7360 UfoHandle
*hh
= ufoGetHandle(hx
);
7361 if (hh
== NULL
) ufoFatal("invalid handle");
7370 UFWORD(PAR_HANDLE_SET_USED
) {
7371 const uint32_t hx
= ufoPop();
7372 const uint32_t used
= ufoPop();
7373 if (used
> 0x04000000) ufoFatal("invalid handle used");
7374 if ((hx
& UFO_ADDR_HANDLE_BIT
) == 0) ufoFatal("not a handle");
7375 UfoHandle
*hh
= ufoGetHandle(hx
);
7376 if (hh
== NULL
) ufoFatal("invalid handle");
7377 if (used
> hh
->size
) ufoFatal("handle used %u out of range (%u)", used
, hh
->size
);
7381 #define POP_PREPARE_HANDLE() \
7382 const uint32_t hx = ufoPop(); \
7383 uint32_t idx = ufoPop()
7387 // ( idx hx -- value )
7388 UFWORD(PAR_HANDLE_LOAD_BYTE
) {
7389 POP_PREPARE_HANDLE();
7390 ufoPush(ufoHandleLoadByte(hx
, idx
));
7394 // ( idx hx -- value )
7395 UFWORD(PAR_HANDLE_LOAD_WORD
) {
7396 POP_PREPARE_HANDLE();
7397 ufoPush(ufoHandleLoadWord(hx
, idx
));
7401 // ( idx hx -- value )
7402 UFWORD(PAR_HANDLE_LOAD_CELL
) {
7403 POP_PREPARE_HANDLE();
7404 ufoPush(ufoHandleLoadCell(hx
, idx
));
7408 // ( value idx hx -- value )
7409 UFWORD(PAR_HANDLE_STORE_BYTE
) {
7410 POP_PREPARE_HANDLE();
7411 const uint32_t value
= ufoPop();
7412 ufoHandleStoreByte(hx
, idx
, value
);
7416 // ( value idx hx -- )
7417 UFWORD(PAR_HANDLE_STORE_WORD
) {
7418 POP_PREPARE_HANDLE();
7419 const uint32_t value
= ufoPop();
7420 ufoHandleStoreWord(hx
, idx
, value
);
7424 // ( value idx hx -- )
7425 UFWORD(PAR_HANDLE_STORE_CELL
) {
7426 POP_PREPARE_HANDLE();
7427 const uint32_t value
= ufoPop();
7428 ufoHandleStoreCell(hx
, idx
, value
);
7433 // ( addr count -- stx / FALSE )
7434 UFWORD(PAR_HANDLE_LOAD_FILE
) {
7435 uint32_t count
= ufoPop();
7436 uint32_t addr
= ufoPop();
7438 if ((count
& ((uint32_t)1<<31)) != 0) ufoFatal("invalid file name");
7440 uint8_t *dest
= (uint8_t *)ufoFNameBuf
;
7441 while (count
!= 0 && dest
< (uint8_t *)ufoFNameBuf
+ sizeof(ufoFNameBuf
)) {
7442 uint8_t ch
= ufoImgGetU8(addr
);
7444 dest
+= 1u; addr
+= 1u; count
-= 1u;
7446 if (dest
== (uint8_t *)ufoFNameBuf
+ sizeof(ufoFNameBuf
)) ufoFatal("file name too long");
7449 if (*ufoFNameBuf
== 0) ufoFatal("empty file name");
7451 char *ffn
= ufoCreateIncludeName(ufoFNameBuf
, 0/*system*/, ufoLastIncPath
);
7453 FILE *fl
= fopen(ffn
, "rb");
7455 FILE *fl
= fopen(ffn
, "r");
7463 if (fseek(fl
, 0, SEEK_END
) != 0) {
7465 ufoFatal("seek error in file '%s'", ffn
);
7468 long sz
= ftell(fl
);
7469 if (sz
< 0 || sz
>= 1024 * 1024 * 64) {
7471 ufoFatal("tell error in file '%s' (or too big)", ffn
);
7474 if (fseek(fl
, 0, SEEK_SET
) != 0) {
7476 ufoFatal("seek error in file '%s'", ffn
);
7479 UfoHandle
*hh
= ufoAllocHandle(0);
7481 hh
->data
= malloc((uint32_t)sz
);
7482 if (hh
->data
== NULL
) {
7484 ufoFatal("out of memory for file '%s'", ffn
);
7486 hh
->size
= (uint32_t)sz
;
7487 if (fread(hh
->data
, (uint32_t)sz
, 1, fl
) != 1) {
7489 ufoFatal("error reading file '%s'", ffn
);
7495 ufoPush(hh
->ufoHandle
);
7499 // ////////////////////////////////////////////////////////////////////////// //
7503 #ifdef UFO_MTASK_ALLOWED
7504 #define UFO_MTASK_POP_STATE() \
7505 UfoState *st = ufoFindState(ufoPop()); \
7506 if (st == NULL) ufoFatal("unknown state")
7508 #define UFO_MTASK_POP_STATE() \
7509 if (ufoPop() != 0) ufoFatal("no multitasking support compiled in"); \
7510 UfoState *st = &ufoCurrState
7513 // DEBUG:(DECOMPILE-CFA)
7515 UFWORD(DEBUG_DECOMPILE_CFA
) {
7516 const uint32_t cfa
= ufoPop();
7518 ufoDecompileWord(cfa
);
7521 // DEBUG:(DECOMPILE-MEM)
7522 // ( addr-start addr-end -- )
7523 UFWORD(DEBUG_DECOMPILE_MEM
) {
7524 const uint32_t end
= ufoPop();
7525 const uint32_t start
= ufoPop();
7527 ufoDecompilePart(start
, end
, 0);
7533 ufoPush((uint32_t)ufo_get_msecs());
7536 // this is called by INTERPRET when it is out of input stream
7537 UFWORD(UFO_INTERPRET_FINISHED_ACTION
) {
7538 longjmp(ufoStopVMJP
, 666);
7541 #ifdef UFO_MTASK_ALLOWED
7544 UFWORD(MT_NEW_STATE
) {
7545 UfoState
*st
= ufoNewState();
7546 const uint32_t cfa
= ufoPop();
7547 const uint32_t cfaidx
= ufoImgGetU32(cfa
);
7548 if (cfaidx
!= ufoDoForthCFA
) ufoFatal("state starting word should be in Forth");
7549 ufoInitStateUserVars(st
);
7550 st
->ip
= UFO_CFA_TO_PFA(cfa
);
7551 st
->rStack
[0] = 0xdeadf00d; // dummy value
7558 UFWORD(MT_FREE_STATE
) {
7559 UfoState
*st
= ufoFindState(ufoPop());
7560 if (st
== NULL
) ufoFatal("cannot free unknown state");
7561 if (st
== ufoCurrState
) ufoFatal("cannot free current state");
7566 // MTASK:STATE-NAME@
7567 // ( stid -- addr count )
7569 UFWORD(MT_GET_STATE_NAME
) {
7570 UFO_MTASK_POP_STATE();
7571 uint32_t addr
= UFO_PAD_ADDR
;
7573 while (st
->name
[count
] != 0) {
7574 ufoImgPutU8(addr
+ count
, ((const unsigned char *)st
->name
)[count
]);
7577 ufoImgPutU8(addr
+ count
, 0);
7582 // MTASK:STATE-NAME!
7583 // ( addr count stid -- )
7584 UFWORD(MT_SET_STATE_NAME
) {
7585 UFO_MTASK_POP_STATE();
7586 uint32_t count
= ufoPop();
7587 uint32_t addr
= ufoPop();
7588 if ((count
& ((uint32_t)1 << 31)) == 0) {
7589 if (count
> UFO_MAX_TASK_NAME
) ufoFatal("task name too long");
7590 for (uint32_t f
= 0; f
< count
; f
+= 1u) {
7591 ((unsigned char *)st
->name
)[f
] = ufoImgGetU8(addr
+ f
);
7593 st
->name
[count
] = 0;
7597 #ifdef UFO_MTASK_ALLOWED
7598 // MTASK:STATE-FIRST
7600 UFWORD(MT_STATE_FIRST
) {
7602 while (fidx
!= (uint32_t)(UFO_MAX_STATES
/32) && ufoStateUsedBitmap
[fidx
] == 0) fidx
+= 1u;
7603 // there should be at least one allocated state
7604 ufo_assert(fidx
!= (uint32_t)(UFO_MAX_STATES
/32));
7605 uint32_t bmp
= ufoStateUsedBitmap
[fidx
];
7607 while ((bmp
& 0x01) == 0) { fidx
+= 1u; bmp
>>= 1; }
7612 // ( stid -- stid / 0 )
7613 UFWORD(MT_STATE_NEXT
) {
7614 uint32_t stid
= ufoPop();
7615 if (stid
!= 0 && stid
< (uint32_t)(UFO_MAX_STATES
/32)) {
7616 // it is already incremented for us, yay!
7617 uint32_t fidx
= stid
/ 32u;
7618 uint8_t fofs
= stid
& 0x1f;
7619 while (fidx
< (uint32_t)(UFO_MAX_STATES
/32)) {
7620 const uint32_t bmp
= ufoStateUsedBitmap
[fidx
];
7622 while (fofs
!= 32u) {
7623 if ((bmp
& ((uint32_t)1 << (fofs
& 0x1f))) == 0) fofs
+= 1u;
7626 ufoPush(fidx
* 32u + fofs
+ 1u);
7630 fidx
+= 1u; fofs
= 0;
7637 // ( ... argc stid -- )
7638 UFWORD(MT_YIELD_TO
) {
7639 UfoState
*st
= ufoFindState(ufoPop());
7640 if (st
== NULL
) ufoFatal("cannot yield to unknown state");
7641 //if (st == ufoDebuggerState) ufoFatal("cannot yield to debugger"); // why not?
7642 const uint32_t argc
= ufoPop();
7643 if (argc
> 256) ufoFatal("too many YIELD-TO arguments");
7644 UfoState
*curst
= ufoCurrState
;
7645 if (st
!= ufoCurrState
) {
7646 for (uint32_t f
= 0; f
< argc
; f
+= 1) {
7647 ufoCurrState
= curst
;
7648 const uint32_t n
= ufoPop();
7652 ufoCurrState
= curst
; // we need to use API call to switch states
7654 ufoSwitchToState(st
); // always use API call for this!
7659 // MTASK:SET-SELF-AS-DEBUGGER
7661 UFWORD(MT_SET_SELF_AS_DEBUGGER
) {
7662 ufoDebuggerState
= ufoCurrState
;
7665 // DEBUG:SINGLE-STEP@
7667 UFWORD(DBG_GET_SS
) {
7668 ufoPush(ufoSingleStepAllowed
);
7674 // debugger task receives debugge stid on the data stack, and -1 as argc.
7675 // i.e. debugger stask is: ( -1 old-stid )
7676 UFWORD(MT_DEBUGGER_BP
) {
7677 #ifdef UFO_MTASK_ALLOWED
7678 if (ufoDebuggerState
!= NULL
&& ufoCurrState
!= ufoDebuggerState
&& ufoIsGoodTTY()) {
7679 UfoState
*st
= ufoCurrState
;
7680 ufoSwitchToState(ufoDebuggerState
); // always use API call for this!
7685 UFCALL(UFO_BACKTRACE
);
7688 UFCALL(UFO_BACKTRACE
);
7692 #ifdef UFO_MTASK_ALLOWED
7693 // MTASK:DEBUGGER-RESUME
7695 UFWORD(MT_RESUME_DEBUGEE
) {
7696 if (ufoCurrState
!= ufoDebuggerState
) ufoFatal("cannot resume from non-debugger");
7697 UfoState
*st
= ufoFindState(ufoPop());
7698 if (st
== NULL
) ufoFatal("cannot yield to unknown state");
7699 if (st
== ufoCurrState
) ufoFatal("cannot resume into debugger itself");
7700 ufoSwitchToState(st
); // always use API call for this!
7704 // MTASK:DEBUGGER-SINGLE-STEP
7706 UFWORD(MT_SINGLE_STEP_DEBUGEE
) {
7707 if (ufoCurrState
!= ufoDebuggerState
) ufoFatal("cannot resume from non-debugger");
7708 UfoState
*st
= ufoFindState(ufoPop());
7709 if (st
== NULL
) ufoFatal("cannot yield to unknown state");
7710 if (st
== ufoCurrState
) ufoFatal("cannot resume into debugger itself");
7711 ufoSwitchToState(st
); // always use API call for this!
7712 ufoSingleStep
= 2; // it will be decremented after returning from this word
7718 UFWORD(MT_STATE_IP_GET
) {
7719 UFO_MTASK_POP_STATE();
7725 UFWORD(MT_STATE_IP_SET
) {
7726 UFO_MTASK_POP_STATE();
7732 UFWORD(MT_STATE_REGA_GET
) {
7733 UFO_MTASK_POP_STATE();
7739 UFWORD(MT_STATE_REGA_SET
) {
7740 UFO_MTASK_POP_STATE();
7741 st
->regA
= ufoPop();
7744 // MTASK:STATE-USER@
7745 // ( addr stid -- value )
7746 UFWORD(MT_STATE_USER_GET
) {
7747 UFO_MTASK_POP_STATE();
7748 const uint32_t addr
= ufoPop();
7749 if ((addr
& UFO_ADDR_TEMP_BIT
) != 0 && (addr
& UFO_ADDR_TEMP_MASK
) + 3u < ufoSTImageTempSize(st
)) {
7750 uint32_t v
= *(const uint32_t *)((const uint8_t *)st
->imageTemp
+ (addr
& UFO_ADDR_TEMP_MASK
));
7753 ufoFatal("invalid user area address");
7757 // MTASK:STATE-USER!
7758 // ( value addr stid -- )
7759 UFWORD(MT_STATE_USER_SET
) {
7760 UFO_MTASK_POP_STATE();
7761 const uint32_t addr
= ufoPop();
7762 const uint32_t value
= ufoPop();
7763 if ((addr
& UFO_ADDR_TEMP_BIT
) != 0 && (addr
& UFO_ADDR_TEMP_MASK
) + 3u < ufoSTImageTempSize(st
)) {
7764 *(uint32_t *)((const uint8_t *)st
->imageTemp
+ (addr
& UFO_ADDR_TEMP_MASK
)) = value
;
7766 ufoFatal("invalid user area address");
7770 // MTASK:ACTIVE-STATE
7772 UFWORD(MT_ACTIVE_STATE
) {
7773 #ifdef UFO_MTASK_ALLOWED
7774 ufoPush(ufoCurrState
->id
);
7780 // MTASK:YIELDED-FROM
7782 UFWORD(MT_YIELDED_FROM
) {
7783 #ifdef UFO_MTASK_ALLOWED
7784 if (ufoYieldedState
!= NULL
) {
7785 ufoPush(ufoYieldedState
->id
);
7795 // ( stid -- depth )
7796 UFWORD(MT_DSTACK_DEPTH_GET
) {
7797 UFO_MTASK_POP_STATE();
7802 // ( stid -- depth )
7803 UFWORD(MT_RSTACK_DEPTH_GET
) {
7804 UFO_MTASK_POP_STATE();
7811 UFO_MTASK_POP_STATE();
7817 UFWORD(MT_LBP_GET
) {
7818 UFO_MTASK_POP_STATE();
7823 // ( depth stid -- )
7824 UFWORD(MT_DSTACK_DEPTH_SET
) {
7825 UFO_MTASK_POP_STATE();
7826 const uint32_t idx
= ufoPop();
7827 if (idx
>= UFO_DSTACK_SIZE
) ufoFatal("invalid stack index %u (%u)", idx
, UFO_DSTACK_SIZE
);
7832 // ( depth stid -- )
7833 UFWORD(MT_RSTACK_DEPTH_SET
) {
7834 UFO_MTASK_POP_STATE();
7835 const uint32_t idx
= ufoPop();
7836 const uint32_t left
= UFO_RSTACK_SIZE
;
7837 if (idx
>= left
) ufoFatal("invalid rstack index %u (%u)", idx
, left
);
7844 UFO_MTASK_POP_STATE();
7850 UFWORD(MT_LBP_SET
) {
7851 UFO_MTASK_POP_STATE();
7856 // ( idx stid -- value )
7857 UFWORD(MT_DSTACK_LOAD
) {
7858 UFO_MTASK_POP_STATE();
7859 const uint32_t idx
= ufoPop();
7860 if (idx
>= st
->SP
) ufoFatal("invalid stack index %u (%u)", idx
, st
->SP
);
7861 ufoPush(st
->dStack
[st
->SP
- idx
- 1u]);
7865 // ( idx stid -- value )
7866 UFWORD(MT_RSTACK_LOAD
) {
7867 UFO_MTASK_POP_STATE();
7868 const uint32_t idx
= ufoPop();
7869 if (idx
>= st
->RP
) ufoFatal("invalid stack index %u (%u)", idx
, st
->RP
);
7870 ufoPush(st
->dStack
[st
->RP
- idx
- 1u]);
7874 // ( idx stid -- value )
7875 UFWORD(MT_LSTACK_LOAD
) {
7876 UFO_MTASK_POP_STATE();
7877 const uint32_t idx
= ufoPop();
7878 if (idx
>= st
->LP
) ufoFatal("invalid lstack index %u (%u)", idx
, st
->LP
);
7879 ufoPush(st
->lStack
[st
->LP
- idx
- 1u]);
7883 // ( value idx stid -- )
7884 UFWORD(MT_DSTACK_STORE
) {
7885 UFO_MTASK_POP_STATE();
7886 const uint32_t idx
= ufoPop();
7887 const uint32_t value
= ufoPop();
7888 if (idx
>= st
->SP
) ufoFatal("invalid stack index %u (%u)", idx
, st
->SP
);
7889 st
->dStack
[st
->SP
- idx
- 1u] = value
;
7893 // ( value idx stid -- )
7894 UFWORD(MT_RSTACK_STORE
) {
7895 UFO_MTASK_POP_STATE();
7896 const uint32_t idx
= ufoPop();
7897 const uint32_t value
= ufoPop();
7898 if (idx
>= st
->RP
) ufoFatal("invalid stack index %u (%u)", idx
, st
->RP
);
7899 st
->dStack
[st
->RP
- idx
- 1u] = value
;
7903 // ( value idx stid -- )
7904 UFWORD(MT_LSTACK_STORE
) {
7905 UFO_MTASK_POP_STATE();
7906 const uint32_t idx
= ufoPop();
7907 const uint32_t value
= ufoPop();
7908 if (idx
>= st
->LP
) ufoFatal("invalid stack index %u (%u)", idx
, st
->LP
);
7909 st
->dStack
[st
->LP
- idx
- 1u] = value
;
7914 UFWORD(MT_VSP_GET
) {
7915 UFO_MTASK_POP_STATE();
7921 UFWORD(MT_VSP_SET
) {
7922 UFO_MTASK_POP_STATE();
7923 const uint32_t vsp
= ufoPop();
7924 if (vsp
> UFO_VOCSTACK_SIZE
) ufoFatal("VSP %u out of range (%u)", vsp
, UFO_VOCSTACK_SIZE
);
7928 // MTASK:STATE-VSP-AT@
7929 // ( idx stidf -- value )
7930 UFWORD(MT_VSP_LOAD
) {
7931 UFO_MTASK_POP_STATE();
7932 const uint32_t vsp
= ufoPop();
7933 if (vsp
>= UFO_VOCSTACK_SIZE
) ufoFatal("VSP %u out of range (%u)", vsp
, UFO_VOCSTACK_SIZE
);
7934 ufoPush(st
->vocStack
[vsp
]);
7937 // MTASK:STATE-VSP-AT!
7938 // ( value idx stid -- )
7939 UFWORD(MT_VSP_STORE
) {
7940 UFO_MTASK_POP_STATE();
7941 const uint32_t vsp
= ufoPop();
7942 const uint32_t value
= ufoPop();
7943 if (vsp
> UFO_VOCSTACK_SIZE
) ufoFatal("VSP %u out of range (%u)", vsp
, UFO_VOCSTACK_SIZE
);
7944 st
->vocStack
[vsp
] = value
;
7948 #include "urforth_tty.c"
7951 // ////////////////////////////////////////////////////////////////////////// //
7955 static unsigned char ufoFileIOBuffer
[4096];
7958 //==========================================================================
7962 //==========================================================================
7963 static char *ufoPopFileName (void) {
7964 uint32_t count
= ufoPop();
7965 uint32_t addr
= ufoPop();
7967 if ((count
& 0x80000000U
) != 0) ufoFatal("invalid file name");
7968 if (count
== 0) ufoFatal("empty file name");
7969 if (count
> (uint32_t)sizeof(ufoFNameBuf
) - 1u) ufoFatal("file name too long");
7971 unsigned char *dest
= (unsigned char *)ufoFNameBuf
;
7972 while (count
!= 0) {
7973 *dest
= ufoImgGetU8(addr
);
7974 dest
+= 1u; addr
+= 1u; count
-= 1u;
7983 UFWORD(FILES_ERRNO
) {
7984 ufoPush((uint32_t)errno
);
7988 // ( addr count -- success? )
7989 UFWORD(FILES_UNLINK
) {
7990 const char *fname
= ufoPopFileName();
7991 ufoPushBool(unlink(fname
) == 0);
7995 // ( addr count -- handle TRUE / FALSE )
7996 UFWORD(FILES_OPEN_RO
) {
7997 const char *fname
= ufoPopFileName();
7998 const int fd
= open(fname
, O_RDONLY
);
8000 ufoPush((uint32_t)fd
);
8008 // ( addr count -- handle TRUE / FALSE )
8009 UFWORD(FILES_OPEN_RW
) {
8010 const char *fname
= ufoPopFileName();
8011 const int fd
= open(fname
, O_RDWR
);
8013 ufoPush((uint32_t)fd
);
8021 // ( addr count -- handle TRUE / FALSE )
8022 UFWORD(FILES_CREATE
) {
8023 const char *fname
= ufoPopFileName();
8024 //FIXME: add variable with default flags
8025 const int fd
= open(fname
, O_RDWR
|O_CREAT
|O_TRUNC
, 0644);
8027 ufoPush((uint32_t)fd
);
8035 // ( handle -- success? )
8036 UFWORD(FILES_CLOSE
) {
8037 const int32_t fd
= (int32_t)ufoPop();
8038 if (fd
< 0) ufoFatal("invalid file handle in 'CLOSE'");
8039 ufoPushBool(close(fd
) == 0);
8043 // ( handle -- ofs TRUE / FALSE )
8044 // `handle` cannot be 0.
8045 UFWORD(FILES_TELL
) {
8046 const int32_t fd
= (int32_t)ufoPop();
8047 if (fd
< 0) ufoFatal("invalid file handle in 'TELL'");
8048 const off_t pos
= lseek(fd
, 0, SEEK_CUR
);
8049 if (pos
!= (off_t
)-1) {
8050 ufoPush((uint32_t)pos
);
8058 // ( ofs whence handle -- TRUE / FALSE )
8059 // `handle` cannot be 0.
8060 UFWORD(FILES_SEEK_EX
) {
8061 const int32_t fd
= (int32_t)ufoPop();
8062 const uint32_t whence
= ufoPop();
8063 const uint32_t ofs
= ufoPop();
8064 if (fd
< 0) ufoFatal("invalid file handle in 'SEEK-EX'");
8065 if (whence
!= (uint32_t)SEEK_SET
&&
8066 whence
!= (uint32_t)SEEK_CUR
&&
8067 whence
!= (uint32_t)SEEK_END
) ufoFatal("invalid `whence` in 'SEEK-EX'");
8068 const off_t pos
= lseek(fd
, (off_t
)ofs
, (int)whence
);
8069 ufoPushBool(pos
!= (off_t
)-1);
8073 // ( handle -- size TRUE / FALSE )
8074 // `handle` cannot be 0.
8075 UFWORD(FILES_SIZE
) {
8076 const int32_t fd
= (int32_t)ufoPop();
8077 if (fd
< 0) ufoFatal("invalid file handle in 'SIZE'");
8078 const off_t origpos
= lseek(fd
, 0, SEEK_CUR
);
8079 if (origpos
== (off_t
)-1) {
8082 const off_t size
= lseek(fd
, 0, SEEK_END
);
8083 if (size
== (off_t
)-1) {
8084 (void)lseek(origpos
, 0, SEEK_SET
);
8086 } else if (lseek(origpos
, 0, SEEK_SET
) == origpos
) {
8087 ufoPush((uint32_t)size
);
8096 // ( addr count handle -- rdsize TRUE / FALSE )
8097 // `handle` cannot be 0.
8098 UFWORD(FILES_READ
) {
8099 const int32_t fd
= (int32_t)ufoPop();
8100 if (fd
< 0) ufoFatal("invalid file handle in 'READ'");
8101 uint32_t count
= ufoPop();
8102 uint32_t addr
= ufoPop();
8105 if ((count
& 0x80000000U
) != 0) ufoFatal("invalid number of bytes to read from file");
8106 while (count
!= done
) {
8107 uint32_t rd
= (uint32_t)sizeof(ufoFileIOBuffer
);
8108 if (rd
> count
) rd
= count
;
8110 const ssize_t xres
= read(fd
, ufoFileIOBuffer
, rd
);
8111 if (xres
>= 0) { rd
= (uint32_t)xres
; break; }
8112 if (errno
== EINTR
) continue;
8113 if (errno
== EAGAIN
|| errno
== EWOULDBLOCK
) { rd
= 0; break; }
8120 for (uint32_t f
= 0; f
!= rd
; f
+= 1u) {
8121 ufoImgPutU8(addr
, ufoFileIOBuffer
[f
]);
8131 // ( addr count handle -- TRUE / FALSE )
8132 // `handle` cannot be 0.
8133 UFWORD(FILES_READ_EXACT
) {
8134 const int32_t fd
= (int32_t)ufoPop();
8135 if (fd
< 0) ufoFatal("invalid file handle in 'READ-EXACT'");
8136 uint32_t count
= ufoPop();
8137 uint32_t addr
= ufoPop();
8139 if ((count
& 0x80000000U
) != 0) ufoFatal("invalid number of bytes to read from file");
8140 while (count
!= 0) {
8141 uint32_t rd
= (uint32_t)sizeof(ufoFileIOBuffer
);
8142 if (rd
> count
) rd
= count
;
8144 const ssize_t xres
= read(fd
, ufoFileIOBuffer
, rd
);
8145 if (xres
>= 0) { rd
= (uint32_t)xres
; break; }
8146 if (errno
== EINTR
) continue;
8147 if (errno
== EAGAIN
|| errno
== EWOULDBLOCK
) { rd
= 0; break; }
8152 if (rd
== 0) { ufoPushBool(0); return; } // still error
8154 for (uint32_t f
= 0; f
!= rd
; f
+= 1u) {
8155 ufoImgPutU8(addr
, ufoFileIOBuffer
[f
]);
8164 // ( addr count handle -- TRUE / FALSE )
8165 // `handle` cannot be 0.
8166 UFWORD(FILES_WRITE
) {
8167 const int32_t fd
= (int32_t)ufoPop();
8168 if (fd
< 0) ufoFatal("invalid file handle in 'WRITE'");
8169 uint32_t count
= ufoPop();
8170 uint32_t addr
= ufoPop();
8172 if ((count
& 0x80000000U
) != 0) ufoFatal("invalid number of bytes to write to file");
8173 while (count
!= 0) {
8174 uint32_t wr
= (uint32_t)sizeof(ufoFileIOBuffer
);
8175 if (wr
> count
) wr
= count
;
8176 for (uint32_t f
= 0; f
!= wr
; f
+= 1u) {
8177 ufoFileIOBuffer
[f
] = ufoImgGetU8(addr
+ f
);
8180 const ssize_t xres
= write(fd
, ufoFileIOBuffer
, wr
);
8181 if (xres
>= 0) { wr
= (uint32_t)xres
; break; }
8182 if (errno
== EINTR
) continue;
8183 fprintf(stderr
, "ERRNO: %d (fd=%d)\n", errno
, fd
);
8184 //if (errno == EAGAIN || errno == EWOULDBLOCK) { wr = 0; break; }
8189 if (wr
== 0) { ufoPushBool(1); return; } // still error
8190 count
-= wr
; addr
+= wr
;
8197 // ////////////////////////////////////////////////////////////////////////// //
8201 #ifdef UFO_MTASK_ALLOWED
8202 //==========================================================================
8206 // create a new state, its execution will start from the given CFA.
8207 // state is not automatically activated.
8209 //==========================================================================
8210 static UfoState
*ufoNewState (void) {
8211 // find free state id
8213 uint32_t bmp
= ufoStateUsedBitmap
[0];
8214 while (fidx
!= (uint32_t)(UFO_MAX_STATES
/32) && bmp
== ~(uint32_t)0) {
8216 bmp
= ufoStateUsedBitmap
[fidx
];
8218 if (fidx
== (uint32_t)(UFO_MAX_STATES
/32)) ufoFatal("too many execution states");
8219 //fprintf(stderr, "NST:000: fidx=%u; bmp=0x%08x\n", fidx, bmp);
8221 while ((bmp
& 0x01) != 0) { fidx
+= 1u; bmp
>>= 1; }
8222 ufo_assert(fidx
< UFO_MAX_STATES
);
8223 ufo_assert((ufoStateUsedBitmap
[fidx
/ 32u] & ((uint32_t)1 << (fidx
& 0x1f))) == 0);
8224 ufo_assert(ufoStateMap
[fidx
] == NULL
);
8225 UfoState
*st
= calloc(1, sizeof(UfoState
));
8226 if (st
== NULL
) ufoFatal("out of memory for states");
8228 ufoStateMap
[fidx
] = st
;
8229 ufoStateUsedBitmap
[fidx
/ 32u] |= ((uint32_t)1 << (fidx
& 0x1f));
8230 //fprintf(stderr, "NST: fidx=%u; 0x%08x\n", fidx, ufoStateUsedBitmap[fidx / 32u]);
8235 //==========================================================================
8239 // free all memory used for the state, remove it from state list.
8240 // WARNING! never free current state!
8242 //==========================================================================
8243 static void ufoFreeState (UfoState
*st
) {
8245 if (st
== ufoCurrState
) ufoFatal("cannot free active state");
8246 if (ufoYieldedState
== st
) ufoYieldedState
= NULL
;
8247 if (ufoDebuggerState
== st
) ufoDebuggerState
= NULL
;
8248 const uint32_t fidx
= st
->id
- 1u;
8249 //fprintf(stderr, "FST: fidx=%u; 0x%08x\n", fidx, ufoStateUsedBitmap[fidx / 32u]);
8250 ufo_assert(fidx
< UFO_MAX_STATES
);
8251 ufo_assert((ufoStateUsedBitmap
[fidx
/ 32u] & (1u << (fidx
& 0x1f))) != 0);
8252 ufo_assert(ufoStateMap
[fidx
] == st
);
8253 // free default TIB handle
8254 UfoState
*oldst
= ufoCurrState
;
8256 const uint32_t tib
= ufoImgGetU32(ufoAddrDefTIB
);
8257 if ((tib
& UFO_ADDR_TEMP_BIT
) != 0) {
8258 UfoHandle
*tibh
= ufoGetHandle(tib
);
8259 if (tibh
!= NULL
) ufoFreeHandle(tibh
);
8261 ufoCurrState
= oldst
;
8263 #ifndef UFO_HUGE_IMAGES
8264 if (st
->imageTemp
!= NULL
) free(st
->imageTemp
);
8267 ufoStateMap
[fidx
] = NULL
;
8268 ufoStateUsedBitmap
[fidx
/ 32u] &= ~((uint32_t)1 << (fidx
& 0x1f));
8273 //==========================================================================
8277 //==========================================================================
8278 static UfoState
*ufoFindState (uint32_t stid
) {
8279 UfoState
*res
= NULL
;
8280 if (stid
>= 0 && stid
<= UFO_MAX_STATES
) {
8283 ufo_assert(ufoCurrState
!= NULL
);
8284 stid
= ufoCurrState
->id
- 1u;
8288 res
= ufoStateMap
[stid
];
8290 ufo_assert((ufoStateUsedBitmap
[stid
/ 32u] & (1u << (stid
& 0x1f))) != 0);
8291 ufo_assert(res
->id
== stid
+ 1u);
8293 ufo_assert((ufoStateUsedBitmap
[stid
/ 32u] & (1u << (stid
& 0x1f))) == 0);
8300 //==========================================================================
8304 //==========================================================================
8305 static void ufoSwitchToState (UfoState
*newst
) {
8306 ufo_assert(newst
!= NULL
);
8307 if (newst
!= ufoCurrState
) {
8308 ufoCurrState
= newst
;
8314 // ////////////////////////////////////////////////////////////////////////// //
8315 // initial dictionary definitions
8320 #define UFWORD(name_) do { \
8321 const uint32_t xcfa_ = ufoCFAsUsed; \
8322 ufo_assert(xcfa_ < UFO_MAX_NATIVE_CFAS); \
8323 ufoForthCFAs[xcfa_] = &ufoWord_##name_; \
8325 ufoDefineNative(""#name_, xcfa_, 0); \
8328 #define UFWORDX(strname_,name_) do { \
8329 const uint32_t xcfa_ = ufoCFAsUsed; \
8330 ufo_assert(xcfa_ < UFO_MAX_NATIVE_CFAS); \
8331 ufoForthCFAs[xcfa_] = &ufoWord_##name_; \
8333 ufoDefineNative(strname_, xcfa_, 0); \
8336 #define UFWORD_IMM(name_) do { \
8337 const uint32_t xcfa_ = ufoCFAsUsed; \
8338 ufo_assert(xcfa_ < UFO_MAX_NATIVE_CFAS); \
8339 ufoForthCFAs[xcfa_] = &ufoWord_##name_; \
8341 ufoDefineNative(""#name_, xcfa_, 1); \
8344 #define UFWORDX_IMM(strname_,name_) do { \
8345 const uint32_t xcfa_ = ufoCFAsUsed; \
8346 ufo_assert(xcfa_ < UFO_MAX_NATIVE_CFAS); \
8347 ufoForthCFAs[xcfa_] = &ufoWord_##name_; \
8349 ufoDefineNative(strname_, xcfa_, 1); \
8352 #define UFC(name_) ufoImgEmitU32_NoInline(ufoFindWordChecked(name_))
8355 //==========================================================================
8357 // ufoFindWordChecked
8359 //==========================================================================
8360 UFO_DISABLE_INLINE
uint32_t ufoFindWordChecked (const char *wname
) {
8361 const uint32_t cfa
= ufoFindWord(wname
);
8362 if (cfa
== 0) ufoFatal("word '%s' not found", wname
);
8367 //==========================================================================
8371 // get "FORTH" vocid
8373 //==========================================================================
8374 uint32_t ufoGetForthVocId (void) {
8375 return ufoForthVocId
;
8379 //==========================================================================
8381 // ufoVocSetOnlyDefs
8383 //==========================================================================
8384 void ufoVocSetOnlyDefs (uint32_t vocid
) {
8385 ufoImgPutU32(ufoAddrCurrent
, vocid
);
8386 ufoImgPutU32(ufoAddrContext
, vocid
);
8390 //==========================================================================
8394 // return voc PFA (vocid)
8396 //==========================================================================
8397 uint32_t ufoCreateVoc (const char *wname
, uint32_t parentvocid
, uint32_t flags
) {
8398 // create wordlist struct
8399 // typeid, used by Forth code (structs and such)
8400 ufoImgEmitU32(0); // typeid
8401 // vocid points here, to "LATEST-LFA"
8402 const uint32_t vocid
= UFO_GET_DP();
8403 //fprintf(stderr, "NEW VOCID (%s): 0x%08x\n", wname, vocid);
8404 ufoImgEmitU32(0); // latest
8405 const uint32_t vlink
= UFO_GET_DP();
8406 if ((vocid
& UFO_ADDR_TEMP_BIT
) == 0) {
8407 ufoImgEmitU32(ufoImgGetU32(ufoAddrVocLink
)); // voclink
8408 ufoImgPutU32(ufoAddrVocLink
, vlink
); // update voclink
8413 ufoImgEmitU32(parentvocid
); // parent
8414 const uint32_t hdraddr
= UFO_GET_DP();
8415 ufoImgEmitU32(0); // word header
8416 // create empty hash table
8417 for (int f
= 0; f
< UFO_HASHTABLE_SIZE
; f
+= 1) ufoImgEmitU32(0);
8418 // update CONTEXT and CURRENT if this is the first wordlist ever
8419 if (ufoImgGetU32(ufoAddrContext
) == 0) {
8420 ufoImgPutU32(ufoAddrContext
, vocid
);
8422 if (ufoImgGetU32(ufoAddrCurrent
) == 0) {
8423 ufoImgPutU32(ufoAddrCurrent
, vocid
);
8425 // create word header
8426 if (wname
!= NULL
&& wname
[0] != 0) {
8428 uint32_t flags = ufoImgGetU32(ufoAddrNewWordFlags);
8430 //UFW_FLAG_IMMEDIATE|
8432 //UFW_FLAG_NORETURN|
8438 flags |= UFW_FLAG_VOCAB;
8440 flags
&= 0xffffff00u
;
8441 flags
|= UFW_FLAG_VOCAB
;
8442 ufoCreateWordHeader(wname
, flags
);
8443 const uint32_t cfa
= UFO_GET_DP();
8444 ufoImgEmitCFA(ufoDoVocCFA
); // cfa
8445 ufoImgEmitU32(vocid
); // pfa
8446 // update vocab header pointer
8447 const uint32_t lfa
= UFO_CFA_TO_LFA(cfa
);
8448 ufoImgPutU32(hdraddr
, UFO_LFA_TO_NFA(lfa
));
8449 #ifdef UFO_DEBUG_DUMP_NEW_HEADERS
8450 ufoDumpWordHeader(lfa
);
8457 //==========================================================================
8461 //==========================================================================
8462 static void ufoSetLatestArgs (uint32_t warg
) {
8463 const uint32_t curr
= ufoImgGetU32(ufoAddrCurrent
);
8464 const uint32_t lfa
= ufoImgGetU32(curr
);
8465 const uint32_t nfa
= UFO_LFA_TO_NFA(lfa
);
8466 uint32_t flags
= ufoImgGetU32(nfa
);
8467 //fprintf(stderr, "OLD FLAGS: 0x%08x\n", flags);
8468 flags
&= ~UFW_WARG_MASK
;
8469 flags
|= warg
& UFW_WARG_MASK
;
8470 //fprintf(stderr, "NEW FLAGS: 0x%08x\n", flags);
8471 ufoImgPutU32(nfa
, flags
);
8472 #ifdef UFO_DEBUG_DUMP_NEW_HEADERS
8473 ufoDumpWordHeader(lfa
);
8478 //==========================================================================
8482 //==========================================================================
8483 static void ufoDefineNative (const char *wname
, uint32_t cfaidx
, int immed
) {
8484 cfaidx
|= UFO_ADDR_CFA_BIT
;
8485 uint32_t flags
= ufoImgGetU32(ufoAddrNewWordFlags
);
8487 //UFW_FLAG_IMMEDIATE|
8489 //UFW_FLAG_NORETURN|
8495 if (immed
) flags
|= UFW_FLAG_IMMEDIATE
;
8496 ufoCreateWordHeader(wname
, flags
);
8497 ufoImgEmitCFA(cfaidx
);
8501 //==========================================================================
8503 // ufoDefineConstant
8505 //==========================================================================
8506 static void ufoDefineConstant (const char *name
, uint32_t value
) {
8507 ufoDefineNative(name
, ufoDoConstCFA
, 0);
8508 ufoImgEmitU32(value
);
8512 //==========================================================================
8516 //==========================================================================
8517 static void ufoDefineUserVar (const char *name
, uint32_t addr
) {
8518 ufoDefineNative(name
, ufoDoUserVariableCFA
, 0);
8519 ufoImgEmitU32(addr
);
8523 //==========================================================================
8527 //==========================================================================
8528 static void ufoDefineVar (const char *name
, uint32_t value
) {
8529 ufoDefineNative(name
, ufoDoVariableCFA
, 0);
8530 ufoImgEmitU32(value
);
8534 //==========================================================================
8538 //==========================================================================
8539 static void ufoDefineDefer (const char *name
, uint32_t value
) {
8540 ufoDefineNative(name
, ufoDoDeferCFA
, 0);
8541 ufoImgEmitU32(value
);
8545 //==========================================================================
8549 //==========================================================================
8550 static void ufoHiddenWords (void) {
8551 const uint32_t flags
= ufoImgGetU32(ufoAddrNewWordFlags
);
8552 ufoImgPutU32(ufoAddrNewWordFlags
, flags
| UFW_FLAG_HIDDEN
);
8556 //==========================================================================
8560 //==========================================================================
8561 static void ufoPublicWords (void) {
8562 const uint32_t flags
= ufoImgGetU32(ufoAddrNewWordFlags
);
8563 ufoImgPutU32(ufoAddrNewWordFlags
, flags
& ~UFW_FLAG_HIDDEN
);
8567 //==========================================================================
8571 //==========================================================================
8573 static void ufoDefineForth (const char *name) {
8574 ufoDefineNative(name, ufoDoForthCFA, 0);
8579 //==========================================================================
8581 // ufoDefineForthImm
8583 //==========================================================================
8585 static void ufoDefineForthImm (const char *name) {
8586 ufoDefineNative(name, ufoDoForthCFA, 1);
8591 //==========================================================================
8593 // ufoDefineForthHidden
8595 //==========================================================================
8597 static void ufoDefineForthHidden (const char *name) {
8598 const uint32_t flags = ufoImgGetU32(ufoAddrNewWordFlags);
8599 ufoImgPutU32(ufoAddrNewWordFlags, flags | UFW_FLAG_HIDDEN);
8600 ufoDefineNative(name, ufoDoForthCFA, 0);
8601 ufoImgPutU32(ufoAddrNewWordFlags, flags);
8606 //==========================================================================
8608 // ufoDefineSColonForth
8610 // create word suitable for scattered colon extension
8612 //==========================================================================
8613 static void ufoDefineSColonForth (const char *name
) {
8614 ufoDefineNative(name
, ufoDoForthCFA
, 0);
8615 // placeholder for scattered colon
8616 // it will compile two branches:
8617 // the first branch will jump to the first "..:" word (or over the two branches)
8618 // the second branch is never taken, and works as a pointer to the latest branch addr in the list
8619 // this way, each extension word will simply fix the last branch address, and update list tail
8620 // at the creation time, second branch points to the first branch
8621 UFC("FORTH:(BRANCH)");
8622 const uint32_t xjmp
= UFO_GET_DP();
8624 UFC("FORTH:(BRANCH)");
8625 #ifdef UFO_RELATIVE_BRANCH
8626 ufoImgEmitU32(xjmp
- UFO_GET_DP()); // address of the fist branch dest
8627 ufoImgPutU32(xjmp
, UFO_GET_DP() - xjmp
); // jump over the jump
8629 ufoImgEmitU32(xjmp
);
8630 ufoImgPutU32(xjmp
, UFO_GET_DP());
8635 //==========================================================================
8639 //==========================================================================
8640 UFO_FORCE_INLINE
void ufoDoneForth (void) {
8641 UFC("FORTH:(EXIT)");
8645 //==========================================================================
8649 // compile string literal, the same as QUOTE_IMM
8651 //==========================================================================
8652 static void ufoCompileStrLitEx (const char *str
, const uint32_t slen
) {
8653 if (str
== NULL
) str
= "";
8654 if (slen
> 255) ufoFatal("string literal too long");
8655 UFC("FORTH:(LITSTR8)");
8656 ufoImgEmitU8((uint8_t)slen
);
8657 for (size_t f
= 0; f
< slen
; f
+= 1) {
8658 ufoImgEmitU8(((const unsigned char *)str
)[f
]);
8665 //==========================================================================
8669 //==========================================================================
8671 static void ufoCompileStrLit (const char *str) {
8672 ufoCompileStrLitEx(str, (uint32_t)strlen(str));
8677 //==========================================================================
8681 //==========================================================================
8682 static void ufoCompileLit (uint32_t value
) {
8684 ufoImgEmitU32(value
);
8688 //==========================================================================
8692 //==========================================================================
8694 static void ufoCompileCFALit (const char *wname) {
8695 UFC("FORTH:(LITCFA)");
8696 const uint32_t cfa = ufoFindWordChecked(wname);
8702 //==========================================================================
8706 //==========================================================================
8707 static int ufoXStrEquCI (const char *word
, const char *text
, uint32_t tlen
) {
8708 while (tlen
!= 0 && *word
) {
8709 if (toUpper(*word
) != toUpper(*text
)) return 0;
8710 word
+= 1u; text
+= 1u; tlen
-= 1u;
8712 return (tlen
== 0 && *word
== 0);
8716 #define UFO_MAX_LABEL_NAME (63)
8717 typedef struct UfoLabel_t
{
8720 char name
[UFO_MAX_LABEL_NAME
];
8721 uint32_t addr
; // jump chain tail, or address
8723 uint32_t word
; // is this a forward word definition?
8724 struct UfoLabel_t
*next
;
8727 static UfoLabel
*ufoLabels
= NULL
;
8730 //==========================================================================
8732 // ufoFindAddLabelEx
8734 //==========================================================================
8735 static UfoLabel
*ufoFindAddLabelEx (const char *name
, uint32_t namelen
, int allowAdd
) {
8736 if (namelen
== 0 || namelen
> UFO_MAX_LABEL_NAME
) ufoFatal("invalid label name");
8737 const uint32_t hash
= joaatHashBufCI(name
, namelen
);
8738 UfoLabel
*lbl
= ufoLabels
;
8739 while (lbl
!= NULL
) {
8740 if (lbl
->hash
== hash
&& lbl
->namelen
== namelen
) {
8743 while (ok
&& sidx
!= namelen
) {
8744 ok
= (toUpper(name
[sidx
]) == toUpper(lbl
->name
[sidx
]));
8753 lbl
= calloc(1, sizeof(UfoLabel
));
8755 lbl
->namelen
= namelen
;
8756 memcpy(lbl
->name
, name
, namelen
);
8757 lbl
->name
[namelen
] = 0;
8758 lbl
->next
= ufoLabels
;
8767 //==========================================================================
8771 //==========================================================================
8772 static UfoLabel
*ufoFindAddLabel (const char *name
, uint32_t namelen
) {
8773 return ufoFindAddLabelEx(name
, namelen
, 1);
8777 //==========================================================================
8781 //==========================================================================
8782 static UfoLabel
*ufoFindLabel (const char *name
, uint32_t namelen
) {
8783 return ufoFindAddLabelEx(name
, namelen
, 0);
8787 //==========================================================================
8789 // ufoTrySimpleNumber
8791 // only decimal and C-like hexes; with an optional sign
8793 //==========================================================================
8794 static int ufoTrySimpleNumber (const char *text
, uint32_t tlen
, uint32_t *num
) {
8797 if (tlen
!= 0 && *text
== '+') { text
+= 1u; tlen
-= 1u; }
8798 else if (tlen
!= 0 && *text
== '-') { neg
= 1; text
+= 1u; tlen
-= 1u; }
8800 int base
= 10; // default base
8801 if (tlen
> 2 && text
[0] == '0' && toUpper(text
[1]) == 'X') {
8804 text
+= 2u; tlen
-= 2u;
8807 if (tlen
== 0 || digitInBase(*text
, base
) < 0) return 0;
8814 if (!wasDigit
) return 0;
8817 dig
= digitInBase(*text
, base
);
8818 if (dig
< 0) return 0;
8820 n
= n
* (uint32_t)base
+ (uint32_t)dig
;
8822 text
+= 1u; tlen
-= 1u;
8825 if (!wasDigit
) return 0;
8826 if (neg
) n
= ~n
+ 1u;
8832 //==========================================================================
8834 // ufoEmitLabelChain
8836 //==========================================================================
8837 static void ufoEmitLabelChain (UfoLabel
*lbl
) {
8838 ufo_assert(lbl
!= NULL
);
8839 ufo_assert(lbl
->defined
== 0);
8840 const uint32_t here
= UFO_GET_DP();
8841 ufoImgEmitU32(lbl
->addr
);
8846 #ifdef UFO_RELATIVE_BRANCH
8847 #define UFO_XCOMPILER_BRANCH_SET(addr_,dest_) { \
8848 const uint32_t a = (addr_); \
8849 const uint32_t da = (dest_); \
8850 ufoImgPutU32(a, da - a); \
8853 #define UFO_XCOMPILER_BRANCH_SET(addr_,dest_) { \
8854 const uint32_t a = (addr_); \
8855 const uint32_t da = (dest_); \
8856 ufoImgPutU32(a, da); \
8861 //==========================================================================
8863 // ufoEmitLabelRefHere
8865 //==========================================================================
8866 UFO_FORCE_INLINE
void ufoEmitLabelRefHere (UfoLabel
*lbl
) {
8867 ufo_assert(lbl
!= NULL
);
8868 ufo_assert(lbl
->defined
!= 0);
8870 ufoImgEmitU32(lbl
->addr
);
8872 const uint32_t here
= UFO_GET_DP();
8874 UFO_XCOMPILER_BRANCH_SET(here
, lbl
->addr
);
8879 //==========================================================================
8881 // ufoFixLabelChainHere
8883 //==========================================================================
8884 static void ufoFixLabelChainHere (UfoLabel
*lbl
) {
8885 ufo_assert(lbl
!= NULL
);
8886 ufo_assert(lbl
->defined
== 0);
8887 const uint32_t here
= UFO_GET_DP();
8889 while (lbl
->addr
!= 0) {
8890 const uint32_t aprev
= ufoImgGetU32(lbl
->addr
);
8892 ufoImgPutU32(lbl
->addr
, here
);
8894 UFO_XCOMPILER_BRANCH_SET(lbl
->addr
, here
);
8902 #define UFO_MII_WORD_X_COMPILE (-5)
8903 #define UFO_MII_WORD_COMPILE_IMM (-4)
8904 #define UFO_MII_WORD_CFA_LIT (-3)
8905 #define UFO_MII_WORD_COMPILE (-2)
8906 #define UFO_MII_IN_WORD (-1)
8907 #define UFO_MII_NO_WORD (0)
8908 #define UFO_MII_WORD_NAME (1)
8909 #define UFO_MII_WORD_NAME_IMM (2)
8910 #define UFO_MII_WORD_NAME_HIDDEN (3)
8912 static int ufoMinInterpState
= UFO_MII_NO_WORD
;
8915 //==========================================================================
8917 // ufoFinalLabelCheck
8919 //==========================================================================
8920 static void ufoFinalLabelCheck (void) {
8922 if (ufoMinInterpState
!= UFO_MII_NO_WORD
) {
8923 ufoFatal("missing semicolon");
8925 while (ufoLabels
!= NULL
) {
8926 UfoLabel
*lbl
= ufoLabels
; ufoLabels
= lbl
->next
;
8927 if (!lbl
->defined
) {
8928 fprintf(stderr
, "UFO ERROR: label '%s' is not defined!\n", lbl
->name
);
8933 if (errorCount
!= 0) {
8934 ufoFatal("%d undefined label%s", errorCount
, (errorCount
!= 1 ? "s" : ""));
8939 //==========================================================================
8943 // this is so i could write Forth definitions more easily
8946 // $name -- reference
8947 // $name: -- definition
8949 //==========================================================================
8950 UFO_DISABLE_INLINE
void ufoInterpretLine (const char *line
) {
8951 char wname
[UFO_MAX_WORD_LENGTH
];
8952 uint32_t wlen
, num
, cfa
;
8955 if (*(const unsigned char *)line
<= 32) {
8957 } else if (ufoMinInterpState
== UFO_MII_WORD_CFA_LIT
||
8958 ufoMinInterpState
== UFO_MII_WORD_COMPILE
||
8959 ufoMinInterpState
== UFO_MII_WORD_COMPILE_IMM
||
8960 ufoMinInterpState
== UFO_MII_WORD_X_COMPILE
)
8962 // "[']"/"COMPILE"/"[COMPILE]" argument
8964 while (((const unsigned char *)line
)[wlen
] > 32) wlen
+= 1;
8965 if (wlen
>= UFO_MAX_WORD_LENGTH
) ufoFatal("word name too long");
8966 memcpy(wname
, line
, wlen
);
8968 switch (ufoMinInterpState
) {
8969 case UFO_MII_WORD_CFA_LIT
: UFC("FORTH:(LITCFA)"); break;
8970 case UFO_MII_WORD_COMPILE
: UFC("FORTH:(LITCFA)"); break;
8971 case UFO_MII_WORD_X_COMPILE
: UFC("FORTH:(LITCFA)"); break;
8972 case UFO_MII_WORD_COMPILE_IMM
: break;
8973 default: ufo_assert(0);
8975 cfa
= ufoFindWord(wname
);
8979 // forward reference
8980 lbl
= ufoFindAddLabel(line
, wlen
);
8981 if (lbl
->defined
|| (lbl
->word
== 0 && lbl
->addr
)) {
8982 ufoFatal("unknown word: '%s'", wname
);
8985 ufoEmitLabelChain(lbl
);
8987 switch (ufoMinInterpState
) {
8988 case UFO_MII_WORD_CFA_LIT
: break;
8989 case UFO_MII_WORD_COMPILE
: UFC("FORTH:COMPILE,"); break;
8990 case UFO_MII_WORD_X_COMPILE
: UFC("FORTH:,"); break;
8991 case UFO_MII_WORD_COMPILE_IMM
: break;
8992 default: ufo_assert(0);
8994 ufoMinInterpState
= UFO_MII_IN_WORD
;
8996 } else if (ufoMinInterpState
> UFO_MII_NO_WORD
) {
8999 while (((const unsigned char *)line
)[wlen
] > 32) wlen
+= 1;
9000 if (wlen
>= UFO_MAX_WORD_LENGTH
) ufoFatal("word name too long");
9001 if (wlen
> 2 && line
[0] == ':' && line
[wlen
- 1u] == ':') ufoFatal("invalid word name");
9002 memcpy(wname
, line
, wlen
);
9004 const uint32_t oldFlags
= ufoImgGetU32(ufoAddrNewWordFlags
);
9005 if (ufoMinInterpState
== UFO_MII_WORD_NAME_HIDDEN
) {
9006 ufoImgPutU32(ufoAddrNewWordFlags
, oldFlags
| UFW_FLAG_HIDDEN
);
9008 ufoDefineNative(wname
, ufoDoForthCFA
, (ufoMinInterpState
== UFO_MII_WORD_NAME_IMM
));
9009 ufoImgPutU32(ufoAddrNewWordFlags
, oldFlags
);
9010 ufoMinInterpState
= UFO_MII_IN_WORD
;
9011 // check for forward references
9012 lbl
= ufoFindLabel(line
, wlen
);
9014 if (lbl
->defined
|| !lbl
->word
) {
9015 ufoFatal("label/word conflict for '%.*s'", (unsigned)wlen
, line
);
9017 ufoFixLabelChainHere(lbl
);
9020 } else if ((line
[0] == ';' && line
[1] == ';') ||
9021 (line
[0] == '-' && line
[1] == '-') ||
9022 (line
[0] == '/' && line
[1] == '/') ||
9023 (line
[0] == '\\' && ((const unsigned char *)line
)[1] <= 32))
9025 ufoFatal("do not use single-line comments");
9026 } else if (line
[0] == '(' && ((const unsigned char *)line
)[1] <= 32) {
9027 while (*line
&& *line
!= ')') line
+= 1;
9028 if (*line
== ')') line
+= 1;
9032 while (((const unsigned char *)line
)[wlen
] > 32) wlen
+= 1;
9033 if (wlen
== 1 && (line
[0] == '"' || line
[0] == '`')) {
9035 const char qch
= line
[0];
9036 if (!line
[1]) ufoFatal("unterminated string literal");
9037 // skip quote and space
9038 if (((const unsigned char *)line
)[1] <= 32) line
+= 2u; else line
+= 1u;
9040 while (line
[wlen
] && line
[wlen
] != qch
) wlen
+= 1u;
9041 if (line
[wlen
] != qch
) ufoFatal("unterminated string literal");
9042 ufoCompileStrLitEx(line
, wlen
);
9043 line
+= wlen
+ 1u; // skip final quote
9044 } else if (wlen
== 1 && line
[0] == ':') {
9046 if (ufoMinInterpState
!= UFO_MII_NO_WORD
) ufoFatal("unexpected colon");
9047 ufoMinInterpState
= UFO_MII_WORD_NAME
;
9049 } else if (wlen
== 1 && line
[0] == ';') {
9051 if (ufoMinInterpState
!= UFO_MII_IN_WORD
) ufoFatal("unexpected semicolon");
9052 ufoImgEmitU32(ufoFindWordChecked("FORTH:(EXIT)"));
9053 ufoMinInterpState
= UFO_MII_NO_WORD
;
9055 } else if (wlen
== 2 && line
[0] == '!' && line
[1] == ':') {
9056 // new immediate word
9057 if (ufoMinInterpState
!= UFO_MII_NO_WORD
) ufoFatal("unexpected colon");
9058 ufoMinInterpState
= UFO_MII_WORD_NAME_IMM
;
9060 } else if (wlen
== 2 && line
[0] == '*' && line
[1] == ':') {
9062 if (ufoMinInterpState
!= UFO_MII_NO_WORD
) ufoFatal("unexpected colon");
9063 ufoMinInterpState
= UFO_MII_WORD_NAME_HIDDEN
;
9065 } else if (wlen
== 3 && memcmp(line
, "[']", 3) == 0) {
9067 if (ufoMinInterpState
!= UFO_MII_IN_WORD
) ufoFatal("unexpected immediate tick");
9068 ufoMinInterpState
= UFO_MII_WORD_CFA_LIT
;
9070 } else if (wlen
== 7 && ufoXStrEquCI("COMPILE", line
, wlen
)) {
9072 if (ufoMinInterpState
!= UFO_MII_IN_WORD
) ufoFatal("unexpected immediate tick");
9073 ufoMinInterpState
= UFO_MII_WORD_COMPILE
;
9075 } else if (wlen
== 9 && ufoXStrEquCI("X-COMPILE", line
, wlen
)) {
9077 if (ufoMinInterpState
!= UFO_MII_IN_WORD
) ufoFatal("unexpected immediate tick");
9078 ufoMinInterpState
= UFO_MII_WORD_X_COMPILE
;
9080 } else if (wlen
== 9 && ufoXStrEquCI("[COMPILE]", line
, wlen
)) {
9082 if (ufoMinInterpState
!= UFO_MII_IN_WORD
) ufoFatal("unexpected immediate tick");
9083 ufoMinInterpState
= UFO_MII_WORD_COMPILE_IMM
;
9087 if (wlen
>= UFO_MAX_WORD_LENGTH
) ufoFatal("word name too long");
9088 memcpy(wname
, line
, wlen
);
9090 cfa
= ufoFindWord(wname
);
9094 } else if (ufoTrySimpleNumber(line
, wlen
, &num
)) {
9095 // compile numeric literal
9098 // unknown word, this may be a forward reference, or a label definition
9099 // label defintion starts with "$"
9100 // (there are no words starting with "$" in the initial image)
9101 if (line
[0] == '$') {
9102 if (wlen
== 1) ufoFatal("dollar what?");
9103 if (wlen
> 2 && line
[wlen
- 1u] == ':') {
9105 lbl
= ufoFindAddLabel(line
, wlen
- 1u);
9106 if (lbl
->defined
) ufoFatal("double label '%s' definition", lbl
->name
);
9107 if (lbl
->word
) ufoFatal("double label '%s' word conflict", lbl
->name
);
9108 ufoFixLabelChainHere(lbl
);
9111 lbl
= ufoFindAddLabel(line
, wlen
);
9113 ufoEmitLabelRefHere(lbl
);
9115 ufoEmitLabelChain(lbl
);
9119 // forward reference
9120 lbl
= ufoFindAddLabel(line
, wlen
);
9121 if (lbl
->defined
|| (lbl
->word
== 0 && lbl
->addr
)) {
9122 ufoFatal("unknown word: '%s'", wname
);
9125 ufoEmitLabelChain(lbl
);
9135 //==========================================================================
9139 //==========================================================================
9140 UFO_DISABLE_INLINE
void ufoReset (void) {
9141 #ifdef UFO_MTASK_ALLOWED
9142 if (ufoCurrState
== NULL
) ufoFatal("no active execution state");
9145 ufoSP
= 0; ufoRP
= 0;
9146 ufoLP
= 0; ufoLBP
= 0;
9153 const uint32_t tib
= ufoImgGetU32(ufoAddrTIBx
);
9154 const uint32_t tibDef
= ufoImgGetU32(ufoAddrDefTIB
);
9155 #ifdef UFO_MTASK_ALLOWED
9156 ufoInitStateUserVars(ufoCurrState
);
9158 ufoInitStateUserVars(&ufoCurrState
);
9161 ufoImgPutU32(ufoAddrTIBx
, tib
);
9162 ufoImgPutU32(ufoAddrDefTIB
, tibDef
);
9163 ufoImgPutU32(ufoAddrRedefineWarning
, UFO_REDEF_WARN_NORMAL
);
9166 ufoImgPutU32(ufoAddrNewWordFlags
, 0);
9167 ufoVocSetOnlyDefs(ufoForthVocId
);
9171 //==========================================================================
9173 // ufoDefineEmitType
9175 //==========================================================================
9176 UFO_DISABLE_INLINE
void ufoDefineEmitType (void) {
9179 ufoInterpretLine(": EMIT ( ch -- ) (NORM-EMIT-CHAR) (EMIT) ;");
9183 ufoInterpretLine(": XEMIT ( ch -- ) (NORM-XEMIT-CHAR) (EMIT) ;");
9187 ufoInterpretLine(": CR ( -- ) NL (EMIT) ;");
9193 " LASTCR? FORTH:(TBRANCH) $endcr-exit CR "
9196 //ufoDecompileWord(ufoFindWordChecked("ENDCR"));
9200 ufoInterpretLine(": SPACE ( -- ) BL (EMIT) ;");
9205 ": SPACES ( count -- ) "
9207 " DUP 0> FORTH:(0BRANCH) $spaces-exit "
9209 " FORTH:(BRANCH) $spaces-again "
9215 // ( addr count -- )
9217 ": (TYPE) ( addr count -- ) "
9220 " DUP 0> FORTH:(0BRANCH) $par-type-exit "
9223 " FORTH:(BRANCH) $par-type-again "
9229 // ( addr count -- )
9231 ": TYPE ( addr count -- ) "
9234 " DUP 0> FORTH:(0BRANCH) $type-exit "
9237 " FORTH:(BRANCH) $type-again "
9243 // ( addr count -- )
9245 ": XTYPE ( addr count -- ) "
9248 " DUP 0> FORTH:(0BRANCH) $xtype-exit "
9251 " FORTH:(BRANCH) $xtype-again "
9257 // ( C:addr count -- ) ( E: -- addr count )
9259 ": STRLITERAL ( C:addr count -- ) ( E: -- addr count ) "
9260 " DUP 255 U> ` string literal too long` ?ERROR "
9261 " COMPILER:EXEC? FORTH:(TBRANCH) $strlit-exit "
9262 " HERE >R ( addr count | here ) "
9263 " ['] FORTH:(LITSTR8) COMPILE, "
9265 " ( compile length ) "
9267 " ( compile chars ) "
9269 " DUP 0<> FORTH:(0BRANCH) $strlit-loop-exit "
9271 " FORTH:(BRANCH) $strlit-loop "
9272 "$strlit-loop-exit: "
9274 " ( final 0: our counter is 0 here, so use it ) "
9276 " R> COMPILER:(AFTER-COMPILE-WORD) "
9281 // ( -- addr count )
9283 "!: \" ( -- addr count ) "
9284 " 34 PARSE ` string literal expected` ?NOT-ERROR "
9285 " COMPILER:(UNESCAPE) STRLITERAL "
9290 //==========================================================================
9292 // ufoDefineInterpret
9294 // define "INTERPRET" in Forth
9296 //==========================================================================
9297 UFO_DISABLE_INLINE
void ufoDefineInterpret (void) {
9298 UFWORDX("(UFO-INTERPRET-FINISHED-ACTION)", UFO_INTERPRET_FINISHED_ACTION
);
9300 // return "stop flag"
9302 "*: (UFO-INTERPRET-NEXT-LINE) ( -- continue? ) "
9303 " COMPILER:COMP? FORTH:(TBRANCH) $ipn_incomp "
9304 " ( interpreter allowed to cross include boundary ) "
9305 " REFILL FORTH:(BRANCH) $ipn_done "
9307 " ( compiler is not allowed to cross include boundary ) "
9308 " REFILL-NOCROSS ` compiler cannot cross file boundaries` ?NOT-ERROR "
9313 ufoInterpNextLineCFA
= ufoFindWordChecked("FORTH:(UFO-INTERPRET-NEXT-LINE)");
9314 ufoInterpretLine("*: (INTERPRET-NEXT-LINE) (USER-INTERPRET-NEXT-LINE) @ EXECUTE-TAIL ;");
9316 // skip comments, parse name, refilling lines if necessary
9317 // returning FALSE as counter means: "no addr, exit INTERPRET"
9319 "*: (INTERPRET-PARSE-NAME) ( -- addr count / FALSE ) "
9320 "$label_ipn_again: "
9321 " TRUE (PARSE-SKIP-COMMENTS) PARSE-NAME "
9322 " DUP FORTH:(TBRANCH) $label_ipn_exit_fwd "
9323 " 2DROP (INTERPRET-NEXT-LINE) "
9324 " FORTH:(TBRANCH) $label_ipn_again "
9326 "$label_ipn_exit_fwd: "
9328 //ufoDecompileWord(ufoFindWordChecked("(INTERPRET-PARSE-NAME)"));
9333 " FORTH:(INTERPRET-PARSE-NAME) ( addr count / FALSE )"
9334 " ?DUP FORTH:(0BRANCH) $interp-done "
9335 " ( try defered checker ) "
9336 " ( addr count FALSE -- addr count FALSE / TRUE ) "
9337 " FALSE (INTERPRET-CHECK-WORD) FORTH:(TBRANCH) $interp-again "
9338 " 2DUP FIND-WORD ( addr count cfa TRUE / addr count FALSE ) "
9339 " FORTH:(0BRANCH) $interp-try-number "
9341 " NROT 2DROP ( drop word string ) "
9342 " COMPILER:EXEC? FORTH:(TBRANCH) $interp-exec "
9343 " ( compiling; check immediate bit ) "
9344 " DUP CFA->NFA @ COMPILER:(WFLAG-IMMEDIATE) AND FORTH:(TBRANCH) $interp-exec "
9346 " FORTH:COMPILE, FORTH:(BRANCH) $interp-again "
9349 " EXECUTE FORTH:(BRANCH) $interp-again "
9350 " ( not a word, try a number ) "
9351 "$interp-try-number: "
9352 " 2DUP TRUE BASE @ (BASED-NUMBER) ( addr count allowsign? base -- num TRUE / FALSE ) "
9353 " FORTH:(0BRANCH) $interp-number-error "
9355 " NROT 2DROP ( drop word string ) "
9356 " LITERAL FORTH:(BRANCH) $interp-again "
9358 "$interp-number-error: "
9359 " ( addr count FALSE -- addr count FALSE / TRUE ) "
9360 " FALSE (INTERPRET-WORD-NOT-FOUND) FORTH:(TBRANCH) $interp-again "
9361 " (INTERPRET-WORD-NOT-FOUND-POST) "
9362 " ENDCR SPACE XTYPE ` -- wut?` TYPE CR "
9363 " ` unknown word` ERROR "
9366 //ufoDecompileWord(ufoFindWordChecked("INTERPRET"));
9370 //==========================================================================
9374 //==========================================================================
9375 UFO_DISABLE_INLINE
void ufoInitBaseDict (void) {
9376 uint32_t imgAddr
= 0;
9378 // reserve 32 bytes for nothing
9379 for (uint32_t f
= 0; f
< 32; f
+= 1) {
9380 ufoImgPutU8(imgAddr
, 0);
9384 while ((imgAddr
& 3) != 0) {
9385 ufoImgPutU8(imgAddr
, 0);
9390 ufoAddrDP
= imgAddr
;
9391 ufoImgPutU32(imgAddr
, 0); imgAddr
+= 4u;
9394 ufoAddrLastXFA
= imgAddr
;
9395 ufoImgPutU32(imgAddr
, 0); imgAddr
+= 4u;
9398 ufoAddrVocLink
= imgAddr
;
9399 ufoImgPutU32(imgAddr
, 0); imgAddr
+= 4u;
9402 ufoAddrNewWordFlags
= imgAddr
;
9403 ufoImgPutU32(imgAddr
, UFW_FLAG_PROTECTED
); imgAddr
+= 4u;
9405 // WORD-REDEFINE-WARN-MODE
9406 ufoAddrRedefineWarning
= imgAddr
;
9407 ufoImgPutU32(imgAddr
, UFO_REDEF_WARN_NORMAL
); imgAddr
+= 4u;
9409 // setup (DP) and (DP-TEMP)
9410 ufoImgPutU32(ufoAddrDP
, imgAddr
);
9411 ufoImgPutU32(ufoAddrDPTemp
, UFO_DPTEMP_BASE_ADDR
);
9412 ufoImgPutU32(ufoAddrHereDP
, ufoAddrDP
);
9415 fprintf(stderr
, "INITIAL HERE: 0x%08x (0x%08x)\n", imgAddr
, UFO_GET_DP());
9420 //==========================================================================
9422 // ufoInitStateUserVars
9424 //==========================================================================
9425 static void ufoInitStateUserVars (UfoState
*st
) {
9426 ufo_assert(st
!= NULL
);
9427 #ifndef UFO_HUGE_IMAGES
9428 if (st
->imageTempSize
< 8192u) {
9429 uint32_t *itmp
= realloc(st
->imageTemp
, 8192);
9430 if (itmp
== NULL
) ufoFatal("out of memory for state user area");
9431 st
->imageTemp
= itmp
;
9432 memset((uint8_t *)st
->imageTemp
+ st
->imageTempSize
, 0, 8192u - st
->imageTempSize
);
9433 st
->imageTempSize
= 8192;
9436 st
->imageTemp
[(ufoAddrBASE
& UFO_ADDR_TEMP_MASK
) / 4u] = 10;
9437 st
->imageTemp
[(ufoAddrSTATE
& UFO_ADDR_TEMP_MASK
) / 4u] = 0;
9438 st
->imageTemp
[(ufoAddrUserVarUsed
& UFO_ADDR_TEMP_MASK
) / 4u] = ufoAddrUserVarUsed
;
9439 st
->imageTemp
[(ufoAddrDefTIB
& UFO_ADDR_TEMP_MASK
) / 4u] = UFO_DEF_TIB_ADDR
;
9440 st
->imageTemp
[(ufoAddrTIBx
& UFO_ADDR_TEMP_MASK
) / 4u] = UFO_DEF_TIB_ADDR
;
9441 st
->imageTemp
[(ufoAddrINx
& UFO_ADDR_TEMP_MASK
) / 4u] = 0;
9442 st
->imageTemp
[(ufoAddrContext
& UFO_ADDR_TEMP_MASK
) / 4u] = ufoForthVocId
;
9443 st
->imageTemp
[(ufoAddrCurrent
& UFO_ADDR_TEMP_MASK
) / 4u] = ufoForthVocId
;
9444 st
->imageTemp
[(ufoAddrSelf
& UFO_ADDR_TEMP_MASK
) / 4u] = 0;
9445 st
->imageTemp
[(ufoAddrInterNextLine
& UFO_ADDR_TEMP_MASK
) / 4u] = ufoInterpNextLineCFA
;
9446 st
->imageTemp
[(ufoAddrEP
& UFO_ADDR_TEMP_MASK
) / 4u] = 0;
9447 st
->imageTemp
[(ufoAddrDPTemp
& UFO_ADDR_TEMP_MASK
) / 4u] = UFO_DPTEMP_BASE_ADDR
;
9448 st
->imageTemp
[(ufoAddrHereDP
& UFO_ADDR_TEMP_MASK
) / 4u] = ufoAddrDP
;
9450 // init other things, because this procedure is used in `ufoReset()` too
9451 st
->SP
= 0; st
->RP
= 0; st
->regA
= 0;
9452 st
->LP
= 0; st
->LBP
= 0;
9457 //==========================================================================
9459 // ufoInitBasicWords
9461 //==========================================================================
9462 UFO_DISABLE_INLINE
void ufoInitBasicWords (void) {
9463 ufoDefineConstant("FALSE", 0);
9464 ufoDefineConstant("TRUE", ufoTrueValue
);
9466 ufoDefineConstant("BL", 32);
9467 ufoDefineConstant("NL", 10);
9469 UFWORDX("NOOP", NOOP
);
9470 UFWORDX("(NOTIMPL)", PAR_NOTIMPL
);
9473 ufoDefineUserVar("BASE", ufoAddrBASE
);
9474 ufoDefineUserVar("TIB", ufoAddrTIBx
);
9475 ufoDefineUserVar(">IN", ufoAddrINx
);
9476 ufoDefineUserVar("(STD-TIB-ADDR)", ufoAddrDefTIB
);
9477 ufoDefineUserVar("(USER-VAR-USED)", ufoAddrUserVarUsed
);
9478 ufoDefineConstant("(USER-VAR-ADDR)", UFO_ADDR_TEMP_BIT
);
9479 ufoDefineConstant("(USER-VAR-SIZE)", UFO_USER_AREA_SIZE
);
9480 ufoDefineConstant("(USER-TIB)", UFO_DEF_TIB_ADDR
);
9481 ufoDefineConstant("(USER-TIB-SIZE)", UFO_ADDR_HANDLE_OFS_MASK
);
9483 ufoDefineUserVar("STATE", ufoAddrSTATE
);
9484 ufoDefineConstant("CONTEXT", ufoAddrContext
);
9485 ufoDefineConstant("CURRENT", ufoAddrCurrent
);
9486 ufoDefineConstant("(SELF)", ufoAddrSelf
); // used in OOP implementations
9487 ufoDefineConstant("(USER-INTERPRET-NEXT-LINE)", ufoAddrInterNextLine
);
9488 ufoDefineConstant("(EXC-FRAME-PTR)", ufoAddrEP
);
9491 ufoDefineConstant("(LATEST-XFA)", ufoAddrLastXFA
);
9492 ufoDefineConstant("(VOC-LINK)", ufoAddrVocLink
);
9493 ufoDefineConstant("(NEW-WORD-FLAGS)", ufoAddrNewWordFlags
);
9494 ufoDefineConstant("(ADDR-TEMP-BIT)", UFO_ADDR_TEMP_BIT
);
9495 ufoDefineConstant("(ADDR-CFA-BIT)", UFO_ADDR_CFA_BIT
);
9496 ufoDefineConstant("(ADDR-HANDLE-BIT)", UFO_ADDR_HANDLE_BIT
);
9497 ufoDefineConstant("(MAX-HANDLE-OFS)", UFO_ADDR_HANDLE_OFS_MASK
);
9498 ufoDefineConstant("(DP-TEMP-BASE-ADDR))", UFO_DPTEMP_BASE_ADDR
);
9500 ufoDefineConstant("(PAD-ADDR)", UFO_PAD_ADDR
);
9501 ufoDefineConstant("(#BUF)", UFO_NBUF_ADDR
+ 4u); // reserve room for counter
9502 ufoDefineConstant("(#BUF-SIZE)", UFO_NBUF_SIZE
- 8u);
9504 ufoDefineConstant("(DP-MAIN)", ufoAddrDP
);
9505 ufoDefineConstant("(DP-TEMP)", ufoAddrDPTemp
); // in user vars
9506 ufoDefineConstant("(DP-HERE)", ufoAddrHereDP
); // in user vars
9509 //UFWORDX("(UFO-BUCKET-STATS)", PAR_UFO_BUCKET_STATS);
9510 UFWORDX("SP0!", SP0_STORE
);
9511 UFWORDX("RP0!", RP0_STORE
);
9513 UFWORDX("(SELF@)", PAR_SELF_LOAD
);
9514 UFWORDX("(SELF!)", PAR_SELF_STORE
);
9516 UFWORDX("PAD", PAD
);
9517 UFWORDX("HERE", HERE
);
9518 UFWORDX("ALIGN-HERE", ALIGN_HERE
);
9521 UFWORDX("C@", CPEEK
);
9522 UFWORDX("W@", WPEEK
);
9525 UFWORDX("C!", CPOKE
);
9526 UFWORDX("W!", WPOKE
);
9528 UFWORDX("(DIRECT:@)", DIRECT_PEEK
); ufoSetLatestArgs(UFW_WARG_PFA
);
9529 UFWORDX("(DIRECT:!)", DIRECT_POKE
); ufoSetLatestArgs(UFW_WARG_PFA
);
9530 UFWORDX("(DIRECT:0:!)", DIRECT_POKE0
); ufoSetLatestArgs(UFW_WARG_PFA
);
9531 UFWORDX("(DIRECT:1:!)", DIRECT_POKE1
); ufoSetLatestArgs(UFW_WARG_PFA
);
9532 UFWORDX("(DIRECT:-1:!)", DIRECT_POKEM1
); ufoSetLatestArgs(UFW_WARG_PFA
);
9533 UFWORDX("(DIRECT:+!)", DIRECT_ADD_POKE
); ufoSetLatestArgs(UFW_WARG_PFA
);
9534 UFWORDX("(DIRECT:-!)", DIRECT_SUB_POKE
); ufoSetLatestArgs(UFW_WARG_PFA
);
9535 UFWORDX("(DIRECT:+:@)", DIRECT_OFS_PEEK
); ufoSetLatestArgs(UFW_WARG_LIT
);
9536 UFWORDX("(DIRECT:+:!)", DIRECT_OFS_POKE
); ufoSetLatestArgs(UFW_WARG_LIT
);
9537 UFWORDX("(DIRECT:1+!)", DIRECT_POKE_INC1
); ufoSetLatestArgs(UFW_WARG_LIT
);
9538 UFWORDX("(DIRECT:2+!)", DIRECT_POKE_INC2
); ufoSetLatestArgs(UFW_WARG_LIT
);
9539 UFWORDX("(DIRECT:4+!)", DIRECT_POKE_INC4
); ufoSetLatestArgs(UFW_WARG_LIT
);
9540 UFWORDX("(DIRECT:8+!)", DIRECT_POKE_INC8
); ufoSetLatestArgs(UFW_WARG_LIT
);
9541 UFWORDX("(DIRECT:1-!)", DIRECT_POKE_DEC1
); ufoSetLatestArgs(UFW_WARG_LIT
);
9542 UFWORDX("(DIRECT:2-!)", DIRECT_POKE_DEC2
); ufoSetLatestArgs(UFW_WARG_LIT
);
9543 UFWORDX("(DIRECT:4-!)", DIRECT_POKE_DEC4
); ufoSetLatestArgs(UFW_WARG_LIT
);
9544 UFWORDX("(DIRECT:8-!)", DIRECT_POKE_DEC8
); ufoSetLatestArgs(UFW_WARG_LIT
);
9546 UFWORDX("(LIT-AND)", LIT_AND
); ufoSetLatestArgs(UFW_WARG_LIT
);
9547 UFWORDX("(LIT-~AND)", LIT_NAND
); ufoSetLatestArgs(UFW_WARG_LIT
);
9548 UFWORDX("(LIT-OR)", LIT_OR
); ufoSetLatestArgs(UFW_WARG_LIT
);
9549 UFWORDX("(LIT-XOR)", LIT_XOR
); ufoSetLatestArgs(UFW_WARG_LIT
);
9551 UFWORDX("0!", POKE_0
);
9552 UFWORDX("1!", POKE_1
);
9553 UFWORDX("1+!", POKE_INC_1
);
9554 UFWORDX("1-!", POKE_DEC_1
);
9555 UFWORDX("+!", POKE_INC
);
9556 UFWORDX("-!", POKE_DEC
);
9558 UFWORDX("SWAP!", SWAP_POKE
);
9559 UFWORDX("SWAP-C!", SWAP_CPOKE
);
9560 UFWORDX("SWAP-W!", SWAP_WPOKE
);
9561 UFWORDX("OR!", OR_POKE
);
9562 UFWORDX("OR-C!", OR_CPOKE
);
9563 UFWORDX("OR-W!", OR_WPOKE
);
9564 UFWORDX("XOR!", XOR_POKE
);
9565 UFWORDX("XOR-C!", XOR_CPOKE
);
9566 UFWORDX("XOR-W!", XOR_WPOKE
);
9567 UFWORDX("~AND!", NAND_POKE
);
9568 UFWORDX("~AND-C!", NAND_CPOKE
);
9569 UFWORDX("~AND-W!", NAND_WPOKE
);
9571 UFWORDX("COUNT", COUNT
);
9572 UFWORDX("BCOUNT", BCOUNT
);
9573 UFWORDX("ID-COUNT", ID_COUNT
);
9575 UFWORDX(",", COMMA
);
9576 UFWORDX("C,", CCOMMA
);
9577 UFWORDX("W,", WCOMMA
);
9579 UFWORDX("A>", REGA_LOAD
);
9580 UFWORDX(">A", REGA_STORE
);
9581 UFWORDX("A-SWAP", REGA_SWAP
);
9582 UFWORDX("+1>A", REGA_INC
);
9583 UFWORDX("+2>A", REGA_INC_WORD
);
9584 UFWORDX("+4>A", REGA_INC_CELL
);
9585 UFWORDX("-1>A", REGA_DEC
);
9586 UFWORDX("-2>A", REGA_DEC_WORD
);
9587 UFWORDX("-4>A", REGA_DEC_CELL
);
9588 UFWORDX("A>R", REGA_TO_R
);
9589 UFWORDX("R>A", R_TO_REGA
);
9591 UFWORDX("@A", PEEK_REGA
);
9592 UFWORDX("C@A", CPEEK_REGA
);
9593 UFWORDX("W@A", WPEEK_REGA
);
9595 UFWORDX("!A", POKE_REGA
);
9596 UFWORDX("C!A", CPOKE_REGA
);
9597 UFWORDX("W!A", WPOKE_REGA
);
9599 UFWORDX("@A+", PEEK_REGA_IDX
);
9600 UFWORDX("C@A+", CPEEK_REGA_IDX
);
9601 UFWORDX("W@A+", WPEEK_REGA_IDX
);
9603 UFWORDX("!A+", POKE_REGA_IDX
);
9604 UFWORDX("C!A+", CPOKE_REGA_IDX
);
9605 UFWORDX("W!A+", WPOKE_REGA_IDX
);
9607 UFWORDX("C!+1>A", CPOKE_REGA_INC1
);
9608 UFWORDX("W!+2>A", WPOKE_REGA_INC2
);
9609 UFWORDX("!+4>A", POKE_REGA_INC4
);
9610 UFWORDX("C@+1>A", CPEEK_REGA_INC1
);
9611 UFWORDX("W@+2>A", WPEEK_REGA_INC2
);
9612 UFWORDX("@+4>A", PEEK_REGA_INC4
);
9615 UFWORDX("(LIT)", PAR_LIT
); ufoSetLatestArgs(UFW_WARG_LIT
);
9616 UFWORDX("(LITCFA)", PAR_LITCFA
); ufoSetLatestArgs(UFW_WARG_CFA
);
9617 UFWORDX("(LITPFA)", PAR_LITPFA
); ufoSetLatestArgs(UFW_WARG_PFA
);
9618 UFWORDX("(LITVOCID)", PAR_LITVOCID
); ufoSetLatestArgs(UFW_WARG_VOCID
);
9619 UFWORDX("(LITSTR8)", PAR_LITSTR8
); ufoSetLatestArgs(UFW_WARG_C1STRZ
);
9620 UFWORDX("(EXIT)", PAR_EXIT
);
9622 ufoLitStr8CFA
= ufoFindWordChecked("FORTH:(LITSTR8)");
9624 UFWORDX("(L-ENTER)", PAR_LENTER
); ufoSetLatestArgs(UFW_WARG_LIT
);
9625 UFWORDX("(L-LEAVE)", PAR_LLEAVE
);
9626 UFWORDX("(LOCAL@)", PAR_LOCAL_LOAD
);
9627 UFWORDX("(LOCAL!)", PAR_LOCAL_STORE
);
9629 UFWORDX("(BRANCH)", PAR_BRANCH
); ufoSetLatestArgs(UFW_WARG_BRANCH
);
9630 UFWORDX("(TBRANCH)", PAR_TBRANCH
); ufoSetLatestArgs(UFW_WARG_BRANCH
);
9631 UFWORDX("(0BRANCH)", PAR_0BRANCH
); ufoSetLatestArgs(UFW_WARG_BRANCH
);
9632 UFWORDX("(+0BRANCH)", PAR_P0BRANCH
); ufoSetLatestArgs(UFW_WARG_BRANCH
);
9633 UFWORDX("(+BRANCH)", PAR_PBRANCH
); ufoSetLatestArgs(UFW_WARG_BRANCH
);
9634 UFWORDX("(-0BRANCH)", PAR_M0BRANCH
); ufoSetLatestArgs(UFW_WARG_BRANCH
);
9635 UFWORDX("(-BRANCH)", PAR_MBRANCH
); ufoSetLatestArgs(UFW_WARG_BRANCH
);
9636 UFWORDX("(DATASKIP)", PAR_DATASKIP
); ufoSetLatestArgs(UFW_WARG_DATASKIP
);
9637 UFWORDX("(OR-BRANCH)", PAR_OR_BRANCH
); ufoSetLatestArgs(UFW_WARG_BRANCH
);
9638 UFWORDX("(AND-BRANCH)", PAR_AND_BRANCH
); ufoSetLatestArgs(UFW_WARG_BRANCH
);
9639 UFWORDX("(?DUP-0BRANCH)", PAR_QDUP_0BRANCH
); ufoSetLatestArgs(UFW_WARG_BRANCH
);
9640 UFWORDX("(CASE-BRANCH)", PAR_CASE_BRANCH
); ufoSetLatestArgs(UFW_WARG_BRANCH
);
9645 //==========================================================================
9649 //==========================================================================
9650 UFO_DISABLE_INLINE
void ufoInitMoreWords (void) {
9651 UFWORDX("CFA->DOES-CFA", CFA2DOESCFA
);
9652 UFWORDX("CFA->PFA", CFA2PFA
);
9653 UFWORDX("CFA->NFA", CFA2NFA
);
9654 UFWORDX("CFA->LFA", CFA2LFA
);
9655 UFWORDX("CFA->WEND", CFA2WEND
);
9657 UFWORDX("PFA->CFA", PFA2CFA
);
9658 UFWORDX("PFA->NFA", PFA2NFA
);
9660 UFWORDX("NFA->CFA", NFA2CFA
);
9661 UFWORDX("NFA->PFA", NFA2PFA
);
9662 UFWORDX("NFA->LFA", NFA2LFA
);
9664 UFWORDX("LFA->CFA", LFA2CFA
);
9665 UFWORDX("LFA->PFA", LFA2PFA
);
9666 UFWORDX("LFA->BFA", LFA2BFA
);
9667 UFWORDX("LFA->XFA", LFA2XFA
);
9668 UFWORDX("LFA->YFA", LFA2YFA
);
9669 UFWORDX("LFA->NFA", LFA2NFA
);
9671 UFWORDX("(BASED-NUMBER)", PAR_BASED_NUMBER
);
9672 UFWORDX("FIND-WORD", FIND_WORD
);
9673 UFWORDX("(FIND-WORD-IN-VOC)", PAR_FIND_WORD_IN_VOC
);
9674 UFWORDX("(FIND-WORD-IN-VOC-AND-PARENTS)", PAR_FIND_WORD_IN_VOC_AND_PARENTS
);
9675 UFWORDX("FIND-WORD-IN-VOC", FIND_WORD_IN_VOC
);
9676 UFWORDX("FIND-WORD-IN-VOC-AND-PARENTS", FIND_WORD_IN_VOC_AND_PARENTS
);
9679 UFWORDX("EXECUTE-TAIL", EXECUTE_TAIL
);
9680 UFWORDX("@EXECUTE", LOAD_EXECUTE
);
9681 UFWORDX("@EXECUTE-TAIL", LOAD_EXECUTE_TAIL
);
9682 UFWORDX("(FORTH-CALL)", FORTH_CALL
);
9683 UFWORDX("(FORTH-TAIL-CALL)", FORTH_TAIL_CALL
);
9688 UFWORDX("?DUP", QDUP
);
9689 UFWORDX("2DUP", DDUP
);
9691 UFWORDX("2DROP", DDROP
);
9693 UFWORDX("2SWAP", DSWAP
);
9695 UFWORDX("2OVER", DOVER
);
9698 UFWORDX("PICK", PICK
);
9699 UFWORDX("ROLL", ROLL
);
9703 UFWORDX(">R", DTOR
);
9704 UFWORDX("R>", RTOD
);
9705 UFWORDX("R@", RPEEK
);
9706 UFWORDX("2>R", 2DTOR
);
9707 UFWORDX("2R>", 2RTOD
);
9708 UFWORDX("2R@", 2RPEEK
);
9709 UFWORDX("2RDROP", 2RDROP
);
9710 UFWORDX("RPICK", RPICK
);
9711 UFWORDX("RROLL", RROLL
);
9712 UFWORDX("RSWAP", RSWAP
);
9713 UFWORDX("ROVER", ROVER
);
9714 UFWORDX("RROT", RROT
);
9715 UFWORDX("RNROT", RNROT
);
9717 UFWORDX("FLUSH-EMIT", FLUSH_EMIT
);
9718 UFWORDX("(EMIT)", PAR_EMIT
);
9719 UFWORDX("(NORM-EMIT-CHAR)", PAR_NORM_EMIT_CHAR
);
9720 UFWORDX("(NORM-XEMIT-CHAR)", PAR_NORM_XEMIT_CHAR
);
9721 UFWORDX("LASTCR?", LASTCRQ
);
9722 UFWORDX("LASTCR!", LASTCRSET
);
9726 UFWORDX("-", MINUS
);
9728 UFWORDX("U*", UMUL
);
9730 UFWORDX("U/", UDIV
);
9731 UFWORDX("MOD", MOD
);
9732 UFWORDX("UMOD", UMOD
);
9733 UFWORDX("/MOD", DIVMOD
);
9734 UFWORDX("U/MOD", UDIVMOD
);
9735 UFWORDX("*/", MULDIV
);
9736 UFWORDX("U*/", UMULDIV
);
9737 UFWORDX("*/MOD", MULDIVMOD
);
9738 UFWORDX("U*/MOD", UMULDIVMOD
);
9739 UFWORDX("M*", MMUL
);
9740 UFWORDX("UM*", UMMUL
);
9741 UFWORDX("M/MOD", MDIVMOD
);
9742 UFWORDX("UM/MOD", UMDIVMOD
);
9743 UFWORDX("UDS*", UDSMUL
);
9745 UFWORDX("SM/REM", SMREM
);
9746 UFWORDX("FM/MOD", FMMOD
);
9748 UFWORDX("D-", DMINUS
);
9749 UFWORDX("D+", DPLUS
);
9750 UFWORDX("D=", DEQU
);
9751 UFWORDX("D<", DLESS
);
9752 UFWORDX("D<=", DLESSEQU
);
9753 UFWORDX("DU<", DULESS
);
9754 UFWORDX("DU<=", DULESSEQU
);
9762 UFWORDX("~AND", BN_AND
);
9763 UFWORDX("ABS", ABS
);
9764 UFWORDX("NEGATE", NEGATE
);
9765 UFWORDX("SIGN?", SIGNQ
);
9766 UFWORDX("LO-WORD", LO_WORD
);
9767 UFWORDX("HI-WORD", HI_WORD
);
9768 UFWORDX("LO-BYTE", LO_BYTE
);
9769 UFWORDX("HI-BYTE", HI_BYTE
);
9770 UFWORDX("MIN", MIN
);
9771 UFWORDX("MAX", MAX
);
9772 UFWORDX("UMIN", UMIN
);
9773 UFWORDX("UMAX", UMAX
);
9774 UFWORDX("WITHIN", WITHIN
);
9775 UFWORDX("UWITHIN", UWITHIN
);
9776 UFWORDX("BOUNDS?", BOUNDSQ
);
9777 UFWORDX("BSWAP16", BSWAP16
);
9778 UFWORDX("BSWAP32", BSWAP32
);
9781 UFWORDX("(SWAP:1+:SWAP)", PAR_SWAP_INC_SWAP
);
9785 UFWORDX(">", GREAT
);
9786 UFWORDX("<=", LESSEQU
);
9787 UFWORDX(">=", GREATEQU
);
9788 UFWORDX("U<", ULESS
);
9789 UFWORDX("U>", UGREAT
);
9790 UFWORDX("U<=", ULESSEQU
);
9791 UFWORDX("U>=", UGREATEQU
);
9793 UFWORDX("<>", NOTEQU
);
9795 UFWORDX("0=", ZERO_EQU
);
9796 UFWORDX("0<>", ZERO_NOTEQU
);
9797 UFWORDX("0<", 0LESS
);
9798 UFWORDX("0>", 0GREAT
);
9799 UFWORDX("0<=", 0LESSEQU
);
9800 UFWORDX("0>=", 0GREATEQU
);
9802 UFWORDX("NOT", ZERO_EQU
);
9803 UFWORDX("NOTNOT", ZERO_NOTEQU
);
9809 UFWORDX("LOGAND", LOGAND
);
9810 UFWORDX("LOGOR", LOGOR
);
9812 UFWORDX("2*", 2MUL
);
9813 UFWORDX("4*", 4MUL
);
9814 UFWORDX("8*", 8MUL
);
9815 UFWORDX("2/", 2DIV
);
9816 UFWORDX("4/", 4DIV
);
9817 UFWORDX("8/", 8DIV
);
9818 UFWORDX("2U/", 2UDIV
);
9819 UFWORDX("4U/", 4UDIV
);
9820 UFWORDX("8U/", 8UDIV
);
9822 UFWORDX("1+", 1ADD
);
9823 UFWORDX("1-", 1SUB
);
9824 UFWORDX("2+", 2ADD
);
9825 UFWORDX("2-", 2SUB
);
9826 UFWORDX("4+", 4ADD
);
9827 UFWORDX("4-", 4SUB
);
9828 UFWORDX("8+", 8ADD
);
9829 UFWORDX("8-", 8SUB
);
9831 ufoDefineConstant("CELL", 4);
9833 UFWORDX("CELL+", 4ADD
);
9834 UFWORDX("CELL-", 4SUB
);
9836 UFWORDX("CELLS", 4MUL
);
9837 UFWORDX("/CELLS", 4DIV
);
9838 UFWORDX("+CELLS", ADD_CELLS
);
9839 UFWORDX("-CELLS", SUB_CELLS
);
9841 UFWORDX("MEMCMP", MEMCMP
);
9842 UFWORDX("MEMCMP-CI", MEMCMP_CI
);
9844 UFWORDX("CMOVE-CELLS", CMOVE_CELLS_FWD
);
9845 UFWORDX("CMOVE>-CELLS", CMOVE_CELLS_BWD
);
9846 UFWORDX("CMOVE", CMOVE_FWD
);
9847 UFWORDX("CMOVE>", CMOVE_BWD
);
9848 UFWORDX("MOVE", MOVE
);
9850 UFWORDX("FILL-CELLS", FILL_CELLS
);
9851 UFWORDX("FILL", FILL
);
9854 UFWORDX("(TIB-IN)", TIB_IN
);
9855 UFWORDX("TIB-PEEKCH", TIB_PEEKCH
);
9856 UFWORDX("TIB-PEEKCH-OFS", TIB_PEEKCH_OFS
);
9857 UFWORDX("TIB-GETCH", TIB_GETCH
);
9858 UFWORDX("TIB-SKIPCH", TIB_SKIPCH
);
9860 UFWORDX("REFILL", REFILL
);
9861 UFWORDX("REFILL-NOCROSS", REFILL_NOCROSS
);
9864 UFWORDX("(PARSE)", PAR_PARSE
);
9865 UFWORDX("(PARSE-SKIP-COMMENTS)", PAR_PARSE_SKIP_COMMENTS
);
9867 UFWORDX("PARSE-SKIP-BLANKS", PARSE_SKIP_BLANKS
);
9868 UFWORDX("PARSE-NAME", PARSE_NAME
);
9869 UFWORDX("PARSE-SKIP-LINE", PARSE_SKIP_LINE
);
9870 UFWORDX("PARSE", PARSE
);
9873 UFWORDX("(VSP@)", PAR_GET_VSP
);
9874 UFWORDX("(VSP!)", PAR_SET_VSP
);
9875 UFWORDX("(VSP-AT@)", PAR_VSP_LOAD
);
9876 UFWORDX("(VSP-AT!)", PAR_VSP_STORE
);
9877 ufoDefineConstant("(VSP-SIZE)", UFO_VOCSTACK_SIZE
);
9879 ufoDefineConstant("(SP-SIZE)", UFO_DSTACK_SIZE
);
9880 ufoDefineConstant("(RP-SIZE)", UFO_RSTACK_SIZE
);
9881 ufoDefineConstant("(LP-SIZE)", UFO_LSTACK_SIZE
);
9884 UFWORDX("ERROR", ERROR
);
9885 UFWORDX("FATAL-ERROR", ERROR
);
9886 UFWORDX("(USER-ABORT)", PAR_USER_ABORT
);
9888 ufoUserAbortCFA
= ufoImgGetU32(ufoAddrCurrent
);
9889 ufoUserAbortCFA
= ufoImgGetU32(ufoUserAbortCFA
+ UFW_VOCAB_OFS_LATEST
);
9890 ufoUserAbortCFA
= UFO_LFA_TO_CFA(ufoUserAbortCFA
);
9892 UFWORDX("?ERROR", QERROR
);
9893 UFWORDX("?NOT-ERROR", QNOTERROR
);
9897 ufoInterpretLine(": ABORT ` \"ABORT\" called` ERROR ;");
9899 UFWORDX("GET-MSECS", GET_MSECS
);
9903 //==========================================================================
9905 // ufoInitBasicCompilerWords
9907 //==========================================================================
9908 UFO_DISABLE_INLINE
void ufoInitBasicCompilerWords (void) {
9909 // create "COMPILER" vocabulary
9910 ufoCompilerVocId
= ufoCreateVoc("COMPILER", 0, UFW_FLAG_PROTECTED
);
9911 ufoVocSetOnlyDefs(ufoCompilerVocId
);
9913 ufoDefineConstant("(CFAIDX-DO-FORTH)", ufoDoForthCFA
);
9914 ufoDefineConstant("(CFAIDX-DO-VAR)", ufoDoVariableCFA
);
9915 ufoDefineConstant("(CFAIDX-DO-VALUE)", ufoDoValueCFA
);
9916 ufoDefineConstant("(CFAIDX-DO-CONST)", ufoDoConstCFA
);
9917 ufoDefineConstant("(CFAIDX-DO-DEFER)", ufoDoDeferCFA
);
9918 ufoDefineConstant("(CFAIDX-DO-DOES)", ufoDoDoesCFA
);
9919 ufoDefineConstant("(CFAIDX-DO-REDIRECT)", ufoDoRedirectCFA
);
9920 ufoDefineConstant("(CFAIDX-DO-VOC)", ufoDoVocCFA
);
9921 ufoDefineConstant("(CFAIDX-DO-CREATE)", ufoDoCreateCFA
);
9922 ufoDefineConstant("(CFAIDX-DO-USER-VAR)", ufoDoUserVariableCFA
);
9924 ufoDefineConstant("(WFLAG-IMMEDIATE)", UFW_FLAG_IMMEDIATE
);
9925 ufoDefineConstant("(WFLAG-SMUDGE)", UFW_FLAG_SMUDGE
);
9926 ufoDefineConstant("(WFLAG-NORETURN)", UFW_FLAG_NORETURN
);
9927 ufoDefineConstant("(WFLAG-HIDDEN)", UFW_FLAG_HIDDEN
);
9928 ufoDefineConstant("(WFLAG-CBLOCK)", UFW_FLAG_CBLOCK
);
9929 ufoDefineConstant("(WFLAG-VOCAB)", UFW_FLAG_VOCAB
);
9930 ufoDefineConstant("(WFLAG-SCOLON)", UFW_FLAG_SCOLON
);
9931 ufoDefineConstant("(WFLAG-PROTECTED)", UFW_FLAG_PROTECTED
);
9933 ufoDefineConstant("(WARG-MASK)", UFW_WARG_MASK
);
9934 ufoDefineConstant("(WARG-NONE)", UFW_WARG_NONE
);
9935 ufoDefineConstant("(WARG-BRANCH)", UFW_WARG_BRANCH
);
9936 ufoDefineConstant("(WARG-LIT)", UFW_WARG_LIT
);
9937 ufoDefineConstant("(WARG-C4STRZ)", UFW_WARG_C4STRZ
);
9938 ufoDefineConstant("(WARG-CFA)", UFW_WARG_CFA
);
9939 ufoDefineConstant("(WARG-CBLOCK)", UFW_WARG_CBLOCK
);
9940 ufoDefineConstant("(WARG-VOCID)", UFW_WARG_VOCID
);
9941 ufoDefineConstant("(WARG-C1STRZ)", UFW_WARG_C1STRZ
);
9942 ufoDefineConstant("(WARG-DATASKIP)", UFW_WARG_DATASKIP
);
9943 ufoDefineConstant("(WARG-PFA)", UFW_WARG_PFA
);
9945 ufoDefineConstant("(VOCOFS-LATEST)", UFW_VOCAB_OFS_LATEST
);
9946 ufoDefineConstant("(VOCOFS-VOCLINK)", UFW_VOCAB_OFS_VOCLINK
);
9947 ufoDefineConstant("(VOCOFS-PARENT)", UFW_VOCAB_OFS_PARENT
);
9948 ufoDefineConstant("(VOCOFS-HEADER)", UFW_VOCAB_OFS_HEADER
);
9949 ufoDefineConstant("(VOCOFS-HTABLE)", UFW_VOCAB_OFS_HTABLE
);
9950 ufoDefineConstant("(VOC-HTABLE-SIZE)", UFO_HASHTABLE_SIZE
);
9951 ufoDefineConstant("(VOC-HTABLE-NOFLAG)", UFO_NO_HTABLE_FLAG
);
9953 ufoDefineConstant("(REDEFINE-WARN-DON'T-CARE)", UFO_REDEF_WARN_DONT_CARE
);
9954 ufoDefineConstant("(REDEFINE-WARN-NONE)", UFO_REDEF_WARN_NONE
);
9955 ufoDefineConstant("(REDEFINE-WARN-NORMAL)", UFO_REDEF_WARN_NORMAL
);
9956 ufoDefineConstant("(REDEFINE-WARN-PARENTS)", UFO_REDEF_WARN_PARENTS
);
9958 ufoDefineConstant("WORD-REDEFINE-WARN-MODE", ufoAddrRedefineWarning
);
9960 UFWORDX("(BRANCH-ADDR!)", PAR_BRANCH_ADDR_POKE
);
9961 UFWORDX("(BRANCH-ADDR@)", PAR_BRANCH_ADDR_PEEK
);
9963 UFWORDX("CFA,", CFA_COMMA
);
9964 UFWORDX("(UNESCAPE)", PAR_UNESCAPE
);
9966 const uint32_t dropCFA
= ufoFindWordChecked("FORTH:DROP");
9967 const uint32_t noopCFA
= ufoFindWordChecked("FORTH:NOOP");
9969 ufoDefineDefer("(AFTER-COMPILE-WORD)", dropCFA
); // ( start-addr -- )
9970 ufoDefineDefer("(AFTER-COMPILE-LIT)", dropCFA
); // ( start-addr -- )
9971 ufoDefineDefer("(JUMP-HERE-MARKED)", noopCFA
); // ( -- )
9972 ufoDefineDefer("(RESET-SINOPT)", noopCFA
); // ( -- )
9976 " FORTH:STATE FORTH:@ ` expecting interpretation mode` FORTH:?ERROR "
9981 " FORTH:STATE FORTH:@ ` expecting compilation mode` FORTH:?NOT-ERROR "
9985 ": EXEC? ( -- bool ) "
9986 " FORTH:STATE FORTH:@ FORTH:0= "
9990 ": COMP? ( -- bool ) "
9991 " FORTH:STATE FORTH:@ FORTH:0<> "
9996 " FORTH:STATE FORTH:0! "
10001 " FORTH:STATE FORTH:1! "
10004 UFWORDX("(CREATE-WORD-HEADER)", PAR_CREATE_WORD_HEADER
);
10005 UFWORDX("(CREATE-NAMELESS-WORD-HEADER)", PAR_CREATE_NAMELESS_WORD_HEADER
);
10007 ufoVocSetOnlyDefs(ufoForthVocId
);
10010 ufoInterpretLine("!: [ COMPILER:?COMP COMPILER:EXEC! ;");
10012 ufoInterpretLine(": ] COMPILER:?EXEC COMPILER:COMP! ;");
10015 ": COMPILE, ( n -- ) "
10016 " HERE >R , R> COMPILER:(AFTER-COMPILE-WORD) "
10020 ": COMPILE-IMM, ( n -- ) "
10024 ufoDefineVar("(COMPILE-START-HERE)", 0);
10027 ": COMPILE-START, ( n -- ) "
10028 " HERE (COMPILE-START-HERE) ! , "
10032 ": COMPILE-ARG, ( n -- ) "
10037 ": COMPILE-END, ( n -- ) "
10038 " , (COMPILE-START-HERE) @ (COMPILE-START-HERE) 0! "
10039 " COMPILER:(AFTER-COMPILE-WORD) "
10043 // ( C:n -- ) ( E:n -- n )
10045 ": LITERAL ( C:n -- ) ( E:n -- n ) "
10046 " COMPILER:COMP? FORTH:(0BRANCH) $literal_exit "
10047 " HERE >R X-COMPILE FORTH:(LIT) , "
10048 " R> COMPILER:(AFTER-COMPILE-LIT) "
10051 //ufoDecompileWord(ufoFindWordChecked("LITERAL"));
10054 // ( C:cfa -- ) ( E:cfa -- cfa )
10056 ": CFALITERAL ( C:cfa -- ) ( E:cfa -- cfa ) "
10057 " COMPILER:COMP? FORTH:(0BRANCH) $cfa_literal_exit "
10058 " HERE >R X-COMPILE FORTH:(LITCFA) , "
10059 " R> COMPILER:(AFTER-COMPILE-LIT) "
10060 "$cfa_literal_exit: "
10064 // ( C:pfa -- ) ( E:pfa -- pfa )
10066 ": PFALITERAL ( C:pfa -- ) ( E:pfa -- pfa ) "
10067 " COMPILER:COMP? FORTH:(0BRANCH) $pfa_literal_exit "
10068 " HERE >R X-COMPILE FORTH:(LITPFA) , "
10069 " R> COMPILER:(AFTER-COMPILE-LIT) "
10070 "$pfa_literal_exit: "
10073 ufoInterpretLine("!: IMM-LITERAL LITERAL ;");
10074 ufoInterpretLine("!: IMM-CFALITERAL CFALITERAL ;");
10075 ufoInterpretLine("!: IMM-PFALITERAL PFALITERAL ;");
10079 //==========================================================================
10081 // ufoInitHandleWords
10083 //==========================================================================
10084 UFO_DISABLE_INLINE
void ufoInitHandleWords (void) {
10085 // create "HANDLE" vocabulary
10086 const uint32_t handleVocId
= ufoCreateVoc("HANDLE", 0, UFW_FLAG_PROTECTED
);
10087 ufoVocSetOnlyDefs(handleVocId
);
10088 UFWORDX("NEW", PAR_NEW_HANDLE
);
10089 UFWORDX("FREE", PAR_FREE_HANDLE
);
10090 UFWORDX("TYPEID@", PAR_HANDLE_GET_TYPEID
);
10091 UFWORDX("TYPEID!", PAR_HANDLE_SET_TYPEID
);
10092 UFWORDX("SIZE@", PAR_HANDLE_GET_SIZE
);
10093 UFWORDX("SIZE!", PAR_HANDLE_SET_SIZE
);
10094 UFWORDX("USED@", PAR_HANDLE_GET_USED
);
10095 UFWORDX("USED!", PAR_HANDLE_SET_USED
);
10096 UFWORDX("C@", PAR_HANDLE_LOAD_BYTE
);
10097 UFWORDX("W@", PAR_HANDLE_LOAD_WORD
);
10098 UFWORDX("@", PAR_HANDLE_LOAD_CELL
);
10099 UFWORDX("C!", PAR_HANDLE_STORE_BYTE
);
10100 UFWORDX("W!", PAR_HANDLE_STORE_WORD
);
10101 UFWORDX("!", PAR_HANDLE_STORE_CELL
);
10102 UFWORDX("LOAD-FILE", PAR_HANDLE_LOAD_FILE
);
10103 ufoVocSetOnlyDefs(ufoForthVocId
);
10107 //==========================================================================
10109 // ufoInitHigherWords
10111 //==========================================================================
10112 UFO_DISABLE_INLINE
void ufoInitHigherWords (void) {
10113 UFWORDX("(INCLUDE)", PAR_INCLUDE
);
10114 UFWORDX("(INCLUDE-DROP)", PAR_INCLUDE_DROP
);
10115 UFWORDX("(INCLUDE-BUILD-NAME)", PAR_INCLUDE_BUILD_NAME
);
10116 UFWORDX("(INCLUDE-NO-REFILL)", PAR_INCLUDE_NO_REFILL
);
10117 UFWORDX("(INCLUDE-LINE-SEEK)", PAR_INCLUDE_LINE_SEEK
);
10119 UFWORDX("(INCLUDE-LINE-FOFS)", PAR_INCLUDE_LINE_FOFS
);
10120 UFWORDX("(INCLUDE-DEPTH)", PAR_INCLUDE_DEPTH
);
10121 UFWORDX("(INCLUDE-FILE-ID)", PAR_INCLUDE_FILE_ID
);
10122 UFWORDX("(INCLUDE-FILE-LINE)", PAR_INCLUDE_FILE_LINE
);
10123 UFWORDX("(INCLUDE-FILE-NAME)", PAR_INCLUDE_FILE_NAME
);
10125 UFWORDX("($DEFINED?)", PAR_DLR_DEFINEDQ
);
10126 UFWORDX("($DEFINE)", PAR_DLR_DEFINE
);
10127 UFWORDX("($UNDEF)", PAR_DLR_UNDEF
);
10129 UFWORDX_IMM("$INCLUDE", DLR_INCLUDE_IMM
);
10130 UFWORDX_IMM("$INCLUDE-ONCE", DLR_INCLUDE_ONCE_IMM
);
10134 //==========================================================================
10136 // ufoInitStringWords
10138 //==========================================================================
10139 UFO_DISABLE_INLINE
void ufoInitStringWords (void) {
10140 // create "STRING" vocabulary
10141 const uint32_t stringVocId
= ufoCreateVoc("STRING", 0, UFW_FLAG_PROTECTED
);
10142 ufoVocSetOnlyDefs(stringVocId
);
10143 UFWORDX("=", STREQU
);
10144 UFWORDX("=CI", STREQUCI
);
10145 UFWORDX("SEARCH", SEARCH
);
10146 UFWORDX("HASH", STRHASH
);
10147 UFWORDX("HASH-CI", STRHASHCI
);
10148 UFWORDX("CHAR-UPPER", CHAR_UPPER
);
10149 UFWORDX("CHAR-LOWER", CHAR_LOWER
);
10150 UFWORDX("UPPER", STRUPPER
);
10151 UFWORDX("LOWER", STRLOWER
);
10152 UFWORDX("(CHAR-DIGIT)", CHAR_DIGIT
);
10153 UFWORDX("DIGIT", DIGIT
);
10154 UFWORDX("DIGIT?", DIGITQ
);
10156 UFWORDX("IS-DIGIT", IS_DIGIT
);
10157 UFWORDX("IS-BIN-DIGIT", IS_BIN_DIGIT
);
10158 UFWORDX("IS-OCT-DIGIT", IS_OCT_DIGIT
);
10159 UFWORDX("IS-HEX-DIGIT", IS_HEX_DIGIT
);
10160 UFWORDX("IS-ALPHA", IS_ALPHA
);
10161 UFWORDX("IS-UNDER-DOT", IS_UNDER_DOT
);
10162 UFWORDX("IS-ALNUM", IS_ALNUM
);
10163 UFWORDX("IS-ID-START", IS_ID_START
);
10164 UFWORDX("IS-ID-CHAR", IS_ID_CHAR
);
10166 ufoVocSetOnlyDefs(ufoForthVocId
);
10170 //==========================================================================
10172 // ufoInitDebugWords
10174 //==========================================================================
10175 UFO_DISABLE_INLINE
void ufoInitDebugWords (void) {
10176 // create "DEBUG" vocabulary
10177 const uint32_t debugVocId
= ufoCreateVoc("DEBUG", 0, UFW_FLAG_PROTECTED
);
10178 ufoVocSetOnlyDefs(debugVocId
);
10179 UFWORDX("(DECOMPILE-CFA)", DEBUG_DECOMPILE_CFA
);
10180 UFWORDX("(DECOMPILE-MEM)", DEBUG_DECOMPILE_MEM
);
10181 UFWORDX("BACKTRACE", UFO_BACKTRACE
);
10182 UFWORDX("DUMP-STACK", DUMP_STACK
);
10183 #ifdef UFO_MTASK_ALLOWED
10184 UFWORDX("BACKTRACE-TASK", UFO_BACKTRACE_TASK
);
10185 UFWORDX("DUMP-STACK-TASK", DUMP_STACK_TASK
);
10186 UFWORDX("DUMP-RSTACK-TASK", DUMP_RSTACK_TASK
);
10188 UFWORDX("(BP)", MT_DEBUGGER_BP
);
10189 UFWORDX("IP->NFA", IP2NFA
);
10190 UFWORDX("IP->FILE/LINE", IP2FILELINE
);
10191 UFWORDX("IP->FILE-HASH/LINE", IP2FILEHASHLINE
);
10192 #ifdef UFO_MTASK_ALLOWED
10193 UFWORDX("SINGLE-STEP@", DBG_GET_SS
);
10195 ufoVocSetOnlyDefs(ufoForthVocId
);
10199 //==========================================================================
10203 //==========================================================================
10204 UFO_DISABLE_INLINE
void ufoInitMTWords (void) {
10205 // create "MTASK" vocabulary
10206 const uint32_t mtVocId
= ufoCreateVoc("MTASK", 0, UFW_FLAG_PROTECTED
);
10207 ufoVocSetOnlyDefs(mtVocId
);
10208 #ifdef UFO_MTASK_ALLOWED
10209 UFWORDX("NEW-STATE", MT_NEW_STATE
);
10210 UFWORDX("FREE-STATE", MT_FREE_STATE
);
10212 UFWORDX("STATE-NAME@", MT_GET_STATE_NAME
);
10213 UFWORDX("STATE-NAME!", MT_SET_STATE_NAME
);
10214 #ifdef UFO_MTASK_ALLOWED
10215 UFWORDX("STATE-FIRST", MT_STATE_FIRST
);
10216 UFWORDX("STATE-NEXT", MT_STATE_NEXT
);
10217 UFWORDX("YIELD-TO", MT_YIELD_TO
);
10218 UFWORDX("SET-SELF-AS-DEBUGGER", MT_SET_SELF_AS_DEBUGGER
);
10219 UFWORDX("DEBUGGER-RESUME", MT_RESUME_DEBUGEE
);
10220 UFWORDX("DEBUGGER-SINGLE-STEP", MT_SINGLE_STEP_DEBUGEE
);
10222 UFWORDX("ACTIVE-STATE", MT_ACTIVE_STATE
);
10223 UFWORDX("STATE-IP@", MT_STATE_IP_GET
);
10224 UFWORDX("STATE-IP!", MT_STATE_IP_SET
);
10225 UFWORDX("STATE-A>", MT_STATE_REGA_GET
);
10226 UFWORDX("STATE->A", MT_STATE_REGA_SET
);
10227 UFWORDX("STATE-USER@", MT_STATE_USER_GET
);
10228 UFWORDX("STATE-USER!", MT_STATE_USER_SET
);
10229 UFWORDX("YIELDED-FROM", MT_YIELDED_FROM
);
10230 UFWORDX("STATE-SP@", MT_DSTACK_DEPTH_GET
);
10231 UFWORDX("STATE-RP@", MT_RSTACK_DEPTH_GET
);
10232 UFWORDX("STATE-LP@", MT_LP_GET
);
10233 UFWORDX("STATE-LBP@", MT_LBP_GET
);
10234 UFWORDX("STATE-SP!", MT_DSTACK_DEPTH_SET
);
10235 UFWORDX("STATE-RP!", MT_RSTACK_DEPTH_SET
);
10236 UFWORDX("STATE-LP!", MT_LP_SET
);
10237 UFWORDX("STATE-LBP!", MT_LBP_SET
);
10238 UFWORDX("STATE-DS@", MT_DSTACK_LOAD
);
10239 UFWORDX("STATE-RS@", MT_RSTACK_LOAD
);
10240 UFWORDX("STATE-LS@", MT_LSTACK_LOAD
);
10241 UFWORDX("STATE-DS!", MT_DSTACK_STORE
);
10242 UFWORDX("STATE-RS!", MT_RSTACK_STORE
);
10243 UFWORDX("STATE-LS!", MT_LSTACK_STORE
);
10244 UFWORDX("STATE-VSP@", MT_VSP_GET
);
10245 UFWORDX("STATE-VSP!", MT_VSP_SET
);
10246 UFWORDX("STATE-VSP-AT@", MT_VSP_LOAD
);
10247 UFWORDX("STATE-VSP-AT!", MT_VSP_STORE
);
10248 ufoVocSetOnlyDefs(ufoForthVocId
);
10252 //==========================================================================
10256 //==========================================================================
10257 UFO_DISABLE_INLINE
void ufoInitTTYWords (void) {
10258 // create "TTY" vocabulary
10259 const uint32_t ttyVocId
= ufoCreateVoc("TTY", 0, UFW_FLAG_PROTECTED
);
10260 ufoVocSetOnlyDefs(ttyVocId
);
10261 UFWORDX("TTY?", TTY_TTYQ
);
10262 UFWORDX("RAW?", TTY_RAWQ
);
10263 UFWORDX("SIZE", TTY_SIZE
);
10264 UFWORDX("SET-RAW", TTY_SET_RAW
);
10265 UFWORDX("SET-COOKED", TTY_SET_COOKED
);
10266 UFWORDX("RAW-EMIT", TTY_RAW_EMIT
);
10267 UFWORDX("RAW-TYPE", TTY_RAW_TYPE
);
10268 UFWORDX("RAW-FLUSH", TTY_RAW_FLUSH
);
10269 UFWORDX("RAW-READCH", TTY_RAW_READCH
);
10270 UFWORDX("RAW-READY?", TTY_RAW_READYQ
);
10271 ufoVocSetOnlyDefs(ufoForthVocId
);
10275 //==========================================================================
10277 // ufoInitFilesWords
10279 //==========================================================================
10280 UFO_DISABLE_INLINE
void ufoInitFilesWords (void) {
10281 // create "FILES" vocabulary
10282 const uint32_t filesVocId
= ufoCreateVoc("FILES", 0, UFW_FLAG_PROTECTED
);
10283 ufoVocSetOnlyDefs(filesVocId
);
10284 ufoDefineConstant("SEEK-SET", SEEK_SET
);
10285 ufoDefineConstant("SEEK-CUR", SEEK_CUR
);
10286 ufoDefineConstant("SEEK-END", SEEK_END
);
10288 UFWORDX("OPEN-R/O", FILES_OPEN_RO
);
10289 UFWORDX("OPEN-R/W", FILES_OPEN_RW
);
10290 UFWORDX("CREATE", FILES_CREATE
);
10291 UFWORDX("CLOSE", FILES_CLOSE
);
10292 UFWORDX("TELL", FILES_TELL
);
10293 UFWORDX("SEEK-EX", FILES_SEEK_EX
);
10294 UFWORDX("SIZE", FILES_SIZE
);
10295 UFWORDX("READ", FILES_READ
);
10296 UFWORDX("READ-EXACT", FILES_READ_EXACT
);
10297 UFWORDX("WRITE", FILES_WRITE
);
10299 UFWORDX("UNLINK", FILES_UNLINK
);
10301 UFWORDX("ERRNO", FILES_ERRNO
);
10304 ": SEEK ( ofs handle -- success? ) "
10305 " SEEK-SET FORTH:SWAP SEEK-EX "
10308 ufoVocSetOnlyDefs(ufoForthVocId
);
10312 //==========================================================================
10314 // ufoInitVeryVeryHighWords
10316 //==========================================================================
10317 UFO_DISABLE_INLINE
void ufoInitVeryVeryHighWords (void) {
10319 //ufoDefineDefer("INTERPRET", idumbCFA);
10321 ufoDefineEmitType();
10323 // ( addr count FALSE -- addr count FALSE / TRUE )
10324 ufoDefineSColonForth("(INTERPRET-CHECK-WORD)");
10326 // ( addr count FALSE -- addr count FALSE / TRUE )
10327 ufoDefineSColonForth("(INTERPRET-WORD-NOT-FOUND)");
10329 // ( addr count -- addr count )
10330 ufoDefineSColonForth("(INTERPRET-WORD-NOT-FOUND-POST)");
10332 // ( -- ) -- called in "EXIT", before compiling "FORTH:(EXIT)"
10333 ufoDefineSColonForth("(EXIT-EXTENDER)");
10339 " COMPILER:?COMP (EXIT-EXTENDER) "
10341 " COMPILE FORTH:(EXIT) "
10342 //" R> COMPILER:(AFTER-COMPILE-WORD) "
10345 ufoDefineInterpret();
10347 //ufoDumpVocab(ufoCompilerVocId);
10350 ": RUN-INTERPRET-LOOP "
10351 "$run-interp-loop-again: "
10352 " RP0! INTERPRET (UFO-INTERPRET-FINISHED-ACTION) "
10353 " FORTH:(BRANCH) $run-interp-loop-again "
10357 #define UFO_ADD_DO_CFA(cfx_) do { \
10358 ufoDo##cfx_##CFA = ufoCFAsUsed | UFO_ADDR_CFA_BIT; \
10359 ufoForthCFAs[ufoCFAsUsed] = &ufoDo##cfx_; \
10360 ufoCFAsUsed += 1; \
10364 //==========================================================================
10368 //==========================================================================
10369 static void ufoBadCFA (uint32_t pfa
) {
10370 ufoFatal("tried to execute an invalid CFA: IP=%u", ufoIP
- 4u);
10374 //==========================================================================
10378 //==========================================================================
10379 UFO_DISABLE_INLINE
void ufoInitCommon (void) {
10381 ufoForthVocId
= 0; ufoCompilerVocId
= 0;
10383 //ufoForthCFAs = calloc(UFO_MAX_NATIVE_CFAS, sizeof(ufoForthCFAs[0]));
10384 for (uint32_t f
= 0; f
< UFO_MAX_NATIVE_CFAS
; f
+= 1) ufoForthCFAs
[f
] = &ufoBadCFA
;
10386 // allocate default TIB handle
10387 //UfoHandle *tibh = ufoAllocHandle(0x69a029a6); // arbitrary number
10388 //ufoDefTIB = tibh->ufoHandle;
10390 /*ufoForthCFAs[0] = NULL;*/ ufoCFAsUsed
= 1u;
10391 UFO_ADD_DO_CFA(Forth
);
10392 UFO_ADD_DO_CFA(Variable
);
10393 UFO_ADD_DO_CFA(Value
);
10394 UFO_ADD_DO_CFA(Const
);
10395 UFO_ADD_DO_CFA(Defer
);
10396 UFO_ADD_DO_CFA(Does
);
10397 UFO_ADD_DO_CFA(Redirect
);
10398 UFO_ADD_DO_CFA(Voc
);
10399 UFO_ADD_DO_CFA(Create
);
10400 UFO_ADD_DO_CFA(UserVariable
);
10402 //fprintf(stderr, "DO-FORTH-CFA: 0x%08x\n", ufoDoForthCFA);
10406 // create "FORTH" vocabulary (it should be the first one)
10407 ufoForthVocId
= ufoCreateVoc("FORTH", 0, UFW_FLAG_PROTECTED
);
10408 ufoVocSetOnlyDefs(ufoForthVocId
);
10410 // base low-level interpreter words
10411 ufoInitBasicWords();
10413 // more FORTH words
10414 ufoInitMoreWords();
10416 // some COMPILER words
10417 ufoInitBasicCompilerWords();
10419 // STRING vocabulary
10420 ufoInitStringWords();
10422 // DEBUG vocabulary
10423 ufoInitDebugWords();
10425 // MTASK vocabulary
10428 // HANDLE vocabulary
10429 ufoInitHandleWords();
10434 // FILES vocabulary
10435 ufoInitFilesWords();
10437 // some higher-level FORTH words (includes, etc.)
10438 ufoInitHigherWords();
10440 // very-very high-level FORTH words
10441 ufoInitVeryVeryHighWords();
10443 ufoFinalLabelCheck();
10446 ufoDecompileWord(ufoFindWordChecked("RUN-INTERPRET-LOOP"));
10455 // ////////////////////////////////////////////////////////////////////////// //
10456 // virtual machine executor
10460 //==========================================================================
10464 // address interpreter
10466 //==========================================================================
10467 static void ufoRunVMxxx (uint32_t cfa
) {
10469 // VM execution loop
10471 cfa
= ufoImgGetU32(ufoIP
); ufoIP
+= 4u;
10477 //==========================================================================
10481 //==========================================================================
10482 static void ufoRunVMCFA (uint32_t cfa
) {
10483 if (ufoInRunWord
) ufoFatal("cannot run VM recursively");
10485 if (setjmp(ufoStopVMJP
) == 0) {
10492 // ////////////////////////////////////////////////////////////////////////// //
10496 //==========================================================================
10500 // register new word
10502 //==========================================================================
10503 uint32_t ufoRegisterWord (const char *wname
, ufoNativeCFA cfa
, uint32_t flags
) {
10504 ufo_assert(cfa
!= NULL
);
10505 ufo_assert(wname
!= NULL
&& wname
[0] != 0);
10506 uint32_t cfaidx
= ufoCFAsUsed
;
10507 if (cfaidx
>= UFO_MAX_NATIVE_CFAS
) ufoFatal("too many native words");
10508 ufoForthCFAs
[cfaidx
] = cfa
;
10510 //ufoDefineNative(wname, xcfa, 0);
10511 cfaidx
|= UFO_ADDR_CFA_BIT
;
10512 flags
&= 0xffffff00u
;
10513 ufoCreateWordHeader(wname
, flags
);
10514 const uint32_t res
= UFO_GET_DP();
10515 ufoImgEmitCFA(cfaidx
);
10520 //==========================================================================
10522 // ufoRegisterDataWord
10524 //==========================================================================
10525 static uint32_t ufoRegisterDataWord (const char *wname
, uint32_t cfaidx
, uint32_t value
,
10528 ufo_assert(wname
!= NULL
&& wname
[0] != 0);
10529 flags
&= 0xffffff00u
;
10530 ufoCreateWordHeader(wname
, flags
);
10531 ufoImgEmitCFA(cfaidx
);
10532 const uint32_t res
= UFO_GET_DP();
10533 ufoImgEmitU32(value
);
10538 //==========================================================================
10540 // ufoRegisterConstant
10542 //==========================================================================
10543 void ufoRegisterConstant (const char *wname
, uint32_t value
, uint32_t flags
) {
10544 (void)ufoRegisterDataWord(wname
, ufoDoConstCFA
, value
, flags
);
10548 //==========================================================================
10550 // ufoRegisterVariable
10552 //==========================================================================
10553 uint32_t ufoRegisterVariable (const char *wname
, uint32_t value
, uint32_t flags
) {
10554 return ufoRegisterDataWord(wname
, ufoDoVariableCFA
, value
, flags
);
10558 //==========================================================================
10560 // ufoRegisterValue
10562 //==========================================================================
10563 uint32_t ufoRegisterValue (const char *wname
, uint32_t value
, uint32_t flags
) {
10564 return ufoRegisterDataWord(wname
, ufoDoValueCFA
, value
, flags
);
10568 //==========================================================================
10570 // ufoRegisterDefer
10572 //==========================================================================
10573 uint32_t ufoRegisterDefer (const char *wname
, uint32_t value
, uint32_t flags
) {
10574 return ufoRegisterDataWord(wname
, ufoDoDeferCFA
, value
, flags
);
10578 //==========================================================================
10580 // ufoFindWordInVocabulary
10582 // check if we have the corresponding word.
10583 // return CFA suitable for executing, or 0.
10585 //==========================================================================
10586 uint32_t ufoFindWordInVocabulary (const char *wname
, uint32_t vocid
) {
10587 if (wname
== NULL
|| wname
[0] == 0) return 0;
10588 size_t wlen
= strlen(wname
);
10589 if (wlen
>= UFO_MAX_WORD_LENGTH
) return 0;
10590 return ufoFindWordInVocAndParents(wname
, (uint32_t)wlen
, 0, vocid
, 0);
10594 //==========================================================================
10598 //==========================================================================
10599 uint32_t ufoGetIP (void) {
10604 //==========================================================================
10608 //==========================================================================
10609 void ufoSetIP (uint32_t newip
) {
10614 //==========================================================================
10618 //==========================================================================
10619 int ufoIsExecuting (void) {
10620 return (ufoImgGetU32(ufoAddrSTATE
) == 0);
10624 //==========================================================================
10628 //==========================================================================
10629 int ufoIsCompiling (void) {
10630 return (ufoImgGetU32(ufoAddrSTATE
) != 0);
10634 //==========================================================================
10638 //==========================================================================
10639 void ufoSetExecuting (void) {
10640 ufoImgPutU32(ufoAddrSTATE
, 0);
10644 //==========================================================================
10648 //==========================================================================
10649 void ufoSetCompiling (void) {
10650 ufoImgPutU32(ufoAddrSTATE
, 1);
10654 //==========================================================================
10658 //==========================================================================
10659 uint32_t ufoGetHere () {
10660 return UFO_GET_DP();
10664 //==========================================================================
10668 //==========================================================================
10669 uint32_t ufoGetPad () {
10670 return UFO_PAD_ADDR
;
10674 //==========================================================================
10678 //==========================================================================
10679 uint8_t ufoTIBPeekCh (uint32_t ofs
) {
10680 return ufoTibPeekChOfs(ofs
);
10684 //==========================================================================
10688 //==========================================================================
10689 uint8_t ufoTIBGetCh (void) {
10690 return ufoTibGetCh();
10694 //==========================================================================
10698 //==========================================================================
10699 void ufoTIBSkipCh (void) {
10704 //==========================================================================
10708 // returns 0 on EOF
10710 //==========================================================================
10711 int ufoTIBSRefill (int allowCrossIncludes
) {
10712 return ufoLoadNextLine(allowCrossIncludes
);
10716 //==========================================================================
10720 //==========================================================================
10721 uint32_t ufoPeekData (void) {
10726 //==========================================================================
10730 //==========================================================================
10731 uint32_t ufoPopData (void) {
10736 //==========================================================================
10740 //==========================================================================
10741 void ufoPushData (uint32_t value
) {
10742 return ufoPush(value
);
10746 //==========================================================================
10750 //==========================================================================
10751 void ufoPushBoolData (int val
) {
10756 //==========================================================================
10760 //==========================================================================
10761 uint32_t ufoPeekRet (void) {
10766 //==========================================================================
10770 //==========================================================================
10771 uint32_t ufoPopRet (void) {
10776 //==========================================================================
10780 //==========================================================================
10781 void ufoPushRet (uint32_t value
) {
10782 return ufoRPush(value
);
10786 //==========================================================================
10790 //==========================================================================
10791 void ufoPushBoolRet (int val
) {
10792 ufoRPush(val
? ufoTrueValue
: 0);
10796 //==========================================================================
10800 //==========================================================================
10801 uint8_t ufoPeekByte (uint32_t addr
) {
10802 return ufoImgGetU8(addr
);
10806 //==========================================================================
10810 //==========================================================================
10811 uint16_t ufoPeekWord (uint32_t addr
) {
10818 //==========================================================================
10822 //==========================================================================
10823 uint32_t ufoPeekCell (uint32_t addr
) {
10830 //==========================================================================
10834 //==========================================================================
10835 void ufoPokeByte (uint32_t addr
, uint32_t value
) {
10836 ufoImgPutU8(addr
, value
);
10840 //==========================================================================
10844 //==========================================================================
10845 void ufoPokeWord (uint32_t addr
, uint32_t value
) {
10852 //==========================================================================
10856 //==========================================================================
10857 void ufoPokeCell (uint32_t addr
, uint32_t value
) {
10864 //==========================================================================
10868 //==========================================================================
10869 uint32_t ufoGetPAD (void) {
10870 return UFO_PAD_ADDR
;
10874 //==========================================================================
10878 //==========================================================================
10879 void ufoEmitByte (uint32_t value
) {
10880 ufoImgEmitU8(value
);
10884 //==========================================================================
10888 //==========================================================================
10889 void ufoEmitWord (uint32_t value
) {
10890 ufoImgEmitU8(value
& 0xff);
10891 ufoImgEmitU8((value
>> 8) & 0xff);
10895 //==========================================================================
10899 //==========================================================================
10900 void ufoEmitCell (uint32_t value
) {
10901 ufoImgEmitU32(value
);
10905 //==========================================================================
10909 //==========================================================================
10910 int ufoIsInited (void) {
10911 return (ufoMode
!= UFO_MODE_NONE
);
10915 //==========================================================================
10919 //==========================================================================
10920 void ufoSetUserAbort (void) {
10922 //HACK: push "(USER-ABORT)" word to RP
10923 ufoRPush(ufoUserAbortCFA
);
10927 static void (*ufoUserPostInitCB
) (void);
10930 //==========================================================================
10932 // ufoSetUserPostInit
10934 // called after main initialisation
10936 //==========================================================================
10937 void ufoSetUserPostInit (void (*cb
) (void)) {
10938 ufoUserPostInitCB
= cb
;
10942 //==========================================================================
10946 //==========================================================================
10947 int ufoSStepAllowed (void) {
10948 #ifdef UFO_MTASK_ALLOWED
10949 return (ufoSingleStepAllowed
!= 0);
10956 //==========================================================================
10958 // ufoSetSStepAllowed
10960 //==========================================================================
10961 void ufoSetSStepAllowed (int enabled
) {
10962 #ifdef UFO_MTASK_ALLOWED
10963 ufoSingleStepAllowed
= (enabled
? 1 : 0);
10970 //==========================================================================
10974 //==========================================================================
10975 void ufoInit (void) {
10976 if (ufoMode
!= UFO_MODE_NONE
) return;
10977 ufoMode
= UFO_MODE_NATIVE
;
10979 #ifdef UFO_HUGE_IMAGES
10980 memset(ufoImage
, 0, sizeof(ufoImage
));
10983 #ifdef UFO_MTASK_ALLOWED
10984 ufoSingleStepAllowed
= 0;
10988 ufoInFileName
= NULL
; ufoInFileNameLen
= 0; ufoInFileNameHash
= 0;
10990 ufoLastIncPath
= NULL
; ufoLastSysIncPath
= NULL
;
10992 #ifdef UFO_MTASK_ALLOWED
10993 for (uint32_t f
= 0; f
< UFO_MAX_STATES
; f
+= 1u) ufoStateMap
[f
] = NULL
;
10994 memset(ufoStateUsedBitmap
, 0, sizeof(ufoStateUsedBitmap
));
10995 ufoCurrState
= ufoNewState();
10996 strcpy(ufoCurrState
->name
, "MAIN");
10997 ufoInitStateUserVars(ufoCurrState
);
10999 memset(&ufoCurrState
, 0, sizeof(ufoCurrState
));
11000 strcpy(ufoCurrState
.name
, "MAIN");
11001 ufoInitStateUserVars(&ufoCurrState
);
11004 ufoImgPutU32(ufoAddrDefTIB
, 0); // create TIB handle
11005 ufoImgPutU32(ufoAddrTIBx
, 0); // create TIB handle
11007 #ifdef UFO_MTASK_ALLOWED
11008 ufoYieldedState
= NULL
;
11009 ufoDebuggerState
= NULL
;
11013 #ifdef UFO_DEBUG_STARTUP_TIMES
11014 uint32_t stt
= ufo_get_msecs();
11015 ufoCondDefine("UFO-DEBUG-STARTUP-TIMES");
11018 #ifdef UFO_DEBUG_STARTUP_TIMES
11019 uint32_t ett
= ufo_get_msecs();
11020 fprintf(stderr
, "UrForth init time: %u msecs\n", (unsigned)(ett
- stt
));
11025 if (ufoUserPostInitCB
) {
11026 ufoUserPostInitCB();
11030 // load ufo modules
11031 char *ufmname
= ufoCreateIncludeName("init", 1, NULL
);
11033 FILE *ufl
= fopen(ufmname
, "rb");
11035 FILE *ufl
= fopen(ufmname
, "r");
11039 ufoSetInFileNameReuse(ufmname
);
11041 ufoFileId
= ufoLastUsedFileId
;
11042 setLastIncPath(ufoInFileName
, 1);
11045 ufoFatal("cannot load init code");
11048 if (ufoInFile
!= NULL
) {
11049 ufoRunInterpretLoop();
11054 //==========================================================================
11058 //==========================================================================
11059 void ufoFinishVM (void) {
11060 if (ufoInRunWord
) {
11061 longjmp(ufoStopVMJP
, 669);
11063 ufoFatal("VM is not running");
11068 //==========================================================================
11070 // ufoCallParseIntr
11072 // ( -- addr count TRUE / FALSE )
11073 // does base TIB parsing; never copies anything.
11074 // as our reader is line-based, returns FALSE on EOL.
11075 // EOL is detected after skipping leading delimiters.
11076 // passing -1 as delimiter skips the whole line, and always returns FALSE.
11077 // trailing delimiter is always skipped.
11078 // result is on the data stack.
11080 //==========================================================================
11081 void ufoCallParseIntr (uint32_t delim
, int skipLeading
) {
11082 ufoPush(delim
); ufoPushBool(skipLeading
);
11087 //==========================================================================
11089 // ufoCallParseName
11091 // ( -- addr count )
11092 // parse with leading blanks skipping. doesn't copy anything.
11093 // return empty string on EOL.
11095 //==========================================================================
11096 void ufoCallParseName (void) {
11097 UFCALL(PARSE_NAME
);
11101 //==========================================================================
11105 // ( -- addr count TRUE / FALSE )
11106 // parse without skipping delimiters; never copies anything.
11107 // as our reader is line-based, returns FALSE on EOL.
11108 // passing 0 as delimiter skips the whole line, and always returns FALSE.
11109 // trailing delimiter is always skipped.
11111 //==========================================================================
11112 void ufoCallParse (uint32_t delim
) {
11118 //==========================================================================
11120 // ufoCallParseSkipBlanks
11122 //==========================================================================
11123 void ufoCallParseSkipBlanks (void) {
11124 UFCALL(PARSE_SKIP_BLANKS
);
11128 //==========================================================================
11130 // ufoCallParseSkipComments
11132 //==========================================================================
11133 void ufoCallParseSkipComments (void) {
11134 ufoPushBool(1); UFCALL(PAR_PARSE_SKIP_COMMENTS
);
11138 //==========================================================================
11140 // ufoCallParseSkipLineComments
11142 //==========================================================================
11143 void ufoCallParseSkipLineComments (void) {
11144 ufoPushBool(0); UFCALL(PAR_PARSE_SKIP_COMMENTS
);
11148 //==========================================================================
11150 // ufoCallParseSkipLine
11152 // to the end of line; doesn't refill
11154 //==========================================================================
11155 void ufoCallParseSkipLine (void) {
11156 UFCALL(PARSE_SKIP_LINE
);
11160 //==========================================================================
11162 // ufoCallBasedNumber
11164 // convert number from addrl+1
11165 // returns address of the first inconvertible char
11166 // (BASED-NUMBER) ( addr count allowsign? base -- num TRUE / FALSE )
11168 //==========================================================================
11169 void ufoCallBasedNumber (uint32_t addr
, uint32_t count
, int allowSign
, int base
) {
11170 ufoPush(addr
); ufoPush(count
); ufoPushBool(allowSign
);
11171 if (base
< 0) ufoPush(0); else ufoPush((uint32_t)base
);
11172 UFCALL(PAR_BASED_NUMBER
);
11176 //==========================================================================
11180 //==========================================================================
11181 void ufoRunWord (uint32_t cfa
) {
11183 if (ufoMode
== UFO_MODE_NONE
) ufoFatal("UrForth is not properly inited");
11184 if (ufoInRunWord
) ufoFatal("`ufoRunWord` cannot be called recursively");
11185 ufoMode
= UFO_MODE_NATIVE
;
11191 //==========================================================================
11195 //==========================================================================
11196 void ufoRunMacroWord (uint32_t cfa
) {
11198 if (ufoMode
== UFO_MODE_NONE
) ufoFatal("UrForth is not properly inited");
11199 if (ufoInRunWord
) ufoFatal("`ufoRunWord` cannot be called recursively");
11200 ufoMode
= UFO_MODE_MACRO
;
11201 const uint32_t oisp
= ufoFileStackPos
;
11204 (void)ufoLoadNextUserLine();
11207 ufo_assert(ufoFileStackPos
== oisp
); // sanity check
11212 //==========================================================================
11214 // ufoIsInMacroMode
11216 // check if we are currently in "MACRO" mode.
11217 // should be called from registered words.
11219 //==========================================================================
11220 int ufoIsInMacroMode (void) {
11221 return (ufoMode
== UFO_MODE_MACRO
);
11225 //==========================================================================
11227 // ufoRunInterpretLoop
11229 // run default interpret loop.
11231 //==========================================================================
11232 void ufoRunInterpretLoop (void) {
11233 if (ufoMode
== UFO_MODE_NONE
) {
11236 const uint32_t cfa
= ufoFindWord("RUN-INTERPRET-LOOP");
11237 if (cfa
== 0) ufoFatal("'RUN-INTERPRET-LOOP' word not found");
11239 ufoMode
= UFO_MODE_NATIVE
;
11241 while (ufoFileStackPos
!= 0) ufoPopInFile();
11245 //==========================================================================
11249 //==========================================================================
11250 void ufoRunFile (const char *fname
) {
11251 if (ufoMode
== UFO_MODE_NONE
) {
11254 if (ufoInRunWord
) ufoFatal("`ufoRunFile` cannot be called recursively");
11255 ufoMode
= UFO_MODE_NATIVE
;
11258 char *ufmname
= ufoCreateIncludeName(fname
, 0, ".");
11260 FILE *ufl
= fopen(ufmname
, "rb");
11262 FILE *ufl
= fopen(ufmname
, "r");
11266 ufoSetInFileNameReuse(ufmname
);
11268 ufoFileId
= ufoLastUsedFileId
;
11269 setLastIncPath(ufoInFileName
, 0);
11272 ufoFatal("cannot load source file '%s'", fname
);
11274 ufoRunInterpretLoop();
11278 //==========================================================================
11280 // ufoIsMTaskEnabled
11282 // check if the system was compiled with multitasking support
11284 //==========================================================================
11285 int ufoIsMTaskEnabled (void) {
11286 #ifdef UFO_MTASK_ALLOWED